Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release/18x: [OpenMP][AIX] Affinity implementation for AIX (#84984) #86695

Merged
merged 1 commit into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion openmp/runtime/src/kmp.h
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,7 @@ class KMPAffinity {
typedef KMPAffinity::Mask kmp_affin_mask_t;
extern KMPAffinity *__kmp_affinity_dispatch;

#ifndef KMP_OS_AIX
class kmp_affinity_raii_t {
kmp_affin_mask_t *mask;
bool restored;
Expand All @@ -842,6 +843,7 @@ class kmp_affinity_raii_t {
}
~kmp_affinity_raii_t() { restore(); }
};
#endif // !KMP_OS_AIX

// Declare local char buffers with this size for printing debug and info
// messages, using __kmp_affinity_print_mask().
Expand Down Expand Up @@ -3911,7 +3913,7 @@ extern void __kmp_balanced_affinity(kmp_info_t *th, int team_size);
#if KMP_WEIGHTED_ITERATIONS_SUPPORTED
extern int __kmp_get_first_osid_with_ecore(void);
#endif
#if KMP_OS_LINUX || KMP_OS_FREEBSD
#if KMP_OS_LINUX || KMP_OS_FREEBSD || KMP_OS_AIX
extern int kmp_set_thread_affinity_mask_initial(void);
#endif
static inline void __kmp_assign_root_init_mask() {
Expand Down
129 changes: 121 additions & 8 deletions openmp/runtime/src/kmp_affinity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2906,12 +2906,17 @@ static inline const char *__kmp_cpuinfo_get_envvar() {
}

// Parse /proc/cpuinfo (or an alternate file in the same format) to obtain the
// affinity map.
// affinity map. On AIX, the map is obtained through system SRAD (Scheduler
// Resource Allocation Domain).
static bool __kmp_affinity_create_cpuinfo_map(int *line,
kmp_i18n_id_t *const msg_id) {
*msg_id = kmp_i18n_null;

#if KMP_OS_AIX
unsigned num_records = __kmp_xproc;
#else
const char *filename = __kmp_cpuinfo_get_filename();
const char *envvar = __kmp_cpuinfo_get_envvar();
*msg_id = kmp_i18n_null;

if (__kmp_affinity.flags.verbose) {
KMP_INFORM(AffParseFilename, "KMP_AFFINITY", filename);
Expand Down Expand Up @@ -2970,6 +2975,7 @@ static bool __kmp_affinity_create_cpuinfo_map(int *line,
*msg_id = kmp_i18n_str_CantRewindCpuinfo;
return false;
}
#endif // KMP_OS_AIX

// Allocate the array of records to store the proc info in. The dummy
// element at the end makes the logic in filling them out easier to code.
Expand Down Expand Up @@ -2999,6 +3005,99 @@ static bool __kmp_affinity_create_cpuinfo_map(int *line,
INIT_PROC_INFO(threadInfo[i]);
}

#if KMP_OS_AIX
int smt_threads;
lpar_info_format1_t cpuinfo;
unsigned num_avail = __kmp_xproc;

if (__kmp_affinity.flags.verbose)
KMP_INFORM(AffParseFilename, "KMP_AFFINITY", "system info for topology");

// Get the number of SMT threads per core.
int retval =
lpar_get_info(LPAR_INFO_FORMAT1, &cpuinfo, sizeof(lpar_info_format1_t));
if (!retval)
smt_threads = cpuinfo.smt_threads;
else {
CLEANUP_THREAD_INFO;
*msg_id = kmp_i18n_str_UnknownTopology;
return false;
}

// Allocate a resource set containing available system resourses.
rsethandle_t sys_rset = rs_alloc(RS_SYSTEM);
if (sys_rset == NULL) {
CLEANUP_THREAD_INFO;
*msg_id = kmp_i18n_str_UnknownTopology;
return false;
}
// Allocate a resource set for the SRAD info.
rsethandle_t srad = rs_alloc(RS_EMPTY);
if (srad == NULL) {
rs_free(sys_rset);
CLEANUP_THREAD_INFO;
*msg_id = kmp_i18n_str_UnknownTopology;
return false;
}

// Get the SRAD system detail level.
int sradsdl = rs_getinfo(NULL, R_SRADSDL, 0);
if (sradsdl < 0) {
rs_free(sys_rset);
rs_free(srad);
CLEANUP_THREAD_INFO;
*msg_id = kmp_i18n_str_UnknownTopology;
return false;
}
// Get the number of RADs at that SRAD SDL.
int num_rads = rs_numrads(sys_rset, sradsdl, 0);
if (num_rads < 0) {
rs_free(sys_rset);
rs_free(srad);
CLEANUP_THREAD_INFO;
*msg_id = kmp_i18n_str_UnknownTopology;
return false;
}

// Get the maximum number of procs that may be contained in a resource set.
int max_procs = rs_getinfo(NULL, R_MAXPROCS, 0);
if (max_procs < 0) {
rs_free(sys_rset);
rs_free(srad);
CLEANUP_THREAD_INFO;
*msg_id = kmp_i18n_str_UnknownTopology;
return false;
}

int cur_rad = 0;
int num_set = 0;
for (int srad_idx = 0; cur_rad < num_rads && srad_idx < VMI_MAXRADS;
++srad_idx) {
// Check if the SRAD is available in the RSET.
if (rs_getrad(sys_rset, srad, sradsdl, srad_idx, 0) < 0)
continue;

for (int cpu = 0; cpu < max_procs; cpu++) {
// Set the info for the cpu if it is in the SRAD.
if (rs_op(RS_TESTRESOURCE, srad, NULL, R_PROCS, cpu)) {
threadInfo[cpu][osIdIndex] = cpu;
threadInfo[cpu][pkgIdIndex] = cur_rad;
threadInfo[cpu][coreIdIndex] = cpu / smt_threads;
++num_set;
if (num_set >= num_avail) {
// Done if all available CPUs have been set.
break;
}
}
}
++cur_rad;
}
rs_free(sys_rset);
rs_free(srad);

// The topology is already sorted.

#else // !KMP_OS_AIX
unsigned num_avail = 0;
*line = 0;
#if KMP_ARCH_S390X
Expand Down Expand Up @@ -3246,6 +3345,8 @@ static bool __kmp_affinity_create_cpuinfo_map(int *line,
qsort(threadInfo, num_avail, sizeof(*threadInfo),
__kmp_affinity_cmp_ProcCpuInfo_phys_id);

#endif // KMP_OS_AIX

// The table is now sorted by pkgId / coreId / threadId, but we really don't
// know the radix of any of the fields. pkgId's may be sparsely assigned among
// the chips on a system. Although coreId's are usually assigned
Expand Down Expand Up @@ -4441,7 +4542,7 @@ static bool __kmp_aux_affinity_initialize_topology(kmp_affinity_t &affinity) {
}
#endif /* KMP_ARCH_X86 || KMP_ARCH_X86_64 */

#if KMP_OS_LINUX
#if KMP_OS_LINUX || KMP_OS_AIX
if (!success) {
int line = 0;
success = __kmp_affinity_create_cpuinfo_map(&line, &msg_id);
Expand Down Expand Up @@ -4837,7 +4938,12 @@ void __kmp_affinity_uninitialize(void) {
}
if (__kmp_affin_origMask != NULL) {
if (KMP_AFFINITY_CAPABLE()) {
#if KMP_OS_AIX
// Uninitialize by unbinding the thread.
bindprocessor(BINDTHREAD, thread_self(), PROCESSOR_CLASS_ANY);
#else
__kmp_set_system_affinity(__kmp_affin_origMask, FALSE);
#endif
}
KMP_CPU_FREE(__kmp_affin_origMask);
__kmp_affin_origMask = NULL;
Expand Down Expand Up @@ -5011,7 +5117,10 @@ void __kmp_affinity_bind_init_mask(int gtid) {
__kmp_set_system_affinity(th->th.th_affin_mask, FALSE);
} else
#endif
#ifndef KMP_OS_AIX
// Do not set the full mask as the init mask on AIX.
__kmp_set_system_affinity(th->th.th_affin_mask, TRUE);
#endif
}

void __kmp_affinity_bind_place(int gtid) {
Expand Down Expand Up @@ -5124,15 +5233,15 @@ int __kmp_aux_set_affinity(void **mask) {
int __kmp_aux_get_affinity(void **mask) {
int gtid;
int retval;
#if KMP_OS_WINDOWS || KMP_DEBUG
#if KMP_OS_WINDOWS || KMP_OS_AIX || KMP_DEBUG
kmp_info_t *th;
#endif
if (!KMP_AFFINITY_CAPABLE()) {
return -1;
}

gtid = __kmp_entry_gtid();
#if KMP_OS_WINDOWS || KMP_DEBUG
#if KMP_OS_WINDOWS || KMP_OS_AIX || KMP_DEBUG
th = __kmp_threads[gtid];
#else
(void)gtid; // unused variable
Expand All @@ -5155,7 +5264,7 @@ int __kmp_aux_get_affinity(void **mask) {
}
}

#if !KMP_OS_WINDOWS
#if !KMP_OS_WINDOWS && !KMP_OS_AIX

retval = __kmp_get_system_affinity((kmp_affin_mask_t *)(*mask), FALSE);
KA_TRACE(
Expand All @@ -5175,7 +5284,7 @@ int __kmp_aux_get_affinity(void **mask) {
KMP_CPU_COPY((kmp_affin_mask_t *)(*mask), th->th.th_affin_mask);
return 0;

#endif /* KMP_OS_WINDOWS */
#endif /* !KMP_OS_WINDOWS && !KMP_OS_AIX */
}

int __kmp_aux_get_affinity_max_proc() {
Expand Down Expand Up @@ -5557,7 +5666,7 @@ void __kmp_balanced_affinity(kmp_info_t *th, int nthreads) {
}
}

#if KMP_OS_LINUX || KMP_OS_FREEBSD
#if KMP_OS_LINUX || KMP_OS_FREEBSD || KMP_OS_AIX
// We don't need this entry for Windows because
// there is GetProcessAffinityMask() api
//
Expand Down Expand Up @@ -5592,7 +5701,11 @@ extern "C"
"set full mask for thread %d\n",
gtid));
KMP_DEBUG_ASSERT(__kmp_affin_fullMask != NULL);
#if KMP_OS_AIX
return bindprocessor(BINDTHREAD, thread_self(), PROCESSOR_CLASS_ANY);
#else
return __kmp_set_system_affinity(__kmp_affin_fullMask, FALSE);
#endif
}
#endif

Expand Down
73 changes: 71 additions & 2 deletions openmp/runtime/src/kmp_affinity.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ class KMPHwlocAffinity : public KMPAffinity {
};
#endif /* KMP_USE_HWLOC */

#if KMP_OS_LINUX || KMP_OS_FREEBSD
#if KMP_OS_LINUX || KMP_OS_FREEBSD || KMP_OS_AIX
#if KMP_OS_LINUX
/* On some of the older OS's that we build on, these constants aren't present
in <asm/unistd.h> #included from <sys.syscall.h>. They must be the same on
Expand Down Expand Up @@ -314,6 +314,10 @@ class KMPHwlocAffinity : public KMPAffinity {
#elif KMP_OS_FREEBSD
#include <pthread.h>
#include <pthread_np.h>
#elif KMP_OS_AIX
#include <sys/dr.h>
#include <sys/rset.h>
#define VMI_MAXRADS 64 // Maximum number of RADs allowed by AIX.
#endif
class KMPNativeAffinity : public KMPAffinity {
class Mask : public KMPAffinity::Mask {
Expand Down Expand Up @@ -401,6 +405,70 @@ class KMPNativeAffinity : public KMPAffinity {
++retval;
return retval;
}
#if KMP_OS_AIX
// On AIX, we don't have a way to get CPU(s) a thread is bound to.
// This routine is only used to get the full mask.
int get_system_affinity(bool abort_on_error) override {
KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
"Illegal get affinity operation when not capable");

(void)abort_on_error;

// Set the mask with all CPUs that are available.
for (int i = 0; i < __kmp_xproc; ++i)
KMP_CPU_SET(i, this);
return 0;
}
int set_system_affinity(bool abort_on_error) const override {
KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),

"Illegal set affinity operation when not capable");

int location;
int gtid = __kmp_entry_gtid();
int tid = thread_self();

// Unbind the thread if it was bound to any processors before so that
// we can bind the thread to CPUs specified by the mask not others.
int retval = bindprocessor(BINDTHREAD, tid, PROCESSOR_CLASS_ANY);

// On AIX, we can only bind to one instead of a set of CPUs with the
// bindprocessor() system call.
KMP_CPU_SET_ITERATE(location, this) {
if (KMP_CPU_ISSET(location, this)) {
retval = bindprocessor(BINDTHREAD, tid, location);
if (retval == -1 && errno == 1) {
rsid_t rsid;
rsethandle_t rsh;
// Put something in rsh to prevent compiler warning
// about uninitalized use
rsh = rs_alloc(RS_EMPTY);
rsid.at_pid = getpid();
if (RS_DEFAULT_RSET != ra_getrset(R_PROCESS, rsid, 0, rsh)) {
retval = ra_detachrset(R_PROCESS, rsid, 0);
retval = bindprocessor(BINDTHREAD, tid, location);
}
}
if (retval == 0) {
KA_TRACE(10, ("__kmp_set_system_affinity: Done binding "
"T#%d to cpu=%d.\n",
gtid, location));
continue;
}
int error = errno;
if (abort_on_error) {
__kmp_fatal(KMP_MSG(FunctionError, "bindprocessor()"),
KMP_ERR(error), __kmp_msg_null);
KA_TRACE(10, ("__kmp_set_system_affinity: Error binding "
"T#%d to cpu=%d, errno=%d.\n",
gtid, location, error));
return error;
}
}
}
return 0;
}
#else // !KMP_OS_AIX
int get_system_affinity(bool abort_on_error) override {
KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
"Illegal get affinity operation when not capable");
Expand Down Expand Up @@ -443,6 +511,7 @@ class KMPNativeAffinity : public KMPAffinity {
}
return error;
}
#endif // KMP_OS_AIX
};
void determine_capable(const char *env_var) override {
__kmp_affinity_determine_capable(env_var);
Expand Down Expand Up @@ -471,7 +540,7 @@ class KMPNativeAffinity : public KMPAffinity {
}
api_type get_api_type() const override { return NATIVE_OS; }
};
#endif /* KMP_OS_LINUX || KMP_OS_FREEBSD */
#endif /* KMP_OS_LINUX || KMP_OS_FREEBSD || KMP_OS_AIX */

#if KMP_OS_WINDOWS
class KMPNativeAffinity : public KMPAffinity {
Expand Down
3 changes: 2 additions & 1 deletion openmp/runtime/src/kmp_os.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@
#error Unknown compiler
#endif

#if (KMP_OS_LINUX || KMP_OS_WINDOWS || KMP_OS_FREEBSD) && !KMP_OS_WASI
#if (KMP_OS_LINUX || KMP_OS_WINDOWS || KMP_OS_FREEBSD || KMP_OS_AIX) && \
!KMP_OS_WASI
#define KMP_AFFINITY_SUPPORTED 1
#if KMP_OS_WINDOWS && KMP_ARCH_X86_64
#define KMP_GROUP_AFFINITY 1
Expand Down
Loading
Loading