Skip to content

Commit 4722c6b

Browse files
authored
[openmp] Use core_siblings_list if physical_package_id not available (#111831)
On powerpc, physical_package_id may not be available. Currently, this causes openmp to fall back to flat topology and various affinity tests fail. Fix this by parsing core_siblings_list to deterimine which cpus belong to the same socket. This matches what the testing code does. The code to parse the CPU list format thankfully already exists. Fixes #111809.
1 parent 4a0dc3e commit 4722c6b

File tree

2 files changed

+72
-30
lines changed

2 files changed

+72
-30
lines changed

openmp/runtime/src/kmp_affinity.cpp

Lines changed: 71 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,15 +1589,13 @@ kmp_str_buf_t *__kmp_affinity_str_buf_mask(kmp_str_buf_t *buf,
15891589
return buf;
15901590
}
15911591

1592-
// Return (possibly empty) affinity mask representing the offline CPUs
1593-
// Caller must free the mask
1594-
kmp_affin_mask_t *__kmp_affinity_get_offline_cpus() {
1595-
kmp_affin_mask_t *offline;
1596-
KMP_CPU_ALLOC(offline);
1597-
KMP_CPU_ZERO(offline);
1592+
static kmp_affin_mask_t *__kmp_parse_cpu_list(const char *path) {
1593+
kmp_affin_mask_t *mask;
1594+
KMP_CPU_ALLOC(mask);
1595+
KMP_CPU_ZERO(mask);
15981596
#if KMP_OS_LINUX
15991597
int n, begin_cpu, end_cpu;
1600-
kmp_safe_raii_file_t offline_file;
1598+
kmp_safe_raii_file_t file;
16011599
auto skip_ws = [](FILE *f) {
16021600
int c;
16031601
do {
@@ -1606,29 +1604,29 @@ kmp_affin_mask_t *__kmp_affinity_get_offline_cpus() {
16061604
if (c != EOF)
16071605
ungetc(c, f);
16081606
};
1609-
// File contains CSV of integer ranges representing the offline CPUs
1607+
// File contains CSV of integer ranges representing the CPUs
16101608
// e.g., 1,2,4-7,9,11-15
1611-
int status = offline_file.try_open("/sys/devices/system/cpu/offline", "r");
1609+
int status = file.try_open(path, "r");
16121610
if (status != 0)
1613-
return offline;
1614-
while (!feof(offline_file)) {
1615-
skip_ws(offline_file);
1616-
n = fscanf(offline_file, "%d", &begin_cpu);
1611+
return mask;
1612+
while (!feof(file)) {
1613+
skip_ws(file);
1614+
n = fscanf(file, "%d", &begin_cpu);
16171615
if (n != 1)
16181616
break;
1619-
skip_ws(offline_file);
1620-
int c = fgetc(offline_file);
1617+
skip_ws(file);
1618+
int c = fgetc(file);
16211619
if (c == EOF || c == ',') {
16221620
// Just single CPU
16231621
end_cpu = begin_cpu;
16241622
} else if (c == '-') {
16251623
// Range of CPUs
1626-
skip_ws(offline_file);
1627-
n = fscanf(offline_file, "%d", &end_cpu);
1624+
skip_ws(file);
1625+
n = fscanf(file, "%d", &end_cpu);
16281626
if (n != 1)
16291627
break;
1630-
skip_ws(offline_file);
1631-
c = fgetc(offline_file); // skip ','
1628+
skip_ws(file);
1629+
c = fgetc(file); // skip ','
16321630
} else {
16331631
// Syntax problem
16341632
break;
@@ -1638,13 +1636,19 @@ kmp_affin_mask_t *__kmp_affinity_get_offline_cpus() {
16381636
end_cpu >= __kmp_xproc || begin_cpu > end_cpu) {
16391637
continue;
16401638
}
1641-
// Insert [begin_cpu, end_cpu] into offline mask
1639+
// Insert [begin_cpu, end_cpu] into mask
16421640
for (int cpu = begin_cpu; cpu <= end_cpu; ++cpu) {
1643-
KMP_CPU_SET(cpu, offline);
1641+
KMP_CPU_SET(cpu, mask);
16441642
}
16451643
}
16461644
#endif
1647-
return offline;
1645+
return mask;
1646+
}
1647+
1648+
// Return (possibly empty) affinity mask representing the offline CPUs
1649+
// Caller must free the mask
1650+
kmp_affin_mask_t *__kmp_affinity_get_offline_cpus() {
1651+
return __kmp_parse_cpu_list("/sys/devices/system/cpu/offline");
16481652
}
16491653

16501654
// Return the number of available procs
@@ -3175,6 +3179,37 @@ static inline const char *__kmp_cpuinfo_get_envvar() {
31753179
return envvar;
31763180
}
31773181

3182+
static bool __kmp_package_id_from_core_siblings_list(unsigned **threadInfo,
3183+
unsigned num_avail,
3184+
unsigned idx) {
3185+
if (!KMP_AFFINITY_CAPABLE())
3186+
return false;
3187+
3188+
char path[256];
3189+
KMP_SNPRINTF(path, sizeof(path),
3190+
"/sys/devices/system/cpu/cpu%u/topology/core_siblings_list",
3191+
threadInfo[idx][osIdIndex]);
3192+
kmp_affin_mask_t *siblings = __kmp_parse_cpu_list(path);
3193+
for (unsigned i = 0; i < num_avail; ++i) {
3194+
unsigned cpu_id = threadInfo[i][osIdIndex];
3195+
KMP_ASSERT(cpu_id < __kmp_affin_mask_size * CHAR_BIT);
3196+
if (!KMP_CPU_ISSET(cpu_id, siblings))
3197+
continue;
3198+
if (threadInfo[i][pkgIdIndex] == UINT_MAX) {
3199+
// Arbitrarily pick the first index we encounter, it only matters that
3200+
// the value is the same for all siblings.
3201+
threadInfo[i][pkgIdIndex] = idx;
3202+
} else if (threadInfo[i][pkgIdIndex] != idx) {
3203+
// Contradictory sibling lists.
3204+
KMP_CPU_FREE(siblings);
3205+
return false;
3206+
}
3207+
}
3208+
KMP_ASSERT(threadInfo[idx][pkgIdIndex] != UINT_MAX);
3209+
KMP_CPU_FREE(siblings);
3210+
return true;
3211+
}
3212+
31783213
// Parse /proc/cpuinfo (or an alternate file in the same format) to obtain the
31793214
// affinity map. On AIX, the map is obtained through system SRAD (Scheduler
31803215
// Resource Allocation Domain).
@@ -3550,18 +3585,13 @@ static bool __kmp_affinity_create_cpuinfo_map(int *line,
35503585
return false;
35513586
}
35523587

3553-
// Check for missing fields. The osId field must be there, and we
3554-
// currently require that the physical id field is specified, also.
3588+
// Check for missing fields. The osId field must be there. The physical
3589+
// id field will be checked later.
35553590
if (threadInfo[num_avail][osIdIndex] == UINT_MAX) {
35563591
CLEANUP_THREAD_INFO;
35573592
*msg_id = kmp_i18n_str_MissingProcField;
35583593
return false;
35593594
}
3560-
if (threadInfo[0][pkgIdIndex] == UINT_MAX) {
3561-
CLEANUP_THREAD_INFO;
3562-
*msg_id = kmp_i18n_str_MissingPhysicalIDField;
3563-
return false;
3564-
}
35653595

35663596
// Skip this proc if it is not included in the machine model.
35673597
if (KMP_AFFINITY_CAPABLE() &&
@@ -3591,6 +3621,18 @@ static bool __kmp_affinity_create_cpuinfo_map(int *line,
35913621
}
35923622
*line = 0;
35933623

3624+
// At least on powerpc, Linux may return -1 for physical_package_id. Try
3625+
// to reconstruct topology from core_siblings_list in that case.
3626+
for (i = 0; i < num_avail; ++i) {
3627+
if (threadInfo[i][pkgIdIndex] == UINT_MAX) {
3628+
if (!__kmp_package_id_from_core_siblings_list(threadInfo, num_avail, i)) {
3629+
CLEANUP_THREAD_INFO;
3630+
*msg_id = kmp_i18n_str_MissingPhysicalIDField;
3631+
return false;
3632+
}
3633+
}
3634+
}
3635+
35943636
#if KMP_MIC && REDUCE_TEAM_SIZE
35953637
unsigned teamSize = 0;
35963638
#endif // KMP_MIC && REDUCE_TEAM_SIZE

openmp/runtime/test/affinity/kmp-hw-subset.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ static int compare_hw_subset_places(const place_list_t *openmp_places,
2525
expected_per_place = nthreads_per_core;
2626
} else {
2727
expected_total = nsockets;
28-
expected_per_place = ncores_per_socket;
28+
expected_per_place = ncores_per_socket * nthreads_per_core;
2929
}
3030
if (openmp_places->num_places != expected_total) {
3131
fprintf(stderr, "error: KMP_HW_SUBSET did not half each resource layer!\n");

0 commit comments

Comments
 (0)