LLVM OpenMP* Runtime Library
Loading...
Searching...
No Matches
kmp_affinity.h
1/*
2 * kmp_affinity.h -- header for affinity management
3 */
4
5//===----------------------------------------------------------------------===//
6//
7// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
8// See https://llvm.org/LICENSE.txt for license information.
9// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef KMP_AFFINITY_H
14#define KMP_AFFINITY_H
15
16#include "kmp.h"
17#include "kmp_os.h"
18#include <limits>
19
20#if KMP_AFFINITY_SUPPORTED
21#if KMP_HWLOC_ENABLED
22class KMPHwlocAffinity : public KMPAffinity {
23public:
24 class Mask : public KMPAffinity::Mask {
25 hwloc_cpuset_t mask;
26
27 public:
28 Mask() {
29 mask = hwloc_bitmap_alloc();
30 this->zero();
31 }
32 Mask(const Mask &other) = delete;
33 Mask &operator=(const Mask &other) = delete;
34 ~Mask() { hwloc_bitmap_free(mask); }
35 void set(int i) override { hwloc_bitmap_set(mask, i); }
36 bool is_set(int i) const override { return hwloc_bitmap_isset(mask, i); }
37 void clear(int i) override { hwloc_bitmap_clr(mask, i); }
38 void zero() override { hwloc_bitmap_zero(mask); }
39 bool empty() const override { return hwloc_bitmap_iszero(mask); }
40 void copy(const KMPAffinity::Mask *src) override {
41 const Mask *convert = static_cast<const Mask *>(src);
42 hwloc_bitmap_copy(mask, convert->mask);
43 }
44 void bitwise_and(const KMPAffinity::Mask *rhs) override {
45 const Mask *convert = static_cast<const Mask *>(rhs);
46 hwloc_bitmap_and(mask, mask, convert->mask);
47 }
48 void bitwise_or(const KMPAffinity::Mask *rhs) override {
49 const Mask *convert = static_cast<const Mask *>(rhs);
50 hwloc_bitmap_or(mask, mask, convert->mask);
51 }
52 void bitwise_not() override { hwloc_bitmap_not(mask, mask); }
53 bool is_equal(const KMPAffinity::Mask *rhs) const override {
54 const Mask *convert = static_cast<const Mask *>(rhs);
55 return hwloc_bitmap_isequal(mask, convert->mask);
56 }
57 int begin() const override { return hwloc_bitmap_first(mask); }
58 int end() const override { return -1; }
59 int next(int previous) const override {
60 return hwloc_bitmap_next(mask, previous);
61 }
62 int get_system_affinity(bool abort_on_error) override {
63 KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
64 "Illegal get affinity operation when not capable");
65 long retval =
66 hwloc_get_cpubind(__kmp_hwloc_topology, mask, HWLOC_CPUBIND_THREAD);
67 if (retval >= 0) {
68 return 0;
69 }
70 int error = errno;
71 if (abort_on_error) {
72 __kmp_fatal(KMP_MSG(FunctionError, "hwloc_get_cpubind()"),
73 KMP_ERR(error), __kmp_msg_null);
74 }
75 return error;
76 }
77 int set_system_affinity(bool abort_on_error) const override {
78 KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
79 "Illegal set affinity operation when not capable");
80 long retval =
81 hwloc_set_cpubind(__kmp_hwloc_topology, mask, HWLOC_CPUBIND_THREAD);
82 if (retval >= 0) {
83 return 0;
84 }
85 int error = errno;
86 if (abort_on_error) {
87 __kmp_fatal(KMP_MSG(FunctionError, "hwloc_set_cpubind()"),
88 KMP_ERR(error), __kmp_msg_null);
89 }
90 return error;
91 }
92#if KMP_OS_WINDOWS
93 int set_process_affinity(bool abort_on_error) const override {
94 KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
95 "Illegal set process affinity operation when not capable");
96 int error = 0;
97 const hwloc_topology_support *support =
98 hwloc_topology_get_support(__kmp_hwloc_topology);
99 if (support->cpubind->set_proc_cpubind) {
100 int retval;
101 retval = hwloc_set_cpubind(__kmp_hwloc_topology, mask,
102 HWLOC_CPUBIND_PROCESS);
103 if (retval >= 0)
104 return 0;
105 error = errno;
106 if (abort_on_error)
107 __kmp_fatal(KMP_MSG(FunctionError, "hwloc_set_cpubind()"),
108 KMP_ERR(error), __kmp_msg_null);
109 }
110 return error;
111 }
112#endif // KMP_OS_WINDOWS
113 int get_proc_group() const override {
114 int group = -1;
115#if KMP_OS_WINDOWS
116 if (__kmp_num_proc_groups == 1) {
117 return 1;
118 }
119 for (int i = 0; i < __kmp_num_proc_groups; i++) {
120 // On windows, the long type is always 32 bits
121 unsigned long first_32_bits = hwloc_bitmap_to_ith_ulong(mask, i * 2);
122 unsigned long second_32_bits =
123 hwloc_bitmap_to_ith_ulong(mask, i * 2 + 1);
124 if (first_32_bits == 0 && second_32_bits == 0) {
125 continue;
126 }
127 if (group >= 0) {
128 return -1;
129 }
130 group = i;
131 }
132#endif /* KMP_OS_WINDOWS */
133 return group;
134 }
135 };
136 void determine_capable(const char *var) override {
137 const hwloc_topology_support *topology_support;
138 if (__kmp_hwloc_topology == NULL) {
139 if (hwloc_topology_init(&__kmp_hwloc_topology) < 0) {
140 __kmp_hwloc_error = TRUE;
141 if (__kmp_affinity.flags.verbose) {
142 KMP_WARNING(AffHwlocErrorOccurred, var, "hwloc_topology_init()");
143 }
144 }
145 if (hwloc_topology_load(__kmp_hwloc_topology) < 0) {
146 __kmp_hwloc_error = TRUE;
147 if (__kmp_affinity.flags.verbose) {
148 KMP_WARNING(AffHwlocErrorOccurred, var, "hwloc_topology_load()");
149 }
150 }
151 }
152 topology_support = hwloc_topology_get_support(__kmp_hwloc_topology);
153 // Is the system capable of setting/getting this thread's affinity?
154 // Also, is topology discovery possible? (pu indicates ability to discover
155 // processing units). And finally, were there no errors when calling any
156 // hwloc_* API functions?
157 if (topology_support && topology_support->cpubind->set_thisthread_cpubind &&
158 topology_support->cpubind->get_thisthread_cpubind &&
159 topology_support->discovery->pu && !__kmp_hwloc_error) {
160 // enables affinity according to KMP_AFFINITY_CAPABLE() macro
161 KMP_AFFINITY_ENABLE(TRUE);
162 } else {
163 // indicate that hwloc didn't work and disable affinity
164 __kmp_hwloc_error = TRUE;
165 KMP_AFFINITY_DISABLE();
166 }
167 }
168 void bind_thread(int which) override {
169 KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
170 "Illegal set affinity operation when not capable");
171 KMPAffinity::Mask *mask;
172 KMP_CPU_ALLOC_ON_STACK(mask);
173 KMP_CPU_ZERO(mask);
174 KMP_CPU_SET(which, mask);
175 __kmp_set_system_affinity(mask, TRUE);
176 KMP_CPU_FREE_FROM_STACK(mask);
177 }
178 KMPAffinity::Mask *allocate_mask() override { return new Mask(); }
179 void deallocate_mask(KMPAffinity::Mask *m) override { delete m; }
180 KMPAffinity::Mask *allocate_mask_array(int num) override {
181 return new Mask[num];
182 }
183 void deallocate_mask_array(KMPAffinity::Mask *array) override {
184 Mask *hwloc_array = static_cast<Mask *>(array);
185 delete[] hwloc_array;
186 }
187 KMPAffinity::Mask *index_mask_array(KMPAffinity::Mask *array,
188 int index) override {
189 Mask *hwloc_array = static_cast<Mask *>(array);
190 return &(hwloc_array[index]);
191 }
192 api_type get_api_type() const override { return HWLOC; }
193};
194#endif /* KMP_HWLOC_ENABLED */
195
196#if KMP_OS_LINUX || KMP_OS_FREEBSD || KMP_OS_NETBSD || KMP_OS_DRAGONFLY || \
197 KMP_OS_AIX
198#if KMP_OS_LINUX
199/* On some of the older OS's that we build on, these constants aren't present
200 in <asm/unistd.h> #included from <sys.syscall.h>. They must be the same on
201 all systems of the same arch where they are defined, and they cannot change.
202 stone forever. */
203#include <sys/syscall.h>
204#if KMP_ARCH_X86 || KMP_ARCH_ARM
205#ifndef __NR_sched_setaffinity
206#define __NR_sched_setaffinity 241
207#elif __NR_sched_setaffinity != 241
208#error Wrong code for setaffinity system call.
209#endif /* __NR_sched_setaffinity */
210#ifndef __NR_sched_getaffinity
211#define __NR_sched_getaffinity 242
212#elif __NR_sched_getaffinity != 242
213#error Wrong code for getaffinity system call.
214#endif /* __NR_sched_getaffinity */
215#elif KMP_ARCH_AARCH64
216#ifndef __NR_sched_setaffinity
217#define __NR_sched_setaffinity 122
218#elif __NR_sched_setaffinity != 122
219#error Wrong code for setaffinity system call.
220#endif /* __NR_sched_setaffinity */
221#ifndef __NR_sched_getaffinity
222#define __NR_sched_getaffinity 123
223#elif __NR_sched_getaffinity != 123
224#error Wrong code for getaffinity system call.
225#endif /* __NR_sched_getaffinity */
226#elif KMP_ARCH_RISCV64
227#ifndef __NR_sched_setaffinity
228#define __NR_sched_setaffinity 122
229#elif __NR_sched_setaffinity != 122
230#error Wrong code for setaffinity system call.
231#endif /* __NR_sched_setaffinity */
232#ifndef __NR_sched_getaffinity
233#define __NR_sched_getaffinity 123
234#elif __NR_sched_getaffinity != 123
235#error Wrong code for getaffinity system call.
236#endif /* __NR_sched_getaffinity */
237#elif KMP_ARCH_X86_64
238#ifndef __NR_sched_setaffinity
239#define __NR_sched_setaffinity 203
240#elif __NR_sched_setaffinity != 203
241#error Wrong code for setaffinity system call.
242#endif /* __NR_sched_setaffinity */
243#ifndef __NR_sched_getaffinity
244#define __NR_sched_getaffinity 204
245#elif __NR_sched_getaffinity != 204
246#error Wrong code for getaffinity system call.
247#endif /* __NR_sched_getaffinity */
248#elif KMP_ARCH_PPC64
249#ifndef __NR_sched_setaffinity
250#define __NR_sched_setaffinity 222
251#elif __NR_sched_setaffinity != 222
252#error Wrong code for setaffinity system call.
253#endif /* __NR_sched_setaffinity */
254#ifndef __NR_sched_getaffinity
255#define __NR_sched_getaffinity 223
256#elif __NR_sched_getaffinity != 223
257#error Wrong code for getaffinity system call.
258#endif /* __NR_sched_getaffinity */
259#elif KMP_ARCH_MIPS
260#ifndef __NR_sched_setaffinity
261#define __NR_sched_setaffinity 4239
262#elif __NR_sched_setaffinity != 4239
263#error Wrong code for setaffinity system call.
264#endif /* __NR_sched_setaffinity */
265#ifndef __NR_sched_getaffinity
266#define __NR_sched_getaffinity 4240
267#elif __NR_sched_getaffinity != 4240
268#error Wrong code for getaffinity system call.
269#endif /* __NR_sched_getaffinity */
270#elif KMP_ARCH_MIPS64
271#ifndef __NR_sched_setaffinity
272#define __NR_sched_setaffinity 5195
273#elif __NR_sched_setaffinity != 5195
274#error Wrong code for setaffinity system call.
275#endif /* __NR_sched_setaffinity */
276#ifndef __NR_sched_getaffinity
277#define __NR_sched_getaffinity 5196
278#elif __NR_sched_getaffinity != 5196
279#error Wrong code for getaffinity system call.
280#endif /* __NR_sched_getaffinity */
281#elif KMP_ARCH_LOONGARCH64
282#ifndef __NR_sched_setaffinity
283#define __NR_sched_setaffinity 122
284#elif __NR_sched_setaffinity != 122
285#error Wrong code for setaffinity system call.
286#endif /* __NR_sched_setaffinity */
287#ifndef __NR_sched_getaffinity
288#define __NR_sched_getaffinity 123
289#elif __NR_sched_getaffinity != 123
290#error Wrong code for getaffinity system call.
291#endif /* __NR_sched_getaffinity */
292#elif KMP_ARCH_RISCV64
293#ifndef __NR_sched_setaffinity
294#define __NR_sched_setaffinity 122
295#elif __NR_sched_setaffinity != 122
296#error Wrong code for setaffinity system call.
297#endif /* __NR_sched_setaffinity */
298#ifndef __NR_sched_getaffinity
299#define __NR_sched_getaffinity 123
300#elif __NR_sched_getaffinity != 123
301#error Wrong code for getaffinity system call.
302#endif /* __NR_sched_getaffinity */
303#elif KMP_ARCH_VE
304#ifndef __NR_sched_setaffinity
305#define __NR_sched_setaffinity 203
306#elif __NR_sched_setaffinity != 203
307#error Wrong code for setaffinity system call.
308#endif /* __NR_sched_setaffinity */
309#ifndef __NR_sched_getaffinity
310#define __NR_sched_getaffinity 204
311#elif __NR_sched_getaffinity != 204
312#error Wrong code for getaffinity system call.
313#endif /* __NR_sched_getaffinity */
314#elif KMP_ARCH_S390X
315#ifndef __NR_sched_setaffinity
316#define __NR_sched_setaffinity 239
317#elif __NR_sched_setaffinity != 239
318#error Wrong code for setaffinity system call.
319#endif /* __NR_sched_setaffinity */
320#ifndef __NR_sched_getaffinity
321#define __NR_sched_getaffinity 240
322#elif __NR_sched_getaffinity != 240
323#error Wrong code for getaffinity system call.
324#endif /* __NR_sched_getaffinity */
325#elif KMP_ARCH_SPARC
326#ifndef __NR_sched_setaffinity
327#define __NR_sched_setaffinity 261
328#elif __NR_sched_setaffinity != 261
329#error Wrong code for setaffinity system call.
330#endif /* __NR_sched_setaffinity */
331#ifndef __NR_sched_getaffinity
332#define __NR_sched_getaffinity 260
333#elif __NR_sched_getaffinity != 260
334#error Wrong code for getaffinity system call.
335#endif /* __NR_sched_getaffinity */
336#else
337#error Unknown or unsupported architecture
338#endif /* KMP_ARCH_* */
339#elif KMP_OS_FREEBSD || KMP_OS_DRAGONFLY
340#include <pthread.h>
341#include <pthread_np.h>
342#elif KMP_OS_NETBSD
343#include <pthread.h>
344#include <sched.h>
345#elif KMP_OS_AIX
346#include <sys/dr.h>
347#include <sys/rset.h>
348#define VMI_MAXRADS 64 // Maximum number of RADs allowed by AIX.
349#define GET_NUMBER_SMT_SETS 0x0004
350extern "C" int syssmt(int flags, int, int, int *);
351#endif
352class KMPNativeAffinity : public KMPAffinity {
353 class Mask : public KMPAffinity::Mask {
354 typedef unsigned long mask_t;
355 typedef decltype(__kmp_affin_mask_size) mask_size_type;
356 static const unsigned int BITS_PER_MASK_T = sizeof(mask_t) * CHAR_BIT;
357 static const mask_t ONE = 1;
358 mask_size_type get_num_mask_types() const {
359 return __kmp_affin_mask_size / sizeof(mask_t);
360 }
361
362 public:
363 mask_t *mask;
364 Mask()
365 : mask(__kmp_affin_mask_size == 0
366 ? nullptr
367 : (mask_t *)__kmp_allocate(__kmp_affin_mask_size)) {}
368 ~Mask() {
369 if (mask)
370 __kmp_free(mask);
371 }
372 void set(int i) override {
373 mask[i / BITS_PER_MASK_T] |= (ONE << (i % BITS_PER_MASK_T));
374 }
375 bool is_set(int i) const override {
376 return (mask[i / BITS_PER_MASK_T] & (ONE << (i % BITS_PER_MASK_T)));
377 }
378 void clear(int i) override {
379 mask[i / BITS_PER_MASK_T] &= ~(ONE << (i % BITS_PER_MASK_T));
380 }
381 void zero() override {
382 mask_size_type e = get_num_mask_types();
383 for (mask_size_type i = 0; i < e; ++i)
384 mask[i] = (mask_t)0;
385 }
386 bool empty() const override {
387 mask_size_type e = get_num_mask_types();
388 for (mask_size_type i = 0; i < e; ++i)
389 if (mask[i] != (mask_t)0)
390 return false;
391 return true;
392 }
393 void copy(const KMPAffinity::Mask *src) override {
394 const Mask *convert = static_cast<const Mask *>(src);
395 mask_size_type e = get_num_mask_types();
396 for (mask_size_type i = 0; i < e; ++i)
397 mask[i] = convert->mask[i];
398 }
399 void bitwise_and(const KMPAffinity::Mask *rhs) override {
400 const Mask *convert = static_cast<const Mask *>(rhs);
401 mask_size_type e = get_num_mask_types();
402 for (mask_size_type i = 0; i < e; ++i)
403 mask[i] &= convert->mask[i];
404 }
405 void bitwise_or(const KMPAffinity::Mask *rhs) override {
406 const Mask *convert = static_cast<const Mask *>(rhs);
407 mask_size_type e = get_num_mask_types();
408 for (mask_size_type i = 0; i < e; ++i)
409 mask[i] |= convert->mask[i];
410 }
411 void bitwise_not() override {
412 mask_size_type e = get_num_mask_types();
413 for (mask_size_type i = 0; i < e; ++i)
414 mask[i] = ~(mask[i]);
415 }
416 bool is_equal(const KMPAffinity::Mask *rhs) const override {
417 const Mask *convert = static_cast<const Mask *>(rhs);
418 mask_size_type e = get_num_mask_types();
419 for (mask_size_type i = 0; i < e; ++i)
420 if (mask[i] != convert->mask[i])
421 return false;
422 return true;
423 }
424 int begin() const override {
425 int retval = 0;
426 while (retval < end() && !is_set(retval))
427 ++retval;
428 return retval;
429 }
430 int end() const override {
431 int e;
432 __kmp_type_convert(get_num_mask_types() * BITS_PER_MASK_T, &e);
433 return e;
434 }
435 int next(int previous) const override {
436 int retval = previous + 1;
437 while (retval < end() && !is_set(retval))
438 ++retval;
439 return retval;
440 }
441#if KMP_OS_AIX
442 // On AIX, we don't have a way to get CPU(s) a thread is bound to.
443 // This routine is only used to get the full mask.
444 int get_system_affinity(bool abort_on_error) override {
445 KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
446 "Illegal get affinity operation when not capable");
447
448 (void)abort_on_error;
449
450 // Set the mask with all CPUs that are available.
451 for (int i = 0; i < __kmp_xproc; ++i)
452 KMP_CPU_SET(i, this);
453 return 0;
454 }
455 int set_system_affinity(bool abort_on_error) const override {
456 KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
457
458 "Illegal set affinity operation when not capable");
459
460 int location;
461 int gtid = __kmp_entry_gtid();
462 int tid = thread_self();
463
464 // Unbind the thread if it was bound to any processors before so that
465 // we can bind the thread to CPUs specified by the mask not others.
466 int retval = bindprocessor(BINDTHREAD, tid, PROCESSOR_CLASS_ANY);
467
468 // On AIX, we can only bind to one instead of a set of CPUs with the
469 // bindprocessor() system call.
470 KMP_CPU_SET_ITERATE(location, this) {
471 if (KMP_CPU_ISSET(location, this)) {
472 retval = bindprocessor(BINDTHREAD, tid, location);
473 if (retval == -1 && errno == 1) {
474 rsid_t rsid;
475 rsethandle_t rsh;
476 // Put something in rsh to prevent compiler warning
477 // about uninitalized use
478 rsh = rs_alloc(RS_EMPTY);
479 rsid.at_pid = getpid();
480 if (RS_DEFAULT_RSET != ra_getrset(R_PROCESS, rsid, 0, rsh)) {
481 retval = ra_detachrset(R_PROCESS, rsid, 0);
482 retval = bindprocessor(BINDTHREAD, tid, location);
483 }
484 }
485 if (retval == 0) {
486 KA_TRACE(10, ("__kmp_set_system_affinity: Done binding "
487 "T#%d to cpu=%d.\n",
488 gtid, location));
489 continue;
490 }
491 int error = errno;
492 if (abort_on_error) {
493 __kmp_fatal(KMP_MSG(FunctionError, "bindprocessor()"),
494 KMP_ERR(error), __kmp_msg_null);
495 KA_TRACE(10, ("__kmp_set_system_affinity: Error binding "
496 "T#%d to cpu=%d, errno=%d.\n",
497 gtid, location, error));
498 return error;
499 }
500 }
501 }
502 return 0;
503 }
504#else // !KMP_OS_AIX
505 int get_system_affinity(bool abort_on_error) override {
506 KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
507 "Illegal get affinity operation when not capable");
508#if KMP_OS_LINUX
509 long retval =
510 syscall(__NR_sched_getaffinity, 0, __kmp_affin_mask_size, mask);
511#elif KMP_OS_FREEBSD || KMP_OS_NETBSD || KMP_OS_DRAGONFLY
512 int r = pthread_getaffinity_np(pthread_self(), __kmp_affin_mask_size,
513 reinterpret_cast<cpuset_t *>(mask));
514 int retval = (r == 0 ? 0 : -1);
515#endif
516 if (retval >= 0) {
517 return 0;
518 }
519 int error = errno;
520 if (abort_on_error) {
521 __kmp_fatal(KMP_MSG(FunctionError, "pthread_getaffinity_np()"),
522 KMP_ERR(error), __kmp_msg_null);
523 }
524 return error;
525 }
526 int set_system_affinity(bool abort_on_error) const override {
527 KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
528 "Illegal set affinity operation when not capable");
529#if KMP_OS_LINUX
530 long retval =
531 syscall(__NR_sched_setaffinity, 0, __kmp_affin_mask_size, mask);
532#elif KMP_OS_FREEBSD || KMP_OS_NETBSD || KMP_OS_DRAGONFLY
533 int r = pthread_setaffinity_np(pthread_self(), __kmp_affin_mask_size,
534 reinterpret_cast<cpuset_t *>(mask));
535 int retval = (r == 0 ? 0 : -1);
536#endif
537 if (retval >= 0) {
538 return 0;
539 }
540 int error = errno;
541 if (abort_on_error) {
542 __kmp_fatal(KMP_MSG(FunctionError, "pthread_setaffinity_np()"),
543 KMP_ERR(error), __kmp_msg_null);
544 }
545 return error;
546 }
547#endif // KMP_OS_AIX
548 };
549 void determine_capable(const char *env_var) override {
550 __kmp_affinity_determine_capable(env_var);
551 }
552 void bind_thread(int which) override { __kmp_affinity_bind_thread(which); }
553 KMPAffinity::Mask *allocate_mask() override {
554 KMPNativeAffinity::Mask *retval = new Mask();
555 return retval;
556 }
557 void deallocate_mask(KMPAffinity::Mask *m) override {
558 KMPNativeAffinity::Mask *native_mask =
559 static_cast<KMPNativeAffinity::Mask *>(m);
560 delete native_mask;
561 }
562 KMPAffinity::Mask *allocate_mask_array(int num) override {
563 return new Mask[num];
564 }
565 void deallocate_mask_array(KMPAffinity::Mask *array) override {
566 Mask *linux_array = static_cast<Mask *>(array);
567 delete[] linux_array;
568 }
569 KMPAffinity::Mask *index_mask_array(KMPAffinity::Mask *array,
570 int index) override {
571 Mask *linux_array = static_cast<Mask *>(array);
572 return &(linux_array[index]);
573 }
574 api_type get_api_type() const override { return NATIVE_OS; }
575};
576#endif /* KMP_OS_LINUX || KMP_OS_FREEBSD || KMP_OS_NETBSD || KMP_OS_DRAGONFLY \
577 || KMP_OS_AIX */
578
579#if KMP_OS_WINDOWS
580class KMPNativeAffinity : public KMPAffinity {
581 class Mask : public KMPAffinity::Mask {
582 typedef ULONG_PTR mask_t;
583 static const int BITS_PER_MASK_T = sizeof(mask_t) * CHAR_BIT;
584 mask_t *mask;
585
586 public:
587 Mask() {
588 mask = (mask_t *)__kmp_allocate(sizeof(mask_t) * __kmp_num_proc_groups);
589 }
590 ~Mask() {
591 if (mask)
592 __kmp_free(mask);
593 }
594 void set(int i) override {
595 mask[i / BITS_PER_MASK_T] |= ((mask_t)1 << (i % BITS_PER_MASK_T));
596 }
597 bool is_set(int i) const override {
598 return (mask[i / BITS_PER_MASK_T] & ((mask_t)1 << (i % BITS_PER_MASK_T)));
599 }
600 void clear(int i) override {
601 mask[i / BITS_PER_MASK_T] &= ~((mask_t)1 << (i % BITS_PER_MASK_T));
602 }
603 void zero() override {
604 for (int i = 0; i < __kmp_num_proc_groups; ++i)
605 mask[i] = 0;
606 }
607 bool empty() const override {
608 for (size_t i = 0; i < __kmp_num_proc_groups; ++i)
609 if (mask[i])
610 return false;
611 return true;
612 }
613 void copy(const KMPAffinity::Mask *src) override {
614 const Mask *convert = static_cast<const Mask *>(src);
615 for (int i = 0; i < __kmp_num_proc_groups; ++i)
616 mask[i] = convert->mask[i];
617 }
618 void bitwise_and(const KMPAffinity::Mask *rhs) override {
619 const Mask *convert = static_cast<const Mask *>(rhs);
620 for (int i = 0; i < __kmp_num_proc_groups; ++i)
621 mask[i] &= convert->mask[i];
622 }
623 void bitwise_or(const KMPAffinity::Mask *rhs) override {
624 const Mask *convert = static_cast<const Mask *>(rhs);
625 for (int i = 0; i < __kmp_num_proc_groups; ++i)
626 mask[i] |= convert->mask[i];
627 }
628 void bitwise_not() override {
629 for (int i = 0; i < __kmp_num_proc_groups; ++i)
630 mask[i] = ~(mask[i]);
631 }
632 bool is_equal(const KMPAffinity::Mask *rhs) const override {
633 const Mask *convert = static_cast<const Mask *>(rhs);
634 for (size_t i = 0; i < __kmp_num_proc_groups; ++i)
635 if (mask[i] != convert->mask[i])
636 return false;
637 return true;
638 }
639 int begin() const override {
640 int retval = 0;
641 while (retval < end() && !is_set(retval))
642 ++retval;
643 return retval;
644 }
645 int end() const override { return __kmp_num_proc_groups * BITS_PER_MASK_T; }
646 int next(int previous) const override {
647 int retval = previous + 1;
648 while (retval < end() && !is_set(retval))
649 ++retval;
650 return retval;
651 }
652 int set_process_affinity(bool abort_on_error) const override {
653 if (__kmp_num_proc_groups <= 1) {
654 if (!SetProcessAffinityMask(GetCurrentProcess(), *mask)) {
655 DWORD error = GetLastError();
656 if (abort_on_error) {
657 __kmp_fatal(KMP_MSG(CantSetThreadAffMask), KMP_ERR(error),
658 __kmp_msg_null);
659 }
660 return error;
661 }
662 }
663 return 0;
664 }
665 int set_system_affinity(bool abort_on_error) const override {
666 if (__kmp_num_proc_groups > 1) {
667 // Check for a valid mask.
668 GROUP_AFFINITY ga;
669 int group = get_proc_group();
670 if (group < 0) {
671 if (abort_on_error) {
672 KMP_FATAL(AffinityInvalidMask, "kmp_set_affinity");
673 }
674 return -1;
675 }
676 // Transform the bit vector into a GROUP_AFFINITY struct
677 // and make the system call to set affinity.
678 ga.Group = group;
679 ga.Mask = mask[group];
680 ga.Reserved[0] = ga.Reserved[1] = ga.Reserved[2] = 0;
681
682 KMP_DEBUG_ASSERT(__kmp_SetThreadGroupAffinity != NULL);
683 if (__kmp_SetThreadGroupAffinity(GetCurrentThread(), &ga, NULL) == 0) {
684 DWORD error = GetLastError();
685 if (abort_on_error) {
686 __kmp_fatal(KMP_MSG(CantSetThreadAffMask), KMP_ERR(error),
687 __kmp_msg_null);
688 }
689 return error;
690 }
691 } else {
692 if (!SetThreadAffinityMask(GetCurrentThread(), *mask)) {
693 DWORD error = GetLastError();
694 if (abort_on_error) {
695 __kmp_fatal(KMP_MSG(CantSetThreadAffMask), KMP_ERR(error),
696 __kmp_msg_null);
697 }
698 return error;
699 }
700 }
701 return 0;
702 }
703 int get_system_affinity(bool abort_on_error) override {
704 if (__kmp_num_proc_groups > 1) {
705 this->zero();
706 GROUP_AFFINITY ga;
707 KMP_DEBUG_ASSERT(__kmp_GetThreadGroupAffinity != NULL);
708 if (__kmp_GetThreadGroupAffinity(GetCurrentThread(), &ga) == 0) {
709 DWORD error = GetLastError();
710 if (abort_on_error) {
711 __kmp_fatal(KMP_MSG(FunctionError, "GetThreadGroupAffinity()"),
712 KMP_ERR(error), __kmp_msg_null);
713 }
714 return error;
715 }
716 if ((ga.Group < 0) || (ga.Group > __kmp_num_proc_groups) ||
717 (ga.Mask == 0)) {
718 return -1;
719 }
720 mask[ga.Group] = ga.Mask;
721 } else {
722 mask_t newMask, sysMask, retval;
723 if (!GetProcessAffinityMask(GetCurrentProcess(), &newMask, &sysMask)) {
724 DWORD error = GetLastError();
725 if (abort_on_error) {
726 __kmp_fatal(KMP_MSG(FunctionError, "GetProcessAffinityMask()"),
727 KMP_ERR(error), __kmp_msg_null);
728 }
729 return error;
730 }
731 retval = SetThreadAffinityMask(GetCurrentThread(), newMask);
732 if (!retval) {
733 DWORD error = GetLastError();
734 if (abort_on_error) {
735 __kmp_fatal(KMP_MSG(FunctionError, "SetThreadAffinityMask()"),
736 KMP_ERR(error), __kmp_msg_null);
737 }
738 return error;
739 }
740 newMask = SetThreadAffinityMask(GetCurrentThread(), retval);
741 if (!newMask) {
742 DWORD error = GetLastError();
743 if (abort_on_error) {
744 __kmp_fatal(KMP_MSG(FunctionError, "SetThreadAffinityMask()"),
745 KMP_ERR(error), __kmp_msg_null);
746 }
747 }
748 *mask = retval;
749 }
750 return 0;
751 }
752 int get_proc_group() const override {
753 int group = -1;
754 if (__kmp_num_proc_groups == 1) {
755 return 1;
756 }
757 for (int i = 0; i < __kmp_num_proc_groups; i++) {
758 if (mask[i] == 0)
759 continue;
760 if (group >= 0)
761 return -1;
762 group = i;
763 }
764 return group;
765 }
766 };
767 void determine_capable(const char *env_var) override {
768 __kmp_affinity_determine_capable(env_var);
769 }
770 void bind_thread(int which) override { __kmp_affinity_bind_thread(which); }
771 KMPAffinity::Mask *allocate_mask() override { return new Mask(); }
772 void deallocate_mask(KMPAffinity::Mask *m) override { delete m; }
773 KMPAffinity::Mask *allocate_mask_array(int num) override {
774 return new Mask[num];
775 }
776 void deallocate_mask_array(KMPAffinity::Mask *array) override {
777 Mask *windows_array = static_cast<Mask *>(array);
778 delete[] windows_array;
779 }
780 KMPAffinity::Mask *index_mask_array(KMPAffinity::Mask *array,
781 int index) override {
782 Mask *windows_array = static_cast<Mask *>(array);
783 return &(windows_array[index]);
784 }
785 api_type get_api_type() const override { return NATIVE_OS; }
786};
787#endif /* KMP_OS_WINDOWS */
788#endif /* KMP_AFFINITY_SUPPORTED */
789
790// Describe an attribute for a level in the machine topology
791struct kmp_hw_attr_t {
792 int core_type : 8;
793 int core_eff : 8;
794 unsigned valid : 1;
795 unsigned reserved : 15;
796
797 static const int UNKNOWN_CORE_EFF = -1;
798
799 kmp_hw_attr_t()
800 : core_type(KMP_HW_CORE_TYPE_UNKNOWN), core_eff(UNKNOWN_CORE_EFF),
801 valid(0), reserved(0) {}
802 void set_core_type(kmp_hw_core_type_t type) {
803 valid = 1;
804 core_type = type;
805 }
806 void set_core_eff(int eff) {
807 valid = 1;
808 core_eff = eff;
809 }
810 kmp_hw_core_type_t get_core_type() const {
811 return (kmp_hw_core_type_t)core_type;
812 }
813 int get_core_eff() const { return core_eff; }
814 bool is_core_type_valid() const {
815 return core_type != KMP_HW_CORE_TYPE_UNKNOWN;
816 }
817 bool is_core_eff_valid() const { return core_eff != UNKNOWN_CORE_EFF; }
818 operator bool() const { return valid; }
819 void clear() {
820 core_type = KMP_HW_CORE_TYPE_UNKNOWN;
821 core_eff = UNKNOWN_CORE_EFF;
822 valid = 0;
823 }
824 bool contains(const kmp_hw_attr_t &other) const {
825 if (!valid && !other.valid)
826 return true;
827 if (valid && other.valid) {
828 if (other.is_core_type_valid()) {
829 if (!is_core_type_valid() || (get_core_type() != other.get_core_type()))
830 return false;
831 }
832 if (other.is_core_eff_valid()) {
833 if (!is_core_eff_valid() || (get_core_eff() != other.get_core_eff()))
834 return false;
835 }
836 return true;
837 }
838 return false;
839 }
840#if KMP_AFFINITY_SUPPORTED
841 bool contains(const kmp_affinity_attrs_t &attr) const {
842 if (!valid && !attr.valid)
843 return true;
844 if (valid && attr.valid) {
845 if (attr.core_type != KMP_HW_CORE_TYPE_UNKNOWN)
846 return (is_core_type_valid() &&
847 (get_core_type() == (kmp_hw_core_type_t)attr.core_type));
848 if (attr.core_eff != UNKNOWN_CORE_EFF)
849 return (is_core_eff_valid() && (get_core_eff() == attr.core_eff));
850 return true;
851 }
852 return false;
853 }
854#endif // KMP_AFFINITY_SUPPORTED
855 bool operator==(const kmp_hw_attr_t &rhs) const {
856 return (rhs.valid == valid && rhs.core_eff == core_eff &&
857 rhs.core_type == core_type);
858 }
859 bool operator!=(const kmp_hw_attr_t &rhs) const { return !operator==(rhs); }
860};
861
862#if KMP_AFFINITY_SUPPORTED
863KMP_BUILD_ASSERT(sizeof(kmp_hw_attr_t) == sizeof(kmp_affinity_attrs_t));
864#endif
865
866class kmp_hw_thread_t {
867public:
868 static const int UNKNOWN_ID = -1;
869 static const int MULTIPLE_ID = -2;
870 static int compare_ids(const void *a, const void *b);
871 static int compare_compact(const void *a, const void *b);
872 int ids[KMP_HW_LAST];
873 int sub_ids[KMP_HW_LAST];
874 bool leader;
875 int os_id;
876 int original_idx;
877 kmp_hw_attr_t attrs;
878
879 void print() const;
880 void clear() {
881 for (int i = 0; i < (int)KMP_HW_LAST; ++i)
882 ids[i] = UNKNOWN_ID;
883 leader = false;
884 attrs.clear();
885 }
886};
887
888class kmp_topology_t {
889
890 struct flags_t {
891 int uniform : 1;
892 int reserved : 31;
893 };
894
895 int depth;
896
897 // The following arrays are all 'depth' long and have been
898 // allocated to hold up to KMP_HW_LAST number of objects if
899 // needed so layers can be added without reallocation of any array
900
901 // Orderd array of the types in the topology
902 kmp_hw_t *types;
903
904 // Keep quick topology ratios, for non-uniform topologies,
905 // this ratio holds the max number of itemAs per itemB
906 // e.g., [ 4 packages | 6 cores / package | 2 threads / core ]
907 int *ratio;
908
909 // Storage containing the absolute number of each topology layer
910 int *count;
911
912 // The number of core efficiencies. This is only useful for hybrid
913 // topologies. Core efficiencies will range from 0 to num efficiencies - 1
914 int num_core_efficiencies;
915 int num_core_types;
916 kmp_hw_core_type_t core_types[KMP_HW_MAX_NUM_CORE_TYPES];
917
918 // The hardware threads array
919 // hw_threads is num_hw_threads long
920 // Each hw_thread's ids and sub_ids are depth deep
921 int num_hw_threads;
922 kmp_hw_thread_t *hw_threads;
923
924 // Equivalence hash where the key is the hardware topology item
925 // and the value is the equivalent hardware topology type in the
926 // types[] array, if the value is KMP_HW_UNKNOWN, then there is no
927 // known equivalence for the topology type
928 kmp_hw_t equivalent[KMP_HW_LAST];
929
930 // Flags describing the topology
931 flags_t flags;
932
933 // Compact value used during sort_compact()
934 int compact;
935
936#if KMP_GROUP_AFFINITY
937 // Insert topology information about Windows Processor groups
938 void _insert_windows_proc_groups();
939#endif
940
941 // Count each item & get the num x's per y
942 // e.g., get the number of cores and the number of threads per core
943 // for each (x, y) in (KMP_HW_* , KMP_HW_*)
944 void _gather_enumeration_information();
945
946 // Remove layers that don't add information to the topology.
947 // This is done by having the layer take on the id = UNKNOWN_ID (-1)
948 void _remove_radix1_layers();
949
950 // Find out if the topology is uniform
951 void _discover_uniformity();
952
953 // Set all the sub_ids for each hardware thread
954 void _set_sub_ids();
955
956 // Set global affinity variables describing the number of threads per
957 // core, the number of packages, the number of cores per package, and
958 // the number of cores.
959 void _set_globals();
960
961 // Set the last level cache equivalent type
962 void _set_last_level_cache();
963
964 // Return the number of cores with a particular attribute, 'attr'.
965 // If 'find_all' is true, then find all cores on the machine, otherwise find
966 // all cores per the layer 'above'
967 int _get_ncores_with_attr(const kmp_hw_attr_t &attr, int above,
968 bool find_all = false) const;
969
970public:
971 // Force use of allocate()/deallocate()
972 kmp_topology_t() = delete;
973 kmp_topology_t(const kmp_topology_t &t) = delete;
974 kmp_topology_t(kmp_topology_t &&t) = delete;
975 kmp_topology_t &operator=(const kmp_topology_t &t) = delete;
976 kmp_topology_t &operator=(kmp_topology_t &&t) = delete;
977
978 static kmp_topology_t *allocate(int nproc, int ndepth, const kmp_hw_t *types);
979 static void deallocate(kmp_topology_t *);
980
981 // Functions used in create_map() routines
982 kmp_hw_thread_t &at(int index) {
983 KMP_DEBUG_ASSERT(index >= 0 && index < num_hw_threads);
984 return hw_threads[index];
985 }
986 const kmp_hw_thread_t &at(int index) const {
987 KMP_DEBUG_ASSERT(index >= 0 && index < num_hw_threads);
988 return hw_threads[index];
989 }
990 int get_num_hw_threads() const { return num_hw_threads; }
991 void sort_ids() {
992 qsort(hw_threads, num_hw_threads, sizeof(kmp_hw_thread_t),
993 kmp_hw_thread_t::compare_ids);
994 }
995
996 // Insert a new topology layer after allocation
997 void insert_layer(kmp_hw_t type, const int *ids);
998
999 // Check if the hardware ids are unique, if they are
1000 // return true, otherwise return false
1001 bool check_ids() const;
1002
1003 // Function to call after the create_map() routine
1004 void canonicalize();
1005 void canonicalize(int pkgs, int cores_per_pkg, int thr_per_core, int cores);
1006
1007// Functions used after canonicalize() called
1008
1009#if KMP_AFFINITY_SUPPORTED
1010 // Set the granularity for affinity settings
1011 void set_granularity(kmp_affinity_t &stgs) const;
1012 bool is_close(int hwt1, int hwt2, const kmp_affinity_t &stgs) const;
1013 bool restrict_to_mask(const kmp_affin_mask_t *mask);
1014 bool filter_hw_subset();
1015#endif
1016 bool is_uniform() const { return flags.uniform; }
1017 // Tell whether a type is a valid type in the topology
1018 // returns KMP_HW_UNKNOWN when there is no equivalent type
1019 kmp_hw_t get_equivalent_type(kmp_hw_t type) const {
1020 if (type == KMP_HW_UNKNOWN)
1021 return KMP_HW_UNKNOWN;
1022 return equivalent[type];
1023 }
1024 // Set type1 = type2
1025 void set_equivalent_type(kmp_hw_t type1, kmp_hw_t type2) {
1026 KMP_DEBUG_ASSERT_VALID_HW_TYPE(type1);
1027 KMP_DEBUG_ASSERT_VALID_HW_TYPE(type2);
1028 kmp_hw_t real_type2 = equivalent[type2];
1029 if (real_type2 == KMP_HW_UNKNOWN)
1030 real_type2 = type2;
1031 equivalent[type1] = real_type2;
1032 // This loop is required since any of the types may have been set to
1033 // be equivalent to type1. They all must be checked and reset to type2.
1034 KMP_FOREACH_HW_TYPE(type) {
1035 if (equivalent[type] == type1) {
1036 equivalent[type] = real_type2;
1037 }
1038 }
1039 }
1040 // Calculate number of types corresponding to level1
1041 // per types corresponding to level2 (e.g., number of threads per core)
1042 int calculate_ratio(int level1, int level2) const {
1043 KMP_DEBUG_ASSERT(level1 >= 0 && level1 < depth);
1044 KMP_DEBUG_ASSERT(level2 >= 0 && level2 < depth);
1045 int r = 1;
1046 for (int level = level1; level > level2; --level)
1047 r *= ratio[level];
1048 return r;
1049 }
1050 int get_ratio(int level) const {
1051 KMP_DEBUG_ASSERT(level >= 0 && level < depth);
1052 return ratio[level];
1053 }
1054 int get_depth() const { return depth; };
1055 kmp_hw_t get_type(int level) const {
1056 KMP_DEBUG_ASSERT(level >= 0 && level < depth);
1057 return types[level];
1058 }
1059 int get_level(kmp_hw_t type) const {
1060 KMP_DEBUG_ASSERT_VALID_HW_TYPE(type);
1061 int eq_type = equivalent[type];
1062 if (eq_type == KMP_HW_UNKNOWN)
1063 return -1;
1064 for (int i = 0; i < depth; ++i)
1065 if (types[i] == eq_type)
1066 return i;
1067 return -1;
1068 }
1069 int get_count(int level) const {
1070 KMP_DEBUG_ASSERT(level >= 0 && level < depth);
1071 return count[level];
1072 }
1073 // Return the total number of cores with attribute 'attr'
1074 int get_ncores_with_attr(const kmp_hw_attr_t &attr) const {
1075 return _get_ncores_with_attr(attr, -1, true);
1076 }
1077 // Return the number of cores with attribute
1078 // 'attr' per topology level 'above'
1079 int get_ncores_with_attr_per(const kmp_hw_attr_t &attr, int above) const {
1080 return _get_ncores_with_attr(attr, above, false);
1081 }
1082
1083#if KMP_AFFINITY_SUPPORTED
1084 friend int kmp_hw_thread_t::compare_compact(const void *a, const void *b);
1085 void sort_compact(kmp_affinity_t &affinity) {
1086 compact = affinity.compact;
1087 qsort(hw_threads, num_hw_threads, sizeof(kmp_hw_thread_t),
1088 kmp_hw_thread_t::compare_compact);
1089 }
1090#endif
1091 void print(const char *env_var = "KMP_AFFINITY") const;
1092 void dump() const;
1093};
1094extern kmp_topology_t *__kmp_topology;
1095
1096class kmp_hw_subset_t {
1097 const static size_t MAX_ATTRS = KMP_HW_MAX_NUM_CORE_EFFS;
1098
1099public:
1100 // Describe a machine topology item in KMP_HW_SUBSET
1101 struct item_t {
1102 kmp_hw_t type;
1103 int num_attrs;
1104 int num[MAX_ATTRS];
1105 int offset[MAX_ATTRS];
1106 kmp_hw_attr_t attr[MAX_ATTRS];
1107 };
1108 // Put parenthesis around max to avoid accidental use of Windows max macro.
1109 const static int USE_ALL = (std::numeric_limits<int>::max)();
1110
1111private:
1112 int depth;
1113 int capacity;
1114 item_t *items;
1115 kmp_uint64 set;
1116 bool absolute;
1117 // The set must be able to handle up to KMP_HW_LAST number of layers
1118 KMP_BUILD_ASSERT(sizeof(set) * 8 >= KMP_HW_LAST);
1119 // Sorting the KMP_HW_SUBSET items to follow topology order
1120 // All unknown topology types will be at the beginning of the subset
1121 static int hw_subset_compare(const void *i1, const void *i2) {
1122 kmp_hw_t type1 = ((const item_t *)i1)->type;
1123 kmp_hw_t type2 = ((const item_t *)i2)->type;
1124 int level1 = __kmp_topology->get_level(type1);
1125 int level2 = __kmp_topology->get_level(type2);
1126 return level1 - level2;
1127 }
1128
1129public:
1130 // Force use of allocate()/deallocate()
1131 kmp_hw_subset_t() = delete;
1132 kmp_hw_subset_t(const kmp_hw_subset_t &t) = delete;
1133 kmp_hw_subset_t(kmp_hw_subset_t &&t) = delete;
1134 kmp_hw_subset_t &operator=(const kmp_hw_subset_t &t) = delete;
1135 kmp_hw_subset_t &operator=(kmp_hw_subset_t &&t) = delete;
1136
1137 static kmp_hw_subset_t *allocate() {
1138 int initial_capacity = 5;
1139 kmp_hw_subset_t *retval =
1140 (kmp_hw_subset_t *)__kmp_allocate(sizeof(kmp_hw_subset_t));
1141 retval->depth = 0;
1142 retval->capacity = initial_capacity;
1143 retval->set = 0ull;
1144 retval->absolute = false;
1145 retval->items = (item_t *)__kmp_allocate(sizeof(item_t) * initial_capacity);
1146 return retval;
1147 }
1148 static void deallocate(kmp_hw_subset_t *subset) {
1149 __kmp_free(subset->items);
1150 __kmp_free(subset);
1151 }
1152 void set_absolute() { absolute = true; }
1153 bool is_absolute() const { return absolute; }
1154 void push_back(int num, kmp_hw_t type, int offset, kmp_hw_attr_t attr) {
1155 for (int i = 0; i < depth; ++i) {
1156 // Found an existing item for this layer type
1157 // Add the num, offset, and attr to this item
1158 if (items[i].type == type) {
1159 int idx = items[i].num_attrs++;
1160 if ((size_t)idx >= MAX_ATTRS)
1161 return;
1162 items[i].num[idx] = num;
1163 items[i].offset[idx] = offset;
1164 items[i].attr[idx] = attr;
1165 return;
1166 }
1167 }
1168 if (depth == capacity - 1) {
1169 capacity *= 2;
1170 item_t *new_items = (item_t *)__kmp_allocate(sizeof(item_t) * capacity);
1171 for (int i = 0; i < depth; ++i)
1172 new_items[i] = items[i];
1173 __kmp_free(items);
1174 items = new_items;
1175 }
1176 items[depth].num_attrs = 1;
1177 items[depth].type = type;
1178 items[depth].num[0] = num;
1179 items[depth].offset[0] = offset;
1180 items[depth].attr[0] = attr;
1181 depth++;
1182 set |= (1ull << type);
1183 }
1184 int get_depth() const { return depth; }
1185 const item_t &at(int index) const {
1186 KMP_DEBUG_ASSERT(index >= 0 && index < depth);
1187 return items[index];
1188 }
1189 item_t &at(int index) {
1190 KMP_DEBUG_ASSERT(index >= 0 && index < depth);
1191 return items[index];
1192 }
1193 void remove(int index) {
1194 KMP_DEBUG_ASSERT(index >= 0 && index < depth);
1195 set &= ~(1ull << items[index].type);
1196 for (int j = index + 1; j < depth; ++j) {
1197 items[j - 1] = items[j];
1198 }
1199 depth--;
1200 }
1201 void sort() {
1202 KMP_DEBUG_ASSERT(__kmp_topology);
1203 qsort(items, depth, sizeof(item_t), hw_subset_compare);
1204 }
1205 bool specified(kmp_hw_t type) const { return ((set & (1ull << type)) > 0); }
1206
1207 // Canonicalize the KMP_HW_SUBSET value if it is not an absolute subset.
1208 // This means putting each of {sockets, cores, threads} in the topology if
1209 // they are not specified:
1210 // e.g., 1s,2c => 1s,2c,*t | 2c,1t => *s,2c,1t | 1t => *s,*c,1t | etc.
1211 // e.g., 3module => *s,3module,*c,*t
1212 // By doing this, the runtime assumes users who fiddle with KMP_HW_SUBSET
1213 // are expecting the traditional sockets/cores/threads topology. For newer
1214 // hardware, there can be intervening layers like dies/tiles/modules
1215 // (usually corresponding to a cache level). So when a user asks for
1216 // 1s,6c,2t and the topology is really 1s,2modules,4cores,2threads, the user
1217 // should get 12 hardware threads across 6 cores and effectively ignore the
1218 // module layer.
1219 void canonicalize(const kmp_topology_t *top) {
1220 // Layers to target for KMP_HW_SUBSET canonicalization
1221 kmp_hw_t targeted[] = {KMP_HW_SOCKET, KMP_HW_CORE, KMP_HW_THREAD};
1222
1223 // Do not target-layer-canonicalize absolute KMP_HW_SUBSETS
1224 if (is_absolute())
1225 return;
1226
1227 // Do not target-layer-canonicalize KMP_HW_SUBSETS when the
1228 // topology doesn't have these layers
1229 for (kmp_hw_t type : targeted)
1230 if (top->get_level(type) == KMP_HW_UNKNOWN)
1231 return;
1232
1233 // Put targeted layers in topology if they do not exist
1234 for (kmp_hw_t type : targeted) {
1235 bool found = false;
1236 for (int i = 0; i < get_depth(); ++i) {
1237 if (top->get_equivalent_type(items[i].type) == type) {
1238 found = true;
1239 break;
1240 }
1241 }
1242 if (!found) {
1243 push_back(USE_ALL, type, 0, kmp_hw_attr_t{});
1244 }
1245 }
1246 sort();
1247 // Set as an absolute topology that only targets the targeted layers
1248 set_absolute();
1249 }
1250 void dump() const {
1251 printf("**********************\n");
1252 printf("*** kmp_hw_subset: ***\n");
1253 printf("* depth: %d\n", depth);
1254 printf("* items:\n");
1255 for (int i = 0; i < depth; ++i) {
1256 printf(" type: %s\n", __kmp_hw_get_keyword(items[i].type));
1257 for (int j = 0; j < items[i].num_attrs; ++j) {
1258 printf(" num: %d, offset: %d, attr: ", items[i].num[j],
1259 items[i].offset[j]);
1260 if (!items[i].attr[j]) {
1261 printf(" (none)\n");
1262 } else {
1263 printf(
1264 " core_type = %s, core_eff = %d\n",
1265 __kmp_hw_get_core_type_string(items[i].attr[j].get_core_type()),
1266 items[i].attr[j].get_core_eff());
1267 }
1268 }
1269 }
1270 printf("* set: 0x%llx\n", set);
1271 printf("* absolute: %d\n", absolute);
1272 printf("**********************\n");
1273 }
1274};
1275extern kmp_hw_subset_t *__kmp_hw_subset;
1276
1277/* A structure for holding machine-specific hierarchy info to be computed once
1278 at init. This structure represents a mapping of threads to the actual machine
1279 hierarchy, or to our best guess at what the hierarchy might be, for the
1280 purpose of performing an efficient barrier. In the worst case, when there is
1281 no machine hierarchy information, it produces a tree suitable for a barrier,
1282 similar to the tree used in the hyper barrier. */
1283class hierarchy_info {
1284public:
1285 /* Good default values for number of leaves and branching factor, given no
1286 affinity information. Behaves a bit like hyper barrier. */
1287 static const kmp_uint32 maxLeaves = 4;
1288 static const kmp_uint32 minBranch = 4;
1294 kmp_uint32 maxLevels;
1295
1300 kmp_uint32 depth;
1301 kmp_uint32 base_num_threads = 0;
1302 enum init_status { initialized = 0, not_initialized = 1, initializing = 2 };
1303 volatile kmp_int8 uninitialized; // 0=initialized, 1=not initialized,
1304 // 2=initialization in progress
1305 volatile kmp_int8 resizing; // 0=not resizing, 1=resizing
1306
1311 kmp_uint32 *numPerLevel = nullptr;
1312 kmp_uint32 *skipPerLevel = nullptr;
1313
1314 void deriveLevels() {
1315 int hier_depth = __kmp_topology->get_depth();
1316 for (int i = hier_depth - 1, level = 0; i >= 0; --i, ++level) {
1317 numPerLevel[level] = __kmp_topology->get_ratio(i);
1318 }
1319 }
1320
1321 hierarchy_info()
1322 : maxLevels(7), depth(1), uninitialized(not_initialized), resizing(0) {}
1323
1324 void fini() {
1325 if (!uninitialized && numPerLevel) {
1326 __kmp_free(numPerLevel);
1327 numPerLevel = NULL;
1328 uninitialized = not_initialized;
1329 }
1330 }
1331
1332 void init(int num_addrs) {
1333 kmp_int8 bool_result = KMP_COMPARE_AND_STORE_ACQ8(
1334 &uninitialized, not_initialized, initializing);
1335 if (bool_result == 0) { // Wait for initialization
1336 while (TCR_1(uninitialized) != initialized)
1337 KMP_CPU_PAUSE();
1338 return;
1339 }
1340 KMP_DEBUG_ASSERT(bool_result == 1);
1341
1342 /* Added explicit initialization of the data fields here to prevent usage of
1343 dirty value observed when static library is re-initialized multiple times
1344 (e.g. when non-OpenMP thread repeatedly launches/joins thread that uses
1345 OpenMP). */
1346 depth = 1;
1347 resizing = 0;
1348 maxLevels = 7;
1349 numPerLevel =
1350 (kmp_uint32 *)__kmp_allocate(maxLevels * 2 * sizeof(kmp_uint32));
1351 skipPerLevel = &(numPerLevel[maxLevels]);
1352 for (kmp_uint32 i = 0; i < maxLevels;
1353 ++i) { // init numPerLevel[*] to 1 item per level
1354 numPerLevel[i] = 1;
1355 skipPerLevel[i] = 1;
1356 }
1357
1358 // Sort table by physical ID
1359 if (__kmp_topology && __kmp_topology->get_depth() > 0) {
1360 deriveLevels();
1361 } else {
1362 numPerLevel[0] = maxLeaves;
1363 numPerLevel[1] = num_addrs / maxLeaves;
1364 if (num_addrs % maxLeaves)
1365 numPerLevel[1]++;
1366 }
1367
1368 base_num_threads = num_addrs;
1369 for (int i = maxLevels - 1; i >= 0;
1370 --i) // count non-empty levels to get depth
1371 if (numPerLevel[i] != 1 || depth > 1) // only count one top-level '1'
1372 depth++;
1373
1374 kmp_uint32 branch = minBranch;
1375 if (numPerLevel[0] == 1)
1376 branch = num_addrs / maxLeaves;
1377 if (branch < minBranch)
1378 branch = minBranch;
1379 for (kmp_uint32 d = 0; d < depth - 1; ++d) { // optimize hierarchy width
1380 while (numPerLevel[d] > branch ||
1381 (d == 0 && numPerLevel[d] > maxLeaves)) { // max 4 on level 0!
1382 if (numPerLevel[d] & 1)
1383 numPerLevel[d]++;
1384 numPerLevel[d] = numPerLevel[d] >> 1;
1385 if (numPerLevel[d + 1] == 1)
1386 depth++;
1387 numPerLevel[d + 1] = numPerLevel[d + 1] << 1;
1388 }
1389 if (numPerLevel[0] == 1) {
1390 branch = branch >> 1;
1391 if (branch < 4)
1392 branch = minBranch;
1393 }
1394 }
1395
1396 for (kmp_uint32 i = 1; i < depth; ++i)
1397 skipPerLevel[i] = numPerLevel[i - 1] * skipPerLevel[i - 1];
1398 // Fill in hierarchy in the case of oversubscription
1399 for (kmp_uint32 i = depth; i < maxLevels; ++i)
1400 skipPerLevel[i] = 2 * skipPerLevel[i - 1];
1401
1402 uninitialized = initialized; // One writer
1403 }
1404
1405 // Resize the hierarchy if nproc changes to something larger than before
1406 void resize(kmp_uint32 nproc) {
1407 kmp_int8 bool_result = KMP_COMPARE_AND_STORE_ACQ8(&resizing, 0, 1);
1408 while (bool_result == 0) { // someone else is trying to resize
1409 KMP_CPU_PAUSE();
1410 if (nproc <= base_num_threads) // happy with other thread's resize
1411 return;
1412 else // try to resize
1413 bool_result = KMP_COMPARE_AND_STORE_ACQ8(&resizing, 0, 1);
1414 }
1415 KMP_DEBUG_ASSERT(bool_result != 0);
1416 if (nproc <= base_num_threads)
1417 return; // happy with other thread's resize
1418
1419 // Calculate new maxLevels
1420 kmp_uint32 old_sz = skipPerLevel[depth - 1];
1421 kmp_uint32 incs = 0, old_maxLevels = maxLevels;
1422 // First see if old maxLevels is enough to contain new size
1423 for (kmp_uint32 i = depth; i < maxLevels && nproc > old_sz; ++i) {
1424 skipPerLevel[i] = 2 * skipPerLevel[i - 1];
1425 numPerLevel[i - 1] *= 2;
1426 old_sz *= 2;
1427 depth++;
1428 }
1429 if (nproc > old_sz) { // Not enough space, need to expand hierarchy
1430 while (nproc > old_sz) {
1431 old_sz *= 2;
1432 incs++;
1433 depth++;
1434 }
1435 maxLevels += incs;
1436
1437 // Resize arrays
1438 kmp_uint32 *old_numPerLevel = numPerLevel;
1439 kmp_uint32 *old_skipPerLevel = skipPerLevel;
1440 numPerLevel = skipPerLevel = NULL;
1441 numPerLevel =
1442 (kmp_uint32 *)__kmp_allocate(maxLevels * 2 * sizeof(kmp_uint32));
1443 skipPerLevel = &(numPerLevel[maxLevels]);
1444
1445 // Copy old elements from old arrays
1446 for (kmp_uint32 i = 0; i < old_maxLevels; ++i) {
1447 // init numPerLevel[*] to 1 item per level
1448 numPerLevel[i] = old_numPerLevel[i];
1449 skipPerLevel[i] = old_skipPerLevel[i];
1450 }
1451
1452 // Init new elements in arrays to 1
1453 for (kmp_uint32 i = old_maxLevels; i < maxLevels; ++i) {
1454 // init numPerLevel[*] to 1 item per level
1455 numPerLevel[i] = 1;
1456 skipPerLevel[i] = 1;
1457 }
1458
1459 // Free old arrays
1460 __kmp_free(old_numPerLevel);
1461 }
1462
1463 // Fill in oversubscription levels of hierarchy
1464 for (kmp_uint32 i = old_maxLevels; i < maxLevels; ++i)
1465 skipPerLevel[i] = 2 * skipPerLevel[i - 1];
1466
1467 base_num_threads = nproc;
1468 resizing = 0; // One writer
1469 }
1470};
1471#endif // KMP_AFFINITY_H