diff options
Diffstat (limited to 'hwloc-1.2.1/src/topology.c')
-rw-r--r-- | hwloc-1.2.1/src/topology.c | 2468 |
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) |