Skip to content

Commit 561b6ab

Browse files
authored
[OpenMP][AIX] Implement __kmp_get_load_balance() for AIX (#91520)
AIX has the `/proc` filesystem where `/proc/<pid>/lwp/<tid>/lwpsinfo` has the thread state in binary, similar to Linux's `/proc/<pid>/task/<tid>/stat` where the state is in ASCII. However, the definition of state info `R` in `lwpsinfo` is `runnable`. In Linux, state `R` means the thread is `running`. Therefore, `lwpsinfo` is not ideal for our purpose of getting the current load of the system. This patch uses `perfstat_cpu()` in AIX system library `libperfstat.a` to obtain the number of threads current running on logical CPUs.
1 parent d48bf8a commit 561b6ab

File tree

2 files changed

+80
-12
lines changed

2 files changed

+80
-12
lines changed

openmp/runtime/CMakeLists.txt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,13 @@ set(LIBOMP_ASMFLAGS "" CACHE STRING
132132
"Appended user specified assembler flags.")
133133
set(LIBOMP_LDFLAGS "" CACHE STRING
134134
"Appended user specified linker flags.")
135-
if("${LIBOMP_ARCH}" STREQUAL "ppc" AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
136-
# PPC (32-bit) on AIX needs libatomic for __atomic_load_8, etc.
137-
set(LIBOMP_LIBFLAGS "-latomic" CACHE STRING
135+
if(${CMAKE_SYSTEM_NAME} MATCHES "AIX")
136+
set(LIBOMP_LIBFLAGS "-lperfstat" CACHE STRING
138137
"Appended user specified linked libs flags. (e.g., -lm)")
138+
if("${LIBOMP_ARCH}" STREQUAL "ppc")
139+
# PPC (32-bit) on AIX needs libatomic for __atomic_load_8, etc.
140+
set(LIBOMP_LIBFLAGS "${LIBOMP_LIBFLAGS} -latomic")
141+
endif()
139142
else()
140143
set(LIBOMP_LIBFLAGS "" CACHE STRING
141144
"Appended user specified linked libs flags. (e.g., -lm)")

openmp/runtime/src/z_Linux_util.cpp

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <sys/resource.h>
3232
#if KMP_OS_AIX
3333
#include <sys/ldr.h>
34+
#include <libperfstat.h>
3435
#else
3536
#include <sys/syscall.h>
3637
#endif
@@ -2427,6 +2428,79 @@ int __kmp_get_load_balance(int max) {
24272428
return ret_avg;
24282429
}
24292430

2431+
#elif KMP_OS_AIX
2432+
2433+
// The function returns number of running (not sleeping) threads, or -1 in case
2434+
// of error.
2435+
int __kmp_get_load_balance(int max) {
2436+
2437+
static int glb_running_threads = 0; // Saved count of the running threads for
2438+
// the thread balance algorithm.
2439+
static double glb_call_time = 0; // Thread balance algorithm call time.
2440+
int running_threads = 0; // Number of running threads in the system.
2441+
2442+
double call_time = 0.0;
2443+
2444+
__kmp_elapsed(&call_time);
2445+
2446+
if (glb_call_time &&
2447+
(call_time - glb_call_time < __kmp_load_balance_interval))
2448+
return glb_running_threads;
2449+
2450+
glb_call_time = call_time;
2451+
2452+
if (max <= 0) {
2453+
max = INT_MAX;
2454+
}
2455+
2456+
// Check how many perfstat_cpu_t structures are available.
2457+
int logical_cpus = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
2458+
if (logical_cpus <= 0) {
2459+
glb_call_time = -1;
2460+
return -1;
2461+
}
2462+
2463+
perfstat_cpu_t *cpu_stat = (perfstat_cpu_t *)KMP_INTERNAL_MALLOC(
2464+
logical_cpus * sizeof(perfstat_cpu_t));
2465+
if (cpu_stat == NULL) {
2466+
glb_call_time = -1;
2467+
return -1;
2468+
}
2469+
2470+
// Set first CPU as the name of the first logical CPU for which the info is
2471+
// desired.
2472+
perfstat_id_t first_cpu_name;
2473+
strcpy(first_cpu_name.name, FIRST_CPU);
2474+
2475+
// Get the stat info of logical CPUs.
2476+
int rc = perfstat_cpu(&first_cpu_name, cpu_stat, sizeof(perfstat_cpu_t),
2477+
logical_cpus);
2478+
KMP_DEBUG_ASSERT(rc == logical_cpus);
2479+
if (rc <= 0) {
2480+
KMP_INTERNAL_FREE(cpu_stat);
2481+
glb_call_time = -1;
2482+
return -1;
2483+
}
2484+
for (int i = 0; i < logical_cpus; ++i) {
2485+
running_threads += cpu_stat[i].runque;
2486+
if (running_threads >= max)
2487+
break;
2488+
}
2489+
2490+
// There _might_ be a timing hole where the thread executing this
2491+
// code gets skipped in the load balance, and running_threads is 0.
2492+
// Assert in the debug builds only!!!
2493+
KMP_DEBUG_ASSERT(running_threads > 0);
2494+
if (running_threads <= 0)
2495+
running_threads = 1;
2496+
2497+
KMP_INTERNAL_FREE(cpu_stat);
2498+
2499+
glb_running_threads = running_threads;
2500+
2501+
return running_threads;
2502+
}
2503+
24302504
#else // Linux* OS
24312505

24322506
// The function returns number of running (not sleeping) threads, or -1 in case
@@ -2498,14 +2572,9 @@ int __kmp_get_load_balance(int max) {
24982572

24992573
proc_entry = readdir(proc_dir);
25002574
while (proc_entry != NULL) {
2501-
#if KMP_OS_AIX
2502-
// Proc entry name starts with a digit. Assume it is a process' directory.
2503-
if (isdigit(proc_entry->d_name[0])) {
2504-
#else
25052575
// Proc entry is a directory and name starts with a digit. Assume it is a
25062576
// process' directory.
25072577
if (proc_entry->d_type == DT_DIR && isdigit(proc_entry->d_name[0])) {
2508-
#endif
25092578

25102579
#ifdef KMP_DEBUG
25112580
++total_processes;
@@ -2549,11 +2618,7 @@ int __kmp_get_load_balance(int max) {
25492618
task_entry = readdir(task_dir);
25502619
while (task_entry != NULL) {
25512620
// It is a directory and name starts with a digit.
2552-
#if KMP_OS_AIX
2553-
if (isdigit(task_entry->d_name[0])) {
2554-
#else
25552621
if (proc_entry->d_type == DT_DIR && isdigit(task_entry->d_name[0])) {
2556-
#endif
25572622

25582623
// Construct complete stat file path. Easiest way would be:
25592624
// __kmp_str_buf_print( & stat_path, "%s/%s/stat", task_path.str,

0 commit comments

Comments
 (0)