xref: /freebsd/contrib/llvm-project/openmp/runtime/src/kmp_affinity.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric /*
20b57cec5SDimitry Andric  * kmp_affinity.h -- header for affinity management
30b57cec5SDimitry Andric  */
40b57cec5SDimitry Andric 
50b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
80b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
90b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #ifndef KMP_AFFINITY_H
140b57cec5SDimitry Andric #define KMP_AFFINITY_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "kmp.h"
170b57cec5SDimitry Andric #include "kmp_os.h"
180eae32dcSDimitry Andric #include <limits>
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric #if KMP_AFFINITY_SUPPORTED
210b57cec5SDimitry Andric #if KMP_USE_HWLOC
220b57cec5SDimitry Andric class KMPHwlocAffinity : public KMPAffinity {
230b57cec5SDimitry Andric public:
240b57cec5SDimitry Andric   class Mask : public KMPAffinity::Mask {
250b57cec5SDimitry Andric     hwloc_cpuset_t mask;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric   public:
280b57cec5SDimitry Andric     Mask() {
290b57cec5SDimitry Andric       mask = hwloc_bitmap_alloc();
300b57cec5SDimitry Andric       this->zero();
310b57cec5SDimitry Andric     }
320b57cec5SDimitry Andric     ~Mask() { hwloc_bitmap_free(mask); }
330b57cec5SDimitry Andric     void set(int i) override { hwloc_bitmap_set(mask, i); }
340b57cec5SDimitry Andric     bool is_set(int i) const override { return hwloc_bitmap_isset(mask, i); }
350b57cec5SDimitry Andric     void clear(int i) override { hwloc_bitmap_clr(mask, i); }
360b57cec5SDimitry Andric     void zero() override { hwloc_bitmap_zero(mask); }
37*5f757f3fSDimitry Andric     bool empty() const override { return hwloc_bitmap_iszero(mask); }
380b57cec5SDimitry Andric     void copy(const KMPAffinity::Mask *src) override {
390b57cec5SDimitry Andric       const Mask *convert = static_cast<const Mask *>(src);
400b57cec5SDimitry Andric       hwloc_bitmap_copy(mask, convert->mask);
410b57cec5SDimitry Andric     }
420b57cec5SDimitry Andric     void bitwise_and(const KMPAffinity::Mask *rhs) override {
430b57cec5SDimitry Andric       const Mask *convert = static_cast<const Mask *>(rhs);
440b57cec5SDimitry Andric       hwloc_bitmap_and(mask, mask, convert->mask);
450b57cec5SDimitry Andric     }
460b57cec5SDimitry Andric     void bitwise_or(const KMPAffinity::Mask *rhs) override {
470b57cec5SDimitry Andric       const Mask *convert = static_cast<const Mask *>(rhs);
480b57cec5SDimitry Andric       hwloc_bitmap_or(mask, mask, convert->mask);
490b57cec5SDimitry Andric     }
500b57cec5SDimitry Andric     void bitwise_not() override { hwloc_bitmap_not(mask, mask); }
51*5f757f3fSDimitry Andric     bool is_equal(const KMPAffinity::Mask *rhs) const override {
52*5f757f3fSDimitry Andric       const Mask *convert = static_cast<const Mask *>(rhs);
53*5f757f3fSDimitry Andric       return hwloc_bitmap_isequal(mask, convert->mask);
54*5f757f3fSDimitry Andric     }
550b57cec5SDimitry Andric     int begin() const override { return hwloc_bitmap_first(mask); }
560b57cec5SDimitry Andric     int end() const override { return -1; }
570b57cec5SDimitry Andric     int next(int previous) const override {
580b57cec5SDimitry Andric       return hwloc_bitmap_next(mask, previous);
590b57cec5SDimitry Andric     }
600b57cec5SDimitry Andric     int get_system_affinity(bool abort_on_error) override {
610b57cec5SDimitry Andric       KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
620b57cec5SDimitry Andric                   "Illegal get affinity operation when not capable");
63e8d8bef9SDimitry Andric       long retval =
640b57cec5SDimitry Andric           hwloc_get_cpubind(__kmp_hwloc_topology, mask, HWLOC_CPUBIND_THREAD);
650b57cec5SDimitry Andric       if (retval >= 0) {
660b57cec5SDimitry Andric         return 0;
670b57cec5SDimitry Andric       }
680b57cec5SDimitry Andric       int error = errno;
690b57cec5SDimitry Andric       if (abort_on_error) {
7006c3fb27SDimitry Andric         __kmp_fatal(KMP_MSG(FunctionError, "hwloc_get_cpubind()"),
7106c3fb27SDimitry Andric                     KMP_ERR(error), __kmp_msg_null);
720b57cec5SDimitry Andric       }
730b57cec5SDimitry Andric       return error;
740b57cec5SDimitry Andric     }
750b57cec5SDimitry Andric     int set_system_affinity(bool abort_on_error) const override {
760b57cec5SDimitry Andric       KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
77e8d8bef9SDimitry Andric                   "Illegal set affinity operation when not capable");
78e8d8bef9SDimitry Andric       long retval =
790b57cec5SDimitry Andric           hwloc_set_cpubind(__kmp_hwloc_topology, mask, HWLOC_CPUBIND_THREAD);
800b57cec5SDimitry Andric       if (retval >= 0) {
810b57cec5SDimitry Andric         return 0;
820b57cec5SDimitry Andric       }
830b57cec5SDimitry Andric       int error = errno;
840b57cec5SDimitry Andric       if (abort_on_error) {
8506c3fb27SDimitry Andric         __kmp_fatal(KMP_MSG(FunctionError, "hwloc_set_cpubind()"),
8606c3fb27SDimitry Andric                     KMP_ERR(error), __kmp_msg_null);
870b57cec5SDimitry Andric       }
880b57cec5SDimitry Andric       return error;
890b57cec5SDimitry Andric     }
90e8d8bef9SDimitry Andric #if KMP_OS_WINDOWS
91e8d8bef9SDimitry Andric     int set_process_affinity(bool abort_on_error) const override {
92e8d8bef9SDimitry Andric       KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
93e8d8bef9SDimitry Andric                   "Illegal set process affinity operation when not capable");
94e8d8bef9SDimitry Andric       int error = 0;
95e8d8bef9SDimitry Andric       const hwloc_topology_support *support =
96e8d8bef9SDimitry Andric           hwloc_topology_get_support(__kmp_hwloc_topology);
97e8d8bef9SDimitry Andric       if (support->cpubind->set_proc_cpubind) {
98e8d8bef9SDimitry Andric         int retval;
99e8d8bef9SDimitry Andric         retval = hwloc_set_cpubind(__kmp_hwloc_topology, mask,
100e8d8bef9SDimitry Andric                                    HWLOC_CPUBIND_PROCESS);
101e8d8bef9SDimitry Andric         if (retval >= 0)
102e8d8bef9SDimitry Andric           return 0;
103e8d8bef9SDimitry Andric         error = errno;
104e8d8bef9SDimitry Andric         if (abort_on_error)
10506c3fb27SDimitry Andric           __kmp_fatal(KMP_MSG(FunctionError, "hwloc_set_cpubind()"),
10606c3fb27SDimitry Andric                       KMP_ERR(error), __kmp_msg_null);
107e8d8bef9SDimitry Andric       }
108e8d8bef9SDimitry Andric       return error;
109e8d8bef9SDimitry Andric     }
110e8d8bef9SDimitry Andric #endif
1110b57cec5SDimitry Andric     int get_proc_group() const override {
1120b57cec5SDimitry Andric       int group = -1;
1130b57cec5SDimitry Andric #if KMP_OS_WINDOWS
1140b57cec5SDimitry Andric       if (__kmp_num_proc_groups == 1) {
1150b57cec5SDimitry Andric         return 1;
1160b57cec5SDimitry Andric       }
1170b57cec5SDimitry Andric       for (int i = 0; i < __kmp_num_proc_groups; i++) {
1180b57cec5SDimitry Andric         // On windows, the long type is always 32 bits
1190b57cec5SDimitry Andric         unsigned long first_32_bits = hwloc_bitmap_to_ith_ulong(mask, i * 2);
1200b57cec5SDimitry Andric         unsigned long second_32_bits =
1210b57cec5SDimitry Andric             hwloc_bitmap_to_ith_ulong(mask, i * 2 + 1);
1220b57cec5SDimitry Andric         if (first_32_bits == 0 && second_32_bits == 0) {
1230b57cec5SDimitry Andric           continue;
1240b57cec5SDimitry Andric         }
1250b57cec5SDimitry Andric         if (group >= 0) {
1260b57cec5SDimitry Andric           return -1;
1270b57cec5SDimitry Andric         }
1280b57cec5SDimitry Andric         group = i;
1290b57cec5SDimitry Andric       }
1300b57cec5SDimitry Andric #endif /* KMP_OS_WINDOWS */
1310b57cec5SDimitry Andric       return group;
1320b57cec5SDimitry Andric     }
1330b57cec5SDimitry Andric   };
1340b57cec5SDimitry Andric   void determine_capable(const char *var) override {
1350b57cec5SDimitry Andric     const hwloc_topology_support *topology_support;
1360b57cec5SDimitry Andric     if (__kmp_hwloc_topology == NULL) {
1370b57cec5SDimitry Andric       if (hwloc_topology_init(&__kmp_hwloc_topology) < 0) {
1380b57cec5SDimitry Andric         __kmp_hwloc_error = TRUE;
139bdd1243dSDimitry Andric         if (__kmp_affinity.flags.verbose) {
1400b57cec5SDimitry Andric           KMP_WARNING(AffHwlocErrorOccurred, var, "hwloc_topology_init()");
1410b57cec5SDimitry Andric         }
142bdd1243dSDimitry Andric       }
1430b57cec5SDimitry Andric       if (hwloc_topology_load(__kmp_hwloc_topology) < 0) {
1440b57cec5SDimitry Andric         __kmp_hwloc_error = TRUE;
145bdd1243dSDimitry Andric         if (__kmp_affinity.flags.verbose) {
1460b57cec5SDimitry Andric           KMP_WARNING(AffHwlocErrorOccurred, var, "hwloc_topology_load()");
1470b57cec5SDimitry Andric         }
1480b57cec5SDimitry Andric       }
149bdd1243dSDimitry Andric     }
1500b57cec5SDimitry Andric     topology_support = hwloc_topology_get_support(__kmp_hwloc_topology);
1510b57cec5SDimitry Andric     // Is the system capable of setting/getting this thread's affinity?
1520b57cec5SDimitry Andric     // Also, is topology discovery possible? (pu indicates ability to discover
1530b57cec5SDimitry Andric     // processing units). And finally, were there no errors when calling any
1540b57cec5SDimitry Andric     // hwloc_* API functions?
1550b57cec5SDimitry Andric     if (topology_support && topology_support->cpubind->set_thisthread_cpubind &&
1560b57cec5SDimitry Andric         topology_support->cpubind->get_thisthread_cpubind &&
1570b57cec5SDimitry Andric         topology_support->discovery->pu && !__kmp_hwloc_error) {
1580b57cec5SDimitry Andric       // enables affinity according to KMP_AFFINITY_CAPABLE() macro
1590b57cec5SDimitry Andric       KMP_AFFINITY_ENABLE(TRUE);
1600b57cec5SDimitry Andric     } else {
1610b57cec5SDimitry Andric       // indicate that hwloc didn't work and disable affinity
1620b57cec5SDimitry Andric       __kmp_hwloc_error = TRUE;
1630b57cec5SDimitry Andric       KMP_AFFINITY_DISABLE();
1640b57cec5SDimitry Andric     }
1650b57cec5SDimitry Andric   }
1660b57cec5SDimitry Andric   void bind_thread(int which) override {
1670b57cec5SDimitry Andric     KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
1680b57cec5SDimitry Andric                 "Illegal set affinity operation when not capable");
1690b57cec5SDimitry Andric     KMPAffinity::Mask *mask;
1700b57cec5SDimitry Andric     KMP_CPU_ALLOC_ON_STACK(mask);
1710b57cec5SDimitry Andric     KMP_CPU_ZERO(mask);
1720b57cec5SDimitry Andric     KMP_CPU_SET(which, mask);
1730b57cec5SDimitry Andric     __kmp_set_system_affinity(mask, TRUE);
1740b57cec5SDimitry Andric     KMP_CPU_FREE_FROM_STACK(mask);
1750b57cec5SDimitry Andric   }
1760b57cec5SDimitry Andric   KMPAffinity::Mask *allocate_mask() override { return new Mask(); }
1770b57cec5SDimitry Andric   void deallocate_mask(KMPAffinity::Mask *m) override { delete m; }
1780b57cec5SDimitry Andric   KMPAffinity::Mask *allocate_mask_array(int num) override {
1790b57cec5SDimitry Andric     return new Mask[num];
1800b57cec5SDimitry Andric   }
1810b57cec5SDimitry Andric   void deallocate_mask_array(KMPAffinity::Mask *array) override {
1820b57cec5SDimitry Andric     Mask *hwloc_array = static_cast<Mask *>(array);
1830b57cec5SDimitry Andric     delete[] hwloc_array;
1840b57cec5SDimitry Andric   }
1850b57cec5SDimitry Andric   KMPAffinity::Mask *index_mask_array(KMPAffinity::Mask *array,
1860b57cec5SDimitry Andric                                       int index) override {
1870b57cec5SDimitry Andric     Mask *hwloc_array = static_cast<Mask *>(array);
1880b57cec5SDimitry Andric     return &(hwloc_array[index]);
1890b57cec5SDimitry Andric   }
1900b57cec5SDimitry Andric   api_type get_api_type() const override { return HWLOC; }
1910b57cec5SDimitry Andric };
1920b57cec5SDimitry Andric #endif /* KMP_USE_HWLOC */
1930b57cec5SDimitry Andric 
194489b1cf2SDimitry Andric #if KMP_OS_LINUX || KMP_OS_FREEBSD
1950b57cec5SDimitry Andric #if KMP_OS_LINUX
1960b57cec5SDimitry Andric /* On some of the older OS's that we build on, these constants aren't present
1970b57cec5SDimitry Andric    in <asm/unistd.h> #included from <sys.syscall.h>. They must be the same on
1980b57cec5SDimitry Andric    all systems of the same arch where they are defined, and they cannot change.
1990b57cec5SDimitry Andric    stone forever. */
2000b57cec5SDimitry Andric #include <sys/syscall.h>
2010b57cec5SDimitry Andric #if KMP_ARCH_X86 || KMP_ARCH_ARM
2020b57cec5SDimitry Andric #ifndef __NR_sched_setaffinity
2030b57cec5SDimitry Andric #define __NR_sched_setaffinity 241
2040b57cec5SDimitry Andric #elif __NR_sched_setaffinity != 241
2050b57cec5SDimitry Andric #error Wrong code for setaffinity system call.
2060b57cec5SDimitry Andric #endif /* __NR_sched_setaffinity */
2070b57cec5SDimitry Andric #ifndef __NR_sched_getaffinity
2080b57cec5SDimitry Andric #define __NR_sched_getaffinity 242
2090b57cec5SDimitry Andric #elif __NR_sched_getaffinity != 242
2100b57cec5SDimitry Andric #error Wrong code for getaffinity system call.
2110b57cec5SDimitry Andric #endif /* __NR_sched_getaffinity */
2120b57cec5SDimitry Andric #elif KMP_ARCH_AARCH64
2130b57cec5SDimitry Andric #ifndef __NR_sched_setaffinity
2140b57cec5SDimitry Andric #define __NR_sched_setaffinity 122
2150b57cec5SDimitry Andric #elif __NR_sched_setaffinity != 122
2160b57cec5SDimitry Andric #error Wrong code for setaffinity system call.
2170b57cec5SDimitry Andric #endif /* __NR_sched_setaffinity */
2180b57cec5SDimitry Andric #ifndef __NR_sched_getaffinity
2190b57cec5SDimitry Andric #define __NR_sched_getaffinity 123
2200b57cec5SDimitry Andric #elif __NR_sched_getaffinity != 123
2210b57cec5SDimitry Andric #error Wrong code for getaffinity system call.
2220b57cec5SDimitry Andric #endif /* __NR_sched_getaffinity */
2230b57cec5SDimitry Andric #elif KMP_ARCH_X86_64
2240b57cec5SDimitry Andric #ifndef __NR_sched_setaffinity
2250b57cec5SDimitry Andric #define __NR_sched_setaffinity 203
2260b57cec5SDimitry Andric #elif __NR_sched_setaffinity != 203
2270b57cec5SDimitry Andric #error Wrong code for setaffinity system call.
2280b57cec5SDimitry Andric #endif /* __NR_sched_setaffinity */
2290b57cec5SDimitry Andric #ifndef __NR_sched_getaffinity
2300b57cec5SDimitry Andric #define __NR_sched_getaffinity 204
2310b57cec5SDimitry Andric #elif __NR_sched_getaffinity != 204
2320b57cec5SDimitry Andric #error Wrong code for getaffinity system call.
2330b57cec5SDimitry Andric #endif /* __NR_sched_getaffinity */
2340b57cec5SDimitry Andric #elif KMP_ARCH_PPC64
2350b57cec5SDimitry Andric #ifndef __NR_sched_setaffinity
2360b57cec5SDimitry Andric #define __NR_sched_setaffinity 222
2370b57cec5SDimitry Andric #elif __NR_sched_setaffinity != 222
2380b57cec5SDimitry Andric #error Wrong code for setaffinity system call.
2390b57cec5SDimitry Andric #endif /* __NR_sched_setaffinity */
2400b57cec5SDimitry Andric #ifndef __NR_sched_getaffinity
2410b57cec5SDimitry Andric #define __NR_sched_getaffinity 223
2420b57cec5SDimitry Andric #elif __NR_sched_getaffinity != 223
2430b57cec5SDimitry Andric #error Wrong code for getaffinity system call.
2440b57cec5SDimitry Andric #endif /* __NR_sched_getaffinity */
2450b57cec5SDimitry Andric #elif KMP_ARCH_MIPS
2460b57cec5SDimitry Andric #ifndef __NR_sched_setaffinity
2470b57cec5SDimitry Andric #define __NR_sched_setaffinity 4239
2480b57cec5SDimitry Andric #elif __NR_sched_setaffinity != 4239
2490b57cec5SDimitry Andric #error Wrong code for setaffinity system call.
2500b57cec5SDimitry Andric #endif /* __NR_sched_setaffinity */
2510b57cec5SDimitry Andric #ifndef __NR_sched_getaffinity
2520b57cec5SDimitry Andric #define __NR_sched_getaffinity 4240
2530b57cec5SDimitry Andric #elif __NR_sched_getaffinity != 4240
2540b57cec5SDimitry Andric #error Wrong code for getaffinity system call.
2550b57cec5SDimitry Andric #endif /* __NR_sched_getaffinity */
2560b57cec5SDimitry Andric #elif KMP_ARCH_MIPS64
2570b57cec5SDimitry Andric #ifndef __NR_sched_setaffinity
2580b57cec5SDimitry Andric #define __NR_sched_setaffinity 5195
2590b57cec5SDimitry Andric #elif __NR_sched_setaffinity != 5195
2600b57cec5SDimitry Andric #error Wrong code for setaffinity system call.
2610b57cec5SDimitry Andric #endif /* __NR_sched_setaffinity */
2620b57cec5SDimitry Andric #ifndef __NR_sched_getaffinity
2630b57cec5SDimitry Andric #define __NR_sched_getaffinity 5196
2640b57cec5SDimitry Andric #elif __NR_sched_getaffinity != 5196
2650b57cec5SDimitry Andric #error Wrong code for getaffinity system call.
2660b57cec5SDimitry Andric #endif /* __NR_sched_getaffinity */
267bdd1243dSDimitry Andric #elif KMP_ARCH_LOONGARCH64
268bdd1243dSDimitry Andric #ifndef __NR_sched_setaffinity
269bdd1243dSDimitry Andric #define __NR_sched_setaffinity 122
270bdd1243dSDimitry Andric #elif __NR_sched_setaffinity != 122
271bdd1243dSDimitry Andric #error Wrong code for setaffinity system call.
272bdd1243dSDimitry Andric #endif /* __NR_sched_setaffinity */
273bdd1243dSDimitry Andric #ifndef __NR_sched_getaffinity
274bdd1243dSDimitry Andric #define __NR_sched_getaffinity 123
275bdd1243dSDimitry Andric #elif __NR_sched_getaffinity != 123
276bdd1243dSDimitry Andric #error Wrong code for getaffinity system call.
277bdd1243dSDimitry Andric #endif /* __NR_sched_getaffinity */
278bdd1243dSDimitry Andric #elif KMP_ARCH_RISCV64
279bdd1243dSDimitry Andric #ifndef __NR_sched_setaffinity
280bdd1243dSDimitry Andric #define __NR_sched_setaffinity 122
281bdd1243dSDimitry Andric #elif __NR_sched_setaffinity != 122
282bdd1243dSDimitry Andric #error Wrong code for setaffinity system call.
283bdd1243dSDimitry Andric #endif /* __NR_sched_setaffinity */
284bdd1243dSDimitry Andric #ifndef __NR_sched_getaffinity
285bdd1243dSDimitry Andric #define __NR_sched_getaffinity 123
286bdd1243dSDimitry Andric #elif __NR_sched_getaffinity != 123
287bdd1243dSDimitry Andric #error Wrong code for getaffinity system call.
288bdd1243dSDimitry Andric #endif /* __NR_sched_getaffinity */
289*5f757f3fSDimitry Andric #elif KMP_ARCH_VE
290*5f757f3fSDimitry Andric #ifndef __NR_sched_setaffinity
291*5f757f3fSDimitry Andric #define __NR_sched_setaffinity 203
292*5f757f3fSDimitry Andric #elif __NR_sched_setaffinity != 203
293*5f757f3fSDimitry Andric #error Wrong code for setaffinity system call.
294*5f757f3fSDimitry Andric #endif /* __NR_sched_setaffinity */
295*5f757f3fSDimitry Andric #ifndef __NR_sched_getaffinity
296*5f757f3fSDimitry Andric #define __NR_sched_getaffinity 204
297*5f757f3fSDimitry Andric #elif __NR_sched_getaffinity != 204
298*5f757f3fSDimitry Andric #error Wrong code for getaffinity system call.
299*5f757f3fSDimitry Andric #endif /* __NR_sched_getaffinity */
300*5f757f3fSDimitry Andric #elif KMP_ARCH_S390X
301*5f757f3fSDimitry Andric #ifndef __NR_sched_setaffinity
302*5f757f3fSDimitry Andric #define __NR_sched_setaffinity 239
303*5f757f3fSDimitry Andric #elif __NR_sched_setaffinity != 239
304*5f757f3fSDimitry Andric #error Wrong code for setaffinity system call.
305*5f757f3fSDimitry Andric #endif /* __NR_sched_setaffinity */
306*5f757f3fSDimitry Andric #ifndef __NR_sched_getaffinity
307*5f757f3fSDimitry Andric #define __NR_sched_getaffinity 240
308*5f757f3fSDimitry Andric #elif __NR_sched_getaffinity != 240
309*5f757f3fSDimitry Andric #error Wrong code for getaffinity system call.
310*5f757f3fSDimitry Andric #endif /* __NR_sched_getaffinity */
311bdd1243dSDimitry Andric #else
3120b57cec5SDimitry Andric #error Unknown or unsupported architecture
3130b57cec5SDimitry Andric #endif /* KMP_ARCH_* */
314489b1cf2SDimitry Andric #elif KMP_OS_FREEBSD
315489b1cf2SDimitry Andric #include <pthread.h>
316489b1cf2SDimitry Andric #include <pthread_np.h>
317489b1cf2SDimitry Andric #endif
3180b57cec5SDimitry Andric class KMPNativeAffinity : public KMPAffinity {
3190b57cec5SDimitry Andric   class Mask : public KMPAffinity::Mask {
320e8d8bef9SDimitry Andric     typedef unsigned long mask_t;
321e8d8bef9SDimitry Andric     typedef decltype(__kmp_affin_mask_size) mask_size_type;
322e8d8bef9SDimitry Andric     static const unsigned int BITS_PER_MASK_T = sizeof(mask_t) * CHAR_BIT;
323e8d8bef9SDimitry Andric     static const mask_t ONE = 1;
324e8d8bef9SDimitry Andric     mask_size_type get_num_mask_types() const {
325e8d8bef9SDimitry Andric       return __kmp_affin_mask_size / sizeof(mask_t);
326e8d8bef9SDimitry Andric     }
3270b57cec5SDimitry Andric 
3280b57cec5SDimitry Andric   public:
3290b57cec5SDimitry Andric     mask_t *mask;
3300b57cec5SDimitry Andric     Mask() { mask = (mask_t *)__kmp_allocate(__kmp_affin_mask_size); }
3310b57cec5SDimitry Andric     ~Mask() {
3320b57cec5SDimitry Andric       if (mask)
3330b57cec5SDimitry Andric         __kmp_free(mask);
3340b57cec5SDimitry Andric     }
3350b57cec5SDimitry Andric     void set(int i) override {
336e8d8bef9SDimitry Andric       mask[i / BITS_PER_MASK_T] |= (ONE << (i % BITS_PER_MASK_T));
3370b57cec5SDimitry Andric     }
3380b57cec5SDimitry Andric     bool is_set(int i) const override {
339e8d8bef9SDimitry Andric       return (mask[i / BITS_PER_MASK_T] & (ONE << (i % BITS_PER_MASK_T)));
3400b57cec5SDimitry Andric     }
3410b57cec5SDimitry Andric     void clear(int i) override {
342e8d8bef9SDimitry Andric       mask[i / BITS_PER_MASK_T] &= ~(ONE << (i % BITS_PER_MASK_T));
3430b57cec5SDimitry Andric     }
3440b57cec5SDimitry Andric     void zero() override {
345e8d8bef9SDimitry Andric       mask_size_type e = get_num_mask_types();
346e8d8bef9SDimitry Andric       for (mask_size_type i = 0; i < e; ++i)
347e8d8bef9SDimitry Andric         mask[i] = (mask_t)0;
3480b57cec5SDimitry Andric     }
349*5f757f3fSDimitry Andric     bool empty() const override {
350*5f757f3fSDimitry Andric       mask_size_type e = get_num_mask_types();
351*5f757f3fSDimitry Andric       for (mask_size_type i = 0; i < e; ++i)
352*5f757f3fSDimitry Andric         if (mask[i] != (mask_t)0)
353*5f757f3fSDimitry Andric           return false;
354*5f757f3fSDimitry Andric       return true;
355*5f757f3fSDimitry Andric     }
3560b57cec5SDimitry Andric     void copy(const KMPAffinity::Mask *src) override {
3570b57cec5SDimitry Andric       const Mask *convert = static_cast<const Mask *>(src);
358e8d8bef9SDimitry Andric       mask_size_type e = get_num_mask_types();
359e8d8bef9SDimitry Andric       for (mask_size_type i = 0; i < e; ++i)
3600b57cec5SDimitry Andric         mask[i] = convert->mask[i];
3610b57cec5SDimitry Andric     }
3620b57cec5SDimitry Andric     void bitwise_and(const KMPAffinity::Mask *rhs) override {
3630b57cec5SDimitry Andric       const Mask *convert = static_cast<const Mask *>(rhs);
364e8d8bef9SDimitry Andric       mask_size_type e = get_num_mask_types();
365e8d8bef9SDimitry Andric       for (mask_size_type i = 0; i < e; ++i)
3660b57cec5SDimitry Andric         mask[i] &= convert->mask[i];
3670b57cec5SDimitry Andric     }
3680b57cec5SDimitry Andric     void bitwise_or(const KMPAffinity::Mask *rhs) override {
3690b57cec5SDimitry Andric       const Mask *convert = static_cast<const Mask *>(rhs);
370e8d8bef9SDimitry Andric       mask_size_type e = get_num_mask_types();
371e8d8bef9SDimitry Andric       for (mask_size_type i = 0; i < e; ++i)
3720b57cec5SDimitry Andric         mask[i] |= convert->mask[i];
3730b57cec5SDimitry Andric     }
3740b57cec5SDimitry Andric     void bitwise_not() override {
375e8d8bef9SDimitry Andric       mask_size_type e = get_num_mask_types();
376e8d8bef9SDimitry Andric       for (mask_size_type i = 0; i < e; ++i)
3770b57cec5SDimitry Andric         mask[i] = ~(mask[i]);
3780b57cec5SDimitry Andric     }
379*5f757f3fSDimitry Andric     bool is_equal(const KMPAffinity::Mask *rhs) const override {
380*5f757f3fSDimitry Andric       const Mask *convert = static_cast<const Mask *>(rhs);
381*5f757f3fSDimitry Andric       mask_size_type e = get_num_mask_types();
382*5f757f3fSDimitry Andric       for (mask_size_type i = 0; i < e; ++i)
383*5f757f3fSDimitry Andric         if (mask[i] != convert->mask[i])
384*5f757f3fSDimitry Andric           return false;
385*5f757f3fSDimitry Andric       return true;
386*5f757f3fSDimitry Andric     }
3870b57cec5SDimitry Andric     int begin() const override {
3880b57cec5SDimitry Andric       int retval = 0;
3890b57cec5SDimitry Andric       while (retval < end() && !is_set(retval))
3900b57cec5SDimitry Andric         ++retval;
3910b57cec5SDimitry Andric       return retval;
3920b57cec5SDimitry Andric     }
393e8d8bef9SDimitry Andric     int end() const override {
394e8d8bef9SDimitry Andric       int e;
395e8d8bef9SDimitry Andric       __kmp_type_convert(get_num_mask_types() * BITS_PER_MASK_T, &e);
396e8d8bef9SDimitry Andric       return e;
397e8d8bef9SDimitry Andric     }
3980b57cec5SDimitry Andric     int next(int previous) const override {
3990b57cec5SDimitry Andric       int retval = previous + 1;
4000b57cec5SDimitry Andric       while (retval < end() && !is_set(retval))
4010b57cec5SDimitry Andric         ++retval;
4020b57cec5SDimitry Andric       return retval;
4030b57cec5SDimitry Andric     }
4040b57cec5SDimitry Andric     int get_system_affinity(bool abort_on_error) override {
4050b57cec5SDimitry Andric       KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
4060b57cec5SDimitry Andric                   "Illegal get affinity operation when not capable");
407489b1cf2SDimitry Andric #if KMP_OS_LINUX
408e8d8bef9SDimitry Andric       long retval =
4090b57cec5SDimitry Andric           syscall(__NR_sched_getaffinity, 0, __kmp_affin_mask_size, mask);
410489b1cf2SDimitry Andric #elif KMP_OS_FREEBSD
411fe6060f1SDimitry Andric       int r = pthread_getaffinity_np(pthread_self(), __kmp_affin_mask_size,
412fe6060f1SDimitry Andric                                      reinterpret_cast<cpuset_t *>(mask));
4135ffd83dbSDimitry Andric       int retval = (r == 0 ? 0 : -1);
414489b1cf2SDimitry Andric #endif
4150b57cec5SDimitry Andric       if (retval >= 0) {
4160b57cec5SDimitry Andric         return 0;
4170b57cec5SDimitry Andric       }
4180b57cec5SDimitry Andric       int error = errno;
4190b57cec5SDimitry Andric       if (abort_on_error) {
42006c3fb27SDimitry Andric         __kmp_fatal(KMP_MSG(FunctionError, "pthread_getaffinity_np()"),
42106c3fb27SDimitry Andric                     KMP_ERR(error), __kmp_msg_null);
4220b57cec5SDimitry Andric       }
4230b57cec5SDimitry Andric       return error;
4240b57cec5SDimitry Andric     }
4250b57cec5SDimitry Andric     int set_system_affinity(bool abort_on_error) const override {
4260b57cec5SDimitry Andric       KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
427e8d8bef9SDimitry Andric                   "Illegal set affinity operation when not capable");
428489b1cf2SDimitry Andric #if KMP_OS_LINUX
429e8d8bef9SDimitry Andric       long retval =
4300b57cec5SDimitry Andric           syscall(__NR_sched_setaffinity, 0, __kmp_affin_mask_size, mask);
431489b1cf2SDimitry Andric #elif KMP_OS_FREEBSD
432fe6060f1SDimitry Andric       int r = pthread_setaffinity_np(pthread_self(), __kmp_affin_mask_size,
433fe6060f1SDimitry Andric                                      reinterpret_cast<cpuset_t *>(mask));
4345ffd83dbSDimitry Andric       int retval = (r == 0 ? 0 : -1);
435489b1cf2SDimitry Andric #endif
4360b57cec5SDimitry Andric       if (retval >= 0) {
4370b57cec5SDimitry Andric         return 0;
4380b57cec5SDimitry Andric       }
4390b57cec5SDimitry Andric       int error = errno;
4400b57cec5SDimitry Andric       if (abort_on_error) {
44106c3fb27SDimitry Andric         __kmp_fatal(KMP_MSG(FunctionError, "pthread_setaffinity_np()"),
44206c3fb27SDimitry Andric                     KMP_ERR(error), __kmp_msg_null);
4430b57cec5SDimitry Andric       }
4440b57cec5SDimitry Andric       return error;
4450b57cec5SDimitry Andric     }
4460b57cec5SDimitry Andric   };
4470b57cec5SDimitry Andric   void determine_capable(const char *env_var) override {
4480b57cec5SDimitry Andric     __kmp_affinity_determine_capable(env_var);
4490b57cec5SDimitry Andric   }
4500b57cec5SDimitry Andric   void bind_thread(int which) override { __kmp_affinity_bind_thread(which); }
4510b57cec5SDimitry Andric   KMPAffinity::Mask *allocate_mask() override {
4520b57cec5SDimitry Andric     KMPNativeAffinity::Mask *retval = new Mask();
4530b57cec5SDimitry Andric     return retval;
4540b57cec5SDimitry Andric   }
4550b57cec5SDimitry Andric   void deallocate_mask(KMPAffinity::Mask *m) override {
4560b57cec5SDimitry Andric     KMPNativeAffinity::Mask *native_mask =
4570b57cec5SDimitry Andric         static_cast<KMPNativeAffinity::Mask *>(m);
4580b57cec5SDimitry Andric     delete native_mask;
4590b57cec5SDimitry Andric   }
4600b57cec5SDimitry Andric   KMPAffinity::Mask *allocate_mask_array(int num) override {
4610b57cec5SDimitry Andric     return new Mask[num];
4620b57cec5SDimitry Andric   }
4630b57cec5SDimitry Andric   void deallocate_mask_array(KMPAffinity::Mask *array) override {
4640b57cec5SDimitry Andric     Mask *linux_array = static_cast<Mask *>(array);
4650b57cec5SDimitry Andric     delete[] linux_array;
4660b57cec5SDimitry Andric   }
4670b57cec5SDimitry Andric   KMPAffinity::Mask *index_mask_array(KMPAffinity::Mask *array,
4680b57cec5SDimitry Andric                                       int index) override {
4690b57cec5SDimitry Andric     Mask *linux_array = static_cast<Mask *>(array);
4700b57cec5SDimitry Andric     return &(linux_array[index]);
4710b57cec5SDimitry Andric   }
4720b57cec5SDimitry Andric   api_type get_api_type() const override { return NATIVE_OS; }
4730b57cec5SDimitry Andric };
474489b1cf2SDimitry Andric #endif /* KMP_OS_LINUX || KMP_OS_FREEBSD */
4750b57cec5SDimitry Andric 
4760b57cec5SDimitry Andric #if KMP_OS_WINDOWS
4770b57cec5SDimitry Andric class KMPNativeAffinity : public KMPAffinity {
4780b57cec5SDimitry Andric   class Mask : public KMPAffinity::Mask {
4790b57cec5SDimitry Andric     typedef ULONG_PTR mask_t;
4800b57cec5SDimitry Andric     static const int BITS_PER_MASK_T = sizeof(mask_t) * CHAR_BIT;
4810b57cec5SDimitry Andric     mask_t *mask;
4820b57cec5SDimitry Andric 
4830b57cec5SDimitry Andric   public:
4840b57cec5SDimitry Andric     Mask() {
4850b57cec5SDimitry Andric       mask = (mask_t *)__kmp_allocate(sizeof(mask_t) * __kmp_num_proc_groups);
4860b57cec5SDimitry Andric     }
4870b57cec5SDimitry Andric     ~Mask() {
4880b57cec5SDimitry Andric       if (mask)
4890b57cec5SDimitry Andric         __kmp_free(mask);
4900b57cec5SDimitry Andric     }
4910b57cec5SDimitry Andric     void set(int i) override {
4920b57cec5SDimitry Andric       mask[i / BITS_PER_MASK_T] |= ((mask_t)1 << (i % BITS_PER_MASK_T));
4930b57cec5SDimitry Andric     }
4940b57cec5SDimitry Andric     bool is_set(int i) const override {
4950b57cec5SDimitry Andric       return (mask[i / BITS_PER_MASK_T] & ((mask_t)1 << (i % BITS_PER_MASK_T)));
4960b57cec5SDimitry Andric     }
4970b57cec5SDimitry Andric     void clear(int i) override {
4980b57cec5SDimitry Andric       mask[i / BITS_PER_MASK_T] &= ~((mask_t)1 << (i % BITS_PER_MASK_T));
4990b57cec5SDimitry Andric     }
5000b57cec5SDimitry Andric     void zero() override {
5010b57cec5SDimitry Andric       for (int i = 0; i < __kmp_num_proc_groups; ++i)
5020b57cec5SDimitry Andric         mask[i] = 0;
5030b57cec5SDimitry Andric     }
504*5f757f3fSDimitry Andric     bool empty() const override {
505*5f757f3fSDimitry Andric       for (size_t i = 0; i < __kmp_num_proc_groups; ++i)
506*5f757f3fSDimitry Andric         if (mask[i])
507*5f757f3fSDimitry Andric           return false;
508*5f757f3fSDimitry Andric       return true;
509*5f757f3fSDimitry Andric     }
5100b57cec5SDimitry Andric     void copy(const KMPAffinity::Mask *src) override {
5110b57cec5SDimitry Andric       const Mask *convert = static_cast<const Mask *>(src);
5120b57cec5SDimitry Andric       for (int i = 0; i < __kmp_num_proc_groups; ++i)
5130b57cec5SDimitry Andric         mask[i] = convert->mask[i];
5140b57cec5SDimitry Andric     }
5150b57cec5SDimitry Andric     void bitwise_and(const KMPAffinity::Mask *rhs) override {
5160b57cec5SDimitry Andric       const Mask *convert = static_cast<const Mask *>(rhs);
5170b57cec5SDimitry Andric       for (int i = 0; i < __kmp_num_proc_groups; ++i)
5180b57cec5SDimitry Andric         mask[i] &= convert->mask[i];
5190b57cec5SDimitry Andric     }
5200b57cec5SDimitry Andric     void bitwise_or(const KMPAffinity::Mask *rhs) override {
5210b57cec5SDimitry Andric       const Mask *convert = static_cast<const Mask *>(rhs);
5220b57cec5SDimitry Andric       for (int i = 0; i < __kmp_num_proc_groups; ++i)
5230b57cec5SDimitry Andric         mask[i] |= convert->mask[i];
5240b57cec5SDimitry Andric     }
5250b57cec5SDimitry Andric     void bitwise_not() override {
5260b57cec5SDimitry Andric       for (int i = 0; i < __kmp_num_proc_groups; ++i)
5270b57cec5SDimitry Andric         mask[i] = ~(mask[i]);
5280b57cec5SDimitry Andric     }
529*5f757f3fSDimitry Andric     bool is_equal(const KMPAffinity::Mask *rhs) const override {
530*5f757f3fSDimitry Andric       const Mask *convert = static_cast<const Mask *>(rhs);
531*5f757f3fSDimitry Andric       for (size_t i = 0; i < __kmp_num_proc_groups; ++i)
532*5f757f3fSDimitry Andric         if (mask[i] != convert->mask[i])
533*5f757f3fSDimitry Andric           return false;
534*5f757f3fSDimitry Andric       return true;
535*5f757f3fSDimitry Andric     }
5360b57cec5SDimitry Andric     int begin() const override {
5370b57cec5SDimitry Andric       int retval = 0;
5380b57cec5SDimitry Andric       while (retval < end() && !is_set(retval))
5390b57cec5SDimitry Andric         ++retval;
5400b57cec5SDimitry Andric       return retval;
5410b57cec5SDimitry Andric     }
5420b57cec5SDimitry Andric     int end() const override { return __kmp_num_proc_groups * BITS_PER_MASK_T; }
5430b57cec5SDimitry Andric     int next(int previous) const override {
5440b57cec5SDimitry Andric       int retval = previous + 1;
5450b57cec5SDimitry Andric       while (retval < end() && !is_set(retval))
5460b57cec5SDimitry Andric         ++retval;
5470b57cec5SDimitry Andric       return retval;
5480b57cec5SDimitry Andric     }
549e8d8bef9SDimitry Andric     int set_process_affinity(bool abort_on_error) const override {
550e8d8bef9SDimitry Andric       if (__kmp_num_proc_groups <= 1) {
551e8d8bef9SDimitry Andric         if (!SetProcessAffinityMask(GetCurrentProcess(), *mask)) {
552e8d8bef9SDimitry Andric           DWORD error = GetLastError();
553e8d8bef9SDimitry Andric           if (abort_on_error) {
554e8d8bef9SDimitry Andric             __kmp_fatal(KMP_MSG(CantSetThreadAffMask), KMP_ERR(error),
555e8d8bef9SDimitry Andric                         __kmp_msg_null);
556e8d8bef9SDimitry Andric           }
557e8d8bef9SDimitry Andric           return error;
558e8d8bef9SDimitry Andric         }
559e8d8bef9SDimitry Andric       }
560e8d8bef9SDimitry Andric       return 0;
561e8d8bef9SDimitry Andric     }
5620b57cec5SDimitry Andric     int set_system_affinity(bool abort_on_error) const override {
5630b57cec5SDimitry Andric       if (__kmp_num_proc_groups > 1) {
5640b57cec5SDimitry Andric         // Check for a valid mask.
5650b57cec5SDimitry Andric         GROUP_AFFINITY ga;
5660b57cec5SDimitry Andric         int group = get_proc_group();
5670b57cec5SDimitry Andric         if (group < 0) {
5680b57cec5SDimitry Andric           if (abort_on_error) {
5690b57cec5SDimitry Andric             KMP_FATAL(AffinityInvalidMask, "kmp_set_affinity");
5700b57cec5SDimitry Andric           }
5710b57cec5SDimitry Andric           return -1;
5720b57cec5SDimitry Andric         }
5730b57cec5SDimitry Andric         // Transform the bit vector into a GROUP_AFFINITY struct
5740b57cec5SDimitry Andric         // and make the system call to set affinity.
5750b57cec5SDimitry Andric         ga.Group = group;
5760b57cec5SDimitry Andric         ga.Mask = mask[group];
5770b57cec5SDimitry Andric         ga.Reserved[0] = ga.Reserved[1] = ga.Reserved[2] = 0;
5780b57cec5SDimitry Andric 
5790b57cec5SDimitry Andric         KMP_DEBUG_ASSERT(__kmp_SetThreadGroupAffinity != NULL);
5800b57cec5SDimitry Andric         if (__kmp_SetThreadGroupAffinity(GetCurrentThread(), &ga, NULL) == 0) {
5810b57cec5SDimitry Andric           DWORD error = GetLastError();
5820b57cec5SDimitry Andric           if (abort_on_error) {
5830b57cec5SDimitry Andric             __kmp_fatal(KMP_MSG(CantSetThreadAffMask), KMP_ERR(error),
5840b57cec5SDimitry Andric                         __kmp_msg_null);
5850b57cec5SDimitry Andric           }
5860b57cec5SDimitry Andric           return error;
5870b57cec5SDimitry Andric         }
5880b57cec5SDimitry Andric       } else {
5890b57cec5SDimitry Andric         if (!SetThreadAffinityMask(GetCurrentThread(), *mask)) {
5900b57cec5SDimitry Andric           DWORD error = GetLastError();
5910b57cec5SDimitry Andric           if (abort_on_error) {
5920b57cec5SDimitry Andric             __kmp_fatal(KMP_MSG(CantSetThreadAffMask), KMP_ERR(error),
5930b57cec5SDimitry Andric                         __kmp_msg_null);
5940b57cec5SDimitry Andric           }
5950b57cec5SDimitry Andric           return error;
5960b57cec5SDimitry Andric         }
5970b57cec5SDimitry Andric       }
5980b57cec5SDimitry Andric       return 0;
5990b57cec5SDimitry Andric     }
6000b57cec5SDimitry Andric     int get_system_affinity(bool abort_on_error) override {
6010b57cec5SDimitry Andric       if (__kmp_num_proc_groups > 1) {
6020b57cec5SDimitry Andric         this->zero();
6030b57cec5SDimitry Andric         GROUP_AFFINITY ga;
6040b57cec5SDimitry Andric         KMP_DEBUG_ASSERT(__kmp_GetThreadGroupAffinity != NULL);
6050b57cec5SDimitry Andric         if (__kmp_GetThreadGroupAffinity(GetCurrentThread(), &ga) == 0) {
6060b57cec5SDimitry Andric           DWORD error = GetLastError();
6070b57cec5SDimitry Andric           if (abort_on_error) {
6080b57cec5SDimitry Andric             __kmp_fatal(KMP_MSG(FunctionError, "GetThreadGroupAffinity()"),
6090b57cec5SDimitry Andric                         KMP_ERR(error), __kmp_msg_null);
6100b57cec5SDimitry Andric           }
6110b57cec5SDimitry Andric           return error;
6120b57cec5SDimitry Andric         }
6130b57cec5SDimitry Andric         if ((ga.Group < 0) || (ga.Group > __kmp_num_proc_groups) ||
6140b57cec5SDimitry Andric             (ga.Mask == 0)) {
6150b57cec5SDimitry Andric           return -1;
6160b57cec5SDimitry Andric         }
6170b57cec5SDimitry Andric         mask[ga.Group] = ga.Mask;
6180b57cec5SDimitry Andric       } else {
6190b57cec5SDimitry Andric         mask_t newMask, sysMask, retval;
6200b57cec5SDimitry Andric         if (!GetProcessAffinityMask(GetCurrentProcess(), &newMask, &sysMask)) {
6210b57cec5SDimitry Andric           DWORD error = GetLastError();
6220b57cec5SDimitry Andric           if (abort_on_error) {
6230b57cec5SDimitry Andric             __kmp_fatal(KMP_MSG(FunctionError, "GetProcessAffinityMask()"),
6240b57cec5SDimitry Andric                         KMP_ERR(error), __kmp_msg_null);
6250b57cec5SDimitry Andric           }
6260b57cec5SDimitry Andric           return error;
6270b57cec5SDimitry Andric         }
6280b57cec5SDimitry Andric         retval = SetThreadAffinityMask(GetCurrentThread(), newMask);
6290b57cec5SDimitry Andric         if (!retval) {
6300b57cec5SDimitry Andric           DWORD error = GetLastError();
6310b57cec5SDimitry Andric           if (abort_on_error) {
6320b57cec5SDimitry Andric             __kmp_fatal(KMP_MSG(FunctionError, "SetThreadAffinityMask()"),
6330b57cec5SDimitry Andric                         KMP_ERR(error), __kmp_msg_null);
6340b57cec5SDimitry Andric           }
6350b57cec5SDimitry Andric           return error;
6360b57cec5SDimitry Andric         }
6370b57cec5SDimitry Andric         newMask = SetThreadAffinityMask(GetCurrentThread(), retval);
6380b57cec5SDimitry Andric         if (!newMask) {
6390b57cec5SDimitry Andric           DWORD error = GetLastError();
6400b57cec5SDimitry Andric           if (abort_on_error) {
6410b57cec5SDimitry Andric             __kmp_fatal(KMP_MSG(FunctionError, "SetThreadAffinityMask()"),
6420b57cec5SDimitry Andric                         KMP_ERR(error), __kmp_msg_null);
6430b57cec5SDimitry Andric           }
6440b57cec5SDimitry Andric         }
6450b57cec5SDimitry Andric         *mask = retval;
6460b57cec5SDimitry Andric       }
6470b57cec5SDimitry Andric       return 0;
6480b57cec5SDimitry Andric     }
6490b57cec5SDimitry Andric     int get_proc_group() const override {
6500b57cec5SDimitry Andric       int group = -1;
6510b57cec5SDimitry Andric       if (__kmp_num_proc_groups == 1) {
6520b57cec5SDimitry Andric         return 1;
6530b57cec5SDimitry Andric       }
6540b57cec5SDimitry Andric       for (int i = 0; i < __kmp_num_proc_groups; i++) {
6550b57cec5SDimitry Andric         if (mask[i] == 0)
6560b57cec5SDimitry Andric           continue;
6570b57cec5SDimitry Andric         if (group >= 0)
6580b57cec5SDimitry Andric           return -1;
6590b57cec5SDimitry Andric         group = i;
6600b57cec5SDimitry Andric       }
6610b57cec5SDimitry Andric       return group;
6620b57cec5SDimitry Andric     }
6630b57cec5SDimitry Andric   };
6640b57cec5SDimitry Andric   void determine_capable(const char *env_var) override {
6650b57cec5SDimitry Andric     __kmp_affinity_determine_capable(env_var);
6660b57cec5SDimitry Andric   }
6670b57cec5SDimitry Andric   void bind_thread(int which) override { __kmp_affinity_bind_thread(which); }
6680b57cec5SDimitry Andric   KMPAffinity::Mask *allocate_mask() override { return new Mask(); }
6690b57cec5SDimitry Andric   void deallocate_mask(KMPAffinity::Mask *m) override { delete m; }
6700b57cec5SDimitry Andric   KMPAffinity::Mask *allocate_mask_array(int num) override {
6710b57cec5SDimitry Andric     return new Mask[num];
6720b57cec5SDimitry Andric   }
6730b57cec5SDimitry Andric   void deallocate_mask_array(KMPAffinity::Mask *array) override {
6740b57cec5SDimitry Andric     Mask *windows_array = static_cast<Mask *>(array);
6750b57cec5SDimitry Andric     delete[] windows_array;
6760b57cec5SDimitry Andric   }
6770b57cec5SDimitry Andric   KMPAffinity::Mask *index_mask_array(KMPAffinity::Mask *array,
6780b57cec5SDimitry Andric                                       int index) override {
6790b57cec5SDimitry Andric     Mask *windows_array = static_cast<Mask *>(array);
6800b57cec5SDimitry Andric     return &(windows_array[index]);
6810b57cec5SDimitry Andric   }
6820b57cec5SDimitry Andric   api_type get_api_type() const override { return NATIVE_OS; }
6830b57cec5SDimitry Andric };
6840b57cec5SDimitry Andric #endif /* KMP_OS_WINDOWS */
6850b57cec5SDimitry Andric #endif /* KMP_AFFINITY_SUPPORTED */
6860b57cec5SDimitry Andric 
6870eae32dcSDimitry Andric // Describe an attribute for a level in the machine topology
6880eae32dcSDimitry Andric struct kmp_hw_attr_t {
6890eae32dcSDimitry Andric   int core_type : 8;
6900eae32dcSDimitry Andric   int core_eff : 8;
6910eae32dcSDimitry Andric   unsigned valid : 1;
6920eae32dcSDimitry Andric   unsigned reserved : 15;
6930eae32dcSDimitry Andric 
6940eae32dcSDimitry Andric   static const int UNKNOWN_CORE_EFF = -1;
6950eae32dcSDimitry Andric 
6960eae32dcSDimitry Andric   kmp_hw_attr_t()
6970eae32dcSDimitry Andric       : core_type(KMP_HW_CORE_TYPE_UNKNOWN), core_eff(UNKNOWN_CORE_EFF),
6980eae32dcSDimitry Andric         valid(0), reserved(0) {}
6990eae32dcSDimitry Andric   void set_core_type(kmp_hw_core_type_t type) {
7000eae32dcSDimitry Andric     valid = 1;
7010eae32dcSDimitry Andric     core_type = type;
7020eae32dcSDimitry Andric   }
7030eae32dcSDimitry Andric   void set_core_eff(int eff) {
7040eae32dcSDimitry Andric     valid = 1;
7050eae32dcSDimitry Andric     core_eff = eff;
7060eae32dcSDimitry Andric   }
7070eae32dcSDimitry Andric   kmp_hw_core_type_t get_core_type() const {
7080eae32dcSDimitry Andric     return (kmp_hw_core_type_t)core_type;
7090eae32dcSDimitry Andric   }
7100eae32dcSDimitry Andric   int get_core_eff() const { return core_eff; }
7110eae32dcSDimitry Andric   bool is_core_type_valid() const {
7120eae32dcSDimitry Andric     return core_type != KMP_HW_CORE_TYPE_UNKNOWN;
7130eae32dcSDimitry Andric   }
7140eae32dcSDimitry Andric   bool is_core_eff_valid() const { return core_eff != UNKNOWN_CORE_EFF; }
7150eae32dcSDimitry Andric   operator bool() const { return valid; }
7160eae32dcSDimitry Andric   void clear() {
7170eae32dcSDimitry Andric     core_type = KMP_HW_CORE_TYPE_UNKNOWN;
7180eae32dcSDimitry Andric     core_eff = UNKNOWN_CORE_EFF;
7190eae32dcSDimitry Andric     valid = 0;
7200eae32dcSDimitry Andric   }
7210eae32dcSDimitry Andric   bool contains(const kmp_hw_attr_t &other) const {
7220eae32dcSDimitry Andric     if (!valid && !other.valid)
7230eae32dcSDimitry Andric       return true;
7240eae32dcSDimitry Andric     if (valid && other.valid) {
7250eae32dcSDimitry Andric       if (other.is_core_type_valid()) {
7260eae32dcSDimitry Andric         if (!is_core_type_valid() || (get_core_type() != other.get_core_type()))
7270eae32dcSDimitry Andric           return false;
7280eae32dcSDimitry Andric       }
7290eae32dcSDimitry Andric       if (other.is_core_eff_valid()) {
7300eae32dcSDimitry Andric         if (!is_core_eff_valid() || (get_core_eff() != other.get_core_eff()))
7310eae32dcSDimitry Andric           return false;
7320eae32dcSDimitry Andric       }
7330eae32dcSDimitry Andric       return true;
7340eae32dcSDimitry Andric     }
7350eae32dcSDimitry Andric     return false;
7360eae32dcSDimitry Andric   }
737*5f757f3fSDimitry Andric #if KMP_AFFINITY_SUPPORTED
738*5f757f3fSDimitry Andric   bool contains(const kmp_affinity_attrs_t &attr) const {
739*5f757f3fSDimitry Andric     if (!valid && !attr.valid)
740*5f757f3fSDimitry Andric       return true;
741*5f757f3fSDimitry Andric     if (valid && attr.valid) {
742*5f757f3fSDimitry Andric       if (attr.core_type != KMP_HW_CORE_TYPE_UNKNOWN)
743*5f757f3fSDimitry Andric         return (is_core_type_valid() &&
744*5f757f3fSDimitry Andric                 (get_core_type() == (kmp_hw_core_type_t)attr.core_type));
745*5f757f3fSDimitry Andric       if (attr.core_eff != UNKNOWN_CORE_EFF)
746*5f757f3fSDimitry Andric         return (is_core_eff_valid() && (get_core_eff() == attr.core_eff));
747*5f757f3fSDimitry Andric       return true;
748*5f757f3fSDimitry Andric     }
749*5f757f3fSDimitry Andric     return false;
750*5f757f3fSDimitry Andric   }
751*5f757f3fSDimitry Andric #endif // KMP_AFFINITY_SUPPORTED
7520eae32dcSDimitry Andric   bool operator==(const kmp_hw_attr_t &rhs) const {
7530eae32dcSDimitry Andric     return (rhs.valid == valid && rhs.core_eff == core_eff &&
7540eae32dcSDimitry Andric             rhs.core_type == core_type);
7550eae32dcSDimitry Andric   }
7560eae32dcSDimitry Andric   bool operator!=(const kmp_hw_attr_t &rhs) const { return !operator==(rhs); }
7570eae32dcSDimitry Andric };
758349cc55cSDimitry Andric 
759bdd1243dSDimitry Andric #if KMP_AFFINITY_SUPPORTED
760bdd1243dSDimitry Andric KMP_BUILD_ASSERT(sizeof(kmp_hw_attr_t) == sizeof(kmp_affinity_attrs_t));
761bdd1243dSDimitry Andric #endif
762bdd1243dSDimitry Andric 
763fe6060f1SDimitry Andric class kmp_hw_thread_t {
7640b57cec5SDimitry Andric public:
765fe6060f1SDimitry Andric   static const int UNKNOWN_ID = -1;
766bdd1243dSDimitry Andric   static const int MULTIPLE_ID = -2;
767fe6060f1SDimitry Andric   static int compare_ids(const void *a, const void *b);
768fe6060f1SDimitry Andric   static int compare_compact(const void *a, const void *b);
769fe6060f1SDimitry Andric   int ids[KMP_HW_LAST];
770fe6060f1SDimitry Andric   int sub_ids[KMP_HW_LAST];
771fe6060f1SDimitry Andric   bool leader;
772fe6060f1SDimitry Andric   int os_id;
7730eae32dcSDimitry Andric   kmp_hw_attr_t attrs;
774349cc55cSDimitry Andric 
775fe6060f1SDimitry Andric   void print() const;
776fe6060f1SDimitry Andric   void clear() {
777fe6060f1SDimitry Andric     for (int i = 0; i < (int)KMP_HW_LAST; ++i)
778fe6060f1SDimitry Andric       ids[i] = UNKNOWN_ID;
779fe6060f1SDimitry Andric     leader = false;
7800eae32dcSDimitry Andric     attrs.clear();
7810b57cec5SDimitry Andric   }
7820b57cec5SDimitry Andric };
7830b57cec5SDimitry Andric 
784fe6060f1SDimitry Andric class kmp_topology_t {
785fe6060f1SDimitry Andric 
786fe6060f1SDimitry Andric   struct flags_t {
787fe6060f1SDimitry Andric     int uniform : 1;
788fe6060f1SDimitry Andric     int reserved : 31;
7890b57cec5SDimitry Andric   };
7900b57cec5SDimitry Andric 
791fe6060f1SDimitry Andric   int depth;
792fe6060f1SDimitry Andric 
793349cc55cSDimitry Andric   // The following arrays are all 'depth' long and have been
794349cc55cSDimitry Andric   // allocated to hold up to KMP_HW_LAST number of objects if
795349cc55cSDimitry Andric   // needed so layers can be added without reallocation of any array
796fe6060f1SDimitry Andric 
797fe6060f1SDimitry Andric   // Orderd array of the types in the topology
798fe6060f1SDimitry Andric   kmp_hw_t *types;
799fe6060f1SDimitry Andric 
800fe6060f1SDimitry Andric   // Keep quick topology ratios, for non-uniform topologies,
801fe6060f1SDimitry Andric   // this ratio holds the max number of itemAs per itemB
802fe6060f1SDimitry Andric   // e.g., [ 4 packages | 6 cores / package | 2 threads / core ]
803fe6060f1SDimitry Andric   int *ratio;
804fe6060f1SDimitry Andric 
805fe6060f1SDimitry Andric   // Storage containing the absolute number of each topology layer
806fe6060f1SDimitry Andric   int *count;
807fe6060f1SDimitry Andric 
8080eae32dcSDimitry Andric   // The number of core efficiencies. This is only useful for hybrid
8090eae32dcSDimitry Andric   // topologies. Core efficiencies will range from 0 to num efficiencies - 1
8100eae32dcSDimitry Andric   int num_core_efficiencies;
8110eae32dcSDimitry Andric   int num_core_types;
812349cc55cSDimitry Andric   kmp_hw_core_type_t core_types[KMP_HW_MAX_NUM_CORE_TYPES];
813349cc55cSDimitry Andric 
814fe6060f1SDimitry Andric   // The hardware threads array
815fe6060f1SDimitry Andric   // hw_threads is num_hw_threads long
816fe6060f1SDimitry Andric   // Each hw_thread's ids and sub_ids are depth deep
817fe6060f1SDimitry Andric   int num_hw_threads;
818fe6060f1SDimitry Andric   kmp_hw_thread_t *hw_threads;
819fe6060f1SDimitry Andric 
820fe6060f1SDimitry Andric   // Equivalence hash where the key is the hardware topology item
821fe6060f1SDimitry Andric   // and the value is the equivalent hardware topology type in the
822fe6060f1SDimitry Andric   // types[] array, if the value is KMP_HW_UNKNOWN, then there is no
823fe6060f1SDimitry Andric   // known equivalence for the topology type
824fe6060f1SDimitry Andric   kmp_hw_t equivalent[KMP_HW_LAST];
825fe6060f1SDimitry Andric 
826fe6060f1SDimitry Andric   // Flags describing the topology
827fe6060f1SDimitry Andric   flags_t flags;
828fe6060f1SDimitry Andric 
829bdd1243dSDimitry Andric   // Compact value used during sort_compact()
830bdd1243dSDimitry Andric   int compact;
831bdd1243dSDimitry Andric 
832349cc55cSDimitry Andric   // Insert a new topology layer after allocation
833349cc55cSDimitry Andric   void _insert_layer(kmp_hw_t type, const int *ids);
834349cc55cSDimitry Andric 
835349cc55cSDimitry Andric #if KMP_GROUP_AFFINITY
836349cc55cSDimitry Andric   // Insert topology information about Windows Processor groups
837349cc55cSDimitry Andric   void _insert_windows_proc_groups();
838349cc55cSDimitry Andric #endif
839349cc55cSDimitry Andric 
840fe6060f1SDimitry Andric   // Count each item & get the num x's per y
841fe6060f1SDimitry Andric   // e.g., get the number of cores and the number of threads per core
842fe6060f1SDimitry Andric   // for each (x, y) in (KMP_HW_* , KMP_HW_*)
843fe6060f1SDimitry Andric   void _gather_enumeration_information();
844fe6060f1SDimitry Andric 
845fe6060f1SDimitry Andric   // Remove layers that don't add information to the topology.
846fe6060f1SDimitry Andric   // This is done by having the layer take on the id = UNKNOWN_ID (-1)
847fe6060f1SDimitry Andric   void _remove_radix1_layers();
848fe6060f1SDimitry Andric 
849fe6060f1SDimitry Andric   // Find out if the topology is uniform
850fe6060f1SDimitry Andric   void _discover_uniformity();
851fe6060f1SDimitry Andric 
852fe6060f1SDimitry Andric   // Set all the sub_ids for each hardware thread
853fe6060f1SDimitry Andric   void _set_sub_ids();
854fe6060f1SDimitry Andric 
855fe6060f1SDimitry Andric   // Set global affinity variables describing the number of threads per
856fe6060f1SDimitry Andric   // core, the number of packages, the number of cores per package, and
857fe6060f1SDimitry Andric   // the number of cores.
858fe6060f1SDimitry Andric   void _set_globals();
859fe6060f1SDimitry Andric 
860fe6060f1SDimitry Andric   // Set the last level cache equivalent type
861fe6060f1SDimitry Andric   void _set_last_level_cache();
862fe6060f1SDimitry Andric 
8630eae32dcSDimitry Andric   // Return the number of cores with a particular attribute, 'attr'.
8640eae32dcSDimitry Andric   // If 'find_all' is true, then find all cores on the machine, otherwise find
8650eae32dcSDimitry Andric   // all cores per the layer 'above'
8660eae32dcSDimitry Andric   int _get_ncores_with_attr(const kmp_hw_attr_t &attr, int above,
8670eae32dcSDimitry Andric                             bool find_all = false) const;
868349cc55cSDimitry Andric 
869fe6060f1SDimitry Andric public:
870fe6060f1SDimitry Andric   // Force use of allocate()/deallocate()
871fe6060f1SDimitry Andric   kmp_topology_t() = delete;
872fe6060f1SDimitry Andric   kmp_topology_t(const kmp_topology_t &t) = delete;
873fe6060f1SDimitry Andric   kmp_topology_t(kmp_topology_t &&t) = delete;
874fe6060f1SDimitry Andric   kmp_topology_t &operator=(const kmp_topology_t &t) = delete;
875fe6060f1SDimitry Andric   kmp_topology_t &operator=(kmp_topology_t &&t) = delete;
876fe6060f1SDimitry Andric 
877fe6060f1SDimitry Andric   static kmp_topology_t *allocate(int nproc, int ndepth, const kmp_hw_t *types);
878fe6060f1SDimitry Andric   static void deallocate(kmp_topology_t *);
879fe6060f1SDimitry Andric 
880fe6060f1SDimitry Andric   // Functions used in create_map() routines
881fe6060f1SDimitry Andric   kmp_hw_thread_t &at(int index) {
882fe6060f1SDimitry Andric     KMP_DEBUG_ASSERT(index >= 0 && index < num_hw_threads);
883fe6060f1SDimitry Andric     return hw_threads[index];
884fe6060f1SDimitry Andric   }
885fe6060f1SDimitry Andric   const kmp_hw_thread_t &at(int index) const {
886fe6060f1SDimitry Andric     KMP_DEBUG_ASSERT(index >= 0 && index < num_hw_threads);
887fe6060f1SDimitry Andric     return hw_threads[index];
888fe6060f1SDimitry Andric   }
889fe6060f1SDimitry Andric   int get_num_hw_threads() const { return num_hw_threads; }
890fe6060f1SDimitry Andric   void sort_ids() {
891fe6060f1SDimitry Andric     qsort(hw_threads, num_hw_threads, sizeof(kmp_hw_thread_t),
892fe6060f1SDimitry Andric           kmp_hw_thread_t::compare_ids);
893fe6060f1SDimitry Andric   }
894fe6060f1SDimitry Andric   // Check if the hardware ids are unique, if they are
895fe6060f1SDimitry Andric   // return true, otherwise return false
896fe6060f1SDimitry Andric   bool check_ids() const;
897fe6060f1SDimitry Andric 
898fe6060f1SDimitry Andric   // Function to call after the create_map() routine
899fe6060f1SDimitry Andric   void canonicalize();
900fe6060f1SDimitry Andric   void canonicalize(int pkgs, int cores_per_pkg, int thr_per_core, int cores);
901fe6060f1SDimitry Andric 
902fe6060f1SDimitry Andric // Functions used after canonicalize() called
903bdd1243dSDimitry Andric 
904bdd1243dSDimitry Andric #if KMP_AFFINITY_SUPPORTED
905bdd1243dSDimitry Andric   // Set the granularity for affinity settings
906bdd1243dSDimitry Andric   void set_granularity(kmp_affinity_t &stgs) const;
907*5f757f3fSDimitry Andric   bool is_close(int hwt1, int hwt2, const kmp_affinity_t &stgs) const;
908*5f757f3fSDimitry Andric   bool restrict_to_mask(const kmp_affin_mask_t *mask);
909fe6060f1SDimitry Andric   bool filter_hw_subset();
910*5f757f3fSDimitry Andric #endif
911fe6060f1SDimitry Andric   bool is_uniform() const { return flags.uniform; }
912fe6060f1SDimitry Andric   // Tell whether a type is a valid type in the topology
913fe6060f1SDimitry Andric   // returns KMP_HW_UNKNOWN when there is no equivalent type
914*5f757f3fSDimitry Andric   kmp_hw_t get_equivalent_type(kmp_hw_t type) const {
915*5f757f3fSDimitry Andric     if (type == KMP_HW_UNKNOWN)
916*5f757f3fSDimitry Andric       return KMP_HW_UNKNOWN;
917*5f757f3fSDimitry Andric     return equivalent[type];
918*5f757f3fSDimitry Andric   }
919fe6060f1SDimitry Andric   // Set type1 = type2
920fe6060f1SDimitry Andric   void set_equivalent_type(kmp_hw_t type1, kmp_hw_t type2) {
921fe6060f1SDimitry Andric     KMP_DEBUG_ASSERT_VALID_HW_TYPE(type1);
922fe6060f1SDimitry Andric     KMP_DEBUG_ASSERT_VALID_HW_TYPE(type2);
923fe6060f1SDimitry Andric     kmp_hw_t real_type2 = equivalent[type2];
924fe6060f1SDimitry Andric     if (real_type2 == KMP_HW_UNKNOWN)
925fe6060f1SDimitry Andric       real_type2 = type2;
926fe6060f1SDimitry Andric     equivalent[type1] = real_type2;
927fe6060f1SDimitry Andric     // This loop is required since any of the types may have been set to
928fe6060f1SDimitry Andric     // be equivalent to type1.  They all must be checked and reset to type2.
929fe6060f1SDimitry Andric     KMP_FOREACH_HW_TYPE(type) {
930fe6060f1SDimitry Andric       if (equivalent[type] == type1) {
931fe6060f1SDimitry Andric         equivalent[type] = real_type2;
932fe6060f1SDimitry Andric       }
933fe6060f1SDimitry Andric     }
934fe6060f1SDimitry Andric   }
935fe6060f1SDimitry Andric   // Calculate number of types corresponding to level1
936fe6060f1SDimitry Andric   // per types corresponding to level2 (e.g., number of threads per core)
937fe6060f1SDimitry Andric   int calculate_ratio(int level1, int level2) const {
938fe6060f1SDimitry Andric     KMP_DEBUG_ASSERT(level1 >= 0 && level1 < depth);
939fe6060f1SDimitry Andric     KMP_DEBUG_ASSERT(level2 >= 0 && level2 < depth);
940fe6060f1SDimitry Andric     int r = 1;
941fe6060f1SDimitry Andric     for (int level = level1; level > level2; --level)
942fe6060f1SDimitry Andric       r *= ratio[level];
943fe6060f1SDimitry Andric     return r;
944fe6060f1SDimitry Andric   }
945fe6060f1SDimitry Andric   int get_ratio(int level) const {
946fe6060f1SDimitry Andric     KMP_DEBUG_ASSERT(level >= 0 && level < depth);
947fe6060f1SDimitry Andric     return ratio[level];
948fe6060f1SDimitry Andric   }
949fe6060f1SDimitry Andric   int get_depth() const { return depth; };
950fe6060f1SDimitry Andric   kmp_hw_t get_type(int level) const {
951fe6060f1SDimitry Andric     KMP_DEBUG_ASSERT(level >= 0 && level < depth);
952fe6060f1SDimitry Andric     return types[level];
953fe6060f1SDimitry Andric   }
954fe6060f1SDimitry Andric   int get_level(kmp_hw_t type) const {
955fe6060f1SDimitry Andric     KMP_DEBUG_ASSERT_VALID_HW_TYPE(type);
956fe6060f1SDimitry Andric     int eq_type = equivalent[type];
957fe6060f1SDimitry Andric     if (eq_type == KMP_HW_UNKNOWN)
9580b57cec5SDimitry Andric       return -1;
959fe6060f1SDimitry Andric     for (int i = 0; i < depth; ++i)
960fe6060f1SDimitry Andric       if (types[i] == eq_type)
961fe6060f1SDimitry Andric         return i;
962fe6060f1SDimitry Andric     return -1;
9630b57cec5SDimitry Andric   }
964fe6060f1SDimitry Andric   int get_count(int level) const {
965fe6060f1SDimitry Andric     KMP_DEBUG_ASSERT(level >= 0 && level < depth);
966fe6060f1SDimitry Andric     return count[level];
9670b57cec5SDimitry Andric   }
9680eae32dcSDimitry Andric   // Return the total number of cores with attribute 'attr'
9690eae32dcSDimitry Andric   int get_ncores_with_attr(const kmp_hw_attr_t &attr) const {
9700eae32dcSDimitry Andric     return _get_ncores_with_attr(attr, -1, true);
9710eae32dcSDimitry Andric   }
9720eae32dcSDimitry Andric   // Return the number of cores with attribute
9730eae32dcSDimitry Andric   // 'attr' per topology level 'above'
9740eae32dcSDimitry Andric   int get_ncores_with_attr_per(const kmp_hw_attr_t &attr, int above) const {
9750eae32dcSDimitry Andric     return _get_ncores_with_attr(attr, above, false);
9760eae32dcSDimitry Andric   }
9770eae32dcSDimitry Andric 
978fe6060f1SDimitry Andric #if KMP_AFFINITY_SUPPORTED
979bdd1243dSDimitry Andric   friend int kmp_hw_thread_t::compare_compact(const void *a, const void *b);
980bdd1243dSDimitry Andric   void sort_compact(kmp_affinity_t &affinity) {
981bdd1243dSDimitry Andric     compact = affinity.compact;
982fe6060f1SDimitry Andric     qsort(hw_threads, num_hw_threads, sizeof(kmp_hw_thread_t),
983fe6060f1SDimitry Andric           kmp_hw_thread_t::compare_compact);
984fe6060f1SDimitry Andric   }
985fe6060f1SDimitry Andric #endif
986fe6060f1SDimitry Andric   void print(const char *env_var = "KMP_AFFINITY") const;
987fe6060f1SDimitry Andric   void dump() const;
988fe6060f1SDimitry Andric };
989349cc55cSDimitry Andric extern kmp_topology_t *__kmp_topology;
990fe6060f1SDimitry Andric 
991fe6060f1SDimitry Andric class kmp_hw_subset_t {
9920eae32dcSDimitry Andric   const static size_t MAX_ATTRS = KMP_HW_MAX_NUM_CORE_EFFS;
9930eae32dcSDimitry Andric 
994fe6060f1SDimitry Andric public:
9950eae32dcSDimitry Andric   // Describe a machine topology item in KMP_HW_SUBSET
996fe6060f1SDimitry Andric   struct item_t {
997fe6060f1SDimitry Andric     kmp_hw_t type;
9980eae32dcSDimitry Andric     int num_attrs;
9990eae32dcSDimitry Andric     int num[MAX_ATTRS];
10000eae32dcSDimitry Andric     int offset[MAX_ATTRS];
10010eae32dcSDimitry Andric     kmp_hw_attr_t attr[MAX_ATTRS];
1002fe6060f1SDimitry Andric   };
10030eae32dcSDimitry Andric   // Put parenthesis around max to avoid accidental use of Windows max macro.
10040eae32dcSDimitry Andric   const static int USE_ALL = (std::numeric_limits<int>::max)();
1005fe6060f1SDimitry Andric 
1006fe6060f1SDimitry Andric private:
1007fe6060f1SDimitry Andric   int depth;
1008fe6060f1SDimitry Andric   int capacity;
1009fe6060f1SDimitry Andric   item_t *items;
1010fe6060f1SDimitry Andric   kmp_uint64 set;
1011fe6060f1SDimitry Andric   bool absolute;
1012fe6060f1SDimitry Andric   // The set must be able to handle up to KMP_HW_LAST number of layers
1013fe6060f1SDimitry Andric   KMP_BUILD_ASSERT(sizeof(set) * 8 >= KMP_HW_LAST);
1014349cc55cSDimitry Andric   // Sorting the KMP_HW_SUBSET items to follow topology order
1015349cc55cSDimitry Andric   // All unknown topology types will be at the beginning of the subset
1016349cc55cSDimitry Andric   static int hw_subset_compare(const void *i1, const void *i2) {
1017349cc55cSDimitry Andric     kmp_hw_t type1 = ((const item_t *)i1)->type;
1018349cc55cSDimitry Andric     kmp_hw_t type2 = ((const item_t *)i2)->type;
1019349cc55cSDimitry Andric     int level1 = __kmp_topology->get_level(type1);
1020349cc55cSDimitry Andric     int level2 = __kmp_topology->get_level(type2);
1021349cc55cSDimitry Andric     return level1 - level2;
1022349cc55cSDimitry Andric   }
1023fe6060f1SDimitry Andric 
1024fe6060f1SDimitry Andric public:
1025fe6060f1SDimitry Andric   // Force use of allocate()/deallocate()
1026fe6060f1SDimitry Andric   kmp_hw_subset_t() = delete;
1027fe6060f1SDimitry Andric   kmp_hw_subset_t(const kmp_hw_subset_t &t) = delete;
1028fe6060f1SDimitry Andric   kmp_hw_subset_t(kmp_hw_subset_t &&t) = delete;
1029fe6060f1SDimitry Andric   kmp_hw_subset_t &operator=(const kmp_hw_subset_t &t) = delete;
1030fe6060f1SDimitry Andric   kmp_hw_subset_t &operator=(kmp_hw_subset_t &&t) = delete;
1031fe6060f1SDimitry Andric 
1032fe6060f1SDimitry Andric   static kmp_hw_subset_t *allocate() {
1033fe6060f1SDimitry Andric     int initial_capacity = 5;
1034fe6060f1SDimitry Andric     kmp_hw_subset_t *retval =
1035fe6060f1SDimitry Andric         (kmp_hw_subset_t *)__kmp_allocate(sizeof(kmp_hw_subset_t));
1036fe6060f1SDimitry Andric     retval->depth = 0;
1037fe6060f1SDimitry Andric     retval->capacity = initial_capacity;
1038fe6060f1SDimitry Andric     retval->set = 0ull;
1039fe6060f1SDimitry Andric     retval->absolute = false;
1040fe6060f1SDimitry Andric     retval->items = (item_t *)__kmp_allocate(sizeof(item_t) * initial_capacity);
1041fe6060f1SDimitry Andric     return retval;
1042fe6060f1SDimitry Andric   }
1043fe6060f1SDimitry Andric   static void deallocate(kmp_hw_subset_t *subset) {
1044fe6060f1SDimitry Andric     __kmp_free(subset->items);
1045fe6060f1SDimitry Andric     __kmp_free(subset);
1046fe6060f1SDimitry Andric   }
1047fe6060f1SDimitry Andric   void set_absolute() { absolute = true; }
1048fe6060f1SDimitry Andric   bool is_absolute() const { return absolute; }
10490eae32dcSDimitry Andric   void push_back(int num, kmp_hw_t type, int offset, kmp_hw_attr_t attr) {
10500eae32dcSDimitry Andric     for (int i = 0; i < depth; ++i) {
10510eae32dcSDimitry Andric       // Found an existing item for this layer type
10520eae32dcSDimitry Andric       // Add the num, offset, and attr to this item
10530eae32dcSDimitry Andric       if (items[i].type == type) {
10540eae32dcSDimitry Andric         int idx = items[i].num_attrs++;
10550eae32dcSDimitry Andric         if ((size_t)idx >= MAX_ATTRS)
10560eae32dcSDimitry Andric           return;
10570eae32dcSDimitry Andric         items[i].num[idx] = num;
10580eae32dcSDimitry Andric         items[i].offset[idx] = offset;
10590eae32dcSDimitry Andric         items[i].attr[idx] = attr;
10600eae32dcSDimitry Andric         return;
10610eae32dcSDimitry Andric       }
10620eae32dcSDimitry Andric     }
1063fe6060f1SDimitry Andric     if (depth == capacity - 1) {
1064fe6060f1SDimitry Andric       capacity *= 2;
1065fe6060f1SDimitry Andric       item_t *new_items = (item_t *)__kmp_allocate(sizeof(item_t) * capacity);
1066fe6060f1SDimitry Andric       for (int i = 0; i < depth; ++i)
1067fe6060f1SDimitry Andric         new_items[i] = items[i];
1068fe6060f1SDimitry Andric       __kmp_free(items);
1069fe6060f1SDimitry Andric       items = new_items;
1070fe6060f1SDimitry Andric     }
10710eae32dcSDimitry Andric     items[depth].num_attrs = 1;
1072fe6060f1SDimitry Andric     items[depth].type = type;
10730eae32dcSDimitry Andric     items[depth].num[0] = num;
10740eae32dcSDimitry Andric     items[depth].offset[0] = offset;
10750eae32dcSDimitry Andric     items[depth].attr[0] = attr;
1076fe6060f1SDimitry Andric     depth++;
1077fe6060f1SDimitry Andric     set |= (1ull << type);
1078fe6060f1SDimitry Andric   }
1079fe6060f1SDimitry Andric   int get_depth() const { return depth; }
1080fe6060f1SDimitry Andric   const item_t &at(int index) const {
1081fe6060f1SDimitry Andric     KMP_DEBUG_ASSERT(index >= 0 && index < depth);
1082fe6060f1SDimitry Andric     return items[index];
1083fe6060f1SDimitry Andric   }
1084fe6060f1SDimitry Andric   item_t &at(int index) {
1085fe6060f1SDimitry Andric     KMP_DEBUG_ASSERT(index >= 0 && index < depth);
1086fe6060f1SDimitry Andric     return items[index];
1087fe6060f1SDimitry Andric   }
1088fe6060f1SDimitry Andric   void remove(int index) {
1089fe6060f1SDimitry Andric     KMP_DEBUG_ASSERT(index >= 0 && index < depth);
1090fe6060f1SDimitry Andric     set &= ~(1ull << items[index].type);
1091fe6060f1SDimitry Andric     for (int j = index + 1; j < depth; ++j) {
1092fe6060f1SDimitry Andric       items[j - 1] = items[j];
1093fe6060f1SDimitry Andric     }
1094fe6060f1SDimitry Andric     depth--;
1095fe6060f1SDimitry Andric   }
1096349cc55cSDimitry Andric   void sort() {
1097349cc55cSDimitry Andric     KMP_DEBUG_ASSERT(__kmp_topology);
1098349cc55cSDimitry Andric     qsort(items, depth, sizeof(item_t), hw_subset_compare);
1099349cc55cSDimitry Andric   }
1100fe6060f1SDimitry Andric   bool specified(kmp_hw_t type) const { return ((set & (1ull << type)) > 0); }
1101fe6060f1SDimitry Andric   void dump() const {
1102fe6060f1SDimitry Andric     printf("**********************\n");
1103fe6060f1SDimitry Andric     printf("*** kmp_hw_subset: ***\n");
1104fe6060f1SDimitry Andric     printf("* depth: %d\n", depth);
1105fe6060f1SDimitry Andric     printf("* items:\n");
1106fe6060f1SDimitry Andric     for (int i = 0; i < depth; ++i) {
11070eae32dcSDimitry Andric       printf(" type: %s\n", __kmp_hw_get_keyword(items[i].type));
11080eae32dcSDimitry Andric       for (int j = 0; j < items[i].num_attrs; ++j) {
11090eae32dcSDimitry Andric         printf("  num: %d, offset: %d, attr: ", items[i].num[j],
11100eae32dcSDimitry Andric                items[i].offset[j]);
11110eae32dcSDimitry Andric         if (!items[i].attr[j]) {
11120eae32dcSDimitry Andric           printf(" (none)\n");
11130eae32dcSDimitry Andric         } else {
11140eae32dcSDimitry Andric           printf(
11150eae32dcSDimitry Andric               " core_type = %s, core_eff = %d\n",
11160eae32dcSDimitry Andric               __kmp_hw_get_core_type_string(items[i].attr[j].get_core_type()),
11170eae32dcSDimitry Andric               items[i].attr[j].get_core_eff());
11180eae32dcSDimitry Andric         }
11190eae32dcSDimitry Andric       }
1120fe6060f1SDimitry Andric     }
1121fe6060f1SDimitry Andric     printf("* set: 0x%llx\n", set);
1122fe6060f1SDimitry Andric     printf("* absolute: %d\n", absolute);
1123fe6060f1SDimitry Andric     printf("**********************\n");
1124fe6060f1SDimitry Andric   }
1125fe6060f1SDimitry Andric };
1126fe6060f1SDimitry Andric extern kmp_hw_subset_t *__kmp_hw_subset;
11270b57cec5SDimitry Andric 
11280b57cec5SDimitry Andric /* A structure for holding machine-specific hierarchy info to be computed once
11290b57cec5SDimitry Andric    at init. This structure represents a mapping of threads to the actual machine
11300b57cec5SDimitry Andric    hierarchy, or to our best guess at what the hierarchy might be, for the
11310b57cec5SDimitry Andric    purpose of performing an efficient barrier. In the worst case, when there is
11320b57cec5SDimitry Andric    no machine hierarchy information, it produces a tree suitable for a barrier,
11330b57cec5SDimitry Andric    similar to the tree used in the hyper barrier. */
11340b57cec5SDimitry Andric class hierarchy_info {
11350b57cec5SDimitry Andric public:
11360b57cec5SDimitry Andric   /* Good default values for number of leaves and branching factor, given no
11370b57cec5SDimitry Andric      affinity information. Behaves a bit like hyper barrier. */
11380b57cec5SDimitry Andric   static const kmp_uint32 maxLeaves = 4;
11390b57cec5SDimitry Andric   static const kmp_uint32 minBranch = 4;
11400b57cec5SDimitry Andric   /** Number of levels in the hierarchy. Typical levels are threads/core,
11410b57cec5SDimitry Andric       cores/package or socket, packages/node, nodes/machine, etc. We don't want
11420b57cec5SDimitry Andric       to get specific with nomenclature. When the machine is oversubscribed we
11430b57cec5SDimitry Andric       add levels to duplicate the hierarchy, doubling the thread capacity of the
11440b57cec5SDimitry Andric       hierarchy each time we add a level. */
11450b57cec5SDimitry Andric   kmp_uint32 maxLevels;
11460b57cec5SDimitry Andric 
11470b57cec5SDimitry Andric   /** This is specifically the depth of the machine configuration hierarchy, in
11480b57cec5SDimitry Andric       terms of the number of levels along the longest path from root to any
11490b57cec5SDimitry Andric       leaf. It corresponds to the number of entries in numPerLevel if we exclude
11500b57cec5SDimitry Andric       all but one trailing 1. */
11510b57cec5SDimitry Andric   kmp_uint32 depth;
11520b57cec5SDimitry Andric   kmp_uint32 base_num_threads;
11530b57cec5SDimitry Andric   enum init_status { initialized = 0, not_initialized = 1, initializing = 2 };
11540b57cec5SDimitry Andric   volatile kmp_int8 uninitialized; // 0=initialized, 1=not initialized,
11550b57cec5SDimitry Andric   // 2=initialization in progress
11560b57cec5SDimitry Andric   volatile kmp_int8 resizing; // 0=not resizing, 1=resizing
11570b57cec5SDimitry Andric 
11580b57cec5SDimitry Andric   /** Level 0 corresponds to leaves. numPerLevel[i] is the number of children
11590b57cec5SDimitry Andric       the parent of a node at level i has. For example, if we have a machine
11600b57cec5SDimitry Andric       with 4 packages, 4 cores/package and 2 HT per core, then numPerLevel =
11610b57cec5SDimitry Andric       {2, 4, 4, 1, 1}. All empty levels are set to 1. */
11620b57cec5SDimitry Andric   kmp_uint32 *numPerLevel;
11630b57cec5SDimitry Andric   kmp_uint32 *skipPerLevel;
11640b57cec5SDimitry Andric 
1165fe6060f1SDimitry Andric   void deriveLevels() {
1166fe6060f1SDimitry Andric     int hier_depth = __kmp_topology->get_depth();
1167fe6060f1SDimitry Andric     for (int i = hier_depth - 1, level = 0; i >= 0; --i, ++level) {
1168fe6060f1SDimitry Andric       numPerLevel[level] = __kmp_topology->get_ratio(i);
11690b57cec5SDimitry Andric     }
11700b57cec5SDimitry Andric   }
11710b57cec5SDimitry Andric 
11720b57cec5SDimitry Andric   hierarchy_info()
11730b57cec5SDimitry Andric       : maxLevels(7), depth(1), uninitialized(not_initialized), resizing(0) {}
11740b57cec5SDimitry Andric 
11750b57cec5SDimitry Andric   void fini() {
11760b57cec5SDimitry Andric     if (!uninitialized && numPerLevel) {
11770b57cec5SDimitry Andric       __kmp_free(numPerLevel);
11780b57cec5SDimitry Andric       numPerLevel = NULL;
11790b57cec5SDimitry Andric       uninitialized = not_initialized;
11800b57cec5SDimitry Andric     }
11810b57cec5SDimitry Andric   }
11820b57cec5SDimitry Andric 
1183fe6060f1SDimitry Andric   void init(int num_addrs) {
11840b57cec5SDimitry Andric     kmp_int8 bool_result = KMP_COMPARE_AND_STORE_ACQ8(
11850b57cec5SDimitry Andric         &uninitialized, not_initialized, initializing);
11860b57cec5SDimitry Andric     if (bool_result == 0) { // Wait for initialization
11870b57cec5SDimitry Andric       while (TCR_1(uninitialized) != initialized)
11880b57cec5SDimitry Andric         KMP_CPU_PAUSE();
11890b57cec5SDimitry Andric       return;
11900b57cec5SDimitry Andric     }
11910b57cec5SDimitry Andric     KMP_DEBUG_ASSERT(bool_result == 1);
11920b57cec5SDimitry Andric 
11930b57cec5SDimitry Andric     /* Added explicit initialization of the data fields here to prevent usage of
11940b57cec5SDimitry Andric        dirty value observed when static library is re-initialized multiple times
11950b57cec5SDimitry Andric        (e.g. when non-OpenMP thread repeatedly launches/joins thread that uses
11960b57cec5SDimitry Andric        OpenMP). */
11970b57cec5SDimitry Andric     depth = 1;
11980b57cec5SDimitry Andric     resizing = 0;
11990b57cec5SDimitry Andric     maxLevels = 7;
12000b57cec5SDimitry Andric     numPerLevel =
12010b57cec5SDimitry Andric         (kmp_uint32 *)__kmp_allocate(maxLevels * 2 * sizeof(kmp_uint32));
12020b57cec5SDimitry Andric     skipPerLevel = &(numPerLevel[maxLevels]);
12030b57cec5SDimitry Andric     for (kmp_uint32 i = 0; i < maxLevels;
12040b57cec5SDimitry Andric          ++i) { // init numPerLevel[*] to 1 item per level
12050b57cec5SDimitry Andric       numPerLevel[i] = 1;
12060b57cec5SDimitry Andric       skipPerLevel[i] = 1;
12070b57cec5SDimitry Andric     }
12080b57cec5SDimitry Andric 
12090b57cec5SDimitry Andric     // Sort table by physical ID
1210fe6060f1SDimitry Andric     if (__kmp_topology && __kmp_topology->get_depth() > 0) {
1211fe6060f1SDimitry Andric       deriveLevels();
12120b57cec5SDimitry Andric     } else {
12130b57cec5SDimitry Andric       numPerLevel[0] = maxLeaves;
12140b57cec5SDimitry Andric       numPerLevel[1] = num_addrs / maxLeaves;
12150b57cec5SDimitry Andric       if (num_addrs % maxLeaves)
12160b57cec5SDimitry Andric         numPerLevel[1]++;
12170b57cec5SDimitry Andric     }
12180b57cec5SDimitry Andric 
12190b57cec5SDimitry Andric     base_num_threads = num_addrs;
12200b57cec5SDimitry Andric     for (int i = maxLevels - 1; i >= 0;
12210b57cec5SDimitry Andric          --i) // count non-empty levels to get depth
12220b57cec5SDimitry Andric       if (numPerLevel[i] != 1 || depth > 1) // only count one top-level '1'
12230b57cec5SDimitry Andric         depth++;
12240b57cec5SDimitry Andric 
12250b57cec5SDimitry Andric     kmp_uint32 branch = minBranch;
12260b57cec5SDimitry Andric     if (numPerLevel[0] == 1)
12270b57cec5SDimitry Andric       branch = num_addrs / maxLeaves;
12280b57cec5SDimitry Andric     if (branch < minBranch)
12290b57cec5SDimitry Andric       branch = minBranch;
12300b57cec5SDimitry Andric     for (kmp_uint32 d = 0; d < depth - 1; ++d) { // optimize hierarchy width
12310b57cec5SDimitry Andric       while (numPerLevel[d] > branch ||
12320b57cec5SDimitry Andric              (d == 0 && numPerLevel[d] > maxLeaves)) { // max 4 on level 0!
12330b57cec5SDimitry Andric         if (numPerLevel[d] & 1)
12340b57cec5SDimitry Andric           numPerLevel[d]++;
12350b57cec5SDimitry Andric         numPerLevel[d] = numPerLevel[d] >> 1;
12360b57cec5SDimitry Andric         if (numPerLevel[d + 1] == 1)
12370b57cec5SDimitry Andric           depth++;
12380b57cec5SDimitry Andric         numPerLevel[d + 1] = numPerLevel[d + 1] << 1;
12390b57cec5SDimitry Andric       }
12400b57cec5SDimitry Andric       if (numPerLevel[0] == 1) {
12410b57cec5SDimitry Andric         branch = branch >> 1;
12420b57cec5SDimitry Andric         if (branch < 4)
12430b57cec5SDimitry Andric           branch = minBranch;
12440b57cec5SDimitry Andric       }
12450b57cec5SDimitry Andric     }
12460b57cec5SDimitry Andric 
12470b57cec5SDimitry Andric     for (kmp_uint32 i = 1; i < depth; ++i)
12480b57cec5SDimitry Andric       skipPerLevel[i] = numPerLevel[i - 1] * skipPerLevel[i - 1];
12490b57cec5SDimitry Andric     // Fill in hierarchy in the case of oversubscription
12500b57cec5SDimitry Andric     for (kmp_uint32 i = depth; i < maxLevels; ++i)
12510b57cec5SDimitry Andric       skipPerLevel[i] = 2 * skipPerLevel[i - 1];
12520b57cec5SDimitry Andric 
12530b57cec5SDimitry Andric     uninitialized = initialized; // One writer
12540b57cec5SDimitry Andric   }
12550b57cec5SDimitry Andric 
12560b57cec5SDimitry Andric   // Resize the hierarchy if nproc changes to something larger than before
12570b57cec5SDimitry Andric   void resize(kmp_uint32 nproc) {
12580b57cec5SDimitry Andric     kmp_int8 bool_result = KMP_COMPARE_AND_STORE_ACQ8(&resizing, 0, 1);
12590b57cec5SDimitry Andric     while (bool_result == 0) { // someone else is trying to resize
12600b57cec5SDimitry Andric       KMP_CPU_PAUSE();
12610b57cec5SDimitry Andric       if (nproc <= base_num_threads) // happy with other thread's resize
12620b57cec5SDimitry Andric         return;
12630b57cec5SDimitry Andric       else // try to resize
12640b57cec5SDimitry Andric         bool_result = KMP_COMPARE_AND_STORE_ACQ8(&resizing, 0, 1);
12650b57cec5SDimitry Andric     }
12660b57cec5SDimitry Andric     KMP_DEBUG_ASSERT(bool_result != 0);
12670b57cec5SDimitry Andric     if (nproc <= base_num_threads)
12680b57cec5SDimitry Andric       return; // happy with other thread's resize
12690b57cec5SDimitry Andric 
12700b57cec5SDimitry Andric     // Calculate new maxLevels
12710b57cec5SDimitry Andric     kmp_uint32 old_sz = skipPerLevel[depth - 1];
12720b57cec5SDimitry Andric     kmp_uint32 incs = 0, old_maxLevels = maxLevels;
12730b57cec5SDimitry Andric     // First see if old maxLevels is enough to contain new size
12740b57cec5SDimitry Andric     for (kmp_uint32 i = depth; i < maxLevels && nproc > old_sz; ++i) {
12750b57cec5SDimitry Andric       skipPerLevel[i] = 2 * skipPerLevel[i - 1];
12760b57cec5SDimitry Andric       numPerLevel[i - 1] *= 2;
12770b57cec5SDimitry Andric       old_sz *= 2;
12780b57cec5SDimitry Andric       depth++;
12790b57cec5SDimitry Andric     }
12800b57cec5SDimitry Andric     if (nproc > old_sz) { // Not enough space, need to expand hierarchy
12810b57cec5SDimitry Andric       while (nproc > old_sz) {
12820b57cec5SDimitry Andric         old_sz *= 2;
12830b57cec5SDimitry Andric         incs++;
12840b57cec5SDimitry Andric         depth++;
12850b57cec5SDimitry Andric       }
12860b57cec5SDimitry Andric       maxLevels += incs;
12870b57cec5SDimitry Andric 
12880b57cec5SDimitry Andric       // Resize arrays
12890b57cec5SDimitry Andric       kmp_uint32 *old_numPerLevel = numPerLevel;
12900b57cec5SDimitry Andric       kmp_uint32 *old_skipPerLevel = skipPerLevel;
12910b57cec5SDimitry Andric       numPerLevel = skipPerLevel = NULL;
12920b57cec5SDimitry Andric       numPerLevel =
12930b57cec5SDimitry Andric           (kmp_uint32 *)__kmp_allocate(maxLevels * 2 * sizeof(kmp_uint32));
12940b57cec5SDimitry Andric       skipPerLevel = &(numPerLevel[maxLevels]);
12950b57cec5SDimitry Andric 
12960b57cec5SDimitry Andric       // Copy old elements from old arrays
1297e8d8bef9SDimitry Andric       for (kmp_uint32 i = 0; i < old_maxLevels; ++i) {
1298e8d8bef9SDimitry Andric         // init numPerLevel[*] to 1 item per level
12990b57cec5SDimitry Andric         numPerLevel[i] = old_numPerLevel[i];
13000b57cec5SDimitry Andric         skipPerLevel[i] = old_skipPerLevel[i];
13010b57cec5SDimitry Andric       }
13020b57cec5SDimitry Andric 
13030b57cec5SDimitry Andric       // Init new elements in arrays to 1
1304e8d8bef9SDimitry Andric       for (kmp_uint32 i = old_maxLevels; i < maxLevels; ++i) {
1305e8d8bef9SDimitry Andric         // init numPerLevel[*] to 1 item per level
13060b57cec5SDimitry Andric         numPerLevel[i] = 1;
13070b57cec5SDimitry Andric         skipPerLevel[i] = 1;
13080b57cec5SDimitry Andric       }
13090b57cec5SDimitry Andric 
13100b57cec5SDimitry Andric       // Free old arrays
13110b57cec5SDimitry Andric       __kmp_free(old_numPerLevel);
13120b57cec5SDimitry Andric     }
13130b57cec5SDimitry Andric 
13140b57cec5SDimitry Andric     // Fill in oversubscription levels of hierarchy
13150b57cec5SDimitry Andric     for (kmp_uint32 i = old_maxLevels; i < maxLevels; ++i)
13160b57cec5SDimitry Andric       skipPerLevel[i] = 2 * skipPerLevel[i - 1];
13170b57cec5SDimitry Andric 
13180b57cec5SDimitry Andric     base_num_threads = nproc;
13190b57cec5SDimitry Andric     resizing = 0; // One writer
13200b57cec5SDimitry Andric   }
13210b57cec5SDimitry Andric };
13220b57cec5SDimitry Andric #endif // KMP_AFFINITY_H
1323