Skip to content

Commit 0a7b1c6

Browse files
authored
Merge pull request #84 from openpmix/master
Fork Sync: Update from parent repository
2 parents 2be6580 + b42fe93 commit 0a7b1c6

24 files changed

+444
-94
lines changed

src/docs/prrte-rst-content/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ dist_rst_DATA = \
4848
cli-no-app-prefix.rst \
4949
cli-rank-by.rst \
5050
cli-runtime-options.rst \
51+
cli-set-env.rst \
5152
cli-stream-buffering.rst \
5253
cli-tune.rst \
5354
cli-unset-env.rst \

src/docs/prrte-rst-content/cli-display.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.. -*- rst -*-
22
3-
Copyright (c) 2022-2023 Nanook Consulting. All rights reserved.
3+
Copyright (c) 2022-2025 Nanook Consulting All rights reserved.
44
Copyright (c) 2023 Jeffrey M. Squyres. All rights reserved.
55
66
$COPYRIGHT$
@@ -50,4 +50,8 @@ colon (``:``) and any combination of one or more of the following
5050
is easily parsed by machines. Note that ``PARSABLE`` is also accepted as
5151
a typical spelling for the qualifier.
5252

53-
Provided qualifiers will apply to *all* of the display directives.
53+
* ``PHYSICAL`` directs that the output of the ``BINDINGS`` option be displayed
54+
using physical (instead of logical) CPU IDs.
55+
56+
Provided qualifiers will apply to *all* of the display directives unless
57+
noted.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.. -*- rst -*-
2+
3+
Copyright (c) 2022-2025 Nanook Consulting All rights reserved.
4+
Copyright (c) 2023 Jeffrey M. Squyres. All rights reserved.
5+
6+
$COPYRIGHT$
7+
8+
Additional copyrights may follow
9+
10+
$HEADER$
11+
12+
.. The following line is included so that Sphinx won't complain
13+
about this file not being directly included in some toctree
14+
15+
Set the named environmental variable to the specified value. This will overwrite the
16+
existing value, if it exists. Equivalent to the "-x foo=val" option

src/hwloc/help-prte-hwloc-base.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,17 @@ The specified binding lies above the mapping object type:
6969
Binding level: %s
7070

7171
Please correct the map/bind directives and try again.
72+
#
73+
[pu-not-found]
74+
Construction of the binding output string failed due to inabilty
75+
to obtain a processor unit object:
76+
77+
PU number: %u
78+
79+
There will be no impact to your application, so we will continue
80+
but will not be able to output the binding locations.
81+
#
82+
[too-many-sites]
83+
At least one process in your application is bound to too many sites
84+
for us to report in a string. There will be no impact to your application
85+
so we will continue but will not be able to output the binding locations.

