Skip to content

Commit

Permalink
distances: allow inserting distance matrices between objects of diffe…
Browse files Browse the repository at this point in the history
…rent types

This may be used for upcoming NVLink distances between GPUs and CPUs,
or roofline-like distances between PUs/Caches/Memories.

Signed-off-by: Brice Goglin <Brice.Goglin@inria.fr>
  • Loading branch information
bgoglin committed Jul 10, 2019
1 parent 25e8f25 commit fa636a1
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 46 deletions.
4 changes: 3 additions & 1 deletion NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ Version 2.1.0
structure.
+ Group objects have a new "dont_merge" attribute to prevent them from
being automatically merged with identical parent or children.
+ Add more distances-related functions:
+ Add more distances-related features:
- Add hwloc_distances_get_name() to retrieve a string describing
what a distances structure contain.
- Add hwloc_distances_get_by_name() to retrieve distances structures
based on their name.
- Add hwloc_distances_release_remove()
- Distances may now cover objects of different types with new kind
HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES.
* Backends
+ Add support for Linux 5.3 new sysfs cpu topology files with Die information.
+ Add support for Intel v2 Extended Topology Enumeration in the x86 backend.
Expand Down
5 changes: 3 additions & 2 deletions hwloc/diff.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright © 2013-2018 Inria. All rights reserved.
* Copyright © 2013-2019 Inria. All rights reserved.
* See COPYING in top-level directory.
*/

