|
||||
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 */
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |