1 #ifndef LIBOMP_TEST_TOPOLOGY_H
2 #define LIBOMP_TEST_TOPOLOGY_H
4 #include "libomp_test_affinity.h"
13 typedef enum topology_obj_type_t
{
18 } topology_obj_type_t
;
20 typedef struct place_list_t
{
24 affinity_mask_t
**masks
;
27 // Return the first character in file 'f' that is not a whitespace character
28 // including newlines and carriage returns
29 static int get_first_nonspace_from_file(FILE *f
) {
33 } while (c
!= EOF
&& (isspace(c
) || c
== '\n' || c
== '\r'));
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.
41 static int get_integer_from_file(FILE *f
, int *number
) {
43 n
= fscanf(f
, "%d", number
);
51 // Read a siblings list file from Linux /sys/devices/system/cpu/cpu?/topology/*
52 static affinity_mask_t
*topology_get_mask_from_file(const char *filename
) {
53 int status
= EXIT_SUCCESS
;
54 FILE *f
= fopen(filename
, "r");
59 affinity_mask_t
*mask
= affinity_mask_alloc();
61 int c
, i
, n
, lower
, upper
;
62 // Read the first integer
63 n
= get_integer_from_file(f
, &lower
);
67 fprintf(stderr
, "syntax error: expected integer\n");
68 status
= EXIT_FAILURE
;
72 // Now either a , or -
73 c
= get_first_nonspace_from_file(f
);
74 if (c
== EOF
|| c
== ',') {
75 affinity_mask_set(mask
, lower
);
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
;
85 for (i
= lower
; i
<= upper
; ++i
)
86 affinity_mask_set(mask
, i
);
87 c
= get_first_nonspace_from_file(f
);
90 } else if (c
== ',') {
93 fprintf(stderr
, "syntax error: unexpected character: '%c (%d)'\n", c
,
95 status
= EXIT_FAILURE
;
99 fprintf(stderr
, "syntax error: unexpected character: '%c (%d)'\n", c
, c
);
100 status
= EXIT_FAILURE
;
105 if (status
== EXIT_FAILURE
) {
106 affinity_mask_free(mask
);
112 static int topology_get_num_cpus() {
114 // Count the number of cpus
117 snprintf(buf
, sizeof(buf
), "/sys/devices/system/cpu/cpu%d", cpu
);
118 DIR *dir
= opendir(buf
);
131 // Return whether the current thread has access to all logical processors
132 static int topology_using_full_mask() {
135 int num_cpus
= topology_get_num_cpus();
136 affinity_mask_t
*mask
= affinity_mask_alloc();
137 get_thread_affinity(mask
);
138 for (cpu
= 0; cpu
< num_cpus
; ++cpu
) {
139 if (!affinity_mask_isset(mask
, cpu
)) {
144 affinity_mask_free(mask
);
148 // Return array of masks representing OMP_PLACES keyword (e.g., sockets, cores,
150 static place_list_t
*topology_alloc_type_places(topology_obj_type_t type
) {
152 int i
, cpu
, num_places
, num_unique
;
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
);
159 for (cpu
= 0; cpu
< num_cpus
; ++cpu
) {
160 affinity_mask_t
*mask
;
161 if (type
== TOPOLOGY_OBJ_CORE
) {
162 snprintf(buf
, sizeof(buf
),
163 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list",
165 mask
= topology_get_mask_from_file(buf
);
166 } else if (type
== TOPOLOGY_OBJ_SOCKET
) {
167 snprintf(buf
, sizeof(buf
),
168 "/sys/devices/system/cpu/cpu%d/topology/core_siblings_list",
170 mask
= topology_get_mask_from_file(buf
);
171 } else if (type
== TOPOLOGY_OBJ_THREAD
) {
172 mask
= affinity_mask_alloc();
173 affinity_mask_set(mask
, cpu
);
175 fprintf(stderr
, "Unknown topology type (%d)\n", (int)type
);
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
)) {
182 affinity_mask_free(mask
);
189 masks
[num_unique
++] = mask
;
191 place_nums
= (int *)malloc(sizeof(int) * num_unique
);
192 for (i
= 0; i
< num_unique
; ++i
)
194 places
->num_places
= num_unique
;
195 places
->masks
= masks
;
196 places
->place_nums
= place_nums
;
197 places
->current_place
= -1;
201 static place_list_t
*topology_alloc_openmp_places() {
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
);
212 affinity_mask_t
*mask
= affinity_mask_alloc();
213 for (i
= 0; i
< num_procs
; ++i
)
214 affinity_mask_set(mask
, ids
[i
]);
216 place_nums
[place
] = place
;
218 places
->num_places
= num_places
;
219 places
->place_nums
= place_nums
;
220 places
->masks
= masks
;
221 places
->current_place
= omp_get_place_num();
225 static place_list_t
*topology_alloc_openmp_partition() {
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
);
241 omp_get_place_proc_ids(place
, ids
);
242 affinity_mask_t
*mask
= affinity_mask_alloc();
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
);
251 places
->num_places
= num_places
;
252 places
->place_nums
= place_nums
;
253 places
->masks
= masks
;
254 places
->current_place
= omp_get_place_num();
258 // Free the array of masks from one of: topology_alloc_type_masks()
259 // or topology_alloc_openmp_masks()
260 static void topology_free_places(place_list_t
*places
) {
262 for (i
= 0; i
< places
->num_places
; ++i
)
263 affinity_mask_free(places
->masks
[i
]);
265 free(places
->place_nums
);
269 static void topology_print_places(const place_list_t
*p
) {
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
);
278 // Print out an error message, possibly with two problem place lists,
279 // and then exit with failure
280 static void proc_bind_die(omp_proc_bind_t proc_bind
, int T
, int P
,
281 const char *format
, ...) {
283 va_start(args
, format
);
286 case omp_proc_bind_false
:
289 case omp_proc_bind_true
:
292 case omp_proc_bind_master
:
293 pb
= "Master (Primary)";
295 case omp_proc_bind_close
:
298 case omp_proc_bind_spread
:
302 pb
= "(Unknown Proc Bind Type)";
305 if (proc_bind
== omp_proc_bind_spread
|| proc_bind
== omp_proc_bind_close
) {
307 fprintf(stderr
, "%s : (T(%d) <= P(%d)) : ", pb
, T
, P
);
309 fprintf(stderr
, "%s : (T(%d) > P(%d)) : ", pb
, T
, P
);
312 fprintf(stderr
, "%s : T = %d, P = %d : ", pb
, T
, P
);
314 vfprintf(stderr
, format
, args
);
320 // Return 1 on failure, 0 on success.
321 static void proc_bind_check(omp_proc_bind_t proc_bind
,
322 const place_list_t
*parent
, place_list_t
**children
,
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
;
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
);
333 for (i
= 0; i
< nchildren
; ++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");
342 if (proc_bind
== omp_proc_bind_spread
) {
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
;
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
);
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
]);
367 first
= place_nums
[0];
368 last
= place_nums
[num_places
- 1];
369 // Primary thread executes on place of the parent thread?
371 if (current_place
!= parent
->current_place
) {
374 "Primary thread not on same place (%d) as parent thread (%d)\n",
375 current_place
, parent
->current_place
);
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
);
386 // Partitions don't have intersections?
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
,
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
,
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
,
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
,
419 // Each partition has only one place?
420 for (i
= 0; i
< T
; ++i
) {
421 if (partitions
[i
]->num_places
!= 1) {
424 "Incorrect number of places for thread %d: %d. Expecting 1\n", i
,
425 partitions
[i
]->num_places
);
428 // Correct number of consecutive threads per partition?
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]) {
437 "Too many threads have place %d for their partition\n",
438 partitions
[i
]->place_nums
[0]);
444 "Not enough threads have place %d for their partition\n",
445 partitions
[i
]->place_nums
[0]);
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
) {
456 "Primary thread not on same place (%d) as parent thread (%d)\n",
457 current_place
, parent
->current_place
);
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 "
472 num_places
, parent
->num_places
);
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
]);
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
)
487 if (proc_bind
== omp_proc_bind_close
) {
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
]) {
497 "Thread %d's current place (%d) is incorrect. expected %d\n", i
,
498 current_place
, parent
->place_nums
[j
]);
500 j
= (j
+ 1) % parent
->num_places
;
504 // check place assignment for each thread
506 high
= T
/ P
+ (T
% P
? 1 : 0);
508 if (partitions
[0]->current_place
!= parent
->current_place
) {
511 "Primary thread's place (%d) is not parent thread's place (%d)\n",
512 partitions
[0]->current_place
, parent
->current_place
);
514 for (i
= 1; i
< T
; ++i
) {
515 current_place
= partitions
[i
]->current_place
;
516 if (current_place
== parent
->place_nums
[j
]) {
521 "Too many threads have place %d for their current place\n",
528 "Not enough threads have place %d for their current place\n",
529 parent
->place_nums
[j
]);
531 j
= (j
+ 1) % parent
->num_places
;
532 if (current_place
!= parent
->place_nums
[j
]) {
535 "Thread %d's place (%d) is not corret. Expected %d\n", i
,
536 partitions
[i
]->current_place
, parent
->place_nums
[j
]);
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
) {
549 "Thread %d's place (%d) is not the primary thread's place (%d)\n",
550 i
, partitions
[i
]->current_place
, parent
->current_place
);
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
)
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
);