Struct hwlocality::topology::editor::TopologyEditor

source ·
pub struct TopologyEditor<'topology>(/* private fields */);
Available on crate feature hwloc-2_3_0 only.
Expand description

Proxy for modifying a Topology

This proxy object is carefully crafted to only allow operations that are safe while modifying a topology and minimize the number of times the hwloc lazy caches will need to be refreshed.

The API is broken down into sections roughly following the structure of the upstream hwloc documentation:

Implementations§

source§

impl TopologyEditor<'_>

§Kinds of CPU cores

source

pub fn register_cpu_kind<'infos>( &mut self, cpuset: impl Deref<Target = CpuSet>, forced_efficiency: Option<CpuEfficiency>, infos: impl IntoIterator<Item = (&'infos str, &'infos str)>, ) -> Result<(), RegisterError>

Available on crate feature hwloc-2_4_0 only.

Register a kind of CPU in the topology.

Mark the PUs listed in cpuset as being of the same kind with respect to the given attributes.

cpuset can be a &'_ CpuSet or a BitmapRef<'_, CpuSet>.

forced_efficiency should be None if unknown. Otherwise it is an abstracted efficiency value to enforce the ranking of all kinds if all of them have valid (and different) efficiencies.

Note that the efficiency reported later by Topology::cpu_kinds() may differ because hwloc will scale efficiency values down to between 0 and the number of kinds minus 1.

If cpuset overlaps with some existing kinds, those might get modified or split. For instance if existing kind A contains PUs 0 and 1, and one registers another kind for PU 1 and 2, there will be 3 resulting kinds: existing kind A is restricted to only PU 0; new kind B contains only PU 1 and combines information from A and from the newly-registered kind; new kind C contains only PU 2 and only gets information from the newly-registered kind.

§Errors
source§

impl<'topology> TopologyEditor<'topology>

§Managing memory attributes

source

pub fn register_memory_attribute( &mut self, name: &str, flags: MemoryAttributeFlags, ) -> Result<MemoryAttributeBuilder<'_, 'topology>, RegisterError>

Register a new memory attribute

§Errors
source§

impl TopologyEditor<'_>

§Add distances between objects

source

pub fn add_distances( &mut self, name: Option<&str>, kind: DistancesKind, flags: AddDistancesFlags, collect_objects_and_distances: impl FnOnce(&Topology) -> (Vec<Option<&TopologyObject>>, Vec<u64>), ) -> Result<(), HybridError<AddDistancesError>>

Available on crate feature hwloc-2_5_0 only.

Create a new object distances matrix

kind specifies the kind of distance. You should not use the HETEROGENEOUS_TYPES kind here, it will be set automatically.

flags can be used to request the grouping of existing objects based on distance.

The collect_objects_and_distances callback should query the geometry to collect references to the objects of interest, and produce the corresponding distance matrix. If there are N output objects, then there should be N.pow(2) output distances.

Distances must be provided in sender-major order: the distance from object 0 to object 1, then object 0 to object 2, … all the way to object N, and then from object 1 to object 0, and so on.

§Errors
  • InconsistentData if the number of distances returned by the callback is not compatible with the number of objects (it should be the square of it)
  • BadKind if the provided kind contains HETEROGENEOUS_TYPES or several of the “FROM_” and “MEANS_” kinds
  • BadObjectsCount if less than 2 or more than c_uint::MAX objects are returned by the callback(hwloc does not support such configurations)
  • ForeignEndpoint if the callback returned objects that do not belong to this topology
  • NameContainsNul if the provided name contains NUL chars
source§

impl TopologyEditor<'_>

§Remove distances between objects

source

