summaryrefslogtreecommitdiffstats
path: root/hwloc-1.2.1/src/topology.c
diff options
context:
space:
mode:
Diffstat (limited to 'hwloc-1.2.1/src/topology.c')
-rw-r--r--hwloc-1.2.1/src/topology.c2468
1 files changed, 2468 insertions, 0 deletions
diff --git a/hwloc-1.2.1/src/topology.c b/hwloc-1.2.1/src/topology.c
new file mode 100644
index 00000000..9c5ecd2e
--- /dev/null
+++ b/hwloc-1.2.1/src/topology.c
@@ -0,0 +1,2468 @@
+/*
+ * Copyright © 2009 CNRS
+ * Copyright © 2009-2011 INRIA. All rights reserved.
+ * Copyright © 2009-2010 Université Bordeaux 1
+ * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
+ * See COPYING in top-level directory.
+ */
+
+#include <private/autogen/config.h>
+
+#define _ATFILE_SOURCE
+#include <assert.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <float.h>
+
+#include <hwloc.h>
+#include <private/private.h>
+#include <private/debug.h>
+
+#ifdef HAVE_MACH_MACH_INIT_H
+#include <mach/mach_init.h>
+#endif
+#ifdef HAVE_MACH_MACH_HOST_H
+#include <mach/mach_host.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+
+#ifdef HWLOC_WIN_SYS
+#include <windows.h>
+#endif
+
+unsigned hwloc_get_api_version(void)
+{
+ return HWLOC_API_VERSION;
+}
+
+void hwloc_report_os_error(const char *msg, int line)
+{
+ static int reported = 0;
+
+ if (!reported) {
+ fprintf(stderr, "****************************************************************************\n");
+ fprintf(stderr, "* Hwloc has encountered what looks like an error from the operating system.\n");
+ fprintf(stderr, "*\n");
+ fprintf(stderr, "* %s\n", msg);
+ fprintf(stderr, "* Error occurred in topology.c line %d\n", line);
+ fprintf(stderr, "*\n");
+ fprintf(stderr, "* Please report this error message to the hwloc user's mailing list,\n");
+ fprintf(stderr, "* along with the output from the hwloc-gather-topology.sh script.\n");
+ fprintf(stderr, "****************************************************************************\n");
+ reported = 1;
+ }
+}
+
+static void
+hwloc_topology_clear (struct hwloc_topology *topology);
+
+#if defined(HAVE_SYSCTLBYNAME)
+int hwloc_get_sysctlbyname(const char *name, int64_t *ret)
+{
+ union {
+ int32_t i32;
+ int64_t i64;
+ } n;
+ size_t size = sizeof(n);
+ if (sysctlbyname(name, &n, &size, NULL, 0))
+ return -1;
+ switch (size) {
+ case sizeof(n.i32):
+ *ret = n.i32;
+ break;
+ case sizeof(n.i64):
+ *ret = n.i64;
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+#if defined(HAVE_SYSCTL)
+int hwloc_get_sysctl(int name[], unsigned namelen, int *ret)
+{
+ int n;
+ size_t size = sizeof(n);
+ if (sysctl(name, namelen, &n, &size, NULL, 0))
+ return -1;
+ if (size != sizeof(n))
+ return -1;
+ *ret = n;
+ return 0;
+}
+#endif
+
+/* Return the OS-provided number of processors. Unlike other methods such as
+ reading sysfs on Linux, this method is not virtualizable; thus it's only
+ used as a fall-back method, allowing `hwloc_set_fsroot ()' to
+ have the desired effect. */
+unsigned
+hwloc_fallback_nbprocessors(struct hwloc_topology *topology) {
+ int n;
+#if HAVE_DECL__SC_NPROCESSORS_ONLN
+ n = sysconf(_SC_NPROCESSORS_ONLN);
+#elif HAVE_DECL__SC_NPROC_ONLN
+ n = sysconf(_SC_NPROC_ONLN);
+#elif HAVE_DECL__SC_NPROCESSORS_CONF
+ n = sysconf(_SC_NPROCESSORS_CONF);
+#elif HAVE_DECL__SC_NPROC_CONF
+ n = sysconf(_SC_NPROC_CONF);
+#elif defined(HAVE_HOST_INFO) && HAVE_HOST_INFO
+ struct host_basic_info info;
+ mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
+ host_info(mach_host_self(), HOST_BASIC_INFO, (integer_t*) &info, &count);
+ n = info.avail_cpus;
+#elif defined(HAVE_SYSCTLBYNAME)
+ int64_t n;
+ if (hwloc_get_sysctlbyname("hw.ncpu", &n))
+ n = -1;
+#elif defined(HAVE_SYSCTL) && HAVE_DECL_CTL_HW && HAVE_DECL_HW_NCPU
+ static int name[2] = {CTL_HW, HW_NPCU};
+ if (hwloc_get_sysctl(name, sizeof(name)/sizeof(*name)), &n)
+ n = -1;
+#elif defined(HWLOC_WIN_SYS)
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ n = sysinfo.dwNumberOfProcessors;
+#else
+#ifdef __GNUC__
+#warning No known way to discover number of available processors on this system
+#warning hwloc_fallback_nbprocessors will default to 1
+#endif
+ n = -1;
+#endif
+ if (n >= 1)
+ topology->support.discovery->pu = 1;
+ else
+ n = 1;
+ return n;
+}
+
+/*
+ * Use the given number of processors and the optional online cpuset if given
+ * to set a PU level.
+ */
+void
+hwloc_setup_pu_level(struct hwloc_topology *topology,
+ unsigned nb_pus)
+{
+ struct hwloc_obj *obj;
+ unsigned oscpu,cpu;
+
+ hwloc_debug("%s", "\n\n * CPU cpusets *\n\n");
+ for (cpu=0,oscpu=0; cpu<nb_pus; oscpu++)
+ {
+ obj = hwloc_alloc_setup_object(HWLOC_OBJ_PU, oscpu);
+ obj->cpuset = hwloc_bitmap_alloc();
+ hwloc_bitmap_only(obj->cpuset, oscpu);
+
+ hwloc_debug_2args_bitmap("cpu %u (os %u) has cpuset %s\n",
+ cpu, oscpu, obj->cpuset);
+ hwloc_insert_object_by_cpuset(topology, obj);
+
+ cpu++;
+ }
+}
+
+static void
+print_object(struct hwloc_topology *topology, int indent __hwloc_attribute_unused, hwloc_obj_t obj)
+{
+ char line[256], *cpuset = NULL;
+ hwloc_debug("%*s", 2*indent, "");
+ hwloc_obj_snprintf(line, sizeof(line), topology, obj, "#", 1);
+ hwloc_debug("%s", line);
+ if (obj->cpuset) {
+ hwloc_bitmap_asprintf(&cpuset, obj->cpuset);
+ hwloc_debug(" cpuset %s", cpuset);
+ free(cpuset);
+ }
+ if (obj->complete_cpuset) {
+ hwloc_bitmap_asprintf(&cpuset, obj->complete_cpuset);
+ hwloc_debug(" complete %s", cpuset);
+ free(cpuset);
+ }
+ if (obj->online_cpuset) {
+ hwloc_bitmap_asprintf(&cpuset, obj->online_cpuset);
+ hwloc_debug(" online %s", cpuset);
+ free(cpuset);
+ }
+ if (obj->allowed_cpuset) {
+ hwloc_bitmap_asprintf(&cpuset, obj->allowed_cpuset);
+ hwloc_debug(" allowed %s", cpuset);
+ free(cpuset);
+ }
+ if (obj->nodeset) {
+ hwloc_bitmap_asprintf(&cpuset, obj->nodeset);
+ hwloc_debug(" nodeset %s", cpuset);
+ free(cpuset);
+ }
+ if (obj->complete_nodeset) {
+ hwloc_bitmap_asprintf(&cpuset, obj->complete_nodeset);
+ hwloc_debug(" completeN %s", cpuset);
+ free(cpuset);
+ }
+ if (obj->allowed_nodeset) {
+ hwloc_bitmap_asprintf(&cpuset, obj->allowed_nodeset);
+ hwloc_debug(" allowedN %s", cpuset);
+ free(cpuset);
+ }
+ if (obj->arity)
+ hwloc_debug(" arity %u", obj->arity);
+ hwloc_debug("%s", "\n");
+}
+
+/* Just for debugging. */
+static void
+print_objects(struct hwloc_topology *topology __hwloc_attribute_unused, int indent __hwloc_attribute_unused, hwloc_obj_t obj __hwloc_attribute_unused)
+{
+#ifdef HWLOC_DEBUG
+ print_object(topology, indent, obj);
+ for (obj = obj->first_child; obj; obj = obj->next_sibling)
+ print_objects(topology, indent + 1, obj);
+#endif
+}
+
+void
+hwloc_add_object_info(hwloc_obj_t obj, const char *name, const char *value)
+{
+#define OBJECT_INFO_ALLOC 8
+ /* nothing allocated initially, (re-)allocate by multiple of 8 */
+ unsigned alloccount = (obj->infos_count + 1 + (OBJECT_INFO_ALLOC-1)) & ~(OBJECT_INFO_ALLOC-1);
+ if (obj->infos_count != alloccount)
+ obj->infos = realloc(obj->infos, alloccount*sizeof(*obj->infos));
+ obj->infos[obj->infos_count].name = strdup(name);
+ obj->infos[obj->infos_count].value = strdup(value);
+ obj->infos_count++;
+}
+
+static void
+hwloc_clear_object_distances(hwloc_obj_t obj)
+{
+ unsigned i;
+ for (i=0; i<obj->distances_count; i++)
+ hwloc_free_logical_distances(obj->distances[i]);
+ free(obj->distances);
+ obj->distances = NULL;
+ obj->distances_count = 0;
+}
+
+/* Free an object and all its content. */
+void
+hwloc_free_unlinked_object(hwloc_obj_t obj)
+{
+ unsigned i;
+ switch (obj->type) {
+ default:
+ break;
+ }
+ for(i=0; i<obj->infos_count; i++) {
+ free(obj->infos[i].name);
+ free(obj->infos[i].value);
+ }
+ free(obj->infos);
+ hwloc_clear_object_distances(obj);
+ free(obj->memory.page_types);
+ free(obj->attr);
+ free(obj->children);
+ free(obj->name);
+ hwloc_bitmap_free(obj->cpuset);
+ hwloc_bitmap_free(obj->complete_cpuset);
+ hwloc_bitmap_free(obj->online_cpuset);
+ hwloc_bitmap_free(obj->allowed_cpuset);
+ hwloc_bitmap_free(obj->nodeset);
+ hwloc_bitmap_free(obj->complete_nodeset);
+ hwloc_bitmap_free(obj->allowed_nodeset);
+ free(obj);
+}
+
+/*
+ * How to compare objects based on types.
+ *
+ * Note that HIGHER/LOWER is only a (consistent) heuristic, used to sort
+ * objects with same cpuset consistently.
+ * Only EQUAL / not EQUAL can be relied upon.
+ */
+
+enum hwloc_type_cmp_e {
+ HWLOC_TYPE_HIGHER,
+ HWLOC_TYPE_DEEPER,
+ HWLOC_TYPE_EQUAL
+};
+
+/* WARNING: The indexes of this array MUST match the ordering that of
+ the obj_order_type[] array, below. Specifically, the values must
+ be laid out such that:
+
+ obj_order_type[obj_type_order[N]] = N
+
+ for all HWLOC_OBJ_* values of N. Put differently:
+
+ obj_type_order[A] = B
+
+ where the A values are in order of the hwloc_obj_type_t enum, and
+ the B values are the corresponding indexes of obj_order_type.
+
+ We can't use C99 syntax to initialize this in a little safer manner
+ -- bummer. :-(
+
+ *************************************************************
+ *** DO NOT CHANGE THE ORDERING OF THIS ARRAY WITHOUT TRIPLE
+ *** CHECKING ITS CORRECTNESS!
+ *************************************************************
+ */
+static unsigned obj_type_order[] = {
+ /* first entry is HWLOC_OBJ_SYSTEM */ 0,
+ /* next entry is HWLOC_OBJ_MACHINE */ 1,
+ /* next entry is HWLOC_OBJ_NODE */ 3,
+ /* next entry is HWLOC_OBJ_SOCKET */ 4,
+ /* next entry is HWLOC_OBJ_CACHE */ 5,
+ /* next entry is HWLOC_OBJ_CORE */ 6,
+ /* next entry is HWLOC_OBJ_PU */ 7,
+ /* next entry is HWLOC_OBJ_GROUP */ 2,
+ /* next entry is HWLOC_OBJ_MISC */ 8,
+};
+
+static const hwloc_obj_type_t obj_order_type[] = {
+ HWLOC_OBJ_SYSTEM,
+ HWLOC_OBJ_MACHINE,
+ HWLOC_OBJ_GROUP,
+ HWLOC_OBJ_NODE,
+ HWLOC_OBJ_SOCKET,
+ HWLOC_OBJ_CACHE,
+ HWLOC_OBJ_CORE,
+ HWLOC_OBJ_PU,
+ HWLOC_OBJ_MISC,
+};
+
+static unsigned __hwloc_attribute_const
+hwloc_get_type_order(hwloc_obj_type_t type)
+{
+ return obj_type_order[type];
+}
+
+#if !defined(NDEBUG)
+static hwloc_obj_type_t hwloc_get_order_type(int order)
+{
+ return obj_order_type[order];
+}
+#endif
+
+int hwloc_compare_types (hwloc_obj_type_t type1, hwloc_obj_type_t type2)
+{
+ unsigned order1 = hwloc_get_type_order(type1);
+ unsigned order2 = hwloc_get_type_order(type2);
+ return order1 - order2;
+}
+
+static enum hwloc_type_cmp_e
+hwloc_type_cmp(hwloc_obj_t obj1, hwloc_obj_t obj2)
+{
+ if (hwloc_compare_types(obj1->type, obj2->type) > 0)
+ return HWLOC_TYPE_DEEPER;
+ if (hwloc_compare_types(obj1->type, obj2->type) < 0)
+ return HWLOC_TYPE_HIGHER;
+
+ /* Caches have the same types but can have different depths. */
+ if (obj1->type == HWLOC_OBJ_CACHE) {
+ if (obj1->attr->cache.depth < obj2->attr->cache.depth)
+ return HWLOC_TYPE_DEEPER;
+ else if (obj1->attr->cache.depth > obj2->attr->cache.depth)
+ return HWLOC_TYPE_HIGHER;
+ }
+
+ /* Group objects have the same types but can have different depths. */
+ if (obj1->type == HWLOC_OBJ_GROUP) {
+ if (obj1->attr->group.depth < obj2->attr->group.depth)
+ return HWLOC_TYPE_DEEPER;
+ else if (obj1->attr->group.depth > obj2->attr->group.depth)
+ return HWLOC_TYPE_HIGHER;
+ }
+
+ return HWLOC_TYPE_EQUAL;
+}
+
+/*
+ * How to compare objects based on cpusets.
+ */
+
+enum hwloc_obj_cmp_e {
+ HWLOC_OBJ_EQUAL, /**< \brief Equal */
+ HWLOC_OBJ_INCLUDED, /**< \brief Strictly included into */
+ HWLOC_OBJ_CONTAINS, /**< \brief Strictly contains */
+ HWLOC_OBJ_INTERSECTS, /**< \brief Intersects, but no inclusion! */
+ HWLOC_OBJ_DIFFERENT /**< \brief No intersection */
+};
+
+static int
+hwloc_obj_cmp(hwloc_obj_t obj1, hwloc_obj_t obj2)
+{
+ if (!obj1->cpuset || hwloc_bitmap_iszero(obj1->cpuset)
+ || !obj2->cpuset || hwloc_bitmap_iszero(obj2->cpuset))
+ return HWLOC_OBJ_DIFFERENT;
+
+ if (hwloc_bitmap_isequal(obj1->cpuset, obj2->cpuset)) {
+
+ /* Same cpuset, subsort by type to have a consistent ordering. */
+
+ switch (hwloc_type_cmp(obj1, obj2)) {
+ case HWLOC_TYPE_DEEPER:
+ return HWLOC_OBJ_INCLUDED;
+ case HWLOC_TYPE_HIGHER:
+ return HWLOC_OBJ_CONTAINS;
+
+ case HWLOC_TYPE_EQUAL:
+ if (obj1->type == HWLOC_OBJ_MISC) {
+ /* Misc objects may vary by name */
+ int res = strcmp(obj1->name, obj2->name);
+ if (res < 0)
+ return HWLOC_OBJ_INCLUDED;
+ if (res > 0)
+ return HWLOC_OBJ_CONTAINS;
+ if (res == 0)
+ return HWLOC_OBJ_EQUAL;
+ }
+
+ /* Same level cpuset and type! Let's hope it's coherent. */
+ return HWLOC_OBJ_EQUAL;
+ }
+
+ /* For dumb compilers */
+ abort();
+
+ } else {
+
+ /* Different cpusets, sort by inclusion. */
+
+ if (hwloc_bitmap_isincluded(obj1->cpuset, obj2->cpuset))
+ return HWLOC_OBJ_INCLUDED;
+
+ if (hwloc_bitmap_isincluded(obj2->cpuset, obj1->cpuset))
+ return HWLOC_OBJ_CONTAINS;
+
+ if (hwloc_bitmap_intersects(obj1->cpuset, obj2->cpuset))
+ return HWLOC_OBJ_INTERSECTS;
+
+ return HWLOC_OBJ_DIFFERENT;
+ }
+}
+
+/*
+ * How to insert objects into the topology.
+ *
+ * Note: during detection, only the first_child and next_sibling pointers are
+ * kept up to date. Others are computed only once topology detection is
+ * complete.
+ */
+
+#define merge_index(new, old, field, type) \
+ if ((old)->field == (type) -1) \
+ (old)->field = (new)->field;
+#define merge_sizes(new, old, field) \
+ if (!(old)->field) \
+ (old)->field = (new)->field;
+#ifdef HWLOC_DEBUG
+#define check_sizes(new, old, field) \
+ if ((new)->field) \
+ assert((old)->field == (new)->field)
+#else
+#define check_sizes(new, old, field)
+#endif
+
+/* Try to insert OBJ in CUR, recurse if needed */
+static int
+hwloc___insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t cur, hwloc_obj_t obj,
+ hwloc_report_error_t report_error)
+{
+ hwloc_obj_t child, container, *cur_children, *obj_children, next_child = NULL;
+ int put;
+
+ /* Make sure we haven't gone too deep. */
+ if (!hwloc_bitmap_isincluded(obj->cpuset, cur->cpuset)) {
+ fprintf(stderr,"recursion has gone too deep?!\n");
+ return -1;
+ }
+
+ /* Check whether OBJ is included in some child. */
+ container = NULL;
+ for (child = cur->first_child; child; child = child->next_sibling) {
+ switch (hwloc_obj_cmp(obj, child)) {
+ case HWLOC_OBJ_EQUAL:
+ merge_index(obj, child, os_level, signed);
+ if (obj->os_level != child->os_level) {
+ fprintf(stderr, "Different OS level\n");
+ return -1;
+ }
+ merge_index(obj, child, os_index, unsigned);
+ if (obj->os_index != child->os_index) {
+ fprintf(stderr, "Different OS indexes\n");
+ return -1;
+ }
+ switch(obj->type) {
+ case HWLOC_OBJ_NODE:
+ /* Do not check these, it may change between calls */
+ merge_sizes(obj, child, memory.local_memory);
+ merge_sizes(obj, child, memory.total_memory);
+ /* if both objects have a page_types array, just keep the biggest one for now */
+ if (obj->memory.page_types_len && child->memory.page_types_len)
+ hwloc_debug("%s", "merging page_types by keeping the biggest one only\n");
+ if (obj->memory.page_types_len < child->memory.page_types_len) {
+ free(obj->memory.page_types);
+ } else {
+ free(child->memory.page_types);
+ child->memory.page_types_len = obj->memory.page_types_len;
+ child->memory.page_types = obj->memory.page_types;
+ obj->memory.page_types = NULL;
+ obj->memory.page_types_len = 0;
+ }
+ break;
+ case HWLOC_OBJ_CACHE:
+ merge_sizes(obj, child, attr->cache.size);
+ check_sizes(obj, child, attr->cache.size);
+ merge_sizes(obj, child, attr->cache.linesize);
+ check_sizes(obj, child, attr->cache.linesize);
+ break;
+ default:
+ break;
+ }
+ /* Already present, no need to insert. */
+ return -1;
+ case HWLOC_OBJ_INCLUDED:
+ if (container) {
+ if (report_error)
+ report_error("object included in several different objects!", __LINE__);
+ /* We can't handle that. */
+ return -1;
+ }
+ /* This child contains OBJ. */
+ container = child;
+ break;
+ case HWLOC_OBJ_INTERSECTS:
+ if (report_error)
+ report_error("object intersection without inclusion!", __LINE__);
+ /* We can't handle that. */
+ return -1;
+ case HWLOC_OBJ_CONTAINS:
+ /* OBJ will be above CHILD. */
+ break;
+ case HWLOC_OBJ_DIFFERENT:
+ /* OBJ will be alongside CHILD. */
+ break;
+ }
+ }
+
+ if (container) {
+ /* OBJ is strictly contained is some child of CUR, go deeper. */
+ return hwloc___insert_object_by_cpuset(topology, container, obj, report_error);
+ }
+
+ /*
+ * Children of CUR are either completely different from or contained into
+ * OBJ. Take those that are contained (keeping sorting order), and sort OBJ
+ * along those that are different.
+ */
+
+ /* OBJ is not put yet. */
+ put = 0;
+
+ /* These will always point to the pointer to their next last child. */
+ cur_children = &cur->first_child;
+ obj_children = &obj->first_child;
+
+ /* Construct CUR's and OBJ's children list. */
+
+ /* Iteration with prefetching to be completely safe against CHILD removal. */
+ for (child = cur->first_child, child ? next_child = child->next_sibling : NULL;
+ child;
+ child = next_child, child ? next_child = child->next_sibling : NULL) {
+
+ switch (hwloc_obj_cmp(obj, child)) {
+
+ case HWLOC_OBJ_DIFFERENT:
+ /* Leave CHILD in CUR. */
+ if (!put && hwloc_bitmap_compare_first(obj->cpuset, child->cpuset) < 0) {
+ /* Sort children by cpuset: put OBJ before CHILD in CUR's children. */
+ *cur_children = obj;
+ cur_children = &obj->next_sibling;
+ put = 1;
+ }
+ /* Now put CHILD in CUR's children. */
+ *cur_children = child;
+ cur_children = &child->next_sibling;
+ break;
+
+ case HWLOC_OBJ_CONTAINS:
+ /* OBJ contains CHILD, put the latter in the former. */
+ *obj_children = child;
+ obj_children = &child->next_sibling;
+ break;
+
+ case HWLOC_OBJ_EQUAL:
+ case HWLOC_OBJ_INCLUDED:
+ case HWLOC_OBJ_INTERSECTS:
+ /* Shouldn't ever happen as we have handled them above. */
+ abort();
+ }
+ }
+
+ /* Put OBJ last in CUR's children if not already done so. */
+ if (!put) {
+ *cur_children = obj;
+ cur_children = &obj->next_sibling;
+ }
+
+ /* Close children lists. */
+ *obj_children = NULL;
+ *cur_children = NULL;
+
+ return 0;
+}
+
+/* insertion routine that lets you change the error reporting callback */
+int
+hwloc__insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t obj,
+ hwloc_report_error_t report_error)
+{
+ int ret;
+ /* Start at the top. */
+ /* Add the cpuset to the top */
+ hwloc_bitmap_or(topology->levels[0][0]->complete_cpuset, topology->levels[0][0]->complete_cpuset, obj->cpuset);
+ if (obj->nodeset)
+ hwloc_bitmap_or(topology->levels[0][0]->complete_nodeset, topology->levels[0][0]->complete_nodeset, obj->nodeset);
+ ret = hwloc___insert_object_by_cpuset(topology, topology->levels[0][0], obj, report_error);
+ if (ret < 0)
+ hwloc_free_unlinked_object(obj);
+ return ret;
+}
+
+/* the default insertion routine warns in case of error.
+ * it's used by most backends */
+void
+hwloc_insert_object_by_cpuset(struct hwloc_topology *topology, hwloc_obj_t obj)
+{
+ hwloc__insert_object_by_cpuset(topology, obj, hwloc_report_os_error);
+}
+
+void
+hwloc_insert_object_by_parent(struct hwloc_topology *topology, hwloc_obj_t parent, hwloc_obj_t obj)
+{
+ hwloc_obj_t child, next_child = obj->first_child;
+ hwloc_obj_t *current;
+
+ /* Append to the end of the list */
+ for (current = &parent->first_child; *current; current = &(*current)->next_sibling)
+ ;
+ *current = obj;
+ obj->next_sibling = NULL;
+ obj->first_child = NULL;
+
+ /* Use the new object to insert children */
+ parent = obj;
+
+ /* Recursively insert children below */
+ while (next_child) {
+ child = next_child;
+ next_child = child->next_sibling;
+ hwloc_insert_object_by_parent(topology, parent, child);
+ }
+}
+
+static void
+hwloc_connect_children(hwloc_obj_t parent);
+/* Adds a misc object _after_ detection, and thus has to reconnect all the pointers */
+hwloc_obj_t
+hwloc_topology_insert_misc_object_by_cpuset(struct hwloc_topology *topology, hwloc_const_bitmap_t cpuset, const char *name)
+{
+ hwloc_obj_t obj, child;
+ int err;
+
+ if (hwloc_bitmap_iszero(cpuset))
+ return NULL;
+ if (!hwloc_bitmap_isincluded(cpuset, hwloc_topology_get_complete_cpuset(topology)))
+ return NULL;
+
+ obj = hwloc_alloc_setup_object(HWLOC_OBJ_MISC, -1);
+ if (name)
+ obj->name = strdup(name);
+
+ obj->cpuset = hwloc_bitmap_dup(cpuset);
+ /* initialize default cpusets, we'll adjust them later */
+ obj->complete_cpuset = hwloc_bitmap_dup(cpuset);
+ obj->allowed_cpuset = hwloc_bitmap_dup(cpuset);
+ obj->online_cpuset = hwloc_bitmap_dup(cpuset);
+
+ err = hwloc__insert_object_by_cpuset(topology, obj, NULL /* do not show errors on stdout */);
+ if (err < 0)
+ return NULL;
+
+ hwloc_connect_children(topology->levels[0][0]);
+
+ if ((child = obj->first_child) != NULL && child->cpuset) {
+ /* keep the main cpuset untouched, but update other cpusets and nodesets from children */
+ obj->nodeset = hwloc_bitmap_alloc();
+ obj->complete_nodeset = hwloc_bitmap_alloc();
+ obj->allowed_nodeset = hwloc_bitmap_alloc();
+ while (child) {
+ if (child->complete_cpuset)
+ hwloc_bitmap_or(obj->complete_cpuset, obj->complete_cpuset, child->complete_cpuset);
+ if (child->allowed_cpuset)
+ hwloc_bitmap_or(obj->allowed_cpuset, obj->allowed_cpuset, child->allowed_cpuset);
+ if (child->online_cpuset)
+ hwloc_bitmap_or(obj->online_cpuset, obj->online_cpuset, child->online_cpuset);
+ if (child->nodeset)
+ hwloc_bitmap_or(obj->nodeset, obj->nodeset, child->nodeset);
+ if (child->complete_nodeset)
+ hwloc_bitmap_or(obj->complete_nodeset, obj->complete_nodeset, child->complete_nodeset);
+ if (child->allowed_nodeset)
+ hwloc_bitmap_or(obj->allowed_nodeset, obj->allowed_nodeset, child->allowed_nodeset);
+ child = child->next_sibling;
+ }
+ } else {
+ /* copy the parent nodesets */
+ obj->nodeset = hwloc_bitmap_dup(obj->parent->nodeset);
+ obj->complete_nodeset = hwloc_bitmap_dup(obj->parent->complete_nodeset);
+ obj->allowed_nodeset = hwloc_bitmap_dup(obj->parent->allowed_nodeset);
+ }
+
+ return obj;
+}
+
+hwloc_obj_t
+hwloc_topology_insert_misc_object_by_parent(struct hwloc_topology *topology, hwloc_obj_t parent, const char *name)
+{
+ hwloc_obj_t obj = hwloc_alloc_setup_object(HWLOC_OBJ_MISC, -1);
+ if (name)
+ obj->name = strdup(name);
+
+ hwloc_insert_object_by_parent(topology, parent, obj);
+
+ hwloc_connect_children(topology->levels[0][0]);
+ /* no need to hwloc_connect_levels() since misc object are not in levels */
+
+ return obj;
+}
+
+/* Traverse children of a parent in a safe way: reread the next pointer as
+ * appropriate to prevent crash on child deletion: */
+#define for_each_child_safe(child, parent, pchild) \
+ for (pchild = &(parent)->first_child, child = *pchild; \
+ child; \
+ /* Check whether the current child was not dropped. */ \
+ (*pchild == child ? pchild = &(child->next_sibling) : NULL), \
+ /* Get pointer to next childect. */ \
+ child = *pchild)
+
+static int hwloc_memory_page_type_compare(const void *_a, const void *_b)
+{
+ const struct hwloc_obj_memory_page_type_s *a = _a;
+ const struct hwloc_obj_memory_page_type_s *b = _b;
+ /* consider 0 as larger so that 0-size page_type go to the end */
+ return b->size ? (int)(a->size - b->size) : -1;
+}
+
+/* Propagate memory counts */
+static void
+propagate_total_memory(hwloc_obj_t obj)
+{
+ hwloc_obj_t *temp, child;
+ unsigned i;
+
+ /* reset total before counting local and children memory */
+ obj->memory.total_memory = 0;
+
+ /* Propagate memory up */
+ for_each_child_safe(child, obj, temp) {
+ propagate_total_memory(child);
+ obj->memory.total_memory += child->memory.total_memory;
+ }
+ obj->memory.total_memory += obj->memory.local_memory;
+
+ /* By the way, sort the page_type array.
+ * Cannot do it on insert since some backends (e.g. XML) add page_types after inserting the object.
+ */
+ qsort(obj->memory.page_types, obj->memory.page_types_len, sizeof(*obj->memory.page_types), hwloc_memory_page_type_compare);
+ /* Ignore 0-size page_types, they are at the end */
+ for(i=obj->memory.page_types_len; i>=1; i--)
+ if (obj->memory.page_types[i-1].size)
+ break;
+ obj->memory.page_types_len = i;
+}
+
+/* Collect the cpuset of all the PU objects. */
+static void
+collect_proc_cpuset(hwloc_obj_t obj, hwloc_obj_t sys)
+{
+ hwloc_obj_t child, *temp;
+
+ if (sys) {
+ /* We are already given a pointer to a system object */
+ if (obj->type == HWLOC_OBJ_PU)
+ hwloc_bitmap_or(sys->cpuset, sys->cpuset, obj->cpuset);
+ } else {
+ if (obj->cpuset) {
+ /* This object is the root of a machine */
+ sys = obj;
+ /* Assume no PU for now */
+ hwloc_bitmap_zero(obj->cpuset);
+ }
+ }
+
+ for_each_child_safe(child, obj, temp)
+ collect_proc_cpuset(child, sys);
+}
+
+/* While traversing down and up, propagate the offline/disallowed cpus by
+ * and'ing them to and from the first object that has a cpuset */
+static void
+propagate_unused_cpuset(hwloc_obj_t obj, hwloc_obj_t sys)
+{
+ hwloc_obj_t child, *temp;
+
+ if (obj->cpuset) {
+ if (sys) {
+ /* We are already given a pointer to an system object, update it and update ourselves */
+ hwloc_bitmap_t mask = hwloc_bitmap_alloc();
+
+ /* Apply the topology cpuset */
+ hwloc_bitmap_and(obj->cpuset, obj->cpuset, sys->cpuset);
+
+ /* Update complete cpuset down */
+ if (obj->complete_cpuset) {
+ hwloc_bitmap_and(obj->complete_cpuset, obj->complete_cpuset, sys->complete_cpuset);
+ } else {
+ obj->complete_cpuset = hwloc_bitmap_dup(sys->complete_cpuset);
+ hwloc_bitmap_and(obj->complete_cpuset, obj->complete_cpuset, obj->cpuset);
+ }
+
+ /* Update online cpusets */
+ if (obj->online_cpuset) {
+ /* Update ours */
+ hwloc_bitmap_and(obj->online_cpuset, obj->online_cpuset, sys->online_cpuset);
+
+ /* Update the given cpuset, but only what we know */
+ hwloc_bitmap_copy(mask, obj->cpuset);
+ hwloc_bitmap_not(mask, mask);
+ hwloc_bitmap_or(mask, mask, obj->online_cpuset);
+ hwloc_bitmap_and(sys->online_cpuset, sys->online_cpuset, mask);
+ } else {
+ /* Just take it as such */
+ obj->online_cpuset = hwloc_bitmap_dup(sys->online_cpuset);
+ hwloc_bitmap_and(obj->online_cpuset, obj->online_cpuset, obj->cpuset);
+ }
+
+ /* Update allowed cpusets */
+ if (obj->allowed_cpuset) {
+ /* Update ours */
+ hwloc_bitmap_and(obj->allowed_cpuset, obj->allowed_cpuset, sys->allowed_cpuset);
+
+ /* Update the given cpuset, but only what we know */
+ hwloc_bitmap_copy(mask, obj->cpuset);
+ hwloc_bitmap_not(mask, mask);
+ hwloc_bitmap_or(mask, mask, obj->allowed_cpuset);
+ hwloc_bitmap_and(sys->allowed_cpuset, sys->allowed_cpuset, mask);
+ } else {
+ /* Just take it as such */
+ obj->allowed_cpuset = hwloc_bitmap_dup(sys->allowed_cpuset);
+ hwloc_bitmap_and(obj->allowed_cpuset, obj->allowed_cpuset, obj->cpuset);
+ }
+
+ hwloc_bitmap_free(mask);
+ } else {
+ /* This object is the root of a machine */
+ sys = obj;
+ /* Apply complete cpuset to cpuset, online_cpuset and allowed_cpuset, it
+ * will automatically be applied below */
+ if (obj->complete_cpuset)
+ hwloc_bitmap_and(obj->cpuset, obj->cpuset, obj->complete_cpuset);
+ else
+ obj->complete_cpuset = hwloc_bitmap_dup(obj->cpuset);
+ if (obj->online_cpuset)
+ hwloc_bitmap_and(obj->online_cpuset, obj->online_cpuset, obj->complete_cpuset);
+ else
+ obj->online_cpuset = hwloc_bitmap_dup(obj->complete_cpuset);
+ if (obj->allowed_cpuset)
+ hwloc_bitmap_and(obj->allowed_cpuset, obj->allowed_cpuset, obj->complete_cpuset);
+ else
+ obj->allowed_cpuset = hwloc_bitmap_dup(obj->complete_cpuset);
+ }
+ }
+
+ for_each_child_safe(child, obj, temp)
+ propagate_unused_cpuset(child, sys);
+}
+
+/* Force full nodeset for non-NUMA machines */
+static void
+add_default_object_sets(hwloc_obj_t obj, int parent_has_sets)
+{
+ hwloc_obj_t child, *temp;
+
+ if (parent_has_sets || obj->cpuset) {
+ /* if the parent has non-NULL sets, or if the object has non-NULL cpusets,
+ * it must have non-NULL nodesets
+ */
+ assert(obj->cpuset);
+ assert(obj->online_cpuset);
+ assert(obj->complete_cpuset);
+ assert(obj->allowed_cpuset);
+ if (!obj->nodeset)
+ obj->nodeset = hwloc_bitmap_alloc_full();
+ if (!obj->complete_nodeset)
+ obj->complete_nodeset = hwloc_bitmap_alloc_full();
+ if (!obj->allowed_nodeset)
+ obj->allowed_nodeset = hwloc_bitmap_alloc_full();
+ } else {
+ /* parent has no sets and object has NULL cpusets,
+ * it must have NULL nodesets
+ */
+ assert(!obj->nodeset);
+ assert(!obj->complete_nodeset);
+ assert(!obj->allowed_nodeset);
+ }
+
+ for_each_child_safe(child, obj, temp)
+ add_default_object_sets(child, obj->cpuset != NULL);
+}
+
+/* Propagate nodesets up and down */
+static void
+propagate_nodeset(hwloc_obj_t obj, hwloc_obj_t sys)
+{
+ hwloc_obj_t child, *temp;
+ hwloc_bitmap_t parent_nodeset = NULL;
+ int parent_weight = 0;
+
+ if (!sys && obj->nodeset) {
+ sys = obj;
+ if (!obj->complete_nodeset)
+ obj->complete_nodeset = hwloc_bitmap_dup(obj->nodeset);
+ if (!obj->allowed_nodeset)
+ obj->allowed_nodeset = hwloc_bitmap_dup(obj->complete_nodeset);
+ }
+
+ if (sys) {
+ if (obj->nodeset) {
+ /* Some existing nodeset coming from above, to possibly propagate down */
+ parent_nodeset = obj->nodeset;
+ parent_weight = hwloc_bitmap_weight(parent_nodeset);
+ } else
+ obj->nodeset = hwloc_bitmap_alloc();
+ }
+
+ for_each_child_safe(child, obj, temp) {
+ /* Propagate singleton nodesets down */
+ if (parent_weight == 1) {
+ if (!child->nodeset)
+ child->nodeset = hwloc_bitmap_dup(obj->nodeset);
+ else if (!hwloc_bitmap_isequal(child->nodeset, parent_nodeset)) {
+ hwloc_debug_bitmap("Oops, parent nodeset %s", parent_nodeset);
+ hwloc_debug_bitmap(" is different from child nodeset %s, ignoring the child one\n", child->nodeset);
+ hwloc_bitmap_copy(child->nodeset, parent_nodeset);
+ }
+ }
+
+ /* Recurse */
+ propagate_nodeset(child, sys);
+
+ /* Propagate children nodesets up */
+ if (sys && child->nodeset)
+ hwloc_bitmap_or(obj->nodeset, obj->nodeset, child->nodeset);
+ }
+}
+
+/* Propagate allowed and complete nodesets */
+static void
+propagate_nodesets(hwloc_obj_t obj)
+{
+ hwloc_bitmap_t mask = hwloc_bitmap_alloc();
+ hwloc_obj_t child, *temp;
+
+ for_each_child_safe(child, obj, temp) {
+ if (obj->nodeset) {
+ /* Update complete nodesets down */
+ if (child->complete_nodeset) {
+ hwloc_bitmap_and(child->complete_nodeset, child->complete_nodeset, obj->complete_nodeset);
+ } else if (child->nodeset) {
+ child->complete_nodeset = hwloc_bitmap_dup(obj->complete_nodeset);
+ hwloc_bitmap_and(child->complete_nodeset, child->complete_nodeset, child->nodeset);
+ } /* else the child doesn't have nodeset information, we can not provide a complete nodeset */
+
+ /* Update allowed nodesets down */
+ if (child->allowed_nodeset) {
+ hwloc_bitmap_and(child->allowed_nodeset, child->allowed_nodeset, obj->allowed_nodeset);
+ } else if (child->nodeset) {
+ child->allowed_nodeset = hwloc_bitmap_dup(obj->allowed_nodeset);
+ hwloc_bitmap_and(child->allowed_nodeset, child->allowed_nodeset, child->nodeset);
+ }
+ }
+
+ propagate_nodesets(child);
+
+ if (obj->nodeset) {
+ /* Update allowed nodesets up */
+ if (child->nodeset && child->allowed_nodeset) {
+ hwloc_bitmap_copy(mask, child->nodeset);
+ hwloc_bitmap_andnot(mask, mask, child->allowed_nodeset);
+ hwloc_bitmap_andnot(obj->allowed_nodeset, obj->allowed_nodeset, mask);
+ }
+ }
+ }
+ hwloc_bitmap_free(mask);
+
+ if (obj->nodeset) {
+ /* Apply complete nodeset to nodeset and allowed_nodeset */
+ if (obj->complete_nodeset)
+ hwloc_bitmap_and(obj->nodeset, obj->nodeset, obj->complete_nodeset);
+ else
+ obj->complete_nodeset = hwloc_bitmap_dup(obj->nodeset);
+ if (obj->allowed_nodeset)
+ hwloc_bitmap_and(obj->allowed_nodeset, obj->allowed_nodeset, obj->complete_nodeset);
+ else
+ obj->allowed_nodeset = hwloc_bitmap_dup(obj->complete_nodeset);
+ }
+}
+
+static void
+apply_nodeset(hwloc_obj_t obj, hwloc_obj_t sys)
+{
+ unsigned i;
+ hwloc_obj_t child, *temp;
+
+ if (sys) {
+ if (obj->type == HWLOC_OBJ_NODE && obj->os_index != (unsigned) -1 &&
+ !hwloc_bitmap_isset(sys->allowed_nodeset, obj->os_index)) {
+ hwloc_debug("Dropping memory from disallowed node %u\n", obj->os_index);
+ obj->memory.local_memory = 0;
+ obj->memory.total_memory = 0;
+ for(i=0; i<obj->memory.page_types_len; i++)
+ obj->memory.page_types[i].count = 0;
+ }
+ } else {
+ if (obj->allowed_nodeset) {
+ sys = obj;
+ }
+ }
+
+ for_each_child_safe(child, obj, temp)
+ apply_nodeset(child, sys);
+}
+
+static void
+remove_unused_cpusets(hwloc_obj_t obj)
+{
+ hwloc_obj_t child, *temp;
+
+ if (obj->cpuset) {
+ hwloc_bitmap_and(obj->cpuset, obj->cpuset, obj->online_cpuset);
+ hwloc_bitmap_and(obj->cpuset, obj->cpuset, obj->allowed_cpuset);
+ }
+
+ for_each_child_safe(child, obj, temp)
+ remove_unused_cpusets(child);
+}
+
+/* Remove an object from its parent and free it.
+ * Only updates next_sibling/first_child pointers,
+ * so may only be used during early discovery.
+ * Children are inserted where the object was.
+ */
+static void
+unlink_and_free_single_object(hwloc_obj_t *pparent)