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