Skip to content

Commit bdf2d98

Browse files
committed
memattrs: add HWLOC_MEMTIERS envvar to force some tiers
Or to disable everything entirely. Signed-off-by: Brice Goglin <[email protected]>
1 parent f6bb115 commit bdf2d98

File tree

3 files changed

+189
-4
lines changed

3 files changed

+189
-4
lines changed

doc/hwloc.doxy

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,6 +1128,14 @@ following environment variables.
11281128
assume all SPM nodes are HBM, assume node0 is in the DRAM tier
11291129
-->
11301130

1131+
<dt>HWLOC_MEMTIERS=0x0f=HBM;0xf=DRAM</dt>
1132+
<dd>Enforce the memory tiers from the given semi-colon separated list.
1133+
Each entry specifies a bitmask (nodeset) of NUMA nodes and their subtype.
1134+
Nodes not listed in any entry are not placed in any tier.
1135+
1136+
If an empty value or <tt>none</tt> is given, tiers are entirely disabled.
1137+
</dd>
1138+
11311139
<dt>HWLOC_GROUPING=1</dt>
11321140
<dd>enables or disables objects grouping based on distances.
11331141
By default, hwloc uses distance matrices between objects (either read

hwloc/memattrs.c

Lines changed: 147 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,31 @@ static const char * hwloc_memory_tier_type_snprintf(hwloc_memory_tier_type_t typ
12501250
}
12511251
}
12521252

