/* * 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 #define _ATFILE_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_MACH_MACH_INIT_H #include #endif #ifdef HAVE_MACH_MACH_HOST_H #include #endif #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_SYSCTL_H #include #endif #ifdef HWLOC_WIN_SYS #include #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; cpucpuset = 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; idistances_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; iinfos_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 */ if (!b->size) return -1; /* don't cast a-b in int since those are ullongs */ if (b->size == a->size) return 0; return a->size < b->size ? -1 : 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; imemory.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) { hwloc_obj_t parent = *pparent; hwloc_obj_t child = parent->first_child; /* Replace object with its list of children */ if (child) { *pparent = child; while (child->next_sibling) child = child->next_sibling; child->next_sibling = parent->next_sibling; } else *pparent = parent->next_sibling; /* Remove ignored object */ hwloc_free_unlinked_object(parent); } /* Remove all ignored objects. */ static void remove_ignored(hwloc_topology_t topology, hwloc_obj_t *pparent) { hwloc_obj_t parent = *pparent, child, *pchild; for_each_child_safe(child, parent, pchild) remove_ignored(topology, pchild); if (parent != topology->levels[0][0] && topology->ignored_types[parent->type] == HWLOC_IGNORE_TYPE_ALWAYS) { hwloc_debug("%s", "\nDropping ignored object "); print_object(topology, 0, parent); unlink_and_free_single_object(pparent); } } /* Remove an object and its children from its parent and free them. * Only updates next_sibling/first_child pointers, * so may only be used during early discovery. */ static void unlink_and_free_object_and_children(hwloc_obj_t *pobj) { hwloc_obj_t obj = *pobj, child, *pchild; for_each_child_safe(child, obj, pchild) unlink_and_free_object_and_children(pchild); *pobj = obj->next_sibling; hwloc_free_unlinked_object(obj); } /* Remove all children whose cpuset is empty, except NUMA nodes * since we want to keep memory information. */ static void remove_empty(hwloc_topology_t topology, hwloc_obj_t *pobj) { hwloc_obj_t obj = *pobj, child, *pchild; for_each_child_safe(child, obj, pchild) remove_empty(topology, pchild); if (obj->type != HWLOC_OBJ_NODE && !obj->first_child /* only remove if all children were removed above, so that we don't remove parents of NUMAnode */ && hwloc_bitmap_iszero(obj->cpuset)) { /* Remove empty children */ hwloc_debug("%s", "\nRemoving empty object "); print_object(topology, 0, obj); unlink_and_free_single_object(pobj); } } /* adjust object cpusets according the given droppedcpuset, * drop object whose cpuset becomes empty, * and mark dropped nodes in droppednodeset */ static void restrict_object(hwloc_topology_t topology, unsigned long flags, hwloc_obj_t *pobj, hwloc_const_cpuset_t droppedcpuset, hwloc_nodeset_t droppednodeset, int droppingparent) { hwloc_obj_t obj = *pobj, child, *pchild; int dropping; int modified = obj->complete_cpuset && hwloc_bitmap_intersects(obj->complete_cpuset, droppedcpuset); hwloc_clear_object_distances(obj); if (obj->cpuset) hwloc_bitmap_andnot(obj->cpuset, obj->cpuset, droppedcpuset); if (obj->complete_cpuset) hwloc_bitmap_andnot(obj->complete_cpuset, obj->complete_cpuset, droppedcpuset); if (obj->online_cpuset) hwloc_bitmap_andnot(obj->online_cpuset, obj->online_cpuset, droppedcpuset); if (obj->allowed_cpuset) hwloc_bitmap_andnot(obj->allowed_cpuset, obj->allowed_cpuset, droppedcpuset); if (obj->type == HWLOC_OBJ_MISC) { dropping = droppingparent && !(flags & HWLOC_RESTRICT_FLAG_ADAPT_MISC); } else { dropping = droppingparent || (obj->cpuset && hwloc_bitmap_iszero(obj->cpuset)); } if (modified) for_each_child_safe(child, obj, pchild) restrict_object(topology, flags, pchild, droppedcpuset, droppednodeset, dropping); if (dropping) { hwloc_debug("%s", "\nRemoving object during restrict"); print_object(topology, 0, obj); if (obj->type == HWLOC_OBJ_NODE) hwloc_bitmap_set(droppednodeset, obj->os_index); /* remove the object from the tree (no need to remove from levels, they will be entirely rebuilt by the caller) */ unlink_and_free_single_object(pobj); /* do not remove children. if they were to be removed, they would have been already */ } } /* adjust object nodesets accordingly the given droppednodeset */ static void restrict_object_nodeset(hwloc_topology_t topology, hwloc_obj_t *pobj, hwloc_nodeset_t droppednodeset) { hwloc_obj_t obj = *pobj, child, *pchild; /* if this object isn't modified, don't bother looking at children */ if (obj->complete_nodeset && !hwloc_bitmap_intersects(obj->complete_nodeset, droppednodeset)) return; if (obj->nodeset) hwloc_bitmap_andnot(obj->nodeset, obj->nodeset, droppednodeset); if (obj->complete_nodeset) hwloc_bitmap_andnot(obj->complete_nodeset, obj->complete_nodeset, droppednodeset); if (obj->allowed_nodeset) hwloc_bitmap_andnot(obj->allowed_nodeset, obj->allowed_nodeset, droppednodeset); for_each_child_safe(child, obj, pchild) restrict_object_nodeset(topology, pchild, droppednodeset); } /* * Merge with the only child if either the parent or the child has a type to be * ignored while keeping structure */ static void merge_useless_child(hwloc_topology_t topology, hwloc_obj_t *pparent) { hwloc_obj_t parent = *pparent, child, *pchild; for_each_child_safe(child, parent, pchild) merge_useless_child(topology, pchild); child = parent->first_child; if (!child || child->next_sibling) /* There are no or several children, it's useful to keep them. */ return; /* TODO: have a preference order? */ if (topology->ignored_types[parent->type] == HWLOC_IGNORE_TYPE_KEEP_STRUCTURE) { /* Parent can be ignored in favor of the child. */ hwloc_debug("%s", "\nIgnoring parent "); print_object(topology, 0, parent); *pparent = child; child->next_sibling = parent->next_sibling; hwloc_free_unlinked_object(parent); } else if (topology->ignored_types[child->type] == HWLOC_IGNORE_TYPE_KEEP_STRUCTURE) { /* Child can be ignored in favor of the parent. */ hwloc_debug("%s", "\nIgnoring child "); print_object(topology, 0, child); parent->first_child = child->first_child; hwloc_free_unlinked_object(child); } } /* * Initialize handy pointers in the whole topology. * The topology only had first_child and next_sibling pointers. * When this funtions return, all parent/children pointers are initialized. * The remaining fields (levels, cousins, logical_index, depth, ...) will * be setup later in hwloc_connect_levels(). */ static void hwloc_connect_children(hwloc_obj_t parent) { unsigned n; hwloc_obj_t child, prev_child = NULL; for (n = 0, child = parent->first_child; child; n++, prev_child = child, child = child->next_sibling) { child->parent = parent; child->sibling_rank = n; child->prev_sibling = prev_child; } parent->last_child = prev_child; parent->arity = n; free(parent->children); if (!n) { parent->children = NULL; return; } parent->children = malloc(n * sizeof(*parent->children)); for (n = 0, child = parent->first_child; child; n++, child = child->next_sibling) { parent->children[n] = child; hwloc_connect_children(child); } } /* * Check whether there is an object below ROOT that has the same type as OBJ */ static int find_same_type(hwloc_obj_t root, hwloc_obj_t obj) { hwloc_obj_t child; if (hwloc_type_cmp(root, obj) == HWLOC_TYPE_EQUAL) return 1; for (child = root->first_child; child; child = child->next_sibling) if (find_same_type(child, obj)) return 1; return 0; } /* traverse the array of current object and compare them with top_obj. * if equal, take the object and put its children into the remaining objs. * if not equal, put the object into the remaining objs. */ static int hwloc_level_take_objects(hwloc_obj_t top_obj, hwloc_obj_t *current_objs, unsigned n_current_objs, hwloc_obj_t *taken_objs, unsigned n_taken_objs __hwloc_attribute_unused, hwloc_obj_t *remaining_objs, unsigned n_remaining_objs __hwloc_attribute_unused) { unsigned taken_i = 0; unsigned new_i = 0; unsigned i, j; for (i = 0; i < n_current_objs; i++) if (hwloc_type_cmp(top_obj, current_objs[i]) == HWLOC_TYPE_EQUAL) { /* Take it, add children. */ taken_objs[taken_i++] = current_objs[i]; for (j = 0; j < current_objs[i]->arity; j++) remaining_objs[new_i++] = current_objs[i]->children[j]; } else { /* Leave it. */ remaining_objs[new_i++] = current_objs[i]; } #ifdef HWLOC_DEBUG /* Make sure we didn't mess up. */ assert(taken_i == n_taken_objs); assert(new_i == n_current_objs - n_taken_objs + n_remaining_objs); #endif return new_i; } /* Given an input object, copy it or its interesting children into the output array. * If new_obj is NULL, we're just counting interesting ohjects. */ static unsigned hwloc_level_filter_object(hwloc_topology_t topology, hwloc_obj_t *new_obj, hwloc_obj_t old) { unsigned i, total; if (old->type != HWLOC_OBJ_MISC) { if (new_obj) *new_obj = old; return 1; } for(i=0, total=0; iarity; i++) { int nb = hwloc_level_filter_object(topology, new_obj, old->children[i]); if (new_obj) new_obj += nb; total += nb; } return total; } /* Replace an input array of objects with an input array containing * only interesting objects for levels. * Misc objects are removed, their interesting children are added. * I/O devices are removed and queue to their own lists. */ static int hwloc_level_filter_objects(hwloc_topology_t topology, hwloc_obj_t **objs, unsigned *n_objs) { hwloc_obj_t *old = *objs, *new; unsigned nold = *n_objs, nnew, i; /* anything to filter? */ for(i=0; itype == HWLOC_OBJ_MISC) break; if (i==nold) return 0; /* count interesting objects and allocate the new array */ for(i=0, nnew=0; ilevels[l]); memset(topology->levels+1, 0, (HWLOC_DEPTH_MAX-1)*sizeof(*topology->levels)); memset(topology->level_nbobjects+1, 0, (HWLOC_DEPTH_MAX-1)*sizeof(*topology->level_nbobjects)); topology->nb_levels = 1; /* don't touch next_group_depth, the Group objects are still here */ /* initialize all depth to unknown */ for (l=0; l < HWLOC_OBJ_TYPE_MAX; l++) topology->type_depth[l] = HWLOC_TYPE_DEPTH_UNKNOWN; topology->type_depth[topology->levels[0][0]->type] = 0; /* Start with children of the whole system. */ n_objs = topology->levels[0][0]->arity; objs = malloc(n_objs * sizeof(objs[0])); if (!objs) { errno = ENOMEM; hwloc_topology_clear(topology); return -1; } memcpy(objs, topology->levels[0][0]->children, n_objs*sizeof(objs[0])); /* Filter-out interesting objects */ err = hwloc_level_filter_objects(topology, &objs, &n_objs); if (err < 0) { errno = ENOMEM; hwloc_topology_clear(topology); return -1; } /* Keep building levels while there are objects left in OBJS. */ while (n_objs) { /* At this point, the objs array contains only objects that may go into levels */ /* First find which type of object is the topmost. * Don't use PU if there are other types since we want to keep PU at the bottom. */ /* Look for the first non-PU object, and use the first PU if we really find nothing else */ for (i = 0; i < n_objs; i++) if (objs[i]->type != HWLOC_OBJ_PU) break; top_obj = i == n_objs ? objs[0] : objs[i]; /* See if this is actually the topmost object */ for (i = 0; i < n_objs; i++) { if (hwloc_type_cmp(top_obj, objs[i]) != HWLOC_TYPE_EQUAL) { if (find_same_type(objs[i], top_obj)) { /* OBJS[i] is strictly above an object of the same type as TOP_OBJ, so it * is above TOP_OBJ. */ top_obj = objs[i]; } } } /* Now peek all objects of the same type, build a level with that and * replace them with their children. */ /* First count them. */ n_taken_objs = 0; n_new_objs = 0; for (i = 0; i < n_objs; i++) if (hwloc_type_cmp(top_obj, objs[i]) == HWLOC_TYPE_EQUAL) { n_taken_objs++; n_new_objs += objs[i]->arity; } /* New level. */ taken_objs = malloc((n_taken_objs + 1) * sizeof(taken_objs[0])); /* New list of pending objects. */ new_objs = malloc((n_objs - n_taken_objs + n_new_objs) * sizeof(new_objs[0])); n_new_objs = hwloc_level_take_objects(top_obj, objs, n_objs, taken_objs, n_taken_objs, new_objs, n_new_objs); /* Ok, put numbers in the level and link cousins. */ for (i = 0; i < n_taken_objs; i++) { taken_objs[i]->depth = topology->nb_levels; taken_objs[i]->logical_index = i; if (i) { taken_objs[i]->prev_cousin = taken_objs[i-1]; taken_objs[i-1]->next_cousin = taken_objs[i]; } } taken_objs[0]->prev_cousin = NULL; taken_objs[n_taken_objs-1]->next_cousin = NULL; /* One more level! */ if (top_obj->type == HWLOC_OBJ_CACHE) hwloc_debug("--- Cache level depth %u", top_obj->attr->cache.depth); else hwloc_debug("--- %s level", hwloc_obj_type_string(top_obj->type)); hwloc_debug(" has number %u\n\n", topology->nb_levels); if (topology->type_depth[top_obj->type] == HWLOC_TYPE_DEPTH_UNKNOWN) topology->type_depth[top_obj->type] = topology->nb_levels; else topology->type_depth[top_obj->type] = HWLOC_TYPE_DEPTH_MULTIPLE; /* mark as unknown */ taken_objs[n_taken_objs] = NULL; topology->level_nbobjects[topology->nb_levels] = n_taken_objs; topology->levels[topology->nb_levels] = taken_objs; topology->nb_levels++; free(objs); /* Switch to new_objs, after filtering-out interesting objects */ err = hwloc_level_filter_objects(topology, &new_objs, &n_new_objs); if (err < 0) { errno = ENOMEM; hwloc_topology_clear(topology); return -1; } objs = new_objs; n_objs = n_new_objs; } /* It's empty now. */ free(objs); return 0; } /* * Empty binding hooks always returning success */ static int dontset_return_complete_cpuset(hwloc_topology_t topology, hwloc_cpuset_t set) { hwloc_const_cpuset_t cpuset = hwloc_topology_get_complete_cpuset(topology); if (cpuset) { hwloc_bitmap_copy(set, hwloc_topology_get_complete_cpuset(topology)); return 0; } else return -1; } static int dontset_thisthread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, int flags __hwloc_attribute_unused) { return 0; } static int dontget_thisthread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_bitmap_t set, int flags __hwloc_attribute_unused) { return dontset_return_complete_cpuset(topology, set); } static int dontset_thisproc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, int flags __hwloc_attribute_unused) { return 0; } static int dontget_thisproc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_bitmap_t set, int flags __hwloc_attribute_unused) { return dontset_return_complete_cpuset(topology, set); } static int dontset_proc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_pid_t pid __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, int flags __hwloc_attribute_unused) { return 0; } static int dontget_proc_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_pid_t pid __hwloc_attribute_unused, hwloc_bitmap_t cpuset, int flags __hwloc_attribute_unused) { return dontset_return_complete_cpuset(topology, cpuset); } #ifdef hwloc_thread_t static int dontset_thread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_thread_t tid __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, int flags __hwloc_attribute_unused) { return 0; } static int dontget_thread_cpubind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_thread_t tid __hwloc_attribute_unused, hwloc_bitmap_t cpuset, int flags __hwloc_attribute_unused) { return dontset_return_complete_cpuset(topology, cpuset); } #endif static int dontset_return_complete_nodeset(hwloc_topology_t topology, hwloc_nodeset_t set, hwloc_membind_policy_t *policy) { hwloc_const_nodeset_t nodeset = hwloc_topology_get_complete_nodeset(topology); if (nodeset) { hwloc_bitmap_copy(set, hwloc_topology_get_complete_nodeset(topology)); *policy = HWLOC_MEMBIND_DEFAULT; return 0; } else return -1; } static int dontset_thisproc_membind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, hwloc_membind_policy_t policy __hwloc_attribute_unused, int flags __hwloc_attribute_unused) { return 0; } static int dontget_thisproc_membind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_bitmap_t set, hwloc_membind_policy_t * policy, int flags __hwloc_attribute_unused) { return dontset_return_complete_nodeset(topology, set, policy); } static int dontset_thisthread_membind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, hwloc_membind_policy_t policy __hwloc_attribute_unused, int flags __hwloc_attribute_unused) { return 0; } static int dontget_thisthread_membind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_bitmap_t set, hwloc_membind_policy_t * policy, int flags __hwloc_attribute_unused) { return dontset_return_complete_nodeset(topology, set, policy); } static int dontset_proc_membind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_pid_t pid __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, hwloc_membind_policy_t policy __hwloc_attribute_unused, int flags __hwloc_attribute_unused) { return 0; } static int dontget_proc_membind(hwloc_topology_t topology __hwloc_attribute_unused, hwloc_pid_t pid __hwloc_attribute_unused, hwloc_bitmap_t set, hwloc_membind_policy_t * policy, int flags __hwloc_attribute_unused) { return dontset_return_complete_nodeset(topology, set, policy); } static int dontset_area_membind(hwloc_topology_t topology __hwloc_attribute_unused, const void *addr __hwloc_attribute_unused, size_t size __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, hwloc_membind_policy_t policy __hwloc_attribute_unused, int flags __hwloc_attribute_unused) { return 0; } static int dontget_area_membind(hwloc_topology_t topology __hwloc_attribute_unused, const void *addr __hwloc_attribute_unused, size_t size __hwloc_attribute_unused, hwloc_bitmap_t set, hwloc_membind_policy_t * policy, int flags __hwloc_attribute_unused) { return dontset_return_complete_nodeset(topology, set, policy); } static void * dontalloc_membind(hwloc_topology_t topology __hwloc_attribute_unused, size_t size __hwloc_attribute_unused, hwloc_const_bitmap_t set __hwloc_attribute_unused, hwloc_membind_policy_t policy __hwloc_attribute_unused, int flags __hwloc_attribute_unused) { return malloc(size); } static int dontfree_membind(hwloc_topology_t topology __hwloc_attribute_unused, void *addr __hwloc_attribute_unused, size_t size __hwloc_attribute_unused) { free(addr); return 0; } static void alloc_cpusets(hwloc_obj_t obj) { obj->cpuset = hwloc_bitmap_alloc_full(); obj->complete_cpuset = hwloc_bitmap_alloc(); obj->online_cpuset = hwloc_bitmap_alloc_full(); obj->allowed_cpuset = hwloc_bitmap_alloc_full(); obj->nodeset = hwloc_bitmap_alloc(); obj->complete_nodeset = hwloc_bitmap_alloc(); obj->allowed_nodeset = hwloc_bitmap_alloc_full(); } /* Main discovery loop */ static int hwloc_discover(struct hwloc_topology *topology) { if (topology->backend_type == HWLOC_BACKEND_SYNTHETIC) { alloc_cpusets(topology->levels[0][0]); hwloc_look_synthetic(topology); #ifdef HWLOC_HAVE_XML } else if (topology->backend_type == HWLOC_BACKEND_XML) { hwloc_look_xml(topology); #endif } else { /* Raw detection, from coarser levels to finer levels for more efficiency. */ /* hwloc_look_* functions should use hwloc_obj_add to add objects initialized * through hwloc_alloc_setup_object. For node levels, nodeset, memory_Kb and * huge_page_free must be initialized. For cache levels, memory_kB and * attr->cache.depth must be initialized. For misc levels, attr->misc.depth * must be initialized. */ /* There must be at least a PU object for each logical processor, at worse * produced by hwloc_setup_pu_level() */ /* To be able to just use hwloc_insert_object_by_cpuset to insert the object * in the topology according to the cpuset, the cpuset field must be * initialized. */ /* A priori, All processors are visible in the topology, online, and allowed * for the application. * * - If some processors exist but topology information is unknown for them * (and thus the backend couldn't create objects for them), they should be * added to the complete_cpuset field of the lowest object where the object * could reside. * * - If some processors are not online, they should be dropped from the * online_cpuset field. * * - If some processors are not allowed for the application (e.g. for * administration reasons), they should be dropped from the allowed_cpuset * field. * * The same applies to the node sets complete_nodeset and allowed_cpuset. * * If such field doesn't exist yet, it can be allocated, and initialized to * zero (for complete), or to full (for online and allowed). The values are * automatically propagated to the whole tree after detection. * * Here, we only allocate cpusets for the root object. */ alloc_cpusets(topology->levels[0][0]); /* Each OS type should also fill the bind functions pointers, at least the * set_cpubind one */ # ifdef HWLOC_LINUX_SYS # define HAVE_OS_SUPPORT hwloc_look_linux(topology); # endif /* HWLOC_LINUX_SYS */ # ifdef HWLOC_AIX_SYS # define HAVE_OS_SUPPORT hwloc_look_aix(topology); # endif /* HWLOC_AIX_SYS */ # ifdef HWLOC_OSF_SYS # define HAVE_OS_SUPPORT hwloc_look_osf(topology); # endif /* HWLOC_OSF_SYS */ # ifdef HWLOC_SOLARIS_SYS # define HAVE_OS_SUPPORT hwloc_look_solaris(topology); # endif /* HWLOC_SOLARIS_SYS */ # ifdef HWLOC_WIN_SYS # define HAVE_OS_SUPPORT hwloc_look_windows(topology); # endif /* HWLOC_WIN_SYS */ # ifdef HWLOC_DARWIN_SYS # define HAVE_OS_SUPPORT hwloc_look_darwin(topology); # endif /* HWLOC_DARWIN_SYS */ # ifdef HWLOC_FREEBSD_SYS # define HAVE_OS_SUPPORT hwloc_look_freebsd(topology); # endif /* HWLOC_FREEBSD_SYS */ # ifdef HWLOC_HPUX_SYS # define HAVE_OS_SUPPORT hwloc_look_hpux(topology); # endif /* HWLOC_HPUX_SYS */ # ifndef HAVE_OS_SUPPORT hwloc_setup_pu_level(topology, hwloc_fallback_nbprocessors(topology)); # endif /* Unsupported OS */ # ifndef HWLOC_LINUX_SYS if (topology->is_thissystem) { /* gather uname info, except for Linux, which does it internally depending on load options */ hwloc_add_uname_info(topology); } # endif } /* * Now that backends have detected objects, sort them and establish pointers. */ print_objects(topology, 0, topology->levels[0][0]); /* * Group levels by distances */ hwloc_convert_distances_indexes_into_objects(topology); hwloc_group_by_distances(topology); /* First tweak a bit to clean the topology. */ hwloc_debug("%s", "\nRestrict topology cpusets to existing PU and NODE objects\n"); collect_proc_cpuset(topology->levels[0][0], NULL); hwloc_debug("%s", "\nPropagate offline and disallowed cpus down and up\n"); propagate_unused_cpuset(topology->levels[0][0], NULL); if (topology->levels[0][0]->complete_nodeset && hwloc_bitmap_iszero(topology->levels[0][0]->complete_nodeset)) { /* No nodeset, drop all of them */ hwloc_bitmap_free(topology->levels[0][0]->nodeset); topology->levels[0][0]->nodeset = NULL; hwloc_bitmap_free(topology->levels[0][0]->complete_nodeset); topology->levels[0][0]->complete_nodeset = NULL; hwloc_bitmap_free(topology->levels[0][0]->allowed_nodeset); topology->levels[0][0]->allowed_nodeset = NULL; } hwloc_debug("%s", "\nPropagate nodesets\n"); propagate_nodeset(topology->levels[0][0], NULL); propagate_nodesets(topology->levels[0][0]); print_objects(topology, 0, topology->levels[0][0]); if (!(topology->flags & HWLOC_TOPOLOGY_FLAG_WHOLE_SYSTEM)) { hwloc_debug("%s", "\nRemoving unauthorized and offline cpusets from all cpusets\n"); remove_unused_cpusets(topology->levels[0][0]); hwloc_debug("%s", "\nRemoving disallowed memory according to nodesets\n"); apply_nodeset(topology->levels[0][0], NULL); print_objects(topology, 0, topology->levels[0][0]); } hwloc_debug("%s", "\nRemoving ignored objects\n"); remove_ignored(topology, &topology->levels[0][0]); print_objects(topology, 0, topology->levels[0][0]); hwloc_debug("%s", "\nRemoving empty objects except numa nodes and PCI devices\n"); remove_empty(topology, &topology->levels[0][0]); if (!topology->levels[0][0]) { fprintf(stderr, "Topology became empty, aborting!\n"); abort(); } print_objects(topology, 0, topology->levels[0][0]); hwloc_debug("%s", "\nRemoving objects whose type has HWLOC_IGNORE_TYPE_KEEP_STRUCTURE and have only one child or are the only child\n"); merge_useless_child(topology, &topology->levels[0][0]); print_objects(topology, 0, topology->levels[0][0]); hwloc_debug("%s", "\nAdd default object sets\n"); add_default_object_sets(topology->levels[0][0], 0); hwloc_debug("%s", "\nOk, finished tweaking, now connect\n"); /* Now connect handy pointers. */ hwloc_connect_children(topology->levels[0][0]); print_objects(topology, 0, topology->levels[0][0]); /* Explore the resulting topology level by level. */ if (hwloc_connect_levels(topology) < 0) return -1; /* accumulate children memory in total_memory fields (only once parent is set) */ hwloc_debug("%s", "\nPropagate total memory up\n"); propagate_total_memory(topology->levels[0][0]); /* * Now that objects are numbered, take distance matrices from backends and put them in the main topology. * * Some objects may have disappeared (in removed_empty or removed_ignored) since we setup os distances * (hwloc_distances_finalize_os()) above. Reset them so as to not point to disappeared objects anymore. */ hwloc_restrict_distances(topology, HWLOC_RESTRICT_FLAG_ADAPT_DISTANCES); hwloc_convert_distances_indexes_into_objects(topology); hwloc_finalize_logical_distances(topology); # ifdef HWLOC_HAVE_XML if (topology->backend_type == HWLOC_BACKEND_XML) /* make sure the XML-imported distances are ok now that the tree is properly setup */ hwloc_xml_check_distances(topology); # endif /* * Now set binding hooks. * If the represented system is actually not this system, use dummy binding * hooks. */ if (topology->flags & HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM) topology->is_thissystem = 1; if (topology->is_thissystem) { # ifdef HWLOC_LINUX_SYS hwloc_set_linux_hooks(topology); # endif /* HWLOC_LINUX_SYS */ # ifdef HWLOC_AIX_SYS hwloc_set_aix_hooks(topology); # endif /* HWLOC_AIX_SYS */ # ifdef HWLOC_OSF_SYS hwloc_set_osf_hooks(topology); # endif /* HWLOC_OSF_SYS */ # ifdef HWLOC_SOLARIS_SYS hwloc_set_solaris_hooks(topology); # endif /* HWLOC_SOLARIS_SYS */ # ifdef HWLOC_WIN_SYS hwloc_set_windows_hooks(topology); # endif /* HWLOC_WIN_SYS */ # ifdef HWLOC_DARWIN_SYS hwloc_set_darwin_hooks(topology); # endif /* HWLOC_DARWIN_SYS */ # ifdef HWLOC_FREEBSD_SYS hwloc_set_freebsd_hooks(topology); # endif /* HWLOC_FREEBSD_SYS */ # ifdef HWLOC_HPUX_SYS hwloc_set_hpux_hooks(topology); # endif /* HWLOC_HPUX_SYS */ } else { topology->set_thisproc_cpubind = dontset_thisproc_cpubind; topology->get_thisproc_cpubind = dontget_thisproc_cpubind; topology->set_thisthread_cpubind = dontset_thisthread_cpubind; topology->get_thisthread_cpubind = dontget_thisthread_cpubind; topology->set_proc_cpubind = dontset_proc_cpubind; topology->get_proc_cpubind = dontget_proc_cpubind; #ifdef hwloc_thread_t topology->set_thread_cpubind = dontset_thread_cpubind; topology->get_thread_cpubind = dontget_thread_cpubind; #endif topology->get_thisproc_last_cpu_location = dontget_thisproc_cpubind; /* cpubind instead of last_cpu_location is ok */ topology->get_thisthread_last_cpu_location = dontget_thisthread_cpubind; /* cpubind instead of last_cpu_location is ok */ topology->get_proc_last_cpu_location = dontget_proc_cpubind; /* cpubind instead of last_cpu_location is ok */ /* TODO: get_thread_last_cpu_location */ topology->set_thisproc_membind = dontset_thisproc_membind; topology->get_thisproc_membind = dontget_thisproc_membind; topology->set_thisthread_membind = dontset_thisthread_membind; topology->get_thisthread_membind = dontget_thisthread_membind; topology->set_proc_membind = dontset_proc_membind; topology->get_proc_membind = dontget_proc_membind; topology->set_area_membind = dontset_area_membind; topology->get_area_membind = dontget_area_membind; topology->alloc_membind = dontalloc_membind; topology->free_membind = dontfree_membind; } /* if not is_thissystem, set_cpubind is fake * and get_cpubind returns the whole system cpuset, * so don't report that set/get_cpubind as supported */ if (topology->is_thissystem) { #define DO(which,kind) \ if (topology->kind) \ topology->support.which##bind->kind = 1; DO(cpu,set_thisproc_cpubind); DO(cpu,get_thisproc_cpubind); DO(cpu,set_proc_cpubind); DO(cpu,get_proc_cpubind); DO(cpu,set_thisthread_cpubind); DO(cpu,get_thisthread_cpubind); DO(cpu,set_thread_cpubind); DO(cpu,get_thread_cpubind); DO(cpu,get_thisproc_last_cpu_location); DO(cpu,get_proc_last_cpu_location); DO(cpu,get_thisthread_last_cpu_location); DO(mem,set_thisproc_membind); DO(mem,get_thisproc_membind); DO(mem,set_thisthread_membind); DO(mem,get_thisthread_membind); DO(mem,set_proc_membind); DO(mem,get_proc_membind); DO(mem,set_area_membind); DO(mem,get_area_membind); DO(mem,alloc_membind); } return 0; } /* To be before discovery is actually launched, * Resets everything in case a previous load initialized some stuff. */ static void hwloc_topology_setup_defaults(struct hwloc_topology *topology) { struct hwloc_obj *root_obj; /* reset support */ topology->set_thisproc_cpubind = NULL; topology->get_thisproc_cpubind = NULL; topology->set_thisthread_cpubind = NULL; topology->get_thisthread_cpubind = NULL; topology->set_proc_cpubind = NULL; topology->get_proc_cpubind = NULL; #ifdef hwloc_thread_t topology->set_thread_cpubind = NULL; topology->get_thread_cpubind = NULL; #endif topology->set_thisproc_membind = NULL; topology->get_thisproc_membind = NULL; topology->set_thisthread_membind = NULL; topology->get_thisthread_membind = NULL; topology->set_proc_membind = NULL; topology->get_proc_membind = NULL; topology->set_area_membind = NULL; topology->get_area_membind = NULL; topology->alloc = NULL; topology->alloc_membind = NULL; topology->free_membind = NULL; memset(topology->support.discovery, 0, sizeof(*topology->support.discovery)); memset(topology->support.cpubind, 0, sizeof(*topology->support.cpubind)); memset(topology->support.membind, 0, sizeof(*topology->support.membind)); /* Only the System object on top by default */ topology->nb_levels = 1; /* there's at least SYSTEM */ topology->next_group_depth = 0; topology->levels[0] = malloc (sizeof (struct hwloc_obj)); topology->level_nbobjects[0] = 1; /* NULLify other levels so that we can detect and free old ones in hwloc_connect_levels() if needed */ memset(topology->levels+1, 0, (HWLOC_DEPTH_MAX-1)*sizeof(*topology->levels)); /* Create the actual machine object, but don't touch its attributes yet * since the OS backend may still change the object into something else * (for instance System) */ root_obj = hwloc_alloc_setup_object(HWLOC_OBJ_MACHINE, 0); root_obj->depth = 0; root_obj->logical_index = 0; root_obj->sibling_rank = 0; topology->levels[0][0] = root_obj; } int hwloc_topology_init (struct hwloc_topology **topologyp) { struct hwloc_topology *topology; int i; topology = malloc (sizeof (struct hwloc_topology)); if(!topology) return -1; /* Setup topology context */ topology->is_loaded = 0; topology->flags = 0; topology->is_thissystem = 1; topology->backend_type = HWLOC_BACKEND_NONE; /* backend not specified by default */ topology->pid = 0; topology->support.discovery = malloc(sizeof(*topology->support.discovery)); topology->support.cpubind = malloc(sizeof(*topology->support.cpubind)); topology->support.membind = malloc(sizeof(*topology->support.membind)); /* Only ignore useless cruft by default */ for(i=0; i< HWLOC_OBJ_TYPE_MAX; i++) topology->ignored_types[i] = HWLOC_IGNORE_TYPE_NEVER; topology->ignored_types[HWLOC_OBJ_GROUP] = HWLOC_IGNORE_TYPE_KEEP_STRUCTURE; hwloc_topology_distances_init(topology); /* Make the topology look like something coherent but empty */ hwloc_topology_setup_defaults(topology); *topologyp = topology; return 0; } static void hwloc_backend_exit(struct hwloc_topology *topology) { switch (topology->backend_type) { #ifdef HWLOC_LINUX_SYS case HWLOC_BACKEND_SYSFS: hwloc_backend_sysfs_exit(topology); break; #endif #ifdef HWLOC_HAVE_XML case HWLOC_BACKEND_XML: hwloc_backend_xml_exit(topology); break; #endif case HWLOC_BACKEND_SYNTHETIC: hwloc_backend_synthetic_exit(topology); break; default: break; } assert(topology->backend_type == HWLOC_BACKEND_NONE); } int hwloc_topology_set_fsroot(struct hwloc_topology *topology, const char *fsroot_path __hwloc_attribute_unused) { /* cleanup existing backend */ hwloc_backend_exit(topology); #ifdef HWLOC_LINUX_SYS if (hwloc_backend_sysfs_init(topology, fsroot_path) < 0) return -1; #endif /* HWLOC_LINUX_SYS */ return 0; } int hwloc_topology_set_pid(struct hwloc_topology *topology __hwloc_attribute_unused, hwloc_pid_t pid __hwloc_attribute_unused) { #ifdef HWLOC_LINUX_SYS topology->pid = pid; return 0; #else /* HWLOC_LINUX_SYS */ errno = ENOSYS; return -1; #endif /* HWLOC_LINUX_SYS */ } int hwloc_topology_set_synthetic(struct hwloc_topology *topology, const char *description) { /* cleanup existing backend */ hwloc_backend_exit(topology); return hwloc_backend_synthetic_init(topology, description); } int hwloc_topology_set_xml(struct hwloc_topology *topology __hwloc_attribute_unused, const char *xmlpath __hwloc_attribute_unused) { #ifdef HWLOC_HAVE_XML /* cleanup existing backend */ hwloc_backend_exit(topology); return hwloc_backend_xml_init(topology, xmlpath, NULL, 0); #else /* HWLOC_HAVE_XML */ errno = ENOSYS; return -1; #endif /* !HWLOC_HAVE_XML */ } int hwloc_topology_set_xmlbuffer(struct hwloc_topology *topology __hwloc_attribute_unused, const char *xmlbuffer __hwloc_attribute_unused, int size __hwloc_attribute_unused) { #ifdef HWLOC_HAVE_XML /* cleanup existing backend */ hwloc_backend_exit(topology); return hwloc_backend_xml_init(topology, NULL, xmlbuffer, size); #else /* HWLOC_HAVE_XML */ errno = ENOSYS; return -1; #endif /* !HWLOC_HAVE_XML */ } int hwloc_topology_set_flags (struct hwloc_topology *topology, unsigned long flags) { topology->flags = flags; return 0; } int hwloc_topology_ignore_type(struct hwloc_topology *topology, hwloc_obj_type_t type) { if (type >= HWLOC_OBJ_TYPE_MAX) { errno = EINVAL; return -1; } if (type == HWLOC_OBJ_PU) { /* we need the PU level */ errno = EINVAL; return -1; } topology->ignored_types[type] = HWLOC_IGNORE_TYPE_ALWAYS; return 0; } int hwloc_topology_ignore_type_keep_structure(struct hwloc_topology *topology, hwloc_obj_type_t type) { if (type >= HWLOC_OBJ_TYPE_MAX) { errno = EINVAL; return -1; } if (type == HWLOC_OBJ_PU) { /* we need the PU level */ errno = EINVAL; return -1; } topology->ignored_types[type] = HWLOC_IGNORE_TYPE_KEEP_STRUCTURE; return 0; } int hwloc_topology_ignore_all_keep_structure(struct hwloc_topology *topology) { unsigned type; for(type=0; typeignored_types[type] = HWLOC_IGNORE_TYPE_KEEP_STRUCTURE; return 0; } static void hwloc_topology_clear_tree (struct hwloc_topology *topology, struct hwloc_obj *root) { unsigned i; for(i=0; iarity; i++) hwloc_topology_clear_tree (topology, root->children[i]); hwloc_free_unlinked_object (root); } static void hwloc_topology_clear (struct hwloc_topology *topology) { unsigned l; hwloc_topology_distances_clear(topology); hwloc_topology_clear_tree (topology, topology->levels[0][0]); for (l=0; lnb_levels; l++) free(topology->levels[l]); } void hwloc_topology_destroy (struct hwloc_topology *topology) { hwloc_topology_clear(topology); hwloc_topology_distances_destroy(topology); hwloc_backend_exit(topology); free(topology->support.discovery); free(topology->support.cpubind); free(topology->support.membind); free(topology); } int hwloc_topology_load (struct hwloc_topology *topology) { char *local_env; int err; if (topology->is_loaded) { hwloc_topology_clear(topology); hwloc_topology_setup_defaults(topology); topology->is_loaded = 0; } /* enforce backend anyway if a FORCE variable was given */ #ifdef HWLOC_LINUX_SYS { char *fsroot_path_env = getenv("HWLOC_FORCE_FSROOT"); if (fsroot_path_env) { hwloc_backend_exit(topology); hwloc_backend_sysfs_init(topology, fsroot_path_env); } } #endif #ifdef HWLOC_HAVE_XML { char *xmlpath_env = getenv("HWLOC_FORCE_XMLFILE"); if (xmlpath_env) { hwloc_backend_exit(topology); hwloc_backend_xml_init(topology, xmlpath_env, NULL, 0); } } #endif /* only apply non-FORCE variables if we have not changed the backend yet */ #ifdef HWLOC_LINUX_SYS if (topology->backend_type == HWLOC_BACKEND_NONE) { char *fsroot_path_env = getenv("HWLOC_FSROOT"); if (fsroot_path_env) hwloc_backend_sysfs_init(topology, fsroot_path_env); } #endif #ifdef HWLOC_HAVE_XML if (topology->backend_type == HWLOC_BACKEND_NONE) { char *xmlpath_env = getenv("HWLOC_XMLFILE"); if (xmlpath_env) hwloc_backend_xml_init(topology, xmlpath_env, NULL, 0); } #endif /* always apply non-FORCE THISSYSTEM since it was explicitly designed to override setups from other backends */ local_env = getenv("HWLOC_THISSYSTEM"); if (local_env) topology->is_thissystem = atoi(local_env); /* if we haven't chosen the backend, set the OS-specific one if needed */ if (topology->backend_type == HWLOC_BACKEND_NONE) { #ifdef HWLOC_LINUX_SYS if (hwloc_backend_sysfs_init(topology, "/") < 0) return -1; #endif } /* get distance matrix from the environment are store them (as indexes) in the topology. * indexes will be converted into objects later once the tree will be filled */ hwloc_store_distances_from_env(topology); /* actual topology discovery */ err = hwloc_discover(topology); if (err < 0) return err; /* enforce THISSYSTEM if given in a FORCE variable */ local_env = getenv("HWLOC_FORCE_THISSYSTEM"); if (local_env) topology->is_thissystem = atoi(local_env); #ifndef HWLOC_DEBUG if (getenv("HWLOC_DEBUG_CHECK")) #endif hwloc_topology_check(topology); topology->is_loaded = 1; return 0; } int hwloc_topology_restrict(struct hwloc_topology *topology, hwloc_const_cpuset_t cpuset, unsigned long flags) { hwloc_bitmap_t droppedcpuset, droppednodeset; /* make sure we'll keep something in the topology */ if (!hwloc_bitmap_intersects(cpuset, topology->levels[0][0]->cpuset)) { errno = EINVAL; return -1; } droppedcpuset = hwloc_bitmap_alloc(); droppednodeset = hwloc_bitmap_alloc(); /* drop object based on the reverse of cpuset, and fill the 'dropped' nodeset */ hwloc_bitmap_not(droppedcpuset, cpuset); restrict_object(topology, flags, &topology->levels[0][0], droppedcpuset, droppednodeset, 0 /* root cannot be removed */); /* update nodesets according to dropped nodeset */ restrict_object_nodeset(topology, &topology->levels[0][0], droppednodeset); hwloc_bitmap_free(droppedcpuset); hwloc_bitmap_free(droppednodeset); hwloc_connect_children(topology->levels[0][0]); hwloc_connect_levels(topology); propagate_total_memory(topology->levels[0][0]); hwloc_restrict_distances(topology, flags); hwloc_convert_distances_indexes_into_objects(topology); hwloc_finalize_logical_distances(topology); return 0; } int hwloc_topology_is_thissystem(struct hwloc_topology *topology) { return topology->is_thissystem; } unsigned hwloc_topology_get_depth(struct hwloc_topology *topology) { return topology->nb_levels; } /* check children between a parent object */ static void hwloc__check_children(struct hwloc_obj *parent) { hwloc_bitmap_t remaining_parent_set; unsigned j; if (!parent->arity) { /* check whether that parent has no children for real */ assert(!parent->children); assert(!parent->first_child); assert(!parent->last_child); return; } /* check whether that parent has children for real */ assert(parent->children); assert(parent->first_child); assert(parent->last_child); /* first child specific checks */ assert(parent->first_child->sibling_rank == 0); assert(parent->first_child == parent->children[0]); assert(parent->first_child->prev_sibling == NULL); /* last child specific checks */ assert(parent->last_child->sibling_rank == parent->arity-1); assert(parent->last_child == parent->children[parent->arity-1]); assert(parent->last_child->next_sibling == NULL); if (parent->cpuset) { remaining_parent_set = hwloc_bitmap_dup(parent->cpuset); for(j=0; jarity; j++) { if (!parent->children[j]->cpuset) continue; /* check that child cpuset is included in the parent */ assert(hwloc_bitmap_isincluded(parent->children[j]->cpuset, remaining_parent_set)); #if !defined(NDEBUG) /* check that children are correctly ordered (see below), empty ones may be anywhere */ if (!hwloc_bitmap_iszero(parent->children[j]->cpuset)) { int firstchild = hwloc_bitmap_first(parent->children[j]->cpuset); int firstparent = hwloc_bitmap_first(remaining_parent_set); assert(firstchild == firstparent); } #endif /* clear previously used parent cpuset bits so that we actually checked above * that children cpusets do not intersect and are ordered properly */ hwloc_bitmap_andnot(remaining_parent_set, remaining_parent_set, parent->children[j]->cpuset); } assert(hwloc_bitmap_iszero(remaining_parent_set)); hwloc_bitmap_free(remaining_parent_set); } /* checks for all children */ for(j=1; jarity; j++) { assert(parent->children[j]->sibling_rank == j); assert(parent->children[j-1]->next_sibling == parent->children[j]); assert(parent->children[j]->prev_sibling == parent->children[j-1]); } } /* check a whole topology structure */ void hwloc_topology_check(struct hwloc_topology *topology) { struct hwloc_obj *obj; hwloc_obj_type_t type; unsigned i, j, depth; /* check type orders */ for (type = HWLOC_OBJ_SYSTEM; type < HWLOC_OBJ_TYPE_MAX; type++) { assert(hwloc_get_order_type(hwloc_get_type_order(type)) == type); } for (i = hwloc_get_type_order(HWLOC_OBJ_SYSTEM); i <= hwloc_get_type_order(HWLOC_OBJ_CORE); i++) { assert(i == hwloc_get_type_order(hwloc_get_order_type(i))); } /* check that last level is PU */ assert(hwloc_get_depth_type(topology, hwloc_topology_get_depth(topology)-1) == HWLOC_OBJ_PU); /* check that other levels are not PU */ for(i=1; idepth == i); assert(obj->logical_index == j); /* check that all objects in the level have the same type */ if (prev) { assert(hwloc_type_cmp(obj, prev) == HWLOC_TYPE_EQUAL); assert(prev->next_cousin == obj); assert(obj->prev_cousin == prev); } if (obj->complete_cpuset) { if (obj->cpuset) assert(hwloc_bitmap_isincluded(obj->cpuset, obj->complete_cpuset)); if (obj->online_cpuset) assert(hwloc_bitmap_isincluded(obj->online_cpuset, obj->complete_cpuset)); if (obj->allowed_cpuset) assert(hwloc_bitmap_isincluded(obj->allowed_cpuset, obj->complete_cpuset)); } if (obj->complete_nodeset) { if (obj->nodeset) assert(hwloc_bitmap_isincluded(obj->nodeset, obj->complete_nodeset)); if (obj->allowed_nodeset) assert(hwloc_bitmap_isincluded(obj->allowed_nodeset, obj->complete_nodeset)); } /* check children */ hwloc__check_children(obj); prev = obj; } /* check first object of the level */ obj = hwloc_get_obj_by_depth(topology, i, 0); assert(obj); assert(!obj->prev_cousin); /* check type */ assert(hwloc_get_depth_type(topology, i) == obj->type); assert(i == (unsigned) hwloc_get_type_depth(topology, obj->type) || HWLOC_TYPE_DEPTH_MULTIPLE == hwloc_get_type_depth(topology, obj->type)); /* check last object of the level */ obj = hwloc_get_obj_by_depth(topology, i, width-1); assert(obj); assert(!obj->next_cousin); /* check last+1 object of the level */ obj = hwloc_get_obj_by_depth(topology, i, width); assert(!obj); } /* check bottom objects */ assert(hwloc_get_nbobjs_by_depth(topology, depth-1) > 0); for(j=0; jtype == HWLOC_OBJ_PU); } } const struct hwloc_topology_support * hwloc_topology_get_support(struct hwloc_topology * topology) { return &topology->support; }