Skip to content

Commit 3fd2469

Browse files
committed
API: add HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT to import support bits from XML
Useful when you want to check whether binding/... is supported on the distant platform. OMPI currently passes this info on the side of the XML. The support bits are still the local ones by default, but may be overwritten with the XML ones when this topology flag is set. The flag doesn't change the fact that binding is disabled by default when loading from XML. Most tools enable this flag so that imported support bits are propagated in output XMLs. Export support to XML may be disabled for debugging with HWLOC_XML_SUPPORT_EXPORT=0. Signed-off-by: Brice Goglin <[email protected]>
1 parent c606f04 commit 3fd2469

25 files changed

+227
-23
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ bug fixes (and other actions) for each version of hwloc since version
2020

2121
Version 2.3.0
2222
-------------
23+
* API
24+
+ The new topology flag HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT causes
25+
support arrays to be loaded from XML exported with hwloc 2.3+.
2326
* Backends
2427
+ Add a ROCm SMI backend and a hwloc/rsmi.h helper file for getting
2528
the locality of AMD GPUs, now exposed as "rsmi" OS devices.

doc/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ man3_configuration_DATA = \
432432
$(DOX_MAN_DIR)/man3/HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED.3 \
433433
$(DOX_MAN_DIR)/man3/HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM.3 \
434434
$(DOX_MAN_DIR)/man3/HWLOC_TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES.3 \
435+
$(DOX_MAN_DIR)/man3/HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT.3 \
435436
$(DOX_MAN_DIR)/man3/hwloc_topology_flags_e.3 \
436437
$(DOX_MAN_DIR)/man3/hwloc_topology_get_flags.3 \
437438
$(DOX_MAN_DIR)/man3/hwloc_topology_set_flags.3 \

doc/hwloc.doxy

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,8 @@ following environment variables.
12611261
HWLOC_XML_USERDATA_NOT_DECODED
12621262
do not decode base64 userdata on import,
12631263
and reexport it the same (used by tools for leaving userdata untouched)
1264+
HWLOC_XML_SUPPORT_EXPORT=0
1265+
don't export support info to XML.
12641266
HWLOC_RSMI_SHUTDOWN
12651267
force rsmi_shutdown to make valgrind happy
12661268
not enabled by default on rsmi <= 3.3.x because those old libs do not

hwloc/hwloc2.dtd

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
<!--
22
Copyright © 2009 CNRS
3-
Copyright © 2009-2019 Inria. All rights reserved.
3+
Copyright © 2009-2020 Inria. All rights reserved.
44
Copyright © 2009-2011 Université Bordeaux.
55
See COPYING in top-level directory.
66

77
This is the DTD for hwloc v2.x XMLs.
88
-->
99

10-
<!ELEMENT topology (object+,distances2*,distances2hetero*)>
10+
<!ELEMENT topology (object+,distances2*,distances2hetero*,support*)>
1111
<!ATTLIST topology version CDATA "">
1212

1313
<!ELEMENT object (page_type*,info*,userdata*,object*)>
@@ -67,3 +67,7 @@
6767
<!ATTLIST userdata name CDATA "" >
6868
<!ATTLIST userdata length CDATA "0" >
6969
<!ATTLIST userdata encoding CDATA "" >
70+
71+
<!ELEMENT support EMPTY>
72+
<!ATTLIST support name CDATA #REQUIRED>
73+
<!ATTLIST support value CDATA "1" >

hwloc/topology-xml.c

Lines changed: 143 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,73 @@ hwloc__xml_import_object(hwloc_topology_t topology,
12391239
return -1;
12401240
}
12411241