1253+
static hwloc_memory_tier_type_t hwloc_memory_tier_type_sscanf(const char *name)
1254+
{
1255+
if (!strcasecmp(name, "DRAM"))
1256+
return HWLOC_MEMORY_TIER_DRAM;
1257+
if (!strcasecmp(name, "HBM"))
1258+
return HWLOC_MEMORY_TIER_HBM;
1259+
if (!strcasecmp(name, "GPUMemory"))
1260+
return HWLOC_MEMORY_TIER_GPU;
1261+
if (!strcasecmp(name, "SPM"))
1262+
return HWLOC_MEMORY_TIER_SPM;
1263+
if (!strcasecmp(name, "NVM"))
1264+
return HWLOC_MEMORY_TIER_NVM;
1265+
if (!strcasecmp(name, "CXL-DRAM"))
1266+
return HWLOC_MEMORY_TIER_CXL|HWLOC_MEMORY_TIER_DRAM;
1267+
if (!strcasecmp(name, "CXL-HBM"))
1268+
return HWLOC_MEMORY_TIER_CXL|HWLOC_MEMORY_TIER_HBM;
1269+
if (!strcasecmp(name, "CXL-GPUMemory"))
1270+
return HWLOC_MEMORY_TIER_CXL|HWLOC_MEMORY_TIER_GPU;
1271+
if (!strcasecmp(name, "CXL-SPM"))
1272+
return HWLOC_MEMORY_TIER_CXL|HWLOC_MEMORY_TIER_SPM;
1273+
if (!strcasecmp(name, "CXL-NVM"))
1274+
return HWLOC_MEMORY_TIER_CXL|HWLOC_MEMORY_TIER_NVM;
1275+
return 0;
1276+
}
1277+
12531278
/* factorized tier, grouping multiple nodes */
12541279
struct hwloc_memory_tier_s {
12551280
hwloc_nodeset_t nodeset;
@@ -1629,10 +1654,113 @@ hwloc__guess_memory_tiers_types(hwloc_topology_t topology __hwloc_attribute_unus
16291654
return 0;
16301655
}
16311656

1657+
/* parses something like 0xf=HBM;0x0f=DRAM;0x00f=CXL-DRAM */
1658+
static struct hwloc_memory_tier_s *
1659+
hwloc__force_memory_tiers(hwloc_topology_t topology __hwloc_attribute_unused,
1660+
unsigned *nr_tiers_p,
1661+
const char *_env)
1662+
{
1663+
struct hwloc_memory_tier_s *tiers = NULL;
1664+
unsigned nr_tiers, i;
1665+
hwloc_bitmap_t nodeset = NULL;
1666+
char *env;
1667+
const char *tmp;
1668+
1669+
env = strdup(_env);
1670+
if (!env) {
1671+
fprintf(stderr, "[hwloc/memtiers] failed to duplicate HWLOC_MEMTIERS envvar\n");
1672+
goto out;
1673+
}
1674+
1675+
tmp = env;
1676+
nr_tiers = 1;
1677+
while (1) {
1678+
tmp = strchr(tmp, ';');
1679+
if (!tmp)
1680+
break;
1681+
tmp++;
1682+
nr_tiers++;
1683+
}
1684+
1685+
nodeset = hwloc_bitmap_alloc();
1686+
if (!nodeset) {
1687+
fprintf(stderr, "[hwloc/memtiers] failed to allocated forced tiers' nodeset\n");
1688+
goto out_with_envvar;
1689+
}
1690+
1691+
tiers = calloc(nr_tiers, sizeof(*tiers));
1692+
if (!tiers) {
1693+
fprintf(stderr, "[hwloc/memtiers] failed to allocated forced tiers\n");
1694+
goto out_with_nodeset;
1695+
}
1696+
nr_tiers = 0;
1697+
1698+
tmp = env;
1699+
while (1) {
1700+
char *end;
1701+
char *equal;
1702+
hwloc_memory_tier_type_t type;
1703+
1704+
end = strchr(tmp, ';');
1705+
if (end)
1706+
*end = '\0';
1707+
1708+
equal = strchr(tmp, '=');
1709+
if (!equal) {
1710+
fprintf(stderr, "[hwloc/memtiers] missing `=' before end of forced tier description at `%s'\n", tmp);
1711+
goto out_with_tiers;
1712+
}
1713+
*equal = '\0';
1714+
1715+
hwloc_bitmap_sscanf(nodeset, tmp);
1716+
if (hwloc_bitmap_iszero(nodeset)) {
1717+
fprintf(stderr, "[hwloc/memtiers] empty forced tier nodeset `%s', aborting\n", tmp);
1718+
goto out_with_tiers;
1719+
}
1720+
type = hwloc_memory_tier_type_sscanf(equal+1);
1721+
if (!type)
1722+
hwloc_debug("failed to recognize forced tier type `%s'\n", equal+1);
1723+
tiers[nr_tiers].nodeset = hwloc_bitmap_dup(nodeset);
1724+
tiers[nr_tiers].type = type;
1725+
tiers[nr_tiers].local_bw_min = tiers[nr_tiers].local_bw_max = 0;
1726+
tiers[nr_tiers].local_lat_min = tiers[nr_tiers].local_lat_max = 0;
1727+
nr_tiers++;
1728+
if (!end)
1729+
break;
1730+
tmp = end+1;
1731+
}
1732+
1733+
free(env);
1734+
hwloc_bitmap_free(nodeset);
1735+
hwloc_debug("Forcing %u memory tiers\n", nr_tiers);
1736+
#ifdef HWLOC_DEBUG
1737+
for(i=0; i<nr_tiers; i++) {
1738+
char *s;
1739+
hwloc_bitmap_asprintf(&s, tiers[i].nodeset);
1740+
hwloc_debug(" tier #%u type %lx nodeset %s\n", i, tiers[i].type, s);
1741+
free(s);
1742+
}
1743+
#endif
1744+
*nr_tiers_p = nr_tiers;
1745+
return tiers;
1746+
1747+
out_with_tiers:
1748+
for(i=0; i<nr_tiers; i++)
1749+
hwloc_bitmap_free(tiers[i].nodeset);
1750+
free(tiers);
1751+
out_with_nodeset:
1752+
hwloc_bitmap_free(nodeset);
1753+
out_with_envvar:
1754+
free(env);
1755+
out:
1756+
return NULL;
1757+
}
1758+
16321759
static void
16331760
hwloc__apply_memory_tiers_subtypes(hwloc_topology_t topology,
16341761
unsigned nr_tiers,
1635-
struct hwloc_memory_tier_s *tiers)
1762+
struct hwloc_memory_tier_s *tiers,
1763+
int force)
16361764
{
16371765
hwloc_obj_t node = NULL;
16381766
hwloc_debug("Marking node tiers\n");
@@ -1641,9 +1769,10 @@ hwloc__apply_memory_tiers_subtypes(hwloc_topology_t topology,
16411769
for(j=0; j<nr_tiers; j++) {
16421770
if (hwloc_bitmap_isset(tiers[j].nodeset, node->os_index)) {
16431771
const char *subtype = hwloc_memory_tier_type_snprintf(tiers[j].type);
1644-
if (!node->subtype) { /* don't overwrite the existing subtype */
1772+
if (!node->subtype || force) { /* don't overwrite the existing subtype unless forced */
16451773
if (subtype) { /* don't set a subtype for unknown tiers */
16461774
hwloc_debug(" marking node L#%u P#%u as %s (was %s)\n", node->logical_index, node->os_index, subtype, node->subtype);
1775+
free(node->subtype);
16471776
node->subtype = strdup(subtype);
16481777
}
16491778
} else
@@ -1661,13 +1790,28 @@ hwloc_internal_memattrs_guess_memory_tiers(hwloc_topology_t topology)
16611790
struct hwloc_memory_tier_s *tiers;
16621791
unsigned nr_tiers;
16631792
unsigned i;
1793+
int force_subtype = 0;
1794+
const char *env;
1795+
1796+
env = getenv("HWLOC_MEMTIERS");
1797+
if (env) {
1798+
if (!strcmp(env, "none"))
1799+
goto out;
1800+
tiers = hwloc__force_memory_tiers(topology, &nr_tiers, env);
1801+
if (tiers) {
1802+
assert(nr_tiers > 0);
1803+
force_subtype = 1;
1804+
goto ready;
1805+
}
1806+
}
16641807

16651808
tiers = hwloc__group_memory_tiers(topology, &nr_tiers);
16661809
if (!tiers)
16671810
goto out;
16681811

16691812
hwloc__guess_memory_tiers_types(topology, nr_tiers, tiers);
16701813

1814+
ready:
16711815
#ifdef HWLOC_DEBUG
16721816
for(i=0; i<nr_tiers; i++) {
16731817
char *s;
@@ -1683,7 +1827,7 @@ hwloc_internal_memattrs_guess_memory_tiers(hwloc_topology_t topology)
16831827
}
16841828
#endif
16851829

1686-
hwloc__apply_memory_tiers_subtypes(topology, nr_tiers, tiers);
1830+
hwloc__apply_memory_tiers_subtypes(topology, nr_tiers, tiers, force_subtype);
16871831

16881832
for(i=0; i<nr_tiers; i++)
16891833
hwloc_bitmap_free(tiers[i].nodeset);

tests/hwloc/memtiers.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ main(void)
215215
check_subtypes(new, "NVM", NULL, "HBM", NULL, "HBM");
216216
hwloc_topology_destroy(new);
217217

218-
printf("checking everything can be disabled if HWLOC_MEMTIERS_GUESS=none\n");
218+
printf("checking guessing can be disabled if HWLOC_MEMTIERS_GUESS=none\n");
219219
putenv((char*)"HWLOC_MEMTIERS_GUESS=none");
220220
err = hwloc_topology_init(&new);
221221
assert(!err);
@@ -226,6 +226,39 @@ main(void)
226226
check_subtypes(new, "NVM", NULL, "SPM", NULL, "SPM");
227227
hwloc_topology_destroy(new);
228228

229+
printf("checking all tier stuff can be disabled if HWLOC_MEMTIERS=none\n");
230+
putenv((char*)"HWLOC_MEMTIERS=none");
231+
err = hwloc_topology_init(&new);
232+
assert(!err);
233+
err = hwloc_topology_set_xmlbuffer(new, xmlbuffer, buflen);
234+
assert(!err);
235+
err = hwloc_topology_load(new);
236+
assert(!err);
237+
check_subtypes(new, NULL, NULL, NULL, NULL, NULL);
238+
hwloc_topology_destroy(new);
239+
240+
printf("checking everything can be overwritten with HWLOC_MEMTIERS\n");
241+
putenv((char*)"HWLOC_MEMTIERS=0x5=HBM;0x12=SPM;0x8=DRAM");
242+
err = hwloc_topology_init(&new);
243+
assert(!err);
244+
err = hwloc_topology_set_xmlbuffer(new, xmlbuffer, buflen);
245+
assert(!err);
246+
err = hwloc_topology_load(new);
247+
assert(!err);
248+
check_subtypes(new, "SPM", "HBM", "SPM", "HBM", "DRAM");
249+
hwloc_topology_destroy(new);
250+
251+
printf("checking everything can be overwritten with HWLOC_MEMTIERS with invalid types\n");
252+
putenv((char*)"HWLOC_MEMTIERS=0x14=foo;0xb=HBM");
253+
err = hwloc_topology_init(&new);
254+
assert(!err);
255+
err = hwloc_topology_set_xmlbuffer(new, xmlbuffer, buflen);
256+
assert(!err);
257+
err = hwloc_topology_load(new);
258+
assert(!err);
259+
check_subtypes(new, NULL, "HBM", "HBM", NULL, "HBM");
260+
hwloc_topology_destroy(new);
261+
229262
free(xmlbuffer);
230263

231264
hwloc_topology_destroy(topology);

0 commit comments

Comments
 (0)