mirror of https://github.com/xzeldon/htop.git
701 lines
23 KiB
C
701 lines
23 KiB
C
|
/*
|
||
|
* Copyright © 2009 CNRS
|
||
|
* Copyright © 2009-2011 INRIA. All rights reserved.
|
||
|
* Copyright © 2009-2011 Université Bordeaux 1
|
||
|
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
|
||
|
* See COPYING in top-level directory.
|
||
|
*/
|
||
|
|
||
|
#include <private/autogen/config.h>
|
||
|
#include <hwloc.h>
|
||
|
#include <private/private.h>
|
||
|
#include <private/debug.h>
|
||
|
|
||
|
#ifdef HWLOC_HAVE_XML
|
||
|
|
||
|
#include <libxml/parser.h>
|
||
|
#include <libxml/tree.h>
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include <strings.h>
|
||
|
|
||
|
int
|
||
|
hwloc_backend_xml_init(struct hwloc_topology *topology, const char *xmlpath, const char *xmlbuffer, int buflen)
|
||
|
{
|
||
|
xmlDoc *doc = NULL;
|
||
|
|
||
|
assert(topology->backend_type == HWLOC_BACKEND_NONE);
|
||
|
|
||
|
LIBXML_TEST_VERSION;
|
||
|
|
||
|
if (xmlpath)
|
||
|
doc = xmlReadFile(xmlpath, NULL, 0);
|
||
|
else if (xmlbuffer)
|
||
|
doc = xmlReadMemory(xmlbuffer, buflen, "", NULL, 0);
|
||
|
if (!doc)
|
||
|
return -1;
|
||
|
|
||
|
topology->backend_params.xml.doc = doc;
|
||
|
topology->is_thissystem = 0;
|
||
|
topology->backend_type = HWLOC_BACKEND_XML;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
hwloc_backend_xml_exit(struct hwloc_topology *topology)
|
||
|
{
|
||
|
assert(topology->backend_type == HWLOC_BACKEND_XML);
|
||
|
xmlFreeDoc((xmlDoc*)topology->backend_params.xml.doc);
|
||
|
topology->backend_type = HWLOC_BACKEND_NONE;
|
||
|
}
|
||
|
|
||
|
/******************************
|
||
|
********* XML import *********
|
||
|
******************************/
|
||
|
|
||
|
static void hwloc__xml_import_node(struct hwloc_topology *topology, struct hwloc_obj *parent, xmlNode *node, int depth);
|
||
|
|
||
|
static const xmlChar *
|
||
|
hwloc__xml_import_attr_value(xmlAttr *attr)
|
||
|
{
|
||
|
xmlNode *subnode;
|
||
|
/* use the first valid attribute content */
|
||
|
for (subnode = attr->children; subnode; subnode = subnode->next) {
|
||
|
if (subnode->type == XML_TEXT_NODE) {
|
||
|
if (subnode->content && subnode->content[0] != '\0' && subnode->content[0] != '\n')
|
||
|
return subnode->content;
|
||
|
} else {
|
||
|
fprintf(stderr, "ignoring unexpected xml attr node type %u\n", subnode->type);
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
hwloc__xml_import_object_attr(struct hwloc_topology *topology __hwloc_attribute_unused, struct hwloc_obj *obj,
|
||
|
const xmlChar *_name, const xmlChar *_value)
|
||
|
{
|
||
|
const char *name = (const char *) _name;
|
||
|
const char *value = (const char *) _value;
|
||
|
|
||
|
if (!strcmp(name, "type")) {
|
||
|
/* already handled */
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
else if (!strcmp(name, "os_level"))
|
||
|
obj->os_level = strtoul(value, NULL, 10);
|
||
|
else if (!strcmp(name, "os_index"))
|
||
|
obj->os_index = strtoul(value, NULL, 10);
|
||
|
else if (!strcmp(name, "cpuset")) {
|
||
|
obj->cpuset = hwloc_bitmap_alloc();
|
||
|
hwloc_bitmap_sscanf(obj->cpuset, value);
|
||
|
} else if (!strcmp(name, "complete_cpuset")) {
|
||
|
obj->complete_cpuset = hwloc_bitmap_alloc();
|
||
|
hwloc_bitmap_sscanf(obj->complete_cpuset,value);
|
||
|
} else if (!strcmp(name, "online_cpuset")) {
|
||
|
obj->online_cpuset = hwloc_bitmap_alloc();
|
||
|
hwloc_bitmap_sscanf(obj->online_cpuset, value);
|
||
|
} else if (!strcmp(name, "allowed_cpuset")) {
|
||
|
obj->allowed_cpuset = hwloc_bitmap_alloc();
|
||
|
hwloc_bitmap_sscanf(obj->allowed_cpuset, value);
|
||
|
} else if (!strcmp(name, "nodeset")) {
|
||
|
obj->nodeset = hwloc_bitmap_alloc();
|
||
|
hwloc_bitmap_sscanf(obj->nodeset, value);
|
||
|
} else if (!strcmp(name, "complete_nodeset")) {
|
||
|
obj->complete_nodeset = hwloc_bitmap_alloc();
|
||
|
hwloc_bitmap_sscanf(obj->complete_nodeset, value);
|
||
|
} else if (!strcmp(name, "allowed_nodeset")) {
|
||
|
obj->allowed_nodeset = hwloc_bitmap_alloc();
|
||
|
hwloc_bitmap_sscanf(obj->allowed_nodeset, value);
|
||
|
} else if (!strcmp(name, "name"))
|
||
|
obj->name = strdup(value);
|
||
|
|
||
|
else if (!strcmp(name, "cache_size")) {
|
||
|
unsigned long long lvalue = strtoull(value, NULL, 10);
|
||
|
if (obj->type == HWLOC_OBJ_CACHE)
|
||
|
obj->attr->cache.size = lvalue;
|
||
|
else
|
||
|
fprintf(stderr, "ignoring cache_size attribute for non-cache object type\n");
|
||
|
}
|
||
|
|
||
|
else if (!strcmp(name, "cache_linesize")) {
|
||
|
unsigned long lvalue = strtoul(value, NULL, 10);
|
||
|
if (obj->type == HWLOC_OBJ_CACHE)
|
||
|
obj->attr->cache.linesize = lvalue;
|
||
|
else
|
||
|
fprintf(stderr, "ignoring cache_linesize attribute for non-cache object type\n");
|
||
|
}
|
||
|
|
||
|
else if (!strcmp(name, "local_memory"))
|
||
|
obj->memory.local_memory = strtoull(value, NULL, 10);
|
||
|
|
||
|
else if (!strcmp(name, "depth")) {
|
||
|
unsigned long lvalue = strtoul(value, NULL, 10);
|
||
|
switch (obj->type) {
|
||
|
case HWLOC_OBJ_CACHE:
|
||
|
obj->attr->cache.depth = lvalue;
|
||
|
break;
|
||
|
case HWLOC_OBJ_GROUP:
|
||
|
obj->attr->group.depth = lvalue;
|
||
|
break;
|
||
|
default:
|
||
|
fprintf(stderr, "ignoring depth attribute for object type without depth\n");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*************************
|
||
|
* deprecated (from 1.0)
|
||
|
*/
|
||
|
else if (!strcmp(name, "dmi_board_vendor")) {
|
||
|
hwloc_add_object_info(obj, "DMIBoardVendor", strdup(value));
|
||
|
}
|
||
|
else if (!strcmp(name, "dmi_board_name")) {
|
||
|
hwloc_add_object_info(obj, "DMIBoardName", strdup(value));
|
||
|
}
|
||
|
|
||
|
/*************************
|
||
|
* deprecated (from 0.9)
|
||
|
*/
|
||
|
else if (!strcmp(name, "memory_kB")) {
|
||
|
unsigned long long lvalue = strtoull(value, NULL, 10);
|
||
|
switch (obj->type) {
|
||
|
case HWLOC_OBJ_CACHE:
|
||
|
obj->attr->cache.size = lvalue << 10;
|
||
|
break;
|
||
|
case HWLOC_OBJ_NODE:
|
||
|
case HWLOC_OBJ_MACHINE:
|
||
|
case HWLOC_OBJ_SYSTEM:
|
||
|
obj->memory.local_memory = lvalue << 10;
|
||
|
break;
|
||
|
default:
|
||
|
fprintf(stderr, "ignoring memory_kB attribute for object type without memory\n");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else if (!strcmp(name, "huge_page_size_kB")) {
|
||
|
unsigned long lvalue = strtoul(value, NULL, 10);
|
||
|
switch (obj->type) {
|
||
|
case HWLOC_OBJ_NODE:
|
||
|
case HWLOC_OBJ_MACHINE:
|
||
|
case HWLOC_OBJ_SYSTEM:
|
||
|
if (!obj->memory.page_types) {
|
||
|
obj->memory.page_types = malloc(sizeof(*obj->memory.page_types));
|
||
|
obj->memory.page_types_len = 1;
|
||
|
}
|
||
|
obj->memory.page_types[0].size = lvalue << 10;
|
||
|
break;
|
||
|
default:
|
||
|
fprintf(stderr, "ignoring huge_page_size_kB attribute for object type without huge pages\n");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else if (!strcmp(name, "huge_page_free")) {
|
||
|
unsigned long lvalue = strtoul(value, NULL, 10);
|
||
|
switch (obj->type) {
|
||
|
case HWLOC_OBJ_NODE:
|
||
|
case HWLOC_OBJ_MACHINE:
|
||
|
case HWLOC_OBJ_SYSTEM:
|
||
|
if (!obj->memory.page_types) {
|
||
|
obj->memory.page_types = malloc(sizeof(*obj->memory.page_types));
|
||
|
obj->memory.page_types_len = 1;
|
||
|
}
|
||
|
obj->memory.page_types[0].count = lvalue;
|
||
|
break;
|
||
|
default:
|
||
|
fprintf(stderr, "ignoring huge_page_free attribute for object type without huge pages\n");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* end of deprecated (from 0.9)
|
||
|
*******************************/
|
||
|
|
||
|
|
||
|
|
||
|
else
|
||
|
fprintf(stderr, "ignoring unknown object attribute %s\n", name);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
hwloc__xml_import_object_node(struct hwloc_topology *topology, struct hwloc_obj *parent, struct hwloc_obj *obj, xmlNode *node, int depth)
|
||
|
{
|
||
|
xmlAttr *attr = NULL;
|
||
|
|
||
|
/* first determine the object type */
|
||
|
for (attr = node->properties; attr; attr = attr->next) {
|
||
|
if (attr->type == XML_ATTRIBUTE_NODE && !strcmp((const char*) attr->name, "type")) {
|
||
|
const xmlChar *value = hwloc__xml_import_attr_value(attr);
|
||
|
if (!value) {
|
||
|
fprintf(stderr, "ignoring xml object without type attr %s\n", (const char*) value);
|
||
|
return;
|
||
|
}
|
||
|
obj->type = hwloc_obj_type_of_string((const char*) value);
|
||
|
if (obj->type == (hwloc_obj_type_t)-1) {
|
||
|
fprintf(stderr, "ignoring unknown object type %s\n", (const char*) value);
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
} else {
|
||
|
fprintf(stderr, "ignoring unexpected xml attr type %u\n", attr->type);
|
||
|
}
|
||
|
}
|
||
|
if (obj->type == HWLOC_OBJ_TYPE_MAX) {
|
||
|
fprintf(stderr, "ignoring object without type\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* process attributes now that the type is known */
|
||
|
for (attr = node->properties; attr; attr = attr->next) {
|
||
|
if (attr->type == XML_ATTRIBUTE_NODE) {
|
||
|
const xmlChar *value = hwloc__xml_import_attr_value(attr);
|
||
|
if (value)
|
||
|
hwloc__xml_import_object_attr(topology, obj, attr->name, value);
|
||
|
} else {
|
||
|
fprintf(stderr, "ignoring unexpected xml object attr type %u\n", attr->type);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (depth > 0) { /* root object is already in place */
|
||
|
/* add object */
|
||
|
hwloc_insert_object_by_parent(topology, parent, obj);
|
||
|
}
|
||
|
|
||
|
/* process children */
|
||
|
if (node->children)
|
||
|
hwloc__xml_import_node(topology, obj, node->children, depth+1);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
hwloc__xml_import_pagetype_node(struct hwloc_topology *topology __hwloc_attribute_unused, struct hwloc_obj *obj, xmlNode *node)
|
||
|
{
|
||
|
uint64_t size = 0, count = 0;
|
||
|
xmlAttr *attr = NULL;
|
||
|
|
||
|
for (attr = node->properties; attr; attr = attr->next) {
|
||
|
if (attr->type == XML_ATTRIBUTE_NODE) {
|
||
|
const xmlChar *value = hwloc__xml_import_attr_value(attr);
|
||
|
if (value) {
|
||
|
if (!strcmp((char *) attr->name, "size"))
|
||
|
size = strtoul((char *) value, NULL, 10);
|
||
|
else if (!strcmp((char *) attr->name, "count"))
|
||
|
count = strtoul((char *) value, NULL, 10);
|
||
|
else
|
||
|
fprintf(stderr, "ignoring unknown pagetype attribute %s\n", (char *) attr->name);
|
||
|
}
|
||
|
} else {
|
||
|
fprintf(stderr, "ignoring unexpected xml pagetype attr type %u\n", attr->type);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (size) {
|
||
|
int idx = obj->memory.page_types_len;
|
||
|
obj->memory.page_types = realloc(obj->memory.page_types, (idx+1)*sizeof(*obj->memory.page_types));
|
||
|
obj->memory.page_types_len = idx+1;
|
||
|
obj->memory.page_types[idx].size = size;
|
||
|
obj->memory.page_types[idx].count = count;
|
||
|
} else
|
||
|
fprintf(stderr, "ignoring pagetype attribute without size\n");
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
hwloc__xml_import_distances_node(struct hwloc_topology *topology __hwloc_attribute_unused, struct hwloc_obj *obj, xmlNode *node)
|
||
|
{
|
||
|
unsigned long reldepth = 0, nbobjs = 0;
|
||
|
float latbase = 0;
|
||
|
xmlAttr *attr = NULL;
|
||
|
xmlNode *subnode;
|
||
|
|
||
|
for (attr = node->properties; attr; attr = attr->next) {
|
||
|
if (attr->type == XML_ATTRIBUTE_NODE) {
|
||
|
const xmlChar *value = hwloc__xml_import_attr_value(attr);
|
||
|
if (value) {
|
||
|
if (!strcmp((char *) attr->name, "nbobjs"))
|
||
|
nbobjs = strtoul((char *) value, NULL, 10);
|
||
|
else if (!strcmp((char *) attr->name, "relative_depth"))
|
||
|
reldepth = strtoul((char *) value, NULL, 10);
|
||
|
else if (!strcmp((char *) attr->name, "latency_base"))
|
||
|
latbase = (float) atof((char *) value);
|
||
|
else
|
||
|
fprintf(stderr, "ignoring unknown distances attribute %s\n", (char *) attr->name);
|
||
|
} else
|
||
|
fprintf(stderr, "ignoring unexpected xml distances attr name `%s' with no value\n", (const char*) attr->name);
|
||
|
} else {
|
||
|
fprintf(stderr, "ignoring unexpected xml distances attr type %u\n", attr->type);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (nbobjs && reldepth && latbase) {
|
||
|
int idx = obj->distances_count;
|
||
|
unsigned nbcells, i;
|
||
|
float *matrix, latmax = 0;
|
||
|
|
||
|
nbcells = 0;
|
||
|
if (node->children)
|
||
|
for(subnode = node->children; subnode; subnode = subnode->next)
|
||
|
if (subnode->type == XML_ELEMENT_NODE)
|
||
|
nbcells++;
|
||
|
if (nbcells != nbobjs*nbobjs) {
|
||
|
fprintf(stderr, "ignoring distances with %u cells instead of %lu\n", nbcells, nbobjs*nbobjs);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
obj->distances = realloc(obj->distances, (idx+1)*sizeof(*obj->distances));
|
||
|
obj->distances_count = idx+1;
|
||
|
obj->distances[idx] = malloc(sizeof(**obj->distances));
|
||
|
obj->distances[idx]->relative_depth = reldepth;
|
||
|
obj->distances[idx]->nbobjs = nbobjs;
|
||
|
obj->distances[idx]->latency = matrix = malloc(nbcells*sizeof(float));
|
||
|
obj->distances[idx]->latency_base = latbase;
|
||
|
|
||
|
i = 0;
|
||
|
for(subnode = node->children; subnode; subnode = subnode->next)
|
||
|
if (subnode->type == XML_ELEMENT_NODE) {
|
||
|
/* read one cell */
|
||
|
for (attr = subnode->properties; attr; attr = attr->next)
|
||
|
if (attr->type == XML_ATTRIBUTE_NODE) {
|
||
|
const xmlChar *value = hwloc__xml_import_attr_value(attr);
|
||
|
if (value) {
|
||
|
if (!strcmp((char *) attr->name, "value")) {
|
||
|
float val = (float) atof((char *) value);
|
||
|
matrix[i] = val;
|
||
|
if (val > latmax)
|
||
|
latmax = val;
|
||
|
} else
|
||
|
fprintf(stderr, "ignoring unknown distance attribute %s\n", (char *) attr->name);
|
||
|
} else
|
||
|
fprintf(stderr, "ignoring unexpected xml distance attr name `%s' with no value\n", (const char*) attr->name);
|
||
|
} else {
|
||
|
fprintf(stderr, "ignoring unexpected xml distance attr type %u\n", attr->type);
|
||
|
}
|
||
|
/* next matrix cell */
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
obj->distances[idx]->latency_max = latmax;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
hwloc__xml_import_info_node(struct hwloc_topology *topology __hwloc_attribute_unused, struct hwloc_obj *obj, xmlNode *node)
|
||
|
{
|
||
|
char *infoname = NULL;
|
||
|
char *infovalue = NULL;
|
||
|
xmlAttr *attr = NULL;
|
||
|
|
||
|
for (attr = node->properties; attr; attr = attr->next) {
|
||
|
if (attr->type == XML_ATTRIBUTE_NODE) {
|
||
|
const xmlChar *value = hwloc__xml_import_attr_value(attr);
|
||
|
if (value) {
|
||
|
if (!strcmp((char *) attr->name, "name"))
|
||
|
infoname = (char *) value;
|
||
|
else if (!strcmp((char *) attr->name, "value"))
|
||
|
infovalue = (char *) value;
|
||
|
else
|
||
|
fprintf(stderr, "ignoring unknown info attribute %s\n", (char *) attr->name);
|
||
|
}
|
||
|
} else {
|
||
|
fprintf(stderr, "ignoring unexpected xml info attr type %u\n", attr->type);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (infoname)
|
||
|
/* empty strings are ignored by libxml */
|
||
|
hwloc_add_object_info(obj, infoname, infovalue ? infovalue : "");
|
||
|
else
|
||
|
fprintf(stderr, "ignoring info attribute without name\n");
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
hwloc__xml_import_node(struct hwloc_topology *topology, struct hwloc_obj *parent, xmlNode *node, int depth)
|
||
|
{
|
||
|
for (; node; node = node->next) {
|
||
|
if (node->type == XML_ELEMENT_NODE) {
|
||
|
if (!strcmp((const char*) node->name, "object")) {
|
||
|
/* object attributes */
|
||
|
struct hwloc_obj *obj;
|
||
|
if (depth)
|
||
|
obj = hwloc_alloc_setup_object(HWLOC_OBJ_TYPE_MAX, -1);
|
||
|
else
|
||
|
obj = topology->levels[0][0];
|
||
|
hwloc__xml_import_object_node(topology, parent, obj, node, depth);
|
||
|
|
||
|
} else if (!strcmp((const char*) node->name, "page_type")) {
|
||
|
hwloc__xml_import_pagetype_node(topology, parent, node);
|
||
|
|
||
|
} else if (!strcmp((const char*) node->name, "info")) {
|
||
|
hwloc__xml_import_info_node(topology, parent, node);
|
||
|
|
||
|
} else if (!strcmp((const char*) node->name, "distances")) {
|
||
|
hwloc__xml_import_distances_node(topology, parent, node);
|
||
|
|
||
|
} else {
|
||
|
/* unknown class */
|
||
|
fprintf(stderr, "ignoring unexpected node class `%s'\n", (const char*) node->name);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
} else if (node->type == XML_TEXT_NODE) {
|
||
|
if (node->content && node->content[0] != '\0' && node->content[0] != '\n')
|
||
|
fprintf(stderr, "ignoring object text content %s\n", (const char*) node->content);
|
||
|
} else {
|
||
|
fprintf(stderr, "ignoring unexpected xml node type %u\n", node->type);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
hwloc__xml_import_topology_node(struct hwloc_topology *topology, xmlNode *node)
|
||
|
{
|
||
|
xmlAttr *attr = NULL;
|
||
|
|
||
|
if (strcmp((const char *) node->name, "topology") && strcmp((const char *) node->name, "root")) {
|
||
|
/* root node should be in "topology" class (or "root" if importing from < 1.0) */
|
||
|
fprintf(stderr, "ignoring object of class `%s' not at the top the xml hierarchy\n", (const char *) node->name);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* process attributes */
|
||
|
for (attr = node->properties; attr; attr = attr->next) {
|
||
|
if (attr->type == XML_ATTRIBUTE_NODE) {
|
||
|
const xmlChar *value = hwloc__xml_import_attr_value(attr);
|
||
|
if (value) {
|
||
|
fprintf(stderr, "ignoring unknown root attribute %s\n", (char *) attr->name);
|
||
|
}
|
||
|
} else {
|
||
|
fprintf(stderr, "ignoring unexpected xml root attr type %u\n", attr->type);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* process children */
|
||
|
if (node->children)
|
||
|
hwloc__xml_import_node(topology, NULL, node->children, 0);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
hwloc_look_xml(struct hwloc_topology *topology)
|
||
|
{
|
||
|
xmlNode* root_node;
|
||
|
xmlDtd *dtd;
|
||
|
|
||
|
topology->support.discovery->pu = 1;
|
||
|
|
||
|
dtd = xmlGetIntSubset((xmlDoc*) topology->backend_params.xml.doc);
|
||
|
if (!dtd)
|
||
|
fprintf(stderr, "Loading XML topology without DTD\n");
|
||
|
else if (strcmp((char *) dtd->SystemID, "hwloc.dtd"))
|
||
|
fprintf(stderr, "Loading XML topology with wrong DTD SystemID (%s instead of %s)\n",
|
||
|
(char *) dtd->SystemID, "hwloc.dtd");
|
||
|
|
||
|
root_node = xmlDocGetRootElement((xmlDoc*) topology->backend_params.xml.doc);
|
||
|
|
||
|
hwloc__xml_import_topology_node(topology, root_node);
|
||
|
if (root_node->next)
|
||
|
fprintf(stderr, "ignoring non-first root nodes\n");
|
||
|
|
||
|
/* keep the "Backend" information intact */
|
||
|
/* we could add "BackendSource=XML" to notify that XML was used between the actual backend and here */
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
hwloc_xml__check_distances(struct hwloc_topology *topology, hwloc_obj_t obj)
|
||
|
{
|
||
|
hwloc_obj_t child;
|
||
|
unsigned i=0;
|
||
|
while (i<obj->distances_count) {
|
||
|
unsigned depth = obj->depth + obj->distances[i]->relative_depth;
|
||
|
unsigned nbobjs = hwloc_get_nbobjs_inside_cpuset_by_depth(topology, obj->cpuset, depth);
|
||
|
if (nbobjs != obj->distances[i]->nbobjs) {
|
||
|
fprintf(stderr, "ignoring invalid distance matrix with %u objs instead of %u\n",
|
||
|
obj->distances[i]->nbobjs, nbobjs);
|
||
|
hwloc_free_logical_distances(obj->distances[i]);
|
||
|
memmove(&obj->distances[i], &obj->distances[i+1], (obj->distances_count-i-1)*sizeof(*obj->distances));
|
||
|
obj->distances_count--;
|
||
|
} else
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
child = obj->first_child;
|
||
|
while (child != NULL) {
|
||
|
hwloc_xml__check_distances(topology, child);
|
||
|
child = child->next_sibling;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
hwloc_xml_check_distances(struct hwloc_topology *topology)
|
||
|
{
|
||
|
/* now that the topology tree has been properly setup,
|
||
|
* check that our distance matrice sizes make sense */
|
||
|
hwloc_xml__check_distances(topology, topology->levels[0][0]);
|
||
|
}
|
||
|
|
||
|
/******************************
|
||
|
********* XML export *********
|
||
|
******************************/
|
||
|
|
||
|
static void
|
||
|
hwloc__xml_export_object (hwloc_topology_t topology, hwloc_obj_t obj, xmlNodePtr root_node)
|
||
|
{
|
||
|
xmlNodePtr node = NULL, ptnode = NULL, dnode = NULL, dcnode = NULL;
|
||
|
char *cpuset = NULL;
|
||
|
char tmp[255];
|
||
|
unsigned i;
|
||
|
|
||
|
/* xmlNewChild() creates a new node, which is "attached" as child node
|
||
|
* of root_node node. */
|
||
|
node = xmlNewChild(root_node, NULL, BAD_CAST "object", NULL);
|
||
|
xmlNewProp(node, BAD_CAST "type", BAD_CAST hwloc_obj_type_string(obj->type));
|
||
|
sprintf(tmp, "%d", obj->os_level);
|
||
|
xmlNewProp(node, BAD_CAST "os_level", BAD_CAST tmp);
|
||
|
if (obj->os_index != (unsigned) -1) {
|
||
|
sprintf(tmp, "%u", obj->os_index);
|
||
|
xmlNewProp(node, BAD_CAST "os_index", BAD_CAST tmp);
|
||
|
}
|
||
|
if (obj->cpuset) {
|
||
|
hwloc_bitmap_asprintf(&cpuset, obj->cpuset);
|
||
|
xmlNewProp(node, BAD_CAST "cpuset", BAD_CAST cpuset);
|
||
|
free(cpuset);
|
||
|
}
|
||
|
if (obj->complete_cpuset) {
|
||
|
hwloc_bitmap_asprintf(&cpuset, obj->complete_cpuset);
|
||
|
xmlNewProp(node, BAD_CAST "complete_cpuset", BAD_CAST cpuset);
|
||
|
free(cpuset);
|
||
|
}
|
||
|
if (obj->online_cpuset) {
|
||
|
hwloc_bitmap_asprintf(&cpuset, obj->online_cpuset);
|
||
|
xmlNewProp(node, BAD_CAST "online_cpuset", BAD_CAST cpuset);
|
||
|
free(cpuset);
|
||
|
}
|
||
|
if (obj->allowed_cpuset) {
|
||
|
hwloc_bitmap_asprintf(&cpuset, obj->allowed_cpuset);
|
||
|
xmlNewProp(node, BAD_CAST "allowed_cpuset", BAD_CAST cpuset);
|
||
|
free(cpuset);
|
||
|
}
|
||
|
if (obj->nodeset && !hwloc_bitmap_isfull(obj->nodeset)) {
|
||
|
hwloc_bitmap_asprintf(&cpuset, obj->nodeset);
|
||
|
xmlNewProp(node, BAD_CAST "nodeset", BAD_CAST cpuset);
|
||
|
free(cpuset);
|
||
|
}
|
||
|
if (obj->complete_nodeset && !hwloc_bitmap_isfull(obj->complete_nodeset)) {
|
||
|
hwloc_bitmap_asprintf(&cpuset, obj->complete_nodeset);
|
||
|
xmlNewProp(node, BAD_CAST "complete_nodeset", BAD_CAST cpuset);
|
||
|
free(cpuset);
|
||
|
}
|
||
|
if (obj->allowed_nodeset && !hwloc_bitmap_isfull(obj->allowed_nodeset)) {
|
||
|
hwloc_bitmap_asprintf(&cpuset, obj->allowed_nodeset);
|
||
|
xmlNewProp(node, BAD_CAST "allowed_nodeset", BAD_CAST cpuset);
|
||
|
free(cpuset);
|
||
|
}
|
||
|
|
||
|
if (obj->name)
|
||
|
xmlNewProp(node, BAD_CAST "name", BAD_CAST obj->name);
|
||
|
|
||
|
switch (obj->type) {
|
||
|
case HWLOC_OBJ_CACHE:
|
||
|
sprintf(tmp, "%llu", (unsigned long long) obj->attr->cache.size);
|
||
|
xmlNewProp(node, BAD_CAST "cache_size", BAD_CAST tmp);
|
||
|
sprintf(tmp, "%u", obj->attr->cache.depth);
|
||
|
xmlNewProp(node, BAD_CAST "depth", BAD_CAST tmp);
|
||
|
sprintf(tmp, "%u", (unsigned) obj->attr->cache.linesize);
|
||
|
xmlNewProp(node, BAD_CAST "cache_linesize", BAD_CAST tmp);
|
||
|
break;
|
||
|
case HWLOC_OBJ_GROUP:
|
||
|
sprintf(tmp, "%u", obj->attr->group.depth);
|
||
|
xmlNewProp(node, BAD_CAST "depth", BAD_CAST tmp);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (obj->memory.local_memory) {
|
||
|
sprintf(tmp, "%llu", (unsigned long long) obj->memory.local_memory);
|
||
|
xmlNewProp(node, BAD_CAST "local_memory", BAD_CAST tmp);
|
||
|
}
|
||
|
for(i=0; i<obj->memory.page_types_len; i++) {
|
||
|
ptnode = xmlNewChild(node, NULL, BAD_CAST "page_type", NULL);
|
||
|
sprintf(tmp, "%llu", (unsigned long long) obj->memory.page_types[i].size);
|
||
|
xmlNewProp(ptnode, BAD_CAST "size", BAD_CAST tmp);
|
||
|
sprintf(tmp, "%llu", (unsigned long long) obj->memory.page_types[i].count);
|
||
|
xmlNewProp(ptnode, BAD_CAST "count", BAD_CAST tmp);
|
||
|
}
|
||
|
|
||
|
for(i=0; i<obj->infos_count; i++) {
|
||
|
ptnode = xmlNewChild(node, NULL, BAD_CAST "info", NULL);
|
||
|
xmlNewProp(ptnode, BAD_CAST "name", BAD_CAST obj->infos[i].name);
|
||
|
xmlNewProp(ptnode, BAD_CAST "value", BAD_CAST obj->infos[i].value);
|
||
|
}
|
||
|
|
||
|
for(i=0; i<obj->distances_count; i++) {
|
||
|
unsigned nbobjs = obj->distances[i]->nbobjs;
|
||
|
unsigned j;
|
||
|
dnode = xmlNewChild(node, NULL, BAD_CAST "distances", NULL);
|
||
|
sprintf(tmp, "%u", nbobjs);
|
||
|
xmlNewProp(dnode, BAD_CAST "nbobjs", BAD_CAST tmp);
|
||
|
sprintf(tmp, "%u", obj->distances[i]->relative_depth);
|
||
|
xmlNewProp(dnode, BAD_CAST "relative_depth", BAD_CAST tmp);
|
||
|
sprintf(tmp, "%f", obj->distances[i]->latency_base);
|
||
|
xmlNewProp(dnode, BAD_CAST "latency_base", BAD_CAST tmp);
|
||
|
for(j=0; j<nbobjs*nbobjs; j++) {
|
||
|
dcnode = xmlNewChild(dnode, NULL, BAD_CAST "latency", NULL);
|
||
|
sprintf(tmp, "%f", obj->distances[i]->latency[j]);
|
||
|
xmlNewProp(dcnode, BAD_CAST "value", BAD_CAST tmp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (obj->arity) {
|
||
|
unsigned x;
|
||
|
for (x=0; x<obj->arity; x++)
|
||
|
hwloc__xml_export_object (topology, obj->children[x], node);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
hwloc__xml_export_topology_info (hwloc_topology_t topology __hwloc_attribute_unused, xmlNodePtr root_node __hwloc_attribute_unused)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
static xmlDocPtr
|
||
|
hwloc__topology_prepare_export(hwloc_topology_t topology)
|
||
|
{
|
||
|
xmlDocPtr doc = NULL; /* document pointer */
|
||
|
xmlNodePtr root_node = NULL; /* root pointer */
|
||
|
xmlDtdPtr dtd = NULL; /* DTD pointer */
|
||
|
|
||
|
LIBXML_TEST_VERSION;
|
||
|
|
||
|
/* Creates a new document, a node and set it as a root node. */
|
||
|
doc = xmlNewDoc(BAD_CAST "1.0");
|
||
|
root_node = xmlNewNode(NULL, BAD_CAST "topology");
|
||
|
xmlDocSetRootElement(doc, root_node);
|
||
|
|
||
|
/* Creates a DTD declaration. Isn't mandatory. */
|
||
|
dtd = xmlCreateIntSubset(doc, BAD_CAST "topology", NULL, BAD_CAST "hwloc.dtd");
|
||
|
|
||
|
hwloc__xml_export_object (topology, hwloc_get_root_obj(topology), root_node);
|
||
|
|
||
|
hwloc__xml_export_topology_info (topology, root_node);
|
||
|
|
||
|
return doc;
|
||
|
}
|
||
|
|
||
|
void hwloc_topology_export_xml(hwloc_topology_t topology, const char *filename)
|
||
|
{
|
||
|
xmlDocPtr doc = hwloc__topology_prepare_export(topology);
|
||
|
xmlSaveFormatFileEnc(filename, doc, "UTF-8", 1);
|
||
|
xmlFreeDoc(doc);
|
||
|
}
|
||
|
|
||
|
void hwloc_topology_export_xmlbuffer(hwloc_topology_t topology, char **xmlbuffer, int *buflen)
|
||
|
{
|
||
|
xmlDocPtr doc = hwloc__topology_prepare_export(topology);
|
||
|
xmlDocDumpFormatMemoryEnc(doc, (xmlChar **)xmlbuffer, buflen, "UTF-8", 1);
|
||
|
xmlFreeDoc(doc);
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif /* HWLOC_HAVE_XML */
|