Open MPI logo

Portable Hardware Locality (hwloc) Documentation: v1.3.3

  |   Home   |   Support   |   FAQ   |  
helper.h
1 /*
2  * Copyright © 2009 CNRS
3  * Copyright © 2009-2011 inria. All rights reserved.
4  * Copyright © 2009-2012 Université Bordeaux 1
5  * Copyright © 2009-2010 Cisco Systems, Inc. All rights reserved.
6  * See COPYING in top-level directory.
7  */
8 
13 #ifndef HWLOC_HELPER_H
14 #define HWLOC_HELPER_H
15 
16 #ifndef HWLOC_H
17 #error Please include the main hwloc.h instead
18 #endif
19 
20 #include <stdlib.h>
21 #include <errno.h>
22 
23 
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27 
28 
47 static inline int
49 static inline int
51 {
52  int depth = hwloc_get_type_depth(topology, type);
53 
54  if (depth != HWLOC_TYPE_DEPTH_UNKNOWN)
55  return depth;
56 
57  /* find the highest existing level with type order >= */
58  for(depth = hwloc_get_type_depth(topology, HWLOC_OBJ_PU); ; depth--)
59  if (hwloc_compare_types(hwloc_get_depth_type(topology, depth), type) < 0)
60  return depth+1;
61 
62  /* Shouldn't ever happen, as there is always a SYSTEM level with lower order and known depth. */
63  /* abort(); */
64 }
65 
75 static inline int
77 static inline int
79 {
80  int depth = hwloc_get_type_depth(topology, type);
81 
82  if (depth != HWLOC_TYPE_DEPTH_UNKNOWN)
83  return depth;
84 
85  /* find the lowest existing level with type order <= */
86  for(depth = 0; ; depth++)
87  if (hwloc_compare_types(hwloc_get_depth_type(topology, depth), type) > 0)
88  return depth-1;
89 
90  /* Shouldn't ever happen, as there is always a PU level with higher order and known depth. */
91  /* abort(); */
92 }
93 
113 static inline hwloc_obj_t
115 static inline hwloc_obj_t
117 {
118  return hwloc_get_obj_by_depth (topology, 0, 0);
119 }
120 
122 static inline hwloc_obj_t
123 hwloc_get_ancestor_obj_by_depth (hwloc_topology_t topology , unsigned depth, hwloc_obj_t obj) ;
124 static inline hwloc_obj_t
126 {
127  hwloc_obj_t ancestor = obj;
128  if (obj->depth < depth)
129  return NULL;
130  while (ancestor && ancestor->depth > depth)
131  ancestor = ancestor->parent;
132  return ancestor;
133 }
134 
136 static inline hwloc_obj_t
138 static inline hwloc_obj_t
140 {
141  hwloc_obj_t ancestor = obj->parent;
142  while (ancestor && ancestor->type != type)
143  ancestor = ancestor->parent;
144  return ancestor;
145 }
146 
151 static inline hwloc_obj_t
153 {
154  if (!prev)
155  return hwloc_get_obj_by_depth (topology, depth, 0);
156  if (prev->depth != depth)
157  return NULL;
158  return prev->next_cousin;
159 }
160 
167 static inline hwloc_obj_t
169  hwloc_obj_t prev)
170 {
171  int depth = hwloc_get_type_depth(topology, type);
172  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE)
173  return NULL;
174  return hwloc_get_next_obj_by_depth (topology, depth, prev);
175 }
176 
185 static inline hwloc_obj_t
186 hwloc_get_pu_obj_by_os_index(hwloc_topology_t topology, unsigned os_index) ;
187 static inline hwloc_obj_t
188 hwloc_get_pu_obj_by_os_index(hwloc_topology_t topology, unsigned os_index)
189 {
190  hwloc_obj_t obj = NULL;
191  while ((obj = hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_PU, obj)) != NULL)
192  if (obj->os_index == os_index)
193  return obj;
194  return NULL;
195 }
196 
201 static inline hwloc_obj_t
203 {
204  if (!prev)
205  return parent->first_child;
206  if (prev->parent != parent)
207  return NULL;
208  return prev->next_sibling;
209 }
210 
212 static inline hwloc_obj_t
214 static inline hwloc_obj_t
216 {
217  /* the loop isn't so easy since intermediate ancestors may have
218  * different depth, causing us to alternate between using obj1->parent
219  * and obj2->parent. Also, even if at some point we find ancestors of
220  * of the same depth, their ancestors may have different depth again.
221  */
222  while (obj1 != obj2) {
223  while (obj1->depth > obj2->depth)
224  obj1 = obj1->parent;
225  while (obj2->depth > obj1->depth)
226  obj2 = obj2->parent;
227  if (obj1 != obj2 && obj1->depth == obj2->depth) {
228  obj1 = obj1->parent;
229  obj2 = obj2->parent;
230  }
231  }
232  return obj1;
233 }
234 
239 static inline int
240 hwloc_obj_is_in_subtree (hwloc_topology_t topology , hwloc_obj_t obj, hwloc_obj_t subtree_root) ;
241 static inline int
243 {
244  return hwloc_bitmap_isincluded(obj->cpuset, subtree_root->cpuset);
245 }
246 
263 static inline hwloc_obj_t
265 {
266  hwloc_obj_t obj = hwloc_get_root_obj(topology);
267  /* FIXME: what if !root->cpuset? */
268  if (!hwloc_bitmap_intersects(obj->cpuset, set))
269  return NULL;
270  while (!hwloc_bitmap_isincluded(obj->cpuset, set)) {
271  /* while the object intersects without being included, look at its children */
272  hwloc_obj_t child = NULL;
273  while ((child = hwloc_get_next_child(topology, obj, child)) != NULL) {
274  if (child->cpuset && hwloc_bitmap_intersects(child->cpuset, set))
275  break;
276  }
277  if (!child)
278  /* no child intersects, return their father */
279  return obj;
280  /* found one intersecting child, look at its children */
281  obj = child;
282  }
283  /* obj is included, return it */
284  return obj;
285 }
286 
292  hwloc_obj_t * restrict objs, int max);
293 
300 static inline hwloc_obj_t
302  unsigned depth, hwloc_obj_t prev)
303 {
304  hwloc_obj_t next = hwloc_get_next_obj_by_depth(topology, depth, prev);
305  /* no need to check next->cpuset because objects in levels always have a cpuset */
306  while (next && !hwloc_bitmap_isincluded(next->cpuset, set))
307  next = next->next_cousin;
308  return next;
309 }
310 
317 static inline hwloc_obj_t
319  hwloc_obj_type_t type, hwloc_obj_t prev)
320 {
321  int depth = hwloc_get_type_depth(topology, type);
322  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE)
323  return NULL;
324  return hwloc_get_next_obj_inside_cpuset_by_depth(topology, set, depth, prev);
325 }
326 
329 static inline hwloc_obj_t
331  unsigned depth, unsigned idx) ;
332 static inline hwloc_obj_t
334  unsigned depth, unsigned idx)
335 {
336  unsigned count = 0;
337  hwloc_obj_t obj = hwloc_get_obj_by_depth (topology, depth, 0);
338  while (obj) {
339  /* no need to check obj->cpuset because objects in levels always have a cpuset */
340  if (hwloc_bitmap_isincluded(obj->cpuset, set)) {
341  if (count == idx)
342  return obj;
343  count++;
344  }
345  obj = obj->next_cousin;
346  }
347  return NULL;
348 }
349 
356 static inline hwloc_obj_t
358  hwloc_obj_type_t type, unsigned idx) ;
359 static inline hwloc_obj_t
361  hwloc_obj_type_t type, unsigned idx)
362 {
363  int depth = hwloc_get_type_depth(topology, type);
364  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE)
365  return NULL;
366  return hwloc_get_obj_inside_cpuset_by_depth(topology, set, depth, idx);
367 }
368 
370 static inline unsigned
372  unsigned depth) ;
373 static inline unsigned
375  unsigned depth)
376 {
377  hwloc_obj_t obj = hwloc_get_obj_by_depth (topology, depth, 0);
378  int count = 0;
379  while (obj) {
380  /* no need to check obj->cpuset because objects in levels always have a cpuset */
381  if (hwloc_bitmap_isincluded(obj->cpuset, set))
382  count++;
383  obj = obj->next_cousin;
384  }
385  return count;
386 }
387 
394 static inline int
396  hwloc_obj_type_t type) ;
397 static inline int
399  hwloc_obj_type_t type)
400 {
401  int depth = hwloc_get_type_depth(topology, type);
402  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN)
403  return 0;
404  if (depth == HWLOC_TYPE_DEPTH_MULTIPLE)
405  return -1; /* FIXME: agregate nbobjs from different levels? */
406  return hwloc_get_nbobjs_inside_cpuset_by_depth(topology, set, depth);
407 }
408 
421 static inline hwloc_obj_t
423  hwloc_obj_t parent) ;
424 static inline hwloc_obj_t
426  hwloc_obj_t parent)
427 {
428  hwloc_obj_t child;
429 
430  if (hwloc_bitmap_iszero(set))
431  return NULL;
432 
433  child = parent->first_child;
434  while (child) {
435  if (child->cpuset && hwloc_bitmap_isincluded(set, child->cpuset))
436  return child;
437  child = child->next_sibling;
438  }
439  return NULL;
440 }
441 
446 static inline hwloc_obj_t
448 static inline hwloc_obj_t
450 {
451  struct hwloc_obj *current = hwloc_get_root_obj(topology);
452 
453  if (hwloc_bitmap_iszero(set))
454  return NULL;
455 
456  /* FIXME: what if !root->cpuset? */
457  if (!hwloc_bitmap_isincluded(set, current->cpuset))
458  return NULL;
459 
460  while (1) {
461  hwloc_obj_t child = hwloc_get_child_covering_cpuset(topology, set, current);
462  if (!child)
463  return current;
464  current = child;
465  }
466 }
467 
468 
484 static inline hwloc_obj_t
486  unsigned depth, hwloc_obj_t prev)
487 {
488  hwloc_obj_t next = hwloc_get_next_obj_by_depth(topology, depth, prev);
489  /* no need to check next->cpuset because objects in levels always have a cpuset */
490  while (next && !hwloc_bitmap_intersects(set, next->cpuset))
491  next = next->next_cousin;
492  return next;
493 }
494 
507 static inline hwloc_obj_t
510 {
511  int depth = hwloc_get_type_depth(topology, type);
512  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE)
513  return NULL;
514  return hwloc_get_next_obj_covering_cpuset_by_depth(topology, set, depth, prev);
515 }
516 
529 static inline hwloc_obj_t
531 static inline hwloc_obj_t
533 {
534  hwloc_obj_t current = hwloc_get_obj_covering_cpuset(topology, set);
535  while (current) {
536  if (current->type == HWLOC_OBJ_CACHE)
537  return current;
538  current = current->parent;
539  }
540  return NULL;
541 }
542 
547 static inline hwloc_obj_t
549 static inline hwloc_obj_t
551 {
552  hwloc_obj_t current = obj->parent;
553  if (!obj->cpuset)
554  return NULL;
555  while (current && current->cpuset) {
556  if (!hwloc_bitmap_isequal(current->cpuset, obj->cpuset)
557  && current->type == HWLOC_OBJ_CACHE)
558  return current;
559  current = current->parent;
560  }
561  return NULL;
562 }
563 
586 /* TODO: rather provide an iterator? Provide a way to know how much should be allocated? By returning the total number of objects instead? */
587  unsigned hwloc_get_closest_objs (hwloc_topology_t topology, hwloc_obj_t src, hwloc_obj_t * restrict objs, unsigned max);
588 
599 static inline hwloc_obj_t
601  hwloc_obj_type_t type1, unsigned idx1,
602  hwloc_obj_type_t type2, unsigned idx2) ;
603 static inline hwloc_obj_t
605  hwloc_obj_type_t type1, unsigned idx1,
606  hwloc_obj_type_t type2, unsigned idx2)
607 {
608  hwloc_obj_t obj;
609 
610  obj = hwloc_get_obj_by_type (topology, type1, idx1);
611  if (!obj)
612  return NULL;
613 
614  return hwloc_get_obj_inside_cpuset_by_type(topology, obj->cpuset, type2, idx2);
615 }
616 
632 static inline hwloc_obj_t
633 hwloc_get_obj_below_array_by_type (hwloc_topology_t topology, int nr, hwloc_obj_type_t *typev, unsigned *idxv) ;
634 static inline hwloc_obj_t
635 hwloc_get_obj_below_array_by_type (hwloc_topology_t topology, int nr, hwloc_obj_type_t *typev, unsigned *idxv)
636 {
637  hwloc_obj_t obj = hwloc_get_root_obj(topology);
638  int i;
639 
640  /* FIXME: what if !root->cpuset? */
641  for(i=0; i<nr; i++) {
642  obj = hwloc_get_obj_inside_cpuset_by_type(topology, obj->cpuset, typev[i], idxv[i]);
643  if (!obj)
644  return NULL;
645  }
646 
647  return obj;
648 }
649 
671 static inline void
672 hwloc_distributev(hwloc_topology_t topology, hwloc_obj_t *root, unsigned n_roots, hwloc_cpuset_t *cpuset, unsigned n, unsigned until);
673 static inline void
674 hwloc_distribute(hwloc_topology_t topology, hwloc_obj_t root, hwloc_cpuset_t *cpuset, unsigned n, unsigned until)
675 {
676  unsigned i;
677 
678  /* FIXME: what if !root->cpuset? */
679  if (!root->arity || n == 1 || root->depth >= until) {
680  /* Got to the bottom, we can't split any more, put everything there. */
681  for (i=0; i<n; i++)
682  cpuset[i] = hwloc_bitmap_dup(root->cpuset);
683  return;
684  }
685 
686  hwloc_distributev(topology, root->children, root->arity, cpuset, n, until);
687 }
688 
694 static inline void
695 hwloc_distributev(hwloc_topology_t topology, hwloc_obj_t *roots, unsigned n_roots, hwloc_cpuset_t *cpuset, unsigned n, unsigned until)
696 {
697  unsigned i;
698  unsigned tot_weight;
699  hwloc_cpuset_t *cpusetp = cpuset;
700 
701  tot_weight = 0;
702  for (i = 0; i < n_roots; i++)
703  if (roots[i]->cpuset)
704  tot_weight += hwloc_bitmap_weight(roots[i]->cpuset);
705 
706  for (i = 0; i < n_roots && tot_weight; i++) {
707  /* Give to roots[i] a portion proportional to its weight */
708  unsigned weight = roots[i]->cpuset ? hwloc_bitmap_weight(roots[i]->cpuset) : 0;
709  unsigned chunk = (n * weight + tot_weight-1) / tot_weight;
710  hwloc_distribute(topology, roots[i], cpusetp, chunk, until);
711  cpusetp += chunk;
712  tot_weight -= weight;
713  n -= chunk;
714  }
715 }
716 
723 static inline void *
725 {
726  void *p = hwloc_alloc_membind_nodeset(topology, len, nodeset, policy, flags);
727  if (p)
728  return p;
729  hwloc_set_membind_nodeset(topology, nodeset, policy, flags);
730  p = hwloc_alloc(topology, len);
731  if (p && policy != HWLOC_MEMBIND_FIRSTTOUCH)
732  /* Enforce the binding by touching the data */
733  memset(p, 0, len);
734  return p;
735 }
736 
741 static inline void *
743 {
744  void *p = hwloc_alloc_membind(topology, len, cpuset, policy, flags);
745  if (p)
746  return p;
747  hwloc_set_membind(topology, cpuset, policy, flags);
748  p = hwloc_alloc(topology, len);
749  if (p && policy != HWLOC_MEMBIND_FIRSTTOUCH)
750  /* Enforce the binding by touching the data */
751  memset(p, 0, len);
752  return p;
753 }
754 
771 static inline hwloc_const_cpuset_t
773 static inline hwloc_const_cpuset_t
775 {
776  return hwloc_get_root_obj(topology)->complete_cpuset;
777 }
778 
789 static inline hwloc_const_cpuset_t
791 static inline hwloc_const_cpuset_t
793 {
794  return hwloc_get_root_obj(topology)->cpuset;
795 }
796 
806 static inline hwloc_const_cpuset_t
808 static inline hwloc_const_cpuset_t
810 {
811  return hwloc_get_root_obj(topology)->online_cpuset;
812 }
813 
823 static inline hwloc_const_cpuset_t
825 static inline hwloc_const_cpuset_t
827 {
828  return hwloc_get_root_obj(topology)->allowed_cpuset;
829 }
830 
847 static inline hwloc_const_nodeset_t
849 static inline hwloc_const_nodeset_t
851 {
852  return hwloc_get_root_obj(topology)->complete_nodeset;
853 }
854 
865 static inline hwloc_const_nodeset_t
867 static inline hwloc_const_nodeset_t
869 {
870  return hwloc_get_root_obj(topology)->nodeset;
871 }
872 
882 static inline hwloc_const_nodeset_t
884 static inline hwloc_const_nodeset_t
886 {
887  return hwloc_get_root_obj(topology)->allowed_nodeset;
888 }
889 
920 static inline void
922 {
923  int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NODE);
924  hwloc_obj_t obj;
925 
926  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN) {
927  if (hwloc_bitmap_iszero(cpuset))
928  hwloc_bitmap_zero(nodeset);
929  else
930  /* Assume the whole system */
931  hwloc_bitmap_fill(nodeset);
932  return;
933  }
934 
935  hwloc_bitmap_zero(nodeset);
936  obj = NULL;
937  while ((obj = hwloc_get_next_obj_covering_cpuset_by_depth(topology, cpuset, depth, obj)) != NULL)
938  hwloc_bitmap_set(nodeset, obj->os_index);
939 }
940 
948 static inline void
950 {
951  int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NODE);
952  hwloc_obj_t obj;
953  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN )
954  return;
955  hwloc_bitmap_zero(nodeset);
956  obj = NULL;
957  while ((obj = hwloc_get_next_obj_covering_cpuset_by_depth(topology, cpuset, depth, obj)) != NULL)
958  hwloc_bitmap_set(nodeset, obj->os_index);
959 }
960 
969 static inline void
971 {
972  int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NODE);
973  hwloc_obj_t obj;
974 
975  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN ) {
976  if (hwloc_bitmap_iszero(nodeset))
977  hwloc_bitmap_zero(cpuset);
978  else
979  /* Assume the whole system */
980  hwloc_bitmap_fill(cpuset);
981  return;
982  }
983 
984  hwloc_bitmap_zero(cpuset);
985  obj = NULL;
986  while ((obj = hwloc_get_next_obj_by_depth(topology, depth, obj)) != NULL) {
987  if (hwloc_bitmap_isset(nodeset, obj->os_index))
988  /* no need to check obj->cpuset because objects in levels always have a cpuset */
989  hwloc_bitmap_or(cpuset, cpuset, obj->cpuset);
990  }
991 }
992 
1000 static inline void
1002 {
1003  int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NODE);
1004  hwloc_obj_t obj;
1005  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN )
1006  return;
1007  hwloc_bitmap_zero(cpuset);
1008  obj = NULL;
1009  while ((obj = hwloc_get_next_obj_by_depth(topology, depth, obj)) != NULL)
1010  if (hwloc_bitmap_isset(nodeset, obj->os_index))
1011  /* no need to check obj->cpuset because objects in levels always have a cpuset */
1012  hwloc_bitmap_or(cpuset, cpuset, obj->cpuset);
1013 }
1014 
1042 static inline const struct hwloc_distances_s *
1044 {
1045  hwloc_obj_t root = hwloc_get_root_obj(topology);
1046  unsigned i;
1047  for(i=0; i<root->distances_count; i++)
1048  if (root->distances[i]->relative_depth == depth)
1049  return root->distances[i];
1050  return NULL;
1051 }
1052 
1072 static inline const struct hwloc_distances_s *
1074 {
1075  int depth = hwloc_get_type_depth(topology, type);
1076  if (depth < 0)
1077  return NULL;
1078  return hwloc_get_whole_distance_matrix_by_depth(topology, depth);
1079 }
1080 
1094 static inline const struct hwloc_distances_s *
1096  hwloc_obj_t obj, unsigned depth,
1097  unsigned *firstp)
1098 {
1099  while (obj && obj->cpuset) {
1100  unsigned i;
1101  for(i=0; i<obj->distances_count; i++)
1102  if (obj->distances[i]->relative_depth == depth - obj->depth) {
1103  if (!obj->distances[i]->nbobjs)
1104  continue;
1105  *firstp = hwloc_get_next_obj_inside_cpuset_by_depth(topology, obj->cpuset, depth, NULL)->logical_index;
1106  return obj->distances[i];
1107  }
1108  obj = obj->parent;
1109  }
1110  return NULL;
1111 }
1112 
1124 static inline int
1126  hwloc_obj_t obj1, hwloc_obj_t obj2,
1127  float *latency, float *reverse_latency)
1128 {
1129  hwloc_obj_t ancestor;
1130  const struct hwloc_distances_s * distances;
1131  unsigned first_logical ;
1132 
1133  if (obj1->depth != obj2->depth) {
1134  errno = EINVAL;
1135  return -1;
1136  }
1137 
1138  ancestor = hwloc_get_common_ancestor_obj(topology, obj1, obj2);
1139  distances = hwloc_get_distance_matrix_covering_obj_by_depth(topology, ancestor, obj1->depth, &first_logical);
1140  if (distances && distances->latency) {
1141  const float * latency_matrix = distances->latency;
1142  unsigned nbobjs = distances->nbobjs;
1143  unsigned l1 = obj1->logical_index - first_logical;
1144  unsigned l2 = obj2->logical_index - first_logical;
1145  *latency = latency_matrix[l1*nbobjs+l2];
1146  *reverse_latency = latency_matrix[l2*nbobjs+l1];
1147  return 0;
1148  }
1149 
1150  errno = ENOSYS;
1151  return -1;
1152 }
1153 
1168 static inline hwloc_obj_t
1170  hwloc_obj_t ioobj)
1171 {
1172  hwloc_obj_t obj = ioobj;
1173  while (obj && !obj->cpuset) {
1174  obj = obj->parent;
1175  }
1176  return obj;
1177 }
1178 
1183 static inline hwloc_obj_t
1185 {
1186  return hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_PCI_DEVICE, prev);
1187 }
1188 
1192 static inline hwloc_obj_t
1194  unsigned domain, unsigned bus, unsigned dev, unsigned func)
1195 {
1196  hwloc_obj_t obj = NULL;
1197  while ((obj = hwloc_get_next_pcidev(topology, obj)) != NULL) {
1198  if (obj->attr->pcidev.domain == domain
1199  && obj->attr->pcidev.bus == bus
1200  && obj->attr->pcidev.dev == dev
1201  && obj->attr->pcidev.func == func)
1202  return obj;
1203  }
1204  return NULL;
1205 }
1206 
1210 static inline hwloc_obj_t
1212 {
1213  unsigned domain = 0; /* default */
1214  unsigned bus, dev, func;
1215 
1216  if (sscanf(busid, "%x:%x.%x", &bus, &dev, &func) != 3
1217  && sscanf(busid, "%x:%x:%x.%x", &domain, &bus, &dev, &func) != 4) {
1218  errno = EINVAL;
1219  return NULL;
1220  }
1221 
1222  return hwloc_get_pcidev_by_busid(topology, domain, bus, dev, func);
1223 }
1224 
1229 static inline hwloc_obj_t
1231 {
1232  return hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_OS_DEVICE, prev);
1233 }
1234 
1239 static inline hwloc_obj_t
1241 {
1242  return hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_BRIDGE, prev);
1243 }
1244 
1245 /* \brief Checks whether a given bridge covers a given PCI bus.
1246  */
1247 static inline int
1249  unsigned domain, unsigned bus)
1250 {
1251  return bridge->type == HWLOC_OBJ_BRIDGE
1253  && bridge->attr->bridge.downstream.pci.domain == domain
1254  && bridge->attr->bridge.downstream.pci.secondary_bus <= bus
1255  && bridge->attr->bridge.downstream.pci.subordinate_bus >= bus;
1256 }
1257 
1263 static inline hwloc_obj_t
1265  unsigned domain, unsigned bus)
1266 {
1267  hwloc_obj_t obj = NULL;
1268  while ((obj = hwloc_get_next_bridge(topology, obj)) != NULL) {
1269  if (hwloc_bridge_covers_pcibus(obj, domain, bus)) {
1270  /* found bridge covering this pcibus, make sure it's a hostbridge */
1272  assert(obj->parent->type != HWLOC_OBJ_BRIDGE);
1273  assert(obj->parent->cpuset);
1274  return obj;
1275  }
1276  }
1277  return NULL;
1278 }
1279 
1284 #ifdef __cplusplus
1285 } /* extern "C" */
1286 #endif
1287 
1288 
1289 #endif /* HWLOC_HELPER_H */