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.
9 #include <private/autogen/config.h>
11 #include <private/xml.h>
12 #include <private/private.h>
13 #include <private/misc.h>
14 #include <private/debug.h>
17 hwloc__xml_verbose(void)
20 static int verbose
= 0;
22 const char *env
= getenv("HWLOC_XML_VERBOSE");
31 hwloc_nolibxml_import(void)
34 static int nolibxml
= 0;
36 const char *env
= getenv("HWLOC_LIBXML");
38 nolibxml
= !atoi(env
);
40 env
= getenv("HWLOC_LIBXML_IMPORT");
42 nolibxml
= !atoi(env
);
44 env
= getenv("HWLOC_NO_LIBXML_IMPORT");
55 hwloc_nolibxml_export(void)
58 static int nolibxml
= 0;
60 const char *env
= getenv("HWLOC_LIBXML");
62 nolibxml
= !atoi(env
);
64 env
= getenv("HWLOC_LIBXML_EXPORT");
66 nolibxml
= !atoi(env
);
68 env
= getenv("HWLOC_NO_LIBXML_EXPORT");
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
;
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
;
100 hwloc_xml_callbacks_reset(void)
102 hwloc_nolibxml_callbacks
= NULL
;
103 hwloc_libxml_callbacks
= NULL
;
106 /************************************************
107 ********* XML import (common routines) *********
108 ************************************************/
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 */
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
;
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);
196 case HWLOC_OBJ_CACHE
:
197 obj
->attr
->cache
.depth
= lvalue
;
199 case HWLOC_OBJ_GROUP
:
200 obj
->attr
->group
.depth
= lvalue
;
202 case HWLOC_OBJ_BRIDGE
:
203 obj
->attr
->bridge
.depth
= lvalue
;
206 if (hwloc__xml_verbose())
207 fprintf(stderr
, "%s: ignoring depth attribute for object type without depth\n",
208 state
->global
->msgprefix
);
213 else if (!strcmp(name
, "pci_busid")) {
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
);
224 obj
->attr
->pcidev
.domain
= domain
;
225 obj
->attr
->pcidev
.bus
= bus
;
226 obj
->attr
->pcidev
.dev
= dev
;
227 obj
->attr
->pcidev
.func
= func
;
232 if (hwloc__xml_verbose())
233 fprintf(stderr
, "%s: ignoring pci_busid attribute for non-PCI object\n",
234 state
->global
->msgprefix
);
239 else if (!strcmp(name
, "pci_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
);
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
;
260 if (hwloc__xml_verbose())
261 fprintf(stderr
, "%s: ignoring pci_type attribute for non-PCI object\n",
262 state
->global
->msgprefix
);
267 else if (!strcmp(name
, "pci_link_speed")) {
269 case HWLOC_OBJ_PCI_DEVICE
:
270 case HWLOC_OBJ_BRIDGE
: {
271 obj
->attr
->pcidev
.linkspeed
= (float) atof(value
);
275 if (hwloc__xml_verbose())
276 fprintf(stderr
, "%s: ignoring pci_link_speed attribute for non-PCI object\n",
277 state
->global
->msgprefix
);
282 else if (!strcmp(name
, "bridge_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
);
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
;
297 if (hwloc__xml_verbose())
298 fprintf(stderr
, "%s: ignoring bridge_type attribute for non-bridge object\n",
299 state
->global
->msgprefix
);
304 else if (!strcmp(name
, "bridge_pci")) {
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
);
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
;
321 if (hwloc__xml_verbose())
322 fprintf(stderr
, "%s: ignoring bridge_pci attribute for non-bridge object\n",
323 state
->global
->msgprefix
);
328 else if (!strcmp(name
, "osdev_type")) {
330 case HWLOC_OBJ_OS_DEVICE
: {
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
);
337 obj
->attr
->osdev
.type
= (hwloc_obj_osdev_type_t
) osdev_type
;
341 if (hwloc__xml_verbose())
342 fprintf(stderr
, "%s: ignoring osdev_type attribute for non-osdev object\n",
343 state
->global
->msgprefix
);
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 */
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);
385 case HWLOC_OBJ_CACHE
:
386 obj
->attr
->cache
.size
= lvalue
<< 10;
388 case HWLOC_OBJ_NUMANODE
:
389 case HWLOC_OBJ_MACHINE
:
390 case HWLOC_OBJ_SYSTEM
:
391 obj
->memory
.local_memory
= lvalue
<< 10;
394 if (hwloc__xml_verbose())
395 fprintf(stderr
, "%s: ignoring memory_kB attribute for object type without memory\n",
396 state
->global
->msgprefix
);
400 else if (!strcmp(name
, "huge_page_size_kB")) {
401 unsigned long lvalue
= strtoul(value
, NULL
, 10);
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;
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
);
419 else if (!strcmp(name
, "huge_page_free")) {
420 unsigned long lvalue
= strtoul(value
, NULL
, 10);
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
;
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
);
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
);
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
;
458 char *attrname
, *attrvalue
;
459 if (state
->global
->next_attr(state
, &attrname
, &attrvalue
) < 0)
461 if (!strcmp(attrname
, "name"))
462 infoname
= attrvalue
;
463 else if (!strcmp(attrname
, "value"))
464 infovalue
= attrvalue
;
470 /* empty strings are ignored by libxml */
471 hwloc_obj_add_info(obj
, infoname
, infovalue
? infovalue
: "");
473 return state
->global
->close_tag(state
);
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;
483 char *attrname
, *attrvalue
;
484 if (state
->global
->next_attr(state
, &attrname
, &attrvalue
) < 0)
486 if (!strcmp(attrname
, "size"))
487 size
= strtoull(attrvalue
, NULL
, 10);
488 else if (!strcmp(attrname
, "count"))
489 count
= strtoull(attrvalue
, NULL
, 10);
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
);
510 hwloc__xml_import_distances(struct hwloc_xml_backend_data_s
*data
,
512 hwloc__xml_import_state_t state
)
514 unsigned long reldepth
= 0, nbobjs
= 0;
520 char *attrname
, *attrvalue
;
521 if (state
->global
->next_attr(state
, &attrname
, &attrvalue
) < 0)
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
);
533 if (nbobjs
&& reldepth
&& latbase
) {
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
);
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
;
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
);
568 ret
= state
->global
->next_attr(&childstate
, &attrname
, &attrvalue
);
569 if (ret
< 0 || strcmp(attrname
, "value")) {
570 free(distances
->distances
.latency
);
575 val
= (float) atof((char *) attrvalue
);
580 ret
= state
->global
->close_tag(&childstate
);
582 free(distances
->distances
.latency
);
587 state
->global
->close_child(&childstate
);
590 distances
->distances
.latency_max
= latmax
;
593 /* distances with a single object are useless, even if the XML isn't invalid */
595 if (hwloc__xml_verbose())
596 fprintf(stderr
, "%s: ignoring invalid distance matrix with only 1 object\n",
597 state
->global
->msgprefix
);
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
;
607 data
->first_distances
= distances
;
608 data
->last_distances
= distances
;
612 return state
->global
->close_tag(state
);
616 hwloc__xml_import_userdata(hwloc_topology_t topology __hwloc_attribute_unused
, hwloc_obj_t obj
,
617 hwloc__xml_import_state_t state
)
621 char *name
= NULL
; /* optional */
625 char *attrname
, *attrvalue
;
626 if (state
->global
->next_attr(state
, &attrname
, &attrvalue
) < 0)
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"))
638 if (!topology
->userdata_import_cb
) {
640 size_t reallength
= encoded
? BASE64_ENCODED_LENGTH(length
) : length
;
641 ret
= state
->global
->get_content(state
, &buffer
, reallength
);
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
);
651 fakename
= malloc(6 + 1 + (name
? strlen(name
) : 4) + 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
);
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
);
665 char *decoded_buffer
= malloc(length
+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
);
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 *) "";
681 ret
= state
->global
->get_content(state
, &buffer
, length
);
685 topology
->userdata_import_cb(topology
, obj
, name
, buffer
, length
);
688 state
->global
->close_content(state
);
689 return state
->global
->close_tag(state
);
693 hwloc__xml_import_object(hwloc_topology_t topology
,
694 struct hwloc_xml_backend_data_s
*data
,
696 hwloc__xml_import_state_t state
)
698 hwloc_obj_t parent
= obj
->parent
;
700 /* process attributes */
702 char *attrname
, *attrvalue
;
703 if (state
->global
->next_attr(state
, &attrname
, &attrvalue
) < 0)
705 if (!strcmp(attrname
, "type")) {
706 if (hwloc_obj_type_sscanf(attrvalue
, &obj
->type
, NULL
, NULL
, 0) < 0)
707 goto error_with_object
;
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
) {
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");
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);
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",
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",
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>");
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");
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 */
791 struct hwloc__xml_import_state_s childstate
;
795 ret
= state
->global
->find_child(state
, &childstate
, &tag
);
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
);
814 if (hwloc__xml_verbose())
815 fprintf(stderr
, "%s: invalid special object child %s\n",
816 state
->global
->msgprefix
, tag
);
823 state
->global
->close_child(&childstate
);
826 return state
->global
->close_tag(state
);
830 /* root->parent is NULL, and root is already inserted. the caller will cleanup that root. */
831 hwloc_free_unlinked_object(obj
);
837 hwloc__xml_import_diff_one(hwloc__xml_import_state_t state
,
838 hwloc_topology_diff_t
*firstdiffp
,
839 hwloc_topology_diff_t
*lastdiffp
)
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
;
851 char *attrname
, *attrvalue
;
852 if (state
->global
->next_attr(state
, &attrname
, &attrvalue
) < 0)
854 if (!strcmp(attrname
, "type"))
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
;
871 if (hwloc__xml_verbose())
872 fprintf(stderr
, "%s: ignoring unknown diff attribute %s\n",
873 state
->global
->msgprefix
, attrname
);
879 switch (atoi(type_s
)) {
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
);
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
);
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
);
912 /* now we know we have everything we need */
913 diff
= malloc(sizeof(*diff
));
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);
927 case HWLOC_TOPOLOGY_DIFF_OBJ_ATTR_INFO
:
928 diff
->obj_attr
.diff
.string
.name
= strdup(obj_attr_name_s
);
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
);
937 (*lastdiffp
)->generic
.next
= 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
;
957 struct hwloc__xml_import_state_s childstate
;
961 ret
= state
->global
->find_child(state
, &childstate
, &tag
);
967 if (!strcmp(tag
, "diff")) {
968 ret
= hwloc__xml_import_diff_one(&childstate
, &firstdiff
, &lastdiff
);
975 state
->global
->close_child(&childstate
);
978 *firstdiffp
= firstdiff
;
982 /***********************************
983 ********* main XML import *********
984 ***********************************/
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
);
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
);
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
;
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
) {
1029 indexes
[j
] = child
->os_index
;
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 */);
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",
1052 free(xmldist
->distances
.latency
);
1059 /* this canNOT be the first XML call */
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
;
1067 hwloc_localeswitch_declare
;
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
);
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"))
1086 ret
= hwloc__xml_import_object(topology
, data
, topology
->levels
[0][0], &childstate
);
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)
1100 data
->first_distances
= data
->last_distances
= NULL
;
1101 topology
->support
.discovery
->pu
= 1;
1103 hwloc_localeswitch_fini();
1107 if (data
->look_failed
)
1108 data
->look_failed(data
);
1109 if (hwloc__xml_verbose())
1110 fprintf(stderr
, "%s: XML component discovery failed.\n",
1113 hwloc_xml__free_distances(data
);
1114 hwloc_localeswitch_fini();
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
;
1131 state
.global
= &fakedata
;
1133 local_basename
= strrchr(xmlpath
, '/');
1137 local_basename
= xmlpath
;
1138 fakedata
.msgprefix
= strdup(local_basename
);
1140 if (!hwloc_libxml_callbacks
&& !hwloc_nolibxml_callbacks
) {
1141 free(fakedata
.msgprefix
);
1146 hwloc_localeswitch_init();
1150 force_nolibxml
= hwloc_nolibxml_import();
1152 if (!hwloc_libxml_callbacks
|| (hwloc_nolibxml_callbacks
&& force_nolibxml
))
1153 ret
= hwloc_nolibxml_callbacks
->import_diff(&state
, xmlpath
, NULL
, 0, firstdiffp
, refnamep
);
1155 ret
= hwloc_libxml_callbacks
->import_diff(&state
, xmlpath
, NULL
, 0, firstdiffp
, refnamep
);
1156 if (ret
< 0 && errno
== ENOSYS
) {
1157 hwloc_libxml_callbacks
= NULL
;
1162 hwloc_localeswitch_fini();
1164 free(fakedata
.msgprefix
);
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
;
1180 state
.global
= &fakedata
;
1181 fakedata
.msgprefix
= strdup("xmldiffbuffer");
1183 if (!hwloc_libxml_callbacks
&& !hwloc_nolibxml_callbacks
) {
1184 free(fakedata
.msgprefix
);
1189 hwloc_localeswitch_init();
1193 force_nolibxml
= hwloc_nolibxml_import();
1195 if (!hwloc_libxml_callbacks
|| (hwloc_nolibxml_callbacks
&& force_nolibxml
))
1196 ret
= hwloc_nolibxml_callbacks
->import_diff(&state
, NULL
, xmlbuffer
, buflen
, firstdiffp
, refnamep
);
1198 ret
= hwloc_libxml_callbacks
->import_diff(&state
, NULL
, xmlbuffer
, buflen
, firstdiffp
, refnamep
);
1199 if (ret
< 0 && errno
== ENOSYS
) {
1200 hwloc_libxml_callbacks
= NULL
;
1205 hwloc_localeswitch_fini();
1207 free(fakedata
.msgprefix
);
1211 /************************************************
1212 ********* XML export (common routines) *********
1213 ************************************************/
1215 #define HWLOC_XML_CHAR_VALID(c) (((c) >= 32 && (c) <= 126) || (c) == '\t' || (c) == '\n' || (c) == '\r')
1218 hwloc__xml_export_check_buffer(const char *buf
, size_t length
)
1221 for(i
=0; i
<length
; i
++)
1222 if (!HWLOC_XML_CHAR_VALID(buf
[i
]))
1227 /* strdup and remove ugly chars from random string */
1229 hwloc__xml_export_safestrdup(const char *old
)
1231 char *new = malloc(strlen(old
)+1);
1233 const char *src
= old
;
1235 if (HWLOC_XML_CHAR_VALID(*src
))
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
;
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
);
1263 hwloc_bitmap_asprintf(&cpuset
, obj
->cpuset
);
1264 state
.new_prop(&state
, "cpuset", cpuset
);
1267 if (obj
->complete_cpuset
) {
1268 hwloc_bitmap_asprintf(&cpuset
, obj
->complete_cpuset
);
1269 state
.new_prop(&state
, "complete_cpuset", cpuset
);
1272 if (obj
->online_cpuset
) {
1273 hwloc_bitmap_asprintf(&cpuset
, obj
->online_cpuset
);
1274 state
.new_prop(&state
, "online_cpuset", cpuset
);
1277 if (obj
->allowed_cpuset
) {
1278 hwloc_bitmap_asprintf(&cpuset
, obj
->allowed_cpuset
);
1279 state
.new_prop(&state
, "allowed_cpuset", cpuset
);
1282 if (obj
->nodeset
&& !hwloc_bitmap_isfull(obj
->nodeset
)) {
1283 hwloc_bitmap_asprintf(&cpuset
, obj
->nodeset
);
1284 state
.new_prop(&state
, "nodeset", 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
);
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
);
1299 char *name
= hwloc__xml_export_safestrdup(obj
->name
);
1300 state
.new_prop(&state
, "name", 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
);
1317 case HWLOC_OBJ_GROUP
:
1318 sprintf(tmp
, "%u", obj
->attr
->group
.depth
);
1319 state
.new_prop(&state
, "depth", tmp
);
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
)
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
);
1352 case HWLOC_OBJ_OS_DEVICE
:
1353 sprintf(tmp
, "%d", (int) obj
->attr
->osdev
.type
);
1354 state
.new_prop(&state
, "osdev_type", tmp
);
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");
1387 for(i
=0; i
<obj
->distances_count
; i
++) {
1388 unsigned nbobjs
= obj
->distances
[i
]->nbobjs
;
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
);
1413 for (x
=0; x
<obj
->arity
; x
++)
1414 hwloc__xml_export_object (&state
, topology
, obj
->children
[x
]);
1417 state
.end_object(&state
, "object");
1421 hwloc__xml_export_diff(hwloc__xml_export_state_t parentstate
, hwloc_topology_diff_t diff
)
1424 struct hwloc__xml_export_state_s state
;
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
);
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
);
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
;
1481 if (!hwloc_libxml_callbacks
&& !hwloc_nolibxml_callbacks
) {
1486 hwloc_localeswitch_init();
1488 force_nolibxml
= hwloc_nolibxml_export();
1490 if (!hwloc_libxml_callbacks
|| (hwloc_nolibxml_callbacks
&& force_nolibxml
))
1491 ret
= hwloc_nolibxml_callbacks
->export_file(topology
, filename
);
1493 ret
= hwloc_libxml_callbacks
->export_file(topology
, filename
);
1494 if (ret
< 0 && errno
== ENOSYS
) {
1495 hwloc_libxml_callbacks
= NULL
;
1500 hwloc_localeswitch_fini();
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
;
1511 if (!hwloc_libxml_callbacks
&& !hwloc_nolibxml_callbacks
) {
1516 hwloc_localeswitch_init();
1518 force_nolibxml
= hwloc_nolibxml_export();
1520 if (!hwloc_libxml_callbacks
|| (hwloc_nolibxml_callbacks
&& force_nolibxml
))
1521 ret
= hwloc_nolibxml_callbacks
->export_buffer(topology
, xmlbuffer
, buflen
);
1523 ret
= hwloc_libxml_callbacks
->export_buffer(topology
, xmlbuffer
, buflen
);
1524 if (ret
< 0 && errno
== ENOSYS
) {
1525 hwloc_libxml_callbacks
= NULL
;
1530 hwloc_localeswitch_fini();
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
;
1545 if (!hwloc_libxml_callbacks
&& !hwloc_nolibxml_callbacks
) {
1552 if (tmpdiff
->generic
.type
== HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX
) {
1556 tmpdiff
= tmpdiff
->generic
.next
;
1559 hwloc_localeswitch_init();
1561 force_nolibxml
= hwloc_nolibxml_export();
1563 if (!hwloc_libxml_callbacks
|| (hwloc_nolibxml_callbacks
&& force_nolibxml
))
1564 ret
= hwloc_nolibxml_callbacks
->export_diff_file(diff
, refname
, filename
);
1566 ret
= hwloc_libxml_callbacks
->export_diff_file(diff
, refname
, filename
);
1567 if (ret
< 0 && errno
== ENOSYS
) {
1568 hwloc_libxml_callbacks
= NULL
;
1573 hwloc_localeswitch_fini();
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
;
1588 if (!hwloc_libxml_callbacks
&& !hwloc_nolibxml_callbacks
) {
1595 if (tmpdiff
->generic
.type
== HWLOC_TOPOLOGY_DIFF_TOO_COMPLEX
) {
1599 tmpdiff
= tmpdiff
->generic
.next
;
1602 hwloc_localeswitch_init();
1604 force_nolibxml
= hwloc_nolibxml_export();
1606 if (!hwloc_libxml_callbacks
|| (hwloc_nolibxml_callbacks
&& force_nolibxml
))
1607 ret
= hwloc_nolibxml_callbacks
->export_diff_buffer(diff
, refname
, xmlbuffer
, buflen
);
1609 ret
= hwloc_libxml_callbacks
->export_diff_buffer(diff
, refname
, xmlbuffer
, buflen
);
1610 if (ret
< 0 && errno
== ENOSYS
) {
1611 hwloc_libxml_callbacks
= NULL
;
1616 hwloc_localeswitch_fini();
1620 void hwloc_free_xmlbuffer(hwloc_topology_t topology __hwloc_attribute_unused
, char *xmlbuffer
)
1624 if (!hwloc_libxml_callbacks
&& !hwloc_nolibxml_callbacks
) {
1629 force_nolibxml
= hwloc_nolibxml_export();
1630 if (!hwloc_libxml_callbacks
|| (hwloc_nolibxml_callbacks
&& force_nolibxml
))
1631 hwloc_nolibxml_callbacks
->free_buffer(xmlbuffer
);
1633 hwloc_libxml_callbacks
->free_buffer(xmlbuffer
);
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
;
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
;
1649 parentstate
->new_child(parentstate
, &state
, "userdata");
1651 state
.new_prop(&state
, "name", name
);
1652 sprintf(tmp
, "%lu", (unsigned long) length
);
1653 state
.new_prop(&state
, "length", tmp
);
1655 state
.new_prop(&state
, "encoding", "base64");
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
;
1673 if ((name
&& hwloc__xml_export_check_buffer(name
, strlen(name
)) < 0)
1674 || hwloc__xml_export_check_buffer(buffer
, length
) < 0) {
1679 if (topology
->userdata_not_decoded
) {
1681 size_t encoded_length
;
1682 const char *realname
;
1683 if (!strncmp(name
, "base64", 6)) {
1685 encoded_length
= BASE64_ENCODED_LENGTH(length
);
1687 assert(!strncmp(name
, "normal", 6));
1689 encoded_length
= length
;
1694 assert(!strcmp(name
+6, "-anon"));
1697 hwloc__export_obj_userdata(state
, encoded
, realname
, length
, buffer
, encoded_length
);
1700 hwloc__export_obj_userdata(state
, 0, name
, length
, buffer
, length
);
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
;
1720 assert(!topology
->userdata_not_decoded
);
1722 if (name
&& hwloc__xml_export_check_buffer(name
, strlen(name
)) < 0) {
1727 encoded_length
= BASE64_ENCODED_LENGTH(length
);
1728 encoded_buffer
= malloc(encoded_length
+1);
1729 if (!encoded_buffer
) {
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
);
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 ***************************************/
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
);
1763 static struct hwloc_backend
*
1764 hwloc_xml_component_instantiate(struct hwloc_disc_component
*component
,
1769 struct hwloc_xml_backend_data_s
*data
;
1770 struct hwloc_backend
*backend
;
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
;
1778 if (!hwloc_libxml_callbacks
&& !hwloc_nolibxml_callbacks
) {
1783 if (!xmlpath
&& !xmlbuffer
) {
1788 backend
= hwloc_backend_alloc(component
);
1792 data
= malloc(sizeof(*data
));
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;
1804 local_basename
= strrchr(xmlpath
, '/');
1808 local_basename
= xmlpath
;
1810 local_basename
= "xmlbuffer";
1812 data
->msgprefix
= strdup(local_basename
);
1814 force_nolibxml
= hwloc_nolibxml_import();
1816 if (!hwloc_libxml_callbacks
|| (hwloc_nolibxml_callbacks
&& force_nolibxml
))
1817 err
= hwloc_nolibxml_callbacks
->backend_init(data
, xmlpath
, xmlbuffer
, xmlbuflen
);
1819 err
= hwloc_libxml_callbacks
->backend_init(data
, xmlpath
, xmlbuffer
, xmlbuflen
);
1820 if (err
< 0 && errno
== ENOSYS
) {
1821 hwloc_libxml_callbacks
= NULL
;
1831 free(data
->msgprefix
);
1839 static struct hwloc_disc_component hwloc_xml_disc_component
= {
1840 HWLOC_DISC_COMPONENT_TYPE_GLOBAL
,
1843 hwloc_xml_component_instantiate
,
1848 const struct hwloc_component hwloc_xml_component
= {
1849 HWLOC_COMPONENT_ABI
,
1851 HWLOC_COMPONENT_TYPE_DISC
,
1853 &hwloc_xml_disc_component