14 #include "kmp_affinity.h"
18 #include "kmp_wrapper_getpid.h"
19 #if KMP_USE_HIER_SCHED
20 #include "kmp_dispatch_hier.h"
24 #define HWLOC_GROUP_KIND_INTEL_MODULE 102
25 #define HWLOC_GROUP_KIND_INTEL_TILE 103
26 #define HWLOC_GROUP_KIND_INTEL_DIE 104
27 #define HWLOC_GROUP_KIND_WINDOWS_PROCESSOR_GROUP 220
31 kmp_topology_t *__kmp_topology =
nullptr;
33 kmp_hw_subset_t *__kmp_hw_subset =
nullptr;
36 static hierarchy_info machine_hierarchy;
38 void __kmp_cleanup_hierarchy() { machine_hierarchy.fini(); }
40 void __kmp_get_hierarchy(kmp_uint32 nproc, kmp_bstate_t *thr_bar) {
44 if (TCR_1(machine_hierarchy.uninitialized))
45 machine_hierarchy.init(nproc);
48 if (nproc > machine_hierarchy.base_num_threads)
49 machine_hierarchy.resize(nproc);
51 depth = machine_hierarchy.depth;
52 KMP_DEBUG_ASSERT(depth > 0);
54 thr_bar->depth = depth;
55 __kmp_type_convert(machine_hierarchy.numPerLevel[0] - 1,
56 &(thr_bar->base_leaf_kids));
57 thr_bar->skip_per_level = machine_hierarchy.skipPerLevel;
60 static int nCoresPerPkg, nPackages;
61 static int __kmp_nThreadsPerCore;
62 #ifndef KMP_DFLT_NTH_CORES
63 static int __kmp_ncores;
66 const char *__kmp_hw_get_catalog_string(kmp_hw_t type,
bool plural) {
69 return ((plural) ? KMP_I18N_STR(Sockets) : KMP_I18N_STR(Socket));
71 return ((plural) ? KMP_I18N_STR(Dice) : KMP_I18N_STR(Die));
73 return ((plural) ? KMP_I18N_STR(Modules) : KMP_I18N_STR(Module));
75 return ((plural) ? KMP_I18N_STR(Tiles) : KMP_I18N_STR(Tile));
77 return ((plural) ? KMP_I18N_STR(NumaDomains) : KMP_I18N_STR(NumaDomain));
79 return ((plural) ? KMP_I18N_STR(L3Caches) : KMP_I18N_STR(L3Cache));
81 return ((plural) ? KMP_I18N_STR(L2Caches) : KMP_I18N_STR(L2Cache));
83 return ((plural) ? KMP_I18N_STR(L1Caches) : KMP_I18N_STR(L1Cache));
85 return ((plural) ? KMP_I18N_STR(LLCaches) : KMP_I18N_STR(LLCache));
87 return ((plural) ? KMP_I18N_STR(Cores) : KMP_I18N_STR(Core));
89 return ((plural) ? KMP_I18N_STR(Threads) : KMP_I18N_STR(Thread));
90 case KMP_HW_PROC_GROUP:
91 return ((plural) ? KMP_I18N_STR(ProcGroups) : KMP_I18N_STR(ProcGroup));
93 return KMP_I18N_STR(Unknown);
96 const char *__kmp_hw_get_keyword(kmp_hw_t type,
bool plural) {
99 return ((plural) ?
"sockets" :
"socket");
101 return ((plural) ?
"dice" :
"die");
103 return ((plural) ?
"modules" :
"module");
105 return ((plural) ?
"tiles" :
"tile");
107 return ((plural) ?
"numa_domains" :
"numa_domain");
109 return ((plural) ?
"l3_caches" :
"l3_cache");
111 return ((plural) ?
"l2_caches" :
"l2_cache");
113 return ((plural) ?
"l1_caches" :
"l1_cache");
115 return ((plural) ?
"ll_caches" :
"ll_cache");
117 return ((plural) ?
"cores" :
"core");
119 return ((plural) ?
"threads" :
"thread");
120 case KMP_HW_PROC_GROUP:
121 return ((plural) ?
"proc_groups" :
"proc_group");
123 return ((plural) ?
"unknowns" :
"unknown");
128 int kmp_hw_thread_t::compare_ids(
const void *a,
const void *b) {
129 const kmp_hw_thread_t *ahwthread = (
const kmp_hw_thread_t *)a;
130 const kmp_hw_thread_t *bhwthread = (
const kmp_hw_thread_t *)b;
131 int depth = __kmp_topology->get_depth();
132 for (
int level = 0; level < depth; ++level) {
133 if (ahwthread->ids[level] < bhwthread->ids[level])
135 else if (ahwthread->ids[level] > bhwthread->ids[level])
138 if (ahwthread->os_id < bhwthread->os_id)
140 else if (ahwthread->os_id > bhwthread->os_id)
145 #if KMP_AFFINITY_SUPPORTED
146 int kmp_hw_thread_t::compare_compact(
const void *a,
const void *b) {
148 const kmp_hw_thread_t *aa = (
const kmp_hw_thread_t *)a;
149 const kmp_hw_thread_t *bb = (
const kmp_hw_thread_t *)b;
150 int depth = __kmp_topology->get_depth();
151 KMP_DEBUG_ASSERT(__kmp_affinity_compact >= 0);
152 KMP_DEBUG_ASSERT(__kmp_affinity_compact <= depth);
153 for (i = 0; i < __kmp_affinity_compact; i++) {
154 int j = depth - i - 1;
155 if (aa->sub_ids[j] < bb->sub_ids[j])
157 if (aa->sub_ids[j] > bb->sub_ids[j])
160 for (; i < depth; i++) {
161 int j = i - __kmp_affinity_compact;
162 if (aa->sub_ids[j] < bb->sub_ids[j])
164 if (aa->sub_ids[j] > bb->sub_ids[j])
171 void kmp_hw_thread_t::print()
const {
172 int depth = __kmp_topology->get_depth();
173 printf(
"%4d ", os_id);
174 for (
int i = 0; i < depth; ++i) {
175 printf(
"%4d ", ids[i]);
185 void kmp_topology_t::_remove_radix1_layers() {
186 int preference[KMP_HW_LAST];
187 int top_index1, top_index2;
189 preference[KMP_HW_PROC_GROUP] = 110;
190 preference[KMP_HW_SOCKET] = 100;
191 preference[KMP_HW_CORE] = 95;
192 preference[KMP_HW_THREAD] = 90;
193 preference[KMP_HW_NUMA] = 85;
194 preference[KMP_HW_DIE] = 80;
195 preference[KMP_HW_TILE] = 75;
196 preference[KMP_HW_MODULE] = 73;
197 preference[KMP_HW_L3] = 70;
198 preference[KMP_HW_L2] = 65;
199 preference[KMP_HW_L1] = 60;
200 preference[KMP_HW_LLC] = 5;
203 while (top_index1 < depth - 1 && top_index2 < depth) {
204 kmp_hw_t type1 = types[top_index1];
205 kmp_hw_t type2 = types[top_index2];
206 KMP_ASSERT_VALID_HW_TYPE(type1);
207 KMP_ASSERT_VALID_HW_TYPE(type2);
210 if ((type1 == KMP_HW_THREAD || type1 == KMP_HW_CORE ||
211 type1 == KMP_HW_SOCKET) &&
212 (type2 == KMP_HW_THREAD || type2 == KMP_HW_CORE ||
213 type2 == KMP_HW_SOCKET)) {
214 top_index1 = top_index2++;
218 bool all_same =
true;
219 int id1 = hw_threads[0].ids[top_index1];
220 int id2 = hw_threads[0].ids[top_index2];
221 int pref1 = preference[type1];
222 int pref2 = preference[type2];
223 for (
int hwidx = 1; hwidx < num_hw_threads; ++hwidx) {
224 if (hw_threads[hwidx].ids[top_index1] == id1 &&
225 hw_threads[hwidx].ids[top_index2] != id2) {
229 if (hw_threads[hwidx].ids[top_index2] != id2)
231 id1 = hw_threads[hwidx].ids[top_index1];
232 id2 = hw_threads[hwidx].ids[top_index2];
236 kmp_hw_t remove_type, keep_type;
237 int remove_layer, remove_layer_ids;
240 remove_layer = remove_layer_ids = top_index2;
244 remove_layer = remove_layer_ids = top_index1;
250 remove_layer_ids = top_index2;
253 set_equivalent_type(remove_type, keep_type);
254 for (
int idx = 0; idx < num_hw_threads; ++idx) {
255 kmp_hw_thread_t &hw_thread = hw_threads[idx];
256 for (
int d = remove_layer_ids; d < depth - 1; ++d)
257 hw_thread.ids[d] = hw_thread.ids[d + 1];
259 for (
int idx = remove_layer; idx < depth - 1; ++idx)
260 types[idx] = types[idx + 1];
263 top_index1 = top_index2++;
266 KMP_ASSERT(depth > 0);
269 void kmp_topology_t::_set_last_level_cache() {
270 if (get_equivalent_type(KMP_HW_L3) != KMP_HW_UNKNOWN)
271 set_equivalent_type(KMP_HW_LLC, KMP_HW_L3);
272 else if (get_equivalent_type(KMP_HW_L2) != KMP_HW_UNKNOWN)
273 set_equivalent_type(KMP_HW_LLC, KMP_HW_L2);
274 #if KMP_MIC_SUPPORTED
275 else if (__kmp_mic_type == mic3) {
276 if (get_equivalent_type(KMP_HW_L2) != KMP_HW_UNKNOWN)
277 set_equivalent_type(KMP_HW_LLC, KMP_HW_L2);
278 else if (get_equivalent_type(KMP_HW_TILE) != KMP_HW_UNKNOWN)
279 set_equivalent_type(KMP_HW_LLC, KMP_HW_TILE);
282 set_equivalent_type(KMP_HW_LLC, KMP_HW_L1);
285 else if (get_equivalent_type(KMP_HW_L1) != KMP_HW_UNKNOWN)
286 set_equivalent_type(KMP_HW_LLC, KMP_HW_L1);
288 if (get_equivalent_type(KMP_HW_LLC) == KMP_HW_UNKNOWN) {
289 if (get_equivalent_type(KMP_HW_SOCKET) != KMP_HW_UNKNOWN)
290 set_equivalent_type(KMP_HW_LLC, KMP_HW_SOCKET);
291 else if (get_equivalent_type(KMP_HW_CORE) != KMP_HW_UNKNOWN)
292 set_equivalent_type(KMP_HW_LLC, KMP_HW_CORE);
294 KMP_ASSERT(get_equivalent_type(KMP_HW_LLC) != KMP_HW_UNKNOWN);
298 void kmp_topology_t::_gather_enumeration_information() {
299 int previous_id[KMP_HW_LAST];
300 int max[KMP_HW_LAST];
302 for (
int i = 0; i < depth; ++i) {
303 previous_id[i] = kmp_hw_thread_t::UNKNOWN_ID;
308 for (
int i = 0; i < num_hw_threads; ++i) {
309 kmp_hw_thread_t &hw_thread = hw_threads[i];
310 for (
int layer = 0; layer < depth; ++layer) {
311 int id = hw_thread.ids[layer];
312 if (
id != previous_id[layer]) {
314 for (
int l = layer; l < depth; ++l)
318 for (
int l = layer + 1; l < depth; ++l) {
319 if (max[l] > ratio[l])
326 for (
int layer = 0; layer < depth; ++layer) {
327 previous_id[layer] = hw_thread.ids[layer];
330 for (
int layer = 0; layer < depth; ++layer) {
331 if (max[layer] > ratio[layer])
332 ratio[layer] = max[layer];
337 void kmp_topology_t::_discover_uniformity() {
339 for (
int level = 0; level < depth; ++level)
341 flags.uniform = (num == count[depth - 1]);
345 void kmp_topology_t::_set_sub_ids() {
346 int previous_id[KMP_HW_LAST];
347 int sub_id[KMP_HW_LAST];
349 for (
int i = 0; i < depth; ++i) {
353 for (
int i = 0; i < num_hw_threads; ++i) {
354 kmp_hw_thread_t &hw_thread = hw_threads[i];
356 for (
int j = 0; j < depth; ++j) {
357 if (hw_thread.ids[j] != previous_id[j]) {
359 for (
int k = j + 1; k < depth; ++k) {
366 for (
int j = 0; j < depth; ++j) {
367 previous_id[j] = hw_thread.ids[j];
370 for (
int j = 0; j < depth; ++j) {
371 hw_thread.sub_ids[j] = sub_id[j];
376 void kmp_topology_t::_set_globals() {
378 int core_level, thread_level, package_level;
379 package_level = get_level(KMP_HW_SOCKET);
380 #if KMP_GROUP_AFFINITY
381 if (package_level == -1)
382 package_level = get_level(KMP_HW_PROC_GROUP);
384 core_level = get_level(KMP_HW_CORE);
385 thread_level = get_level(KMP_HW_THREAD);
387 KMP_ASSERT(core_level != -1);
388 KMP_ASSERT(thread_level != -1);
390 __kmp_nThreadsPerCore = calculate_ratio(thread_level, core_level);
391 if (package_level != -1) {
392 nCoresPerPkg = calculate_ratio(core_level, package_level);
393 nPackages = get_count(package_level);
396 nCoresPerPkg = get_count(core_level);
399 #ifndef KMP_DFLT_NTH_CORES
400 __kmp_ncores = get_count(core_level);
404 kmp_topology_t *kmp_topology_t::allocate(
int nproc,
int ndepth,
405 const kmp_hw_t *types) {
406 kmp_topology_t *retval;
408 size_t size =
sizeof(kmp_topology_t) +
sizeof(kmp_hw_thread_t) * nproc +
409 sizeof(int) * ndepth * 3;
410 char *bytes = (
char *)__kmp_allocate(size);
411 retval = (kmp_topology_t *)bytes;
413 retval->hw_threads = (kmp_hw_thread_t *)(bytes +
sizeof(kmp_topology_t));
415 retval->hw_threads =
nullptr;
417 retval->num_hw_threads = nproc;
418 retval->depth = ndepth;
420 (
int *)(bytes +
sizeof(kmp_topology_t) +
sizeof(kmp_hw_thread_t) * nproc);
421 retval->types = (kmp_hw_t *)arr;
422 retval->ratio = arr + ndepth;
423 retval->count = arr + 2 * ndepth;
424 KMP_FOREACH_HW_TYPE(type) { retval->equivalent[type] = KMP_HW_UNKNOWN; }
425 for (
int i = 0; i < ndepth; ++i) {
426 retval->types[i] = types[i];
427 retval->equivalent[types[i]] = types[i];
432 void kmp_topology_t::deallocate(kmp_topology_t *topology) {
434 __kmp_free(topology);
437 bool kmp_topology_t::check_ids()
const {
439 if (num_hw_threads == 0)
441 for (
int i = 1; i < num_hw_threads; ++i) {
442 kmp_hw_thread_t ¤t_thread = hw_threads[i];
443 kmp_hw_thread_t &previous_thread = hw_threads[i - 1];
445 for (
int j = 0; j < depth; ++j) {
446 if (previous_thread.ids[j] != current_thread.ids[j]) {
458 void kmp_topology_t::dump()
const {
459 printf(
"***********************\n");
460 printf(
"*** __kmp_topology: ***\n");
461 printf(
"***********************\n");
462 printf(
"* depth: %d\n", depth);
465 for (
int i = 0; i < depth; ++i)
466 printf(
"%15s ", __kmp_hw_get_keyword(types[i]));
470 for (
int i = 0; i < depth; ++i) {
471 printf(
"%15d ", ratio[i]);
476 for (
int i = 0; i < depth; ++i) {
477 printf(
"%15d ", count[i]);
481 printf(
"* equivalent map:\n");
482 KMP_FOREACH_HW_TYPE(i) {
483 const char *key = __kmp_hw_get_keyword(i);
484 const char *value = __kmp_hw_get_keyword(equivalent[i]);
485 printf(
"%-15s -> %-15s\n", key, value);
488 printf(
"* uniform: %s\n", (is_uniform() ?
"Yes" :
"No"));
490 printf(
"* num_hw_threads: %d\n", num_hw_threads);
491 printf(
"* hw_threads:\n");
492 for (
int i = 0; i < num_hw_threads; ++i) {
493 hw_threads[i].print();
495 printf(
"***********************\n");
498 void kmp_topology_t::print(
const char *env_var)
const {
500 int print_types_depth;
501 __kmp_str_buf_init(&buf);
502 kmp_hw_t print_types[KMP_HW_LAST + 2];
505 KMP_INFORM(AvailableOSProc, env_var, num_hw_threads);
509 KMP_INFORM(Uniform, env_var);
511 KMP_INFORM(NonUniform, env_var);
515 KMP_FOREACH_HW_TYPE(type) {
516 kmp_hw_t eq_type = equivalent[type];
517 if (eq_type != KMP_HW_UNKNOWN && eq_type != type) {
518 KMP_INFORM(AffEqualTopologyTypes, env_var,
519 __kmp_hw_get_catalog_string(type),
520 __kmp_hw_get_catalog_string(eq_type));
525 KMP_ASSERT(depth > 0 && depth <= (
int)KMP_HW_LAST);
528 print_types_depth = 0;
529 for (
int level = 0; level < depth; ++level)
530 print_types[print_types_depth++] = types[level];
531 if (equivalent[KMP_HW_CORE] != KMP_HW_CORE) {
533 if (print_types[print_types_depth - 1] == KMP_HW_THREAD) {
536 print_types[print_types_depth - 1] = KMP_HW_CORE;
537 print_types[print_types_depth++] = KMP_HW_THREAD;
539 print_types[print_types_depth++] = KMP_HW_CORE;
543 if (equivalent[KMP_HW_THREAD] != KMP_HW_THREAD)
544 print_types[print_types_depth++] = KMP_HW_THREAD;
546 __kmp_str_buf_clear(&buf);
547 kmp_hw_t numerator_type;
548 kmp_hw_t denominator_type = KMP_HW_UNKNOWN;
549 int core_level = get_level(KMP_HW_CORE);
550 int ncores = get_count(core_level);
552 for (
int plevel = 0, level = 0; plevel < print_types_depth; ++plevel) {
555 numerator_type = print_types[plevel];
556 KMP_ASSERT_VALID_HW_TYPE(numerator_type);
557 if (equivalent[numerator_type] != numerator_type)
560 c = get_ratio(level++);
563 __kmp_str_buf_print(&buf,
"%d %s", c,
564 __kmp_hw_get_catalog_string(numerator_type, plural));
566 __kmp_str_buf_print(&buf,
" x %d %s/%s", c,
567 __kmp_hw_get_catalog_string(numerator_type, plural),
568 __kmp_hw_get_catalog_string(denominator_type));
570 denominator_type = numerator_type;
572 KMP_INFORM(TopologyGeneric, env_var, buf.str, ncores);
574 if (num_hw_threads <= 0) {
575 __kmp_str_buf_free(&buf);
580 KMP_INFORM(OSProcToPhysicalThreadMap, env_var);
581 for (
int i = 0; i < num_hw_threads; i++) {
582 __kmp_str_buf_clear(&buf);
583 for (
int level = 0; level < depth; ++level) {
584 kmp_hw_t type = types[level];
585 __kmp_str_buf_print(&buf,
"%s ", __kmp_hw_get_catalog_string(type));
586 __kmp_str_buf_print(&buf,
"%d ", hw_threads[i].ids[level]);
<