src/hwloc/hwloc-internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Copyright (c) 2018 Research Organization for Information Science
88
* and Technology (RIST). All rights reserved.
99
*
10-
* Copyright (c) 2021-2024 Nanook Consulting All rights reserved.
10+
* Copyright (c) 2021-2025 Nanook Consulting All rights reserved.
1111
* Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
1212
* $COPYRIGHT$
1313
*
@@ -332,6 +332,7 @@ PRTE_EXPORT int prte_hwloc_base_memory_set(prte_hwloc_base_memory_segment_t *seg
332332
*/
333333
PRTE_EXPORT char *prte_hwloc_base_cset2str(hwloc_const_cpuset_t cpuset,
334334
bool use_hwthread_cpus,
335+
bool physical,
335336
hwloc_topology_t topo);
336337

337338
PRTE_EXPORT void prte_hwloc_get_binding_info(hwloc_const_cpuset_t cpuset,

src/hwloc/hwloc_base_util.c

Lines changed: 179 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,12 +1352,180 @@ void prte_hwloc_get_binding_info(hwloc_const_cpuset_t cpuset,
13521352
}
13531353
}
13541354

1355+
static int compare_unsigned(const void *a, const void *b)
1356+
{
1357+
return (*(unsigned *)a - *(unsigned *)b);
1358+
}
1359+
1360+
/* generate a logical string output of a hwloc_cpuset_t */
1361+
static bool build_map(char *answer, size_t size,
1362+
hwloc_const_cpuset_t bitmap,
1363+
bool use_hwthread_cpus,
1364+
bool physical, bool bits_as_cores,
1365+
hwloc_topology_t topo)
1366+
{
1367+
unsigned indices[2048], id;
1368+
int nsites = 0, n, start, end, idx;
1369+
hwloc_obj_t pu;
1370+
char tmp[128], *prefix;
1371+
bool inrange, first, unique;
1372+
unsigned val;
1373+
1374+
if (bits_as_cores || !use_hwthread_cpus) {
1375+
if (physical) {
1376+
prefix = "core:P";
1377+
} else {
1378+
prefix = "core:L";
1379+
}
1380+
} else {
1381+
if (physical) {
1382+
prefix = "hwt:P";
1383+
} else {
1384+
prefix = "hwt:L";
1385+
}
1386+
}
1387+
1388+
for (id = hwloc_bitmap_first(bitmap);
1389+
id != (unsigned)-1;
1390+
id = hwloc_bitmap_next(bitmap, id)) {
1391+
// id is the physical ID for the given PU
1392+
if (bits_as_cores) {
1393+
pu = hwloc_get_obj_by_type(topo, HWLOC_OBJ_CORE, id);
1394+
} else if (!use_hwthread_cpus) {
1395+
// the id's are for threads, but we want cores
1396+
pu = hwloc_get_pu_obj_by_os_index(topo, id);
1397+
// go upward to find the core that contains this pu
1398+
while (NULL != pu && pu->type != HWLOC_OBJ_CORE) {
1399+
pu = pu->parent;
1400+
}
1401+
if (NULL == pu) {
1402+
return false;
1403+
}
1404+
} else {
1405+
pu = hwloc_get_pu_obj_by_os_index(topo, id);
1406+
}
1407+
if (NULL == pu) {
1408+
pmix_show_help("help-prte-hwloc-base.txt", "pu-not-found", true, id);
1409+
return false;
1410+
}
1411+
if (physical) {
1412+
// record the physical site
1413+
val = pu->os_index;
1414+
} else {
1415+
// record the logical site
1416+
val = pu->logical_index;
1417+
}
1418+
// add it uniquely to the array of indices - it could be a duplicate
1419+
// if we are looking for cores
1420+
unique = true;
1421+
for (n=0; n < nsites; n++) {
1422+
if (indices[n] == val) {
1423+
unique = false;
1424+
break;
1425+
}
1426+
}
1427+
if (unique) {
1428+
indices[nsites] = val;
1429+
++nsites;
1430+
if (2048 == nsites) {
1431+
pmix_show_help("help-prte-hwloc-base.txt", "too-many-sites", true);
1432+
return false;
1433+
}
1434+
}
1435+
1436+
}
1437+
1438+
/* this should never happen as it would mean that the bitmap was
1439+
* empty, which is something we checked before calling this function */
1440+
if (0 == nsites) {
1441+
return false;
1442+
}
1443+
1444+
if (1 == nsites) {
1445+
// only bound to one location - most common case
1446+
snprintf(answer, size, "%s%u", prefix, indices[0]);
1447+
return true;
1448+
}
1449+
1450+
// sort them
1451+
qsort(indices, nsites, sizeof(unsigned), compare_unsigned);
1452+
1453+
// parse through and look for ranges
1454+
start = indices[0];
1455+
end = indices[0];
1456+
inrange = false;
1457+
first = true;
1458+
// prep the answer
1459+
snprintf(answer, size, "%s", prefix);
1460+
idx = strlen(prefix);
1461+
1462+
for (n=1; n < nsites; n++) {
1463+
// see if we are in a range
1464+
if (1 == (indices[n]-end)) {
1465+
inrange = true;
1466+
end = indices[n];
1467+
continue;
1468+
}
1469+
// we are not in a range, or we are
1470+
// at the end of a range
1471+
if (inrange) {
1472+
// we are at the end of the range
1473+
if (start == end) {
1474+
if (first) {
1475+
snprintf(tmp, 128, "%u", start);
1476+
first = false;
1477+
} else {
1478+
snprintf(tmp, 128, ",%u", start);
1479+
}
1480+
memcpy(&answer[idx], tmp, strlen(tmp));
1481+
idx += strlen(tmp);
1482+
} else {
1483+
if (first) {
1484+
snprintf(tmp, 128, "%u-%u", start, end);
1485+
first = false;
1486+
} else {
1487+
snprintf(tmp, 128, ",%u-%u", start, end);
1488+
}
1489+
memcpy(&answer[idx], tmp, strlen(tmp));
1490+
idx += strlen(tmp);
1491+
}
1492+
// mark the end of the range
1493+
inrange = false;
1494+
start = indices[n];
1495+
end = indices[n];
1496+
} else {
1497+
inrange = true;
1498+
end = indices[n];
1499+
}
1500+
}
1501+
// see if we have a dangling entry
1502+
if (start == end) {
1503+
if (first) {
1504+
snprintf(tmp, 128, "%u", start);
1505+
} else {
1506+
snprintf(tmp, 128, ",%u", start);
1507+
}
1508+
memcpy(&answer[idx], tmp, strlen(tmp));
1509+
snprintf(tmp, 128, "%u", start);
1510+
} else {
1511+
if (first) {
1512+
snprintf(tmp, 128, "%u-%u", start, end);
1513+
first = false;
1514+
} else {
1515+
snprintf(tmp, 128, ",%u-%u", start, end);
1516+
}
1517+
memcpy(&answer[idx], tmp, strlen(tmp));
1518+
idx += strlen(tmp);
1519+
}
1520+
return true;
1521+
}
13551522

13561523
/*
13571524
* Make a prettyprint string for a hwloc_cpuset_t
13581525
*/
13591526
char *prte_hwloc_base_cset2str(hwloc_const_cpuset_t cpuset,
13601527
bool use_hwthread_cpus,
1528+
bool physical,
13611529
hwloc_topology_t topo)
13621530
{
13631531
int n, npkgs, npus, ncores;
@@ -1366,6 +1534,7 @@ char *prte_hwloc_base_cset2str(hwloc_const_cpuset_t cpuset,
13661534
char **output = NULL, *result;
13671535
hwloc_obj_t pkg;
13681536
bool bits_as_cores = false;
1537+
bool complete;
13691538

13701539
/* if the cpuset is all zero, then something is wrong */
13711540
if (hwloc_bitmap_iszero(cpuset)) {
@@ -1403,19 +1572,17 @@ char *prte_hwloc_base_cset2str(hwloc_const_cpuset_t cpuset,
14031572
if (hwloc_bitmap_iszero(avail)) {
14041573
continue;
14051574
}
1406-
if (bits_as_cores) {
1407-
/* can just use the hwloc fn directly */
1408-
hwloc_bitmap_list_snprintf(tmp, 2048, avail);
1409-
snprintf(ans, 4096, "package[%d][core:%s]", n, tmp);
1410-
} else if (use_hwthread_cpus) {
1411-
/* can just use the hwloc fn directly */
1412-
hwloc_bitmap_list_snprintf(tmp, 2048, avail);
1413-
snprintf(ans, 4096, "package[%d][hwt:%s]", n, tmp);
1575+
// build the map for this cpuset
1576+
complete = build_map(tmp, 2048, avail, use_hwthread_cpus,
1577+
physical, bits_as_cores, topo);
1578+
if (complete) {
1579+
if (physical) {
1580+
snprintf(ans, 4096, "package[%d][%s]", n, tmp);
1581+
} else {
1582+
snprintf(ans, 4096, "package[%d][%s]", n, tmp);
1583+
}
14141584
} else {
1415-
prte_hwloc_build_map(topo, avail, use_hwthread_cpus | bits_as_cores, coreset);
1416-
/* now print out the string */
1417-
hwloc_bitmap_list_snprintf(tmp, 2048, coreset);
1418-
snprintf(ans, 4096, "package[%d][core:%s]", n, tmp);
1585+
snprintf(ans, 4096, "package[%d][N/A]", n);
14191586
}
14201587
PMIX_ARGV_APPEND_NOSIZE_COMPAT(&output, ans);
14211588
}

src/mca/odls/base/odls_base_bind.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ static void report_binding(prte_job_t *jobdat, int rank)
6464
char *tmp1;
6565
hwloc_cpuset_t mycpus;
6666
bool use_hwthread_cpus;
67+
bool physical;
6768

6869
/* check for type of cpu being used */
6970
if (prte_get_attribute(&jobdat->attributes, PRTE_JOB_HWT_CPUS, NULL, PMIX_BOOL)) {
@@ -76,7 +77,8 @@ static void report_binding(prte_job_t *jobdat, int rank)
7677
if (hwloc_get_cpubind(prte_hwloc_topology, mycpus, HWLOC_CPUBIND_PROCESS) < 0) {
7778
pmix_output(0, "Rank %d is not bound", rank);
7879
} else {
79-
tmp1 = prte_hwloc_base_cset2str(mycpus, use_hwthread_cpus, prte_hwloc_topology);
80+
physical = prte_get_attribute(&jobdat->attributes, PRTE_JOB_REPORT_PHYSICAL_CPUS, NULL, PMIX_BOOL);
81+
tmp1 = prte_hwloc_base_cset2str(mycpus, use_hwthread_cpus, physical, prte_hwloc_topology);
8082
pmix_output(0, "Rank %d bound to %s", rank, tmp1);
8183
free(tmp1);
8284
}

src/mca/rmaps/base/rmaps_base_binding.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,10 @@ static int bind_generic(prte_job_t *jdata, prte_proc_t *proc,
151151
hwloc_bitmap_list_asprintf(&proc->cpuset, tgtcpus); // bind to the entire target object
152152
if (4 < pmix_output_get_verbosity(prte_rmaps_base_framework.framework_output)) {
153153
char *tmp1;
154-
tmp1 = prte_hwloc_base_cset2str(trg_obj->cpuset, options->use_hwthreads, node->topology->topo);
154+
bool physical;
155+
physical = prte_get_attribute(&jdata->attributes, PRTE_JOB_REPORT_PHYSICAL_CPUS, NULL, PMIX_BOOL);
156+
tmp1 = prte_hwloc_base_cset2str(trg_obj->cpuset, options->use_hwthreads,
157+
physical, node->topology->topo);
155158
pmix_output(prte_rmaps_base_framework.framework_output, "%s BOUND PROC %s[%s] TO %s",
156159
PRTE_NAME_PRINT(PRTE_PROC_MY_NAME), PRTE_NAME_PRINT(&proc->name),
157160
node->name, tmp1);

src/mca/rmaps/base/rmaps_base_map_job.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,10 @@ void prte_rmaps_base_report_bindings(prte_job_t *jdata,
10281028
char **cache = NULL;
10291029
char *out, *tmp;
10301030
pmix_proc_t source;
1031+
bool physical;
10311032

1033+
// see if we are to report physical (vs logical) cpu IDs
1034+
physical = prte_get_attribute(&jdata->attributes, PRTE_JOB_REPORT_PHYSICAL_CPUS, NULL, PMIX_BOOL);
10321035
for (n=0; n < jdata->procs->size; n++) {
10331036
proc = (prte_proc_t*)pmix_pointer_array_get_item(jdata->procs, n);
10341037
if (NULL == proc) {
@@ -1041,6 +1044,7 @@ void prte_rmaps_base_report_bindings(prte_job_t *jdata,
10411044
hwloc_bitmap_list_sscanf(prte_rmaps_base.available, proc->cpuset);
10421045
tmp = prte_hwloc_base_cset2str(prte_rmaps_base.available,
10431046
options->use_hwthreads,
1047+
physical,
10441048
proc->node->topology->topo);
10451049
pmix_asprintf(&out, "Proc %s Node %s bound to %s",
10461050
PRTE_NAME_PRINT(&proc->name),
@@ -1050,12 +1054,14 @@ void prte_rmaps_base_report_bindings(prte_job_t *jdata,
10501054
PMIX_ARGV_APPEND_NOSIZE_COMPAT(&cache, out);
10511055
free(out);
10521056
}
1057+
10531058
if (NULL == cache) {
10541059
out = strdup("Error: job has no procs");
10551060
} else {
10561061
/* add a blank line with \n on it so IOF will output the last line */
10571062
PMIX_ARGV_APPEND_NOSIZE_COMPAT(&cache, "");
10581063
out = PMIX_ARGV_JOIN_COMPAT(cache, '\n');
1064+
PMIX_ARGV_FREE_COMPAT(cache);
10591065
}
10601066
PMIX_LOAD_PROCID(&source, jdata->nspace, PMIX_RANK_WILDCARD);
10611067
prte_iof_base_output(&source, PMIX_FWD_STDOUT_CHANNEL, out);
@@ -1366,8 +1372,8 @@ static void inherit_env_directives(prte_job_t *jdata,
13661372
}
13671373

13681374
// if it doesn't exist, then inherit it
1369-
prte_prepend_attribute(&jdata->attributes, attr->key, PRTE_ATTR_GLOBAL,
1370-
envar, PMIX_ENVAR);
1375+
prte_set_attribute(&jdata->attributes, attr->key, PRTE_ATTR_GLOBAL,
1376+
envar, PMIX_ENVAR);
13711377
}
13721378

13731379
/* There is no one-to-one correlation between the apps, but we can
@@ -1419,8 +1425,8 @@ static void inherit_env_directives(prte_job_t *jdata,
14191425
}
14201426

14211427
// if it doesn't exist, then inherit it
1422-
prte_prepend_attribute(&app2->attributes, attr->key, PRTE_ATTR_GLOBAL,
1423-
envar, PMIX_ENVAR);
1428+
prte_set_attribute(&app2->attributes, attr->key, PRTE_ATTR_GLOBAL,
1429+
envar, PMIX_ENVAR);
14241430
}
14251431
}
14261432

0 commit comments

Comments
 (0)