This source file includes following definitions.
- hwloc__xml_verbose
- hwloc_nolibxml_import
- hwloc_nolibxml_export
- hwloc_xml_callbacks_register
- hwloc_xml_callbacks_reset
- hwloc__xml_import_object_attr
- hwloc__xml_import_info
- hwloc__xml_import_pagetype
- hwloc__xml_v1import_distances
- hwloc__xml_import_userdata
- hwloc__xml_import_report_outoforder
- hwloc__xml_import_object
- hwloc__xml_v2import_distances
- hwloc__xml_import_diff_one
- hwloc__xml_import_diff
- hwloc_convert_from_v1dist_floats
- hwloc_look_xml
- hwloc_topology_diff_load_xml
- hwloc_topology_diff_load_xmlbuffer
- hwloc__xml_export_check_buffer
- hwloc__xml_export_safestrdup
- hwloc__xml_export_object_contents
- hwloc__xml_v2export_object
- hwloc__xml_v1export_object_with_memory
- hwloc__xml_v1export_object
- hwloc__xml_v2export_distances
- hwloc__xml_export_topology
- hwloc__xml_export_diff
- hwloc_topology_export_xml
- hwloc_topology_export_xmlbuffer
- hwloc_topology_diff_export_xml
- hwloc_topology_diff_export_xmlbuffer
- hwloc_free_xmlbuffer
- hwloc_topology_set_userdata_export_callback
- hwloc__export_obj_userdata
- hwloc_export_obj_userdata
- hwloc_export_obj_userdata_base64
- hwloc_topology_set_userdata_import_callback
- hwloc_xml_backend_disable
- hwloc_xml_component_instantiate
1
2
3
4
5
6
7
8
9 #include <private/autogen/config.h>
10 #include <hwloc.h>
11 #include <private/xml.h>
12 #include <private/private.h>
13 #include <private/misc.h>
14 #include <private/debug.h>
15
16 #include <math.h>
17
18 int
19 hwloc__xml_verbose(void)
20 {
21 static int checked = 0;
22 static int verbose = 0;
23 if (!checked) {
24 const char *env = getenv("HWLOC_XML_VERBOSE");
25 if (env)
26 verbose = atoi(env);
27 checked = 1;
28 }
29 return verbose;
30 }
31
32 static int
33 hwloc_nolibxml_import(void)
34 {
35 static int checked = 0;
36 static int nolibxml = 0;
37 if (!checked) {
38 const char *env = getenv("HWLOC_LIBXML");
39 if (env) {
40 nolibxml = !atoi(env);
41 } else {
42 env = getenv("HWLOC_LIBXML_IMPORT");
43 if (env)
44 nolibxml = !atoi(env);
45 }
46 checked = 1;
47 }
48 return nolibxml;
49 }
50
51 static int
52 hwloc_nolibxml_export(void)
53 {
54 static int checked = 0;
55 static int nolibxml = 0;
56 if (!checked) {
57 const char *env = getenv("HWLOC_LIBXML");
58 if (env) {
59 nolibxml = !atoi(env);
60 } else {
61 env = getenv("HWLOC_LIBXML_EXPORT");
62 if (env)
63 nolibxml = !atoi(env);
64 }
65 checked = 1;
66 }
67 return nolibxml;
68 }
69
70 #define BASE64_ENCODED_LENGTH(length) (4*(((length)+2)/3))
71
72
73
74
75
76
77
78
79
80 static struct hwloc_xml_callbacks *hwloc_nolibxml_callbacks = NULL, *hwloc_libxml_callbacks = NULL;
81
82 void
83 hwloc_xml_callbacks_register(struct hwloc_xml_component *comp)
84 {
85 if (!hwloc_nolibxml_callbacks)
86 hwloc_nolibxml_callbacks = comp->nolibxml_callbacks;
87 if (!hwloc_libxml_callbacks)
88 hwloc_libxml_callbacks = comp->libxml_callbacks;
89 }
90
91 void
92 hwloc_xml_callbacks_reset(void)
93 {
94 hwloc_nolibxml_callbacks = NULL;
95 hwloc_libxml_callbacks = NULL;
96 }
97
98
99
100
101
102 #define _HWLOC_OBJ_CACHE_OLD (HWLOC_OBJ_TYPE_MAX+1)
103 #define _HWLOC_OBJ_FUTURE (HWLOC_OBJ_TYPE_MAX+2)
104
105 static void
106 hwloc__xml_import_object_attr(struct hwloc_topology *topology,
107 struct hwloc_xml_backend_data_s *data,
108 struct hwloc_obj *obj,
109 const char *name, const char *value,
110 hwloc__xml_import_state_t state)
111 {
112 if (!strcmp(name, "type")) {
113
114 return;
115 }
116
117 else if (!strcmp(name, "os_index"))
118 obj->os_index = strtoul(value, NULL, 10);
119 else if (!strcmp(name, "gp_index")) {
120 obj->gp_index = strtoull(value, NULL, 10);
121 if (!obj->gp_index && hwloc__xml_verbose())
122 fprintf(stderr, "%s: unexpected zero gp_index, topology may be invalid\n", state->global->msgprefix);
123 if (obj->gp_index >= topology->next_gp_index)
124 topology->next_gp_index = obj->gp_index + 1;
125 } else if (!strcmp(name, "cpuset")) {
126 if (!obj->cpuset)
127 obj->cpuset = hwloc_bitmap_alloc();
128 hwloc_bitmap_sscanf(obj->cpuset, value);
129 } else if (!strcmp(name, "complete_cpuset")) {
130 if (!obj->complete_cpuset)
131 obj->complete_cpuset = hwloc_bitmap_alloc();
132 hwloc_bitmap_sscanf(obj->complete_cpuset, value);
133 } else if (!strcmp(name, "allowed_cpuset")) {
134
135 if (!obj->parent)
136 hwloc_bitmap_sscanf(topology->allowed_cpuset, value);
137 } else if (!strcmp(name, "nodeset")) {
138 if (!obj->nodeset)
139 obj->nodeset = hwloc_bitmap_alloc();
140 hwloc_bitmap_sscanf(obj->nodeset, value);
141 } else if (!strcmp(name, "complete_nodeset")) {
142 if (!obj->complete_nodeset)
143 obj->complete_nodeset = hwloc_bitmap_alloc();
144 hwloc_bitmap_sscanf(obj->complete_nodeset, value);
145 } else if (!strcmp(name, "allowed_nodeset")) {
146
147 if (!obj->parent)
148 hwloc_bitmap_sscanf(topology->allowed_nodeset, value);
149 } else if (!strcmp(name, "name")) {
150 if (obj->name)
151 free(obj->name);
152 obj->name = strdup(value);
153 } else if (!strcmp(name, "subtype")) {
154 if (obj->subtype)
155 free(obj->subtype);
156 obj->subtype = strdup(value);
157 }
158
159 else if (!strcmp(name, "cache_size")) {
160 unsigned long long lvalue = strtoull(value, NULL, 10);
161 if (hwloc__obj_type_is_cache(obj->type) || obj->type == _HWLOC_OBJ_CACHE_OLD)
162 obj->attr->cache.size = lvalue;
163 else if (hwloc__xml_verbose())
164 fprintf(stderr, "%s: ignoring cache_size attribute for non-cache object type\n",
165 state->global->msgprefix);
166 }
167
168 else if (!strcmp(name, "cache_linesize")) {
169 unsigned long lvalue = strtoul(value, NULL, 10);
170 if (hwloc__obj_type_is_cache(obj->type) || obj->type == _HWLOC_OBJ_CACHE_OLD)
171 obj->attr->cache.linesize = lvalue;
172 else if (hwloc__xml_verbose())
173 fprintf(stderr, "%s: ignoring cache_linesize attribute for non-cache object type\n",
174 state->global->msgprefix);
175 }
176
177 else if (!strcmp(name, "cache_associativity")) {
178 int lvalue = atoi(value);
179 if (hwloc__obj_type_is_cache(obj->type) || obj->type == _HWLOC_OBJ_CACHE_OLD)
180 obj->attr->cache.associativity = lvalue;
181 else if (hwloc__xml_verbose())
182 fprintf(stderr, "%s: ignoring cache_associativity attribute for non-cache object type\n",
183 state->global->msgprefix);
184 }
185
186 else if (!strcmp(name, "cache_type")) {
187 unsigned long lvalue = strtoul(value, NULL, 10);
188 if (hwloc__obj_type_is_cache(obj->type) || obj->type == _HWLOC_OBJ_CACHE_OLD) {
189 if (lvalue == HWLOC_OBJ_CACHE_UNIFIED
190 || lvalue == HWLOC_OBJ_CACHE_DATA
191 || lvalue == HWLOC_OBJ_CACHE_INSTRUCTION)
192 obj->attr->cache.type = (hwloc_obj_cache_type_t) lvalue;
193 else
194 fprintf(stderr, "%s: ignoring invalid cache_type attribute %lu\n",
195 state->global->msgprefix, lvalue);
196 } else if (hwloc__xml_verbose())
197 fprintf(stderr, "%s: ignoring cache_type attribute for non-cache object type\n",
198 state->global->msgprefix);
199 }
200
201 else if (!strcmp(name, "local_memory")) {
202 unsigned long long lvalue = strtoull(value, NULL, 10);
203 if (obj->type == HWLOC_OBJ_NUMANODE)
204 obj->attr->numanode.local_memory = lvalue;
205 else if (!obj->parent)
206 topology->machine_memory.local_memory = lvalue;
207 else if (hwloc__xml_verbose())
208 fprintf(stderr, "%s: ignoring local_memory attribute for non-NUMAnode non-root object\n",
209 state->global->msgprefix);
210 }
211
212 else if (!strcmp(name, "depth")) {
213 unsigned long lvalue = strtoul(value, NULL, 10);
214 if (hwloc__obj_type_is_cache(obj->type) || obj->type == _HWLOC_OBJ_CACHE_OLD) {
215 obj->attr->cache.depth = lvalue;
216 } else if (obj->type == HWLOC_OBJ_GROUP || obj->type == HWLOC_OBJ_BRIDGE) {
217
218 } else if (hwloc__xml_verbose())
219 fprintf(stderr, "%s: ignoring depth attribute for object type without depth\n",
220 state->global->msgprefix);
221 }
222
223 else if (!strcmp(name, "kind")) {
224 unsigned long lvalue = strtoul(value, NULL, 10);
225 if (obj->type == HWLOC_OBJ_GROUP)
226 obj->attr->group.kind = lvalue;
227 else if (hwloc__xml_verbose())
228 fprintf(stderr, "%s: ignoring kind attribute for non-group object type\n",
229 state->global->msgprefix);
230 }
231
232 else if (!strcmp(name, "subkind")) {
233 unsigned long lvalue = strtoul(value, NULL, 10);
234 if (obj->type == HWLOC_OBJ_GROUP)
235 obj->attr->group.subkind = lvalue;
236 else if (hwloc__xml_verbose())
237 fprintf(stderr, "%s: ignoring subkind attribute for non-group object type\n",
238 state->global->msgprefix);
239 }
240
241 else if (!strcmp(name, "pci_busid")) {
242 switch (obj->type) {
243 case HWLOC_OBJ_PCI_DEVICE:
244 case HWLOC_OBJ_BRIDGE: {
245 unsigned domain, bus, dev, func;
246 if (sscanf(value, "%04x:%02x:%02x.%01x",
247 &domain, &bus, &dev, &func) != 4) {
248 if (hwloc__xml_verbose())
249 fprintf(stderr, "%s: ignoring invalid pci_busid format string %s\n",
250 state->global->msgprefix, value);
251 } else {
252 obj->attr->pcidev.domain = domain;
253 obj->attr->pcidev.bus = bus;
254 obj->attr->pcidev.dev = dev;
255 obj->attr->pcidev.func = func;
256 }
257 break;
258 }
259 default:
260 if (hwloc__xml_verbose())
261 fprintf(stderr, "%s: ignoring pci_busid attribute for non-PCI object\n",
262 state->global->msgprefix);
263 break;
264 }
265 }
266
267 else if (!strcmp(name, "pci_type")) {
268 switch (obj->type) {
269 case HWLOC_OBJ_PCI_DEVICE:
270 case HWLOC_OBJ_BRIDGE: {
271 unsigned classid, vendor, device, subvendor, subdevice, revision;
272 if (sscanf(value, "%04x [%04x:%04x] [%04x:%04x] %02x",
273 &classid, &vendor, &device, &subvendor, &subdevice, &revision) != 6) {
274 if (hwloc__xml_verbose())
275 fprintf(stderr, "%s: ignoring invalid pci_type format string %s\n",
276 state->global->msgprefix, value);
277 } else {
278 obj->attr->pcidev.class_id = classid;
279 obj->attr->pcidev.vendor_id = vendor;
280 obj->attr->pcidev.device_id = device;
281 obj->attr->pcidev.subvendor_id = subvendor;
282 obj->attr->pcidev.subdevice_id = subdevice;
283 obj->attr->pcidev.revision = revision;
284 }
285 break;
286 }
287 default:
288 if (hwloc__xml_verbose())
289 fprintf(stderr, "%s: ignoring pci_type attribute for non-PCI object\n",
290 state->global->msgprefix);
291 break;
292 }
293 }
294
295 else if (!strcmp(name, "pci_link_speed")) {
296 switch (obj->type) {
297 case HWLOC_OBJ_PCI_DEVICE:
298 case HWLOC_OBJ_BRIDGE: {
299 obj->attr->pcidev.linkspeed = (float) atof(value);
300 break;
301 }
302 default:
303 if (hwloc__xml_verbose())
304 fprintf(stderr, "%s: ignoring pci_link_speed attribute for non-PCI object\n",
305 state->global->msgprefix);
306 break;
307 }
308 }
309
310 else if (!strcmp(name, "bridge_type")) {
311 switch (obj->type) {
312 case HWLOC_OBJ_BRIDGE: {
313 unsigned upstream_type, downstream_type;
314 if (sscanf(value, "%u-%u", &upstream_type, &downstream_type) != 2) {
315 if (hwloc__xml_verbose())
316 fprintf(stderr, "%s: ignoring invalid bridge_type format string %s\n",
317 state->global->msgprefix, value);
318 } else {
319 obj->attr->bridge.upstream_type = (hwloc_obj_bridge_type_t) upstream_type;
320 obj->attr->bridge.downstream_type = (hwloc_obj_bridge_type_t) downstream_type;
321 };
322 break;
323 }
324 default:
325 if (hwloc__xml_verbose())
326 fprintf(stderr, "%s: ignoring bridge_type attribute for non-bridge object\n",
327 state->global->msgprefix);
328 break;
329 }
330 }
331
332 else if (!strcmp(name, "bridge_pci")) {
333 switch (obj->type) {
334 case HWLOC_OBJ_BRIDGE: {
335 unsigned domain, secbus, subbus;
336 if (sscanf(value, "%04x:[%02x-%02x]",
337 &domain, &secbus, &subbus) != 3) {
338 if (hwloc__xml_verbose())
339 fprintf(stderr, "%s: ignoring invalid bridge_pci format string %s\n",
340 state->global->msgprefix, value);
341 } else {
342 obj->attr->bridge.downstream.pci.domain = domain;
343 obj->attr->bridge.downstream.pci.secondary_bus = secbus;
344 obj->attr->bridge.downstream.pci.subordinate_bus = subbus;
345 }
346 break;
347 }
348 default:
349 if (hwloc__xml_verbose())
350 fprintf(stderr, "%s: ignoring bridge_pci attribute for non-bridge object\n",
351 state->global->msgprefix);
352 break;
353 }
354 }
355
356 else if (!strcmp(name, "osdev_type")) {
357 switch (obj->type) {
358 case HWLOC_OBJ_OS_DEVICE: {
359 unsigned osdev_type;
360 if (sscanf(value, "%u", &osdev_type) != 1) {
361 if (hwloc__xml_verbose())
362 fprintf(stderr, "%s: ignoring invalid osdev_type format string %s\n",
363 state->global->msgprefix, value);
364 } else
365 obj->attr->osdev.type = (hwloc_obj_osdev_type_t) osdev_type;
366 break;
367 }
368 default:
369 if (hwloc__xml_verbose())
370 fprintf(stderr, "%s: ignoring osdev_type attribute for non-osdev object\n",
371 state->global->msgprefix);
372 break;
373 }
374 }
375
376 else if (data->version_major < 2) {
377
378
379
380 if (!strcmp(name, "os_level")
381 || !strcmp(name, "online_cpuset"))
382 { }
383
384
385
386
387 else if (!strcmp(name, "dmi_board_vendor")) {
388 if (value[0])
389 hwloc_obj_add_info(obj, "DMIBoardVendor", value);
390 }
391 else if (!strcmp(name, "dmi_board_name")) {
392 if (value[0])
393 hwloc_obj_add_info(obj, "DMIBoardName", value);
394 }
395
396 else if (data->version_major < 1) {
397
398
399
400 if (!strcmp(name, "memory_kB")) {
401 unsigned long long lvalue = strtoull(value, NULL, 10);
402 if (obj->type == _HWLOC_OBJ_CACHE_OLD)
403 obj->attr->cache.size = lvalue << 10;
404 else if (obj->type == HWLOC_OBJ_NUMANODE)
405 obj->attr->numanode.local_memory = lvalue << 10;
406 else if (!obj->parent)
407 topology->machine_memory.local_memory = lvalue << 10;
408 else if (hwloc__xml_verbose())
409 fprintf(stderr, "%s: ignoring memory_kB attribute for non-NUMAnode non-root object\n",
410 state->global->msgprefix);
411 }
412 else if (!strcmp(name, "huge_page_size_kB")) {
413 unsigned long lvalue = strtoul(value, NULL, 10);
414 if (obj->type == HWLOC_OBJ_NUMANODE || !obj->parent) {
415 struct hwloc_numanode_attr_s *memory = obj->type == HWLOC_OBJ_NUMANODE ? &obj->attr->numanode : &topology->machine_memory;
416 if (!memory->page_types) {
417 memory->page_types = malloc(sizeof(*memory->page_types));
418 memory->page_types_len = 1;
419 }
420 memory->page_types[0].size = lvalue << 10;
421 } else if (hwloc__xml_verbose()) {
422 fprintf(stderr, "%s: ignoring huge_page_size_kB attribute for non-NUMAnode non-root object\n",
423 state->global->msgprefix);
424 }
425 }
426 else if (!strcmp(name, "huge_page_free")) {
427 unsigned long lvalue = strtoul(value, NULL, 10);
428 if (obj->type == HWLOC_OBJ_NUMANODE || !obj->parent) {
429 struct hwloc_numanode_attr_s *memory = obj->type == HWLOC_OBJ_NUMANODE ? &obj->attr->numanode : &topology->machine_memory;
430 if (!memory->page_types) {
431 memory->page_types = malloc(sizeof(*memory->page_types));
432 memory->page_types_len = 1;
433 }
434 memory->page_types[0].count = lvalue;
435 } else if (hwloc__xml_verbose()) {
436 fprintf(stderr, "%s: ignoring huge_page_free attribute for non-NUMAnode non-root object\n",
437 state->global->msgprefix);
438 }
439 }
440
441 else goto unknown;
442 }
443
444 else goto unknown;
445 }
446 else {
447 unknown:
448 if (hwloc__xml_verbose())
449 fprintf(stderr, "%s: ignoring unknown object attribute %s\n",
450 state->global->msgprefix, name);
451 }
452 }
453
454
455 static int
456 hwloc__xml_import_info(struct hwloc_xml_backend_data_s *data,
457 hwloc_obj_t obj,
458 hwloc__xml_import_state_t state)
459 {
460 char *infoname = NULL;
461 char *infovalue = NULL;
462
463 while (1) {
464 char *attrname, *attrvalue;
465 if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
466 break;
467 if (!strcmp(attrname, "name"))
468 infoname = attrvalue;
469 else if (!strcmp(attrname, "value"))
470 infovalue = attrvalue;
471 else
472 return -1;
473 }
474
475 if (infoname) {
476
477 if (data->version_major < 2 &&
478 (!strcmp(infoname, "Type") || !strcmp(infoname, "CoProcType"))) {
479
480 if (infovalue) {
481 if (obj->subtype)
482 free(obj->subtype);
483 obj->subtype = strdup(infovalue);
484 }
485 } else {
486 if (infovalue)
487 hwloc_obj_add_info(obj, infoname, infovalue);
488 }
489 }
490
491 return state->global->close_tag(state);
492 }
493
494 static int
495 hwloc__xml_import_pagetype(hwloc_topology_t topology __hwloc_attribute_unused, struct hwloc_numanode_attr_s *memory,
496 hwloc__xml_import_state_t state)
497 {
498 uint64_t size = 0, count = 0;
499
500 while (1) {
501 char *attrname, *attrvalue;
502 if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
503 break;
504 if (!strcmp(attrname, "size"))
505 size = strtoull(attrvalue, NULL, 10);
506 else if (!strcmp(attrname, "count"))
507 count = strtoull(attrvalue, NULL, 10);
508 else
509 return -1;
510 }
511
512 if (size) {
513 unsigned idx = memory->page_types_len;
514 struct hwloc_memory_page_type_s *tmp;
515 tmp = realloc(memory->page_types, (idx+1)*sizeof(*memory->page_types));
516 if (tmp) {
517 memory->page_types = tmp;
518 memory->page_types_len = idx+1;
519 memory->page_types[idx].size = size;
520 memory->page_types[idx].count = count;
521 }
522 }
523
524 return state->global->close_tag(state);
525 }
526
527 static int
528 hwloc__xml_v1import_distances(struct hwloc_xml_backend_data_s *data,
529 hwloc_obj_t obj,
530 hwloc__xml_import_state_t state)
531 {
532 unsigned long reldepth = 0, nbobjs = 0;
533 float latbase = 0;
534 char *tag;
535 int ret;
536
537 while (1) {
538 char *attrname, *attrvalue;
539 if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
540 break;
541 if (!strcmp(attrname, "nbobjs"))
542 nbobjs = strtoul(attrvalue, NULL, 10);
543 else if (!strcmp(attrname, "relative_depth"))
544 reldepth = strtoul(attrvalue, NULL, 10);
545 else if (!strcmp(attrname, "latency_base"))
546 latbase = (float) atof(attrvalue);
547 else
548 return -1;
549 }
550
551 if (nbobjs && reldepth && latbase) {
552 unsigned i;
553 float *matrix;
554 struct hwloc__xml_imported_v1distances_s *v1dist;
555
556 matrix = malloc(nbobjs*nbobjs*sizeof(float));
557 v1dist = malloc(sizeof(*v1dist));
558 if (!matrix || !v1dist) {
559 if (hwloc__xml_verbose())
560 fprintf(stderr, "%s: failed to allocate v1distance matrix for %lu objects\n",
561 state->global->msgprefix, nbobjs);
562 free(v1dist);
563 free(matrix);
564 return -1;
565 }
566
567 v1dist->kind = HWLOC_DISTANCES_KIND_FROM_OS|HWLOC_DISTANCES_KIND_MEANS_LATENCY;
568
569
570
571
572
573
574 v1dist->nbobjs = nbobjs;
575 v1dist->floats = matrix;
576
577 for(i=0; i<nbobjs*nbobjs; i++) {
578 struct hwloc__xml_import_state_s childstate;
579 char *attrname, *attrvalue;
580 float val;
581
582 ret = state->global->find_child(state, &childstate, &tag);
583 if (ret <= 0 || strcmp(tag, "latency")) {
584
585 free(matrix);
586 free(v1dist);
587 return -1;
588 }
589
590 ret = state->global->next_attr(&childstate, &attrname, &attrvalue);
591 if (ret < 0 || strcmp(attrname, "value")) {
592 free(matrix);
593 free(v1dist);
594 return -1;
595 }
596
597 val = (float) atof((char *) attrvalue);
598 matrix[i] = val * latbase;
599
600 ret = state->global->close_tag(&childstate);
601 if (ret < 0)
602 return -1;
603
604 state->global->close_child(&childstate);
605 }
606
607 if (nbobjs < 2) {
608
609 assert(nbobjs == 1);
610 if (hwloc__xml_verbose())
611 fprintf(stderr, "%s: ignoring invalid distance matrix with only 1 object\n",
612 state->global->msgprefix);
613 free(matrix);
614 free(v1dist);
615
616 } else if (obj->parent) {
617
618
619
620
621
622 free(matrix);
623 free(v1dist);
624
625 } else {
626
627 v1dist->prev = data->last_v1dist;
628 v1dist->next = NULL;
629 if (data->last_v1dist)
630 data->last_v1dist->next = v1dist;
631 else
632 data->first_v1dist = v1dist;
633 data->last_v1dist = v1dist;
634 }
635 }
636
637 return state->global->close_tag(state);
638 }
639
640 static int
641 hwloc__xml_import_userdata(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj,
642 hwloc__xml_import_state_t state)
643 {
644 size_t length = 0;
645 int encoded = 0;
646 char *name = NULL;
647 int ret;
648
649 while (1) {
650 char *attrname, *attrvalue;
651 if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
652 break;
653 if (!strcmp(attrname, "length"))
654 length = strtoul(attrvalue, NULL, 10);
655 else if (!strcmp(attrname, "encoding"))
656 encoded = !strcmp(attrvalue, "base64");
657 else if (!strcmp(attrname, "name"))
658 name = attrvalue;
659 else
660 return -1;
661 }
662
663 if (!topology->userdata_import_cb) {
664 char *buffer;
665 size_t reallength = encoded ? BASE64_ENCODED_LENGTH(length) : length;
666 ret = state->global->get_content(state, &buffer, reallength);
667 if (ret < 0)
668 return -1;
669
670 } else if (topology->userdata_not_decoded) {
671 char *buffer, *fakename;
672 size_t reallength = encoded ? BASE64_ENCODED_LENGTH(length) : length;
673 ret = state->global->get_content(state, &buffer, reallength);
674 if (ret < 0)
675 return -1;
676 fakename = malloc(6 + 1 + (name ? strlen(name) : 4) + 1);
677 if (!fakename)
678 return -1;
679 sprintf(fakename, encoded ? "base64%c%s" : "normal%c%s", name ? ':' : '-', name ? name : "anon");
680 topology->userdata_import_cb(topology, obj, fakename, buffer, length);
681 free(fakename);
682
683 } else if (encoded && length) {
684 char *encoded_buffer;
685 size_t encoded_length = BASE64_ENCODED_LENGTH(length);
686 ret = state->global->get_content(state, &encoded_buffer, encoded_length);
687 if (ret < 0)
688 return -1;
689 if (ret) {
690 char *decoded_buffer = malloc(length+1);
691 if (!decoded_buffer)
692 return -1;
693 assert(encoded_buffer[encoded_length] == 0);
694 ret = hwloc_decode_from_base64(encoded_buffer, decoded_buffer, length+1);
695 if (ret != (int) length) {
696 free(decoded_buffer);
697 return -1;
698 }
699 topology->userdata_import_cb(topology, obj, name, decoded_buffer, length);
700 free(decoded_buffer);
701 }
702
703 } else {
704 char *buffer = (char *) "";
705 if (length) {
706 ret = state->global->get_content(state, &buffer, length);
707 if (ret < 0)
708 return -1;
709 }
710 topology->userdata_import_cb(topology, obj, name, buffer, length);
711 }
712
713 state->global->close_content(state);
714 return state->global->close_tag(state);
715 }
716
717 static void hwloc__xml_import_report_outoforder(hwloc_topology_t topology, hwloc_obj_t new, hwloc_obj_t old)
718 {
719 char *progname = hwloc_progname(topology);
720 const char *origversion = hwloc_obj_get_info_by_name(topology->levels[0][0], "hwlocVersion");
721 const char *origprogname = hwloc_obj_get_info_by_name(topology->levels[0][0], "ProcessName");
722 char *c1, *cc1, t1[64];
723 char *c2 = NULL, *cc2 = NULL, t2[64];
724
725 hwloc_bitmap_asprintf(&c1, new->cpuset);
726 hwloc_bitmap_asprintf(&cc1, new->complete_cpuset);
727 hwloc_obj_type_snprintf(t1, sizeof(t1), new, 0);
728
729 if (old->cpuset)
730 hwloc_bitmap_asprintf(&c2, old->cpuset);
731 if (old->complete_cpuset)
732 hwloc_bitmap_asprintf(&cc2, old->complete_cpuset);
733 hwloc_obj_type_snprintf(t2, sizeof(t2), old, 0);
734
735 fprintf(stderr, "****************************************************************************\n");
736 fprintf(stderr, "* hwloc has encountered an out-of-order XML topology load.\n");
737 fprintf(stderr, "* Object %s cpuset %s complete %s\n",
738 t1, c1, cc1);
739 fprintf(stderr, "* was inserted after object %s with %s and %s.\n",
740 t2, c2 ? c2 : "none", cc2 ? cc2 : "none");
741 fprintf(stderr, "* The error occured in hwloc %s inside process `%s', while\n",
742 HWLOC_VERSION,
743 progname ? progname : "<unknown>");
744 if (origversion || origprogname)
745 fprintf(stderr, "* the input XML was generated by hwloc %s inside process `%s'.\n",
746 origversion ? origversion : "(unknown version)",
747 origprogname ? origprogname : "<unknown>");
748 else
749 fprintf(stderr, "* the input XML was generated by an unspecified ancient hwloc release.\n");
750 fprintf(stderr, "* Please check that your input topology XML file is valid.\n");
751 fprintf(stderr, "* Set HWLOC_DEBUG_CHECK=1 in the environment to detect further issues.\n");
752 fprintf(stderr, "****************************************************************************\n");
753
754 free(c1);
755 free(cc1);
756 free(c2);
757 free(cc2);
758 free(progname);
759 }
760
761 static int
762 hwloc__xml_import_object(hwloc_topology_t topology,
763 struct hwloc_xml_backend_data_s *data,
764 hwloc_obj_t parent, hwloc_obj_t obj, int *gotignored,
765 hwloc__xml_import_state_t state)
766 {
767 int ignored = 0;
768 int childrengotignored = 0;
769 int attribute_less_cache = 0;
770 int numa_was_root = 0;
771 char *tag;
772 struct hwloc__xml_import_state_s childstate;
773
774
775 obj->parent = parent;
776
777
778 while (1) {
779 char *attrname, *attrvalue;
780 if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
781 break;
782 if (!strcmp(attrname, "type")) {
783 if (hwloc_type_sscanf(attrvalue, &obj->type, NULL, 0) < 0) {
784 if (!strcasecmp(attrvalue, "Cache")) {
785 obj->type = _HWLOC_OBJ_CACHE_OLD;
786 attribute_less_cache = 1;
787 } else if (!strcasecmp(attrvalue, "System")) {
788 if (!parent)
789 obj->type = HWLOC_OBJ_MACHINE;
790 else {
791 if (hwloc__xml_verbose())
792 fprintf(stderr, "%s: obsolete System object only allowed at root\n",
793 state->global->msgprefix);
794 goto error_with_object;
795 }
796 } else if (!strcasecmp(attrvalue, "MemCache")) {
797
798 obj->type = _HWLOC_OBJ_FUTURE;
799 ignored = 1;
800 if (hwloc__xml_verbose())
801 fprintf(stderr, "%s: %s object not-supported, will be ignored\n",
802 state->global->msgprefix, attrvalue);
803 } else {
804 if (hwloc__xml_verbose())
805 fprintf(stderr, "%s: unrecognized object type string %s\n",
806 state->global->msgprefix, attrvalue);
807 goto error_with_object;
808 }
809 }
810 } else {
811
812 if (obj->type == HWLOC_OBJ_TYPE_NONE) {
813 if (hwloc__xml_verbose())
814 fprintf(stderr, "%s: object attribute %s found before type\n",
815 state->global->msgprefix, attrname);
816 goto error_with_object;
817 }
818 hwloc__xml_import_object_attr(topology, data, obj, attrname, attrvalue, state);
819 }
820 }
821
822
823 while (1) {
824 int ret;
825
826 tag = NULL;
827 ret = state->global->find_child(state, &childstate, &tag);
828 if (ret < 0)
829 goto error;
830 if (!ret)
831 break;
832
833 if (!strcmp(tag, "object")) {
834
835 break;
836
837 } else if (!strcmp(tag, "page_type")) {
838 if (obj->type == HWLOC_OBJ_NUMANODE) {
839 ret = hwloc__xml_import_pagetype(topology, &obj->attr->numanode, &childstate);
840 } else if (!parent) {
841 ret = hwloc__xml_import_pagetype(topology, &topology->machine_memory, &childstate);
842 } else {
843 if (hwloc__xml_verbose())
844 fprintf(stderr, "%s: invalid non-NUMAnode object child %s\n",
845 state->global->msgprefix, tag);
846 ret = -1;
847 }
848
849 } else if (!strcmp(tag, "info")) {
850 ret = hwloc__xml_import_info(data, obj, &childstate);
851 } else if (data->version_major < 2 && !strcmp(tag, "distances")) {
852 ret = hwloc__xml_v1import_distances(data, obj, &childstate);
853 } else if (!strcmp(tag, "userdata")) {
854 ret = hwloc__xml_import_userdata(topology, obj, &childstate);
855 } else {
856 if (hwloc__xml_verbose())
857 fprintf(stderr, "%s: invalid special object child %s\n",
858 state->global->msgprefix, tag);
859 ret = -1;
860 }
861
862 if (ret < 0)
863 goto error;
864
865 state->global->close_child(&childstate);
866 }
867
868 if (parent && obj->type == HWLOC_OBJ_MACHINE) {
869
870 obj->type = HWLOC_OBJ_GROUP;
871 }
872
873 if (parent && data->version_major >= 2) {
874
875 if (hwloc__obj_type_is_normal(obj->type)) {
876 if (!hwloc__obj_type_is_normal(parent->type)) {
877 if (hwloc__xml_verbose())
878 fprintf(stderr, "normal object %s cannot be child of non-normal parent %s\n",
879 hwloc_obj_type_string(obj->type), hwloc_obj_type_string(parent->type));
880 goto error_with_object;
881 }
882 } else if (hwloc__obj_type_is_memory(obj->type)) {
883 if (hwloc__obj_type_is_io(parent->type) || HWLOC_OBJ_MISC == parent->type) {
884 if (hwloc__xml_verbose())
885 fprintf(stderr, "Memory object %s cannot be child of non-normal-or-memory parent %s\n",
886 hwloc_obj_type_string(obj->type), hwloc_obj_type_string(parent->type));
887 goto error_with_object;
888 }
889 } else if (hwloc__obj_type_is_io(obj->type)) {
890 if (hwloc__obj_type_is_memory(parent->type) || HWLOC_OBJ_MISC == parent->type) {
891 if (hwloc__xml_verbose())
892 fprintf(stderr, "I/O object %s cannot be child of non-normal-or-I/O parent %s\n",
893 hwloc_obj_type_string(obj->type), hwloc_obj_type_string(parent->type));
894 goto error_with_object;
895 }
896 }
897
898 } else if (parent && data->version_major < 2) {
899
900 if (hwloc__obj_type_is_normal(obj->type) || HWLOC_OBJ_NUMANODE == obj->type) {
901 if (hwloc__obj_type_is_special(parent->type)) {
902 if (hwloc__xml_verbose())
903 fprintf(stderr, "v1.x normal v1.x object %s cannot be child of special parent %s\n",
904 hwloc_obj_type_string(obj->type), hwloc_obj_type_string(parent->type));
905 goto error_with_object;
906 }
907 } else if (hwloc__obj_type_is_io(obj->type)) {
908 if (HWLOC_OBJ_MISC == parent->type) {
909 if (hwloc__xml_verbose())
910 fprintf(stderr, "I/O object %s cannot be child of Misc parent\n",
911 hwloc_obj_type_string(obj->type));
912 goto error_with_object;
913 }
914 }
915 }
916
917 if (data->version_major < 2) {
918
919
920
921
922
923 if (parent && parent->type == HWLOC_OBJ_NUMANODE) {
924 parent = parent->parent;
925 assert(parent);
926 }
927
928
929 if (obj->type == HWLOC_OBJ_NUMANODE) {
930 if (!parent) {
931
932
933
934 hwloc_obj_t machine = hwloc_alloc_setup_object(topology, HWLOC_OBJ_MACHINE, HWLOC_UNKNOWN_INDEX);
935 machine->cpuset = hwloc_bitmap_dup(obj->cpuset);
936 machine->complete_cpuset = hwloc_bitmap_dup(obj->cpuset);
937 machine->nodeset = hwloc_bitmap_dup(obj->nodeset);
938 machine->complete_nodeset = hwloc_bitmap_dup(obj->complete_nodeset);
939 topology->levels[0][0] = machine;
940 parent = machine;
941 numa_was_root = 1;
942
943 } else if (!hwloc_bitmap_isequal(obj->complete_cpuset, parent->complete_cpuset)) {
944
945
946
947
948 int needgroup = 1;
949 hwloc_obj_t sibling;
950
951 sibling = parent->memory_first_child;
952 if (sibling && !sibling->subtype
953 && !sibling->next_sibling
954 && obj->subtype && !strcmp(obj->subtype, "MCDRAM")
955 && hwloc_bitmap_iszero(obj->complete_cpuset)) {
956
957 needgroup = 0;
958 }
959
960
961
962
963
964 if (needgroup
965 && hwloc_filter_check_keep_object_type(topology, HWLOC_OBJ_GROUP)) {
966 hwloc_obj_t group = hwloc_alloc_setup_object(topology, HWLOC_OBJ_GROUP, HWLOC_UNKNOWN_INDEX);
967 group->gp_index = 0;
968 group->cpuset = hwloc_bitmap_dup(obj->cpuset);
969 group->complete_cpuset = hwloc_bitmap_dup(obj->cpuset);
970 group->nodeset = hwloc_bitmap_dup(obj->nodeset);
971 group->complete_nodeset = hwloc_bitmap_dup(obj->complete_nodeset);
972 group->attr->group.kind = HWLOC_GROUP_KIND_MEMORY;
973 hwloc_insert_object_by_parent(topology, parent, group);
974 parent = group;
975 }
976 }
977 }
978
979
980 if (attribute_less_cache) {
981 assert(obj->type == _HWLOC_OBJ_CACHE_OLD);
982 obj->type = hwloc_cache_type_by_depth_type(obj->attr->cache.depth, obj->attr->cache.type);
983 }
984
985
986 if (obj->type == HWLOC_OBJ_MISC && obj->cpuset)
987 obj->type = HWLOC_OBJ_GROUP;
988
989
990
991
992
993
994 if (!obj->cpuset != !obj->complete_cpuset) {
995
996 if (obj->type == HWLOC_OBJ_GROUP) {
997 ignored = 1;
998 } else {
999 if (hwloc__xml_verbose())
1000 fprintf(stderr, "%s: invalid object %s P#%u with some missing cpusets\n",
1001 state->global->msgprefix, hwloc_obj_type_string(obj->type), obj->os_index);
1002 goto error_with_object;
1003 }
1004 } else if (!obj->nodeset != !obj->complete_nodeset) {
1005
1006 if (obj->type == HWLOC_OBJ_GROUP) {
1007 ignored = 1;
1008 } else {
1009 if (hwloc__xml_verbose())
1010 fprintf(stderr, "%s: invalid object %s P#%u with some missing nodesets\n",
1011 state->global->msgprefix, hwloc_obj_type_string(obj->type), obj->os_index);
1012 goto error_with_object;
1013 }
1014 } else if (obj->nodeset && !obj->cpuset) {
1015
1016 if (obj->type == HWLOC_OBJ_GROUP) {
1017 ignored = 1;
1018 } else {
1019 if (hwloc__xml_verbose())
1020 fprintf(stderr, "%s: invalid object %s P#%u with either cpuset or nodeset missing\n",
1021 state->global->msgprefix, hwloc_obj_type_string(obj->type), obj->os_index);
1022 goto error_with_object;
1023 }
1024 }
1025
1026 }
1027
1028
1029 if (hwloc__obj_type_is_cache(obj->type)
1030 && obj->type != hwloc_cache_type_by_depth_type(obj->attr->cache.depth, obj->attr->cache.type)) {
1031 if (hwloc__xml_verbose())
1032 fprintf(stderr, "%s: invalid cache type %s with attribute depth %u and type %d\n",
1033 state->global->msgprefix, hwloc_obj_type_string(obj->type), obj->attr->cache.depth, (int) obj->attr->cache.type);
1034 goto error_with_object;
1035 }
1036
1037
1038 if (!obj->cpuset && !hwloc__obj_type_is_special(obj->type)) {
1039 if (hwloc__xml_verbose())
1040 fprintf(stderr, "%s: invalid normal object %s P#%u without cpuset\n",
1041 state->global->msgprefix, hwloc_obj_type_string(obj->type), obj->os_index);
1042 goto error_with_object;
1043 }
1044 if (obj->cpuset && hwloc__obj_type_is_special(obj->type)) {
1045 if (hwloc__xml_verbose())
1046 fprintf(stderr, "%s: invalid special object %s with cpuset\n",
1047 state->global->msgprefix, hwloc_obj_type_string(obj->type));
1048 goto error_with_object;
1049 }
1050
1051
1052 if (obj->cpuset && parent && !parent->cpuset) {
1053 if (hwloc__xml_verbose())
1054 fprintf(stderr, "%s: invalid object %s P#%u with cpuset while parent has none\n",
1055 state->global->msgprefix, hwloc_obj_type_string(obj->type), obj->os_index);
1056 goto error_with_object;
1057 }
1058 if (obj->nodeset && parent && !parent->nodeset) {
1059 if (hwloc__xml_verbose())
1060 fprintf(stderr, "%s: invalid object %s P#%u with nodeset while parent has none\n",
1061 state->global->msgprefix, hwloc_obj_type_string(obj->type), obj->os_index);
1062 goto error_with_object;
1063 }
1064
1065
1066 if (obj->type == HWLOC_OBJ_NUMANODE) {
1067 if (!obj->nodeset) {
1068 if (hwloc__xml_verbose())
1069 fprintf(stderr, "%s: invalid NUMA node object P#%u without nodeset\n",
1070 state->global->msgprefix, obj->os_index);
1071 goto error_with_object;
1072 }
1073 data->nbnumanodes++;
1074 obj->prev_cousin = data->last_numanode;
1075 obj->next_cousin = NULL;
1076 if (data->last_numanode)
1077 data->last_numanode->next_cousin = obj;
1078 else
1079 data->first_numanode = obj;
1080 data->last_numanode = obj;
1081 }
1082
1083 if (!hwloc_filter_check_keep_object(topology, obj)) {
1084
1085
1086
1087
1088
1089 if (parent)
1090 ignored = 1;
1091 }
1092
1093 if (parent && !ignored) {
1094
1095 hwloc_insert_object_by_parent(topology, parent, obj);
1096
1097 }
1098
1099
1100 while (tag) {
1101 int ret;
1102
1103 if (!strcmp(tag, "object")) {
1104 hwloc_obj_t childobj = hwloc_alloc_setup_object(topology, HWLOC_OBJ_TYPE_MAX, HWLOC_UNKNOWN_INDEX);
1105 childobj->parent = ignored ? parent : obj;
1106 ret = hwloc__xml_import_object(topology, data, ignored ? parent : obj, childobj,
1107 &childrengotignored,
1108 &childstate);
1109 } else {
1110 if (hwloc__xml_verbose())
1111 fprintf(stderr, "%s: invalid special object child %s while looking for objects\n",
1112 state->global->msgprefix, tag);
1113 ret = -1;
1114 }
1115
1116 if (ret < 0)
1117 goto error;
1118
1119 state->global->close_child(&childstate);
1120
1121 tag = NULL;
1122 ret = state->global->find_child(state, &childstate, &tag);
1123 if (ret < 0)
1124 goto error;
1125 if (!ret)
1126 break;
1127 }
1128
1129 if (numa_was_root) {
1130
1131 unsigned i;
1132 for(i=0; i<obj->infos_count; i++) {
1133 struct hwloc_info_s *info = &obj->infos[i];
1134 hwloc_obj_add_info(parent, info->name, info->value);
1135 }
1136
1137 }
1138
1139 if (ignored) {
1140
1141 hwloc_free_unlinked_object(obj);
1142 *gotignored = 1;
1143
1144 } else if (obj->first_child) {
1145
1146
1147
1148 hwloc_obj_t cur, next;
1149 for(cur = obj->first_child, next = cur->next_sibling;
1150 next;
1151 cur = next, next = next->next_sibling) {
1152
1153
1154
1155
1156
1157 if (hwloc_bitmap_compare_first(next->complete_cpuset, cur->complete_cpuset) < 0) {
1158
1159 if (!childrengotignored) {
1160 static int reported = 0;
1161 if (!reported && !hwloc_hide_errors()) {
1162 hwloc__xml_import_report_outoforder(topology, next, cur);
1163 reported = 1;
1164 }
1165 }
1166 hwloc__reorder_children(obj);
1167 break;
1168 }
1169 }
1170
1171
1172
1173 }
1174
1175 return state->global->close_tag(state);
1176
1177 error_with_object:
1178 if (parent)
1179
1180 hwloc_free_unlinked_object(obj);
1181 error:
1182 return -1;
1183 }
1184
1185 static int
1186 hwloc__xml_v2import_distances(hwloc_topology_t topology,
1187 hwloc__xml_import_state_t state)
1188 {
1189 hwloc_obj_type_t type = HWLOC_OBJ_TYPE_NONE;
1190 unsigned nbobjs = 0;
1191 int indexing = 0;
1192 int os_indexing = 0;
1193 int gp_indexing = 0;
1194 unsigned long kind = 0;
1195 unsigned nr_indexes, nr_u64values;
1196 uint64_t *indexes;
1197 uint64_t *u64values;
1198 int ret;
1199
1200
1201 while (1) {
1202 char *attrname, *attrvalue;
1203 if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
1204 break;
1205 if (!strcmp(attrname, "nbobjs"))
1206 nbobjs = strtoul(attrvalue, NULL, 10);
1207 else if (!strcmp(attrname, "type")) {
1208 if (hwloc_type_sscanf(attrvalue, &type, NULL, 0) < 0)
1209 goto out;
1210 }
1211 else if (!strcmp(attrname, "indexing")) {
1212 indexing = 1;
1213 if (!strcmp(attrvalue, "os"))
1214 os_indexing = 1;
1215 else if (!strcmp(attrvalue, "gp"))
1216 gp_indexing = 1;
1217 }
1218 else if (!strcmp(attrname, "kind")) {
1219 kind = strtoul(attrvalue, NULL, 10);
1220 }
1221 else {
1222 if (hwloc__xml_verbose())
1223 fprintf(stderr, "%s: ignoring unknown distance attribute %s\n",
1224 state->global->msgprefix, attrname);
1225 }
1226 }
1227
1228
1229 if (!nbobjs || type == HWLOC_OBJ_TYPE_NONE || !indexing || !kind) {
1230 if (hwloc__xml_verbose())
1231 fprintf(stderr, "%s: distance2 missing some attributes\n",
1232 state->global->msgprefix);
1233 goto out;
1234 }
1235
1236 indexes = malloc(nbobjs*sizeof(*indexes));
1237 u64values = malloc(nbobjs*nbobjs*sizeof(*u64values));
1238 if (!indexes || !u64values) {
1239 if (hwloc__xml_verbose())
1240 fprintf(stderr, "%s: failed to allocate distances arrays for %u objects\n",
1241 state->global->msgprefix, nbobjs);
1242 goto out_with_arrays;
1243 }
1244
1245
1246 nr_indexes = 0;
1247 nr_u64values = 0;
1248 while (1) {
1249 struct hwloc__xml_import_state_s childstate;
1250 char *attrname, *attrvalue, *tag, *buffer;
1251 int length;
1252 int is_index = 0;
1253 int is_u64values = 0;
1254
1255 ret = state->global->find_child(state, &childstate, &tag);
1256 if (ret <= 0)
1257 break;
1258
1259 if (!strcmp(tag, "indexes"))
1260 is_index = 1;
1261 else if (!strcmp(tag, "u64values"))
1262 is_u64values = 1;
1263 if (!is_index && !is_u64values) {
1264 if (hwloc__xml_verbose())
1265 fprintf(stderr, "%s: distance2 with unrecognized child %s\n",
1266 state->global->msgprefix, tag);
1267 goto out_with_arrays;
1268 }
1269
1270 if (state->global->next_attr(&childstate, &attrname, &attrvalue) < 0
1271 || strcmp(attrname, "length")) {
1272 if (hwloc__xml_verbose())
1273 fprintf(stderr, "%s: distance2 child must have length attribute\n",
1274 state->global->msgprefix);
1275 goto out_with_arrays;
1276 }
1277 length = atoi(attrvalue);
1278
1279 ret = state->global->get_content(&childstate, &buffer, length);
1280 if (ret < 0) {
1281 if (hwloc__xml_verbose())
1282 fprintf(stderr, "%s: distance2 child needs content of length %d\n",
1283 state->global->msgprefix, length);
1284 goto out_with_arrays;
1285 }
1286
1287 if (is_index) {
1288
1289 char *tmp;
1290 if (nr_indexes >= nbobjs) {
1291 if (hwloc__xml_verbose())
1292 fprintf(stderr, "%s: distance2 with more than %u indexes\n",
1293 state->global->msgprefix, nbobjs);
1294 goto out_with_arrays;
1295 }
1296 tmp = buffer;
1297 while (1) {
1298 char *next;
1299 unsigned long long u = strtoull(tmp, &next, 0);
1300 if (next == tmp)
1301 break;
1302 indexes[nr_indexes++] = u;
1303 if (*next != ' ')
1304 break;
1305 if (nr_indexes == nbobjs)
1306 break;
1307 tmp = next+1;
1308 }
1309
1310 } else if (is_u64values) {
1311
1312 char *tmp;
1313 if (nr_u64values >= nbobjs*nbobjs) {
1314 if (hwloc__xml_verbose())
1315 fprintf(stderr, "%s: distance2 with more than %u u64values\n",
1316 state->global->msgprefix, nbobjs*nbobjs);
1317 goto out_with_arrays;
1318 }
1319 tmp = buffer;
1320 while (1) {
1321 char *next;
1322 unsigned long long u = strtoull(tmp, &next, 0);
1323 if (next == tmp)
1324 break;
1325 u64values[nr_u64values++] = u;
1326 if (*next != ' ')
1327 break;
1328 if (nr_u64values == nbobjs*nbobjs)
1329 break;
1330 tmp = next+1;
1331 }
1332 }
1333
1334 state->global->close_content(&childstate);
1335
1336 ret = state->global->close_tag(&childstate);
1337 if (ret < 0) {
1338 if (hwloc__xml_verbose())
1339 fprintf(stderr, "%s: distance2 with more than %u indexes\n",
1340 state->global->msgprefix, nbobjs);
1341 goto out_with_arrays;
1342 }
1343
1344 state->global->close_child(&childstate);
1345 }
1346
1347 if (nr_indexes != nbobjs) {
1348 if (hwloc__xml_verbose())
1349 fprintf(stderr, "%s: distance2 with less than %u indexes\n",
1350 state->global->msgprefix, nbobjs);
1351 goto out_with_arrays;
1352 }
1353 if (nr_u64values != nbobjs*nbobjs) {
1354 if (hwloc__xml_verbose())
1355 fprintf(stderr, "%s: distance2 with less than %u u64values\n",
1356 state->global->msgprefix, nbobjs*nbobjs);
1357 goto out_with_arrays;
1358 }
1359
1360 if (nbobjs < 2) {
1361
1362 if (hwloc__xml_verbose())
1363 fprintf(stderr, "%s: ignoring distances2 with only %u objects\n",
1364 state->global->msgprefix, nbobjs);
1365 goto out_ignore;
1366 }
1367 if (type == HWLOC_OBJ_PU || type == HWLOC_OBJ_NUMANODE) {
1368 if (!os_indexing) {
1369 if (hwloc__xml_verbose())
1370 fprintf(stderr, "%s: ignoring PU or NUMA distances2 without os_indexing\n",
1371 state->global->msgprefix);
1372 goto out_ignore;
1373 }
1374 } else {
1375 if (!gp_indexing) {
1376 if (hwloc__xml_verbose())
1377 fprintf(stderr, "%s: ignoring !PU or !NUMA distances2 without gp_indexing\n",
1378 state->global->msgprefix);
1379 goto out_ignore;
1380 }
1381 }
1382
1383 hwloc_internal_distances_add_by_index(topology, type, nbobjs, indexes, u64values, kind, 0);
1384
1385
1386 indexes = NULL;
1387 u64values = NULL;
1388
1389 out_ignore:
1390 free(indexes);
1391 free(u64values);
1392 return state->global->close_tag(state);
1393
1394 out_with_arrays:
1395 free(indexes);
1396 free(u64values);
1397 out:
1398 return -1;
1399 }
1400
1401 static int
1402 hwloc__xml_import_diff_one(hwloc__xml_import_state_t state,
1403 hwloc_topology_diff_t *firstdiffp,
1404 hwloc_topology_diff_t *lastdiffp)
1405 {
1406 char *type_s = NULL;
1407 char *obj_depth_s = NULL;
1408 char *obj_index_s = NULL;
1409 char *obj_attr_type_s = NULL;
1410
1411 char *obj_attr_name_s = NULL;
1412 char *obj_attr_oldvalue_s = NULL;
1413 char *obj_attr_newvalue_s = NULL;
1414
1415 while (1) {
1416 char *attrname, *attrvalue;
1417 if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
1418 break;
1419 if (!strcmp(attrname, "type"))
1420 type_s = attrvalue;
1421 else if (!strcmp(attrname, "obj_depth"))
1422 obj_depth_s = attrvalue;
1423 else if (!strcmp(attrname, "obj_index"))
1424 obj_index_s = attrvalue;
1425 else if (!strcmp(attrname, "obj_attr_type"))
1426 obj_attr_type_s = attrvalue;
1427 else if (!strcmp(attrname, "obj_attr_index"))
1428 { }
1429 else if (!strcmp(attrname, "obj_attr_name"))
1430 obj_attr_name_s = attrvalue;
1431 else if (!strcmp(attrname, "obj_attr_oldvalue"))
1432 obj_attr_oldvalue_s = attrvalue;
1433 else if (!strcmp(attrname, "obj_attr_newvalue"))
1434 obj_attr_newvalue_s = attrvalue;
1435 else {
1436 if (hwloc__xml_verbose())
1437 fprintf(stderr, "%s: ignoring unknown diff attribute %s\n",
1438 state->global->msgprefix, attrname);
1439 return -1;
1440 }
1441 }
1442
1443 if (type_s) {
1444 switch (atoi(type_s)) {
1445 default:
1446 break;
1447 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR: {
1448
1449 hwloc_topology_diff_obj_attr_type_t obj_attr_type;
1450 hwloc_topology_diff_t diff;
1451
1452
1453 if (!obj_depth_s || !obj_index_s || !obj_attr_type_s) {
1454 if (hwloc__xml_verbose())
1455 fprintf(stderr, "%s: missing mandatory obj attr generic attributes\n",
1456 state->global->msgprefix);
1457 break;
1458 }
1459
1460
1461 if (!obj_attr_oldvalue_s || !obj_attr_newvalue_s) {
1462 if (hwloc__xml_verbose())
1463 fprintf(stderr, "%s: missing mandatory obj attr value attributes\n",
1464 state->global->msgprefix);
1465 break;
1466 }
1467
1468
1469 obj_attr_type = atoi(obj_attr_type_s);
1470 if (obj_attr_type == HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO && !obj_attr_name_s) {
1471 if (hwloc__xml_verbose())
1472 fprintf(stderr, "%s: missing mandatory obj attr info name attribute\n",
1473 state->global->msgprefix);
1474 break;
1475 }
1476
1477
1478 diff = malloc(sizeof(*diff));
1479 if (!diff)
1480 return -1;
1481 diff->obj_attr.type = HWLOC_TOPOLOGY_DIFF_OBJ_ATTR;
1482 diff->obj_attr.obj_depth = atoi(obj_depth_s);
1483 diff->obj_attr.obj_index = atoi(obj_index_s);
1484 memset(&diff->obj_attr.diff, 0, sizeof(diff->obj_attr.diff));
1485 diff->obj_attr.diff.generic.type = obj_attr_type;
1486
1487 switch (atoi(obj_attr_type_s)) {
1488 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_SIZE:
1489 diff->obj_attr.diff.uint64.oldvalue = strtoull(obj_attr_oldvalue_s, NULL, 0);
1490 diff->obj_attr.diff.uint64.newvalue = strtoull(obj_attr_newvalue_s, NULL, 0);
1491 break;
1492 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO:
1493 diff->obj_attr.diff.string.name = strdup(obj_attr_name_s);
1494
1495 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_NAME:
1496 diff->obj_attr.diff.string.oldvalue = strdup(obj_attr_oldvalue_s);
1497 diff->obj_attr.diff.string.newvalue = strdup(obj_attr_newvalue_s);
1498 break;
1499 }
1500
1501 if (*firstdiffp)
1502 (*lastdiffp)->generic.next = diff;
1503 else
1504 *firstdiffp = diff;
1505 *lastdiffp = diff;
1506 diff->generic.next = NULL;
1507 }
1508 }
1509 }
1510
1511 return state->global->close_tag(state);
1512 }
1513
1514 int
1515 hwloc__xml_import_diff(hwloc__xml_import_state_t state,
1516 hwloc_topology_diff_t *firstdiffp)
1517 {
1518 hwloc_topology_diff_t firstdiff = NULL, lastdiff = NULL;
1519 *firstdiffp = NULL;
1520
1521 while (1) {
1522 struct hwloc__xml_import_state_s childstate;
1523 char *tag;
1524 int ret;
1525
1526 ret = state->global->find_child(state, &childstate, &tag);
1527 if (ret < 0)
1528 return -1;
1529 if (!ret)
1530 break;
1531
1532 if (!strcmp(tag, "diff")) {
1533 ret = hwloc__xml_import_diff_one(&childstate, &firstdiff, &lastdiff);
1534 } else
1535 ret = -1;
1536
1537 if (ret < 0)
1538 return ret;
1539
1540 state->global->close_child(&childstate);
1541 }
1542
1543 *firstdiffp = firstdiff;
1544 return 0;
1545 }
1546
1547
1548
1549
1550
1551 static void
1552 hwloc_convert_from_v1dist_floats(hwloc_topology_t topology, unsigned nbobjs, float *floats, uint64_t *u64s)
1553 {
1554 unsigned i;
1555 int is_uint;
1556 char *env;
1557 float scale = 1000.f;
1558 char scalestring[20];
1559
1560 env = getenv("HWLOC_XML_V1DIST_SCALE");
1561 if (env) {
1562 scale = (float) atof(env);
1563 goto scale;
1564 }
1565
1566 is_uint = 1;
1567
1568 for(i=0; i<nbobjs*nbobjs; i++) {
1569 float f, iptr, fptr;
1570 f = floats[i];
1571 if (f < 0.f) {
1572 is_uint = 0;
1573 break;
1574 }
1575 fptr = modff(f, &iptr);
1576 if (fptr > .001f && fptr < .999f) {
1577 is_uint = 0;
1578 break;
1579 }
1580 u64s[i] = (int)(f+.5f);
1581 }
1582 if (is_uint)
1583 return;
1584
1585 scale:
1586
1587 for(i=0; i<nbobjs*nbobjs; i++)
1588 u64s[i] = (uint64_t)(scale * floats[i]);
1589
1590
1591
1592
1593
1594 sprintf(scalestring, "%f", scale);
1595 hwloc_obj_add_info(hwloc_get_root_obj(topology), "xmlv1DistancesScale", scalestring);
1596 }
1597
1598
1599 static int
1600 hwloc_look_xml(struct hwloc_backend *backend)
1601 {
1602 struct hwloc_topology *topology = backend->topology;
1603 struct hwloc_xml_backend_data_s *data = backend->private_data;
1604 struct hwloc__xml_import_state_s state, childstate;
1605 struct hwloc_obj *root = topology->levels[0][0];
1606 char *tag;
1607 int gotignored = 0;
1608 hwloc_localeswitch_declare;
1609 int ret;
1610
1611 state.global = data;
1612
1613 assert(!root->cpuset);
1614
1615 hwloc_localeswitch_init();
1616
1617 data->nbnumanodes = 0;
1618 data->first_numanode = data->last_numanode = NULL;
1619 data->first_v1dist = data->last_v1dist = NULL;
1620
1621 ret = data->look_init(data, &state);
1622 if (ret < 0)
1623 goto failed;
1624
1625 if (data->version_major > 2) {
1626 if (hwloc__xml_verbose())
1627 fprintf(stderr, "%s: cannot import XML version %u.%u > 2\n",
1628 data->msgprefix, data->version_major, data->version_minor);
1629 goto err;
1630 }
1631
1632
1633 ret = state.global->find_child(&state, &childstate, &tag);
1634 if (ret < 0 || !ret || strcmp(tag, "object"))
1635 goto failed;
1636 ret = hwloc__xml_import_object(topology, data, NULL , root,
1637 &gotignored,
1638 &childstate);
1639 if (ret < 0)
1640 goto failed;
1641 state.global->close_child(&childstate);
1642 assert(!gotignored);
1643
1644
1645 root = topology->levels[0][0];
1646
1647 if (data->version_major >= 2) {
1648
1649 while (1) {
1650 ret = state.global->find_child(&state, &childstate, &tag);
1651 if (ret < 0)
1652 goto failed;
1653 if (!ret)
1654 break;
1655 if (strcmp(tag, "distances2")) {
1656 if (hwloc__xml_verbose())
1657 fprintf(stderr, "%s: ignoring unknown tag `%s' after root object, expected `distances2'\n",
1658 data->msgprefix, tag);
1659 goto done;
1660 }
1661 ret = hwloc__xml_v2import_distances(topology, &childstate);
1662 if (ret < 0)
1663 goto failed;
1664 state.global->close_child(&childstate);
1665 }
1666 }
1667
1668
1669 state.global->close_tag(&state);
1670
1671 done:
1672 if (!root->cpuset) {
1673 if (hwloc__xml_verbose())
1674 fprintf(stderr, "%s: invalid root object without cpuset\n",
1675 data->msgprefix);
1676 goto err;
1677 }
1678
1679
1680 if (data->version_major < 2 && data->first_numanode) {
1681 hwloc_obj_t node = data->first_numanode;
1682 do {
1683 if (node->parent->type == HWLOC_OBJ_GROUP
1684 && !node->parent->gp_index)
1685 node->parent->gp_index = topology->next_gp_index++;
1686 node = node->next_cousin;
1687 } while (node);
1688 }
1689
1690 if (data->version_major < 2 && data->first_v1dist) {
1691
1692 struct hwloc__xml_imported_v1distances_s *v1dist, *v1next = data->first_v1dist;
1693 while ((v1dist = v1next) != NULL) {
1694 unsigned nbobjs = v1dist->nbobjs;
1695 v1next = v1dist->next;
1696
1697
1698
1699
1700
1701
1702
1703 if (nbobjs == data->nbnumanodes) {
1704 hwloc_obj_t *objs = malloc(nbobjs*sizeof(hwloc_obj_t));
1705 uint64_t *values = malloc(nbobjs*nbobjs*sizeof(*values));
1706 if (objs && values) {
1707 hwloc_obj_t node;
1708 unsigned i;
1709 for(i=0, node = data->first_numanode;
1710 i<nbobjs;
1711 i++, node = node->next_cousin)
1712 objs[i] = node;
1713 hwloc_convert_from_v1dist_floats(topology, nbobjs, v1dist->floats, values);
1714 hwloc_internal_distances_add(topology, nbobjs, objs, values, v1dist->kind, 0);
1715 } else {
1716 free(objs);
1717 free(values);
1718 }
1719 }
1720 free(v1dist->floats);
1721 free(v1dist);
1722 }
1723 data->first_v1dist = data->last_v1dist = NULL;
1724 }
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737 if (data->version_major >= 2) {
1738
1739 if (!root->nodeset) {
1740 if (hwloc__xml_verbose())
1741 fprintf(stderr, "%s: invalid root object without nodeset\n",
1742 data->msgprefix);
1743 goto err;
1744 }
1745 if (hwloc_bitmap_iszero(root->nodeset)) {
1746 if (hwloc__xml_verbose())
1747 fprintf(stderr, "%s: invalid root object with empty nodeset\n",
1748 data->msgprefix);
1749 goto err;
1750 }
1751 } else {
1752
1753 }
1754
1755
1756 hwloc_alloc_root_sets(root);
1757
1758
1759
1760
1761 topology->support.discovery->pu = 1;
1762 if (data->nbnumanodes) {
1763 topology->support.discovery->numa = 1;
1764 topology->support.discovery->numa_memory = 1;
1765 }
1766
1767 if (data->look_done)
1768 data->look_done(data, 0);
1769
1770 hwloc_localeswitch_fini();
1771 return 0;
1772
1773 failed:
1774 if (data->look_done)
1775 data->look_done(data, -1);
1776 if (hwloc__xml_verbose())
1777 fprintf(stderr, "%s: XML component discovery failed.\n",
1778 data->msgprefix);
1779 err:
1780 hwloc_free_object_siblings_and_children(root->first_child);
1781 root->first_child = NULL;
1782 hwloc_free_object_siblings_and_children(root->memory_first_child);
1783 root->memory_first_child = NULL;
1784 hwloc_free_object_siblings_and_children(root->io_first_child);
1785 root->io_first_child = NULL;
1786 hwloc_free_object_siblings_and_children(root->misc_first_child);
1787 root->misc_first_child = NULL;
1788
1789
1790 if (root->cpuset)
1791 hwloc_bitmap_zero(root->cpuset);
1792 if (root->nodeset)
1793 hwloc_bitmap_zero(root->nodeset);
1794
1795 hwloc_localeswitch_fini();
1796 return -1;
1797 }
1798
1799
1800 int
1801 hwloc_topology_diff_load_xml(const char *xmlpath,
1802 hwloc_topology_diff_t *firstdiffp, char **refnamep)
1803 {
1804 struct hwloc__xml_import_state_s state;
1805 struct hwloc_xml_backend_data_s fakedata;
1806 hwloc_localeswitch_declare;
1807 const char *basename;
1808 int force_nolibxml;
1809 int ret;
1810
1811 state.global = &fakedata;
1812
1813 basename = strrchr(xmlpath, '/');
1814 if (basename)
1815 basename++;
1816 else
1817 basename = xmlpath;
1818 fakedata.msgprefix = strdup(basename);
1819
1820 hwloc_components_init();
1821 assert(hwloc_nolibxml_callbacks);
1822
1823 hwloc_localeswitch_init();
1824
1825 *firstdiffp = NULL;
1826
1827 force_nolibxml = hwloc_nolibxml_import();
1828 retry:
1829 if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml))
1830 ret = hwloc_nolibxml_callbacks->import_diff(&state, xmlpath, NULL, 0, firstdiffp, refnamep);
1831 else {
1832 ret = hwloc_libxml_callbacks->import_diff(&state, xmlpath, NULL, 0, firstdiffp, refnamep);
1833 if (ret < 0 && errno == ENOSYS) {
1834 hwloc_libxml_callbacks = NULL;
1835 goto retry;
1836 }
1837 }
1838
1839 hwloc_localeswitch_fini();
1840 hwloc_components_fini();
1841 free(fakedata.msgprefix);
1842 return ret;
1843 }
1844
1845
1846 int
1847 hwloc_topology_diff_load_xmlbuffer(const char *xmlbuffer, int buflen,
1848 hwloc_topology_diff_t *firstdiffp, char **refnamep)
1849 {
1850 struct hwloc__xml_import_state_s state;
1851 struct hwloc_xml_backend_data_s fakedata;
1852 hwloc_localeswitch_declare;
1853 int force_nolibxml;
1854 int ret;
1855
1856 state.global = &fakedata;
1857 fakedata.msgprefix = strdup("xmldiffbuffer");
1858
1859 hwloc_components_init();
1860 assert(hwloc_nolibxml_callbacks);
1861
1862 hwloc_localeswitch_init();
1863
1864 *firstdiffp = NULL;
1865
1866 force_nolibxml = hwloc_nolibxml_import();
1867 retry:
1868 if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml))
1869 ret = hwloc_nolibxml_callbacks->import_diff(&state, NULL, xmlbuffer, buflen, firstdiffp, refnamep);
1870 else {
1871 ret = hwloc_libxml_callbacks->import_diff(&state, NULL, xmlbuffer, buflen, firstdiffp, refnamep);
1872 if (ret < 0 && errno == ENOSYS) {
1873 hwloc_libxml_callbacks = NULL;
1874 goto retry;
1875 }
1876 }
1877
1878 hwloc_localeswitch_fini();
1879 hwloc_components_fini();
1880 free(fakedata.msgprefix);
1881 return ret;
1882 }
1883
1884
1885
1886
1887
1888 #define HWLOC_XML_CHAR_VALID(c) (((c) >= 32 && (c) <= 126) || (c) == '\t' || (c) == '\n' || (c) == '\r')
1889
1890 static int
1891 hwloc__xml_export_check_buffer(const char *buf, size_t length)
1892 {
1893 unsigned i;
1894 for(i=0; i<length; i++)
1895 if (!HWLOC_XML_CHAR_VALID(buf[i]))
1896 return -1;
1897 return 0;
1898 }
1899
1900
1901 static char*
1902 hwloc__xml_export_safestrdup(const char *old)
1903 {
1904 char *new = malloc(strlen(old)+1);
1905 char *dst = new;
1906 const char *src = old;
1907 while (*src) {
1908 if (HWLOC_XML_CHAR_VALID(*src))
1909 *(dst++) = *src;
1910 src++;
1911 }
1912 *dst = '\0';
1913 return new;
1914 }
1915
1916 static void
1917 hwloc__xml_export_object_contents (hwloc__xml_export_state_t state, hwloc_topology_t topology, hwloc_obj_t obj, unsigned long flags)
1918 {
1919 char *setstring = NULL, *setstring2 = NULL;
1920 char tmp[255];
1921 int v1export = flags & HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1;
1922 unsigned i,j;
1923
1924 if (v1export && obj->type == HWLOC_OBJ_PACKAGE)
1925 state->new_prop(state, "type", "Socket");
1926 else if (v1export && hwloc__obj_type_is_cache(obj->type))
1927 state->new_prop(state, "type", "Cache");
1928 else
1929 state->new_prop(state, "type", hwloc_obj_type_string(obj->type));
1930
1931 if (obj->os_index != HWLOC_UNKNOWN_INDEX) {
1932 sprintf(tmp, "%u", obj->os_index);
1933 state->new_prop(state, "os_index", tmp);
1934 }
1935
1936 if (obj->cpuset) {
1937 if (v1export && obj->type == HWLOC_OBJ_NUMANODE && obj->sibling_rank > 0) {
1938
1939 state->new_prop(state, "cpuset", "0x0");
1940 state->new_prop(state, "online_cpuset", "0x0");
1941 state->new_prop(state, "complete_cpuset", "0x0");
1942 state->new_prop(state, "allowed_cpuset", "0x0");
1943
1944 } else {
1945
1946 hwloc_bitmap_asprintf(&setstring, obj->cpuset);
1947 state->new_prop(state, "cpuset", setstring);
1948
1949 hwloc_bitmap_asprintf(&setstring2, obj->complete_cpuset);
1950 state->new_prop(state, "complete_cpuset", setstring2);
1951 free(setstring2);
1952
1953 if (v1export)
1954 state->new_prop(state, "online_cpuset", setstring);
1955 free(setstring);
1956
1957 if (v1export || !obj->parent) {
1958 hwloc_bitmap_t allowed_cpuset = hwloc_bitmap_dup(obj->cpuset);
1959 hwloc_bitmap_and(allowed_cpuset, allowed_cpuset, topology->allowed_cpuset);
1960 hwloc_bitmap_asprintf(&setstring, allowed_cpuset);
1961 state->new_prop(state, "allowed_cpuset", setstring);
1962 free(setstring);
1963 hwloc_bitmap_free(allowed_cpuset);
1964 }
1965 }
1966
1967
1968
1969
1970 hwloc_bitmap_asprintf(&setstring, obj->nodeset);
1971 state->new_prop(state, "nodeset", setstring);
1972 free(setstring);
1973
1974 hwloc_bitmap_asprintf(&setstring, obj->complete_nodeset);
1975 state->new_prop(state, "complete_nodeset", setstring);
1976 free(setstring);
1977
1978 if (v1export || !obj->parent) {
1979 hwloc_bitmap_t allowed_nodeset = hwloc_bitmap_dup(obj->nodeset);
1980 hwloc_bitmap_and(allowed_nodeset, allowed_nodeset, topology->allowed_nodeset);
1981 hwloc_bitmap_asprintf(&setstring, allowed_nodeset);
1982 state->new_prop(state, "allowed_nodeset", setstring);
1983 free(setstring);
1984 hwloc_bitmap_free(allowed_nodeset);
1985 }
1986 }
1987
1988 if (!v1export) {
1989 sprintf(tmp, "%llu", (unsigned long long) obj->gp_index);
1990 state->new_prop(state, "gp_index", tmp);
1991 }
1992
1993 if (obj->name) {
1994 char *name = hwloc__xml_export_safestrdup(obj->name);
1995 state->new_prop(state, "name", name);
1996 free(name);
1997 }
1998 if (!v1export && obj->subtype) {
1999 char *subtype = hwloc__xml_export_safestrdup(obj->subtype);
2000 state->new_prop(state, "subtype", subtype);
2001 free(subtype);
2002 }
2003
2004 switch (obj->type) {
2005 case HWLOC_OBJ_NUMANODE:
2006 if (obj->attr->numanode.local_memory) {
2007 sprintf(tmp, "%llu", (unsigned long long) obj->attr->numanode.local_memory);
2008 state->new_prop(state, "local_memory", tmp);
2009 }
2010 for(i=0; i<obj->attr->numanode.page_types_len; i++) {
2011 struct hwloc__xml_export_state_s childstate;
2012 state->new_child(state, &childstate, "page_type");
2013 sprintf(tmp, "%llu", (unsigned long long) obj->attr->numanode.page_types[i].size);
2014 childstate.new_prop(&childstate, "size", tmp);
2015 sprintf(tmp, "%llu", (unsigned long long) obj->attr->numanode.page_types[i].count);
2016 childstate.new_prop(&childstate, "count", tmp);
2017 childstate.end_object(&childstate, "page_type");
2018 }
2019 break;
2020 case HWLOC_OBJ_L1CACHE:
2021 case HWLOC_OBJ_L2CACHE:
2022 case HWLOC_OBJ_L3CACHE:
2023 case HWLOC_OBJ_L4CACHE:
2024 case HWLOC_OBJ_L5CACHE:
2025 case HWLOC_OBJ_L1ICACHE:
2026 case HWLOC_OBJ_L2ICACHE:
2027 case HWLOC_OBJ_L3ICACHE:
2028 sprintf(tmp, "%llu", (unsigned long long) obj->attr->cache.size);
2029 state->new_prop(state, "cache_size", tmp);
2030 sprintf(tmp, "%u", obj->attr->cache.depth);
2031 state->new_prop(state, "depth", tmp);
2032 sprintf(tmp, "%u", (unsigned) obj->attr->cache.linesize);
2033 state->new_prop(state, "cache_linesize", tmp);
2034 sprintf(tmp, "%d", obj->attr->cache.associativity);
2035 state->new_prop(state, "cache_associativity", tmp);
2036 sprintf(tmp, "%d", (int) obj->attr->cache.type);
2037 state->new_prop(state, "cache_type", tmp);
2038 break;
2039 case HWLOC_OBJ_GROUP:
2040 if (v1export) {
2041 sprintf(tmp, "%u", obj->attr->group.depth);
2042 state->new_prop(state, "depth", tmp);
2043 } else {
2044 sprintf(tmp, "%u", obj->attr->group.kind);
2045 state->new_prop(state, "kind", tmp);
2046 sprintf(tmp, "%u", obj->attr->group.subkind);
2047 state->new_prop(state, "subkind", tmp);
2048 }
2049 break;
2050 case HWLOC_OBJ_BRIDGE:
2051 sprintf(tmp, "%d-%d", (int) obj->attr->bridge.upstream_type, (int) obj->attr->bridge.downstream_type);
2052 state->new_prop(state, "bridge_type", tmp);
2053 sprintf(tmp, "%u", obj->attr->bridge.depth);
2054 state->new_prop(state, "depth", tmp);
2055 if (obj->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI) {
2056 sprintf(tmp, "%04x:[%02x-%02x]",
2057 (unsigned) obj->attr->bridge.downstream.pci.domain,
2058 (unsigned) obj->attr->bridge.downstream.pci.secondary_bus,
2059 (unsigned) obj->attr->bridge.downstream.pci.subordinate_bus);
2060 state->new_prop(state, "bridge_pci", tmp);
2061 }
2062 if (obj->attr->bridge.upstream_type != HWLOC_OBJ_BRIDGE_PCI)
2063 break;
2064
2065 case HWLOC_OBJ_PCI_DEVICE:
2066 sprintf(tmp, "%04x:%02x:%02x.%01x",
2067 (unsigned) obj->attr->pcidev.domain,
2068 (unsigned) obj->attr->pcidev.bus,
2069 (unsigned) obj->attr->pcidev.dev,
2070 (unsigned) obj->attr->pcidev.func);
2071 state->new_prop(state, "pci_busid", tmp);
2072 sprintf(tmp, "%04x [%04x:%04x] [%04x:%04x] %02x",
2073 (unsigned) obj->attr->pcidev.class_id,
2074 (unsigned) obj->attr->pcidev.vendor_id, (unsigned) obj->attr->pcidev.device_id,
2075 (unsigned) obj->attr->pcidev.subvendor_id, (unsigned) obj->attr->pcidev.subdevice_id,
2076 (unsigned) obj->attr->pcidev.revision);
2077 state->new_prop(state, "pci_type", tmp);
2078 sprintf(tmp, "%f", obj->attr->pcidev.linkspeed);
2079 state->new_prop(state, "pci_link_speed", tmp);
2080 break;
2081 case HWLOC_OBJ_OS_DEVICE:
2082 sprintf(tmp, "%d", (int) obj->attr->osdev.type);
2083 state->new_prop(state, "osdev_type", tmp);
2084 break;
2085 default:
2086 break;
2087 }
2088
2089 for(i=0; i<obj->infos_count; i++) {
2090 char *name = hwloc__xml_export_safestrdup(obj->infos[i].name);
2091 char *value = hwloc__xml_export_safestrdup(obj->infos[i].value);
2092 struct hwloc__xml_export_state_s childstate;
2093 state->new_child(state, &childstate, "info");
2094 childstate.new_prop(&childstate, "name", name);
2095 childstate.new_prop(&childstate, "value", value);
2096 childstate.end_object(&childstate, "info");
2097 free(name);
2098 free(value);
2099 }
2100 if (v1export && obj->subtype) {
2101 char *subtype = hwloc__xml_export_safestrdup(obj->subtype);
2102 struct hwloc__xml_export_state_s childstate;
2103 int is_coproctype = (obj->type == HWLOC_OBJ_OS_DEVICE && obj->attr->osdev.type == HWLOC_OBJ_OSDEV_COPROC);
2104 state->new_child(state, &childstate, "info");
2105 childstate.new_prop(&childstate, "name", is_coproctype ? "CoProcType" : "Type");
2106 childstate.new_prop(&childstate, "value", subtype);
2107 childstate.end_object(&childstate, "info");
2108 free(subtype);
2109 }
2110
2111 if (v1export && !obj->parent) {
2112
2113 struct hwloc_internal_distances_s *dist;
2114
2115 hwloc_internal_distances_refresh(topology);
2116 for(dist = topology->first_dist; dist; dist = dist->next) {
2117 struct hwloc__xml_export_state_s childstate;
2118 unsigned nbobjs = dist->nbobjs;
2119 int depth;
2120
2121 if (nbobjs != (unsigned) hwloc_get_nbobjs_by_type(topology, dist->type))
2122 continue;
2123 if (!(dist->kind & HWLOC_DISTANCES_KIND_MEANS_LATENCY))
2124 continue;
2125 {
2126 HWLOC_VLA(unsigned, logical_to_v2array, nbobjs);
2127 for(i=0; i<nbobjs; i++)
2128 logical_to_v2array[dist->objs[i]->logical_index] = i;
2129
2130
2131 if (dist->type == HWLOC_OBJ_NUMANODE) {
2132
2133 depth = -1;
2134 for(i=0; i<nbobjs; i++) {
2135 hwloc_obj_t parent = dist->objs[i]->parent;
2136 while (hwloc__obj_type_is_memory(parent->type))
2137 parent = parent->parent;
2138 if (parent->depth+1 > depth)
2139 depth = parent->depth+1;
2140 }
2141 } else {
2142
2143 int parent_with_memory = 0;
2144 for(i=0; i<nbobjs; i++) {
2145 hwloc_obj_t parent = dist->objs[i]->parent;
2146 while (parent) {
2147 if (parent->memory_first_child) {
2148 parent_with_memory = 1;
2149 goto done;
2150 }
2151 parent = parent->parent;
2152 }
2153 }
2154 done:
2155 depth = hwloc_get_type_depth(topology, dist->type) + parent_with_memory;
2156 }
2157
2158 state->new_child(state, &childstate, "distances");
2159 sprintf(tmp, "%u", nbobjs);
2160 childstate.new_prop(&childstate, "nbobjs", tmp);
2161 sprintf(tmp, "%d", depth);
2162 childstate.new_prop(&childstate, "relative_depth", tmp);
2163 sprintf(tmp, "%f", 1.f);
2164 childstate.new_prop(&childstate, "latency_base", tmp);
2165 for(i=0; i<nbobjs; i++) {
2166 for(j=0; j<nbobjs; j++) {
2167
2168 unsigned k = logical_to_v2array[i]*nbobjs+logical_to_v2array[j];
2169 struct hwloc__xml_export_state_s greatchildstate;
2170 childstate.new_child(&childstate, &greatchildstate, "latency");
2171 sprintf(tmp, "%f", (float) dist->values[k]);
2172 greatchildstate.new_prop(&greatchildstate, "value", tmp);
2173 greatchildstate.end_object(&greatchildstate, "latency");
2174 }
2175 }
2176 childstate.end_object(&childstate, "distances");
2177 }
2178 }
2179 }
2180
2181 if (obj->userdata && topology->userdata_export_cb)
2182 topology->userdata_export_cb((void*) state, topology, obj);
2183 }
2184
2185 static void
2186 hwloc__xml_v2export_object (hwloc__xml_export_state_t parentstate, hwloc_topology_t topology, hwloc_obj_t obj, unsigned long flags)
2187 {
2188 struct hwloc__xml_export_state_s state;
2189 hwloc_obj_t child;
2190
2191 parentstate->new_child(parentstate, &state, "object");
2192
2193 hwloc__xml_export_object_contents(&state, topology, obj, flags);
2194
2195 for_each_memory_child(child, obj)
2196 hwloc__xml_v2export_object (&state, topology, child, flags);
2197 for_each_child(child, obj)
2198 hwloc__xml_v2export_object (&state, topology, child, flags);
2199 for_each_io_child(child, obj)
2200 hwloc__xml_v2export_object (&state, topology, child, flags);
2201 for_each_misc_child(child, obj)
2202 hwloc__xml_v2export_object (&state, topology, child, flags);
2203
2204 state.end_object(&state, "object");
2205 }
2206
2207 static void
2208 hwloc__xml_v1export_object (hwloc__xml_export_state_t parentstate, hwloc_topology_t topology, hwloc_obj_t obj, unsigned long flags);
2209
2210 static void
2211 hwloc__xml_v1export_object_with_memory(hwloc__xml_export_state_t parentstate, hwloc_topology_t topology, hwloc_obj_t obj, unsigned long flags)
2212 {
2213 struct hwloc__xml_export_state_s gstate, mstate, ostate, *state = parentstate;
2214 hwloc_obj_t child;
2215
2216 if (obj->parent->arity > 1 && obj->memory_arity > 1 && parentstate->global->v1_memory_group) {
2217
2218 hwloc_obj_t group = parentstate->global->v1_memory_group;
2219 parentstate->new_child(parentstate, &gstate, "object");
2220 group->cpuset = obj->cpuset;
2221 group->complete_cpuset = obj->complete_cpuset;
2222 group->nodeset = obj->nodeset;
2223 group->complete_nodeset = obj->complete_nodeset;
2224 hwloc__xml_export_object_contents (&gstate, topology, group, flags);
2225 group->cpuset = NULL;
2226 group->complete_cpuset = NULL;
2227 group->nodeset = NULL;
2228 group->complete_nodeset = NULL;
2229 state = &gstate;
2230 }
2231
2232
2233 child = obj->memory_first_child;
2234 assert(child->type == HWLOC_OBJ_NUMANODE);
2235 state->new_child(state, &mstate, "object");
2236 hwloc__xml_export_object_contents (&mstate, topology, child, flags);
2237
2238
2239 mstate.new_child(&mstate, &ostate, "object");
2240 hwloc__xml_export_object_contents (&ostate, topology, obj, flags);
2241
2242
2243 for_each_child(child, obj)
2244 hwloc__xml_v1export_object (&ostate, topology, child, flags);
2245 for_each_io_child(child, obj)
2246 hwloc__xml_v1export_object (&ostate, topology, child, flags);
2247 for_each_misc_child(child, obj)
2248 hwloc__xml_v1export_object (&ostate, topology, child, flags);
2249
2250
2251 ostate.end_object(&ostate, "object");
2252 mstate.end_object(&mstate, "object");
2253
2254
2255 for_each_memory_child(child, obj)
2256 if (child->sibling_rank > 0)
2257 hwloc__xml_v1export_object (state, topology, child, flags);
2258
2259 if (state == &gstate) {
2260
2261 gstate.end_object(&gstate, "object");
2262 }
2263 }
2264
2265 static void
2266 hwloc__xml_v1export_object (hwloc__xml_export_state_t parentstate, hwloc_topology_t topology, hwloc_obj_t obj, unsigned long flags)
2267 {
2268 struct hwloc__xml_export_state_s state;
2269 hwloc_obj_t child;
2270
2271 parentstate->new_child(parentstate, &state, "object");
2272
2273 hwloc__xml_export_object_contents(&state, topology, obj, flags);
2274
2275 for_each_child(child, obj) {
2276 if (!child->memory_arity) {
2277
2278 hwloc__xml_v1export_object (&state, topology, child, flags);
2279 } else {
2280 hwloc__xml_v1export_object_with_memory(&state, topology, child, flags);
2281 }
2282 }
2283
2284 for_each_io_child(child, obj)
2285 hwloc__xml_v1export_object (&state, topology, child, flags);
2286 for_each_misc_child(child, obj)
2287 hwloc__xml_v1export_object (&state, topology, child, flags);
2288
2289 state.end_object(&state, "object");
2290 }
2291
2292 #define EXPORT_ARRAY(state, type, nr, values, tagname, format, maxperline) do { \
2293 unsigned _i = 0; \
2294 while (_i<(nr)) { \
2295 char _tmp[255]; \
2296 char _tmp2[16]; \
2297 size_t _len = 0; \
2298 unsigned _j; \
2299 struct hwloc__xml_export_state_s _childstate; \
2300 (state)->new_child(state, &_childstate, tagname); \
2301 for(_j=0; \
2302 _i+_j<(nr) && _j<maxperline; \
2303 _j++) \
2304 _len += sprintf(_tmp+_len, format " ", (type) (values)[_i+_j]); \
2305 _i += _j; \
2306 sprintf(_tmp2, "%lu", (unsigned long) _len); \
2307 _childstate.new_prop(&_childstate, "length", _tmp2); \
2308 _childstate.add_content(&_childstate, _tmp, _len); \
2309 _childstate.end_object(&_childstate, tagname); \
2310 } \
2311 } while (0)
2312
2313 static void
2314 hwloc__xml_v2export_distances(hwloc__xml_export_state_t parentstate, hwloc_topology_t topology)
2315 {
2316 struct hwloc_internal_distances_s *dist;
2317 for(dist = topology->first_dist; dist; dist = dist->next) {
2318 char tmp[255];
2319 unsigned nbobjs = dist->nbobjs;
2320 struct hwloc__xml_export_state_s state;
2321
2322 parentstate->new_child(parentstate, &state, "distances2");
2323
2324 state.new_prop(&state, "type", hwloc_obj_type_string(dist->type));
2325 sprintf(tmp, "%u", nbobjs);
2326 state.new_prop(&state, "nbobjs", tmp);
2327 sprintf(tmp, "%lu", dist->kind);
2328 state.new_prop(&state, "kind", tmp);
2329
2330 state.new_prop(&state, "indexing",
2331 (dist->type == HWLOC_OBJ_NUMANODE || dist->type == HWLOC_OBJ_PU) ? "os" : "gp");
2332
2333 EXPORT_ARRAY(&state, unsigned long long, nbobjs, dist->indexes, "indexes", "%llu", 10);
2334 EXPORT_ARRAY(&state, unsigned long long, nbobjs*nbobjs, dist->values, "u64values", "%llu", 10);
2335 state.end_object(&state, "distances2");
2336 }
2337 }
2338
2339 void
2340 hwloc__xml_export_topology(hwloc__xml_export_state_t state, hwloc_topology_t topology, unsigned long flags)
2341 {
2342 if (flags & HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1) {
2343 hwloc__xml_v1export_object (state, topology, hwloc_get_root_obj(topology), flags);
2344 } else {
2345 hwloc__xml_v2export_object (state, topology, hwloc_get_root_obj(topology), flags);
2346 hwloc__xml_v2export_distances (state, topology);
2347 }
2348 }
2349
2350 void
2351 hwloc__xml_export_diff(hwloc__xml_export_state_t parentstate, hwloc_topology_diff_t diff)
2352 {
2353 while (diff) {
2354 struct hwloc__xml_export_state_s state;
2355 char tmp[255];
2356
2357 parentstate->new_child(parentstate, &state, "diff");
2358
2359 sprintf(tmp, "%d", (int) diff->generic.type);
2360 state.new_prop(&state, "type", tmp);
2361
2362 switch (diff->generic.type) {
2363 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR:
2364 sprintf(tmp, "%d", diff->obj_attr.obj_depth);
2365 state.new_prop(&state, "obj_depth", tmp);
2366 sprintf(tmp, "%u", diff->obj_attr.obj_index);
2367 state.new_prop(&state, "obj_index", tmp);
2368
2369 sprintf(tmp, "%d", (int) diff->obj_attr.diff.generic.type);
2370 state.new_prop(&state, "obj_attr_type", tmp);
2371
2372 switch (diff->obj_attr.diff.generic.type) {
2373 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_SIZE:
2374 sprintf(tmp, "%llu", (unsigned long long) diff->obj_attr.diff.uint64.index);
2375 state.new_prop(&state, "obj_attr_index", tmp);
2376 sprintf(tmp, "%llu", (unsigned long long) diff->obj_attr.diff.uint64.oldvalue);
2377 state.new_prop(&state, "obj_attr_oldvalue", tmp);
2378 sprintf(tmp, "%llu", (unsigned long long) diff->obj_attr.diff.uint64.newvalue);
2379 state.new_prop(&state, "obj_attr_newvalue", tmp);
2380 break;
2381 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_NAME:
2382 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO:
2383 if (diff->obj_attr.diff.string.name)
2384 state.new_prop(&state, "obj_attr_name", diff->obj_attr.diff.string.name);
2385 state.new_prop(&state, "obj_attr_oldvalue", diff->obj_attr.diff.string.oldvalue);
2386 state.new_prop(&state, "obj_attr_newvalue", diff->obj_attr.diff.string.newvalue);
2387 break;
2388 }
2389
2390 break;
2391 default:
2392 assert(0);
2393 }
2394 state.end_object(&state, "diff");
2395
2396 diff = diff->generic.next;
2397 }
2398 }
2399
2400
2401
2402
2403
2404
2405 int hwloc_topology_export_xml(hwloc_topology_t topology, const char *filename, unsigned long flags)
2406 {
2407 hwloc_localeswitch_declare;
2408 struct hwloc__xml_export_data_s edata;
2409 int force_nolibxml;
2410 int ret;
2411
2412 if (!topology->is_loaded) {
2413 errno = EINVAL;
2414 return -1;
2415 }
2416
2417 assert(hwloc_nolibxml_callbacks);
2418
2419 if (flags & ~HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1) {
2420 errno = EINVAL;
2421 return -1;
2422 }
2423
2424 hwloc_internal_distances_refresh(topology);
2425
2426 hwloc_localeswitch_init();
2427
2428 edata.v1_memory_group = NULL;
2429 if (flags & HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1)
2430
2431 edata.v1_memory_group = hwloc_alloc_setup_object(topology, HWLOC_OBJ_GROUP, HWLOC_UNKNOWN_INDEX);
2432
2433 force_nolibxml = hwloc_nolibxml_export();
2434 retry:
2435 if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml))
2436 ret = hwloc_nolibxml_callbacks->export_file(topology, &edata, filename, flags);
2437 else {
2438 ret = hwloc_libxml_callbacks->export_file(topology, &edata, filename, flags);
2439 if (ret < 0 && errno == ENOSYS) {
2440 hwloc_libxml_callbacks = NULL;
2441 goto retry;
2442 }
2443 }
2444
2445 if (edata.v1_memory_group)
2446 hwloc_free_unlinked_object(edata.v1_memory_group);
2447
2448 hwloc_localeswitch_fini();
2449 return ret;
2450 }
2451
2452
2453 int hwloc_topology_export_xmlbuffer(hwloc_topology_t topology, char **xmlbuffer, int *buflen, unsigned long flags)
2454 {
2455 hwloc_localeswitch_declare;
2456 struct hwloc__xml_export_data_s edata;
2457 int force_nolibxml;
2458 int ret;
2459
2460 if (!topology->is_loaded) {
2461 errno = EINVAL;
2462 return -1;
2463 }
2464
2465 assert(hwloc_nolibxml_callbacks);
2466
2467 if (flags & ~HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1) {
2468 errno = EINVAL;
2469 return -1;
2470 }
2471
2472 hwloc_internal_distances_refresh(topology);
2473
2474 hwloc_localeswitch_init();
2475
2476 edata.v1_memory_group = NULL;
2477 if (flags & HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1)
2478
2479 edata.v1_memory_group = hwloc_alloc_setup_object(topology, HWLOC_OBJ_GROUP, HWLOC_UNKNOWN_INDEX);
2480
2481 force_nolibxml = hwloc_nolibxml_export();
2482 retry:
2483 if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml))
2484 ret = hwloc_nolibxml_callbacks->export_buffer(topology, &edata, xmlbuffer, buflen, flags);
2485 else {
2486 ret = hwloc_libxml_callbacks->export_buffer(topology, &edata, xmlbuffer, buflen, flags);
2487 if (ret < 0 && errno == ENOSYS) {
2488 hwloc_libxml_callbacks = NULL;
2489 goto retry;
2490 }
2491 }
2492
2493 if (edata.v1_memory_group)
2494 hwloc_free_unlinked_object(edata.v1_memory_group);
2495
2496 hwloc_localeswitch_fini();
2497 return ret;
2498 }
2499
2500
2501 int
2502 hwloc_topology_diff_export_xml(hwloc_topology_diff_t diff, const char *refname,
2503 const char *filename)
2504 {
2505 hwloc_localeswitch_declare;
2506 hwloc_topology_diff_t tmpdiff;
2507 int force_nolibxml;
2508 int ret;
2509
2510 tmpdiff = diff;
2511 while (tmpdiff) {
2512 if (tmpdiff->generic.type == HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX) {
2513 errno = EINVAL;
2514 return -1;
2515 }
2516 tmpdiff = tmpdiff->generic.next;
2517 }
2518
2519 hwloc_components_init();
2520 assert(hwloc_nolibxml_callbacks);
2521
2522 hwloc_localeswitch_init();
2523
2524 force_nolibxml = hwloc_nolibxml_export();
2525 retry:
2526 if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml))
2527 ret = hwloc_nolibxml_callbacks->export_diff_file(diff, refname, filename);
2528 else {
2529 ret = hwloc_libxml_callbacks->export_diff_file(diff, refname, filename);
2530 if (ret < 0 && errno == ENOSYS) {
2531 hwloc_libxml_callbacks = NULL;
2532 goto retry;
2533 }
2534 }
2535
2536 hwloc_localeswitch_fini();
2537 hwloc_components_fini();
2538 return ret;
2539 }
2540
2541
2542 int
2543 hwloc_topology_diff_export_xmlbuffer(hwloc_topology_diff_t diff, const char *refname,
2544 char **xmlbuffer, int *buflen)
2545 {
2546 hwloc_localeswitch_declare;
2547 hwloc_topology_diff_t tmpdiff;
2548 int force_nolibxml;
2549 int ret;
2550
2551 tmpdiff = diff;
2552 while (tmpdiff) {
2553 if (tmpdiff->generic.type == HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX) {
2554 errno = EINVAL;
2555 return -1;
2556 }
2557 tmpdiff = tmpdiff->generic.next;
2558 }
2559
2560 hwloc_components_init();
2561 assert(hwloc_nolibxml_callbacks);
2562
2563 hwloc_localeswitch_init();
2564
2565 force_nolibxml = hwloc_nolibxml_export();
2566 retry:
2567 if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml))
2568 ret = hwloc_nolibxml_callbacks->export_diff_buffer(diff, refname, xmlbuffer, buflen);
2569 else {
2570 ret = hwloc_libxml_callbacks->export_diff_buffer(diff, refname, xmlbuffer, buflen);
2571 if (ret < 0 && errno == ENOSYS) {
2572 hwloc_libxml_callbacks = NULL;
2573 goto retry;
2574 }
2575 }
2576
2577 hwloc_localeswitch_fini();
2578 hwloc_components_fini();
2579 return ret;
2580 }
2581
2582 void hwloc_free_xmlbuffer(hwloc_topology_t topology __hwloc_attribute_unused, char *xmlbuffer)
2583 {
2584 int force_nolibxml;
2585
2586 assert(hwloc_nolibxml_callbacks);
2587
2588 force_nolibxml = hwloc_nolibxml_export();
2589 if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml))
2590 hwloc_nolibxml_callbacks->free_buffer(xmlbuffer);
2591 else
2592 hwloc_libxml_callbacks->free_buffer(xmlbuffer);
2593 }
2594
2595 void
2596 hwloc_topology_set_userdata_export_callback(hwloc_topology_t topology,
2597 void (*export)(void *reserved, struct hwloc_topology *topology, struct hwloc_obj *obj))
2598 {
2599 topology->userdata_export_cb = export;
2600 }
2601
2602 static void
2603 hwloc__export_obj_userdata(hwloc__xml_export_state_t parentstate, int encoded,
2604 const char *name, size_t length, const void *buffer, size_t encoded_length)
2605 {
2606 struct hwloc__xml_export_state_s state;
2607 char tmp[255];
2608 parentstate->new_child(parentstate, &state, "userdata");
2609 if (name)
2610 state.new_prop(&state, "name", name);
2611 sprintf(tmp, "%lu", (unsigned long) length);
2612 state.new_prop(&state, "length", tmp);
2613 if (encoded)
2614 state.new_prop(&state, "encoding", "base64");
2615 if (encoded_length)
2616 state.add_content(&state, buffer, encoded ? encoded_length : length);
2617 state.end_object(&state, "userdata");
2618 }
2619
2620 int
2621 hwloc_export_obj_userdata(void *reserved,
2622 struct hwloc_topology *topology, struct hwloc_obj *obj __hwloc_attribute_unused,
2623 const char *name, const void *buffer, size_t length)
2624 {
2625 hwloc__xml_export_state_t state = reserved;
2626
2627 if (!buffer) {
2628 errno = EINVAL;
2629 return -1;
2630 }
2631
2632 if ((name && hwloc__xml_export_check_buffer(name, strlen(name)) < 0)
2633 || hwloc__xml_export_check_buffer(buffer, length) < 0) {
2634 errno = EINVAL;
2635 return -1;
2636 }
2637
2638 if (topology->userdata_not_decoded) {
2639 int encoded;
2640 size_t encoded_length;
2641 const char *realname;
2642 if (!strncmp(name, "base64", 6)) {
2643 encoded = 1;
2644 encoded_length = BASE64_ENCODED_LENGTH(length);
2645 } else {
2646 assert(!strncmp(name, "normal", 6));
2647 encoded = 0;
2648 encoded_length = length;
2649 }
2650 if (name[6] == ':')
2651 realname = name+7;
2652 else {
2653 assert(!strcmp(name+6, "-anon"));
2654 realname = NULL;
2655 }
2656 hwloc__export_obj_userdata(state, encoded, realname, length, buffer, encoded_length);
2657
2658 } else
2659 hwloc__export_obj_userdata(state, 0, name, length, buffer, length);
2660
2661 return 0;
2662 }
2663
2664 int
2665 hwloc_export_obj_userdata_base64(void *reserved,
2666 struct hwloc_topology *topology __hwloc_attribute_unused, struct hwloc_obj *obj __hwloc_attribute_unused,
2667 const char *name, const void *buffer, size_t length)
2668 {
2669 hwloc__xml_export_state_t state = reserved;
2670 size_t encoded_length;
2671 char *encoded_buffer;
2672 int ret __hwloc_attribute_unused;
2673
2674 if (!buffer) {
2675 errno = EINVAL;
2676 return -1;
2677 }
2678
2679 assert(!topology->userdata_not_decoded);
2680
2681 if (name && hwloc__xml_export_check_buffer(name, strlen(name)) < 0) {
2682 errno = EINVAL;
2683 return -1;
2684 }
2685
2686 encoded_length = BASE64_ENCODED_LENGTH(length);
2687 encoded_buffer = malloc(encoded_length+1);
2688 if (!encoded_buffer) {
2689 errno = ENOMEM;
2690 return -1;
2691 }
2692
2693 ret = hwloc_encode_to_base64(buffer, length, encoded_buffer, encoded_length+1);
2694 assert(ret == (int) encoded_length);
2695
2696 hwloc__export_obj_userdata(state, 1, name, length, encoded_buffer, encoded_length);
2697
2698 free(encoded_buffer);
2699 return 0;
2700 }
2701
2702 void
2703 hwloc_topology_set_userdata_import_callback(hwloc_topology_t topology,
2704 void (*import)(struct hwloc_topology *topology, struct hwloc_obj *obj, const char *name, const void *buffer, size_t length))
2705 {
2706 topology->userdata_import_cb = import;
2707 }
2708
2709
2710
2711
2712
2713 static void
2714 hwloc_xml_backend_disable(struct hwloc_backend *backend)
2715 {
2716 struct hwloc_xml_backend_data_s *data = backend->private_data;
2717 data->backend_exit(data);
2718 free(data->msgprefix);
2719 free(data);
2720 }
2721
2722 static struct hwloc_backend *
2723 hwloc_xml_component_instantiate(struct hwloc_disc_component *component,
2724 const void *_data1,
2725 const void *_data2,
2726 const void *_data3)
2727 {
2728 struct hwloc_xml_backend_data_s *data;
2729 struct hwloc_backend *backend;
2730 const char *env;
2731 int force_nolibxml;
2732 const char * xmlpath = (const char *) _data1;
2733 const char * xmlbuffer = (const char *) _data2;
2734 int xmlbuflen = (int)(uintptr_t) _data3;
2735 const char *basename;
2736 int err;
2737
2738 assert(hwloc_nolibxml_callbacks);
2739
2740 if (!xmlpath && !xmlbuffer) {
2741 env = getenv("HWLOC_XMLFILE");
2742 if (env) {
2743
2744 xmlpath = env;
2745 } else {
2746 errno = EINVAL;
2747 goto out;
2748 }
2749 }
2750
2751 backend = hwloc_backend_alloc(component);
2752 if (!backend)
2753 goto out;
2754
2755 data = malloc(sizeof(*data));
2756 if (!data) {
2757 errno = ENOMEM;
2758 goto out_with_backend;
2759 }
2760
2761 backend->private_data = data;
2762 backend->discover = hwloc_look_xml;
2763 backend->disable = hwloc_xml_backend_disable;
2764 backend->is_thissystem = 0;
2765
2766 if (xmlpath) {
2767 basename = strrchr(xmlpath, '/');
2768 if (basename)
2769 basename++;
2770 else
2771 basename = xmlpath;
2772 } else {
2773 basename = "xmlbuffer";
2774 }
2775 data->msgprefix = strdup(basename);
2776
2777 force_nolibxml = hwloc_nolibxml_import();
2778 retry:
2779 if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml))
2780 err = hwloc_nolibxml_callbacks->backend_init(data, xmlpath, xmlbuffer, xmlbuflen);
2781 else {
2782 err = hwloc_libxml_callbacks->backend_init(data, xmlpath, xmlbuffer, xmlbuflen);
2783 if (err < 0 && errno == ENOSYS) {
2784 hwloc_libxml_callbacks = NULL;
2785 goto retry;
2786 }
2787 }
2788 if (err < 0)
2789 goto out_with_data;
2790
2791 return backend;
2792
2793 out_with_data:
2794 free(data->msgprefix);
2795 free(data);
2796 out_with_backend:
2797 free(backend);
2798 out:
2799 return NULL;
2800 }
2801
2802 static struct hwloc_disc_component hwloc_xml_disc_component = {
2803 HWLOC_DISC_COMPONENT_TYPE_GLOBAL,
2804 "xml",
2805 ~0,
2806 hwloc_xml_component_instantiate,
2807 30,
2808 1,
2809 NULL
2810 };
2811
2812 const struct hwloc_component hwloc_xml_component = {
2813 HWLOC_COMPONENT_ABI,
2814 NULL, NULL,
2815 HWLOC_COMPONENT_TYPE_DISC,
2816 0,
2817 &hwloc_xml_disc_component
2818 };