1242+
static int
1243+
hwloc__xml_v2import_support(hwloc_topology_t topology,
1244+
hwloc__xml_import_state_t state)
1245+
{
1246+
char *name = NULL;
1247+
int value = 1; /* value is optional */
1248+
while (1) {
1249+
char *attrname, *attrvalue;
1250+
if (state->global->next_attr(state, &attrname, &attrvalue) < 0)
1251+
break;
1252+
if (!strcmp(attrname, "name"))
1253+
name = attrvalue;
1254+
else if (!strcmp(attrname, "value"))
1255+
value = atoi(attrvalue);
1256+
else {
1257+
if (hwloc__xml_verbose())
1258+
fprintf(stderr, "%s: ignoring unknown support attribute %s\n",
1259+
state->global->msgprefix, attrname);
1260+
}
1261+
}
1262+
1263+
if (name && topology->flags & HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT) {
1264+
#ifdef HWLOC_DEBUG
1265+
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_support) == 3*sizeof(void*));
1266+
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_discovery_support) == 5);
1267+
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_cpubind_support) == 11);
1268+
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_membind_support) == 15);
1269+
#endif
1270+
1271+
#define DO(_cat,_name) if (!strcmp(#_cat "." #_name, name)) topology->support._cat->_name = value
1272+
DO(discovery,pu);
1273+
else DO(discovery,numa);
1274+
else DO(discovery,numa_memory);
1275+
else DO(discovery,disallowed_pu);
1276+
else DO(discovery,disallowed_numa);
1277+
else DO(cpubind,set_thisproc_cpubind);
1278+
else DO(cpubind,get_thisproc_cpubind);
1279+
else DO(cpubind,set_proc_cpubind);
1280+
else DO(cpubind,get_proc_cpubind);
1281+
else DO(cpubind,set_thisthread_cpubind);
1282+
else DO(cpubind,get_thisthread_cpubind);
1283+
else DO(cpubind,set_thread_cpubind);
1284+
else DO(cpubind,get_thread_cpubind);
1285+
else DO(cpubind,get_thisproc_last_cpu_location);
1286+
else DO(cpubind,get_proc_last_cpu_location);
1287+
else DO(cpubind,get_thisthread_last_cpu_location);
1288+
else DO(membind,set_thisproc_membind);
1289+
else DO(membind,get_thisproc_membind);
1290+
else DO(membind,set_proc_membind);
1291+
else DO(membind,get_proc_membind);
1292+
else DO(membind,set_thisthread_membind);
1293+
else DO(membind,get_thisthread_membind);
1294+
else DO(membind,set_area_membind);
1295+
else DO(membind,get_area_membind);
1296+
else DO(membind,alloc_membind);
1297+
else DO(membind,firsttouch_membind);
1298+
else DO(membind,bind_membind);
1299+
else DO(membind,interleave_membind);
1300+
else DO(membind,nexttouch_membind);
1301+
else DO(membind,migrate_membind);
1302+
else DO(membind,get_area_memlocation);
1303+
#undef DO
1304+
}
1305+
1306+
return 0;
1307+
}
1308+
12421309
static int
12431310
hwloc__xml_v2import_distances(hwloc_topology_t topology,
12441311
hwloc__xml_import_state_t state,
@@ -1761,6 +1828,10 @@ hwloc_look_xml(struct hwloc_backend *backend, struct hwloc_disc_status *dstatus)
17611828
ret = hwloc__xml_v2import_distances(topology, &childstate, 1);
17621829
if (ret < 0)
17631830
goto failed;
1831+
} else if (!strcmp(tag, "support")) {
1832+
ret = hwloc__xml_v2import_support(topology, &childstate);
1833+
if (ret < 0)
1834+
goto failed;
17641835
} else {
17651836
if (hwloc__xml_verbose())
17661837
fprintf(stderr, "%s: ignoring unknown tag `%s' after root object.\n",
@@ -1866,12 +1937,14 @@ hwloc_look_xml(struct hwloc_backend *backend, struct hwloc_disc_status *dstatus)
18661937
/* keep the "Backend" information intact */
18671938
/* we could add "BackendSource=XML" to notify that XML was used between the actual backend and here */
18681939

1869-
topology->support.discovery->pu = 1;
1870-
topology->support.discovery->disallowed_pu = 1;
1871-
if (data->nbnumanodes) {
1872-
topology->support.discovery->numa = 1;
1873-
topology->support.discovery->numa_memory = 1; // FIXME
1874-
topology->support.discovery->disallowed_numa = 1;
1940+
if (!(topology->flags & HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT)) {
1941+
topology->support.discovery->pu = 1;
1942+
topology->support.discovery->disallowed_pu = 1;
1943+
if (data->nbnumanodes) {
1944+
topology->support.discovery->numa = 1;
1945+
topology->support.discovery->numa_memory = 1; // FIXME
1946+
topology->support.discovery->disallowed_numa = 1;
1947+
}
18751948
}
18761949

18771950
if (data->look_done)
@@ -2622,9 +2695,70 @@ hwloc__xml_v2export_distances(hwloc__xml_export_state_t parentstate, hwloc_topol
26222695
hwloc___xml_v2export_distances(parentstate, dist);
26232696
}
26242697

2698+
static void
2699+
hwloc__xml_v2export_support(hwloc__xml_export_state_t parentstate, hwloc_topology_t topology)
2700+
{
2701+
struct hwloc__xml_export_state_s state;
2702+
char tmp[11];
2703+
2704+
#ifdef HWLOC_DEBUG
2705+
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_support) == 3*sizeof(void*));
2706+
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_discovery_support) == 5);
2707+
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_cpubind_support) == 11);
2708+
HWLOC_BUILD_ASSERT(sizeof(struct hwloc_topology_membind_support) == 15);
2709+
#endif
2710+
2711+
#define DO(_cat,_name) do { \
2712+
if (topology->support._cat->_name) { \
2713+
parentstate->new_child(parentstate, &state, "support"); \
2714+
state.new_prop(&state, "name", #_cat "." #_name); \
2715+
if (topology->support._cat->_name != 1) { \
2716+
sprintf(tmp, "%u", topology->support._cat->_name); \
2717+
state.new_prop(&state, "value", tmp); \
2718+
} \
2719+
state.end_object(&state, "support"); \
2720+
} \
2721+
} while (0)
2722+
2723+
DO(discovery,pu);
2724+
DO(discovery,numa);
2725+
DO(discovery,numa_memory);
2726+
DO(discovery,disallowed_pu);
2727+
DO(discovery,disallowed_numa);
2728+
DO(cpubind,set_thisproc_cpubind);
2729+
DO(cpubind,get_thisproc_cpubind);
2730+
DO(cpubind,set_proc_cpubind);
2731+
DO(cpubind,get_proc_cpubind);
2732+
DO(cpubind,set_thisthread_cpubind);
2733+
DO(cpubind,get_thisthread_cpubind);
2734+
DO(cpubind,set_thread_cpubind);
2735+
DO(cpubind,get_thread_cpubind);
2736+
DO(cpubind,get_thisproc_last_cpu_location);
2737+
DO(cpubind,get_proc_last_cpu_location);
2738+
DO(cpubind,get_thisthread_last_cpu_location);
2739+
DO(membind,set_thisproc_membind);
2740+
DO(membind,get_thisproc_membind);
2741+
DO(membind,set_proc_membind);
2742+
DO(membind,get_proc_membind);
2743+
DO(membind,set_thisthread_membind);
2744+
DO(membind,get_thisthread_membind);
2745+
DO(membind,set_area_membind);
2746+
DO(membind,get_area_membind);
2747+
DO(membind,alloc_membind);
2748+
DO(membind,firsttouch_membind);
2749+
DO(membind,bind_membind);
2750+
DO(membind,interleave_membind);
2751+
DO(membind,nexttouch_membind);
2752+
DO(membind,migrate_membind);
2753+
DO(membind,get_area_memlocation);
2754+
2755+
#undef DO
2756+
}
2757+
26252758
void
26262759
hwloc__xml_export_topology(hwloc__xml_export_state_t state, hwloc_topology_t topology, unsigned long flags)
26272760
{
2761+
char *env;
26282762
hwloc_obj_t root = hwloc_get_root_obj(topology);
26292763

26302764
if (flags & HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1) {
@@ -2667,6 +2801,9 @@ hwloc__xml_export_topology(hwloc__xml_export_state_t state, hwloc_topology_t top
26672801
} else {
26682802
hwloc__xml_v2export_object (state, topology, root, flags);
26692803
hwloc__xml_v2export_distances (state, topology);
2804+
env = getenv("HWLOC_XML_EXPORT_SUPPORT");
2805+
if (!env || atoi(env))
2806+
hwloc__xml_v2export_support(state, topology);
26702807
}
26712808
}
26722809

hwloc/topology.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3696,7 +3696,7 @@ hwloc_topology_set_flags (struct hwloc_topology *topology, unsigned long flags)
36963696
return -1;
36973697
}
36983698

