helper.h 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321
  1. /*
  2. * Copyright © 2009 CNRS
  3. * Copyright © 2009-2023 Inria. All rights reserved.
  4. * Copyright © 2009-2012 Université Bordeaux
  5. * Copyright © 2009-2010 Cisco Systems, Inc. All rights reserved.
  6. * See COPYING in top-level directory.
  7. */
  8. /** \file
  9. * \brief High-level hwloc traversal helpers.
  10. */
  11. #ifndef HWLOC_HELPER_H
  12. #define HWLOC_HELPER_H
  13. #ifndef HWLOC_H
  14. #error Please include the main hwloc.h instead
  15. #endif
  16. #include <stdlib.h>
  17. #include <errno.h>
  18. #ifdef __cplusplus
  19. extern "C" {
  20. #endif
  21. /** \defgroup hwlocality_helper_find_inside Finding Objects inside a CPU set
  22. * @{
  23. */
  24. /** \brief Get the first largest object included in the given cpuset \p set.
  25. *
  26. * \return the first object that is included in \p set and whose parent is not.
  27. * \return \c NULL if no such object exists.
  28. *
  29. * This is convenient for iterating over all largest objects within a CPU set
  30. * by doing a loop getting the first largest object and clearing its CPU set
  31. * from the remaining CPU set.
  32. */
  33. static __hwloc_inline hwloc_obj_t
  34. hwloc_get_first_largest_obj_inside_cpuset(hwloc_topology_t topology, hwloc_const_cpuset_t set)
  35. {
  36. hwloc_obj_t obj = hwloc_get_root_obj(topology);
  37. if (!hwloc_bitmap_intersects(obj->cpuset, set))
  38. return NULL;
  39. while (!hwloc_bitmap_isincluded(obj->cpuset, set)) {
  40. /* while the object intersects without being included, look at its children */
  41. hwloc_obj_t child = obj->first_child;
  42. while (child) {
  43. if (hwloc_bitmap_intersects(child->cpuset, set))
  44. break;
  45. child = child->next_sibling;
  46. }
  47. if (!child)
  48. /* no child intersects, return their father */
  49. return obj;
  50. /* found one intersecting child, look at its children */
  51. obj = child;
  52. }
  53. /* obj is included, return it */
  54. return obj;
  55. }
  56. /** \brief Get the set of largest objects covering exactly a given cpuset \p set
  57. *
  58. * \return the number of objects returned in \p objs.
  59. * \return -1 if no set of objects may cover that cpuset.
  60. */
  61. HWLOC_DECLSPEC int hwloc_get_largest_objs_inside_cpuset (hwloc_topology_t topology, hwloc_const_cpuset_t set,
  62. hwloc_obj_t * __hwloc_restrict objs, int max);
  63. /** \brief Return the next object at depth \p depth included in CPU set \p set.
  64. *
  65. * The next invokation should pass the previous return value in \p prev
  66. * so as to obtain the next object in \p set.
  67. *
  68. * \return the first object at depth \p depth included in \p set if \p prev is \c NULL.
  69. * \return the next object at depth \p depth included in \p set if \p prev is not \c NULL.
  70. * \return \c NULL if there is no next object.
  71. *
  72. * \note Objects with empty CPU sets are ignored
  73. * (otherwise they would be considered included in any given set).
  74. *
  75. * \note This function cannot work if objects at the given depth do
  76. * not have CPU sets (I/O or Misc objects).
  77. */
  78. static __hwloc_inline hwloc_obj_t
  79. hwloc_get_next_obj_inside_cpuset_by_depth (hwloc_topology_t topology, hwloc_const_cpuset_t set,
  80. int depth, hwloc_obj_t prev)
  81. {
  82. hwloc_obj_t next = hwloc_get_next_obj_by_depth(topology, depth, prev);
  83. if (!next)
  84. return NULL;
  85. while (next && (hwloc_bitmap_iszero(next->cpuset) || !hwloc_bitmap_isincluded(next->cpuset, set)))
  86. next = next->next_cousin;
  87. return next;
  88. }
  89. /** \brief Return the next object of type \p type included in CPU set \p set.
  90. *
  91. * The next invokation should pass the previous return value in \p prev
  92. * so as to obtain the next object in \p set.
  93. *
  94. * \return the first object of type \p type included in \p set if \p prev is \c NULL.
  95. * \return the next object of type \p type included in \p set if \p prev is not \c NULL.
  96. * \return \c NULL if there is no next object.
  97. * \return \c NULL if there is no depth for the given type.
  98. * \return \c NULL if there are multiple depths for the given type,
  99. * the caller should fallback to hwloc_get_next_obj_inside_cpuset_by_depth().
  100. *
  101. * \note Objects with empty CPU sets are ignored
  102. * (otherwise they would be considered included in any given set).
  103. *
  104. * \note This function cannot work if objects of the given type do
  105. * not have CPU sets (I/O or Misc objects).
  106. */
  107. static __hwloc_inline hwloc_obj_t
  108. hwloc_get_next_obj_inside_cpuset_by_type (hwloc_topology_t topology, hwloc_const_cpuset_t set,
  109. hwloc_obj_type_t type, hwloc_obj_t prev)
  110. {
  111. int depth = hwloc_get_type_depth(topology, type);
  112. if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE)
  113. return NULL;
  114. return hwloc_get_next_obj_inside_cpuset_by_depth(topology, set, depth, prev);
  115. }
  116. /** \brief Return the (logically) \p idx -th object at depth \p depth included in CPU set \p set.
  117. *
  118. * \return the object if any, \c NULL otherwise.
  119. *
  120. * \note Objects with empty CPU sets are ignored
  121. * (otherwise they would be considered included in any given set).
  122. *
  123. * \note This function cannot work if objects at the given depth do
  124. * not have CPU sets (I/O or Misc objects).
  125. */
  126. static __hwloc_inline hwloc_obj_t
  127. hwloc_get_obj_inside_cpuset_by_depth (hwloc_topology_t topology, hwloc_const_cpuset_t set,
  128. int depth, unsigned idx) __hwloc_attribute_pure;
  129. static __hwloc_inline hwloc_obj_t
  130. hwloc_get_obj_inside_cpuset_by_depth (hwloc_topology_t topology, hwloc_const_cpuset_t set,
  131. int depth, unsigned idx)
  132. {
  133. hwloc_obj_t obj = hwloc_get_obj_by_depth (topology, depth, 0);
  134. unsigned count = 0;
  135. if (!obj)
  136. return NULL;
  137. while (obj) {
  138. if (!hwloc_bitmap_iszero(obj->cpuset) && hwloc_bitmap_isincluded(obj->cpuset, set)) {
  139. if (count == idx)
  140. return obj;
  141. count++;
  142. }
  143. obj = obj->next_cousin;
  144. }
  145. return NULL;
  146. }
  147. /** \brief Return the \p idx -th object of type \p type included in CPU set \p set.
  148. *
  149. * \return the object if any.
  150. * \return \c NULL if there is no such object.
  151. * \return \c NULL if there is no depth for given type.
  152. * \return \c NULL if there are multiple depths for given type,
  153. * the caller should fallback to hwloc_get_obj_inside_cpuset_by_depth().
  154. *
  155. * \note Objects with empty CPU sets are ignored
  156. * (otherwise they would be considered included in any given set).
  157. *
  158. * \note This function cannot work if objects of the given type do
  159. * not have CPU sets (I/O or Misc objects).
  160. */
  161. static __hwloc_inline hwloc_obj_t
  162. hwloc_get_obj_inside_cpuset_by_type (hwloc_topology_t topology, hwloc_const_cpuset_t set,
  163. hwloc_obj_type_t type, unsigned idx) __hwloc_attribute_pure;
  164. static __hwloc_inline hwloc_obj_t
  165. hwloc_get_obj_inside_cpuset_by_type (hwloc_topology_t topology, hwloc_const_cpuset_t set,
  166. hwloc_obj_type_t type, unsigned idx)
  167. {
  168. int depth = hwloc_get_type_depth(topology, type);
  169. if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE)
  170. return NULL;
  171. return hwloc_get_obj_inside_cpuset_by_depth(topology, set, depth, idx);
  172. }
  173. /** \brief Return the number of objects at depth \p depth included in CPU set \p set.
  174. *
  175. * \return the number of objects.
  176. * \return 0 if the depth is invalid.
  177. *
  178. * \note Objects with empty CPU sets are ignored
  179. * (otherwise they would be considered included in any given set).
  180. *
  181. * \note This function cannot work if objects at the given depth do
  182. * not have CPU sets (I/O or Misc objects).
  183. */
  184. static __hwloc_inline unsigned
  185. hwloc_get_nbobjs_inside_cpuset_by_depth (hwloc_topology_t topology, hwloc_const_cpuset_t set,
  186. int depth) __hwloc_attribute_pure;
  187. static __hwloc_inline unsigned
  188. hwloc_get_nbobjs_inside_cpuset_by_depth (hwloc_topology_t topology, hwloc_const_cpuset_t set,
  189. int depth)
  190. {
  191. hwloc_obj_t obj = hwloc_get_obj_by_depth (topology, depth, 0);
  192. unsigned count = 0;
  193. if (!obj)
  194. return 0;
  195. while (obj) {
  196. if (!hwloc_bitmap_iszero(obj->cpuset) && hwloc_bitmap_isincluded(obj->cpuset, set))
  197. count++;
  198. obj = obj->next_cousin;
  199. }
  200. return count;
  201. }
  202. /** \brief Return the number of objects of type \p type included in CPU set \p set.
  203. *
  204. * \return the number of objects.
  205. * \return 0 if there are no objects of that type in the topology.
  206. * \return -1 if there are multiple levels of objects of that type,
  207. * the caller should fallback to hwloc_get_nbobjs_inside_cpuset_by_depth().
  208. *
  209. * \note Objects with empty CPU sets are ignored
  210. * (otherwise they would be considered included in any given set).
  211. *
  212. * \note This function cannot work if objects of the given type do
  213. * not have CPU sets (I/O objects).
  214. */
  215. static __hwloc_inline int
  216. hwloc_get_nbobjs_inside_cpuset_by_type (hwloc_topology_t topology, hwloc_const_cpuset_t set,
  217. hwloc_obj_type_t type) __hwloc_attribute_pure;
  218. static __hwloc_inline int
  219. hwloc_get_nbobjs_inside_cpuset_by_type (hwloc_topology_t topology, hwloc_const_cpuset_t set,
  220. hwloc_obj_type_t type)
  221. {
  222. int depth = hwloc_get_type_depth(topology, type);
  223. if (depth == HWLOC_TYPE_DEPTH_UNKNOWN)
  224. return 0;
  225. if (depth == HWLOC_TYPE_DEPTH_MULTIPLE)
  226. return -1; /* FIXME: agregate nbobjs from different levels? */
  227. return (int) hwloc_get_nbobjs_inside_cpuset_by_depth(topology, set, depth);
  228. }
  229. /** \brief Return the logical index among the objects included in CPU set \p set.
  230. *
  231. * Consult all objects in the same level as \p obj and inside CPU set \p set
  232. * in the logical order, and return the index of \p obj within them.
  233. * If \p set covers the entire topology, this is the logical index of \p obj.
  234. * Otherwise, this is similar to a logical index within the part of the topology
  235. * defined by CPU set \p set.
  236. *
  237. * \return the logical index among the objects included in the set if any.
  238. * \return -1 if the object is not included in the set.
  239. *
  240. * \note Objects with empty CPU sets are ignored
  241. * (otherwise they would be considered included in any given set).
  242. *
  243. * \note This function cannot work if obj does not have CPU sets (I/O objects).
  244. */
  245. static __hwloc_inline int
  246. hwloc_get_obj_index_inside_cpuset (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_cpuset_t set,
  247. hwloc_obj_t obj) __hwloc_attribute_pure;
  248. static __hwloc_inline int
  249. hwloc_get_obj_index_inside_cpuset (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_cpuset_t set,
  250. hwloc_obj_t obj)
  251. {
  252. int idx = 0;
  253. if (!hwloc_bitmap_isincluded(obj->cpuset, set))
  254. return -1;
  255. /* count how many objects are inside the cpuset on the way from us to the beginning of the level */
  256. while ((obj = obj->prev_cousin) != NULL)
  257. if (!hwloc_bitmap_iszero(obj->cpuset) && hwloc_bitmap_isincluded(obj->cpuset, set))
  258. idx++;
  259. return idx;
  260. }
  261. /** @} */
  262. /** \defgroup hwlocality_helper_find_covering Finding Objects covering at least CPU set
  263. * @{
  264. */
  265. /** \brief Get the child covering at least CPU set \p set.
  266. *
  267. * \return the child that covers the set entirely.
  268. * \return \c NULL if no child matches or if \p set is empty.
  269. *
  270. * \note This function cannot work if parent does not have a CPU set (I/O or Misc objects).
  271. */
  272. static __hwloc_inline hwloc_obj_t
  273. hwloc_get_child_covering_cpuset (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_cpuset_t set,
  274. hwloc_obj_t parent) __hwloc_attribute_pure;
  275. static __hwloc_inline hwloc_obj_t
  276. hwloc_get_child_covering_cpuset (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_cpuset_t set,
  277. hwloc_obj_t parent)
  278. {
  279. hwloc_obj_t child;
  280. if (hwloc_bitmap_iszero(set))
  281. return NULL;
  282. child = parent->first_child;
  283. while (child) {
  284. if (child->cpuset && hwloc_bitmap_isincluded(set, child->cpuset))
  285. return child;
  286. child = child->next_sibling;
  287. }
  288. return NULL;
  289. }
  290. /** \brief Get the lowest object covering at least CPU set \p set
  291. *
  292. * \return the lowest object covering the set entirely.
  293. * \return \c NULL if no object matches or if \p set is empty.
  294. */
  295. static __hwloc_inline hwloc_obj_t
  296. hwloc_get_obj_covering_cpuset (hwloc_topology_t topology, hwloc_const_cpuset_t set) __hwloc_attribute_pure;
  297. static __hwloc_inline hwloc_obj_t
  298. hwloc_get_obj_covering_cpuset (hwloc_topology_t topology, hwloc_const_cpuset_t set)
  299. {
  300. struct hwloc_obj *current = hwloc_get_root_obj(topology);
  301. if (hwloc_bitmap_iszero(set) || !hwloc_bitmap_isincluded(set, current->cpuset))
  302. return NULL;
  303. while (1) {
  304. hwloc_obj_t child = hwloc_get_child_covering_cpuset(topology, set, current);
  305. if (!child)
  306. return current;
  307. current = child;
  308. }
  309. }
  310. /** \brief Iterate through same-depth objects covering at least CPU set \p set
  311. *
  312. * The next invokation should pass the previous return value in \p prev so as
  313. * to obtain the next object covering at least another part of \p set.
  314. *
  315. * \return the first object at depth \p depth covering at least part of CPU set \p set
  316. * if object \p prev is \c NULL.
  317. * \return the next one if \p prev is not \c NULL.
  318. * \return \c NULL if there is no next object.
  319. *
  320. * \note This function cannot work if objects at the given depth do
  321. * not have CPU sets (I/O or Misc objects).
  322. */
  323. static __hwloc_inline hwloc_obj_t
  324. hwloc_get_next_obj_covering_cpuset_by_depth(hwloc_topology_t topology, hwloc_const_cpuset_t set,
  325. int depth, hwloc_obj_t prev)
  326. {
  327. hwloc_obj_t next = hwloc_get_next_obj_by_depth(topology, depth, prev);
  328. if (!next)
  329. return NULL;
  330. while (next && !hwloc_bitmap_intersects(set, next->cpuset))
  331. next = next->next_cousin;
  332. return next;
  333. }
  334. /** \brief Iterate through same-type objects covering at least CPU set \p set
  335. *
  336. * The next invokation should pass the previous return value in \p prev so as to obtain
  337. * the next object of type \p type covering at least another part of \p set.
  338. *
  339. * \return the first object of type \p type covering at least part of CPU set \p set
  340. * if object \p prev is \c NULL.
  341. * \return the next one if \p prev is not \c NULL.
  342. * \return \c NULL if there is no next object.
  343. * \return \c NULL if there is no depth for the given type.
  344. * \return \c NULL if there are multiple depths for the given type,
  345. * the caller should fallback to hwloc_get_next_obj_covering_cpuset_by_depth().
  346. *
  347. * \note This function cannot work if objects of the given type do
  348. * not have CPU sets (I/O or Misc objects).
  349. */
  350. static __hwloc_inline hwloc_obj_t
  351. hwloc_get_next_obj_covering_cpuset_by_type(hwloc_topology_t topology, hwloc_const_cpuset_t set,
  352. hwloc_obj_type_t type, hwloc_obj_t prev)
  353. {
  354. int depth = hwloc_get_type_depth(topology, type);
  355. if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE)
  356. return NULL;
  357. return hwloc_get_next_obj_covering_cpuset_by_depth(topology, set, depth, prev);
  358. }
  359. /** @} */
  360. /** \defgroup hwlocality_helper_ancestors Looking at Ancestor and Child Objects
  361. * @{
  362. *
  363. * Be sure to see the figure in \ref termsanddefs that shows a
  364. * complete topology tree, including depths, child/sibling/cousin
  365. * relationships, and an example of an asymmetric topology where one
  366. * package has fewer caches than its peers.
  367. */
  368. /** \brief Returns the ancestor object of \p obj at depth \p depth.
  369. *
  370. * \return the ancestor if any.
  371. * \return \c NULL if no such ancestor exists.
  372. *
  373. * \note \p depth should not be the depth of PU or NUMA objects
  374. * since they are ancestors of no objects (except Misc or I/O).
  375. * This function rather expects an intermediate level depth,
  376. * such as the depth of Packages, Cores, or Caches.
  377. */
  378. static __hwloc_inline hwloc_obj_t
  379. hwloc_get_ancestor_obj_by_depth (hwloc_topology_t topology __hwloc_attribute_unused, int depth, hwloc_obj_t obj) __hwloc_attribute_pure;
  380. static __hwloc_inline hwloc_obj_t
  381. hwloc_get_ancestor_obj_by_depth (hwloc_topology_t topology __hwloc_attribute_unused, int depth, hwloc_obj_t obj)
  382. {
  383. hwloc_obj_t ancestor = obj;
  384. if (obj->depth < depth)
  385. return NULL;
  386. while (ancestor && ancestor->depth > depth)
  387. ancestor = ancestor->parent;
  388. return ancestor;
  389. }
  390. /** \brief Returns the ancestor object of \p obj with type \p type.
  391. *
  392. * \return the ancestor if any.
  393. * \return \c NULL if no such ancestor exists.
  394. *
  395. * \note if multiple matching ancestors exist (e.g. multiple levels of ::HWLOC_OBJ_GROUP)
  396. * the lowest one is returned.
  397. *
  398. * \note \p type should not be ::HWLOC_OBJ_PU or ::HWLOC_OBJ_NUMANODE
  399. * since these objects are ancestors of no objects (except Misc or I/O).
  400. * This function rather expects an intermediate object type,
  401. * such as ::HWLOC_OBJ_PACKAGE, ::HWLOC_OBJ_CORE, etc.
  402. */
  403. static __hwloc_inline hwloc_obj_t
  404. 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;
  405. static __hwloc_inline hwloc_obj_t
  406. hwloc_get_ancestor_obj_by_type (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_type_t type, hwloc_obj_t obj)
  407. {
  408. hwloc_obj_t ancestor = obj->parent;
  409. while (ancestor && ancestor->type != type)
  410. ancestor = ancestor->parent;
  411. return ancestor;
  412. }
  413. /** \brief Returns the common parent object to objects \p obj1 and \p obj2.
  414. *
  415. * \return the common ancestor.
  416. *
  417. * \note This function cannot return \c NULL.
  418. */
  419. static __hwloc_inline hwloc_obj_t
  420. hwloc_get_common_ancestor_obj (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj1, hwloc_obj_t obj2) __hwloc_attribute_pure;
  421. static __hwloc_inline hwloc_obj_t
  422. hwloc_get_common_ancestor_obj (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj1, hwloc_obj_t obj2)
  423. {
  424. /* the loop isn't so easy since intermediate ancestors may have
  425. * different depth, causing us to alternate between using obj1->parent
  426. * and obj2->parent. Also, even if at some point we find ancestors of
  427. * of the same depth, their ancestors may have different depth again.
  428. */
  429. while (obj1 != obj2) {
  430. while (obj1->depth > obj2->depth)
  431. obj1 = obj1->parent;
  432. while (obj2->depth > obj1->depth)
  433. obj2 = obj2->parent;
  434. if (obj1 != obj2 && obj1->depth == obj2->depth) {
  435. obj1 = obj1->parent;
  436. obj2 = obj2->parent;
  437. }
  438. }
  439. return obj1;
  440. }
  441. /** \brief Returns true if \p obj is inside the subtree beginning with ancestor object \p subtree_root.
  442. *
  443. * \return 1 is the object is in the subtree, 0 otherwise.
  444. *
  445. * \note This function cannot work if \p obj and \p subtree_root objects do
  446. * not have CPU sets (I/O or Misc objects).
  447. */
  448. static __hwloc_inline int
  449. hwloc_obj_is_in_subtree (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj, hwloc_obj_t subtree_root) __hwloc_attribute_pure;
  450. static __hwloc_inline int
  451. hwloc_obj_is_in_subtree (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj, hwloc_obj_t subtree_root)
  452. {
  453. return obj->cpuset && subtree_root->cpuset && hwloc_bitmap_isincluded(obj->cpuset, subtree_root->cpuset);
  454. }
  455. /** \brief Return the next child.
  456. *
  457. * Return the next child among the normal children list,
  458. * then among the memory children list, then among the I/O
  459. * children list, then among the Misc children list.
  460. *
  461. * \return the first child if \p prev is \c NULL.
  462. * \return the next child if \p prev is not \c NULL.
  463. * \return \c NULL when there is no next child.
  464. */
  465. static __hwloc_inline hwloc_obj_t
  466. hwloc_get_next_child (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t parent, hwloc_obj_t prev)
  467. {
  468. hwloc_obj_t obj;
  469. int state = 0;
  470. if (prev) {
  471. if (prev->type == HWLOC_OBJ_MISC)
  472. state = 3;
  473. else if (prev->type == HWLOC_OBJ_BRIDGE || prev->type == HWLOC_OBJ_PCI_DEVICE || prev->type == HWLOC_OBJ_OS_DEVICE)
  474. state = 2;
  475. else if (prev->type == HWLOC_OBJ_NUMANODE || prev->type == HWLOC_OBJ_MEMCACHE)
  476. state = 1;
  477. obj = prev->next_sibling;
  478. } else {
  479. obj = parent->first_child;
  480. }
  481. if (!obj && state == 0) {
  482. obj = parent->memory_first_child;
  483. state = 1;
  484. }
  485. if (!obj && state == 1) {
  486. obj = parent->io_first_child;
  487. state = 2;
  488. }
  489. if (!obj && state == 2) {
  490. obj = parent->misc_first_child;
  491. state = 3;
  492. }
  493. return obj;
  494. }
  495. /** @} */
  496. /** \defgroup hwlocality_helper_types Kinds of object Type
  497. * @{
  498. *
  499. * Each object type is
  500. * either Normal (i.e. hwloc_obj_type_is_normal() returns 1),
  501. * or Memory (i.e. hwloc_obj_type_is_memory() returns 1)
  502. * or I/O (i.e. hwloc_obj_type_is_io() returns 1)
  503. * or Misc (i.e. equal to ::HWLOC_OBJ_MISC).
  504. * It cannot be of more than one of these kinds.
  505. */
  506. /** \brief Check whether an object type is Normal.
  507. *
  508. * Normal objects are objects of the main CPU hierarchy
  509. * (Machine, Package, Core, PU, CPU caches, etc.),
  510. * but they are not NUMA nodes, I/O devices or Misc objects.
  511. *
  512. * They are attached to parent as Normal children,
  513. * not as Memory, I/O or Misc children.
  514. *
  515. * \return 1 if an object of type \p type is a Normal object, 0 otherwise.
  516. */
  517. HWLOC_DECLSPEC int
  518. hwloc_obj_type_is_normal(hwloc_obj_type_t type);
  519. /** \brief Check whether an object type is I/O.
  520. *
  521. * I/O objects are objects attached to their parents
  522. * in the I/O children list.
  523. * This current includes Bridges, PCI and OS devices.
  524. *
  525. * \return 1 if an object of type \p type is a I/O object, 0 otherwise.
  526. */
  527. HWLOC_DECLSPEC int
  528. hwloc_obj_type_is_io(hwloc_obj_type_t type);
  529. /** \brief Check whether an object type is Memory.
  530. *
  531. * Memory objects are objects attached to their parents
  532. * in the Memory children list.
  533. * This current includes NUMA nodes and Memory-side caches.
  534. *
  535. * \return 1 if an object of type \p type is a Memory object, 0 otherwise.
  536. */
  537. HWLOC_DECLSPEC int
  538. hwloc_obj_type_is_memory(hwloc_obj_type_t type);
  539. /** \brief Check whether an object type is a CPU Cache (Data, Unified or Instruction).
  540. *
  541. * Memory-side caches are not CPU caches.
  542. *
  543. * \return 1 if an object of type \p type is a Cache, 0 otherwise.
  544. */
  545. HWLOC_DECLSPEC int
  546. hwloc_obj_type_is_cache(hwloc_obj_type_t type);
  547. /** \brief Check whether an object type is a CPU Data or Unified Cache.
  548. *
  549. * Memory-side caches are not CPU caches.
  550. *
  551. * \return 1 if an object of type \p type is a CPU Data or Unified Cache, 0 otherwise.
  552. */
  553. HWLOC_DECLSPEC int
  554. hwloc_obj_type_is_dcache(hwloc_obj_type_t type);
  555. /** \brief Check whether an object type is a CPU Instruction Cache,
  556. *
  557. * Memory-side caches are not CPU caches.
  558. *
  559. * \return 1 if an object of type \p type is a CPU Instruction Cache, 0 otherwise.
  560. */
  561. HWLOC_DECLSPEC int
  562. hwloc_obj_type_is_icache(hwloc_obj_type_t type);
  563. /** @} */
  564. /** \defgroup hwlocality_helper_find_cache Looking at Cache Objects
  565. * @{
  566. */
  567. /** \brief Find the depth of cache objects matching cache level and type.
  568. *
  569. * Return the depth of the topology level that contains cache objects
  570. * whose attributes match \p cachelevel and \p cachetype.
  571. * This function is identical to calling hwloc_get_type_depth() with the
  572. * corresponding type such as ::HWLOC_OBJ_L1ICACHE, except that it may
  573. * also return a Unified cache when looking for an instruction cache.
  574. *
  575. * \return the depth of the unique matching unified cache level is returned
  576. * if \p cachetype is ::HWLOC_OBJ_CACHE_UNIFIED.
  577. *
  578. * \return the depth of either a matching cache level or a unified cache level
  579. * if \p cachetype is ::HWLOC_OBJ_CACHE_DATA or ::HWLOC_OBJ_CACHE_INSTRUCTION.
  580. *
  581. * \return the depth of the matching level
  582. * if \p cachetype is \c -1 but only one level matches.
  583. *
  584. * \return ::HWLOC_TYPE_DEPTH_MULTIPLE
  585. * if \p cachetype is \c -1 but multiple levels match.
  586. *
  587. * \return ::HWLOC_TYPE_DEPTH_UNKNOWN if no cache level matches.
  588. */
  589. static __hwloc_inline int
  590. hwloc_get_cache_type_depth (hwloc_topology_t topology,
  591. unsigned cachelevel, hwloc_obj_cache_type_t cachetype)
  592. {
  593. int depth;
  594. int found = HWLOC_TYPE_DEPTH_UNKNOWN;
  595. for (depth=0; ; depth++) {
  596. hwloc_obj_t obj = hwloc_get_obj_by_depth(topology, depth, 0);
  597. if (!obj)
  598. break;
  599. if (!hwloc_obj_type_is_dcache(obj->type) || obj->attr->cache.depth != cachelevel)
  600. /* doesn't match, try next depth */
  601. continue;
  602. if (cachetype == (hwloc_obj_cache_type_t) -1) {
  603. if (found != HWLOC_TYPE_DEPTH_UNKNOWN) {
  604. /* second match, return MULTIPLE */
  605. return HWLOC_TYPE_DEPTH_MULTIPLE;
  606. }
  607. /* first match, mark it as found */
  608. found = depth;
  609. continue;
  610. }
  611. if (obj->attr->cache.type == cachetype || obj->attr->cache.type == HWLOC_OBJ_CACHE_UNIFIED)
  612. /* exact match (either unified is alone, or we match instruction or data), return immediately */
  613. return depth;
  614. }
  615. /* went to the bottom, return what we found */
  616. return found;
  617. }
  618. /** \brief Get the first data (or unified) cache covering a cpuset \p set
  619. *
  620. * \return a covering cache, or \c NULL if no cache matches.
  621. */
  622. static __hwloc_inline hwloc_obj_t
  623. hwloc_get_cache_covering_cpuset (hwloc_topology_t topology, hwloc_const_cpuset_t set) __hwloc_attribute_pure;
  624. static __hwloc_inline hwloc_obj_t
  625. hwloc_get_cache_covering_cpuset (hwloc_topology_t topology, hwloc_const_cpuset_t set)
  626. {
  627. hwloc_obj_t current = hwloc_get_obj_covering_cpuset(topology, set);
  628. while (current) {
  629. if (hwloc_obj_type_is_dcache(current->type))
  630. return current;
  631. current = current->parent;
  632. }
  633. return NULL;
  634. }
  635. /** \brief Get the first data (or unified) cache shared between an object and somebody else.
  636. *
  637. * \return a shared cache.
  638. * \return \c NULL if no cache matches or if an invalid object is given (e.g. I/O object).
  639. */
  640. static __hwloc_inline hwloc_obj_t
  641. hwloc_get_shared_cache_covering_obj (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj) __hwloc_attribute_pure;
  642. static __hwloc_inline hwloc_obj_t
  643. hwloc_get_shared_cache_covering_obj (hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj)
  644. {
  645. hwloc_obj_t current = obj->parent;
  646. if (!obj->cpuset)
  647. return NULL;
  648. while (current) {
  649. if (!hwloc_bitmap_isequal(current->cpuset, obj->cpuset)
  650. && hwloc_obj_type_is_dcache(current->type))
  651. return current;
  652. current = current->parent;
  653. }
  654. return NULL;
  655. }
  656. /** @} */
  657. /** \defgroup hwlocality_helper_find_misc Finding objects, miscellaneous helpers
  658. * @{
  659. *
  660. * Be sure to see the figure in \ref termsanddefs that shows a
  661. * complete topology tree, including depths, child/sibling/cousin
  662. * relationships, and an example of an asymmetric topology where one
  663. * package has fewer caches than its peers.
  664. */
  665. /** \brief Remove simultaneous multithreading PUs from a CPU set.
  666. *
  667. * For each core in \p topology, if \p cpuset contains some PUs of that core,
  668. * modify \p cpuset to only keep a single PU for that core.
  669. *
  670. * \p which specifies which PU will be kept.
  671. * PU are considered in physical index order.
  672. * If 0, for each core, the function keeps the first PU that was originally set in \p cpuset.
  673. *
  674. * If \p which is larger than the number of PUs in a core there were originally set in \p cpuset,
  675. * no PU is kept for that core.
  676. *
  677. * \return 0.
  678. *
  679. * \note PUs that are not below a Core object are ignored
  680. * (for instance if the topology does not contain any Core object).
  681. * None of them is removed from \p cpuset.
  682. */
  683. HWLOC_DECLSPEC int hwloc_bitmap_singlify_per_core(hwloc_topology_t topology, hwloc_bitmap_t cpuset, unsigned which);
  684. /** \brief Returns the object of type ::HWLOC_OBJ_PU with \p os_index.
  685. *
  686. * This function is useful for converting a CPU set into the PU
  687. * objects it contains.
  688. * When retrieving the current binding (e.g. with hwloc_get_cpubind()),
  689. * one may iterate over the bits of the resulting CPU set with
  690. * hwloc_bitmap_foreach_begin(), and find the corresponding PUs
  691. * with this function.
  692. *
  693. * \return the PU object, or \c NULL if none matches.
  694. */
  695. static __hwloc_inline hwloc_obj_t
  696. hwloc_get_pu_obj_by_os_index(hwloc_topology_t topology, unsigned os_index) __hwloc_attribute_pure;
  697. static __hwloc_inline hwloc_obj_t
  698. hwloc_get_pu_obj_by_os_index(hwloc_topology_t topology, unsigned os_index)
  699. {
  700. hwloc_obj_t obj = NULL;
  701. while ((obj = hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_PU, obj)) != NULL)
  702. if (obj->os_index == os_index)
  703. return obj;
  704. return NULL;
  705. }
  706. /** \brief Returns the object of type ::HWLOC_OBJ_NUMANODE with \p os_index.
  707. *
  708. * This function is useful for converting a nodeset into the NUMA node
  709. * objects it contains.
  710. * When retrieving the current binding (e.g. with hwloc_get_membind() with HWLOC_MEMBIND_BYNODESET),
  711. * one may iterate over the bits of the resulting nodeset with
  712. * hwloc_bitmap_foreach_begin(), and find the corresponding NUMA nodes
  713. * with this function.
  714. *
  715. * \return the NUMA node object, or \c NULL if none matches.
  716. */
  717. static __hwloc_inline hwloc_obj_t
  718. hwloc_get_numanode_obj_by_os_index(hwloc_topology_t topology, unsigned os_index) __hwloc_attribute_pure;
  719. static __hwloc_inline hwloc_obj_t
  720. hwloc_get_numanode_obj_by_os_index(hwloc_topology_t topology, unsigned os_index)
  721. {
  722. hwloc_obj_t obj = NULL;
  723. while ((obj = hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_NUMANODE, obj)) != NULL)
  724. if (obj->os_index == os_index)
  725. return obj;
  726. return NULL;
  727. }
  728. /** \brief Do a depth-first traversal of the topology to find and sort
  729. *
  730. * all objects that are at the same depth than \p src.
  731. * Report in \p objs up to \p max physically closest ones to \p src.
  732. *
  733. * \return the number of objects returned in \p objs.
  734. *
  735. * \return 0 if \p src is an I/O object.
  736. *
  737. * \note This function requires the \p src object to have a CPU set.
  738. */
  739. /* TODO: rather provide an iterator? Provide a way to know how much should be allocated? By returning the total number of objects instead? */
  740. HWLOC_DECLSPEC unsigned hwloc_get_closest_objs (hwloc_topology_t topology, hwloc_obj_t src, hwloc_obj_t * __hwloc_restrict objs, unsigned max);
  741. /** \brief Find an object below another object, both specified by types and indexes.
  742. *
  743. * Start from the top system object and find object of type \p type1
  744. * and logical index \p idx1. Then look below this object and find another
  745. * object of type \p type2 and logical index \p idx2. Indexes are specified
  746. * within the parent, not withing the entire system.
  747. *
  748. * For instance, if type1 is PACKAGE, idx1 is 2, type2 is CORE and idx2
  749. * is 3, return the fourth core object below the third package.
  750. *
  751. * \return a matching object if any, \c NULL otherwise.
  752. *
  753. * \note This function requires these objects to have a CPU set.
  754. */
  755. static __hwloc_inline hwloc_obj_t
  756. hwloc_get_obj_below_by_type (hwloc_topology_t topology,
  757. hwloc_obj_type_t type1, unsigned idx1,
  758. hwloc_obj_type_t type2, unsigned idx2) __hwloc_attribute_pure;
  759. static __hwloc_inline hwloc_obj_t
  760. hwloc_get_obj_below_by_type (hwloc_topology_t topology,
  761. hwloc_obj_type_t type1, unsigned idx1,
  762. hwloc_obj_type_t type2, unsigned idx2)
  763. {
  764. hwloc_obj_t obj;
  765. obj = hwloc_get_obj_by_type (topology, type1, idx1);
  766. if (!obj)
  767. return NULL;
  768. return hwloc_get_obj_inside_cpuset_by_type(topology, obj->cpuset, type2, idx2);
  769. }
  770. /** \brief Find an object below a chain of objects specified by types and indexes.
  771. *
  772. * This is a generalized version of hwloc_get_obj_below_by_type().
  773. *
  774. * Arrays \p typev and \p idxv must contain \p nr types and indexes.
  775. *
  776. * Start from the top system object and walk the arrays \p typev and \p idxv.
  777. * For each type and logical index couple in the arrays, look under the previously found
  778. * object to find the index-th object of the given type.
  779. * Indexes are specified within the parent, not withing the entire system.
  780. *
  781. * For instance, if nr is 3, typev contains NODE, PACKAGE and CORE,
  782. * and idxv contains 0, 1 and 2, return the third core object below
  783. * the second package below the first NUMA node.
  784. *
  785. * \return a matching object if any, \c NULL otherwise.
  786. *
  787. * \note This function requires all these objects and the root object
  788. * to have a CPU set.
  789. */
  790. static __hwloc_inline hwloc_obj_t
  791. hwloc_get_obj_below_array_by_type (hwloc_topology_t topology, int nr, hwloc_obj_type_t *typev, unsigned *idxv) __hwloc_attribute_pure;
  792. static __hwloc_inline hwloc_obj_t
  793. hwloc_get_obj_below_array_by_type (hwloc_topology_t topology, int nr, hwloc_obj_type_t *typev, unsigned *idxv)
  794. {
  795. hwloc_obj_t obj = hwloc_get_root_obj(topology);
  796. int i;
  797. for(i=0; i<nr; i++) {
  798. if (!obj)
  799. return NULL;
  800. obj = hwloc_get_obj_inside_cpuset_by_type(topology, obj->cpuset, typev[i], idxv[i]);
  801. }
  802. return obj;
  803. }
  804. /** \brief Return an object of a different type with same locality.
  805. *
  806. * If the source object \p src is a normal or memory type,
  807. * this function returns an object of type \p type with same
  808. * CPU and node sets, either below or above in the hierarchy.
  809. *
  810. * If the source object \p src is a PCI or an OS device within a PCI
  811. * device, the function may either return that PCI device, or another
  812. * OS device in the same PCI parent.
  813. * This may for instance be useful for converting between OS devices
  814. * such as "nvml0" or "rsmi1" used in distance structures into the
  815. * the PCI device, or the CUDA or OpenCL OS device that correspond
  816. * to the same physical card.
  817. *
  818. * If not \c NULL, parameter \p subtype only select objects whose
  819. * subtype attribute exists and is \p subtype (case-insensitively),
  820. * for instance "OpenCL" or "CUDA".
  821. *
  822. * If not \c NULL, parameter \p nameprefix only selects objects whose
  823. * name attribute exists and starts with \p nameprefix (case-insensitively),
  824. * for instance "rsmi" for matching "rsmi0".
  825. *
  826. * If multiple objects match, the first one is returned.
  827. *
  828. * This function will not walk the hierarchy across bridges since
  829. * the PCI locality may become different.
  830. * This function cannot also convert between normal/memory objects
  831. * and I/O or Misc objects.
  832. *
  833. * \p flags must be \c 0 for now.
  834. *
  835. * \return An object with identical locality,
  836. * matching \p subtype and \p nameprefix if any.
  837. *
  838. * \return \c NULL if no matching object could be found,
  839. * or if the source object and target type are incompatible,
  840. * for instance if converting between CPU and I/O objects.
  841. */
  842. HWLOC_DECLSPEC hwloc_obj_t
  843. hwloc_get_obj_with_same_locality(hwloc_topology_t topology, hwloc_obj_t src,
  844. hwloc_obj_type_t type, const char *subtype, const char *nameprefix,
  845. unsigned long flags);
  846. /** @} */
  847. /** \defgroup hwlocality_helper_distribute Distributing items over a topology
  848. * @{
  849. */
  850. /** \brief Flags to be given to hwloc_distrib().
  851. */
  852. enum hwloc_distrib_flags_e {
  853. /** \brief Distrib in reverse order, starting from the last objects.
  854. * \hideinitializer
  855. */
  856. HWLOC_DISTRIB_FLAG_REVERSE = (1UL<<0)
  857. };
  858. /** \brief Distribute \p n items over the topology under \p roots
  859. *
  860. * Array \p set will be filled with \p n cpusets recursively distributed
  861. * linearly over the topology under objects \p roots, down to depth \p until
  862. * (which can be INT_MAX to distribute down to the finest level).
  863. *
  864. * \p n_roots is usually 1 and \p roots only contains the topology root object
  865. * so as to distribute over the entire topology.
  866. *
  867. * This is typically useful when an application wants to distribute \p n
  868. * threads over a machine, giving each of them as much private cache as
  869. * possible and keeping them locally in number order.
  870. *
  871. * The caller may typically want to also call hwloc_bitmap_singlify()
  872. * before binding a thread so that it does not move at all.
  873. *
  874. * \p flags should be 0 or a OR'ed set of ::hwloc_distrib_flags_e.
  875. *
  876. * \return 0 on success, -1 on error.
  877. *
  878. * \note This function requires the \p roots objects to have a CPU set.
  879. */
  880. static __hwloc_inline int
  881. hwloc_distrib(hwloc_topology_t topology,
  882. hwloc_obj_t *roots, unsigned n_roots,
  883. hwloc_cpuset_t *set,
  884. unsigned n,
  885. int until, unsigned long flags)
  886. {
  887. unsigned i;
  888. unsigned tot_weight;
  889. unsigned given, givenweight;
  890. hwloc_cpuset_t *cpusetp = set;
  891. if (flags & ~HWLOC_DISTRIB_FLAG_REVERSE) {
  892. errno = EINVAL;
  893. return -1;
  894. }
  895. tot_weight = 0;
  896. for (i = 0; i < n_roots; i++)
  897. tot_weight += (unsigned) hwloc_bitmap_weight(roots[i]->cpuset);
  898. for (i = 0, given = 0, givenweight = 0; i < n_roots; i++) {
  899. unsigned chunk, weight;
  900. hwloc_obj_t root = roots[flags & HWLOC_DISTRIB_FLAG_REVERSE ? n_roots-1-i : i];
  901. hwloc_cpuset_t cpuset = root->cpuset;
  902. while (!hwloc_obj_type_is_normal(root->type))
  903. /* If memory/io/misc, walk up to normal parent */
  904. root = root->parent;
  905. weight = (unsigned) hwloc_bitmap_weight(cpuset);
  906. if (!weight)
  907. continue;
  908. /* Give to root a chunk proportional to its weight.
  909. * If previous chunks got rounded-up, we may get a bit less. */
  910. chunk = (( (givenweight+weight) * n + tot_weight-1) / tot_weight)
  911. - (( givenweight * n + tot_weight-1) / tot_weight);
  912. if (!root->arity || chunk <= 1 || root->depth >= until) {
  913. /* We can't split any more, put everything there. */
  914. if (chunk) {
  915. /* Fill cpusets with ours */
  916. unsigned j;
  917. for (j=0; j < chunk; j++)
  918. cpusetp[j] = hwloc_bitmap_dup(cpuset);
  919. } else {
  920. /* We got no chunk, just merge our cpuset to a previous one
  921. * (the first chunk cannot be empty)
  922. * so that this root doesn't get ignored.
  923. */
  924. assert(given);
  925. hwloc_bitmap_or(cpusetp[-1], cpusetp[-1], cpuset);
  926. }
  927. } else {
  928. /* Still more to distribute, recurse into children */
  929. hwloc_distrib(topology, root->children, root->arity, cpusetp, chunk, until, flags);
  930. }
  931. cpusetp += chunk;
  932. given += chunk;
  933. givenweight += weight;
  934. }
  935. return 0;
  936. }
  937. /** @} */
  938. /** \defgroup hwlocality_helper_topology_sets CPU and node sets of entire topologies
  939. * @{
  940. */
  941. /** \brief Get complete CPU set
  942. *
  943. * \return the complete CPU set of processors of the system.
  944. *
  945. * \note This function cannot return \c NULL.
  946. *
  947. * \note The returned cpuset is not newly allocated and should thus not be
  948. * changed or freed; hwloc_bitmap_dup() must be used to obtain a local copy.
  949. *
  950. * \note This is equivalent to retrieving the root object complete CPU-set.
  951. */
  952. HWLOC_DECLSPEC hwloc_const_cpuset_t
  953. hwloc_topology_get_complete_cpuset(hwloc_topology_t topology) __hwloc_attribute_pure;
  954. /** \brief Get topology CPU set
  955. *
  956. * \return the CPU set of processors of the system for which hwloc
  957. * provides topology information. This is equivalent to the cpuset of the
  958. * system object.
  959. *
  960. * \note This function cannot return \c NULL.
  961. *
  962. * \note The returned cpuset is not newly allocated and should thus not be
  963. * changed or freed; hwloc_bitmap_dup() must be used to obtain a local copy.
  964. *
  965. * \note This is equivalent to retrieving the root object CPU-set.
  966. */
  967. HWLOC_DECLSPEC hwloc_const_cpuset_t
  968. hwloc_topology_get_topology_cpuset(hwloc_topology_t topology) __hwloc_attribute_pure;
  969. /** \brief Get allowed CPU set
  970. *
  971. * \return the CPU set of allowed processors of the system.
  972. *
  973. * \note This function cannot return \c NULL.
  974. *
  975. * \note If the topology flag ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED was not set,
  976. * this is identical to hwloc_topology_get_topology_cpuset(), which means
  977. * all PUs are allowed.
  978. *
  979. * \note If ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED was set, applying
  980. * hwloc_bitmap_intersects() on the result of this function and on an object
  981. * cpuset checks whether there are allowed PUs inside that object.
  982. * Applying hwloc_bitmap_and() returns the list of these allowed PUs.
  983. *
  984. * \note The returned cpuset is not newly allocated and should thus not be
  985. * changed or freed, hwloc_bitmap_dup() must be used to obtain a local copy.
  986. */
  987. HWLOC_DECLSPEC hwloc_const_cpuset_t
  988. hwloc_topology_get_allowed_cpuset(hwloc_topology_t topology) __hwloc_attribute_pure;
  989. /** \brief Get complete node set
  990. *
  991. * \return the complete node set of memory of the system.
  992. *
  993. * \note This function cannot return \c NULL.
  994. *
  995. * \note The returned nodeset is not newly allocated and should thus not be
  996. * changed or freed; hwloc_bitmap_dup() must be used to obtain a local copy.
  997. *
  998. * \note This is equivalent to retrieving the root object complete nodeset.
  999. */
  1000. HWLOC_DECLSPEC hwloc_const_nodeset_t
  1001. hwloc_topology_get_complete_nodeset(hwloc_topology_t topology) __hwloc_attribute_pure;
  1002. /** \brief Get topology node set
  1003. *
  1004. * \return the node set of memory of the system for which hwloc
  1005. * provides topology information. This is equivalent to the nodeset of the
  1006. * system object.
  1007. *
  1008. * \note This function cannot return \c NULL.
  1009. *
  1010. * \note The returned nodeset is not newly allocated and should thus not be
  1011. * changed or freed; hwloc_bitmap_dup() must be used to obtain a local copy.
  1012. *
  1013. * \note This is equivalent to retrieving the root object nodeset.
  1014. */
  1015. HWLOC_DECLSPEC hwloc_const_nodeset_t
  1016. hwloc_topology_get_topology_nodeset(hwloc_topology_t topology) __hwloc_attribute_pure;
  1017. /** \brief Get allowed node set
  1018. *
  1019. * \return the node set of allowed memory of the system.
  1020. *
  1021. * \note This function cannot return \c NULL.
  1022. *
  1023. * \note If the topology flag ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED was not set,
  1024. * this is identical to hwloc_topology_get_topology_nodeset(), which means
  1025. * all NUMA nodes are allowed.
  1026. *
  1027. * \note If ::HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED was set, applying
  1028. * hwloc_bitmap_intersects() on the result of this function and on an object
  1029. * nodeset checks whether there are allowed NUMA nodes inside that object.
  1030. * Applying hwloc_bitmap_and() returns the list of these allowed NUMA nodes.
  1031. *
  1032. * \note The returned nodeset is not newly allocated and should thus not be
  1033. * changed or freed, hwloc_bitmap_dup() must be used to obtain a local copy.
  1034. */
  1035. HWLOC_DECLSPEC hwloc_const_nodeset_t
  1036. hwloc_topology_get_allowed_nodeset(hwloc_topology_t topology) __hwloc_attribute_pure;
  1037. /** @} */
  1038. /** \defgroup hwlocality_helper_nodeset_convert Converting between CPU sets and node sets
  1039. *
  1040. * @{
  1041. */
  1042. /** \brief Convert a CPU set into a NUMA node set
  1043. *
  1044. * For each PU included in the input \p _cpuset, set the corresponding
  1045. * local NUMA node(s) in the output \p nodeset.
  1046. *
  1047. * If some NUMA nodes have no CPUs at all, this function never sets their
  1048. * indexes in the output node set, even if a full CPU set is given in input.
  1049. *
  1050. * Hence the entire topology CPU set is converted into the set of all nodes
  1051. * that have some local CPUs.
  1052. *
  1053. * \return 0 on success.
  1054. * \return -1 with errno set to \c ENOMEM on internal reallocation failure.
  1055. */
  1056. static __hwloc_inline int
  1057. hwloc_cpuset_to_nodeset(hwloc_topology_t topology, hwloc_const_cpuset_t _cpuset, hwloc_nodeset_t nodeset)
  1058. {
  1059. int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE);
  1060. hwloc_obj_t obj = NULL;
  1061. assert(depth != HWLOC_TYPE_DEPTH_UNKNOWN);
  1062. hwloc_bitmap_zero(nodeset);
  1063. while ((obj = hwloc_get_next_obj_covering_cpuset_by_depth(topology, _cpuset, depth, obj)) != NULL)
  1064. if (hwloc_bitmap_set(nodeset, obj->os_index) < 0)
  1065. return -1;
  1066. return 0;
  1067. }
  1068. /** \brief Convert a NUMA node set into a CPU set
  1069. *
  1070. * For each NUMA node included in the input \p nodeset, set the corresponding
  1071. * local PUs in the output \p _cpuset.
  1072. *
  1073. * If some CPUs have no local NUMA nodes, this function never sets their
  1074. * indexes in the output CPU set, even if a full node set is given in input.
  1075. *
  1076. * Hence the entire topology node set is converted into the set of all CPUs
  1077. * that have some local NUMA nodes.
  1078. *
  1079. * \return 0 on success.
  1080. * \return -1 with errno set to \c ENOMEM on internal reallocation failure.
  1081. */
  1082. static __hwloc_inline int
  1083. hwloc_cpuset_from_nodeset(hwloc_topology_t topology, hwloc_cpuset_t _cpuset, hwloc_const_nodeset_t nodeset)
  1084. {
  1085. int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NUMANODE);
  1086. hwloc_obj_t obj = NULL;
  1087. assert(depth != HWLOC_TYPE_DEPTH_UNKNOWN);
  1088. hwloc_bitmap_zero(_cpuset);
  1089. while ((obj = hwloc_get_next_obj_by_depth(topology, depth, obj)) != NULL) {
  1090. if (hwloc_bitmap_isset(nodeset, obj->os_index))
  1091. /* no need to check obj->cpuset because objects in levels always have a cpuset */
  1092. if (hwloc_bitmap_or(_cpuset, _cpuset, obj->cpuset) < 0)
  1093. return -1;
  1094. }
  1095. return 0;
  1096. }
  1097. /** @} */
  1098. /** \defgroup hwlocality_advanced_io Finding I/O objects
  1099. * @{
  1100. */
  1101. /** \brief Get the first non-I/O ancestor object.
  1102. *
  1103. * Given the I/O object \p ioobj, find the smallest non-I/O ancestor
  1104. * object. This object (normal or memory) may then be used for binding
  1105. * because it has non-NULL CPU and node sets
  1106. * and because its locality is the same as \p ioobj.
  1107. *
  1108. * \return a non-I/O object.
  1109. *
  1110. * \note This function cannot return \c NULL.
  1111. *
  1112. * \note The resulting object is usually a normal object but it could also
  1113. * be a memory object (e.g. NUMA node) in future platforms if I/O objects
  1114. * ever get attached to memory instead of CPUs.
  1115. */
  1116. static __hwloc_inline hwloc_obj_t
  1117. hwloc_get_non_io_ancestor_obj(hwloc_topology_t topology __hwloc_attribute_unused,
  1118. hwloc_obj_t ioobj)
  1119. {
  1120. hwloc_obj_t obj = ioobj;
  1121. while (obj && !obj->cpuset) {
  1122. obj = obj->parent;
  1123. }
  1124. return obj;
  1125. }
  1126. /** \brief Get the next PCI device in the system.
  1127. *
  1128. * \return the first PCI device if \p prev is \c NULL.
  1129. * \return the next PCI device if \p prev is not \c NULL.
  1130. * \return \c NULL if there is no next PCI device.
  1131. */
  1132. static __hwloc_inline hwloc_obj_t
  1133. hwloc_get_next_pcidev(hwloc_topology_t topology, hwloc_obj_t prev)
  1134. {
  1135. return hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_PCI_DEVICE, prev);
  1136. }
  1137. /** \brief Find the PCI device object matching the PCI bus id
  1138. * given domain, bus device and function PCI bus id.
  1139. *
  1140. * \return a matching PCI device object if any, \c NULL otherwise.
  1141. */
  1142. static __hwloc_inline hwloc_obj_t
  1143. hwloc_get_pcidev_by_busid(hwloc_topology_t topology,
  1144. unsigned domain, unsigned bus, unsigned dev, unsigned func)
  1145. {
  1146. hwloc_obj_t obj = NULL;
  1147. while ((obj = hwloc_get_next_pcidev(topology, obj)) != NULL) {
  1148. if (obj->attr->pcidev.domain == domain
  1149. && obj->attr->pcidev.bus == bus
  1150. && obj->attr->pcidev.dev == dev
  1151. && obj->attr->pcidev.func == func)
  1152. return obj;
  1153. }
  1154. return NULL;
  1155. }
  1156. /** \brief Find the PCI device object matching the PCI bus id
  1157. * given as a string xxxx:yy:zz.t or yy:zz.t.
  1158. *
  1159. * \return a matching PCI device object if any, \c NULL otherwise.
  1160. */
  1161. static __hwloc_inline hwloc_obj_t
  1162. hwloc_get_pcidev_by_busidstring(hwloc_topology_t topology, const char *busid)
  1163. {
  1164. unsigned domain = 0; /* default */
  1165. unsigned bus, dev, func;
  1166. if (sscanf(busid, "%x:%x.%x", &bus, &dev, &func) != 3
  1167. && sscanf(busid, "%x:%x:%x.%x", &domain, &bus, &dev, &func) != 4) {
  1168. errno = EINVAL;
  1169. return NULL;
  1170. }
  1171. return hwloc_get_pcidev_by_busid(topology, domain, bus, dev, func);
  1172. }
  1173. /** \brief Get the next OS device in the system.
  1174. *
  1175. * \return the first OS device if \p prev is \c NULL.
  1176. * \return the next OS device if \p prev is not \c NULL.
  1177. * \return \c NULL if there is no next OS device.
  1178. */
  1179. static __hwloc_inline hwloc_obj_t
  1180. hwloc_get_next_osdev(hwloc_topology_t topology, hwloc_obj_t prev)
  1181. {
  1182. return hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_OS_DEVICE, prev);
  1183. }
  1184. /** \brief Get the next bridge in the system.
  1185. *
  1186. * \return the first bridge if \p prev is \c NULL.
  1187. * \return the next bridge if \p prev is not \c NULL.
  1188. * \return \c NULL if there is no next bridge.
  1189. */
  1190. static __hwloc_inline hwloc_obj_t
  1191. hwloc_get_next_bridge(hwloc_topology_t topology, hwloc_obj_t prev)
  1192. {
  1193. return hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_BRIDGE, prev);
  1194. }
  1195. /* \brief Checks whether a given bridge covers a given PCI bus.
  1196. *
  1197. * \return 1 if it covers, 0 if not.
  1198. */
  1199. static __hwloc_inline int
  1200. hwloc_bridge_covers_pcibus(hwloc_obj_t bridge,
  1201. unsigned domain, unsigned bus)
  1202. {
  1203. return bridge->type == HWLOC_OBJ_BRIDGE
  1204. && bridge->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI
  1205. && bridge->attr->bridge.downstream.pci.domain == domain
  1206. && bridge->attr->bridge.downstream.pci.secondary_bus <= bus
  1207. && bridge->attr->bridge.downstream.pci.subordinate_bus >= bus;
  1208. }
  1209. /** @} */
  1210. #ifdef __cplusplus
  1211. } /* extern "C" */
  1212. #endif
  1213. #endif /* HWLOC_HELPER_H */