This source file includes following definitions.
- hwloc_synthetic_process_indexes
- hwloc_synthetic_parse_memory_attr
- hwloc_synthetic_parse_attrs
- hwloc_synthetic_free_levels
- hwloc_backend_synthetic_init
- hwloc_synthetic_set_attr
- hwloc_synthetic_next_index
- hwloc_synthetic_insert_attached
- hwloc__look_synthetic
- hwloc_look_synthetic
- hwloc_synthetic_backend_disable
- hwloc_synthetic_component_instantiate
- hwloc__export_synthetic_update_status
- hwloc__export_synthetic_add_char
- hwloc__export_synthetic_indexes
- hwloc__export_synthetic_obj_attr
- hwloc__export_synthetic_obj
- hwloc__export_synthetic_memory_children
- hwloc_check_memory_symmetric
- hwloc_topology_export_synthetic
1
2
3
4
5
6
7
8
9 #include <private/autogen/config.h>
10 #include <hwloc.h>
11 #include <private/private.h>
12 #include <private/misc.h>
13 #include <private/debug.h>
14
15 #include <limits.h>
16 #include <assert.h>
17 #ifdef HAVE_STRINGS_H
18 #include <strings.h>
19 #endif
20
21 struct hwloc_synthetic_attr_s {
22 hwloc_obj_type_t type;
23 unsigned depth;
24 hwloc_obj_cache_type_t cachetype;
25 hwloc_uint64_t memorysize;
26 };
27
28 struct hwloc_synthetic_indexes_s {
29
30 const char *string;
31 unsigned long string_length;
32
33 unsigned *array;
34
35
36 unsigned next;
37 };
38
39 struct hwloc_synthetic_level_data_s {
40 unsigned arity;
41 unsigned long totalwidth;
42
43 struct hwloc_synthetic_attr_s attr;
44 struct hwloc_synthetic_indexes_s indexes;
45
46 struct hwloc_synthetic_attached_s {
47 struct hwloc_synthetic_attr_s attr;
48
49 struct hwloc_synthetic_attached_s *next;
50 } *attached;
51 };
52
53 struct hwloc_synthetic_backend_data_s {
54
55 char *string;
56
57 unsigned long numa_attached_nr;
58 struct hwloc_synthetic_indexes_s numa_attached_indexes;
59
60 #define HWLOC_SYNTHETIC_MAX_DEPTH 128
61 struct hwloc_synthetic_level_data_s level[HWLOC_SYNTHETIC_MAX_DEPTH];
62 };
63
64 struct hwloc_synthetic_intlv_loop_s {
65 unsigned step;
66 unsigned nb;
67 unsigned level_depth;
68 };
69
70 static void
71 hwloc_synthetic_process_indexes(struct hwloc_synthetic_backend_data_s *data,
72 struct hwloc_synthetic_indexes_s *indexes,
73 unsigned long total,
74 int verbose)
75 {
76 const char *attr = indexes->string;
77 unsigned long length = indexes->string_length;
78 unsigned *array = NULL;
79 size_t i;
80
81 if (!attr)
82 return;
83
84 array = calloc(total, sizeof(*array));
85 if (!array) {
86 if (verbose)
87 fprintf(stderr, "Failed to allocate synthetic index array of size %lu\n", total);
88 goto out;
89 }
90
91 i = strspn(attr, "0123456789,");
92 if (i == length) {
93
94
95 for(i=0; i<total; i++) {
96 const char *next;
97 unsigned idx = strtoul(attr, (char **) &next, 10);
98 if (next == attr) {
99 if (verbose)
100 fprintf(stderr, "Failed to read synthetic index #%lu at '%s'\n", (unsigned long) i, attr);
101 goto out_with_array;
102 }
103
104 array[i] = idx;
105 if (i != total-1) {
106 if (*next != ',') {
107 if (verbose)
108 fprintf(stderr, "Missing comma after synthetic index #%lu at '%s'\n", (unsigned long) i, attr);
109 goto out_with_array;
110 }
111 attr = next+1;
112 } else {
113 attr = next;
114 }
115 }
116 indexes->array = array;
117
118 } else {
119
120 unsigned nr_loops = 1, cur_loop;
121 unsigned minstep = total;
122 unsigned long nbs = 1;
123 unsigned j, mul;
124 const char *tmp;
125
126 tmp = attr;
127 while (tmp) {
128 tmp = strchr(tmp, ':');
129 if (!tmp || tmp >= attr+length)
130 break;
131 nr_loops++;
132 tmp++;
133 }
134
135 {
136
137 HWLOC_VLA(struct hwloc_synthetic_intlv_loop_s, loops, nr_loops+1);
138
139 if (*attr >= '0' && *attr <= '9') {
140
141 unsigned step, nb;
142
143 tmp = attr;
144 cur_loop = 0;
145 while (tmp) {
146 char *tmp2, *tmp3;
147 step = (unsigned) strtol(tmp, &tmp2, 0);
148 if (tmp2 == tmp || *tmp2 != '*') {
149 if (verbose)
150 fprintf(stderr, "Failed to read synthetic index interleaving loop '%s' without number before '*'\n", tmp);
151 goto out_with_array;
152 }
153 if (!step) {
154 if (verbose)
155 fprintf(stderr, "Invalid interleaving loop with step 0 at '%s'\n", tmp);
156 goto out_with_array;
157 }
158 tmp2++;
159 nb = (unsigned) strtol(tmp2, &tmp3, 0);
160 if (tmp3 == tmp2 || (*tmp3 && *tmp3 != ':' && *tmp3 != ')' && *tmp3 != ' ')) {
161 if (verbose)
162 fprintf(stderr, "Failed to read synthetic index interleaving loop '%s' without number between '*' and ':'\n", tmp);
163 goto out_with_array;
164 }
165 if (!nb) {
166 if (verbose)
167 fprintf(stderr, "Invalid interleaving loop with number 0 at '%s'\n", tmp2);
168 goto out_with_array;
169 }
170 loops[cur_loop].step = step;
171 loops[cur_loop].nb = nb;
172 if (step < minstep)
173 minstep = step;
174 nbs *= nb;
175 cur_loop++;
176 if (*tmp3 == ')' || *tmp3 == ' ')
177 break;
178 tmp = (const char*) (tmp3+1);
179 }
180
181 } else {
182
183 hwloc_obj_type_t type;
184 union hwloc_obj_attr_u attrs;
185 int err;
186
187
188 tmp = attr;
189 cur_loop = 0;
190 while (tmp) {
191 err = hwloc_type_sscanf(tmp, &type, &attrs, sizeof(attrs));
192 if (err < 0) {
193 if (verbose)
194 fprintf(stderr, "Failed to read synthetic index interleaving loop type '%s'\n", tmp);
195 goto out_with_array;
196 }
197 if (type == HWLOC_OBJ_MISC || type == HWLOC_OBJ_BRIDGE || type == HWLOC_OBJ_PCI_DEVICE || type == HWLOC_OBJ_OS_DEVICE) {
198 if (verbose)
199 fprintf(stderr, "Misc object type disallowed in synthetic index interleaving loop type '%s'\n", tmp);
200 goto out_with_array;
201 }
202 for(i=0; ; i++) {
203 if (!data->level[i].arity) {
204 loops[cur_loop].level_depth = (unsigned)-1;
205 break;
206 }
207 if (type != data->level[i].attr.type)
208 continue;
209 if (type == HWLOC_OBJ_GROUP
210 && attrs.group.depth != (unsigned) -1
211 && attrs.group.depth != data->level[i].attr.depth)
212 continue;
213 loops[cur_loop].level_depth = (unsigned)i;
214 break;
215 }
216 if (loops[cur_loop].level_depth == (unsigned)-1) {
217 if (verbose)
218 fprintf(stderr, "Failed to find level for synthetic index interleaving loop type '%s'\n",
219 tmp);
220 goto out_with_array;
221 }
222 tmp = strchr(tmp, ':');
223 if (!tmp || tmp > attr+length)
224 break;
225 tmp++;
226 cur_loop++;
227 }
228
229
230 for(cur_loop=0; cur_loop<nr_loops; cur_loop++) {
231 unsigned mydepth = loops[cur_loop].level_depth;
232 unsigned prevdepth = 0;
233 unsigned step, nb;
234 for(i=0; i<nr_loops; i++) {
235 if (loops[i].level_depth == mydepth && i != cur_loop) {
236 if (verbose)
237 fprintf(stderr, "Invalid duplicate interleaving loop type in synthetic index '%s'\n", attr);
238 goto out_with_array;
239 }
240 if (loops[i].level_depth < mydepth
241 && loops[i].level_depth > prevdepth)
242 prevdepth = loops[i].level_depth;
243 }
244 step = total / data->level[mydepth].totalwidth;
245 nb = data->level[mydepth].totalwidth / data->level[prevdepth].totalwidth;
246
247 loops[cur_loop].step = step;
248 loops[cur_loop].nb = nb;
249 assert(nb);
250 assert(step);
251 if (step < minstep)
252 minstep = step;
253 nbs *= nb;
254 }
255 }
256 assert(nbs);
257
258 if (nbs != total) {
259
260 if (minstep == total/nbs) {
261 loops[nr_loops].step = 1;
262 loops[nr_loops].nb = total/nbs;
263 nr_loops++;
264 } else {
265 if (verbose)
266 fprintf(stderr, "Invalid index interleaving total width %lu instead of %lu\n", nbs, total);
267 goto out_with_array;
268 }
269 }
270
271
272 mul = 1;
273 for(i=0; i<nr_loops; i++) {
274 unsigned step = loops[i].step;
275 unsigned nb = loops[i].nb;
276 for(j=0; j<total; j++)
277 array[j] += ((j / step) % nb) * mul;
278 mul *= nb;
279 }
280
281
282 for(j=0; j<total; j++) {
283 if (array[j] >= total) {
284 if (verbose)
285 fprintf(stderr, "Invalid index interleaving generates out-of-range index %u\n", array[j]);
286 goto out_with_array;
287 }
288 if (!array[j] && j) {
289 if (verbose)
290 fprintf(stderr, "Invalid index interleaving generates duplicate index values\n");
291 goto out_with_array;
292 }
293 }
294
295 indexes->array = array;
296 }
297 }
298
299 return;
300
301 out_with_array:
302 free(array);
303 out:
304 return;
305 }
306
307 static hwloc_uint64_t
308 hwloc_synthetic_parse_memory_attr(const char *attr, const char **endp)
309 {
310 const char *endptr;
311 hwloc_uint64_t size;
312 size = strtoull(attr, (char **) &endptr, 0);
313 if (!hwloc_strncasecmp(endptr, "TB", 2)) {
314 size <<= 40;
315 endptr += 2;
316 } else if (!hwloc_strncasecmp(endptr, "GB", 2)) {
317 size <<= 30;
318 endptr += 2;
319 } else if (!hwloc_strncasecmp(endptr, "MB", 2)) {
320 size <<= 20;
321 endptr += 2;
322 } else if (!hwloc_strncasecmp(endptr, "kB", 2)) {
323 size <<= 10;
324 endptr += 2;
325 }
326 *endp = endptr;
327 return size;
328 }
329
330 static int
331 hwloc_synthetic_parse_attrs(const char *attrs, const char **next_posp,
332 struct hwloc_synthetic_attr_s *sattr,
333 struct hwloc_synthetic_indexes_s *sind,
334 int verbose)
335 {
336 hwloc_obj_type_t type = sattr->type;
337 const char *next_pos;
338 hwloc_uint64_t memorysize = 0;
339 const char *index_string = NULL;
340 size_t index_string_length = 0;
341
342 next_pos = (const char *) strchr(attrs, ')');
343 if (!next_pos) {
344 if (verbose)
345 fprintf(stderr, "Missing attribute closing bracket in synthetic string doesn't have a number of objects at '%s'\n", attrs);
346 errno = EINVAL;
347 return -1;
348 }
349
350 while (')' != *attrs) {
351 int iscache = hwloc__obj_type_is_cache(type);
352
353 if (iscache && !strncmp("size=", attrs, 5)) {
354 memorysize = hwloc_synthetic_parse_memory_attr(attrs+5, &attrs);
355
356 } else if (!iscache && !strncmp("memory=", attrs, 7)) {
357 memorysize = hwloc_synthetic_parse_memory_attr(attrs+7, &attrs);
358
359 } else if (!strncmp("indexes=", attrs, 8)) {
360 index_string = attrs+8;
361 attrs += 8;
362 index_string_length = strcspn(attrs, " )");
363 attrs += index_string_length;
364
365 } else {
366 if (verbose)
367 fprintf(stderr, "Unknown attribute at '%s'\n", attrs);
368 errno = EINVAL;
369 return -1;
370 }
371
372 if (' ' == *attrs)
373 attrs++;
374 else if (')' != *attrs) {
375 if (verbose)
376 fprintf(stderr, "Missing parameter separator at '%s'\n", attrs);
377 errno = EINVAL;
378 return -1;
379 }
380 }
381
382 sattr->memorysize = memorysize;
383
384 if (index_string) {
385 if (sind->string && verbose)
386 fprintf(stderr, "Overwriting duplicate indexes attribute with last occurence\n");
387 sind->string = index_string;
388 sind->string_length = (unsigned long)index_string_length;
389 }
390
391 *next_posp = next_pos+1;
392 return 0;
393 }
394
395
396 static void
397 hwloc_synthetic_free_levels(struct hwloc_synthetic_backend_data_s *data)
398 {
399 unsigned i;
400 for(i=0; i<HWLOC_SYNTHETIC_MAX_DEPTH; i++) {
401 struct hwloc_synthetic_level_data_s *curlevel = &data->level[i];
402 struct hwloc_synthetic_attached_s **pprev = &curlevel->attached;
403 while (*pprev) {
404 struct hwloc_synthetic_attached_s *cur = *pprev;
405 *pprev = cur->next;
406 free(cur);
407 }
408 free(curlevel->indexes.array);
409 if (!curlevel->arity)
410 break;
411 }
412 free(data->numa_attached_indexes.array);
413 }
414
415
416
417
418 static int
419 hwloc_backend_synthetic_init(struct hwloc_synthetic_backend_data_s *data,
420 const char *description)
421 {
422 const char *pos, *next_pos;
423 unsigned long item, count;
424 unsigned i;
425 int type_count[HWLOC_OBJ_TYPE_MAX];
426 unsigned unset;
427 int verbose = 0;
428 const char *env = getenv("HWLOC_SYNTHETIC_VERBOSE");
429 int err;
430 unsigned long totalarity = 1;
431
432 if (env)
433 verbose = atoi(env);
434
435 data->numa_attached_nr = 0;
436 data->numa_attached_indexes.array = NULL;
437
438
439 data->level[0].totalwidth = 1;
440 data->level[0].attr.type = HWLOC_OBJ_MACHINE;
441 data->level[0].indexes.string = NULL;
442 data->level[0].indexes.array = NULL;
443 data->level[0].attr.memorysize = 0;
444 data->level[0].attached = NULL;
445 type_count[HWLOC_OBJ_MACHINE] = 1;
446 if (*description == '(') {
447 err = hwloc_synthetic_parse_attrs(description+1, &description, &data->level[0].attr, &data->level[0].indexes, verbose);
448 if (err < 0)
449 return err;
450 }
451
452 data->numa_attached_indexes.string = NULL;
453 data->numa_attached_indexes.array = NULL;
454
455 for (pos = description, count = 1; *pos; pos = next_pos) {
456 hwloc_obj_type_t type = HWLOC_OBJ_TYPE_NONE;
457 union hwloc_obj_attr_u attrs;
458
459
460 data->level[count-1].arity = 0;
461
462 while (*pos == ' ')
463 pos++;
464
465 if (!*pos)
466 break;
467
468 if (*pos == '[') {
469
470 struct hwloc_synthetic_attached_s *attached, **pprev;
471 char *attr;
472
473 pos++;
474
475 if (hwloc_type_sscanf(pos, &type, &attrs, sizeof(attrs)) < 0) {
476 if (verbose)
477 fprintf(stderr, "Synthetic string with unknown attached object type at '%s'\n", pos);
478 errno = EINVAL;
479 goto error;
480 }
481 if (type != HWLOC_OBJ_NUMANODE) {
482 if (verbose)
483 fprintf(stderr, "Synthetic string with disallowed attached object type at '%s'\n", pos);
484 errno = EINVAL;
485 goto error;
486 }
487 data->numa_attached_nr += data->level[count-1].totalwidth;
488
489 attached = malloc(sizeof(*attached));
490 if (attached) {
491 attached->attr.type = type;
492 attached->attr.memorysize = 0;
493
494 attached->next = NULL;
495 pprev = &data->level[count-1].attached;
496 while (*pprev)
497 pprev = &((*pprev)->next);
498 *pprev = attached;
499 }
500
501 next_pos = strchr(pos, ']');
502 if (!next_pos) {
503 if (verbose)
504 fprintf(stderr,"Synthetic string doesn't have a closing `]' after attached object type at '%s'\n", pos);
505 errno = EINVAL;
506 goto error;
507 }
508
509 attr = strchr(pos, '(');
510 if (attr && attr < next_pos && attached) {
511 const char *dummy;
512 err = hwloc_synthetic_parse_attrs(attr+1, &dummy, &attached->attr, &data->numa_attached_indexes, verbose);
513 if (err < 0)
514 goto error;
515 }
516
517 next_pos++;
518 continue;
519 }
520
521
522
523
524 data->level[count].indexes.string = NULL;
525 data->level[count].indexes.array = NULL;
526 data->level[count].attached = NULL;
527
528 if (*pos < '0' || *pos > '9') {
529 if (hwloc_type_sscanf(pos, &type, &attrs, sizeof(attrs)) < 0) {
530
531 if (verbose)
532 fprintf(stderr, "Synthetic string with unknown object type at '%s'\n", pos);
533 errno = EINVAL;
534 goto error;
535 }
536 if (type == HWLOC_OBJ_MACHINE || type == HWLOC_OBJ_MISC || type == HWLOC_OBJ_BRIDGE || type == HWLOC_OBJ_PCI_DEVICE || type == HWLOC_OBJ_OS_DEVICE) {
537 if (verbose)
538 fprintf(stderr, "Synthetic string with disallowed object type at '%s'\n", pos);
539 errno = EINVAL;
540 goto error;
541 }
542
543 next_pos = strchr(pos, ':');
544 if (!next_pos) {
545 if (verbose)
546 fprintf(stderr,"Synthetic string doesn't have a `:' after object type at '%s'\n", pos);
547 errno = EINVAL;
548 goto error;
549 }
550 pos = next_pos + 1;
551 }
552
553 data->level[count].attr.type = type;
554 data->level[count].attr.depth = (unsigned) -1;
555 data->level[count].attr.cachetype = (hwloc_obj_cache_type_t) -1;
556 if (hwloc__obj_type_is_cache(type)) {
557
558 data->level[count].attr.depth = attrs.cache.depth;
559 data->level[count].attr.cachetype = attrs.cache.type;
560 } else if (type == HWLOC_OBJ_GROUP) {
561
562 data->level[count].attr.depth = attrs.group.depth;
563 }
564
565
566 item = strtoul(pos, (char **)&next_pos, 0);
567 if (next_pos == pos) {
568 if (verbose)
569 fprintf(stderr,"Synthetic string doesn't have a number of objects at '%s'\n", pos);
570 errno = EINVAL;
571 goto error;
572 }
573 if (!item) {
574 if (verbose)
575 fprintf(stderr,"Synthetic string with disallow 0 number of objects at '%s'\n", pos);
576 errno = EINVAL;
577 goto error;
578 }
579 data->level[count-1].arity = (unsigned)item;
580
581 totalarity *= item;
582 data->level[count].totalwidth = totalarity;
583 data->level[count].indexes.string = NULL;
584 data->level[count].indexes.array = NULL;
585 data->level[count].attr.memorysize = 0;
586 if (*next_pos == '(') {
587 err = hwloc_synthetic_parse_attrs(next_pos+1, &next_pos, &data->level[count].attr, &data->level[count].indexes, verbose);
588 if (err < 0)
589 goto error;
590 }
591
592 if (count + 1 >= HWLOC_SYNTHETIC_MAX_DEPTH) {
593 if (verbose)
594 fprintf(stderr,"Too many synthetic levels, max %d\n", HWLOC_SYNTHETIC_MAX_DEPTH);
595 errno = EINVAL;
596 goto error;
597 }
598 if (item > UINT_MAX) {
599 if (verbose)
600 fprintf(stderr,"Too big arity, max %u\n", UINT_MAX);
601 errno = EINVAL;
602 goto error;
603 }
604
605 count++;
606 }
607
608 if (data->level[count-1].attr.type != HWLOC_OBJ_TYPE_NONE && data->level[count-1].attr.type != HWLOC_OBJ_PU) {
609 if (verbose)
610 fprintf(stderr, "Synthetic string cannot use non-PU type for last level\n");
611 errno = EINVAL;
612 return -1;
613 }
614 data->level[count-1].attr.type = HWLOC_OBJ_PU;
615
616 for(i=HWLOC_OBJ_TYPE_MIN; i<HWLOC_OBJ_TYPE_MAX; i++) {
617 type_count[i] = 0;
618 }
619 for(i=count-1; i>0; i--) {
620 hwloc_obj_type_t type = data->level[i].attr.type;
621 if (type != HWLOC_OBJ_TYPE_NONE) {
622 type_count[type]++;
623 }
624 }
625
626
627 if (!type_count[HWLOC_OBJ_PU]) {
628 if (verbose)
629 fprintf(stderr, "Synthetic string missing ending number of PUs\n");
630 errno = EINVAL;
631 return -1;
632 } else if (type_count[HWLOC_OBJ_PU] > 1) {
633 if (verbose)
634 fprintf(stderr, "Synthetic string cannot have several PU levels\n");
635 errno = EINVAL;
636 return -1;
637 }
638 if (type_count[HWLOC_OBJ_PACKAGE] > 1) {
639 if (verbose)
640 fprintf(stderr, "Synthetic string cannot have several package levels\n");
641 errno = EINVAL;
642 return -1;
643 }
644 if (type_count[HWLOC_OBJ_NUMANODE] > 1) {
645 if (verbose)
646 fprintf(stderr, "Synthetic string cannot have several NUMA node levels\n");
647 errno = EINVAL;
648 return -1;
649 }
650 if (type_count[HWLOC_OBJ_NUMANODE] && data->numa_attached_nr) {
651 if (verbose)
652 fprintf(stderr,"Synthetic string cannot have NUMA nodes both as a level and attached\n");
653 errno = EINVAL;
654 return -1;
655 }
656 if (type_count[HWLOC_OBJ_CORE] > 1) {
657 if (verbose)
658 fprintf(stderr, "Synthetic string cannot have several core levels\n");
659 errno = EINVAL;
660 return -1;
661 }
662
663
664 unset = 0;
665 for(i=1; i<count-1; i++) {
666 if (data->level[i].attr.type == HWLOC_OBJ_TYPE_NONE)
667 unset++;
668 }
669 if (unset && unset != count-2) {
670 if (verbose)
671 fprintf(stderr, "Synthetic string cannot mix unspecified and specified types for levels\n");
672 errno = EINVAL;
673 return -1;
674 }
675 if (unset) {
676
677 unsigned _count = count;
678 unsigned neednuma = 0;
679 unsigned needpack = 0;
680 unsigned needcore = 0;
681 unsigned needcaches = 0;
682 unsigned needgroups = 0;
683
684 _count -= 2;
685
686 neednuma = (_count >= 1 && !data->numa_attached_nr);
687 _count -= neednuma;
688
689 needpack = (_count >= 1);
690 _count -= needpack;
691
692 needcore = (_count >= 1);
693 _count -= needcore;
694
695 needcaches = (_count > 4 ? 4 : _count);
696 _count -= needcaches;
697
698 needgroups = _count;
699
700
701 for(i = 0; i < needgroups; i++) {
702 unsigned depth = 1 + i;
703 data->level[depth].attr.type = HWLOC_OBJ_GROUP;
704 type_count[HWLOC_OBJ_GROUP]++;
705 }
706 if (needpack) {
707 unsigned depth = 1 + needgroups;
708 data->level[depth].attr.type = HWLOC_OBJ_PACKAGE;
709 type_count[HWLOC_OBJ_PACKAGE] = 1;
710 }
711 if (neednuma) {
712 unsigned depth = 1 + needgroups + needpack;
713 data->level[depth].attr.type = HWLOC_OBJ_NUMANODE;
714 type_count[HWLOC_OBJ_NUMANODE] = 1;
715 }
716 if (needcaches) {
717
718
719 unsigned l3depth = 1 + needgroups + needpack + neednuma;
720 unsigned l2depth = l3depth + (needcaches >= 3);
721 unsigned l1depth = l2depth + 1;
722 unsigned l1idepth = l1depth + 1;
723 if (needcaches >= 3) {
724 data->level[l3depth].attr.type = HWLOC_OBJ_L3CACHE;
725 data->level[l3depth].attr.depth = 3;
726 data->level[l3depth].attr.cachetype = HWLOC_OBJ_CACHE_UNIFIED;
727 type_count[HWLOC_OBJ_L3CACHE] = 1;
728 }
729 data->level[l2depth].attr.type = HWLOC_OBJ_L2CACHE;
730 data->level[l2depth].attr.depth = 2;
731 data->level[l2depth].attr.cachetype = HWLOC_OBJ_CACHE_UNIFIED;
732 type_count[HWLOC_OBJ_L2CACHE] = 1;
733 if (needcaches >= 2) {
734 data->level[l1depth].attr.type = HWLOC_OBJ_L1CACHE;
735 data->level[l1depth].attr.depth = 1;
736 data->level[l1depth].attr.cachetype = HWLOC_OBJ_CACHE_DATA;
737 type_count[HWLOC_OBJ_L1CACHE] = 1;
738 }
739 if (needcaches >= 4) {
740 data->level[l1idepth].attr.type = HWLOC_OBJ_L1ICACHE;
741 data->level[l1idepth].attr.depth = 1;
742 data->level[l1idepth].attr.cachetype = HWLOC_OBJ_CACHE_INSTRUCTION;
743 type_count[HWLOC_OBJ_L1ICACHE] = 1;
744 }
745 }
746 if (needcore) {
747 unsigned depth = 1 + needgroups + needpack + neednuma + needcaches;
748 data->level[depth].attr.type = HWLOC_OBJ_CORE;
749 type_count[HWLOC_OBJ_CORE] = 1;
750 }
751 }
752
753
754 if (!type_count[HWLOC_OBJ_NUMANODE] && !data->numa_attached_nr) {
755
756 if (verbose)
757 fprintf(stderr, "Inserting a NUMA level with a single object at depth 1\n");
758
759 memmove(&data->level[2], &data->level[1], count*sizeof(struct hwloc_synthetic_level_data_s));
760 data->level[1].attr.type = HWLOC_OBJ_NUMANODE;
761 data->level[1].indexes.string = NULL;
762 data->level[1].indexes.array = NULL;
763 data->level[1].attr.memorysize = 0;
764 data->level[1].totalwidth = data->level[0].totalwidth;
765
766 data->level[1].arity = data->level[0].arity;
767 data->level[0].arity = 1;
768 count++;
769 }
770
771 for (i=0; i<count; i++) {
772 struct hwloc_synthetic_level_data_s *curlevel = &data->level[i];
773 hwloc_obj_type_t type = curlevel->attr.type;
774
775 if (type == HWLOC_OBJ_GROUP) {
776 if (curlevel->attr.depth == (unsigned)-1)
777 curlevel->attr.depth = type_count[HWLOC_OBJ_GROUP]--;
778
779 } else if (hwloc__obj_type_is_cache(type)) {
780 if (!curlevel->attr.memorysize) {
781 if (1 == curlevel->attr.depth)
782
783 curlevel->attr.memorysize = 32*1024;
784 else
785
786 curlevel->attr.memorysize = 256*1024 << (2*curlevel->attr.depth);
787 }
788
789 } else if (type == HWLOC_OBJ_NUMANODE && !curlevel->attr.memorysize) {
790
791 curlevel->attr.memorysize = 1024*1024*1024;
792 }
793
794 hwloc_synthetic_process_indexes(data, &data->level[i].indexes, data->level[i].totalwidth, verbose);
795 }
796
797 hwloc_synthetic_process_indexes(data, &data->numa_attached_indexes, data->numa_attached_nr, verbose);
798
799 data->string = strdup(description);
800 data->level[count-1].arity = 0;
801 return 0;
802
803 error:
804 hwloc_synthetic_free_levels(data);
805 return -1;
806 }
807
808 static void
809 hwloc_synthetic_set_attr(struct hwloc_synthetic_attr_s *sattr,
810 hwloc_obj_t obj)
811 {
812 switch (obj->type) {
813 case HWLOC_OBJ_GROUP:
814 obj->attr->group.kind = HWLOC_GROUP_KIND_SYNTHETIC;
815 obj->attr->group.subkind = sattr->depth-1;
816 break;
817 case HWLOC_OBJ_MACHINE:
818 break;
819 case HWLOC_OBJ_NUMANODE:
820 obj->attr->numanode.local_memory = sattr->memorysize;
821 obj->attr->numanode.page_types_len = 1;
822 obj->attr->numanode.page_types = malloc(sizeof(*obj->attr->numanode.page_types));
823 memset(obj->attr->numanode.page_types, 0, sizeof(*obj->attr->numanode.page_types));
824 obj->attr->numanode.page_types[0].size = 4096;
825 obj->attr->numanode.page_types[0].count = sattr->memorysize / 4096;
826 break;
827 case HWLOC_OBJ_PACKAGE:
828 break;
829 case HWLOC_OBJ_L1CACHE:
830 case HWLOC_OBJ_L2CACHE:
831 case HWLOC_OBJ_L3CACHE:
832 case HWLOC_OBJ_L4CACHE:
833 case HWLOC_OBJ_L5CACHE:
834 case HWLOC_OBJ_L1ICACHE:
835 case HWLOC_OBJ_L2ICACHE:
836 case HWLOC_OBJ_L3ICACHE:
837 obj->attr->cache.depth = sattr->depth;
838 obj->attr->cache.linesize = 64;
839 obj->attr->cache.type = sattr->cachetype;
840 obj->attr->cache.size = sattr->memorysize;
841 break;
842 case HWLOC_OBJ_CORE:
843 break;
844 case HWLOC_OBJ_PU:
845 break;
846 default:
847
848 assert(0);
849 break;
850 }
851 }
852
853 static unsigned
854 hwloc_synthetic_next_index(struct hwloc_synthetic_indexes_s *indexes, hwloc_obj_type_t type)
855 {
856 unsigned os_index = indexes->next++;
857
858 if (indexes->array)
859 os_index = indexes->array[os_index];
860 else if (hwloc__obj_type_is_cache(type) || type == HWLOC_OBJ_GROUP)
861
862 os_index = HWLOC_UNKNOWN_INDEX;
863
864 return os_index;
865 }
866
867 static void
868 hwloc_synthetic_insert_attached(struct hwloc_topology *topology,
869 struct hwloc_synthetic_backend_data_s *data,
870 struct hwloc_synthetic_attached_s *attached,
871 hwloc_bitmap_t set)
872 {
873 hwloc_obj_t child;
874 unsigned attached_os_index;
875
876 if (!attached)
877 return;
878
879 assert(attached->attr.type == HWLOC_OBJ_NUMANODE);
880
881 attached_os_index = hwloc_synthetic_next_index(&data->numa_attached_indexes, HWLOC_OBJ_NUMANODE);
882
883 child = hwloc_alloc_setup_object(topology, attached->attr.type, attached_os_index);
884 child->cpuset = hwloc_bitmap_dup(set);
885
886 child->nodeset = hwloc_bitmap_alloc();
887 hwloc_bitmap_set(child->nodeset, attached_os_index);
888
889 hwloc_synthetic_set_attr(&attached->attr, child);
890
891 hwloc_insert_object_by_cpuset(topology, child);
892
893 hwloc_synthetic_insert_attached(topology, data, attached->next, set);
894 }
895
896
897
898
899
900
901
902
903
904 static void
905 hwloc__look_synthetic(struct hwloc_topology *topology,
906 struct hwloc_synthetic_backend_data_s *data,
907 int level,
908 hwloc_bitmap_t parent_cpuset)
909 {
910 hwloc_obj_t obj;
911 unsigned i;
912 struct hwloc_synthetic_level_data_s *curlevel = &data->level[level];
913 hwloc_obj_type_t type = curlevel->attr.type;
914 hwloc_bitmap_t set;
915 unsigned os_index;
916
917 assert(hwloc__obj_type_is_normal(type) || type == HWLOC_OBJ_NUMANODE);
918 assert(type != HWLOC_OBJ_MACHINE);
919
920 os_index = hwloc_synthetic_next_index(&curlevel->indexes, type);
921
922 set = hwloc_bitmap_alloc();
923 if (!curlevel->arity) {
924 hwloc_bitmap_set(set, os_index);
925 } else {
926 for (i = 0; i < curlevel->arity; i++)
927 hwloc__look_synthetic(topology, data, level + 1, set);
928 }
929
930 hwloc_bitmap_or(parent_cpuset, parent_cpuset, set);
931
932 if (hwloc_filter_check_keep_object_type(topology, type)) {
933 obj = hwloc_alloc_setup_object(topology, type, os_index);
934 obj->cpuset = hwloc_bitmap_dup(set);
935
936 if (type == HWLOC_OBJ_NUMANODE) {
937 obj->nodeset = hwloc_bitmap_alloc();
938 hwloc_bitmap_set(obj->nodeset, os_index);
939 }
940
941 hwloc_synthetic_set_attr(&curlevel->attr, obj);
942
943 hwloc_insert_object_by_cpuset(topology, obj);
944 }
945
946 hwloc_synthetic_insert_attached(topology, data, curlevel->attached, set);
947
948 hwloc_bitmap_free(set);
949 }
950
951 static int
952 hwloc_look_synthetic(struct hwloc_backend *backend)
953 {
954 struct hwloc_topology *topology = backend->topology;
955 struct hwloc_synthetic_backend_data_s *data = backend->private_data;
956 hwloc_bitmap_t cpuset = hwloc_bitmap_alloc();
957 unsigned i;
958
959 assert(!topology->levels[0][0]->cpuset);
960
961 hwloc_alloc_root_sets(topology->levels[0][0]);
962
963 topology->support.discovery->pu = 1;
964 topology->support.discovery->numa = 1;
965 topology->support.discovery->numa_memory = 1;
966
967
968 for (i = 0; data->level[i].arity > 0; i++)
969 data->level[i].indexes.next = 0;
970 data->numa_attached_indexes.next = 0;
971
972 data->level[i].indexes.next = 0;
973
974
975 topology->levels[0][0]->type = data->level[0].attr.type;
976 hwloc_synthetic_set_attr(&data->level[0].attr, topology->levels[0][0]);
977
978 for (i = 0; i < data->level[0].arity; i++)
979 hwloc__look_synthetic(topology, data, 1, cpuset);
980
981 hwloc_synthetic_insert_attached(topology, data, data->level[0].attached, cpuset);
982
983 hwloc_bitmap_free(cpuset);
984
985 hwloc_obj_add_info(topology->levels[0][0], "Backend", "Synthetic");
986 hwloc_obj_add_info(topology->levels[0][0], "SyntheticDescription", data->string);
987 return 0;
988 }
989
990 static void
991 hwloc_synthetic_backend_disable(struct hwloc_backend *backend)
992 {
993 struct hwloc_synthetic_backend_data_s *data = backend->private_data;
994 hwloc_synthetic_free_levels(data);
995 free(data->string);
996 free(data);
997 }
998
999 static struct hwloc_backend *
1000 hwloc_synthetic_component_instantiate(struct hwloc_disc_component *component,
1001 const void *_data1,
1002 const void *_data2 __hwloc_attribute_unused,
1003 const void *_data3 __hwloc_attribute_unused)
1004 {
1005 struct hwloc_backend *backend;
1006 struct hwloc_synthetic_backend_data_s *data;
1007 int err;
1008
1009 if (!_data1) {
1010 const char *env = getenv("HWLOC_SYNTHETIC");
1011 if (env) {
1012
1013 _data1 = env;
1014 } else {
1015 errno = EINVAL;
1016 goto out;
1017 }
1018 }
1019
1020 backend = hwloc_backend_alloc(component);
1021 if (!backend)
1022 goto out;
1023
1024 data = malloc(sizeof(*data));
1025 if (!data) {
1026 errno = ENOMEM;
1027 goto out_with_backend;
1028 }
1029
1030 err = hwloc_backend_synthetic_init(data, (const char *) _data1);
1031 if (err < 0)
1032 goto out_with_data;
1033
1034 backend->private_data = data;
1035 backend->discover = hwloc_look_synthetic;
1036 backend->disable = hwloc_synthetic_backend_disable;
1037 backend->is_thissystem = 0;
1038
1039 return backend;
1040
1041 out_with_data:
1042 free(data);
1043 out_with_backend:
1044 free(backend);
1045 out:
1046 return NULL;
1047 }
1048
1049 static struct hwloc_disc_component hwloc_synthetic_disc_component = {
1050 HWLOC_DISC_COMPONENT_TYPE_GLOBAL,
1051 "synthetic",
1052 ~0,
1053 hwloc_synthetic_component_instantiate,
1054 30,
1055 1,
1056 NULL
1057 };
1058
1059 const struct hwloc_component hwloc_synthetic_component = {
1060 HWLOC_COMPONENT_ABI,
1061 NULL, NULL,
1062 HWLOC_COMPONENT_TYPE_DISC,
1063 0,
1064 &hwloc_synthetic_disc_component
1065 };
1066
1067 static __hwloc_inline int
1068 hwloc__export_synthetic_update_status(int *ret, char **tmp, ssize_t *tmplen, int res)
1069 {
1070 if (res < 0)
1071 return -1;
1072 *ret += res;
1073 if (res >= *tmplen)
1074 res = *tmplen>0 ? (int)(*tmplen) - 1 : 0;
1075 *tmp += res;
1076 *tmplen -= res;
1077 return 0;
1078 }
1079
1080 static __hwloc_inline void
1081 hwloc__export_synthetic_add_char(int *ret, char **tmp, ssize_t *tmplen, char c)
1082 {
1083 if (*tmplen > 1) {
1084 (*tmp)[0] = c;
1085 (*tmp)[1] = '\0';
1086 (*tmp)++;
1087 (*tmplen)--;
1088 }
1089 (*ret)++;
1090 }
1091
1092 static int
1093 hwloc__export_synthetic_indexes(hwloc_obj_t *level, unsigned total,
1094 char *buffer, size_t buflen)
1095 {
1096 unsigned step = 1;
1097 unsigned nr_loops = 0;
1098 struct hwloc_synthetic_intlv_loop_s *loops = NULL, *tmploops;
1099 hwloc_obj_t cur;
1100 unsigned i, j;
1101 ssize_t tmplen = buflen;
1102 char *tmp = buffer;
1103 int res, ret = 0;
1104
1105
1106 if (level[0]->os_index)
1107 goto exportall;
1108
1109 while (step != total) {
1110
1111 if (total % step)
1112 goto exportall;
1113
1114
1115 for(i=1; i<total; i++)
1116 if (level[i]->os_index == step)
1117 break;
1118 if (i == total)
1119 goto exportall;
1120 for(j=2; j<total/i; j++)
1121 if (level[i*j]->os_index != step*j)
1122 break;
1123
1124 nr_loops++;
1125 tmploops = realloc(loops, nr_loops*sizeof(*loops));
1126 if (!tmploops)
1127 goto exportall;
1128 loops = tmploops;
1129 loops[nr_loops-1].step = i;
1130 loops[nr_loops-1].nb = j;
1131 step *= j;
1132 }
1133
1134
1135 for(i=0; i<total; i++) {
1136 unsigned ind = 0;
1137 unsigned mul = 1;
1138 for(j=0; j<nr_loops; j++) {
1139 ind += (i / loops[j].step) % loops[j].nb * mul;
1140 mul *= loops[j].nb;
1141 }
1142 if (level[i]->os_index != ind)
1143 goto exportall;
1144 }
1145
1146
1147 for(j=0; j<nr_loops; j++) {
1148 res = hwloc_snprintf(tmp, tmplen, "%u*%u%s", loops[j].step, loops[j].nb,
1149 j == nr_loops-1 ? ")" : ":");
1150 if (hwloc__export_synthetic_update_status(&ret, &tmp, &tmplen, res) < 0) {
1151 free(loops);
1152 return -1;
1153 }
1154 }
1155
1156 free(loops);
1157 return ret;
1158
1159 exportall:
1160 free(loops);
1161
1162
1163 cur = level[0];
1164 while (cur) {
1165 res = snprintf(tmp, tmplen, "%u%s", cur->os_index,
1166 cur->next_cousin ? "," : ")");
1167 if (hwloc__export_synthetic_update_status(&ret, &tmp, &tmplen, res) < 0)
1168 return -1;
1169 cur = cur->next_cousin;
1170 }
1171 return ret;
1172 }
1173
1174 static int
1175 hwloc__export_synthetic_obj_attr(struct hwloc_topology * topology,
1176 hwloc_obj_t obj,
1177 char *buffer, size_t buflen)
1178 {
1179 const char * separator = " ";
1180 const char * prefix = "(";
1181 char cachesize[64] = "";
1182 char memsize[64] = "";
1183 int needindexes = 0;
1184
1185 if (hwloc__obj_type_is_cache(obj->type) && obj->attr->cache.size) {
1186 snprintf(cachesize, sizeof(cachesize), "%ssize=%llu",
1187 prefix, (unsigned long long) obj->attr->cache.size);
1188 prefix = separator;
1189 }
1190 if (obj->type == HWLOC_OBJ_NUMANODE && obj->attr->numanode.local_memory) {
1191 snprintf(memsize, sizeof(memsize), "%smemory=%llu",
1192 prefix, (unsigned long long) obj->attr->numanode.local_memory);
1193 prefix = separator;
1194 }
1195 if (!obj->logical_index
1196 && (obj->type == HWLOC_OBJ_PU || obj->type == HWLOC_OBJ_NUMANODE)) {
1197 hwloc_obj_t cur = obj;
1198 while (cur) {
1199 if (cur->os_index != cur->logical_index) {
1200 needindexes = 1;
1201 break;
1202 }
1203 cur = cur->next_cousin;
1204 }
1205 }
1206 if (*cachesize || *memsize || needindexes) {
1207 ssize_t tmplen = buflen;
1208 char *tmp = buffer;
1209 int res, ret = 0;
1210
1211 res = hwloc_snprintf(tmp, tmplen, "%s%s%s", cachesize, memsize, needindexes ? "" : ")");
1212 if (hwloc__export_synthetic_update_status(&ret, &tmp, &tmplen, res) < 0)
1213 return -1;
1214
1215 if (needindexes) {
1216 unsigned total;
1217 hwloc_obj_t *level;
1218
1219 if (obj->depth < 0) {
1220 assert(obj->depth == HWLOC_TYPE_DEPTH_NUMANODE);
1221 total = topology->slevels[HWLOC_SLEVEL_NUMANODE].nbobjs;
1222 level = topology->slevels[HWLOC_SLEVEL_NUMANODE].objs;
1223 } else {
1224 total = topology->level_nbobjects[obj->depth];
1225 level = topology->levels[obj->depth];
1226 }
1227
1228 res = snprintf(tmp, tmplen, "%sindexes=", prefix);
1229 if (hwloc__export_synthetic_update_status(&ret, &tmp, &tmplen, res) < 0)
1230 return -1;
1231
1232 res = hwloc__export_synthetic_indexes(level, total, tmp, tmplen);
1233 if (hwloc__export_synthetic_update_status(&ret, &tmp, &tmplen, res) < 0)
1234 return -1;
1235 }
1236 return ret;
1237 } else {
1238 return 0;
1239 }
1240 }
1241
1242 static int
1243 hwloc__export_synthetic_obj(struct hwloc_topology * topology, unsigned long flags,
1244 hwloc_obj_t obj, unsigned arity,
1245 char *buffer, size_t buflen)
1246 {
1247 char aritys[12] = "";
1248 ssize_t tmplen = buflen;
1249 char *tmp = buffer;
1250 int res, ret = 0;
1251
1252
1253 if (arity != (unsigned)-1)
1254 snprintf(aritys, sizeof(aritys), ":%u", arity);
1255 if (hwloc__obj_type_is_cache(obj->type)
1256 && (flags & HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_EXTENDED_TYPES)) {
1257
1258 res = hwloc_snprintf(tmp, tmplen, "Cache%s", aritys);
1259
1260 } else if (obj->type == HWLOC_OBJ_PACKAGE
1261 && (flags & (HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_EXTENDED_TYPES
1262 |HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_V1))) {
1263
1264 res = hwloc_snprintf(tmp, tmplen, "Socket%s", aritys);
1265
1266 } else if (obj->type == HWLOC_OBJ_GROUP
1267 || flags & HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_EXTENDED_TYPES) {
1268 res = hwloc_snprintf(tmp, tmplen, "%s%s", hwloc_obj_type_string(obj->type), aritys);
1269 } else {
1270 char types[64];
1271 hwloc_obj_type_snprintf(types, sizeof(types), obj, 1);
1272 res = hwloc_snprintf(tmp, tmplen, "%s%s", types, aritys);
1273 }
1274 if (hwloc__export_synthetic_update_status(&ret, &tmp, &tmplen, res) < 0)
1275 return -1;
1276
1277 if (!(flags & HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_ATTRS)) {
1278
1279 res = hwloc__export_synthetic_obj_attr(topology, obj, tmp, tmplen);
1280 if (hwloc__export_synthetic_update_status(&ret, &tmp, &tmplen, res) < 0)
1281 return -1;
1282 }
1283
1284 return ret;
1285 }
1286
1287 static int
1288 hwloc__export_synthetic_memory_children(struct hwloc_topology * topology, unsigned long flags,
1289 hwloc_obj_t parent,
1290 char *buffer, size_t buflen,
1291 int needprefix, int verbose)
1292 {
1293 hwloc_obj_t mchild;
1294 ssize_t tmplen = buflen;
1295 char *tmp = buffer;
1296 int res, ret = 0;
1297
1298 mchild = parent->memory_first_child;
1299 if (!mchild)
1300 return 0;
1301
1302 if (flags & HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_V1) {
1303
1304 if (parent->memory_arity > 1 || mchild->type != HWLOC_OBJ_NUMANODE) {
1305
1306 if (verbose)
1307 fprintf(stderr, "Cannot export to synthetic v1 if multiple memory children are attached to the same location.\n");
1308 errno = EINVAL;
1309 return -1;
1310 }
1311
1312 if (needprefix)
1313 hwloc__export_synthetic_add_char(&ret, &tmp, &tmplen, ' ');
1314
1315 res = hwloc__export_synthetic_obj(topology, flags, mchild, 1, tmp, tmplen);
1316 if (hwloc__export_synthetic_update_status(&ret, &tmp, &tmplen, res) < 0)
1317 return -1;
1318 return ret;
1319 }
1320
1321 while (mchild) {
1322
1323
1324 assert(mchild->type == HWLOC_OBJ_NUMANODE);
1325
1326 if (needprefix)
1327 hwloc__export_synthetic_add_char(&ret, &tmp, &tmplen, ' ');
1328
1329 hwloc__export_synthetic_add_char(&ret, &tmp, &tmplen, '[');
1330
1331 res = hwloc__export_synthetic_obj(topology, flags, mchild, (unsigned)-1, tmp, tmplen);
1332 if (hwloc__export_synthetic_update_status(&ret, &tmp, &tmplen, res) < 0)
1333 return -1;
1334
1335 hwloc__export_synthetic_add_char(&ret, &tmp, &tmplen, ']');
1336
1337 needprefix = 1;
1338 mchild = mchild->next_sibling;
1339 }
1340
1341 return ret;
1342 }
1343
1344 static int
1345 hwloc_check_memory_symmetric(struct hwloc_topology * topology)
1346 {
1347 hwloc_bitmap_t remaining_nodes;
1348
1349 remaining_nodes = hwloc_bitmap_dup(hwloc_get_root_obj(topology)->nodeset);
1350 if (!remaining_nodes)
1351
1352 return -1;
1353
1354 while (!hwloc_bitmap_iszero(remaining_nodes)) {
1355 unsigned idx;
1356 hwloc_obj_t node;
1357 hwloc_obj_t first_parent;
1358 unsigned i;
1359
1360 idx = hwloc_bitmap_first(remaining_nodes);
1361 node = hwloc_get_numanode_obj_by_os_index(topology, idx);
1362 assert(node);
1363
1364 first_parent = node->parent;
1365 assert(hwloc__obj_type_is_normal(first_parent->type));
1366
1367
1368 for(i=0; i<hwloc_get_nbobjs_by_depth(topology, first_parent->depth); i++) {
1369 hwloc_obj_t parent, mchild;
1370
1371 parent = hwloc_get_obj_by_depth(topology, first_parent->depth, i);
1372 assert(parent);
1373
1374
1375 if (parent->memory_arity != first_parent->memory_arity)
1376 goto out_with_bitmap;
1377
1378
1379 mchild = parent->memory_first_child;
1380 while (mchild) {
1381 assert(mchild->type == HWLOC_OBJ_NUMANODE);
1382 hwloc_bitmap_clr(remaining_nodes, mchild->os_index);
1383 mchild = mchild->next_sibling;
1384 }
1385 }
1386 }
1387
1388 hwloc_bitmap_free(remaining_nodes);
1389 return 0;
1390
1391 out_with_bitmap:
1392 hwloc_bitmap_free(remaining_nodes);
1393 return -1;
1394 }
1395
1396 int
1397 hwloc_topology_export_synthetic(struct hwloc_topology * topology,
1398 char *buffer, size_t buflen,
1399 unsigned long flags)
1400 {
1401 hwloc_obj_t obj = hwloc_get_root_obj(topology);
1402 ssize_t tmplen = buflen;
1403 char *tmp = buffer;
1404 int res, ret = 0;
1405 unsigned arity;
1406 int needprefix = 0;
1407 int verbose = 0;
1408 const char *env = getenv("HWLOC_SYNTHETIC_VERBOSE");
1409
1410 if (env)
1411 verbose = atoi(env);
1412
1413 if (!topology->is_loaded) {
1414 errno = EINVAL;
1415 return -1;
1416 }
1417
1418 if (flags & ~(HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_EXTENDED_TYPES
1419 |HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_ATTRS
1420 |HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_V1
1421 |HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_IGNORE_MEMORY)) {
1422 errno = EINVAL;
1423 return -1;
1424 }
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439 if (!obj->symmetric_subtree) {
1440 if (verbose)
1441 fprintf(stderr, "Cannot export to synthetic unless topology is symmetric (root->symmetric_subtree must be set).\n");
1442 errno = EINVAL;
1443 return -1;
1444 }
1445
1446 if (!(flags & HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_IGNORE_MEMORY)
1447 && hwloc_check_memory_symmetric(topology) < 0) {
1448 if (verbose)
1449 fprintf(stderr, "Cannot export to synthetic unless memory is attached symmetrically.\n");
1450 errno = EINVAL;
1451 return -1;
1452 }
1453
1454 if (flags & HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_V1) {
1455
1456 hwloc_obj_t node;
1457 signed pdepth;
1458
1459 node = hwloc_get_obj_by_type(topology, HWLOC_OBJ_NUMANODE, 0);
1460 assert(hwloc__obj_type_is_normal(node->parent->type));
1461 pdepth = node->parent->depth;
1462
1463 while ((node = node->next_cousin) != NULL) {
1464 assert(hwloc__obj_type_is_normal(node->parent->type));
1465 if (node->parent->depth != pdepth) {
1466 if (verbose)
1467 fprintf(stderr, "Cannot export to synthetic v1 if memory is attached to parents at different depths.\n");
1468 errno = EINVAL;
1469 return -1;
1470 }
1471 }
1472 }
1473
1474
1475
1476 if (!(flags & HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_NO_ATTRS)) {
1477
1478 res = hwloc__export_synthetic_obj_attr(topology, obj, tmp, tmplen);
1479 if (res > 0)
1480 needprefix = 1;
1481 if (hwloc__export_synthetic_update_status(&ret, &tmp, &tmplen, res) < 0)
1482 return -1;
1483 }
1484
1485 if (!(flags & HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_IGNORE_MEMORY)) {
1486 res = hwloc__export_synthetic_memory_children(topology, flags, obj, tmp, tmplen, needprefix, verbose);
1487 if (res > 0)
1488 needprefix = 1;
1489 if (hwloc__export_synthetic_update_status(&ret, &tmp, &tmplen, res) < 0)
1490 return -1;
1491 }
1492
1493 arity = obj->arity;
1494 while (arity) {
1495
1496 obj = obj->first_child;
1497
1498 if (needprefix)
1499 hwloc__export_synthetic_add_char(&ret, &tmp, &tmplen, ' ');
1500
1501 res = hwloc__export_synthetic_obj(topology, flags, obj, arity, tmp, tmplen);
1502 if (hwloc__export_synthetic_update_status(&ret, &tmp, &tmplen, res) < 0)
1503 return -1;
1504
1505 if (!(flags & HWLOC_TOPOLOGY_EXPORT_SYNTHETIC_FLAG_IGNORE_MEMORY)) {
1506 res = hwloc__export_synthetic_memory_children(topology, flags, obj, tmp, tmplen, 1, verbose);
1507 if (hwloc__export_synthetic_update_status(&ret, &tmp, &tmplen, res) < 0)
1508 return -1;
1509 }
1510
1511
1512 needprefix = 1;
1513 arity = obj->arity;
1514 }
1515
1516 return ret;
1517 }