pub fn remove_distances( &mut self, find_distances: impl FnOnce(&Topology) -> Distances<'_>, ) -> Result<(), RawHwlocError>

Remove a single distances matrix from the topology

The distances matrix to be removed can be selected using the find_distances callback.

source

pub fn remove_all_distances(&mut self) -> Result<(), RawHwlocError>

Remove all distance matrices from a topology

If these distances were used to group objects, these additional Group objects are not removed from the topology.

source

pub fn remove_distances_at_depth<DepthLike>( &mut self, depth: DepthLike, ) -> Result<(), RawHwlocError>
where DepthLike: TryInto<Depth>, <DepthLike as TryInto<Depth>>::Error: Debug,

Remove distance matrices for objects at a specific depth in the topology (if any)

Identical to remove_all_distances(), but only applies to one level of the topology.

depth can be a Depth, a NormalDepth or an usize.

source

pub fn remove_distances_with_type( &mut self, ty: ObjectType, ) -> Result<(), RawHwlocError>

Remove distance matrices for objects of a specific type in the topology

Identical to remove_all_distances(), but only applies to one level of the topology.

source§

impl<'topology> TopologyEditor<'topology>

§General-purpose utilities

source

pub fn topology(&mut self) -> &Topology

Get a shared reference to the inner Topology

This requires rebuilding inner caches, which can be costly. Prefer accessing the topology before or after editing it if possible.

source§

impl<'topology> TopologyEditor<'topology>

§Basic modifications

source

pub fn restrict<Set: SpecializedBitmap>( &mut self, set: &Set, flags: RestrictFlags, ) -> Result<(), ParameterError<Set::Owned>>

Restrict the topology to the given CPU set or nodeset

The topology is modified so as to remove all objects that are not included (or partially included) in the specified CpuSet or NodeSet set. All objects CPU and node sets are restricted accordingly.

Restricting the topology removes some locality information, hence the remaining objects may get reordered (including PUs and NUMA nodes), and their logical indices may change.

This call may not be reverted by restricting back to a larger set. Once dropped during restriction, objects may not be brought back, except by loading another topology with Topology::new() or TopologyBuilder.

§Errors

It is an error to attempt to remove all CPUs or NUMA nodes from a topology using a set that has no intersection with the relevant topology set. The topology will not be modified in this case, and a ParameterError will be returned instead.

§Aborts

Failure to allocate internal data will lead to a process abort, because the topology gets corrupted in this case and must not be touched again, but we have no way to prevent this in a safe API.

source

pub fn allow( &mut self, allow_set: AllowSet<'_>, ) -> Result<(), HybridError<AllowSetError>>

Change the sets of allowed PUs and NUMA nodes in the topology

This function only works if BuildFlags::INCLUDE_DISALLOWED was set during topology building. It does not modify any object, it only changes the sets returned by Topology::allowed_cpuset() and Topology::allowed_nodeset().

It is notably useful when importing a topology from another process running in a different Linux Cgroup.

Removing objects from a topology should rather be performed with TopologyEditor::restrict().

§Errors
  • EmptyCustom if an AllowSet::Custom does not do anything because both its cpuset and nodeset members are empty.
  • InvalidCpuset if applying the cpuset of an AllowSet::Custom would amount to disallowing all CPUs from the topology.
  • InvalidNodeset if applying the nodeset of an AllowSet::Custom would amount to disallowing all NUMA nodes from the topology.
  • Unsupported if the specified AllowSet is not supported by the host operating system.
source

pub fn insert_group_object<NormalFilter, MemoryFilter>( &mut self, dont_merge: bool, find_parent: impl FnOnce(&Topology) -> &TopologyObject, child_filter: GroupChildFilter<NormalFilter, MemoryFilter>, ) -> Result<InsertedGroup<'topology>, HybridError<InsertGroupError>>
where NormalFilter: FnMut(&TopologyObject) -> bool, MemoryFilter: FnMut(&TopologyObject) -> bool,

Add more structure to the topology by creating an intermediate Group

Sibling normal objects below a common parent object can be grouped to express that there is a resource shared between the underlying CPU cores, which cannot be modeled using a more specific standard hwloc object type. For example, this is how the intra-chip NUMA clusters of modern high-core-count AMD and Intel CPUs are usually modeled. See the “What are these Group objects in my topology” entry of the hwloc FAQ for more information.

Alas, creating hwloc groups is a lot less straightforward than the above summary may suggest, and you are strongly advised to carefully read and understand all of the following before using this function.

§Group creation guide
§Basic workflow

This function will first call the find_parent callback in order to identify the parent object under which a new group should be inserted.

The callback(s) specified by child_filter will then be called on each normal and/or memory child of this parent, allowing you to tell which objects should become members of the newly created group. See GroupChildFilter for more information.

This API design, which may be unexpectedly complex, helps you honor hwloc’s many group creation rules:

  • Only normal and memory objects can be members of a group. I/O and Misc objects can only be grouped coarsely and indirectly by grouping the normal objects under which they reside.
  • The normal and memory members of an hwloc group must be consistent with each other, as explained in the GroupChildFilter documentation.
  • It is, generally speaking, not possible to group objects which do not lie below the same parent. For example, you cannot create a group that contains the first hyperthreads of each core of an x86 CPU.

One extra constraint that you are responsible for honoring is that hwloc does not support empty groups. Therefore your child_filter callback(s) must select at least one normal or memory child.

Finally, the dont_merge parameter allows you to adjust hwloc’s strategy for merging proposed groups with equivalent topology objects, as explained in the following section.

§Equivalence and merging

hwloc considers a group to be equivalent to one or more existing topology objects in the following circumstances:

  • A group with a single child object is considered to be equivalent to this child object
  • A group which covers all children of the parent object that was designated by find_parent is considered to be equivalent to this parent object
    • This typically happens as a result of your children selection callbacks returning true for all children of the parent object.
    • If you were using GroupChildFilter::Mixed with strict set to false, it may also happen that although one of your callbacks did not pick all children, the remaining children had to be added to follow hwloc’s group consistency rules.

In addition to these equivalence relations, topology objects which form a single-child chain with identical cpusets and nodesets (a simple example being L2 -> L1d -> L1i -> Core chains in x86 topologies), are also considered to be equivalent to each other. Therefore, if a group is considered to be equivalent to one of these objects, then it is considered equivalent to all of them.

When a proposed group is equivalent to an existing topology object, the default hwloc behavior is not to create a group, but instead to return InsertedGroup::Existing with one of the objects that is considered equivalent to the proposed group as a parameter. The idea is that you do not really need a group to model the desired set of CPU cores and NUMA nodes, since at least one existing topology object already does so.

If you want to force the creation of a group in a situation where hwloc would not create one, you can set dont_merge to true to force the creation of a group even when hwloc considers the proposed group to be equivalent to one existing topology object. This comes with two caveats:

  • The group may be created above or below any of the objects that it is considered equivalent to, not necessarily below the parent object that you initially had in mind.
  • Even with this option, hwloc will refuse to create a group that is equivalent to the topology root.
§Documenting groups

By nature, the Group object type is not very descriptive of what the group represents in hardware, so you may want to add extra annotations describing what the group is about.

To this end, after a successful group object insertion, you may use TopologyObject::set_subtype_unchecked() to have lstopo display something other than “Group” as the type name.

If needed, you can also complement this basic group type information with any number of extra name/value info pairs you need using TopologyObject::add_info().

§Identifier invalidation

When a group is created, it becomes a child of the group members’ former parent. To allow for this, the normal children of this parent need to be reordered first, so that the group members lie at consecutive indices. A new depth level of type Group may also need to be created to host the group, which will push existing depths downwards. As a consequence of all these topology changes…

  • The logical indices of all objects at the depth where the group members used to lie may change as a result of calling this function. If you want to identify a child object across calls to this function, you should therefore use another identifier than the logical index or sibling rank. Global persistent indices are explicitly designed for this use case.
  • The mapping of depths to object types may change as a result of calling this function, for all depths below the designated group parent. Therefore, you must be very cautious about reusing previously computed depth values across calls to this function.
§Errors
source

pub fn insert_misc_object( &mut self, name: &str, find_parent: impl FnOnce(&Topology) -> &TopologyObject, ) -> Result<&'topology mut TopologyObject, HybridError<InsertMiscError>>

Add a Misc object as a leaf of the topology

A new Misc object will be created and inserted into the topology as a child of the node selected by find_parent. It is appended to the list of existing Misc children, without ever adding any intermediate hierarchy level. This is useful for annotating the topology without actually changing the hierarchy.

name is supposed to be unique across all Misc objects in the topology. It must not contain any NUL chars. If it contains any other non-printable characters, then they will be dropped when exporting to XML.

The new leaf object will not have any cpuset.

§Errors

Trait Implementations§

source§

impl<'topology> Debug for TopologyEditor<'topology>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'topology> Freeze for TopologyEditor<'topology>

§

impl<'topology> RefUnwindSafe for TopologyEditor<'topology>

§

impl<'topology> Send for TopologyEditor<'topology>

§

impl<'topology> Sync for TopologyEditor<'topology>

§

impl<'topology> Unpin for TopologyEditor<'topology>

§

impl<'topology> !UnwindSafe for TopologyEditor<'topology>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

source§

fn vzip(self) -> V