3699-
if (flags & ~(HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED|HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM|HWLOC_TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES)) {
3699+
if (flags & ~(HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED|HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM|HWLOC_TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES|HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT)) {
37003700
errno = EINVAL;
37013701
return -1;
37023702
}

include/hwloc.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1940,7 +1940,28 @@ enum hwloc_topology_flags_e {
19401940
* would result in the same behavior.
19411941
* \hideinitializer
19421942
*/
1943-
HWLOC_TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES = (1UL<<2)
1943+
HWLOC_TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES = (1UL<<2),
1944+
1945+
/** \brief Import support from the imported topology.
1946+
*
1947+
* When importing a XML topology from a remote machine, binding is
1948+
* disabled by default (see ::HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM).
1949+
* This disabling is also marked by putting zeroes in the corresponding
1950+
* supported feature bits reported by hwloc_topology_get_support().
1951+
*
1952+
* The flag ::HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT actually imports
1953+
* support bits from the remote machine.
1954+
*
1955+
* Note that these supported features are only relevant for the hwloc
1956+
* installation that actually exported the XML topology
1957+
* (it may vary with the operating system, or with how hwloc was compiled).
1958+
*
1959+
* Note that setting this flag however does not enable binding for the
1960+
* locally imported hwloc topology, it only reports what the remote
1961+
* hwloc and machine support.
1962+
*
1963+
*/
1964+
HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT = (1UL<<3)
19441965
};
19451966

19461967
/** \brief Set OR'ed flags to non-yet-loaded topology.
@@ -2073,6 +2094,17 @@ struct hwloc_topology_support {
20732094
* call may still fail in some corner cases.
20742095
*
20752096
* These features are also listed by hwloc-info \--support
2097+
*
2098+
* The reported features are what the current topology supports
2099+
* on the current machine. If the topology was exported to XML
2100+
* from another machine and later imported here, support still
2101+
* describes what is supported for this imported topology after
2102+
* import. By default, binding will be reported as unsupported
2103+
* in this case (see ::HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM).
2104+
*
2105+
* Topology flag ::HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT may be used
2106+
* to report the supported features of the original remote machine
2107+
* instead.
20762108
*/
20772109
HWLOC_DECLSPEC const struct hwloc_topology_support *hwloc_topology_get_support(hwloc_topology_t __hwloc_restrict topology);
20782110

include/hwloc/rename.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
3-
* Copyright © 2010-2019 Inria. All rights reserved.
3+
* Copyright © 2010-2020 Inria. All rights reserved.
44
* See COPYING in top-level directory.
55
*/
66

@@ -119,6 +119,7 @@ extern "C" {
119119
#define HWLOC_TOPOLOGY_FLAG_INCLUDE_DISALLOWED HWLOC_NAME_CAPS(TOPOLOGY_FLAG_WITH_DISALLOWED)
120120
#define HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM HWLOC_NAME_CAPS(TOPOLOGY_FLAG_IS_THISSYSTEM)
121121
#define HWLOC_TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES HWLOC_NAME_CAPS(TOPOLOGY_FLAG_THISSYSTEM_ALLOWED_RESOURCES)
122+
#define HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT HWLOC_NAME_CAPS(TOPOLOGY_FLAG_IMPORT_SUPPORT)
122123

123124
#define hwloc_topology_set_pid HWLOC_NAME(topology_set_pid)
124125
#define hwloc_topology_set_synthetic HWLOC_NAME(topology_set_synthetic)

tests/hwloc/hwloc_insert_misc.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Copyright © 2009 CNRS
3-
* Copyright © 2009-2017 Inria. All rights reserved.
3+
* Copyright © 2009-2020 Inria. All rights reserved.
44
* Copyright © 2009-2010 Université Bordeaux
55
* Copyright © 2011 Cisco Systems, Inc. All rights reserved.
66
* See COPYING in top-level directory.
@@ -78,6 +78,8 @@ int main(void)
7878
assert(!err);
7979
err = hwloc_topology_set_type_filter(reload, HWLOC_OBJ_MISC, HWLOC_TYPE_FILTER_KEEP_ALL);
8080
assert(!err);
81+
err = hwloc_topology_set_flags(reload, HWLOC_TOPOLOGY_FLAG_IMPORT_SUPPORT);
82+
assert(!err);
8183
err = hwloc_topology_load(reload);
8284
assert(!err);
8385
hwloc_topology_check(reload);

tests/hwloc/linux/allowed/test-topology.sh.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ export HWLOC_THISSYSTEM_ALLOWED_RESOURCES
2828
HWLOC_DONT_ADD_VERSION_INFO=1
2929
export HWLOC_DONT_ADD_VERSION_INFO
3030

31+
HWLOC_XML_EXPORT_SUPPORT=0
32+
export HWLOC_XML_EXPORT_SUPPORT
33+
3134
actual_output="$1"
3235

3336
# make sure we use default numeric formats (only XML outputs are dis-localized when supported)

0 commit comments

Comments
 (0)