Open MPI logo

Portable Hardware Locality (hwloc) Documentation: v1.4.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 
266 static inline hwloc_obj_t
268 {
269  hwloc_obj_t obj = hwloc_get_root_obj(topology);
270  if (!obj->cpuset || !hwloc_bitmap_intersects(obj->cpuset, set))
271  return NULL;
272  while (!hwloc_bitmap_isincluded(obj->cpuset, set)) {
273  /* while the object intersects without being included, look at its children */
274  hwloc_obj_t child = NULL;
275  while ((child = hwloc_get_next_child(topology, obj, child)) != NULL) {
276  if (child->cpuset && hwloc_bitmap_intersects(child->cpuset, set))
277  break;
278  }
279  if (!child)
280  /* no child intersects, return their father */
281  return obj;
282  /* found one intersecting child, look at its children */
283  obj = child;
284  }
285  /* obj is included, return it */
286  return obj;
287 }
288 
297  hwloc_obj_t * restrict objs, int max);
298 
308 static inline hwloc_obj_t
310  unsigned depth, hwloc_obj_t prev)
311 {
312  hwloc_obj_t next = hwloc_get_next_obj_by_depth(topology, depth, prev);
313  if (!next || !next->cpuset)
314  return NULL;
315  while (next && !hwloc_bitmap_isincluded(next->cpuset, set))
316  next = next->next_cousin;
317  return next;
318 }
319 
329 static inline hwloc_obj_t
331  hwloc_obj_type_t type, hwloc_obj_t prev)
332 {
333  int depth = hwloc_get_type_depth(topology, type);
334  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE)
335  return NULL;
336  return hwloc_get_next_obj_inside_cpuset_by_depth(topology, set, depth, prev);
337 }
338 
344 static inline hwloc_obj_t
346  unsigned depth, unsigned idx) ;
347 static inline hwloc_obj_t
349  unsigned depth, unsigned idx)
350 {
351  hwloc_obj_t obj = hwloc_get_obj_by_depth (topology, depth, 0);
352  unsigned count = 0;
353  if (!obj || !obj->cpuset)
354  return NULL;
355  while (obj) {
356  if (hwloc_bitmap_isincluded(obj->cpuset, set)) {
357  if (count == idx)
358  return obj;
359  count++;
360  }
361  obj = obj->next_cousin;
362  }
363  return NULL;
364 }
365 
375 static inline hwloc_obj_t
377  hwloc_obj_type_t type, unsigned idx) ;
378 static inline hwloc_obj_t
380  hwloc_obj_type_t type, unsigned idx)
381 {
382  int depth = hwloc_get_type_depth(topology, type);
383  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE)
384  return NULL;
385  return hwloc_get_obj_inside_cpuset_by_depth(topology, set, depth, idx);
386 }
387 
393 static inline unsigned
395  unsigned depth) ;
396 static inline unsigned
398  unsigned depth)
399 {
400  hwloc_obj_t obj = hwloc_get_obj_by_depth (topology, depth, 0);
401  unsigned count = 0;
402  if (!obj || !obj->cpuset)
403  return 0;
404  while (obj) {
405  if (hwloc_bitmap_isincluded(obj->cpuset, set))
406  count++;
407  obj = obj->next_cousin;
408  }
409  return count;
410 }
411 
421 static inline int
423  hwloc_obj_type_t type) ;
424 static inline int
426  hwloc_obj_type_t type)
427 {
428  int depth = hwloc_get_type_depth(topology, type);
429  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN)
430  return 0;
431  if (depth == HWLOC_TYPE_DEPTH_MULTIPLE)
432  return -1; /* FIXME: agregate nbobjs from different levels? */
433  return hwloc_get_nbobjs_inside_cpuset_by_depth(topology, set, depth);
434 }
435 
444 static inline int
446  hwloc_obj_t obj) ;
447 static inline int
449  hwloc_obj_t obj)
450 {
451  int idx = 0;
452  if (!hwloc_bitmap_isincluded(obj->cpuset, set))
453  return -1;
454  /* count how many objects are inside the cpuset on the way from us to the beginning of the level */
455  while ((obj = obj->prev_cousin) != NULL)
456  if (hwloc_bitmap_isincluded(obj->cpuset, set))
457  idx++;
458  return idx;
459 }
460 
475 static inline hwloc_obj_t
477  hwloc_obj_t parent) ;
478 static inline hwloc_obj_t
480  hwloc_obj_t parent)
481 {
482  hwloc_obj_t child;
483  if (!parent->cpuset || hwloc_bitmap_iszero(set))
484  return NULL;
485  child = parent->first_child;
486  while (child) {
487  if (child->cpuset && hwloc_bitmap_isincluded(set, child->cpuset))
488  return child;
489  child = child->next_sibling;
490  }
491  return NULL;
492 }
493 
501 static inline hwloc_obj_t
503 static inline hwloc_obj_t
505 {
506  struct hwloc_obj *current = hwloc_get_root_obj(topology);
507  if (hwloc_bitmap_iszero(set) || !current->cpuset || !hwloc_bitmap_isincluded(set, current->cpuset))
508  return NULL;
509  while (1) {
510  hwloc_obj_t child = hwloc_get_child_covering_cpuset(topology, set, current);
511  if (!child)
512  return current;
513  current = child;
514  }
515 }
516 
517 
536 static inline hwloc_obj_t
538  unsigned depth, hwloc_obj_t prev)
539 {
540  hwloc_obj_t next = hwloc_get_next_obj_by_depth(topology, depth, prev);
541  if (!next || !next->cpuset)
542  return NULL;
543  while (next && !hwloc_bitmap_intersects(set, next->cpuset))
544  next = next->next_cousin;
545  return next;
546 }
547 
563 static inline hwloc_obj_t
566 {
567  int depth = hwloc_get_type_depth(topology, type);
568  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN || depth == HWLOC_TYPE_DEPTH_MULTIPLE)
569  return NULL;
570  return hwloc_get_next_obj_covering_cpuset_by_depth(topology, set, depth, prev);
571 }
572 
588 static inline hwloc_obj_t
590 static inline hwloc_obj_t
592 {
593  hwloc_obj_t current = hwloc_get_obj_covering_cpuset(topology, set);
594  while (current) {
595  if (current->type == HWLOC_OBJ_CACHE)
596  return current;
597  current = current->parent;
598  }
599  return NULL;
600 }
601 
606 static inline hwloc_obj_t
608 static inline hwloc_obj_t
610 {
611  hwloc_obj_t current = obj->parent;
612  if (!obj->cpuset)
613  return NULL;
614  while (current && current->cpuset) {
615  if (!hwloc_bitmap_isequal(current->cpuset, obj->cpuset)
616  && current->type == HWLOC_OBJ_CACHE)
617  return current;
618  current = current->parent;
619  }
620  return NULL;
621 }
622 
647 /* TODO: rather provide an iterator? Provide a way to know how much should be allocated? By returning the total number of objects instead? */
648  unsigned hwloc_get_closest_objs (hwloc_topology_t topology, hwloc_obj_t src, hwloc_obj_t * restrict objs, unsigned max);
649 
662 static inline hwloc_obj_t
664  hwloc_obj_type_t type1, unsigned idx1,
665  hwloc_obj_type_t type2, unsigned idx2) ;
666 static inline hwloc_obj_t
668  hwloc_obj_type_t type1, unsigned idx1,
669  hwloc_obj_type_t type2, unsigned idx2)
670 {
671  hwloc_obj_t obj;
672  obj = hwloc_get_obj_by_type (topology, type1, idx1);
673  if (!obj || !obj->cpuset)
674  return NULL;
675  return hwloc_get_obj_inside_cpuset_by_type(topology, obj->cpuset, type2, idx2);
676 }
677 
696 static inline hwloc_obj_t
697 hwloc_get_obj_below_array_by_type (hwloc_topology_t topology, int nr, hwloc_obj_type_t *typev, unsigned *idxv) ;
698 static inline hwloc_obj_t
699 hwloc_get_obj_below_array_by_type (hwloc_topology_t topology, int nr, hwloc_obj_type_t *typev, unsigned *idxv)
700 {
701  hwloc_obj_t obj = hwloc_get_root_obj(topology);
702  int i;
703  for(i=0; i<nr; i++) {
704  if (!obj || !obj->cpuset)
705  return NULL;
706  obj = hwloc_get_obj_inside_cpuset_by_type(topology, obj->cpuset, typev[i], idxv[i]);
707  }
708  return obj;
709 }
710 
734 static inline void
735 hwloc_distributev(hwloc_topology_t topology, hwloc_obj_t *root, unsigned n_roots, hwloc_cpuset_t *cpuset, unsigned n, unsigned until);
736 static inline void
737 hwloc_distribute(hwloc_topology_t topology, hwloc_obj_t root, hwloc_cpuset_t *cpuset, unsigned n, unsigned until)
738 {
739  unsigned i;
740  if (!root->arity || n == 1 || root->depth >= until) {
741  /* Got to the bottom, we can't split any more, put everything there. */
742  for (i=0; i<n; i++)
743  cpuset[i] = hwloc_bitmap_dup(root->cpuset);
744  return;
745  }
746  hwloc_distributev(topology, root->children, root->arity, cpuset, n, until);
747 }
748 
756 static inline void
757 hwloc_distributev(hwloc_topology_t topology, hwloc_obj_t *roots, unsigned n_roots, hwloc_cpuset_t *cpuset, unsigned n, unsigned until)
758 {
759  unsigned i;
760  unsigned tot_weight;
761  hwloc_cpuset_t *cpusetp = cpuset;
762 
763  tot_weight = 0;
764  for (i = 0; i < n_roots; i++)
765  if (roots[i]->cpuset)
766  tot_weight += hwloc_bitmap_weight(roots[i]->cpuset);
767 
768  for (i = 0; i < n_roots && tot_weight; i++) {
769  /* Give to roots[i] a portion proportional to its weight */
770  unsigned weight = roots[i]->cpuset ? hwloc_bitmap_weight(roots[i]->cpuset) : 0;
771  unsigned chunk = (n * weight + tot_weight-1) / tot_weight;
772  hwloc_distribute(topology, roots[i], cpusetp, chunk, until);
773  cpusetp += chunk;
774  tot_weight -= weight;
775  n -= chunk;
776  }
777 }
778 
785 static inline void *
787 {
788  void *p = hwloc_alloc_membind_nodeset(topology, len, nodeset, policy, flags);
789  if (p)
790  return p;
791  hwloc_set_membind_nodeset(topology, nodeset, policy, flags);
792  p = hwloc_alloc(topology, len);
793  if (p && policy != HWLOC_MEMBIND_FIRSTTOUCH)
794  /* Enforce the binding by touching the data */
795  memset(p, 0, len);
796  return p;
797 }
798 
803 static inline void *
805 {
806  void *p = hwloc_alloc_membind(topology, len, cpuset, policy, flags);
807  if (p)
808  return p;
809  hwloc_set_membind(topology, cpuset, policy, flags);
810  p = hwloc_alloc(topology, len);
811  if (p && policy != HWLOC_MEMBIND_FIRSTTOUCH)
812  /* Enforce the binding by touching the data */
813  memset(p, 0, len);
814  return p;
815 }
816 
833 static inline hwloc_const_cpuset_t
835 static inline hwloc_const_cpuset_t
837 {
838  return hwloc_get_root_obj(topology)->complete_cpuset;
839 }
840 
851 static inline hwloc_const_cpuset_t
853 static inline hwloc_const_cpuset_t
855 {
856  return hwloc_get_root_obj(topology)->cpuset;
857 }
858 
868 static inline hwloc_const_cpuset_t
870 static inline hwloc_const_cpuset_t
872 {
873  return hwloc_get_root_obj(topology)->online_cpuset;
874 }
875 
885 static inline hwloc_const_cpuset_t
887 static inline hwloc_const_cpuset_t
889 {
890  return hwloc_get_root_obj(topology)->allowed_cpuset;
891 }
892 
909 static inline hwloc_const_nodeset_t
911 static inline hwloc_const_nodeset_t
913 {
914  return hwloc_get_root_obj(topology)->complete_nodeset;
915 }
916 
927 static inline hwloc_const_nodeset_t
929 static inline hwloc_const_nodeset_t
931 {
932  return hwloc_get_root_obj(topology)->nodeset;
933 }
934 
944 static inline hwloc_const_nodeset_t
946 static inline hwloc_const_nodeset_t
948 {
949  return hwloc_get_root_obj(topology)->allowed_nodeset;
950 }
951 
982 static inline void
984 {
985  int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NODE);
986  hwloc_obj_t obj;
987 
988  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN) {
989  if (hwloc_bitmap_iszero(cpuset))
990  hwloc_bitmap_zero(nodeset);
991  else
992  /* Assume the whole system */
993  hwloc_bitmap_fill(nodeset);
994  return;
995  }
996 
997  hwloc_bitmap_zero(nodeset);
998  obj = NULL;
999  while ((obj = hwloc_get_next_obj_covering_cpuset_by_depth(topology, cpuset, depth, obj)) != NULL)
1000  hwloc_bitmap_set(nodeset, obj->os_index);
1001 }
1002 
1010 static inline void
1012 {
1013  int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NODE);
1014  hwloc_obj_t obj;
1015  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN )
1016  return;
1017  hwloc_bitmap_zero(nodeset);
1018  obj = NULL;
1019  while ((obj = hwloc_get_next_obj_covering_cpuset_by_depth(topology, cpuset, depth, obj)) != NULL)
1020  hwloc_bitmap_set(nodeset, obj->os_index);
1021 }
1022 
1031 static inline void
1033 {
1034  int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NODE);
1035  hwloc_obj_t obj;
1036 
1037  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN ) {
1038  if (hwloc_bitmap_iszero(nodeset))
1039  hwloc_bitmap_zero(cpuset);
1040  else
1041  /* Assume the whole system */
1042  hwloc_bitmap_fill(cpuset);
1043  return;
1044  }
1045 
1046  hwloc_bitmap_zero(cpuset);
1047  obj = NULL;
1048  while ((obj = hwloc_get_next_obj_by_depth(topology, depth, obj)) != NULL) {
1049  if (hwloc_bitmap_isset(nodeset, obj->os_index))
1050  /* no need to check obj->cpuset because objects in levels always have a cpuset */
1051  hwloc_bitmap_or(cpuset, cpuset, obj->cpuset);
1052  }
1053 }
1054 
1062 static inline void
1064 {
1065  int depth = hwloc_get_type_depth(topology, HWLOC_OBJ_NODE);
1066  hwloc_obj_t obj;
1067  if (depth == HWLOC_TYPE_DEPTH_UNKNOWN )
1068  return;
1069  hwloc_bitmap_zero(cpuset);
1070  obj = NULL;
1071  while ((obj = hwloc_get_next_obj_by_depth(topology, depth, obj)) != NULL)
1072  if (hwloc_bitmap_isset(nodeset, obj->os_index))
1073  /* no need to check obj->cpuset because objects in levels always have a cpuset */
1074  hwloc_bitmap_or(cpuset, cpuset, obj->cpuset);
1075 }
1076 
1104 static inline const struct hwloc_distances_s *
1106 {
1107  hwloc_obj_t root = hwloc_get_root_obj(topology);
1108  unsigned i;
1109  for(i=0; i<root->distances_count; i++)
1110  if (root->distances[i]->relative_depth == depth)
1111  return root->distances[i];
1112  return NULL;
1113 }
1114 
1134 static inline const struct hwloc_distances_s *
1136 {
1137  int depth = hwloc_get_type_depth(topology, type);
1138  if (depth < 0)
1139  return NULL;
1140  return hwloc_get_whole_distance_matrix_by_depth(topology, depth);
1141 }
1142 
1156 static inline const struct hwloc_distances_s *
1158  hwloc_obj_t obj, unsigned depth,
1159  unsigned *firstp)
1160 {
1161  while (obj && obj->cpuset) {
1162  unsigned i;
1163  for(i=0; i<obj->distances_count; i++)
1164  if (obj->distances[i]->relative_depth == depth - obj->depth) {
1165  if (!obj->distances[i]->nbobjs)
1166  continue;
1167  *firstp = hwloc_get_next_obj_inside_cpuset_by_depth(topology, obj->cpuset, depth, NULL)->logical_index;
1168  return obj->distances[i];
1169  }
1170  obj = obj->parent;
1171  }
1172  return NULL;
1173 }
1174 
1186 static inline int
1188  hwloc_obj_t obj1, hwloc_obj_t obj2,
1189  float *latency, float *reverse_latency)
1190 {
1191  hwloc_obj_t ancestor;
1192  const struct hwloc_distances_s * distances;
1193  unsigned first_logical ;
1194 
1195  if (obj1->depth != obj2->depth) {
1196  errno = EINVAL;
1197  return -1;
1198  }
1199 
1200  ancestor = hwloc_get_common_ancestor_obj(topology, obj1, obj2);
1201  distances = hwloc_get_distance_matrix_covering_obj_by_depth(topology, ancestor, obj1->depth, &first_logical);
1202  if (distances && distances->latency) {
1203  const float * latency_matrix = distances->latency;
1204  unsigned nbobjs = distances->nbobjs;
1205  unsigned l1 = obj1->logical_index - first_logical;
1206  unsigned l2 = obj2->logical_index - first_logical;
1207  *latency = latency_matrix[l1*nbobjs+l2];
1208  *reverse_latency = latency_matrix[l2*nbobjs+l1];
1209  return 0;
1210  }
1211 
1212  errno = ENOSYS;
1213  return -1;
1214 }
1215 
1230 static inline hwloc_obj_t
1232  hwloc_obj_t ioobj)
1233 {
1234  hwloc_obj_t obj = ioobj;
1235  while (obj && !obj->cpuset) {
1236  obj = obj->parent;
1237  }
1238  return obj;
1239 }
1240 
1245 static inline hwloc_obj_t
1247 {
1248  return hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_PCI_DEVICE, prev);
1249 }
1250 
1254 static inline hwloc_obj_t
1256  unsigned domain, unsigned bus, unsigned dev, unsigned func)
1257 {
1258  hwloc_obj_t obj = NULL;
1259  while ((obj = hwloc_get_next_pcidev(topology, obj)) != NULL) {
1260  if (obj->attr->pcidev.domain == domain
1261  && obj->attr->pcidev.bus == bus
1262  && obj->attr->pcidev.dev == dev
1263  && obj->attr->pcidev.func == func)
1264  return obj;
1265  }
1266  return NULL;
1267 }
1268 
1272 static inline hwloc_obj_t
1274 {
1275  unsigned domain = 0; /* default */
1276  unsigned bus, dev, func;
1277 
1278  if (sscanf(busid, "%x:%x.%x", &bus, &dev, &func) != 3
1279  && sscanf(busid, "%x:%x:%x.%x", &domain, &bus, &dev, &func) != 4) {
1280  errno = EINVAL;
1281  return NULL;
1282  }
1283 
1284  return hwloc_get_pcidev_by_busid(topology, domain, bus, dev, func);
1285 }
1286 
1291 static inline hwloc_obj_t
1293 {
1294  return hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_OS_DEVICE, prev);
1295 }
1296 
1301 static inline hwloc_obj_t
1303 {
1304  return hwloc_get_next_obj_by_type(topology, HWLOC_OBJ_BRIDGE, prev);
1305 }
1306 
1307 /* \brief Checks whether a given bridge covers a given PCI bus.
1308  */
1309 static inline int
1311  unsigned domain, unsigned bus)
1312 {
1313  return bridge->type == HWLOC_OBJ_BRIDGE
1315  && bridge->attr->bridge.downstream.pci.domain == domain
1316  && bridge->attr->bridge.downstream.pci.secondary_bus <= bus
1317  && bridge->attr->bridge.downstream.pci.subordinate_bus >= bus;
1318 }
1319 
1325 static inline hwloc_obj_t
1327  unsigned domain, unsigned bus)
1328 {
1329  hwloc_obj_t obj = NULL;
1330  while ((obj = hwloc_get_next_bridge(topology, obj)) != NULL) {
1331  if (hwloc_bridge_covers_pcibus(obj, domain, bus)) {
1332  /* found bridge covering this pcibus, make sure it's a hostbridge */
1334  assert(obj->parent->type != HWLOC_OBJ_BRIDGE);
1335  assert(obj->parent->cpuset);
1336  return obj;
1337  }
1338  }
1339  return NULL;
1340 }
1341 
1346 #ifdef __cplusplus
1347 } /* extern "C" */
1348 #endif
1349 
1350 
1351 #endif /* HWLOC_HELPER_H */