Update hwloc to v1.11.12
[charm.git] / contrib / hwloc / src / topology-xml.c
blob566cdcc4a883130c39ad2efa3797095bbb36ea8d
1 /*
2 * Copyright © 2009 CNRS
3 * Copyright © 2009-2018 Inria. All rights reserved.
4 * Copyright © 2009-2011 Université Bordeaux
5 * Copyright © 2009-2018 Cisco Systems, Inc. All rights reserved.
6 * See COPYING in top-level directory.
7 */
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>
16 int
17 hwloc__xml_verbose(void)
19 static int first = 1;
20 static int verbose = 0;
21 if (first) {
22 const char *env = getenv("HWLOC_XML_VERBOSE");
23 if (env)
24 verbose = atoi(env);
25 first = 0;
27 return verbose;
30 static int
31 hwloc_nolibxml_import(void)
33 static int first = 1;
34 static int nolibxml = 0;
35 if (first) {
36 const char *env = getenv("HWLOC_LIBXML");
37 if (env) {
38 nolibxml = !atoi(env);
39 } else {
40 env = getenv("HWLOC_LIBXML_IMPORT");
41 if (env) {
42 nolibxml = !atoi(env);
43 } else {
44 env = getenv("HWLOC_NO_LIBXML_IMPORT");
45 if (env)
46 nolibxml = atoi(env);
49 first = 0;
51 return nolibxml;
54 static int
55 hwloc_nolibxml_export(void)
57 static int first = 1;
58 static int nolibxml = 0;
59 if (first) {
60 const char *env = getenv("HWLOC_LIBXML");
61 if (env) {
62 nolibxml = !atoi(env);
63 } else {
64 env = getenv("HWLOC_LIBXML_EXPORT");
65 if (env) {
66 nolibxml = !atoi(env);
67 } else {
68 env = getenv("HWLOC_NO_LIBXML_EXPORT");
69 if (env)
70 nolibxml = atoi(env);
73 first = 0;
75 return nolibxml;
78 #define BASE64_ENCODED_LENGTH(length) (4*(((length)+2)/3))
80 /*********************************
81 ********* XML callbacks *********
82 *********************************/
84 /* set when registering nolibxml and libxml components.
85 * modifications protected by the components mutex.
86 * read by the common XML code in topology-xml.c to jump to the right XML backend.
88 static struct hwloc_xml_callbacks *hwloc_nolibxml_callbacks = NULL, *hwloc_libxml_callbacks = NULL;
90 void
91 hwloc_xml_callbacks_register(struct hwloc_xml_component *comp)
93 if (!hwloc_nolibxml_callbacks)
94 hwloc_nolibxml_callbacks = comp->nolibxml_callbacks;
95 if (!hwloc_libxml_callbacks)
96 hwloc_libxml_callbacks = comp->libxml_callbacks;
99 void
100 hwloc_xml_callbacks_reset(void)
102 hwloc_nolibxml_callbacks = NULL;
103 hwloc_libxml_callbacks = NULL;
106 /************************************************
107 ********* XML import (common routines) *********
108 ************************************************/
110 static void
111 hwloc__xml_import_object_attr(struct hwloc_topology *topology __hwloc_attribute_unused, struct hwloc_obj *obj,
112 const char *name, const char *value,
113 hwloc__xml_import_state_t state)
115 if (!strcmp(name, "type")) {
116 /* already handled */
117 return;
120 else if (!strcmp(name, "os_level"))
121 obj->os_level = strtoul(value, NULL, 10);
122 else if (!strcmp(name, "os_index"))
123 obj->os_index = strtoul(value, NULL, 10);
124 else if (!strcmp(name, "cpuset")) {
125 obj->cpuset = hwloc_bitmap_alloc();
126 hwloc_bitmap_sscanf(obj->cpuset, value);
127 } else if (!strcmp(name, "complete_cpuset")) {
128 obj->complete_cpuset = hwloc_bitmap_alloc();
129 hwloc_bitmap_sscanf(obj->complete_cpuset,value);
130 } else if (!strcmp(name, "online_cpuset")) {
131 obj->online_cpuset = hwloc_bitmap_alloc();
132 hwloc_bitmap_sscanf(obj->online_cpuset, value);
133 } else if (!strcmp(name, "allowed_cpuset")) {
134 obj->allowed_cpuset = hwloc_bitmap_alloc();
135 hwloc_bitmap_sscanf(obj->allowed_cpuset, value);
136 } else if (!strcmp(name, "nodeset")) {
137 obj->nodeset = hwloc_bitmap_alloc();
138 hwloc_bitmap_sscanf(obj->nodeset, value);
139 } else if (!strcmp(name, "complete_nodeset")) {
140 obj->complete_nodeset = hwloc_bitmap_alloc();
141 hwloc_bitmap_sscanf(obj->complete_nodeset, value);
142 } else if (!strcmp(name, "allowed_nodeset")) {
143 obj->allowed_nodeset = hwloc_bitmap_alloc();
144 hwloc_bitmap_sscanf(obj->allowed_nodeset, value);
145 } else if (!strcmp(name, "name"))
146 obj->name = strdup(value);
148 else if (!strcmp(name, "cache_size")) {
149 unsigned long long lvalue = strtoull(value, NULL, 10);
150 if (obj->type == HWLOC_OBJ_CACHE)
151 obj->attr->cache.size = lvalue;
152 else if (hwloc__xml_verbose())
153 fprintf(stderr, "%s: ignoring cache_size attribute for non-cache object type\n",
154 state->global->msgprefix);
157 else if (!strcmp(name, "cache_linesize")) {
158 unsigned long lvalue = strtoul(value, NULL, 10);
159 if (obj->type == HWLOC_OBJ_CACHE)
160 obj->attr->cache.linesize = lvalue;
161 else if (hwloc__xml_verbose())
162 fprintf(stderr, "%s: ignoring cache_linesize attribute for non-cache object type\n",
163 state->global->msgprefix);
166 else if (!strcmp(name, "cache_associativity")) {
167 int lvalue = atoi(value);
168 if (obj->type == HWLOC_OBJ_CACHE)
169 obj->attr->cache.associativity = lvalue;
170 else if (hwloc__xml_verbose())
171 fprintf(stderr, "%s: ignoring cache_associativity attribute for non-cache object type\n",
172 state->global->msgprefix);
175 else if (!strcmp(name, "cache_type")) {
176 unsigned long lvalue = strtoul(value, NULL, 10);
177 if (obj->type == HWLOC_OBJ_CACHE) {
178 if (lvalue == HWLOC_OBJ_CACHE_UNIFIED
179 || lvalue == HWLOC_OBJ_CACHE_DATA
180 || lvalue == HWLOC_OBJ_CACHE_INSTRUCTION)
181 obj->attr->cache.type = (hwloc_obj_cache_type_t) lvalue;
182 else
183 fprintf(stderr, "%s: ignoring invalid cache_type attribute %lu\n",
184 state->global->msgprefix, lvalue);
185 } else if (hwloc__xml_verbose())
186 fprintf(stderr, "%s: ignoring cache_type attribute for non-cache object type\n",
187 state->global->msgprefix);
190 else if (!strcmp(name, "local_memory"))
191 obj->memory.local_memory = strtoull(value, NULL, 10);
193 else if (!strcmp(name, "depth")) {
194 unsigned long lvalue = strtoul(value, NULL, 10);
195 switch (obj->type) {
196 case HWLOC_OBJ_CACHE:
197 obj->attr->cache.depth = lvalue;
198 break;
199 case HWLOC_OBJ_GROUP:
200 obj->attr->group.depth = lvalue;
201 break;
202 case HWLOC_OBJ_BRIDGE:
203 obj->attr->bridge.depth = lvalue;
204 break;
205 default:
206 if (hwloc__xml_verbose())
207 fprintf(stderr, "%s: ignoring depth attribute for object type without depth\n",
208 state->global->msgprefix);
209 break;
213 else if (!strcmp(name, "pci_busid")) {
214 switch (obj->type) {
215 case HWLOC_OBJ_PCI_DEVICE:
216 case HWLOC_OBJ_BRIDGE: {
217 unsigned domain, bus, dev, func;
218 if (sscanf(value, "%04x:%02x:%02x.%01x",
219 &domain, &bus, &dev, &func) != 4) {
220 if (hwloc__xml_verbose())
221 fprintf(stderr, "%s: ignoring invalid pci_busid format string %s\n",
222 state->global->msgprefix, value);
223 } else {
224 obj->attr->pcidev.domain = domain;
225 obj->attr->pcidev.bus = bus;
226 obj->attr->pcidev.dev = dev;
227 obj->attr->pcidev.func = func;
229 break;
231 default:
232 if (hwloc__xml_verbose())
233 fprintf(stderr, "%s: ignoring pci_busid attribute for non-PCI object\n",
234 state->global->msgprefix);
235 break;
239 else if (!strcmp(name, "pci_type")) {
240 switch (obj->type) {
241 case HWLOC_OBJ_PCI_DEVICE:
242 case HWLOC_OBJ_BRIDGE: {
243 unsigned classid, vendor, device, subvendor, subdevice, revision;
244 if (sscanf(value, "%04x [%04x:%04x] [%04x:%04x] %02x",
245 &classid, &vendor, &device, &subvendor, &subdevice, &revision) != 6) {
246 if (hwloc__xml_verbose())
247 fprintf(stderr, "%s: ignoring invalid pci_type format string %s\n",
248 state->global->msgprefix, value);
249 } else {
250 obj->attr->pcidev.class_id = classid;
251 obj->attr->pcidev.vendor_id = vendor;
252 obj->attr->pcidev.device_id = device;
253 obj->attr->pcidev.subvendor_id = subvendor;
254 obj->attr->pcidev.subdevice_id = subdevice;
255 obj->attr->pcidev.revision = revision;
257 break;
259 default:
260 if (hwloc__xml_verbose())
261 fprintf(stderr, "%s: ignoring pci_type attribute for non-PCI object\n",
262 state->global->msgprefix);
263 break;
267 else if (!strcmp(name, "pci_link_speed")) {
268 switch (obj->type) {
269 case HWLOC_OBJ_PCI_DEVICE:
270 case HWLOC_OBJ_BRIDGE: {
271 obj->attr->pcidev.linkspeed = (float) atof(value);
272 break;
274 default:
275 if (hwloc__xml_verbose())
276 fprintf(stderr, "%s: ignoring pci_link_speed attribute for non-PCI object\n",
277 state->global->msgprefix);
278 break;
282 else if (!strcmp(name, "bridge_type")) {
283 switch (obj->type) {
284 case HWLOC_OBJ_BRIDGE: {
285 unsigned upstream_type, downstream_type;
286 if (sscanf(value, "%u-%u", &upstream_type, &downstream_type) != 2) {
287 if (hwloc__xml_verbose())
288 fprintf(stderr, "%s: ignoring invalid bridge_type format string %s\n",
289 state->global->msgprefix, value);
290 } else {
291 obj->attr->bridge.upstream_type = (hwloc_obj_bridge_type_t) upstream_type;
292 obj->attr->bridge.downstream_type = (hwloc_obj_bridge_type_t) downstream_type;
294 break;
296 default:
297 if (hwloc__xml_verbose())
298 fprintf(stderr, "%s: ignoring bridge_type attribute for non-bridge object\n",
299 state->global->msgprefix);
300 break;
304 else if (!strcmp(name, "bridge_pci")) {
305 switch (obj->type) {
306 case HWLOC_OBJ_BRIDGE: {
307 unsigned domain, secbus, subbus;
308 if (sscanf(value, "%04x:[%02x-%02x]",
309 &domain, &secbus, &subbus) != 3) {
310 if (hwloc__xml_verbose())
311 fprintf(stderr, "%s: ignoring invalid bridge_pci format string %s\n",
312 state->global->msgprefix, value);
313 } else {
314 obj->attr->bridge.downstream.pci.domain = domain;
315 obj->attr->bridge.downstream.pci.secondary_bus = secbus;
316 obj->attr->bridge.downstream.pci.subordinate_bus = subbus;
318 break;
320 default:
321 if (hwloc__xml_verbose())
322 fprintf(stderr, "%s: ignoring bridge_pci attribute for non-bridge object\n",
323 state->global->msgprefix);
324 break;
328 else if (!strcmp(name, "osdev_type")) {
329 switch (obj->type) {
330 case HWLOC_OBJ_OS_DEVICE: {
331 unsigned osdev_type;
332 if (sscanf(value, "%u", &osdev_type) != 1) {
333 if (hwloc__xml_verbose())
334 fprintf(stderr, "%s: ignoring invalid osdev_type format string %s\n",
335 state->global->msgprefix, value);
336 } else
337 obj->attr->osdev.type = (hwloc_obj_osdev_type_t) osdev_type;
338 break;
340 default:
341 if (hwloc__xml_verbose())
342 fprintf(stderr, "%s: ignoring osdev_type attribute for non-osdev object\n",
343 state->global->msgprefix);
344 break;
348 /**************************
349 * forward compat with 2.0
351 else if (!strcmp(name, "kind") || !strcmp(name, "subkind")) {
352 if (obj->type == HWLOC_OBJ_GROUP) {
353 /* ignored, unused in <2.0 */
354 } else {
355 if (hwloc__xml_verbose())
356 fprintf(stderr, "%s: ignoring %s attribute for non-group object\n",
357 state->global->msgprefix, name);
360 else if (!strcmp(name, "subtype")) {
361 hwloc_obj_add_info(obj, "Type", value);
362 /* will be changed into CoProcType in the caller once we have osdev.type too */
364 else if (!strcmp(name, "gp_index")) {
365 /* doesn't exist in v1.x */
369 /*************************
370 * deprecated (from 1.0)
372 else if (!strcmp(name, "dmi_board_vendor")) {
373 hwloc_obj_add_info(obj, "DMIBoardVendor", value);
375 else if (!strcmp(name, "dmi_board_name")) {
376 hwloc_obj_add_info(obj, "DMIBoardName", value);
379 /*************************
380 * deprecated (from 0.9)
382 else if (!strcmp(name, "memory_kB")) {
383 unsigned long long lvalue = strtoull(value, NULL, 10);
384 switch (obj->type) {
385 case HWLOC_OBJ_CACHE:
386 obj->attr->cache.size = lvalue << 10;
387 break;
388 case HWLOC_OBJ_NUMANODE:
389 case HWLOC_OBJ_MACHINE:
390 case HWLOC_OBJ_SYSTEM:
391 obj->memory.local_memory = lvalue << 10;
392 break;
393 default:
394 if (hwloc__xml_verbose())
395 fprintf(stderr, "%s: ignoring memory_kB attribute for object type without memory\n",
396 state->global->msgprefix);
397 break;
400 else if (!strcmp(name, "huge_page_size_kB")) {
401 unsigned long lvalue = strtoul(value, NULL, 10);
402 switch (obj->type) {
403 case HWLOC_OBJ_NUMANODE:
404 case HWLOC_OBJ_MACHINE:
405 case HWLOC_OBJ_SYSTEM:
406 if (!obj->memory.page_types) {
407 obj->memory.page_types = malloc(sizeof(*obj->memory.page_types));
408 obj->memory.page_types_len = 1;
410 obj->memory.page_types[0].size = lvalue << 10;
411 break;
412 default:
413 if (hwloc__xml_verbose())
414 fprintf(stderr, "%s: ignoring huge_page_size_kB attribute for object type without huge pages\n",
415 state->global->msgprefix);
416 break;
419 else if (!strcmp(name, "huge_page_free")) {
420 unsigned long lvalue = strtoul(value, NULL, 10);
421 switch (obj->type) {
422 case HWLOC_OBJ_NUMANODE:
423 case HWLOC_OBJ_MACHINE:
424 case HWLOC_OBJ_SYSTEM:
425 if (!obj->memory.page_types) {
426 obj->memory.page_types = malloc(sizeof(*obj->memory.page_types));
427 obj->memory.page_types_len = 1;
429 obj->memory.page_types[0].count = lvalue;
430 break;
431 default:
432 if (hwloc__xml_verbose())
433 fprintf(stderr, "%s: ignoring huge_page_free attribute for object type without huge pages\n",
434 state->global->msgprefix);
435 break;
439 * end of deprecated (from 0.9)
440 *******************************/
444 else if (hwloc__xml_verbose())
445 fprintf(stderr, "%s: ignoring unknown object attribute %s\n",
446 state->global->msgprefix, name);
450 static int
451 hwloc__xml_import_info(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj,
452 hwloc__xml_import_state_t state)
454 char *infoname = NULL;
455 char *infovalue = NULL;
457 while (1) {
458 char *attrname, *attrvalue;
459 if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
460 break;
461 if (!strcmp(attrname, "name"))
462 infoname = attrvalue;
463 else if (!strcmp(attrname, "value"))
464 infovalue = attrvalue;
465 else
466 return -1;
469 if (infoname)
470 /* empty strings are ignored by libxml */
471 hwloc_obj_add_info(obj, infoname, infovalue ? infovalue : "");
473 return state->global->close_tag(state);
476 static int
477 hwloc__xml_import_pagetype(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj,
478 hwloc__xml_import_state_t state)
480 uint64_t size = 0, count = 0;
482 while (1) {
483 char *attrname, *attrvalue;
484 if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
485 break;
486 if (!strcmp(attrname, "size"))
487 size = strtoull(attrvalue, NULL, 10);
488 else if (!strcmp(attrname, "count"))
489 count = strtoull(attrvalue, NULL, 10);
490 else
491 return -1;
494 if (size) {
495 int idx = obj->memory.page_types_len;
496 struct hwloc_obj_memory_page_type_s *tmp;
497 tmp = realloc(obj->memory.page_types, (idx+1)*sizeof(*obj->memory.page_types));
498 if (tmp) { /* if failed to allocate, ignore this page_type entry */
499 obj->memory.page_types = tmp;
500 obj->memory.page_types_len = idx+1;
501 obj->memory.page_types[idx].size = size;
502 obj->memory.page_types[idx].count = count;
506 return state->global->close_tag(state);
509 static int
510 hwloc__xml_import_distances(struct hwloc_xml_backend_data_s *data,
511 hwloc_obj_t obj,
512 hwloc__xml_import_state_t state)
514 unsigned long reldepth = 0, nbobjs = 0;
515 float latbase = 0;
516 char *tag;
517 int ret;
519 while (1) {
520 char *attrname, *attrvalue;
521 if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
522 break;
523 if (!strcmp(attrname, "nbobjs"))
524 nbobjs = strtoul(attrvalue, NULL, 10);
525 else if (!strcmp(attrname, "relative_depth"))
526 reldepth = strtoul(attrvalue, NULL, 10);
527 else if (!strcmp(attrname, "latency_base"))
528 latbase = (float) atof(attrvalue);
529 else
530 return -1;
533 if (nbobjs && reldepth && latbase) {
534 unsigned i;
535 float *matrix, latmax = 0;
536 struct hwloc_xml_imported_distances_s *distances;
538 matrix = malloc(nbobjs*nbobjs*sizeof(float));
539 distances = malloc(sizeof(*distances));
540 if (!matrix || !distances) {
541 if (hwloc__xml_verbose())
542 fprintf(stderr, "%s: failed to allocate distance matrix for %lu objects\n",
543 state->global->msgprefix, nbobjs);
544 free(distances);
545 free(matrix);
546 return -1;
549 distances->root = obj;
550 distances->distances.relative_depth = reldepth;
551 distances->distances.nbobjs = nbobjs;
552 distances->distances.latency = matrix;
553 distances->distances.latency_base = latbase;
555 for(i=0; i<nbobjs*nbobjs; i++) {
556 struct hwloc__xml_import_state_s childstate;
557 char *attrname, *attrvalue;
558 float val;
560 ret = state->global->find_child(state, &childstate, &tag);
561 if (ret <= 0 || strcmp(tag, "latency")) {
562 /* a latency child is needed */
563 free(distances->distances.latency);
564 free(distances);
565 return -1;
568 ret = state->global->next_attr(&childstate, &attrname, &attrvalue);
569 if (ret < 0 || strcmp(attrname, "value")) {
570 free(distances->distances.latency);
571 free(distances);
572 return -1;
575 val = (float) atof((char *) attrvalue);
576 matrix[i] = val;
577 if (val > latmax)
578 latmax = val;
580 ret = state->global->close_tag(&childstate);
581 if (ret < 0) {
582 free(distances->distances.latency);
583 free(distances);
584 return -1;
587 state->global->close_child(&childstate);
590 distances->distances.latency_max = latmax;
592 if (nbobjs < 2) {
593 /* distances with a single object are useless, even if the XML isn't invalid */
594 assert(nbobjs == 1);
595 if (hwloc__xml_verbose())
596 fprintf(stderr, "%s: ignoring invalid distance matrix with only 1 object\n",
597 state->global->msgprefix);
598 free(matrix);
599 free(distances);
600 } else {
601 /* queue the distance */
602 distances->prev = data->last_distances;
603 distances->next = NULL;
604 if (data->last_distances)
605 data->last_distances->next = distances;
606 else
607 data->first_distances = distances;
608 data->last_distances = distances;
612 return state->global->close_tag(state);
615 static int
616 hwloc__xml_import_userdata(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_obj_t obj,
617 hwloc__xml_import_state_t state)
619 size_t length = 0;
620 int encoded = 0;
621 char *name = NULL; /* optional */
622 int ret;
624 while (1) {
625 char *attrname, *attrvalue;
626 if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
627 break;
628 if (!strcmp(attrname, "length"))
629 length = strtoul(attrvalue, NULL, 10);
630 else if (!strcmp(attrname, "encoding"))
631 encoded = !strcmp(attrvalue, "base64");
632 else if (!strcmp(attrname, "name"))
633 name = attrvalue;
634 else
635 return -1;
638 if (!topology->userdata_import_cb) {
639 char *buffer;
640 size_t reallength = encoded ? BASE64_ENCODED_LENGTH(length) : length;
641 ret = state->global->get_content(state, &buffer, reallength);
642 if (ret < 0)
643 return -1;
645 } else if (topology->userdata_not_decoded) {
646 char *buffer, *fakename;
647 size_t reallength = encoded ? BASE64_ENCODED_LENGTH(length) : length;
648 ret = state->global->get_content(state, &buffer, reallength);
649 if (ret < 0)
650 return -1;
651 fakename = malloc(6 + 1 + (name ? strlen(name) : 4) + 1);
652 if (!fakename)
653 return -1;
654 sprintf(fakename, encoded ? "base64%c%s" : "normal%c%s", name ? ':' : '-', name ? name : "anon");
655 topology->userdata_import_cb(topology, obj, fakename, buffer, length);
656 free(fakename);
658 } else if (encoded && length) {
659 char *encoded_buffer;
660 size_t encoded_length = BASE64_ENCODED_LENGTH(length);
661 ret = state->global->get_content(state, &encoded_buffer, encoded_length);
662 if (ret < 0)
663 return -1;
664 if (ret) {
665 char *decoded_buffer = malloc(length+1);
666 if (!decoded_buffer)
667 return -1;
668 assert(encoded_buffer[encoded_length] == 0);
669 ret = hwloc_decode_from_base64(encoded_buffer, decoded_buffer, length+1);
670 if (ret != (int) length) {
671 free(decoded_buffer);
672 return -1;
674 topology->userdata_import_cb(topology, obj, name, decoded_buffer, length);
675 free(decoded_buffer);
678 } else { /* always handle length==0 in the non-encoded case */
679 char *buffer = (char *) "";
680 if (length) {
681 ret = state->global->get_content(state, &buffer, length);
682 if (ret < 0)
683 return -1;
685 topology->userdata_import_cb(topology, obj, name, buffer, length);
688 state->global->close_content(state);
689 return state->global->close_tag(state);
692 static int
693 hwloc__xml_import_object(hwloc_topology_t topology,
694 struct hwloc_xml_backend_data_s *data,
695 hwloc_obj_t obj,
696 hwloc__xml_import_state_t state)
698 hwloc_obj_t parent = obj->parent;
700 /* process attributes */
701 while (1) {
702 char *attrname, *attrvalue;
703 if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
704 break;
705 if (!strcmp(attrname, "type")) {
706 if (hwloc_obj_type_sscanf(attrvalue, &obj->type, NULL, NULL, 0) < 0)
707 goto error_with_object;
708 } else {
709 /* type needed first */
710 if (obj->type == (hwloc_obj_type_t)-1)
711 goto error_with_object;
712 hwloc__xml_import_object_attr(topology, obj, attrname, attrvalue, state);
716 /* obj->subtype is imported as "CoProcType" instead of "Type" for osdev/coproc.
717 * Cannot properly import earlier because osdev.type is imported after subtype.
718 * Don't do it later so that the actual infos array isn't imported yet,
719 * there's likely only "Type" in obj->infos[].
721 if (obj->type == HWLOC_OBJ_OS_DEVICE && obj->attr->osdev.type == HWLOC_OBJ_OSDEV_COPROC) {
722 unsigned i;
723 for(i=0; i<obj->infos_count; i++)
724 if (!strcmp(obj->infos[i].name, "Type")) {
725 /* HACK: we're not supposed to modify infos[].name from here */
726 free(obj->infos[i].name);
727 obj->infos[i].name = strdup("CoProcType");
731 if (parent) {
732 /* root->parent is NULL, and root is already inserted */
734 /* warn if inserting out-of-order */
735 if (parent->cpuset) { /* don't compare children if multinode parent */
736 hwloc_obj_t *current;
737 for (current = &parent->first_child; *current; current = &(*current)->next_sibling) {
738 hwloc_bitmap_t curcpuset = (*current)->cpuset;
739 if (obj->cpuset && (!curcpuset || hwloc__object_cpusets_compare_first(obj, *current) < 0)) {
740 static int reported = 0;
741 if (!reported && !hwloc_hide_errors()) {
742 char *progname = hwloc_progname(topology);
743 const char *origversion = hwloc_obj_get_info_by_name(topology->levels[0][0], "hwlocVersion");
744 const char *origprogname = hwloc_obj_get_info_by_name(topology->levels[0][0], "ProcessName");
745 char *c1, *cc1, t1[64];
746 char *c2 = NULL, *cc2 = NULL, t2[64];
747 hwloc_bitmap_asprintf(&c1, obj->cpuset);
748 hwloc_bitmap_asprintf(&cc1, obj->complete_cpuset);
749 hwloc_obj_type_snprintf(t1, sizeof(t1), obj, 0);
750 if (curcpuset)
751 hwloc_bitmap_asprintf(&c2, curcpuset);
752 if ((*current)->complete_cpuset)
753 hwloc_bitmap_asprintf(&cc2, (*current)->complete_cpuset);
754 hwloc_obj_type_snprintf(t2, sizeof(t2), *current, 0);
755 fprintf(stderr, "****************************************************************************\n");
756 fprintf(stderr, "* hwloc has encountered an out-of-order XML topology load.\n");
757 fprintf(stderr, "* Object %s cpuset %s complete %s\n",
758 t1, c1, cc1);
759 fprintf(stderr, "* was inserted after object %s with %s and %s.\n",
760 t2, c2 ? c2 : "none", cc2 ? cc2 : "none");
761 fprintf(stderr, "* The error occured in hwloc %s inside process `%s', while\n",
762 HWLOC_VERSION,
763 progname ? progname : "<unknown>");
764 if (origversion || origprogname)
765 fprintf(stderr, "* the input XML was generated by hwloc %s inside process `%s'.\n",
766 origversion ? origversion : "(unknown version)",
767 origprogname ? origprogname : "<unknown>");
768 else
769 fprintf(stderr, "* the input XML was generated by an unspecified ancient hwloc release.\n");
770 fprintf(stderr, "* Please check that your input topology XML file is valid.\n");
771 fprintf(stderr, "****************************************************************************\n");
772 free(c1);
773 free(cc1);
774 if (c2)
775 free(c2);
776 if (cc2)
777 free(cc2);
778 free(progname);
779 reported = 1;
785 hwloc_insert_object_by_parent(topology, obj->parent /* filled by the caller */, obj);
786 /* insert_object_by_parent() doesn't merge during insert, so obj is still valid */
789 /* process subnodes */
790 while (1) {
791 struct hwloc__xml_import_state_s childstate;
792 char *tag;
793 int ret;
795 ret = state->global->find_child(state, &childstate, &tag);
796 if (ret < 0)
797 goto error;
798 if (!ret)
799 break;
801 if (!strcmp(tag, "object")) {
802 hwloc_obj_t childobj = hwloc_alloc_setup_object(HWLOC_OBJ_TYPE_MAX, -1);
803 childobj->parent = obj; /* store the parent pointer for use in insert() below */
804 ret = hwloc__xml_import_object(topology, data, childobj, &childstate);
805 } else if (!strcmp(tag, "page_type")) {
806 ret = hwloc__xml_import_pagetype(topology, obj, &childstate);
807 } else if (!strcmp(tag, "info")) {
808 ret = hwloc__xml_import_info(topology, obj, &childstate);
809 } else if (!strcmp(tag, "distances")) {
810 ret = hwloc__xml_import_distances(data, obj, &childstate);
811 } else if (!strcmp(tag, "userdata")) {
812 ret = hwloc__xml_import_userdata(topology, obj, &childstate);
813 } else {
814 if (hwloc__xml_verbose())
815 fprintf(stderr, "%s: invalid special object child %s\n",
816 state->global->msgprefix, tag);
817 ret = -1;
820 if (ret < 0)
821 goto error;
823 state->global->close_child(&childstate);
826 return state->global->close_tag(state);
828 error_with_object:
829 if (parent)
830 /* root->parent is NULL, and root is already inserted. the caller will cleanup that root. */
831 hwloc_free_unlinked_object(obj);
832 error:
833 return -1;
836 static int
837 hwloc__xml_import_diff_one(hwloc__xml_import_state_t state,
838 hwloc_topology_diff_t *firstdiffp,
839 hwloc_topology_diff_t *lastdiffp)
841 char *type_s = NULL;
842 char *obj_depth_s = NULL;
843 char *obj_index_s = NULL;
844 char *obj_attr_type_s = NULL;
845 /* char *obj_attr_index_s = NULL; unused for now */
846 char *obj_attr_name_s = NULL;
847 char *obj_attr_oldvalue_s = NULL;
848 char *obj_attr_newvalue_s = NULL;
850 while (1) {
851 char *attrname, *attrvalue;
852 if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
853 break;
854 if (!strcmp(attrname, "type"))
855 type_s = attrvalue;
856 else if (!strcmp(attrname, "obj_depth"))
857 obj_depth_s = attrvalue;
858 else if (!strcmp(attrname, "obj_index"))
859 obj_index_s = attrvalue;
860 else if (!strcmp(attrname, "obj_attr_type"))
861 obj_attr_type_s = attrvalue;
862 else if (!strcmp(attrname, "obj_attr_index"))
863 { /* obj_attr_index_s = attrvalue; unused for now */ }
864 else if (!strcmp(attrname, "obj_attr_name"))
865 obj_attr_name_s = attrvalue;
866 else if (!strcmp(attrname, "obj_attr_oldvalue"))
867 obj_attr_oldvalue_s = attrvalue;
868 else if (!strcmp(attrname, "obj_attr_newvalue"))
869 obj_attr_newvalue_s = attrvalue;
870 else {
871 if (hwloc__xml_verbose())
872 fprintf(stderr, "%s: ignoring unknown diff attribute %s\n",
873 state->global->msgprefix, attrname);
874 return -1;
878 if (type_s) {
879 switch (atoi(type_s)) {
880 default:
881 break;
882 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR: {
883 /* object attribute diff */
884 hwloc_topology_diff_obj_attr_type_t obj_attr_type;
885 hwloc_topology_diff_t diff;
887 /* obj_attr mandatory generic attributes */
888 if (!obj_depth_s || !obj_index_s || !obj_attr_type_s) {
889 if (hwloc__xml_verbose())
890 fprintf(stderr, "%s: missing mandatory obj attr generic attributes\n",
891 state->global->msgprefix);
892 break;
895 /* obj_attr mandatory attributes common to all subtypes */
896 if (!obj_attr_oldvalue_s || !obj_attr_newvalue_s) {
897 if (hwloc__xml_verbose())
898 fprintf(stderr, "%s: missing mandatory obj attr value attributes\n",
899 state->global->msgprefix);
900 break;
903 /* mandatory attributes for obj_attr_info subtype */
904 obj_attr_type = atoi(obj_attr_type_s);
905 if (obj_attr_type == HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO && !obj_attr_name_s) {
906 if (hwloc__xml_verbose())
907 fprintf(stderr, "%s: missing mandatory obj attr info name attribute\n",
908 state->global->msgprefix);
909 break;
912 /* now we know we have everything we need */
913 diff = malloc(sizeof(*diff));
914 if (!diff)
915 return -1;
916 diff->obj_attr.type = HWLOC_TOPOLOGY_DIFF_OBJ_ATTR;
917 diff->obj_attr.obj_depth = atoi(obj_depth_s);
918 diff->obj_attr.obj_index = atoi(obj_index_s);
919 memset(&diff->obj_attr.diff, 0, sizeof(diff->obj_attr.diff));
920 diff->obj_attr.diff.generic.type = obj_attr_type;
922 switch (atoi(obj_attr_type_s)) {
923 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_SIZE:
924 diff->obj_attr.diff.uint64.oldvalue = strtoull(obj_attr_oldvalue_s, NULL, 0);
925 diff->obj_attr.diff.uint64.newvalue = strtoull(obj_attr_newvalue_s, NULL, 0);
926 break;
927 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO:
928 diff->obj_attr.diff.string.name = strdup(obj_attr_name_s);
929 /* FALLTHRU */
930 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_NAME:
931 diff->obj_attr.diff.string.oldvalue = strdup(obj_attr_oldvalue_s);
932 diff->obj_attr.diff.string.newvalue = strdup(obj_attr_newvalue_s);
933 break;
936 if (*firstdiffp)
937 (*lastdiffp)->generic.next = diff;
938 else
939 *firstdiffp = diff;
940 *lastdiffp = diff;
941 diff->generic.next = NULL;
946 return state->global->close_tag(state);
950 hwloc__xml_import_diff(hwloc__xml_import_state_t state,
951 hwloc_topology_diff_t *firstdiffp)
953 hwloc_topology_diff_t firstdiff = NULL, lastdiff = NULL;
954 *firstdiffp = NULL;
956 while (1) {
957 struct hwloc__xml_import_state_s childstate;
958 char *tag;
959 int ret;
961 ret = state->global->find_child(state, &childstate, &tag);
962 if (ret < 0)
963 return -1;
964 if (!ret)
965 break;
967 if (!strcmp(tag, "diff")) {
968 ret = hwloc__xml_import_diff_one(&childstate, &firstdiff, &lastdiff);
969 } else
970 ret = -1;
972 if (ret < 0)
973 return ret;
975 state->global->close_child(&childstate);
978 *firstdiffp = firstdiff;
979 return 0;
982 /***********************************
983 ********* main XML import *********
984 ***********************************/
986 static void
987 hwloc_xml__free_distances(struct hwloc_xml_backend_data_s *data)
989 struct hwloc_xml_imported_distances_s *xmldist;
990 while ((xmldist = data->first_distances) != NULL) {
991 data->first_distances = xmldist->next;
992 free(xmldist->distances.latency);
993 free(xmldist);
997 static int
998 hwloc_xml__handle_distances(struct hwloc_topology *topology,
999 struct hwloc_xml_backend_data_s *data,
1000 const char *msgprefix)
1002 struct hwloc_xml_imported_distances_s *xmldist;
1004 /* connect things now because we need levels to check/build, they'll be reconnected properly later anyway */
1005 hwloc_connect_children(topology->levels[0][0]);
1006 if (hwloc_connect_levels(topology) < 0) {
1007 hwloc_xml__free_distances(data);
1008 return -1;
1011 while ((xmldist = data->first_distances) != NULL) {
1012 hwloc_obj_t root = xmldist->root;
1013 unsigned depth = root->depth + xmldist->distances.relative_depth;
1014 unsigned nbobjs = xmldist->distances.nbobjs, j;
1015 unsigned *indexes = malloc(nbobjs * sizeof(unsigned));
1016 hwloc_obj_t child, *objs = malloc(nbobjs * sizeof(hwloc_obj_t));
1018 data->first_distances = xmldist->next;
1019 j = 0;
1020 child = NULL;
1021 /* we can't use hwloc_get_next_obj_inside_cpuset_by_depth() because it ignore CPU-less objects */
1022 while ((child = hwloc_get_next_obj_by_depth(topology, depth, child)) != NULL) {
1023 hwloc_obj_t myparent = child->parent;
1024 while (myparent->depth > root->depth)
1025 myparent = myparent->parent;
1026 if (myparent == root) {
1027 if (j == nbobjs)
1028 goto badnbobjs;
1029 indexes[j] = child->os_index;
1030 objs[j] = child;
1031 j++;
1035 if (j < nbobjs)
1036 goto badnbobjs;
1038 /* distances valid, add it to the internal OS distances list for grouping */
1039 for(j=0; j<nbobjs*nbobjs; j++)
1040 xmldist->distances.latency[j] *= xmldist->distances.latency_base;
1041 hwloc_distances_set(topology, objs[0]->type, nbobjs, indexes, objs, xmldist->distances.latency, 0 /* XML cannot force */);
1042 free(xmldist);
1043 continue;
1045 badnbobjs:
1046 printf("bad nbobjs\n");
1047 if (hwloc__xml_verbose())
1048 fprintf(stderr, "%s: ignoring invalid distance matrix, there aren't exactly %u objects below root\n",
1049 msgprefix, nbobjs);
1050 free(indexes);
1051 free(objs);
1052 free(xmldist->distances.latency);
1053 free(xmldist);
1056 return 0;
1059 /* this canNOT be the first XML call */
1060 static int
1061 hwloc_look_xml(struct hwloc_backend *backend)
1063 struct hwloc_topology *topology = backend->topology;
1064 struct hwloc_xml_backend_data_s *data = backend->private_data;
1065 struct hwloc__xml_import_state_s state, childstate;
1066 char *tag;
1067 hwloc_localeswitch_declare;
1068 int ret;
1070 state.global = data;
1072 assert(!topology->levels[0][0]->cpuset);
1074 hwloc_localeswitch_init();
1076 data->first_distances = data->last_distances = NULL;
1078 ret = data->look_init(data, &state);
1079 if (ret < 0)
1080 goto failed;
1082 /* find root object tag and import it */
1083 ret = state.global->find_child(&state, &childstate, &tag);
1084 if (ret < 0 || !ret || strcmp(tag, "object"))
1085 goto failed;
1086 ret = hwloc__xml_import_object(topology, data, topology->levels[0][0], &childstate);
1087 if (ret < 0)
1088 goto failed;
1089 state.global->close_child(&childstate);
1091 /* find end of topology tag */
1092 state.global->close_tag(&state);
1094 /* keep the "Backend" information intact */
1095 /* we could add "BackendSource=XML" to notify that XML was used between the actual backend and here */
1097 /* if we added some distances, we must check them, and make them groupable */
1098 if (hwloc_xml__handle_distances(topology, data, data->msgprefix) < 0)
1099 goto err;
1100 data->first_distances = data->last_distances = NULL;
1101 topology->support.discovery->pu = 1;
1103 hwloc_localeswitch_fini();
1104 return 1;
1106 failed:
1107 if (data->look_failed)
1108 data->look_failed(data);
1109 if (hwloc__xml_verbose())
1110 fprintf(stderr, "%s: XML component discovery failed.\n",
1111 data->msgprefix);
1112 err:
1113 hwloc_xml__free_distances(data);
1114 hwloc_localeswitch_fini();
1115 return -1;
1118 /* this can be the first XML call */
1120 hwloc_topology_diff_load_xml(hwloc_topology_t topology __hwloc_attribute_unused,
1121 const char *xmlpath,
1122 hwloc_topology_diff_t *firstdiffp, char **refnamep)
1124 struct hwloc__xml_import_state_s state;
1125 struct hwloc_xml_backend_data_s fakedata; /* only for storing global info during parsing */
1126 hwloc_localeswitch_declare;
1127 const char *local_basename;
1128 int force_nolibxml;
1129 int ret;
1131 state.global = &fakedata;
1133 local_basename = strrchr(xmlpath, '/');
1134 if (local_basename)
1135 local_basename++;
1136 else
1137 local_basename = xmlpath;
1138 fakedata.msgprefix = strdup(local_basename);
1140 if (!hwloc_libxml_callbacks && !hwloc_nolibxml_callbacks) {
1141 free(fakedata.msgprefix);
1142 errno = ENOSYS;
1143 return -1;
1146 hwloc_localeswitch_init();
1148 *firstdiffp = NULL;
1150 force_nolibxml = hwloc_nolibxml_import();
1151 retry:
1152 if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml))
1153 ret = hwloc_nolibxml_callbacks->import_diff(&state, xmlpath, NULL, 0, firstdiffp, refnamep);
1154 else {
1155 ret = hwloc_libxml_callbacks->import_diff(&state, xmlpath, NULL, 0, firstdiffp, refnamep);
1156 if (ret < 0 && errno == ENOSYS) {
1157 hwloc_libxml_callbacks = NULL;
1158 goto retry;
1162 hwloc_localeswitch_fini();
1164 free(fakedata.msgprefix);
1165 return ret;
1168 /* this can be the first XML call */
1170 hwloc_topology_diff_load_xmlbuffer(hwloc_topology_t topology __hwloc_attribute_unused,
1171 const char *xmlbuffer, int buflen,
1172 hwloc_topology_diff_t *firstdiffp, char **refnamep)
1174 struct hwloc__xml_import_state_s state;
1175 struct hwloc_xml_backend_data_s fakedata; /* only for storing global info during parsing */
1176 hwloc_localeswitch_declare;
1177 int force_nolibxml;
1178 int ret;
1180 state.global = &fakedata;
1181 fakedata.msgprefix = strdup("xmldiffbuffer");
1183 if (!hwloc_libxml_callbacks && !hwloc_nolibxml_callbacks) {
1184 free(fakedata.msgprefix);
1185 errno = ENOSYS;
1186 return -1;
1189 hwloc_localeswitch_init();
1191 *firstdiffp = NULL;
1193 force_nolibxml = hwloc_nolibxml_import();
1194 retry:
1195 if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml))
1196 ret = hwloc_nolibxml_callbacks->import_diff(&state, NULL, xmlbuffer, buflen, firstdiffp, refnamep);
1197 else {
1198 ret = hwloc_libxml_callbacks->import_diff(&state, NULL, xmlbuffer, buflen, firstdiffp, refnamep);
1199 if (ret < 0 && errno == ENOSYS) {
1200 hwloc_libxml_callbacks = NULL;
1201 goto retry;
1205 hwloc_localeswitch_fini();
1207 free(fakedata.msgprefix);
1208 return ret;
1211 /************************************************
1212 ********* XML export (common routines) *********
1213 ************************************************/
1215 #define HWLOC_XML_CHAR_VALID(c) (((c) >= 32 && (c) <= 126) || (c) == '\t' || (c) == '\n' || (c) == '\r')
1217 static int
1218 hwloc__xml_export_check_buffer(const char *buf, size_t length)
1220 unsigned i;
1221 for(i=0; i<length; i++)
1222 if (!HWLOC_XML_CHAR_VALID(buf[i]))
1223 return -1;
1224 return 0;
1227 /* strdup and remove ugly chars from random string */
1228 static char*
1229 hwloc__xml_export_safestrdup(const char *old)
1231 char *new = malloc(strlen(old)+1);
1232 char *dst = new;
1233 const char *src = old;
1234 while (*src) {
1235 if (HWLOC_XML_CHAR_VALID(*src))
1236 *(dst++) = *src;
1237 src++;
1239 *dst = '\0';
1240 return new;
1243 void
1244 hwloc__xml_export_object (hwloc__xml_export_state_t parentstate, hwloc_topology_t topology, hwloc_obj_t obj)
1246 struct hwloc__xml_export_state_s state;
1247 char *cpuset = NULL;
1248 char tmp[255];
1249 unsigned i;
1251 parentstate->new_child(parentstate, &state, "object");
1253 state.new_prop(&state, "type", hwloc_obj_type_string(obj->type));
1254 if (obj->os_level != -1) {
1255 sprintf(tmp, "%d", obj->os_level);
1256 state.new_prop(&state, "os_level", tmp);
1258 if (obj->os_index != (unsigned) -1) {
1259 sprintf(tmp, "%u", obj->os_index);
1260 state.new_prop(&state, "os_index", tmp);
1262 if (obj->cpuset) {
1263 hwloc_bitmap_asprintf(&cpuset, obj->cpuset);
1264 state.new_prop(&state, "cpuset", cpuset);
1265 free(cpuset);
1267 if (obj->complete_cpuset) {
1268 hwloc_bitmap_asprintf(&cpuset, obj->complete_cpuset);
1269 state.new_prop(&state, "complete_cpuset", cpuset);
1270 free(cpuset);
1272 if (obj->online_cpuset) {
1273 hwloc_bitmap_asprintf(&cpuset, obj->online_cpuset);
1274 state.new_prop(&state, "online_cpuset", cpuset);
1275 free(cpuset);
1277 if (obj->allowed_cpuset) {
1278 hwloc_bitmap_asprintf(&cpuset, obj->allowed_cpuset);
1279 state.new_prop(&state, "allowed_cpuset", cpuset);
1280 free(cpuset);
1282 if (obj->nodeset && !hwloc_bitmap_isfull(obj->nodeset)) {
1283 hwloc_bitmap_asprintf(&cpuset, obj->nodeset);
1284 state.new_prop(&state, "nodeset", cpuset);
1285 free(cpuset);
1287 if (obj->complete_nodeset && !hwloc_bitmap_isfull(obj->complete_nodeset)) {
1288 hwloc_bitmap_asprintf(&cpuset, obj->complete_nodeset);
1289 state.new_prop(&state, "complete_nodeset", cpuset);
1290 free(cpuset);
1292 if (obj->allowed_nodeset && !hwloc_bitmap_isfull(obj->allowed_nodeset)) {
1293 hwloc_bitmap_asprintf(&cpuset, obj->allowed_nodeset);
1294 state.new_prop(&state, "allowed_nodeset", cpuset);
1295 free(cpuset);
1298 if (obj->name) {
1299 char *name = hwloc__xml_export_safestrdup(obj->name);
1300 state.new_prop(&state, "name", name);
1301 free(name);
1304 switch (obj->type) {
1305 case HWLOC_OBJ_CACHE:
1306 sprintf(tmp, "%llu", (unsigned long long) obj->attr->cache.size);
1307 state.new_prop(&state, "cache_size", tmp);
1308 sprintf(tmp, "%u", obj->attr->cache.depth);
1309 state.new_prop(&state, "depth", tmp);
1310 sprintf(tmp, "%u", (unsigned) obj->attr->cache.linesize);
1311 state.new_prop(&state, "cache_linesize", tmp);
1312 sprintf(tmp, "%d", obj->attr->cache.associativity);
1313 state.new_prop(&state, "cache_associativity", tmp);
1314 sprintf(tmp, "%d", (int) obj->attr->cache.type);
1315 state.new_prop(&state, "cache_type", tmp);
1316 break;
1317 case HWLOC_OBJ_GROUP:
1318 sprintf(tmp, "%u", obj->attr->group.depth);
1319 state.new_prop(&state, "depth", tmp);
1320 break;
1321 case HWLOC_OBJ_BRIDGE:
1322 sprintf(tmp, "%d-%d", (int) obj->attr->bridge.upstream_type, (int) obj->attr->bridge.downstream_type);
1323 state.new_prop(&state, "bridge_type", tmp);
1324 sprintf(tmp, "%u", obj->attr->bridge.depth);
1325 state.new_prop(&state, "depth", tmp);
1326 if (obj->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI) {
1327 sprintf(tmp, "%04x:[%02x-%02x]",
1328 (unsigned) obj->attr->bridge.downstream.pci.domain,
1329 (unsigned) obj->attr->bridge.downstream.pci.secondary_bus,
1330 (unsigned) obj->attr->bridge.downstream.pci.subordinate_bus);
1331 state.new_prop(&state, "bridge_pci", tmp);
1333 if (obj->attr->bridge.upstream_type != HWLOC_OBJ_BRIDGE_PCI)
1334 break;
1335 /* FALLTHRU */
1336 case HWLOC_OBJ_PCI_DEVICE:
1337 sprintf(tmp, "%04x:%02x:%02x.%01x",
1338 (unsigned) obj->attr->pcidev.domain,
1339 (unsigned) obj->attr->pcidev.bus,
1340 (unsigned) obj->attr->pcidev.dev,
1341 (unsigned) obj->attr->pcidev.func);
1342 state.new_prop(&state, "pci_busid", tmp);
1343 sprintf(tmp, "%04x [%04x:%04x] [%04x:%04x] %02x",
1344 (unsigned) obj->attr->pcidev.class_id,
1345 (unsigned) obj->attr->pcidev.vendor_id, (unsigned) obj->attr->pcidev.device_id,
1346 (unsigned) obj->attr->pcidev.subvendor_id, (unsigned) obj->attr->pcidev.subdevice_id,
1347 (unsigned) obj->attr->pcidev.revision);
1348 state.new_prop(&state, "pci_type", tmp);
1349 sprintf(tmp, "%f", obj->attr->pcidev.linkspeed);
1350 state.new_prop(&state, "pci_link_speed", tmp);
1351 break;
1352 case HWLOC_OBJ_OS_DEVICE:
1353 sprintf(tmp, "%d", (int) obj->attr->osdev.type);
1354 state.new_prop(&state, "osdev_type", tmp);
1355 break;
1356 default:
1357 break;
1360 if (obj->memory.local_memory) {
1361 sprintf(tmp, "%llu", (unsigned long long) obj->memory.local_memory);
1362 state.new_prop(&state, "local_memory", tmp);
1365 for(i=0; i<obj->memory.page_types_len; i++) {
1366 struct hwloc__xml_export_state_s childstate;
1367 state.new_child(&state, &childstate, "page_type");
1368 sprintf(tmp, "%llu", (unsigned long long) obj->memory.page_types[i].size);
1369 childstate.new_prop(&childstate, "size", tmp);
1370 sprintf(tmp, "%llu", (unsigned long long) obj->memory.page_types[i].count);
1371 childstate.new_prop(&childstate, "count", tmp);
1372 childstate.end_object(&childstate, "page_type");
1375 for(i=0; i<obj->infos_count; i++) {
1376 char *name = hwloc__xml_export_safestrdup(obj->infos[i].name);
1377 char *value = hwloc__xml_export_safestrdup(obj->infos[i].value);
1378 struct hwloc__xml_export_state_s childstate;
1379 state.new_child(&state, &childstate, "info");
1380 childstate.new_prop(&childstate, "name", name);
1381 childstate.new_prop(&childstate, "value", value);
1382 childstate.end_object(&childstate, "info");
1383 free(name);
1384 free(value);
1387 for(i=0; i<obj->distances_count; i++) {
1388 unsigned nbobjs = obj->distances[i]->nbobjs;
1389 unsigned j;
1390 struct hwloc__xml_export_state_s childstate;
1391 state.new_child(&state, &childstate, "distances");
1392 sprintf(tmp, "%u", nbobjs);
1393 childstate.new_prop(&childstate, "nbobjs", tmp);
1394 sprintf(tmp, "%u", obj->distances[i]->relative_depth);
1395 childstate.new_prop(&childstate, "relative_depth", tmp);
1396 sprintf(tmp, "%f", obj->distances[i]->latency_base);
1397 childstate.new_prop(&childstate, "latency_base", tmp);
1398 for(j=0; j<nbobjs*nbobjs; j++) {
1399 struct hwloc__xml_export_state_s greatchildstate;
1400 childstate.new_child(&childstate, &greatchildstate, "latency");
1401 sprintf(tmp, "%f", obj->distances[i]->latency[j]);
1402 greatchildstate.new_prop(&greatchildstate, "value", tmp);
1403 greatchildstate.end_object(&greatchildstate, "latency");
1405 childstate.end_object(&childstate, "distances");
1408 if (obj->userdata && topology->userdata_export_cb)
1409 topology->userdata_export_cb((void*) &state, topology, obj);
1411 if (obj->arity) {
1412 unsigned x;
1413 for (x=0; x<obj->arity; x++)
1414 hwloc__xml_export_object (&state, topology, obj->children[x]);
1417 state.end_object(&state, "object");
1420 void
1421 hwloc__xml_export_diff(hwloc__xml_export_state_t parentstate, hwloc_topology_diff_t diff)
1423 while (diff) {
1424 struct hwloc__xml_export_state_s state;
1425 char tmp[255];
1427 parentstate->new_child(parentstate, &state, "diff");
1429 sprintf(tmp, "%d", (int) diff->generic.type);
1430 state.new_prop(&state, "type", tmp);
1432 switch (diff->generic.type) {
1433 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR:
1434 sprintf(tmp, "%d", (int) diff->obj_attr.obj_depth);
1435 state.new_prop(&state, "obj_depth", tmp);
1436 sprintf(tmp, "%u", diff->obj_attr.obj_index);
1437 state.new_prop(&state, "obj_index", tmp);
1439 sprintf(tmp, "%d", (int) diff->obj_attr.diff.generic.type);
1440 state.new_prop(&state, "obj_attr_type", tmp);
1442 switch (diff->obj_attr.diff.generic.type) {
1443 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_SIZE:
1444 sprintf(tmp, "%llu", (unsigned long long) diff->obj_attr.diff.uint64.index);
1445 state.new_prop(&state, "obj_attr_index", tmp);
1446 sprintf(tmp, "%llu", (unsigned long long) diff->obj_attr.diff.uint64.oldvalue);
1447 state.new_prop(&state, "obj_attr_oldvalue", tmp);
1448 sprintf(tmp, "%llu", (unsigned long long) diff->obj_attr.diff.uint64.newvalue);
1449 state.new_prop(&state, "obj_attr_newvalue", tmp);
1450 break;
1451 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_NAME:
1452 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO:
1453 if (diff->obj_attr.diff.string.name)
1454 state.new_prop(&state, "obj_attr_name", diff->obj_attr.diff.string.name);
1455 state.new_prop(&state, "obj_attr_oldvalue", diff->obj_attr.diff.string.oldvalue);
1456 state.new_prop(&state, "obj_attr_newvalue", diff->obj_attr.diff.string.newvalue);
1457 break;
1460 break;
1461 default:
1462 assert(0);
1464 state.end_object(&state, "diff");
1466 diff = diff->generic.next;
1470 /**********************************
1471 ********* main XML export ********
1472 **********************************/
1474 /* this can be the first XML call */
1475 int hwloc_topology_export_xml(hwloc_topology_t topology, const char *filename)
1477 hwloc_localeswitch_declare;
1478 int force_nolibxml;
1479 int ret;
1481 if (!hwloc_libxml_callbacks && !hwloc_nolibxml_callbacks) {
1482 errno = ENOSYS;
1483 return -1;
1486 hwloc_localeswitch_init();
1488 force_nolibxml = hwloc_nolibxml_export();
1489 retry:
1490 if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml))
1491 ret = hwloc_nolibxml_callbacks->export_file(topology, filename);
1492 else {
1493 ret = hwloc_libxml_callbacks->export_file(topology, filename);
1494 if (ret < 0 && errno == ENOSYS) {
1495 hwloc_libxml_callbacks = NULL;
1496 goto retry;
1500 hwloc_localeswitch_fini();
1501 return ret;
1504 /* this can be the first XML call */
1505 int hwloc_topology_export_xmlbuffer(hwloc_topology_t topology, char **xmlbuffer, int *buflen)
1507 hwloc_localeswitch_declare;
1508 int force_nolibxml;
1509 int ret;
1511 if (!hwloc_libxml_callbacks && !hwloc_nolibxml_callbacks) {
1512 errno = ENOSYS;
1513 return -1;
1516 hwloc_localeswitch_init();
1518 force_nolibxml = hwloc_nolibxml_export();
1519 retry:
1520 if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml))
1521 ret = hwloc_nolibxml_callbacks->export_buffer(topology, xmlbuffer, buflen);
1522 else {
1523 ret = hwloc_libxml_callbacks->export_buffer(topology, xmlbuffer, buflen);
1524 if (ret < 0 && errno == ENOSYS) {
1525 hwloc_libxml_callbacks = NULL;
1526 goto retry;
1530 hwloc_localeswitch_fini();
1531 return ret;
1534 /* this can be the first XML call */
1536 hwloc_topology_diff_export_xml(hwloc_topology_t topology __hwloc_attribute_unused,
1537 hwloc_topology_diff_t diff, const char *refname,
1538 const char *filename)
1540 hwloc_localeswitch_declare;
1541 hwloc_topology_diff_t tmpdiff;
1542 int force_nolibxml;
1543 int ret;
1545 if (!hwloc_libxml_callbacks && !hwloc_nolibxml_callbacks) {
1546 errno = ENOSYS;
1547 return -1;
1550 tmpdiff = diff;
1551 while (tmpdiff) {
1552 if (tmpdiff->generic.type == HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX) {
1553 errno = EINVAL;
1554 return -1;
1556 tmpdiff = tmpdiff->generic.next;
1559 hwloc_localeswitch_init();
1561 force_nolibxml = hwloc_nolibxml_export();
1562 retry:
1563 if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml))
1564 ret = hwloc_nolibxml_callbacks->export_diff_file(diff, refname, filename);
1565 else {
1566 ret = hwloc_libxml_callbacks->export_diff_file(diff, refname, filename);
1567 if (ret < 0 && errno == ENOSYS) {
1568 hwloc_libxml_callbacks = NULL;
1569 goto retry;
1573 hwloc_localeswitch_fini();
1574 return ret;
1577 /* this can be the first XML call */
1579 hwloc_topology_diff_export_xmlbuffer(hwloc_topology_t topology __hwloc_attribute_unused,
1580 hwloc_topology_diff_t diff, const char *refname,
1581 char **xmlbuffer, int *buflen)
1583 hwloc_localeswitch_declare;
1584 hwloc_topology_diff_t tmpdiff;
1585 int force_nolibxml;
1586 int ret;
1588 if (!hwloc_libxml_callbacks && !hwloc_nolibxml_callbacks) {
1589 errno = ENOSYS;
1590 return -1;
1593 tmpdiff = diff;
1594 while (tmpdiff) {
1595 if (tmpdiff->generic.type == HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX) {
1596 errno = EINVAL;
1597 return -1;
1599 tmpdiff = tmpdiff->generic.next;
1602 hwloc_localeswitch_init();
1604 force_nolibxml = hwloc_nolibxml_export();
1605 retry:
1606 if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml))
1607 ret = hwloc_nolibxml_callbacks->export_diff_buffer(diff, refname, xmlbuffer, buflen);
1608 else {
1609 ret = hwloc_libxml_callbacks->export_diff_buffer(diff, refname, xmlbuffer, buflen);
1610 if (ret < 0 && errno == ENOSYS) {
1611 hwloc_libxml_callbacks = NULL;
1612 goto retry;
1616 hwloc_localeswitch_fini();
1617 return ret;
1620 void hwloc_free_xmlbuffer(hwloc_topology_t topology __hwloc_attribute_unused, char *xmlbuffer)
1622 int force_nolibxml;
1624 if (!hwloc_libxml_callbacks && !hwloc_nolibxml_callbacks) {
1625 errno = ENOSYS;
1626 return ;
1629 force_nolibxml = hwloc_nolibxml_export();
1630 if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml))
1631 hwloc_nolibxml_callbacks->free_buffer(xmlbuffer);
1632 else
1633 hwloc_libxml_callbacks->free_buffer(xmlbuffer);
1636 void
1637 hwloc_topology_set_userdata_export_callback(hwloc_topology_t topology,
1638 void (*export)(void *reserved, struct hwloc_topology *topology, struct hwloc_obj *obj))
1640 topology->userdata_export_cb = export;
1643 static void
1644 hwloc__export_obj_userdata(hwloc__xml_export_state_t parentstate, int encoded,
1645 const char *name, size_t length, const void *buffer, size_t encoded_length)
1647 struct hwloc__xml_export_state_s state;
1648 char tmp[255];
1649 parentstate->new_child(parentstate, &state, "userdata");
1650 if (name)
1651 state.new_prop(&state, "name", name);
1652 sprintf(tmp, "%lu", (unsigned long) length);
1653 state.new_prop(&state, "length", tmp);
1654 if (encoded)
1655 state.new_prop(&state, "encoding", "base64");
1656 if (encoded_length)
1657 state.add_content(&state, buffer, encoded ? encoded_length : length);
1658 state.end_object(&state, "userdata");
1662 hwloc_export_obj_userdata(void *reserved,
1663 struct hwloc_topology *topology, struct hwloc_obj *obj __hwloc_attribute_unused,
1664 const char *name, const void *buffer, size_t length)
1666 hwloc__xml_export_state_t state = reserved;
1668 if (!buffer) {
1669 errno = EINVAL;
1670 return -1;
1673 if ((name && hwloc__xml_export_check_buffer(name, strlen(name)) < 0)
1674 || hwloc__xml_export_check_buffer(buffer, length) < 0) {
1675 errno = EINVAL;
1676 return -1;
1679 if (topology->userdata_not_decoded) {
1680 int encoded;
1681 size_t encoded_length;
1682 const char *realname;
1683 if (!strncmp(name, "base64", 6)) {
1684 encoded = 1;
1685 encoded_length = BASE64_ENCODED_LENGTH(length);
1686 } else {
1687 assert(!strncmp(name, "normal", 6));
1688 encoded = 0;
1689 encoded_length = length;
1691 if (name[6] == ':')
1692 realname = name+7;
1693 else {
1694 assert(!strcmp(name+6, "-anon"));
1695 realname = NULL;
1697 hwloc__export_obj_userdata(state, encoded, realname, length, buffer, encoded_length);
1699 } else
1700 hwloc__export_obj_userdata(state, 0, name, length, buffer, length);
1702 return 0;
1706 hwloc_export_obj_userdata_base64(void *reserved,
1707 struct hwloc_topology *topology __hwloc_attribute_unused, struct hwloc_obj *obj __hwloc_attribute_unused,
1708 const char *name, const void *buffer, size_t length)
1710 hwloc__xml_export_state_t state = reserved;
1711 size_t encoded_length;
1712 char *encoded_buffer;
1713 int ret __hwloc_attribute_unused;
1715 if (!buffer) {
1716 errno = EINVAL;
1717 return -1;
1720 assert(!topology->userdata_not_decoded);
1722 if (name && hwloc__xml_export_check_buffer(name, strlen(name)) < 0) {
1723 errno = EINVAL;
1724 return -1;
1727 encoded_length = BASE64_ENCODED_LENGTH(length);
1728 encoded_buffer = malloc(encoded_length+1);
1729 if (!encoded_buffer) {
1730 errno = ENOMEM;
1731 return -1;
1734 ret = hwloc_encode_to_base64(buffer, length, encoded_buffer, encoded_length+1);
1735 assert(ret == (int) encoded_length);
1737 hwloc__export_obj_userdata(state, 1, name, length, encoded_buffer, encoded_length);
1739 free(encoded_buffer);
1740 return 0;
1743 void
1744 hwloc_topology_set_userdata_import_callback(hwloc_topology_t topology,
1745 void (*import)(struct hwloc_topology *topology, struct hwloc_obj *obj, const char *name, const void *buffer, size_t length))
1747 topology->userdata_import_cb = import;
1750 /***************************************
1751 ************ XML component ************
1752 ***************************************/
1754 static void
1755 hwloc_xml_backend_disable(struct hwloc_backend *backend)
1757 struct hwloc_xml_backend_data_s *data = backend->private_data;
1758 data->backend_exit(data);
1759 free(data->msgprefix);
1760 free(data);
1763 static struct hwloc_backend *
1764 hwloc_xml_component_instantiate(struct hwloc_disc_component *component,
1765 const void *_data1,
1766 const void *_data2,
1767 const void *_data3)
1769 struct hwloc_xml_backend_data_s *data;
1770 struct hwloc_backend *backend;
1771 int force_nolibxml;
1772 const char * xmlpath = (const char *) _data1;
1773 const char * xmlbuffer = (const char *) _data2;
1774 int xmlbuflen = (int)(uintptr_t) _data3;
1775 const char *local_basename;
1776 int err;
1778 if (!hwloc_libxml_callbacks && !hwloc_nolibxml_callbacks) {
1779 errno = ENOSYS;
1780 goto out;
1783 if (!xmlpath && !xmlbuffer) {
1784 errno = EINVAL;
1785 goto out;
1788 backend = hwloc_backend_alloc(component);
1789 if (!backend)
1790 goto out;
1792 data = malloc(sizeof(*data));
1793 if (!data) {
1794 errno = ENOMEM;
1795 goto out_with_backend;
1798 backend->private_data = data;
1799 backend->discover = hwloc_look_xml;
1800 backend->disable = hwloc_xml_backend_disable;
1801 backend->is_thissystem = 0;
1803 if (xmlpath) {
1804 local_basename = strrchr(xmlpath, '/');
1805 if (local_basename)
1806 local_basename++;
1807 else
1808 local_basename = xmlpath;
1809 } else {
1810 local_basename = "xmlbuffer";
1812 data->msgprefix = strdup(local_basename);
1814 force_nolibxml = hwloc_nolibxml_import();
1815 retry:
1816 if (!hwloc_libxml_callbacks || (hwloc_nolibxml_callbacks && force_nolibxml))
1817 err = hwloc_nolibxml_callbacks->backend_init(data, xmlpath, xmlbuffer, xmlbuflen);
1818 else {
1819 err = hwloc_libxml_callbacks->backend_init(data, xmlpath, xmlbuffer, xmlbuflen);
1820 if (err < 0 && errno == ENOSYS) {
1821 hwloc_libxml_callbacks = NULL;
1822 goto retry;
1825 if (err < 0)
1826 goto out_with_data;
1828 return backend;
1830 out_with_data:
1831 free(data->msgprefix);
1832 free(data);
1833 out_with_backend:
1834 free(backend);
1835 out:
1836 return NULL;
1839 static struct hwloc_disc_component hwloc_xml_disc_component = {
1840 HWLOC_DISC_COMPONENT_TYPE_GLOBAL,
1841 "xml",
1843 hwloc_xml_component_instantiate,
1845 NULL
1848 const struct hwloc_component hwloc_xml_component = {
1849 HWLOC_COMPONENT_ABI,
1850 NULL, NULL,
1851 HWLOC_COMPONENT_TYPE_DISC,
1853 &hwloc_xml_disc_component