LLVM OpenMP 19.0.0git
libomp_test_topology.h
Go to the documentation of this file.
1#ifndef LIBOMP_TEST_TOPOLOGY_H
2#define LIBOMP_TEST_TOPOLOGY_H
3
5#include <stdio.h>
6#include <stdlib.h>
7#include <dirent.h>
8#include <errno.h>
9#include <ctype.h>
10#include <omp.h>
11#include <stdarg.h>
12
13typedef enum topology_obj_type_t {
19
20typedef struct place_list_t {
26
27// Return the first character in file 'f' that is not a whitespace character
28// including newlines and carriage returns
30 int c;
31 do {
32 c = fgetc(f);
33 } while (c != EOF && (isspace(c) || c == '\n' || c == '\r'));
34 return c;
35}
36
37// Read an integer from file 'f' into 'number'
38// Return 1 on successful read of integer,
39// 0 on unsuccessful read of integer,
40// EOF on end of file.
41static int get_integer_from_file(FILE *f, int *number) {
42 int n;
43 n = fscanf(f, "%d", number);
44 if (feof(f))
45 return EOF;
46 if (n != 1)
47 return 0;
48 return 1;
49}
50
51// Read a siblings list file from Linux /sys/devices/system/cpu/cpu?/topology/*
52static affinity_mask_t *topology_get_mask_from_file(const char *filename) {
53 int status = EXIT_SUCCESS;
54 FILE *f = fopen(filename, "r");
55 if (!f) {
56 perror(filename);
57 exit(EXIT_FAILURE);
58 }
60 while (1) {
61 int c, i, n, lower, upper;
62 // Read the first integer
63 n = get_integer_from_file(f, &lower);
64 if (n == EOF) {
65 break;
66 } else if (n == 0) {
67 fprintf(stderr, "syntax error: expected integer\n");
68 status = EXIT_FAILURE;
69 break;
70 }
71
72 // Now either a , or -
74 if (c == EOF || c == ',') {
75 affinity_mask_set(mask, lower);
76 if (c == EOF)
77 break;
78 } else if (c == '-') {
79 n = get_integer_from_file(f, &upper);
80 if (n == EOF || n == 0) {
81 fprintf(stderr, "syntax error: expected integer\n");
82 status = EXIT_FAILURE;
83 break;
84 }
85 for (i = lower; i <= upper; ++i)
88 if (c == EOF) {
89 break;
90 } else if (c == ',') {
91 continue;
92 } else {
93 fprintf(stderr, "syntax error: unexpected character: '%c (%d)'\n", c,
94 c);
95 status = EXIT_FAILURE;
96 break;
97 }
98 } else {
99 fprintf(stderr, "syntax error: unexpected character: '%c (%d)'\n", c, c);
100 status = EXIT_FAILURE;
101 break;
102 }
103 }
104 fclose(f);
105 if (status == EXIT_FAILURE) {
107 mask = NULL;
108 }
109 return mask;
110}
111
113 char buf[1024];
114 // Count the number of cpus
115 int cpu = 0;
116 while (1) {
117 snprintf(buf, sizeof(buf), "/sys/devices/system/cpu/cpu%d", cpu);
118 DIR *dir = opendir(buf);
119 if (dir) {
120 closedir(dir);
121 cpu++;
122 } else {
123 break;
124 }
125 }
126 if (cpu == 0)
127 cpu = 1;
128 return cpu;
129}
130
131// Return whether the current thread has access to all logical processors
133 int cpu;
134 int has_all = 1;
135 int num_cpus = topology_get_num_cpus();
138 for (cpu = 0; cpu < num_cpus; ++cpu) {
139 if (!affinity_mask_isset(mask, cpu)) {
140 has_all = 0;
141 break;
142 }
143 }
145 return has_all;
146}
147
148// Return array of masks representing OMP_PLACES keyword (e.g., sockets, cores,
149// threads)
151 char buf[1024];
152 int i, cpu, num_places, num_unique;
153 int *place_nums;
154 int num_cpus = topology_get_num_cpus();
155 place_list_t *places = (place_list_t *)malloc(sizeof(place_list_t));
156 affinity_mask_t **masks =
157 (affinity_mask_t **)malloc(sizeof(affinity_mask_t *) * num_cpus);
158 num_unique = 0;
159 for (cpu = 0; cpu < num_cpus; ++cpu) {
161 if (type == TOPOLOGY_OBJ_CORE) {
162 snprintf(buf, sizeof(buf),
163 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list",
164 cpu);
166 } else if (type == TOPOLOGY_OBJ_SOCKET) {
167 snprintf(buf, sizeof(buf),
168 "/sys/devices/system/cpu/cpu%d/topology/core_siblings_list",
169 cpu);
171 } else if (type == TOPOLOGY_OBJ_THREAD) {
174 } else {
175 fprintf(stderr, "Unknown topology type (%d)\n", (int)type);
176 exit(EXIT_FAILURE);
177 }
178 // Check for unique topology objects above the thread level
179 if (type != TOPOLOGY_OBJ_THREAD) {
180 for (i = 0; i < num_unique; ++i) {
181 if (affinity_mask_equal(masks[i], mask)) {
183 mask = NULL;
184 break;
185 }
186 }
187 }
188 if (mask)
189 masks[num_unique++] = mask;
190 }
191 place_nums = (int *)malloc(sizeof(int) * num_unique);
192 for (i = 0; i < num_unique; ++i)
193 place_nums[i] = i;
194 places->num_places = num_unique;
195 places->masks = masks;
196 places->place_nums = place_nums;
197 places->current_place = -1;
198 return places;
199}
200
202 int place, i;
203 int num_places = omp_get_num_places();
204 place_list_t *places = (place_list_t *)malloc(sizeof(place_list_t));
205 affinity_mask_t **masks =
206 (affinity_mask_t **)malloc(sizeof(affinity_mask_t *) * num_places);
207 int *place_nums = (int *)malloc(sizeof(int) * num_places);
208 for (place = 0; place < num_places; ++place) {
209 int num_procs = omp_get_place_num_procs(place);
210 int *ids = (int *)malloc(sizeof(int) * num_procs);
211 omp_get_place_proc_ids(place, ids);
213 for (i = 0; i < num_procs; ++i)
214 affinity_mask_set(mask, ids[i]);
215 masks[place] = mask;
216 place_nums[place] = place;
217 }
218 places->num_places = num_places;
219 places->place_nums = place_nums;
220 places->masks = masks;
221 places->current_place = omp_get_place_num();
222 return places;
223}
224
226 int p, i;
227 int num_places = omp_get_partition_num_places();
228 place_list_t *places = (place_list_t *)malloc(sizeof(place_list_t));
229 int *place_nums = (int *)malloc(sizeof(int) * num_places);
230 affinity_mask_t **masks =
231 (affinity_mask_t **)malloc(sizeof(affinity_mask_t *) * num_places);
232 omp_get_partition_place_nums(place_nums);
233 for (p = 0; p < num_places; ++p) {
234 int place = place_nums[p];
235 int num_procs = omp_get_place_num_procs(place);
236 int *ids = (int *)malloc(sizeof(int) * num_procs);
237 if (num_procs == 0) {
238 fprintf(stderr, "place %d has 0 procs?\n", place);
239 exit(EXIT_FAILURE);
240 }
241 omp_get_place_proc_ids(place, ids);
243 for (i = 0; i < num_procs; ++i)
244 affinity_mask_set(mask, ids[i]);
245 if (affinity_mask_count(mask) == 0) {
246 fprintf(stderr, "place %d has 0 procs set?\n", place);
247 exit(EXIT_FAILURE);
248 }
249 masks[p] = mask;
250 }
251 places->num_places = num_places;
252 places->place_nums = place_nums;
253 places->masks = masks;
254 places->current_place = omp_get_place_num();
255 return places;
256}
257
258// Free the array of masks from one of: topology_alloc_type_masks()
259// or topology_alloc_openmp_masks()
260static void topology_free_places(place_list_t *places) {
261 int i;
262 for (i = 0; i < places->num_places; ++i)
263 affinity_mask_free(places->masks[i]);
264 free(places->masks);
265 free(places->place_nums);
266 free(places);
267}
268
270 int i;
271 char buf[1024];
272 for (i = 0; i < p->num_places; ++i) {
273 affinity_mask_snprintf(buf, sizeof(buf), p->masks[i]);
274 printf("Place %d: %s\n", p->place_nums[i], buf);
275 }
276}
277
278// Print out an error message, possibly with two problem place lists,
279// and then exit with failure
280static void proc_bind_die(omp_proc_bind_t proc_bind, int T, int P,
281 const char *format, ...) {
282 va_list args;
283 va_start(args, format);
284 const char *pb;
285 switch (proc_bind) {
286 case omp_proc_bind_false:
287 pb = "False";
288 break;
289 case omp_proc_bind_true:
290 pb = "True";
291 break;
292 case omp_proc_bind_master:
293 pb = "Master (Primary)";
294 break;
295 case omp_proc_bind_close:
296 pb = "Close";
297 break;
298 case omp_proc_bind_spread:
299 pb = "Spread";
300 break;
301 default:
302 pb = "(Unknown Proc Bind Type)";
303 break;
304 }
305 if (proc_bind == omp_proc_bind_spread || proc_bind == omp_proc_bind_close) {
306 if (T <= P) {
307 fprintf(stderr, "%s : (T(%d) <= P(%d)) : ", pb, T, P);
308 } else {
309 fprintf(stderr, "%s : (T(%d) > P(%d)) : ", pb, T, P);
310 }
311 } else {
312 fprintf(stderr, "%s : T = %d, P = %d : ", pb, T, P);
313 }
314 vfprintf(stderr, format, args);
315 va_end(args);
316
317 exit(EXIT_FAILURE);
318}
319
320// Return 1 on failure, 0 on success.
321static void proc_bind_check(omp_proc_bind_t proc_bind,
322 const place_list_t *parent, place_list_t **children,
323 int nchildren) {
324 place_list_t *partition;
325 int T, i, j, place, low, high, first, last, count, current_place, num_places;
326 const int *place_nums;
327 int P = parent->num_places;
328
329 // Find the correct T (there could be null entries in children)
330 place_list_t **partitions =
331 (place_list_t **)malloc(sizeof(place_list_t *) * nchildren);
332 T = 0;
333 for (i = 0; i < nchildren; ++i)
334 if (children[i])
335 partitions[T++] = children[i];
336 // Only able to check spread, close, master (primary)
337 if (proc_bind != omp_proc_bind_spread && proc_bind != omp_proc_bind_close &&
338 proc_bind != omp_proc_bind_master)
339 proc_bind_die(proc_bind, T, P, NULL, NULL,
340 "Cannot check this proc bind type\n");
341
342 if (proc_bind == omp_proc_bind_spread) {
343 if (T <= P) {
344 // Run through each subpartition
345 for (i = 0; i < T; ++i) {
346 partition = partitions[i];
347 place_nums = partition->place_nums;
348 num_places = partition->num_places;
349 current_place = partition->current_place;
350 // Correct count?
351 low = P / T;
352 high = P / T + (P % T ? 1 : 0);
353 if (num_places != low && num_places != high) {
354 proc_bind_die(proc_bind, T, P,
355 "Incorrect number of places for thread %d: %d. "
356 "Expecting between %d and %d\n",
357 i, num_places, low, high);
358 }
359 // Consecutive places?
360 for (j = 1; j < num_places; ++j) {
361 if (place_nums[j] != (place_nums[j - 1] + 1) % P) {
362 proc_bind_die(proc_bind, T, P,
363 "Not consecutive places: %d, %d in partition\n",
364 place_nums[j - 1], place_nums[j]);
365 }
366 }
367 first = place_nums[0];
368 last = place_nums[num_places - 1];
369 // Primary thread executes on place of the parent thread?
370 if (i == 0) {
371 if (current_place != parent->current_place) {
373 proc_bind, T, P,
374 "Primary thread not on same place (%d) as parent thread (%d)\n",
375 current_place, parent->current_place);
376 }
377 } else {
378 // Thread's current place is first place within it's partition?
379 if (current_place != first) {
380 proc_bind_die(proc_bind, T, P,
381 "Thread's current place (%d) is not the first place "
382 "in its partition [%d, %d]\n",
383 current_place, first, last);
384 }
385 }
386 // Partitions don't have intersections?
387 int f1 = first;
388 int l1 = last;
389 for (j = 0; j < i; ++j) {
390 int f2 = partitions[j]->place_nums[0];
391 int l2 = partitions[j]->place_nums[partitions[j]->num_places - 1];
392 if (f1 > l1 && f2 > l2) {
393 proc_bind_die(proc_bind, T, P,
394 "partitions intersect. [%d, %d] and [%d, %d]\n", f1,
395 l1, f2, l2);
396 }
397 if (f1 > l1 && f2 <= l2)
398 if (f1 < l2 || l1 > f2) {
399 proc_bind_die(proc_bind, T, P,
400 "partitions intersect. [%d, %d] and [%d, %d]\n", f1,
401 l1, f2, l2);
402 }
403 if (f1 <= l1 && f2 > l2)
404 if (f2 < l1 || l2 > f1) {
405 proc_bind_die(proc_bind, T, P,
406 "partitions intersect. [%d, %d] and [%d, %d]\n", f1,
407 l1, f2, l2);
408 }
409 if (f1 <= l1 && f2 <= l2)
410 if (!(f2 > l1 || l2 < f1)) {
411 proc_bind_die(proc_bind, T, P,
412 "partitions intersect. [%d, %d] and [%d, %d]\n", f1,
413 l1, f2, l2);
414 }
415 }
416 }
417 } else {
418 // T > P
419 // Each partition has only one place?
420 for (i = 0; i < T; ++i) {
421 if (partitions[i]->num_places != 1) {
423 proc_bind, T, P,
424 "Incorrect number of places for thread %d: %d. Expecting 1\n", i,
425 partitions[i]->num_places);
426 }
427 }
428 // Correct number of consecutive threads per partition?
429 low = T / P;
430 high = T / P + (T % P ? 1 : 0);
431 for (i = 1, count = 1; i < T; ++i) {
432 if (partitions[i]->place_nums[0] == partitions[i - 1]->place_nums[0]) {
433 count++;
434 if (count > high) {
436 proc_bind, T, P,
437 "Too many threads have place %d for their partition\n",
438 partitions[i]->place_nums[0]);
439 }
440 } else {
441 if (count < low) {
443 proc_bind, T, P,
444 "Not enough threads have place %d for their partition\n",
445 partitions[i]->place_nums[0]);
446 }
447 count = 1;
448 }
449 }
450 // Primary thread executes on place of the parent thread?
451 current_place = partitions[0]->place_nums[0];
452 if (parent->current_place != -1 &&
453 current_place != parent->current_place) {
455 proc_bind, T, P,
456 "Primary thread not on same place (%d) as parent thread (%d)\n",
457 current_place, parent->current_place);
458 }
459 }
460 } else if (proc_bind == omp_proc_bind_close ||
461 proc_bind == omp_proc_bind_master) {
462 // Check that each subpartition is the same as the parent
463 for (i = 0; i < T; ++i) {
464 partition = partitions[i];
465 place_nums = partition->place_nums;
466 num_places = partition->num_places;
467 current_place = partition->current_place;
468 if (parent->num_places != num_places) {
469 proc_bind_die(proc_bind, T, P,
470 "Number of places in subpartition (%d) does not match "
471 "parent (%d)\n",
472 num_places, parent->num_places);
473 }
474 for (j = 0; j < num_places; ++j) {
475 if (parent->place_nums[j] != place_nums[j]) {
476 proc_bind_die(proc_bind, T, P,
477 "Subpartition place (%d) does not match "
478 "parent partition place (%d)\n",
479 place_nums[j], parent->place_nums[j]);
480 }
481 }
482 }
483 // Find index into place_nums of current place for parent
484 for (j = 0; j < parent->num_places; ++j)
485 if (parent->place_nums[j] == parent->current_place)
486 break;
487 if (proc_bind == omp_proc_bind_close) {
488 if (T <= P) {
489 // close T <= P
490 // check place assignment for each thread
491 for (i = 0; i < T; ++i) {
492 partition = partitions[i];
493 current_place = partition->current_place;
494 if (current_place != parent->place_nums[j]) {
496 proc_bind, T, P,
497 "Thread %d's current place (%d) is incorrect. expected %d\n", i,
498 current_place, parent->place_nums[j]);
499 }
500 j = (j + 1) % parent->num_places;
501 }
502 } else {
503 // close T > P
504 // check place assignment for each thread
505 low = T / P;
506 high = T / P + (T % P ? 1 : 0);
507 count = 1;
508 if (partitions[0]->current_place != parent->current_place) {
510 proc_bind, T, P,
511 "Primary thread's place (%d) is not parent thread's place (%d)\n",
512 partitions[0]->current_place, parent->current_place);
513 }
514 for (i = 1; i < T; ++i) {
515 current_place = partitions[i]->current_place;
516 if (current_place == parent->place_nums[j]) {
517 count++;
518 if (count > high) {
520 proc_bind, T, P,
521 "Too many threads have place %d for their current place\n",
522 current_place);
523 }
524 } else {
525 if (count < low) {
527 proc_bind, T, P,
528 "Not enough threads have place %d for their current place\n",
529 parent->place_nums[j]);
530 }
531 j = (j + 1) % parent->num_places;
532 if (current_place != parent->place_nums[j]) {
534 proc_bind, T, P,
535 "Thread %d's place (%d) is not corret. Expected %d\n", i,
536 partitions[i]->current_place, parent->place_nums[j]);
537 }
538 count = 1;
539 }
540 }
541 }
542 } else {
543 // proc_bind_primary
544 // Every thread should be assigned to the primary thread's place
545 for (i = 0; i < T; ++i) {
546 if (partitions[i]->current_place != parent->current_place) {
548 proc_bind, T, P,
549 "Thread %d's place (%d) is not the primary thread's place (%d)\n",
550 i, partitions[i]->current_place, parent->current_place);
551 }
552 }
553 }
554 }
555
556 // Check that each partition's current place is within the partition
557 for (i = 0; i < T; ++i) {
558 current_place = partitions[i]->current_place;
559 num_places = partitions[i]->num_places;
560 first = partitions[i]->place_nums[0];
561 last = partitions[i]->place_nums[num_places - 1];
562 for (j = 0; j < num_places; ++j)
563 if (partitions[i]->place_nums[j] == current_place)
564 break;
565 if (j == num_places) {
566 proc_bind_die(proc_bind, T, P,
567 "Thread %d's current place (%d) is not within its "
568 "partition [%d, %d]\n",
569 i, current_place, first, last);
570 }
571 }
572
573 free(partitions);
574}
575
576#endif
char buf[BUFFER_SIZE]
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int mask
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t count
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function void size_t int ITT_FORMAT d __itt_heap_function void ITT_FORMAT p __itt_heap_function void void size_t int ITT_FORMAT d no args no args unsigned int ITT_FORMAT u const __itt_domain __itt_id ITT_FORMAT lu const __itt_domain __itt_id __itt_id parent
void const char const char int ITT_FORMAT __itt_group_sync p
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function void size_t int ITT_FORMAT d __itt_heap_function void ITT_FORMAT p __itt_heap_function void void size_t int ITT_FORMAT d no args no args unsigned int ITT_FORMAT u const __itt_domain __itt_id ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain __itt_id ITT_FORMAT p const __itt_domain __itt_id __itt_timestamp __itt_timestamp ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain ITT_FORMAT p const __itt_domain __itt_string_handle unsigned long long ITT_FORMAT lu const __itt_domain __itt_string_handle unsigned long long ITT_FORMAT lu const __itt_domain __itt_id __itt_string_handle __itt_metadata_type type
static volatile kmp_i18n_cat_status_t status
Definition: kmp_i18n.cpp:48
#define args
#define i
Definition: kmp_stub.cpp:87
static int affinity_mask_isset(const affinity_mask_t *mask, int cpu)
static affinity_mask_t * affinity_mask_alloc()
static int affinity_mask_count(const affinity_mask_t *mask)
static int affinity_mask_equal(const affinity_mask_t *mask1, const affinity_mask_t *mask2)
static void affinity_mask_free(affinity_mask_t *mask)
static void affinity_mask_set(affinity_mask_t *mask, int cpu)
static size_t affinity_mask_snprintf(char *buf, size_t bufsize, const affinity_mask_t *mask)
static void get_thread_affinity(affinity_mask_t *mask)
static void topology_print_places(const place_list_t *p)
topology_obj_type_t
@ TOPOLOGY_OBJ_CORE
@ TOPOLOGY_OBJ_THREAD
@ TOPOLOGY_OBJ_MAX
@ TOPOLOGY_OBJ_SOCKET
static place_list_t * topology_alloc_openmp_places()
static place_list_t * topology_alloc_openmp_partition()
static place_list_t * topology_alloc_type_places(topology_obj_type_t type)
static void proc_bind_check(omp_proc_bind_t proc_bind, const place_list_t *parent, place_list_t **children, int nchildren)
static int topology_using_full_mask()
static void topology_free_places(place_list_t *places)
static int topology_get_num_cpus()
static void proc_bind_die(omp_proc_bind_t proc_bind, int T, int P, const char *format,...)
static affinity_mask_t * topology_get_mask_from_file(const char *filename)
static int get_first_nonspace_from_file(FILE *f)
static int get_integer_from_file(FILE *f, int *number)
if(ret)
affinity_mask_t ** masks