Expand Down Expand Up @@ -351,7 +351,8 @@ int hwloc_topology_diff_build(hwloc_topology_t topo1,
err = 1;
break;
}
if (dist1->type != dist2->type
if (dist1->unique_type != dist2->unique_type
|| dist1->different_types || dist2->different_types /* too lazy to support this case */
|| dist1->nbobjs != dist2->nbobjs
|| dist1->kind != dist2->kind
|| memcmp(dist1->values, dist2->values, dist1->nbobjs * dist1->nbobjs * sizeof(*dist1->values))) {
Expand Down
83 changes: 63 additions & 20 deletions hwloc/distances.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ void hwloc_internal_distances_prepare(struct hwloc_topology *topology)
static void hwloc_internal_distances_free(struct hwloc_internal_distances_s *dist)
{
free(dist->name);
free(dist->different_types);
free(dist->indexes);
free(dist->objs);
free(dist->values);
Expand Down Expand Up @@ -111,7 +112,17 @@ static int hwloc_internal_distances_dup_one(struct hwloc_topology *new, struct h
newdist->name = NULL;
}

newdist->type = olddist->type;
if (olddist->different_types) {
newdist->different_types = hwloc_tma_malloc(tma, nbobjs * sizeof(*newdist->different_types));
if (!newdist->different_types) {
assert(!tma || !tma->dontfree); /* this tma cannot fail to allocate */
hwloc_internal_distances_free(newdist);
return -1;
}
memcpy(newdist->different_types, olddist->different_types, nbobjs * sizeof(*newdist->different_types));
} else
newdist->different_types = NULL;
newdist->unique_type = olddist->unique_type;
newdist->nbobjs = nbobjs;
newdist->kind = olddist->kind;
newdist->id = olddist->id;
Expand Down Expand Up @@ -196,7 +207,7 @@ int hwloc_distances_remove_by_depth(hwloc_topology_t topology, int depth)
next = topology->first_dist;
while ((dist = next) != NULL) {
next = dist->next;
if (dist->type == type) {
if (dist->unique_type == type) {
if (next)
next->prev = dist->prev;
else
Expand Down Expand Up @@ -245,17 +256,28 @@ hwloc__groups_by_distances(struct hwloc_topology *topology, unsigned nbobjs, str
*/
static int
hwloc_internal_distances__add(hwloc_topology_t topology, const char *name,
hwloc_obj_type_t type, unsigned nbobjs, hwloc_obj_t *objs, uint64_t *indexes, uint64_t *values,
hwloc_obj_type_t unique_type, hwloc_obj_type_t *different_types,
unsigned nbobjs, hwloc_obj_t *objs, uint64_t *indexes, uint64_t *values,
unsigned long kind)
{
struct hwloc_internal_distances_s *dist = calloc(1, sizeof(*dist));
struct hwloc_internal_distances_s *dist;

if (different_types) {
kind |= HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES; /* the user isn't forced to give it */
} else if (kind & HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES) {
errno = EINVAL;
goto err;
}

dist = calloc(1, sizeof(*dist));
if (!dist)
goto err;

if (name)
dist->name = strdup(name); /* ignore failure */

dist->type = type;
dist->unique_type = unique_type;
dist->different_types = different_types;
dist->nbobjs = nbobjs;
dist->kind = kind;

Expand All @@ -277,7 +299,7 @@ hwloc_internal_distances__add(hwloc_topology_t topology, const char *name,
dist->indexes = malloc(nbobjs * sizeof(*dist->indexes));
if (!dist->indexes)
goto err_with_dist;
if (HWLOC_DIST_TYPE_USE_OS_INDEX(dist->type)) {
if (HWLOC_DIST_TYPE_USE_OS_INDEX(dist->unique_type)) {
for(i=0; i<nbobjs; i++)
dist->indexes[i] = objs[i]->os_index;
} else {
Expand All @@ -302,14 +324,15 @@ hwloc_internal_distances__add(hwloc_topology_t topology, const char *name,
err_with_dist:
free(dist);
err:
free(different_types);
free(objs);
free(indexes);
free(values);
return -1;
}

int hwloc_internal_distances_add_by_index(hwloc_topology_t topology, const char *name,
hwloc_obj_type_t type, unsigned nbobjs, uint64_t *indexes, uint64_t *values,
hwloc_obj_type_t unique_type, hwloc_obj_type_t *different_types, unsigned nbobjs, uint64_t *indexes, uint64_t *values,
unsigned long kind, unsigned long flags)
{
if (nbobjs < 2) {
Expand All @@ -325,7 +348,7 @@ int hwloc_internal_distances_add_by_index(hwloc_topology_t topology, const char
goto err;
}

return hwloc_internal_distances__add(topology, name, type, nbobjs, NULL, indexes, values, kind);
return hwloc_internal_distances__add(topology, name, unique_type, different_types, nbobjs, NULL, indexes, values, kind);

err:
free(indexes);
Expand All @@ -343,6 +366,7 @@ int hwloc_internal_distances_add(hwloc_topology_t topology, const char *name,
unsigned nbobjs, hwloc_obj_t *objs, uint64_t *values,
unsigned long kind, unsigned long flags)
{
hwloc_obj_type_t unique_type, *different_types;
unsigned i, disappeared = 0;

if (nbobjs < 2) {
Expand All @@ -367,7 +391,26 @@ int hwloc_internal_distances_add(hwloc_topology_t topology, const char *name,
nbobjs -= disappeared;
}

if (topology->grouping && (flags & HWLOC_DISTANCES_ADD_FLAG_GROUP)) {
unique_type = objs[0]->type;
for(i=1; i<nbobjs; i++)
if (objs[i]->type != unique_type) {
unique_type = HWLOC_OBJ_TYPE_NONE;
break;
}
if (unique_type == HWLOC_OBJ_TYPE_NONE) {
/* heterogeneous types */
different_types = malloc(nbobjs * sizeof(*different_types));
if (!different_types)
goto err;
for(i=0; i<nbobjs; i++)
different_types[i] = objs[i]->type;

} else {
/* homogeneous types */
different_types = NULL;
}

if (topology->grouping && (flags & HWLOC_DISTANCES_ADD_FLAG_GROUP) && !different_types) {
float full_accuracy = 0.f;
float *accuracies;
unsigned nbaccuracies;
Expand All @@ -382,7 +425,7 @@ int hwloc_internal_distances_add(hwloc_topology_t topology, const char *name,

if (topology->grouping_verbose) {
unsigned j;
int gp = !HWLOC_DIST_TYPE_USE_OS_INDEX(objs[0]->type);
int gp = !HWLOC_DIST_TYPE_USE_OS_INDEX(unique_type);
fprintf(stderr, "Trying to group objects using distance matrix:\n");
fprintf(stderr, "%s", gp ? "gp_index" : "os_index");
for(j=0; j<nbobjs; j++)
Expand All @@ -400,7 +443,7 @@ int hwloc_internal_distances_add(hwloc_topology_t topology, const char *name,
kind, nbaccuracies, accuracies, 1 /* check the first matrice */);
}

return hwloc_internal_distances__add(topology, name, objs[0]->type, nbobjs, objs, NULL, values, kind);
return hwloc_internal_distances__add(topology, name, unique_type, different_types, nbobjs, objs, NULL, values, kind);

err:
free(objs);
Expand All @@ -419,7 +462,6 @@ int hwloc_distances_add(hwloc_topology_t topology,
unsigned nbobjs, hwloc_obj_t *objs, hwloc_uint64_t *values,
unsigned long kind, unsigned long flags)
{
hwloc_obj_type_t type;
unsigned i;
uint64_t *_values;
hwloc_obj_t *_objs;
Expand All @@ -443,9 +485,8 @@ int hwloc_distances_add(hwloc_topology_t topology,

/* no strict need to check for duplicates, things shouldn't break */

type = objs[0]->type;
for(i=1; i<nbobjs; i++)
if (!objs[i] || objs[i]->type != type) {
if (!objs[i]) {
errno = EINVAL;
return -1;
}
Expand Down Expand Up @@ -540,7 +581,8 @@ static int
hwloc_internal_distances_refresh_one(hwloc_topology_t topology,
struct hwloc_internal_distances_s *dist)
{
hwloc_obj_type_t type = dist->type;
hwloc_obj_type_t unique_type = dist->unique_type;
hwloc_obj_type_t *different_types = dist->different_types;
unsigned nbobjs = dist->nbobjs;
hwloc_obj_t *objs = dist->objs;
uint64_t *indexes = dist->indexes;
Expand All @@ -555,15 +597,15 @@ hwloc_internal_distances_refresh_one(hwloc_topology_t topology,
/* TODO use cpuset/nodeset to find pus/numas from the root?
* faster than traversing the entire level?
*/
if (HWLOC_DIST_TYPE_USE_OS_INDEX(type)) {
if (type == HWLOC_OBJ_PU)
if (HWLOC_DIST_TYPE_USE_OS_INDEX(unique_type)) {
if (unique_type == HWLOC_OBJ_PU)
obj = hwloc_get_pu_obj_by_os_index(topology, (unsigned) indexes[i]);
else if (type == HWLOC_OBJ_NUMANODE)
else if (unique_type == HWLOC_OBJ_NUMANODE)
obj = hwloc_get_numanode_obj_by_os_index(topology, (unsigned) indexes[i]);
else
abort();
} else {
obj = hwloc_find_obj_by_type_and_gp_index(topology, type, indexes[i]);
obj = hwloc_find_obj_by_type_and_gp_index(topology, different_types ? different_types[i] : unique_type, indexes[i]);
}
objs[i] = obj;
if (!obj)
Expand Down Expand Up @@ -685,6 +727,7 @@ hwloc_distances_get_one(hwloc_topology_t topology __hwloc_attribute_unused,
memcpy(distances->values, dist->values, nbobjs*nbobjs*sizeof(*distances->values));

distances->kind = dist->kind;

cont->id = dist->id;
return distances;

Expand Down Expand Up @@ -731,7 +774,7 @@ hwloc__distances_get(hwloc_topology_t topology,
if (name && (!dist->name || strcmp(name, dist->name)))
continue;

if (type != HWLOC_OBJ_TYPE_NONE && type != dist->type)
if (type != HWLOC_OBJ_TYPE_NONE && type != dist->unique_type)
continue;

if (kind_from && !(kind_from & dist->kind))
Expand Down
16 changes: 10 additions & 6 deletions hwloc/topology-xml.c
Original file line number Diff line number Diff line change
Expand Up @@ -1415,7 +1415,7 @@ hwloc__xml_v2import_distances(hwloc_topology_t topology,
}
}

hwloc_internal_distances_add_by_index(topology, name, type, nbobjs, indexes, u64values, kind, 0);
hwloc_internal_distances_add_by_index(topology, name, type, NULL, nbobjs, indexes, u64values, kind, 0);

/* prevent freeing below */
indexes = NULL;
Expand Down Expand Up @@ -2200,10 +2200,12 @@ hwloc__xml_export_object_contents (hwloc__xml_export_state_t state, hwloc_topolo
unsigned *logical_to_v2array;
int depth;

if (nbobjs != (unsigned) hwloc_get_nbobjs_by_type(topology, dist->type))
if (nbobjs != (unsigned) hwloc_get_nbobjs_by_type(topology, dist->unique_type))
continue;
if (!(dist->kind & HWLOC_DISTANCES_KIND_MEANS_LATENCY))
continue;
if (dist->kind & HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES)
continue;

logical_to_v2array = malloc(nbobjs * sizeof(*logical_to_v2array));
if (!logical_to_v2array) {
Expand All @@ -2215,7 +2217,7 @@ hwloc__xml_export_object_contents (hwloc__xml_export_state_t state, hwloc_topolo
logical_to_v2array[dist->objs[i]->logical_index] = i;

/* compute the relative depth */
if (dist->type == HWLOC_OBJ_NUMANODE) {
if (dist->unique_type == HWLOC_OBJ_NUMANODE) {
/* for NUMA nodes, use the highest normal-parent depth + 1 */
depth = -1;
for(i=0; i<nbobjs; i++) {
Expand All @@ -2239,7 +2241,7 @@ hwloc__xml_export_object_contents (hwloc__xml_export_state_t state, hwloc_topolo
}
}
done:
depth = hwloc_get_type_depth(topology, dist->type) + parent_with_memory;
depth = hwloc_get_type_depth(topology, dist->unique_type) + parent_with_memory;
}

state->new_child(state, &childstate, "distances");
Expand Down Expand Up @@ -2480,9 +2482,11 @@ hwloc___xml_v2export_distances(hwloc__xml_export_state_t parentstate, struct hwl
unsigned nbobjs = dist->nbobjs;
struct hwloc__xml_export_state_s state;

assert(!dist->different_types); // FIXME

parentstate->new_child(parentstate, &state, "distances2");

state.new_prop(&state, "type", hwloc_obj_type_string(dist->type));
state.new_prop(&state, "type", hwloc_obj_type_string(dist->unique_type));
sprintf(tmp, "%u", nbobjs);
state.new_prop(&state, "nbobjs", tmp);
sprintf(tmp, "%lu", dist->kind);
Expand All @@ -2491,7 +2495,7 @@ hwloc___xml_v2export_distances(hwloc__xml_export_state_t parentstate, struct hwl
state.new_prop(&state, "name", dist->name);

state.new_prop(&state, "indexing",
HWLOC_DIST_TYPE_USE_OS_INDEX(dist->type) ? "os" : "gp");
HWLOC_DIST_TYPE_USE_OS_INDEX(dist->unique_type) ? "os" : "gp");
/* TODO don't hardwire 10 below. either snprintf the max to guess it, or just append until the end of the buffer */
EXPORT_ARRAY(&state, unsigned long long, nbobjs, dist->indexes, "indexes", "%llu", 10);
EXPORT_ARRAY(&state, unsigned long long, nbobjs*nbobjs, dist->values, "u64values", "%llu", 10);
Expand Down
11 changes: 8 additions & 3 deletions include/hwloc/distances.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,12 @@ enum hwloc_distances_kind_e {
* Such values are currently ignored for distance-based grouping.
* \hideinitializer
*/
HWLOC_DISTANCES_KIND_MEANS_BANDWIDTH = (1UL<<3)
HWLOC_DISTANCES_KIND_MEANS_BANDWIDTH = (1UL<<3),

/** \brief This distances structure covers objects of different types.
* \hideinitializer
*/
HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES = (1UL<<4)
};

/** \brief Retrieve distance matrices.
Expand Down Expand Up @@ -241,11 +246,11 @@ enum hwloc_distances_add_flag_e {
* The distance from object i to object j is in slot i*nbobjs+j.
*
* \p kind specifies the kind of distance as a OR'ed set of ::hwloc_distances_kind_e.
* Kind ::HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES will be automatically added
* if objects of different types are given.
*
* \p flags configures the behavior of the function using an optional OR'ed set of
* ::hwloc_distances_add_flag_e.
*
* Objects must be of the same type.
*/
HWLOC_DECLSPEC int hwloc_distances_add(hwloc_topology_t topology,
unsigned nbobjs, hwloc_obj_t *objs, hwloc_uint64_t *values,
Expand Down
1 change: 1 addition & 0 deletions include/hwloc/rename.h
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ extern "C" {
#define HWLOC_DISTANCES_KIND_FROM_USER HWLOC_NAME_CAPS(DISTANCES_KIND_FROM_USER)
#define HWLOC_DISTANCES_KIND_MEANS_LATENCY HWLOC_NAME_CAPS(DISTANCES_KIND_MEANS_LATENCY)
#define HWLOC_DISTANCES_KIND_MEANS_BANDWIDTH HWLOC_NAME_CAPS(DISTANCES_KIND_MEANS_BANDWIDTH)
#define HWLOC_DISTANCES_KIND_HETEROGENEOUS_TYPES HWLOC_NAME_CAPS(DISTANCES_KIND_HETEROGENEOUS_TYPES)

#define hwloc_distances_get HWLOC_NAME(distances_get)
#define hwloc_distances_get_by_depth HWLOC_NAME(distances_get_by_depth)
Expand Down
12 changes: 9 additions & 3 deletions include/private/private.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
#endif
#include <string.h>

#define HWLOC_TOPOLOGY_ABI 0x20100 /* version of the layout of struct topology */
#define HWLOC_TOPOLOGY_ABI 0x20200 /* version of the layout of struct topology */

/*****************************************************
* WARNING:
Expand Down Expand Up @@ -131,7 +131,13 @@ struct hwloc_topology {

struct hwloc_internal_distances_s {
char *name; /* FIXME: needs an API to set it from user */
hwloc_obj_type_t type;

/* if all objects have the same type, different_types is NULL and unique_type is valid.
* otherwise unique_type is HWLOC_OBJ_TYPE_NONE and different_types contains individual objects types.
*/
hwloc_obj_type_t unique_type;
hwloc_obj_type_t *different_types;

/* add union hwloc_obj_attr_u if we ever support groups */
unsigned nbobjs;
uint64_t *indexes; /* array of OS or GP indexes before we can convert them into objs.
Expand Down Expand Up @@ -336,7 +342,7 @@ extern void hwloc_internal_distances_destroy(hwloc_topology_t topology);
extern int hwloc_internal_distances_dup(hwloc_topology_t new, hwloc_topology_t old);
extern void hwloc_internal_distances_refresh(hwloc_topology_t topology);
extern int hwloc_internal_distances_add(hwloc_topology_t topology, const char *name, unsigned nbobjs, hwloc_obj_t *objs, uint64_t *values, unsigned long kind, unsigned long flags);
extern int hwloc_internal_distances_add_by_index(hwloc_topology_t topology, const char *name, hwloc_obj_type_t type, unsigned nbobjs, uint64_t *indexes, uint64_t *values, unsigned long kind, unsigned long flags);
extern int hwloc_internal_distances_add_by_index(hwloc_topology_t topology, const char *name, hwloc_obj_type_t unique_type, hwloc_obj_type_t *different_types, unsigned nbobjs, uint64_t *indexes, uint64_t *values, unsigned long kind, unsigned long flags);
extern void hwloc_internal_distances_invalidate_cached_objs(hwloc_topology_t topology);

/* encode src buffer into target buffer.
Expand Down
2 changes: 1 addition & 1 deletion tests/hwloc/hwloc_topology_abi.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ int main(void)
offset = offsetof(struct hwloc_topology, first_dist);
assert(offset == 696);
size = sizeof(struct hwloc_internal_distances_s);
assert(size == 72);
assert(size == 88);

offset = offsetof(struct hwloc_topology, grouping_next_subkind);
assert(offset == 748);
Expand Down

0 comments on commit fa636a1

Please sign in to comment.