Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:01:16

0001 /*
0002  * Copyright © 2009 CNRS
0003  * Copyright © 2009-2024 Inria.  All rights reserved.
0004  * Copyright © 2009-2012 Université Bordeaux
0005  * Copyright © 2009-2010 Cisco Systems, Inc.  All rights reserved.
0006  * See COPYING in top-level directory.
0007  */
0008 
0009 /** \file
0010  * \brief High-level hwloc traversal helpers.
0011  */
0012 
0013 #ifndef HWLOC_HELPER_H
0014 #define HWLOC_HELPER_H
0015 
0016 #ifndef HWLOC_H
0017 #error Please include the main hwloc.h instead
0018 #endif
0019 
0020 #include <stdlib.h>
0021 #include <errno.h>
0022 
0023 
0024 #ifdef __cplusplus
0025 extern "C" {
0026 #endif
0027 
0028 
0029 /** \defgroup hwlocality_helper_types Kinds of object Type
0030  * @{
0031  *
0032  * Each object type is
0033  * either Normal (i.e. hwloc_obj_type_is_normal() returns 1),
0034  * or Memory (i.e. hwloc_obj_type_is_memory() returns 1)
0035  * or I/O (i.e. hwloc_obj_type_is_io() returns 1)
0036  * or Misc (i.e. equal to ::HWLOC_OBJ_MISC).
0037  * It cannot be of more than one of these kinds.
0038  *
0039  * See also Object Kind in \ref termsanddefs.
0040  */
0041 
0042 /** \brief Check whether an object type is Normal.
0043  *
0044  * Normal objects are objects of the main CPU hierarchy
0045  * (Machine, Package, Core, PU, CPU caches, etc.),
0046  * but they are not NUMA nodes, I/O devices or Misc objects.
0047  *
0048  * They are attached to parent as Normal children,
0049  * not as Memory, I/O or Misc children.
0050  *
0051  * \return 1 if an object of type \p type is a Normal object, 0 otherwise.
0052  */
0053 HWLOC_DECLSPEC int
0054 hwloc_obj_type_is_normal(hwloc_obj_type_t type);
0055 
0056 /** \brief Check whether an object type is I/O.
0057  *
0058  * I/O objects are objects attached to their parents
0059  * in the I/O children list.
0060  * This current includes Bridges, PCI and OS devices.
0061  *
0062  * \return 1 if an object of type \p type is a I/O object, 0 otherwise.
0063  */
0064 HWLOC_DECLSPEC int
0065 hwloc_obj_type_is_io(hwloc_obj_type_t type);
0066 
0067 /** \brief Check whether an object type is Memory.
0068  *
0069  * Memory objects are objects attached to their parents
0070  * in the Memory children list.
0071  * This current includes NUMA nodes and Memory-side caches.
0072  *
0073  * \return 1 if an object of type \p type is a Memory object, 0 otherwise.
0074  */
0075 HWLOC_DECLSPEC int
0076 hwloc_obj_type_is_memory(hwloc_obj_type_t type);
0077 
0078 /** \brief Check whether an object type is a CPU Cache (Data, Unified or Instruction).
0079  *
0080  * Memory-side caches are not CPU caches.
0081  *
0082  * \return 1 if an object of type \p type is a Cache, 0 otherwise.
0083  */
0084 HWLOC_DECLSPEC int
0085 hwloc_obj_type_is_cache(hwloc_obj_type_t type);
0086 
0087 /** \brief Check whether an object type is a CPU Data or Unified Cache.
0088  *
0089  * Memory-side caches are not CPU caches.
0090  *
0091  * \return 1 if an object of type \p type is a CPU Data or Unified Cache, 0 otherwise.
0092  */
0093 HWLOC_DECLSPEC int
0094 hwloc_obj_type_is_dcache(hwloc_obj_type_t type);
0095 
0096 /** \brief Check whether an object type is a CPU Instruction Cache,
0097  *
0098  * Memory-side caches are not CPU caches.
0099  *
0100  * \return 1 if an object of type \p type is a CPU Instruction Cache, 0 otherwise.
0101  */
0102 HWLOC_DECLSPEC int
0103 hwloc_obj_type_is_icache(hwloc_obj_type_t type);
0104 
0105 /** @} */
0106 
0107 
0108 
0109 /** \defgroup hwlocality_helper_find_inside Finding Objects inside a CPU set
0110  * @{
0111  */
0112 
0113 /** \brief Get the first largest object included in the given cpuset \p set.
0114  *
0115  * \return the first object that is included in \p set and whose parent is not.
0116  * \return \c NULL if no such object exists.
0117  *
0118  * This is convenient for iterating over all largest objects within a CPU set
0119  * by doing a loop getting the first largest object and clearing its CPU set
0120  * from the remaining CPU set.
0121  */
0122 static __hwloc_inline hwloc_obj_t
0123 hwloc_get_first_largest_obj_inside_cpuset(hwloc_topology_t topology, hwloc_const_cpuset_t set)
0124 {
0125   hwloc_obj_t obj = hwloc_get_root_obj(topology);
0126   if (!hwloc_bitmap_intersects(obj->cpuset, set))
0127     return NULL;
0128   while (!hwloc_bitmap_isincluded(obj->cpuset, set)) {
0129     /* while the object intersects without being included, look at its children */
0130     hwloc_obj_t child = obj->first_child;
0131     while (child) {
0132       if (hwloc_bitmap_intersects(child->cpuset, set))
0133     break;
0134       child = child->next_sibling;
0135     }
0136     if (!child)
0137       /* no child intersects, return their father */
0138       return obj;
0139     /* found one intersecting child, look at its children */
0140     obj = child;
0141   }
0142   /* obj is included, return it */
0143   return obj;
0144 }
0145 
0146 /** \brief Get the set of largest objects covering exactly a given cpuset \p set
0147  *
0148  * \return the number of objects returned in \p objs.
0149  * \return -1 if no set of objects may cover that cpuset.
0150  */
0151 HWLOC_DECLSPEC int hwloc_get_largest_objs_inside_cpuset (hwloc_topology_t topology, hwloc_const_cpuset_t set,
0152                          hwloc_obj_t * __hwloc_restrict objs, int max);
0153 
0154 /** \brief Return the next object at depth \p depth included in CPU set \p set.
0155  *
0156  * The next invokation should pass the previous return value in \p prev
0157  * so as to obtain the next object in \p set.
0158  *
0159  * \return the first object at depth \p depth included in \p set if \p prev is \c NULL.
0160  * \return the next object at depth \p depth included in \p set if \p prev is not \c NULL.
0161  * \return \c NULL if there is no next object.
0162  *
0163  * \note Objects with empty CPU sets are ignored
0164  * (otherwise they would be considered included in any given set).
0165  *
0166  * \note This function cannot work if objects at the given depth do
0167  * not have CPU sets (I/O or Misc objects).
0168  */
0169 static __hwloc_inline hwloc_obj_t
0170 hwloc_get_next_obj_inside_cpuset_by_depth (hwloc_topology_t topology, hwloc_const_cpuset_t set,
0171                        int depth, hwloc_obj_t prev)
0172 {
0173   hwloc_obj_t next = hwloc_get_next_obj_by_depth(topology, depth, prev);
0174   if (!next)
0175     return NULL;
0176   while (next && (hwloc_bitmap_iszero(next->cpuset) || !hwloc_bitmap_isincluded(next->cpuset, set)))
0177     next = next->next_cousin;
0178   return next;
0179 }
0180 
0181 /** \brief Return the next object of type \p type included in CPU set \p set.
0182  *
0183  * The next invokation should pass the previous return value in \p prev
0184  * so as to obtain the next object in \p set.
0185  *
0186  * \return the first object of type \p type included in \p set if \p prev is \c NULL.
0187  * \return the next object of type \p type included in \p set if \p prev is not \c NULL.
0188  * \return \c NULL if there is no next object.
0189  * \return \c NULL if there is no depth for the given type.
0190  * \return \c NULL if there are multiple depths for the given type,
0191  * the caller should fallback to hwloc_get_next_obj_inside_cpuset_by_depth().
0192  *
0193  * \note Objects with empty CPU sets are ignored
0194  * (otherwise they would be considered included in any given set).
0195  *
0196  * \note This function cannot work if objects of the given type do
0197  * not have CPU sets (I/O or Misc objects).
0198  */
0199 static __hwloc_inline hwloc_obj_t
0200 hwloc_get_next_obj_inside_cpuset_by_type (hwloc_topology_t topology, hwloc_const_cpuset_t set,
0201                       hwloc_obj_type_t type, hwloc_obj_t prev)
0202 {
0203   int depth = hwloc_get_type_depth(topology, type);
0204   if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE)
0205     return NULL;
0206   return hwloc_get_next_obj_inside_cpuset_by_depth(topology, set, depth, prev);
0207 }
0208 
0209 /** \brief Return the (logically) \p idx -th object at depth \p depth included in CPU set \p set.
0210  *
0211  * \return the object if any, \c NULL otherwise.
0212  *
0213  * \note Objects with empty CPU sets are ignored
0214  * (otherwise they would be considered included in any given set).
0215  *
0216  * \note This function cannot work if objects at the given depth do
0217  * not have CPU sets (I/O or Misc objects).
0218  */
0219 static __hwloc_inline hwloc_obj_t
0220 hwloc_get_obj_inside_cpuset_by_depth (hwloc_topology_t topology, hwloc_const_cpuset_t set,
0221                       int depth, unsigned idx) __hwloc_attribute_pure;
0222 static __hwloc_inline hwloc_obj_t
0223 hwloc_get_obj_inside_cpuset_by_depth (hwloc_topology_t topology, hwloc_const_cpuset_t set,
0224                       int depth, unsigned idx)
0225 {
0226   hwloc_obj_t obj = hwloc_get_obj_by_depth (topology, depth, 0);
0227   unsigned count = 0;
0228   if (!obj)
0229     return NULL;
0230   while (obj) {
0231     if (!hwloc_bitmap_iszero(obj->cpuset) && hwloc_bitmap_isincluded(obj->cpuset, set)) {
0232       if (count == idx)
0233     return obj;
0234       count++;
0235     }
0236     obj = obj->next_cousin;
0237   }
0238   return NULL;
0239 }
0240 
0241 /** \brief Return the \p idx -th object of type \p type included in CPU set \p set.
0242  *
0243  * \return the object if any.
0244  * \return \c NULL if there is no such object.
0245  * \return \c NULL if there is no depth for given type.
0246  * \return \c NULL if there are multiple depths for given type,
0247  * the caller should fallback to hwloc_get_obj_inside_cpuset_by_depth().
0248  *
0249  * \note Objects with empty CPU sets are ignored
0250  * (otherwise they would be considered included in any given set).
0251  *
0252  * \note This function cannot work if objects of the given type do
0253  * not have CPU sets (I/O or Misc objects).
0254  */
0255 static __hwloc_inline hwloc_obj_t
0256 hwloc_get_obj_inside_cpuset_by_type (hwloc_topology_t topology, hwloc_const_cpuset_t set,
0257                      hwloc_obj_type_t type, unsigned idx) __hwloc_attribute_pure;
0258 static __hwloc_inline hwloc_obj_t
0259 hwloc_get_obj_inside_cpuset_by_type (hwloc_topology_t topology, hwloc_const_cpuset_t set,
0260                      hwloc_obj_type_t type, unsigned idx)
0261 {
0262   int depth = hwloc_get_type_depth(topology, type);
0263   if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE)
0264     return NULL;
0265   return hwloc_get_obj_inside_cpuset_by_depth(topology, set, depth, idx);
0266 }
0267 
0268 /** \brief Return the number of objects at depth \p depth included in CPU set \p set.
0269  *
0270  * \return the number of objects.
0271  * \return 0 if the depth is invalid.
0272  *
0273  * \note Objects with empty CPU sets are ignored
0274  * (otherwise they would be considered included in any given set).
0275  *
0276  * \note This function cannot work if objects at the given depth do
0277  * not have CPU sets (I/O or Misc objects).
0278  */
0279 static __hwloc_inline unsigned
0280 hwloc_get_nbobjs_inside_cpuset_by_depth (hwloc_topology_t topology, hwloc_const_cpuset_t set,
0281                      int depth) __hwloc_attribute_pure;
0282 static __hwloc_inline unsigned
0283 hwloc_get_nbobjs_inside_cpuset_by_depth (hwloc_topology_t topology, hwloc_const_cpuset_t set,
0284                      int depth)
0285 {
0286   hwloc_obj_t obj = hwloc_get_obj_by_depth (topology, depth, 0);
0287   unsigned count = 0;
0288   if (!obj)
0289     return 0;
0290   while (obj) {
0291     if (!hwloc_bitmap_iszero(obj->cpuset) && hwloc_bitmap_isincluded(obj->cpuset, set))
0292       count++;
0293     obj = obj->next_cousin;
0294   }
0295   return count;
0296 }
0297 
0298 /** \brief Return the number of objects of type \p type included in CPU set \p set.
0299  *
0300  * \return the number of objects.
0301  * \return 0 if there are no objects of that type in the topology.
0302  * \return -1 if there are multiple levels of objects of that type,
0303  * the caller should fallback to hwloc_get_nbobjs_inside_cpuset_by_depth().
0304  *
0305  * \note Objects with empty CPU sets are ignored
0306  * (otherwise they would be considered included in any given set).
0307  *
0308  * \note This function cannot work if objects of the given type do
0309  * not have CPU sets (I/O objects).
0310  */
0311 static __hwloc_inline int
0312 hwloc_get_nbobjs_inside_cpuset_by_type (hwloc_topology_t topology, hwloc_const_cpuset_t set,
0313                     hwloc_obj_type_t type) __hwloc_attribute_pure;
0314 static __hwloc_inline int
0315 hwloc_get_nbobjs_inside_cpuset_by_type (hwloc_topology_t topology, hwloc_const_cpuset_t set,
0316                     hwloc_obj_type_t type)
0317 {
0318   int depth = hwloc_get_type_depth(topology, type);
0319   if (depth == HWLOC_TYPE_DEPTH_UNKNOWN)
0320     return 0;
0321   if (depth == HWLOC_TYPE_DEPTH_MULTIPLE)
0322     return -1; /* FIXME: agregate nbobjs from different levels? */
0323   return (int) hwloc_get_nbobjs_inside_cpuset_by_depth(topology, set, depth);
0324 }
0325 
0326 /** \brief Return the logical index among the objects included in CPU set \p set.
0327  *
0328  * Consult all objects in the same level as \p obj and inside CPU set \p set
0329  * in the logical order, and return the index of \p obj within them.
0330  * If \p set covers the entire topology, this is the logical index of \p obj.
0331  * Otherwise, this is similar to a logical index within the part of the topology
0332  * defined by CPU set \p set.
0333  *
0334  * \return the logical index among the objects included in the set if any.
0335  * \return -1 if the object is not included in the set.
0336  *
0337  * \note Objects with empty CPU sets are ignored
0338  * (otherwise they would be considered included in any given set).
0339  *
0340  * \note This function cannot work if obj does not have CPU sets (I/O objects).
0341  */
0342 static __hwloc_inline int
0343 hwloc_get_obj_index_inside_cpuset (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_cpuset_t set,
0344                    hwloc_obj_t obj) __hwloc_attribute_pure;
0345 static __hwloc_inline int
0346 hwloc_get_obj_index_inside_cpuset (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_cpuset_t set,
0347                    hwloc_obj_t obj)
0348 {
0349   int idx = 0;
0350   if (!hwloc_bitmap_isincluded(obj->cpuset, set))
0351     return -1;
0352   /* count how many objects are inside the cpuset on the way from us to the beginning of the level */
0353   while ((obj = obj->prev_cousin) != NULL)
0354     if (!hwloc_bitmap_iszero(obj->cpuset) && hwloc_bitmap_isincluded(obj->cpuset, set))
0355       idx++;
0356   return idx;
0357 }
0358 
0359 /** @} */
0360 
0361 
0362 
0363 /** \defgroup hwlocality_helper_find_covering Finding Objects covering at least CPU set
0364  * @{
0365  */
0366 
0367 /** \brief Get the child covering at least CPU set \p set.
0368  *
0369  * \return the child that covers the set entirely.
0370  * \return \c NULL if no child matches or if \p set is empty.
0371  *
0372  * \note This function cannot work if parent does not have a CPU set (I/O or Misc objects).
0373  */
0374 static __hwloc_inline hwloc_obj_t
0375 hwloc_get_child_covering_cpuset (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_cpuset_t set,
0376                 hwloc_obj_t parent) __hwloc_attribute_pure;
0377 static __hwloc_inline hwloc_obj_t
0378 hwloc_get_child_covering_cpuset (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_cpuset_t set,
0379                 hwloc_obj_t parent)
0380 {
0381   hwloc_obj_t child;
0382   if (hwloc_bitmap_iszero(set))
0383     return NULL;
0384   child = parent->first_child;
0385   while (child) {
0386     if (child->cpuset && hwloc_bitmap_isincluded(set, child->cpuset))
0387       return child;
0388     child = child->next_sibling;
0389   }
0390   return NULL;
0391 }
0392 
0393 /** \brief Get the lowest object covering at least CPU set \p set
0394  *
0395  * \return the lowest object covering the set entirely.
0396  * \return \c NULL if no object matches or if \p set is empty.
0397  */
0398 static __hwloc_inline hwloc_obj_t
0399 hwloc_get_obj_covering_cpuset (hwloc_topology_t topology, hwloc_const_cpuset_t set) __hwloc_attribute_pure;
0400 static __hwloc_inline hwloc_obj_t
0401 hwloc_get_obj_covering_cpuset (hwloc_topology_t topology, hwloc_const_cpuset_t set)
0402 {
0403   struct hwloc_obj *current = hwloc_get_root_obj(topology);
0404   if (hwloc_bitmap_iszero(set) || !hwloc_bitmap_isincluded(set, current->cpuset))
0405     return NULL;
0406   while (1) {
0407     hwloc_obj_t child = hwloc_get_child_covering_cpuset(topology, set, current);
0408     if (!child)
0409       return current;
0410     current = child;
0411   }
0412 }
0413 
0414 /** \brief Iterate through same-depth objects covering at least CPU set \p set
0415  *
0416  * The next invokation should pass the previous return value in \p prev so as
0417  * to obtain the next object covering at least another part of \p set.
0418  *
0419  * \return the first object at depth \p depth covering at least part of CPU set \p set
0420  * if object \p prev is \c NULL.
0421  * \return the next one if \p prev is not \c NULL.
0422  * \return \c NULL if there is no next object.
0423  *
0424  * \note This function cannot work if objects at the given depth do
0425  * not have CPU sets (I/O or Misc objects).
0426  */
0427 static __hwloc_inline hwloc_obj_t
0428 hwloc_get_next_obj_covering_cpuset_by_depth(hwloc_topology_t topology, hwloc_const_cpuset_t set,
0429                         int depth, hwloc_obj_t prev)
0430 {
0431   hwloc_obj_t next = hwloc_get_next_obj_by_depth(topology, depth, prev);
0432   if (!next)
0433     return NULL;
0434   while (next && !hwloc_bitmap_intersects(set, next->cpuset))
0435     next = next->next_cousin;
0436   return next;
0437 }
0438 
0439 /** \brief Iterate through same-type objects covering at least CPU set \p set
0440  *
0441  * The next invokation should pass the previous return value in \p prev so as to obtain
0442  * the next object of type \p type covering at least another part of \p set.
0443  *
0444  * \return the first object of type \p type covering at least part of CPU set \p set
0445  * if object \p prev is \c NULL.
0446  * \return the next one if \p prev is not \c NULL.
0447  * \return \c NULL if there is no next object.
0448  * \return \c NULL if there is no depth for the given type.
0449  * \return \c NULL if there are multiple depths for the given type,
0450  * the caller should fallback to hwloc_get_next_obj_covering_cpuset_by_depth().
0451  *
0452  * \note This function cannot work if objects of the given type do
0453  * not have CPU sets (I/O or Misc objects).
0454  */
0455 static __hwloc_inline hwloc_obj_t
0456 hwloc_get_next_obj_covering_cpuset_by_type(hwloc_topology_t topology, hwloc_const_cpuset_t set,
0457                        hwloc_obj_type_t type, hwloc_obj_t prev)
0458 {
0459   int depth = hwloc_get_type_depth(topology, type);
0460   if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE)
0461     return NULL;
0462   return hwloc_get_next_obj_covering_cpuset_by_depth(topology, set, depth, prev);
0463 }
0464 
0465 /** @} */
0466 
0467 
0468 
0469 /** \defgroup hwlocality_helper_ancestors Looking at Ancestor and Child Objects
0470  * @{
0471  *
0472  * Be sure to see the figure in \ref termsanddefs that shows a
0473  * complete topology tree, including depths, child/sibling/cousin
0474  * relationships, and an example of an asymmetric topology where one
0475  * package has fewer caches than its peers.
0476  */
0477 
0478 /** \brief Returns the ancestor object of \p obj at depth \p depth.
0479  *
0480  * \return the ancestor if any.
0481  * \return \c NULL if no such ancestor exists.
0482  *
0483  * \note \p depth should not be the depth of PU or NUMA objects
0484  * since they are ancestors of no objects (except Misc or I/O).
0485  * This function rather expects an intermediate level depth,
0486  * such as the depth of Packages, Cores, or Caches.
0487  */
0488 static __hwloc_inline hwloc_obj_t
0489 hwloc_get_ancestor_obj_by_depth (hwloc_topology_t topology __hwloc_attribute_unused, int depth, hwloc_obj_t obj) __hwloc_attribute_pure;
0490 static __hwloc_inline hwloc_obj_t
0491 hwloc_get_ancestor_obj_by_depth (hwloc_topology_t topology __hwloc_attribute_unused, int depth, hwloc_obj_t obj)
0492 {
0493   hwloc_obj_t ancestor = obj;
0494   if (obj->depth < depth)
0495     return NULL;
0496   while (ancestor && ancestor->depth > depth)
0497     ancestor = ancestor->parent;
0498   return ancestor;
0499 }
0500 
0501 /** \brief Returns the ancestor object of \p obj with type \p type.
0502  *
0503  * \return the ancestor if any.
0504  * \return \c NULL if no such ancestor exists.
0505  *
0506  * \note if multiple matching ancestors exist (e.g. multiple levels of ::HWLOC_OBJ_GROUP)
0507  * the lowest one is returned.
0508  *
0509  * \note \p type should not be ::HWLOC_OBJ_PU or ::HWLOC_OBJ_NUMANODE
0510  * since these objects are ancestors of no objects (except Misc or I/O).
0511  * This function rather expects an intermediate object type,
0512  * such as ::HWLOC_OBJ_PACKAGE, ::HWLOC_OBJ_CORE, etc.
0513  */
0514 static __hwloc_inline hwloc_obj_t
0515 hwloc_get_ancestor_obj_by_type (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_type_t type, hwloc_obj_t obj) __hwloc_attribute_pure;
0516 static __hwloc_inline hwloc_obj_t
0517 hwloc_get_ancestor_obj_by_type (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_type_t type, hwloc_obj_t obj)
0518 {
0519   hwloc_obj_t ancestor = obj->parent;
0520   while (ancestor && ancestor->type != type)
0521     ancestor = ancestor->parent;
0522   return ancestor;
0523 }
0524 
0525 /** \brief Returns the common parent object to objects \p obj1 and \p obj2.
0526  *
0527  * \return the common ancestor.
0528  *
0529  * \note This function cannot return \c NULL.
0530  */
0531 static __hwloc_inline hwloc_obj_t
0532 hwloc_get_common_ancestor_obj (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj1, hwloc_obj_t obj2) __hwloc_attribute_pure;
0533 static __hwloc_inline hwloc_obj_t
0534 hwloc_get_common_ancestor_obj (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj1, hwloc_obj_t obj2)
0535 {
0536   /* the loop isn't so easy since intermediate ancestors may have
0537    * different depth, causing us to alternate between using obj1->parent
0538    * and obj2->parent. Also, even if at some point we find ancestors of
0539    * of the same depth, their ancestors may have different depth again.
0540    */
0541   while (obj1 != obj2) {
0542     while (obj1->depth > obj2->depth)
0543       obj1 = obj1->parent;
0544     while (obj2->depth > obj1->depth)
0545       obj2 = obj2->parent;
0546     if (obj1 != obj2 && obj1->depth == obj2->depth) {
0547       obj1 = obj1->parent;
0548       obj2 = obj2->parent;
0549     }
0550   }
0551   return obj1;
0552 }
0553 
0554 /** \brief Returns true if \p obj is inside the subtree beginning with ancestor object \p subtree_root.
0555  *
0556  * \return 1 is the object is in the subtree, 0 otherwise.
0557  *
0558  * \note This function cannot work if \p obj and \p subtree_root objects do
0559  * not have CPU sets (I/O or Misc objects).
0560  */
0561 static __hwloc_inline int
0562 hwloc_obj_is_in_subtree (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj, hwloc_obj_t subtree_root) __hwloc_attribute_pure;
0563 static __hwloc_inline int
0564 hwloc_obj_is_in_subtree (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj, hwloc_obj_t subtree_root)
0565 {
0566   return obj->cpuset && subtree_root->cpuset && hwloc_bitmap_isincluded(obj->cpuset, subtree_root->cpuset);
0567 }
0568 
0569 /** \brief Return the next child.
0570  *
0571  * Return the next child among the normal children list,
0572  * then among the memory children list, then among the I/O
0573  * children list, then among the Misc children list.
0574  *
0575  * \return the first child if \p prev is \c NULL.
0576  * \return the next child if \p prev is not \c NULL.
0577  * \return \c NULL when there is no next child.
0578  */
0579 static __hwloc_inline hwloc_obj_t
0580 hwloc_get_next_child (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t parent, hwloc_obj_t prev)
0581 {
0582   hwloc_obj_t obj;
0583   int state = 0;
0584   if (prev) {
0585     if (prev->type == HWLOC_OBJ_MISC)
0586       state = 3;
0587     else if (hwloc_obj_type_is_io(prev->type))
0588       state = 2;
0589     else if (hwloc_obj_type_is_memory(prev->type))
0590       state = 1;
0591     obj = prev->next_sibling;
0592   } else {
0593     obj = parent->first_child;
0594   }
0595   if (!obj && state == 0) {
0596     obj = parent->memory_first_child;
0597     state = 1;
0598   }
0599   if (!obj && state == 1) {
0600     obj = parent->io_first_child;
0601     state = 2;
0602   }
0603   if (!obj && state == 2) {
0604     obj = parent->misc_first_child;
0605     state = 3;
0606   }
0607   return obj;
0608 }
0609 
0610 /** @} */
0611 
0612 
0613 
0614 /** \defgroup hwlocality_helper_find_cache Looking at Cache Objects
0615  * @{
0616  */
0617 
0618 /** \brief Find the depth of cache objects matching cache level and type.
0619  *
0620  * Return the depth of the topology level that contains cache objects
0621  * whose attributes match \p cachelevel and \p cachetype.
0622 
0623  * This function is identical to calling hwloc_get_type_depth() with the
0624  * corresponding type such as ::HWLOC_OBJ_L1ICACHE, except that it may
0625  * also return a Unified cache when looking for an instruction cache.
0626  *
0627  * \return the depth of the unique matching unified cache level is returned
0628  * if \p cachetype is ::HWLOC_OBJ_CACHE_UNIFIED.
0629  *
0630  * \return the depth of either a matching cache level or a unified cache level
0631  * if \p cachetype is ::HWLOC_OBJ_CACHE_DATA or ::HWLOC_OBJ_CACHE_INSTRUCTION.
0632  *
0633  * \return the depth of the matching level
0634  * if \p cachetype is \c -1 but only one level matches.
0635  *
0636  * \return ::HWLOC_TYPE_DEPTH_MULTIPLE
0637  * if \p cachetype is \c -1 but multiple levels match.
0638  *
0639  * \return ::HWLOC_TYPE_DEPTH_UNKNOWN if no cache level matches.
0640  */
0641 static __hwloc_inline int
0642 hwloc_get_cache_type_depth (hwloc_topology_t topology,
0643                 unsigned cachelevel, hwloc_obj_cache_type_t cachetype)
0644 {
0645   int depth;
0646   int found = HWLOC_TYPE_DEPTH_UNKNOWN;
0647   for (depth=0; ; depth++) {
0648     hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, 0);
0649     if (!obj)
0650       break;
0651     if (!hwloc_obj_type_is_dcache(obj->type) || obj->attr->cache.depth != cachelevel)
0652       /* doesn't match, try next depth */
0653       continue;
0654     if (cachetype == (hwloc_obj_cache_type_t) -1) {
0655       if (found != HWLOC_TYPE_DEPTH_UNKNOWN) {
0656     /* second match, return MULTIPLE */
0657         return HWLOC_TYPE_DEPTH_MULTIPLE;
0658       }
0659       /* first match, mark it as found */
0660       found = depth;
0661       continue;
0662     }
0663     if (obj->attr->cache.type == cachetype || obj->attr->cache.type == HWLOC_OBJ_CACHE_UNIFIED)
0664       /* exact match (either unified is alone, or we match instruction or data), return immediately */
0665       return depth;
0666   }
0667   /* went to the bottom, return what we found */
0668   return found;
0669 }
0670 
0671 /** \brief Get the first data (or unified) cache covering a cpuset \p set
0672  *
0673  * \return a covering cache, or \c NULL if no cache matches.
0674  */
0675 static __hwloc_inline hwloc_obj_t
0676 hwloc_get_cache_covering_cpuset (hwloc_topology_t topology, hwloc_const_cpuset_t set) __hwloc_attribute_pure;
0677 static __hwloc_inline hwloc_obj_t
0678 hwloc_get_cache_covering_cpuset (hwloc_topology_t topology, hwloc_const_cpuset_t set)
0679 {
0680   hwloc_obj_t current = hwloc_get_obj_covering_cpuset(topology, set);
0681   while (current) {
0682     if (hwloc_obj_type_is_dcache(current->type))
0683       return current;
0684     current = current->parent;
0685   }
0686   return NULL;
0687 }
0688 
0689 /** \brief Get the first data (or unified) cache shared between an object and somebody else.
0690  *
0691  * \return a shared cache.
0692  * \return \c NULL if no cache matches or if an invalid object is given (e.g. I/O object).
0693  */
0694 static __hwloc_inline hwloc_obj_t
0695 hwloc_get_shared_cache_covering_obj (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj) __hwloc_attribute_pure;
0696 static __hwloc_inline hwloc_obj_t
0697 hwloc_get_shared_cache_covering_obj (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj)
0698 {
0699   hwloc_obj_t current = obj->parent;
0700   if (!obj->cpuset)
0701     return NULL;
0702   while (current) {
0703     if (!hwloc_bitmap_isequal(current->cpuset, obj->cpuset)
0704         && hwloc_obj_type_is_dcache(current->type))
0705       return current;
0706     current = current->parent;
0707   }
0708   return NULL;
0709 }
0710 
0711 /** @} */
0712 
0713 
0714 
0715 /** \defgroup hwlocality_helper_find_misc Finding objects, miscellaneous helpers
0716  * @{
0717  *
0718  * Be sure to see the figure in \ref termsanddefs that shows a
0719  * complete topology tree, including depths, child/sibling/cousin
0720  * relationships, and an example of an asymmetric topology where one
0721  * package has fewer caches than its peers.
0722  */
0723 
0724 /** \brief Remove simultaneous multithreading PUs from a CPU set.
0725  *
0726  * For each core in \p topology, if \p cpuset contains some PUs of that core,
0727  * modify \p cpuset to only keep a single PU for that core.
0728  *
0729  * \p which specifies which PU will be kept.
0730  * PU are considered in physical index order.
0731  * If 0, for each core, the function keeps the first PU that was originally set in \p cpuset.
0732  *
0733  * If \p which is larger than the number of PUs in a core there were originally set in \p cpuset,
0734  * no PU is kept for that core.
0735  *
0736  * \return 0.
0737  *
0738  * \note PUs that are not below a Core object are ignored
0739  * (for instance if the topology does not contain any Core object).
0740  * None of them is removed from \p cpuset.
0741  */
0742 HWLOC_DECLSPEC int hwloc_bitmap_singlify_per_core(hwloc_topology_t topology, hwloc_bitmap_t cpuset, unsigned which);
0743 
0744 /** \brief Returns the object of type ::HWLOC_OBJ_PU with \p os_index.
0745  *
0746  * This function is useful for converting a CPU set into the PU
0747  * objects it contains.
0748  * When retrieving the current binding (e.g. with hwloc_get_cpubind()),
0749  * one may iterate over the bits of the resulting CPU set with
0750  * hwloc_bitmap_foreach_begin(), and find the corresponding PUs
0751  * with this function.
0752  *
0753  * \return the PU object, or \c NULL if none matches.
0754  */
0755 static __hwloc_inline hwloc_obj_t
0756 hwloc_get_pu_obj_by_os_index(hwloc_topology_t topology, unsigned os_index) __hwloc_attribute_pure;
0757 static __hwloc_inline hwloc_obj_t
0758 hwloc_get_pu_obj_by_os_index(hwloc_topology_t topology, unsigned os_index)
0759 {
0760   hwloc_obj_t obj = NULL;
0761   while ((obj = hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_PU, obj)) != NULL)
0762     if (obj->os_index == os_index)
0763       return obj;
0764   return NULL;
0765 }
0766 
0767 /** \brief Returns the object of type ::HWLOC_OBJ_NUMANODE with \p os_index.
0768  *
0769  * This function is useful for converting a nodeset into the NUMA node
0770  * objects it contains.
0771  * When retrieving the current binding (e.g. with hwloc_get_membind() with HWLOC_MEMBIND_BYNODESET),
0772  * one may iterate over the bits of the resulting nodeset with
0773  * hwloc_bitmap_foreach_begin(), and find the corresponding NUMA nodes
0774  * with this function.
0775  *
0776  * \return the NUMA node object, or \c NULL if none matches.
0777  */
0778 static __hwloc_inline hwloc_obj_t
0779 hwloc_get_numanode_obj_by_os_index(hwloc_topology_t topology, unsigned os_index) __hwloc_attribute_pure;
0780 static __hwloc_inline hwloc_obj_t
0781 hwloc_get_numanode_obj_by_os_index(hwloc_topology_t topology, unsigned os_index)
0782 {
0783   hwloc_obj_t obj = NULL;
0784   while ((obj = hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_NUMANODE, obj)) != NULL)
0785     if (obj->os_index == os_index)
0786       return obj;
0787   return NULL;
0788 }
0789 
0790 /** \brief Do a depth-first traversal of the topology to find and sort
0791  *
0792  * all objects that are at the same depth than \p src.
0793  * Report in \p objs up to \p max physically closest ones to \p src.
0794  *
0795  * \return the number of objects returned in \p objs.
0796  *
0797  * \return 0 if \p src is an I/O object.
0798  *
0799  * \note This function requires the \p src object to have a CPU set.
0800  */
0801 /* TODO: rather provide an iterator? Provide a way to know how much should be allocated? By returning the total number of objects instead? */
0802 HWLOC_DECLSPEC unsigned hwloc_get_closest_objs (hwloc_topology_t topology, hwloc_obj_t src, hwloc_obj_t * __hwloc_restrict objs, unsigned max);
0803 
0804 /** \brief Find an object below another object, both specified by types and indexes.
0805  *
0806  * Start from the top system object and find object of type \p type1
0807  * and logical index \p idx1.  Then look below this object and find another
0808  * object of type \p type2 and logical index \p idx2.  Indexes are specified
0809  * within the parent, not withing the entire system.
0810  *
0811  * For instance, if type1 is PACKAGE, idx1 is 2, type2 is CORE and idx2
0812  * is 3, return the fourth core object below the third package.
0813  *
0814  * \return a matching object if any, \c NULL otherwise.
0815  *
0816  * \note This function requires these objects to have a CPU set.
0817  */
0818 static __hwloc_inline hwloc_obj_t
0819 hwloc_get_obj_below_by_type (hwloc_topology_t topology,
0820                  hwloc_obj_type_t type1, unsigned idx1,
0821                  hwloc_obj_type_t type2, unsigned idx2) __hwloc_attribute_pure;
0822 static __hwloc_inline hwloc_obj_t
0823 hwloc_get_obj_below_by_type (hwloc_topology_t topology,
0824                  hwloc_obj_type_t type1, unsigned idx1,
0825                  hwloc_obj_type_t type2, unsigned idx2)
0826 {
0827   hwloc_obj_t obj;
0828   obj = hwloc_get_obj_by_type (topology, type1, idx1);
0829   if (!obj)
0830     return NULL;
0831   return hwloc_get_obj_inside_cpuset_by_type(topology, obj->cpuset, type2, idx2);
0832 }
0833 
0834 /** \brief Find an object below a chain of objects specified by types and indexes.
0835  *
0836  * This is a generalized version of hwloc_get_obj_below_by_type().
0837  *
0838  * Arrays \p typev and \p idxv must contain \p nr types and indexes.
0839  *
0840  * Start from the top system object and walk the arrays \p typev and \p idxv.
0841  * For each type and logical index couple in the arrays, look under the previously found
0842  * object to find the index-th object of the given type.
0843  * Indexes are specified within the parent, not withing the entire system.
0844  *
0845  * For instance, if nr is 3, typev contains NODE, PACKAGE and CORE,
0846  * and idxv contains 0, 1 and 2, return the third core object below
0847  * the second package below the first NUMA node.
0848  *
0849  * \return a matching object if any, \c NULL otherwise.
0850  *
0851  * \note This function requires all these objects and the root object
0852  * to have a CPU set.
0853  */
0854 static __hwloc_inline hwloc_obj_t
0855 hwloc_get_obj_below_array_by_type (hwloc_topology_t topology, int nr, hwloc_obj_type_t *typev, unsigned *idxv) __hwloc_attribute_pure;
0856 static __hwloc_inline hwloc_obj_t
0857 hwloc_get_obj_below_array_by_type (hwloc_topology_t topology, int nr, hwloc_obj_type_t *typev, unsigned *idxv)
0858 {
0859   hwloc_obj_t obj = hwloc_get_root_obj(topology);
0860   int i;
0861   for(i=0; i<nr; i++) {
0862     if (!obj)
0863       return NULL;
0864     obj = hwloc_get_obj_inside_cpuset_by_type(topology, obj->cpuset, typev[i], idxv[i]);
0865   }
0866   return obj;
0867 }
0868 
0869 /** \brief Return an object of a different type with same locality.
0870  *
0871  * If the source object \p src is a normal or memory type,
0872  * this function returns an object of type \p type with same
0873  * CPU and node sets, either below or above in the hierarchy.
0874  *
0875  * If the source object \p src is a PCI or an OS device within a PCI
0876  * device, the function may either return that PCI device, or another
0877  * OS device in the same PCI parent.
0878  * This may for instance be useful for converting between OS devices
0879  * such as "nvml0" or "rsmi1" used in distance structures into the
0880  * the PCI device, or the CUDA or OpenCL OS device that correspond
0881  * to the same physical card.
0882  *
0883  * If not \c NULL, parameter \p subtype only select objects whose
0884  * subtype attribute exists and is \p subtype (case-insensitively),
0885  * for instance "OpenCL" or "CUDA".
0886  *
0887  * If not \c NULL, parameter \p nameprefix only selects objects whose
0888  * name attribute exists and starts with \p nameprefix (case-insensitively),
0889  * for instance "rsmi" for matching "rsmi0".
0890  *
0891  * If multiple objects match, the first one is returned.
0892  *
0893  * This function will not walk the hierarchy across bridges since
0894  * the PCI locality may become different.
0895  * This function cannot also convert between normal/memory objects
0896  * and I/O or Misc objects.
0897  *
0898  * \p flags must be \c 0 for now.
0899  *
0900  * \return An object with identical locality,
0901  * matching \p subtype and \p nameprefix if any.
0902  *
0903  * \return \c NULL if no matching object could be found,
0904  * or if the source object and target type are incompatible,
0905  * for instance if converting between CPU and I/O objects.
0906  */
0907 HWLOC_DECLSPEC hwloc_obj_t
0908 hwloc_get_obj_with_same_locality(hwloc_topology_t topology, hwloc_obj_t src,
0909                                  hwloc_obj_type_t type, const char *subtype, const char *nameprefix,
0910                                  unsigned long flags);
0911 
0912 /** @} */
0913 
0914 
0915 
0916 /** \defgroup hwlocality_helper_distribute Distributing items over a topology
0917  * @{
0918  */
0919 
0920 /** \brief Flags to be given to hwloc_distrib().
0921  */
0922 enum hwloc_distrib_flags_e {
0923   /** \brief Distrib in reverse order, starting from the last objects.
0924    * \hideinitializer
0925    */
0926   HWLOC_DISTRIB_FLAG_REVERSE = (1UL<<0)
0927 };
0928 
0929 /** \brief Distribute \p n items over the topology under \p roots
0930  *
0931  * Array \p set will be filled with \p n cpusets recursively distributed
0932  * linearly over the topology under objects \p roots, down to depth \p until
0933  * (which can be INT_MAX to distribute down to the finest level).
0934  *
0935  * \p n_roots is usually 1 and \p roots only contains the topology root object
0936  * so as to distribute over the entire topology.
0937  *
0938  * This is typically useful when an application wants to distribute \p n
0939  * threads over a machine, giving each of them as much private cache as
0940  * possible and keeping them locally in number order.
0941  *
0942  * The caller may typically want to also call hwloc_bitmap_singlify()
0943  * before binding a thread so that it does not move at all.
0944  *
0945  * \p flags should be 0 or a OR'ed set of ::hwloc_distrib_flags_e.
0946  *
0947  * \return 0 on success, -1 on error.
0948  *
0949  * \note On hybrid CPUs (or asymmetric platforms), distribution may be suboptimal
0950  * since the number of cores or PUs inside packages or below caches may vary
0951  * (the top-down recursive partitioning ignores these numbers until reaching their levels).
0952  * Hence it is recommended to distribute only inside a single homogeneous domain.
0953  * For instance on a CPU with energy-efficient E-cores and high-performance P-cores,
0954  * one should distribute separately N tasks on E-cores and M tasks on P-cores
0955  * instead of trying to distribute directly M+N tasks on the entire CPUs.
0956  *
0957  * \note This function requires the \p roots objects to have a CPU set.
0958  */
0959 static __hwloc_inline int
0960 hwloc_distrib(hwloc_topology_t topology,
0961           hwloc_obj_t *roots, unsigned n_roots,
0962           hwloc_cpuset_t *set,
0963           unsigned n,
0964           int until, unsigned long flags)
0965 {
0966   unsigned i;
0967   unsigned tot_weight;
0968   unsigned given, givenweight;
0969   hwloc_cpuset_t *cpusetp = set;
0970 
0971   if (flags & ~HWLOC_DISTRIB_FLAG_REVERSE) {
0972     errno = EINVAL;
0973     return -1;
0974   }
0975 
0976   tot_weight = 0;
0977   for (i = 0; i < n_roots; i++)
0978     tot_weight += (unsigned) hwloc_bitmap_weight(roots[i]->cpuset);
0979 
0980   for (i = 0, given = 0, givenweight = 0; i < n_roots; i++) {
0981     unsigned chunk, weight;
0982     hwloc_obj_t root = roots[flags & HWLOC_DISTRIB_FLAG_REVERSE ? n_roots-1-i : i];
0983     hwloc_cpuset_t cpuset = root->cpuset;
0984     while (!hwloc_obj_type_is_normal(root->type))
0985       /* If memory/io/misc, walk up to normal parent */
0986       root = root->parent;
0987     weight = (unsigned) hwloc_bitmap_weight(cpuset);
0988     if (!weight)
0989       continue;
0990     /* Give to root a chunk proportional to its weight.
0991      * If previous chunks got rounded-up, we may get a bit less. */
0992     chunk = (( (givenweight+weight) * n  + tot_weight-1) / tot_weight)
0993           - ((  givenweight         * n  + tot_weight-1) / tot_weight);
0994     if (!root->arity || chunk <= 1 || root->depth >= until) {
0995       /* We can't split any more, put everything there.  */
0996       if (chunk) {
0997     /* Fill cpusets with ours */
0998     unsigned j;
0999     for (j=0; j < chunk; j++)
1000       cpusetp[j] = hwloc_bitmap_dup(cpuset);
1001       } else {
1002     /* We got no chunk, just merge our cpuset to a previous one
1003      * (the first chunk cannot be empty)
1004      * so that this root doesn't get ignored.
1005      */
1006     assert(given);
1007     hwloc_bitmap_or(cpusetp[-1], cpusetp[-1], cpuset);
1008       }
1009     } else {
1010       /* Still more to distribute, recurse into children */
1011       hwloc_distrib(topology, root->children, root->arity, cpusetp, chunk, until, flags);
1012     }
1013     cpusetp += chunk;
1014     given += chunk;
1015     givenweight += weight;
1016   }
1017 
1018   return 0;
1019 }
1020 
1021 /** @} */
1022 
1023 
1024 
1025 /** \defgroup hwlocality_helper_topology_sets CPU and node sets of entire topologies
1026  * @{
1027  */
1028 
1029 /** \brief Get complete CPU set
1030  *
1031  * \return the complete CPU set of processors of the system.
1032  *
1033  * \note This function cannot return \c NULL.
1034  *
1035  * \note The returned cpuset is not newly allocated and should thus not be
1036  * changed or freed; hwloc_bitmap_dup() must be used to obtain a local copy.
1037  *
1038  * \note This is equivalent to retrieving the root object complete CPU-set.
1039  */
1040 HWLOC_DECLSPEC hwloc_const_cpuset_t
1041 hwloc_topology_get_complete_cpuset(hwloc_topology_t topology) __hwloc_attribute_pure;
1042 
1043 /** \brief Get topology CPU set
1044  *
1045  * \return the CPU set of processors of the system for which hwloc
1046  * provides topology information. This is equivalent to the cpuset of the
1047  * system object.
1048  *
1049  * \note This function cannot return \c NULL.
1050  *
1051  * \note The returned cpuset is not newly allocated and should thus not be
1052  * changed or freed; hwloc_bitmap_dup() must be used to obtain a local copy.
1053  *
1054  * \note This is equivalent to retrieving the root object CPU-set.
1055  */
1056 HWLOC_DECLSPEC hwloc_const_cpuset_t
1057 hwloc_topology_get_topology_cpuset(hwloc_topology_t topology) __hwloc_attribute_pure;
1058 
1059 /** \brief Get allowed CPU set
1060  *
1061  * \return the CPU set of allowed processors of the system.
1062  *
1063  * \note This function cannot return \c NULL.
1064  *
1065  * \note If the topology flag ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED was not set,
1066  * this is identical to hwloc_topology_get_topology_cpuset(), which means
1067  * all PUs are allowed.
1068  *
1069  * \note If ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED was set, applying
1070  * hwloc_bitmap_intersects() on the result of this function and on an object
1071  * cpuset checks whether there are allowed PUs inside that object.
1072  * Applying hwloc_bitmap_and() returns the list of these allowed PUs.
1073  *
1074  * \note The returned cpuset is not newly allocated and should thus not be
1075  * changed or freed, hwloc_bitmap_dup() must be used to obtain a local copy.
1076  */
1077 HWLOC_DECLSPEC hwloc_const_cpuset_t
1078 hwloc_topology_get_allowed_cpuset(hwloc_topology_t topology) __hwloc_attribute_pure;
1079 
1080 /** \brief Get complete node set
1081  *
1082  * \return the complete node set of memory of the system.
1083  *
1084  * \note This function cannot return \c NULL.
1085  *
1086  * \note The returned nodeset is not newly allocated and should thus not be
1087  * changed or freed; hwloc_bitmap_dup() must be used to obtain a local copy.
1088  *
1089  * \note This is equivalent to retrieving the root object complete nodeset.
1090  */
1091 HWLOC_DECLSPEC hwloc_const_nodeset_t
1092 hwloc_topology_get_complete_nodeset(hwloc_topology_t topology) __hwloc_attribute_pure;
1093 
1094 /** \brief Get topology node set
1095  *
1096  * \return the node set of memory of the system for which hwloc
1097  * provides topology information. This is equivalent to the nodeset of the
1098  * system object.
1099  *
1100  * \note This function cannot return \c NULL.
1101  *
1102  * \note The returned nodeset is not newly allocated and should thus not be
1103  * changed or freed; hwloc_bitmap_dup() must be used to obtain a local copy.
1104  *
1105  * \note This is equivalent to retrieving the root object nodeset.
1106  */
1107 HWLOC_DECLSPEC hwloc_const_nodeset_t
1108 hwloc_topology_get_topology_nodeset(hwloc_topology_t topology) __hwloc_attribute_pure;
1109 
1110 /** \brief Get allowed node set
1111  *
1112  * \return the node set of allowed memory of the system.
1113  *
1114  * \note This function cannot return \c NULL.
1115  *
1116  * \note If the topology flag ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED was not set,
1117  * this is identical to hwloc_topology_get_topology_nodeset(), which means
1118  * all NUMA nodes are allowed.
1119  *
1120  * \note If ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED was set, applying
1121  * hwloc_bitmap_intersects() on the result of this function and on an object
1122  * nodeset checks whether there are allowed NUMA nodes inside that object.
1123  * Applying hwloc_bitmap_and() returns the list of these allowed NUMA nodes.
1124  *
1125  * \note The returned nodeset is not newly allocated and should thus not be
1126  * changed or freed, hwloc_bitmap_dup() must be used to obtain a local copy.
1127  */
1128 HWLOC_DECLSPEC hwloc_const_nodeset_t
1129 hwloc_topology_get_allowed_nodeset(hwloc_topology_t topology) __hwloc_attribute_pure;
1130 
1131 /** @} */
1132 
1133 
1134 
1135 /** \defgroup hwlocality_helper_nodeset_convert Converting between CPU sets and node sets
1136  *
1137  * @{
1138  */
1139 
1140 /** \brief Convert a CPU set into a NUMA node set
1141  *
1142  * For each PU included in the input \p _cpuset, set the corresponding
1143  * local NUMA node(s) in the output \p nodeset.
1144  *
1145  * If some NUMA nodes have no CPUs at all, this function never sets their
1146  * indexes in the output node set, even if a full CPU set is given in input.
1147  *
1148  * Hence the entire topology CPU set is converted into the set of all nodes
1149  * that have some local CPUs.
1150  *
1151  * \return 0 on success.
1152  * \return -1 with errno set to \c ENOMEM on internal reallocation failure.
1153  */
1154 static __hwloc_inline int
1155 hwloc_cpuset_to_nodeset(hwloc_topology_t topology, hwloc_const_cpuset_t _cpuset, hwloc_nodeset_t nodeset)
1156 {
1157     int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE);
1158     hwloc_obj_t obj = NULL;
1159     assert(depth != HWLOC_TYPE_DEPTH_UNKNOWN);
1160     hwloc_bitmap_zero(nodeset);
1161     while ((obj = hwloc_get_next_obj_covering_cpuset_by_depth(topology, _cpuset, depth, obj)) != NULL)
1162         if (hwloc_bitmap_set(nodeset, obj->os_index) < 0)
1163             return -1;
1164     return 0;
1165 }
1166 
1167 /** \brief Convert a NUMA node set into a CPU set
1168  *
1169  * For each NUMA node included in the input \p nodeset, set the corresponding
1170  * local PUs in the output \p _cpuset.
1171  *
1172  * If some CPUs have no local NUMA nodes, this function never sets their
1173  * indexes in the output CPU set, even if a full node set is given in input.
1174  *
1175  * Hence the entire topology node set is converted into the set of all CPUs
1176  * that have some local NUMA nodes.
1177  *
1178  * \return 0 on success.
1179  * \return -1 with errno set to \c ENOMEM on internal reallocation failure.
1180  */
1181 static __hwloc_inline int
1182 hwloc_cpuset_from_nodeset(hwloc_topology_t topology, hwloc_cpuset_t _cpuset, hwloc_const_nodeset_t nodeset)
1183 {
1184     int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE);
1185     hwloc_obj_t obj = NULL;
1186     assert(depth != HWLOC_TYPE_DEPTH_UNKNOWN);
1187     hwloc_bitmap_zero(_cpuset);
1188     while ((obj = hwloc_get_next_obj_by_depth(topology, depth, obj)) != NULL) {
1189         if (hwloc_bitmap_isset(nodeset, obj->os_index))
1190             /* no need to check obj->cpuset because objects in levels always have a cpuset */
1191             if (hwloc_bitmap_or(_cpuset, _cpuset, obj->cpuset) < 0)
1192                 return -1;
1193     }
1194     return 0;
1195 }
1196 
1197 /** @} */
1198 
1199 
1200 
1201 /** \defgroup hwlocality_advanced_io Finding I/O objects
1202  * @{
1203  */
1204 
1205 /** \brief Get the first non-I/O ancestor object.
1206  *
1207  * Given the I/O object \p ioobj, find the smallest non-I/O ancestor
1208  * object. This object (normal or memory) may then be used for binding
1209  * because it has non-NULL CPU and node sets
1210  * and because its locality is the same as \p ioobj.
1211  *
1212  * \return a non-I/O object.
1213  *
1214  * \note This function cannot return \c NULL.
1215  *
1216  * \note The resulting object is usually a normal object but it could also
1217  * be a memory object (e.g. NUMA node) in future platforms if I/O objects
1218  * ever get attached to memory instead of CPUs.
1219  */
1220 static __hwloc_inline hwloc_obj_t
1221 hwloc_get_non_io_ancestor_obj(hwloc_topology_t topology __hwloc_attribute_unused,
1222                   hwloc_obj_t ioobj)
1223 {
1224   hwloc_obj_t obj = ioobj;
1225   while (obj && !obj->cpuset) {
1226     obj = obj->parent;
1227   }
1228   return obj;
1229 }
1230 
1231 /** \brief Get the next PCI device in the system.
1232  *
1233  * \return the first PCI device if \p prev is \c NULL.
1234  * \return the next PCI device if \p prev is not \c NULL.
1235  * \return \c NULL if there is no next PCI device.
1236  */
1237 static __hwloc_inline hwloc_obj_t
1238 hwloc_get_next_pcidev(hwloc_topology_t topology, hwloc_obj_t prev)
1239 {
1240   return hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_PCI_DEVICE, prev);
1241 }
1242 
1243 /** \brief Find the PCI device object matching the PCI bus id
1244  * given domain, bus device and function PCI bus id.
1245  *
1246  * \return a matching PCI device object if any, \c NULL otherwise.
1247  */
1248 static __hwloc_inline hwloc_obj_t
1249 hwloc_get_pcidev_by_busid(hwloc_topology_t topology,
1250               unsigned domain, unsigned bus, unsigned dev, unsigned func)
1251 {
1252   hwloc_obj_t obj = NULL;
1253   while ((obj = hwloc_get_next_pcidev(topology, obj)) != NULL) {
1254     if (obj->attr->pcidev.domain == domain
1255     && obj->attr->pcidev.bus == bus
1256     && obj->attr->pcidev.dev == dev
1257     && obj->attr->pcidev.func == func)
1258       return obj;
1259   }
1260   return NULL;
1261 }
1262 
1263 /** \brief Find the PCI device object matching the PCI bus id
1264  * given as a string xxxx:yy:zz.t or yy:zz.t.
1265  *
1266  * \return a matching PCI device object if any, \c NULL otherwise.
1267  */
1268 static __hwloc_inline hwloc_obj_t
1269 hwloc_get_pcidev_by_busidstring(hwloc_topology_t topology, const char *busid)
1270 {
1271   unsigned domain = 0; /* default */
1272   unsigned bus, dev, func;
1273 
1274   if (sscanf(busid, "%x:%x.%x", &bus, &dev, &func) != 3
1275       && sscanf(busid, "%x:%x:%x.%x", &domain, &bus, &dev, &func) != 4) {
1276     errno = EINVAL;
1277     return NULL;
1278   }
1279 
1280   return hwloc_get_pcidev_by_busid(topology, domain, bus, dev, func);
1281 }
1282 
1283 /** \brief Get the next OS device in the system.
1284  *
1285  * \return the first OS device if \p prev is \c NULL.
1286  * \return the next OS device if \p prev is not \c NULL.
1287  * \return \c NULL if there is no next OS device.
1288  */
1289 static __hwloc_inline hwloc_obj_t
1290 hwloc_get_next_osdev(hwloc_topology_t topology, hwloc_obj_t prev)
1291 {
1292   return hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_OS_DEVICE, prev);
1293 }
1294 
1295 /** \brief Get the next bridge in the system.
1296  *
1297  * \return the first bridge if \p prev is \c NULL.
1298  * \return the next bridge if \p prev is not \c NULL.
1299  * \return \c NULL if there is no next bridge.
1300  */
1301 static __hwloc_inline hwloc_obj_t
1302 hwloc_get_next_bridge(hwloc_topology_t topology, hwloc_obj_t prev)
1303 {
1304   return hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_BRIDGE, prev);
1305 }
1306 
1307 /* \brief Checks whether a given bridge covers a given PCI bus.
1308  *
1309  * \return 1 if it covers, 0 if not.
1310  */
1311 static __hwloc_inline int
1312 hwloc_bridge_covers_pcibus(hwloc_obj_t bridge,
1313                unsigned domain, unsigned bus)
1314 {
1315   return bridge->type == HWLOC_OBJ_BRIDGE
1316     && bridge->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI
1317     && bridge->attr->bridge.downstream.pci.domain == domain
1318     && bridge->attr->bridge.downstream.pci.secondary_bus <= bus
1319     && bridge->attr->bridge.downstream.pci.subordinate_bus >= bus;
1320 }
1321 
1322 /** @} */
1323 
1324 
1325 
1326 #ifdef __cplusplus
1327 } /* extern "C" */
1328 #endif
1329 
1330 
1331 #endif /* HWLOC_HELPER_H */