xref: /llvm-project/openmp/runtime/test/affinity/libomp_test_topology.h (revision 50b68a3d030543daf97794d68682cc698964ca26)
19982f33eSPeyton, Jonathan L #ifndef LIBOMP_TEST_TOPOLOGY_H
29982f33eSPeyton, Jonathan L #define LIBOMP_TEST_TOPOLOGY_H
39982f33eSPeyton, Jonathan L 
49982f33eSPeyton, Jonathan L #include "libomp_test_affinity.h"
59982f33eSPeyton, Jonathan L #include <stdio.h>
69982f33eSPeyton, Jonathan L #include <stdlib.h>
79982f33eSPeyton, Jonathan L #include <dirent.h>
89982f33eSPeyton, Jonathan L #include <errno.h>
99982f33eSPeyton, Jonathan L #include <ctype.h>
109982f33eSPeyton, Jonathan L #include <omp.h>
11*50b68a3dSPeyton, Jonathan L #include <stdarg.h>
129982f33eSPeyton, Jonathan L 
139982f33eSPeyton, Jonathan L typedef enum topology_obj_type_t {
149982f33eSPeyton, Jonathan L   TOPOLOGY_OBJ_THREAD,
159982f33eSPeyton, Jonathan L   TOPOLOGY_OBJ_CORE,
169982f33eSPeyton, Jonathan L   TOPOLOGY_OBJ_SOCKET,
179982f33eSPeyton, Jonathan L   TOPOLOGY_OBJ_MAX
189982f33eSPeyton, Jonathan L } topology_obj_type_t;
199982f33eSPeyton, Jonathan L 
209982f33eSPeyton, Jonathan L typedef struct place_list_t {
219982f33eSPeyton, Jonathan L   int num_places;
22*50b68a3dSPeyton, Jonathan L   int current_place;
23*50b68a3dSPeyton, Jonathan L   int *place_nums;
249982f33eSPeyton, Jonathan L   affinity_mask_t **masks;
259982f33eSPeyton, Jonathan L } place_list_t;
269982f33eSPeyton, Jonathan L 
279982f33eSPeyton, Jonathan L // Return the first character in file 'f' that is not a whitespace character
289982f33eSPeyton, Jonathan L // including newlines and carriage returns
get_first_nonspace_from_file(FILE * f)299982f33eSPeyton, Jonathan L static int get_first_nonspace_from_file(FILE *f) {
309982f33eSPeyton, Jonathan L   int c;
319982f33eSPeyton, Jonathan L   do {
329982f33eSPeyton, Jonathan L     c = fgetc(f);
339982f33eSPeyton, Jonathan L   } while (c != EOF && (isspace(c) || c == '\n' || c == '\r'));
349982f33eSPeyton, Jonathan L   return c;
359982f33eSPeyton, Jonathan L }
369982f33eSPeyton, Jonathan L 
379982f33eSPeyton, Jonathan L // Read an integer from file 'f' into 'number'
389982f33eSPeyton, Jonathan L // Return 1 on successful read of integer,
399982f33eSPeyton, Jonathan L //        0 on unsuccessful read of integer,
409982f33eSPeyton, Jonathan L //        EOF on end of file.
get_integer_from_file(FILE * f,int * number)419982f33eSPeyton, Jonathan L static int get_integer_from_file(FILE *f, int *number) {
429982f33eSPeyton, Jonathan L   int n;
439982f33eSPeyton, Jonathan L   n = fscanf(f, "%d", number);
449982f33eSPeyton, Jonathan L   if (feof(f))
459982f33eSPeyton, Jonathan L     return EOF;
469982f33eSPeyton, Jonathan L   if (n != 1)
479982f33eSPeyton, Jonathan L     return 0;
489982f33eSPeyton, Jonathan L   return 1;
499982f33eSPeyton, Jonathan L }
509982f33eSPeyton, Jonathan L 
519982f33eSPeyton, Jonathan L // Read a siblings list file from Linux /sys/devices/system/cpu/cpu?/topology/*
topology_get_mask_from_file(const char * filename)529982f33eSPeyton, Jonathan L static affinity_mask_t *topology_get_mask_from_file(const char *filename) {
539982f33eSPeyton, Jonathan L   int status = EXIT_SUCCESS;
549982f33eSPeyton, Jonathan L   FILE *f = fopen(filename, "r");
559982f33eSPeyton, Jonathan L   if (!f) {
569982f33eSPeyton, Jonathan L     perror(filename);
579982f33eSPeyton, Jonathan L     exit(EXIT_FAILURE);
589982f33eSPeyton, Jonathan L   }
599982f33eSPeyton, Jonathan L   affinity_mask_t *mask = affinity_mask_alloc();
609982f33eSPeyton, Jonathan L   while (1) {
619982f33eSPeyton, Jonathan L     int c, i, n, lower, upper;
629982f33eSPeyton, Jonathan L     // Read the first integer
639982f33eSPeyton, Jonathan L     n = get_integer_from_file(f, &lower);
649982f33eSPeyton, Jonathan L     if (n == EOF) {
659982f33eSPeyton, Jonathan L       break;
669982f33eSPeyton, Jonathan L     } else if (n == 0) {
679982f33eSPeyton, Jonathan L       fprintf(stderr, "syntax error: expected integer\n");
689982f33eSPeyton, Jonathan L       status = EXIT_FAILURE;
699982f33eSPeyton, Jonathan L       break;
709982f33eSPeyton, Jonathan L     }
719982f33eSPeyton, Jonathan L 
729982f33eSPeyton, Jonathan L     // Now either a , or -
739982f33eSPeyton, Jonathan L     c = get_first_nonspace_from_file(f);
749982f33eSPeyton, Jonathan L     if (c == EOF || c == ',') {
759982f33eSPeyton, Jonathan L       affinity_mask_set(mask, lower);
769982f33eSPeyton, Jonathan L       if (c == EOF)
779982f33eSPeyton, Jonathan L         break;
789982f33eSPeyton, Jonathan L     } else if (c == '-') {
799982f33eSPeyton, Jonathan L       n = get_integer_from_file(f, &upper);
809982f33eSPeyton, Jonathan L       if (n == EOF || n == 0) {
819982f33eSPeyton, Jonathan L         fprintf(stderr, "syntax error: expected integer\n");
829982f33eSPeyton, Jonathan L         status = EXIT_FAILURE;
839982f33eSPeyton, Jonathan L         break;
849982f33eSPeyton, Jonathan L       }
859982f33eSPeyton, Jonathan L       for (i = lower; i <= upper; ++i)
869982f33eSPeyton, Jonathan L         affinity_mask_set(mask, i);
879982f33eSPeyton, Jonathan L       c = get_first_nonspace_from_file(f);
889982f33eSPeyton, Jonathan L       if (c == EOF) {
899982f33eSPeyton, Jonathan L         break;
909982f33eSPeyton, Jonathan L       } else if (c == ',') {
919982f33eSPeyton, Jonathan L         continue;
929982f33eSPeyton, Jonathan L       } else {
939982f33eSPeyton, Jonathan L         fprintf(stderr, "syntax error: unexpected character: '%c (%d)'\n", c,
949982f33eSPeyton, Jonathan L                 c);
959982f33eSPeyton, Jonathan L         status = EXIT_FAILURE;
969982f33eSPeyton, Jonathan L         break;
979982f33eSPeyton, Jonathan L       }
989982f33eSPeyton, Jonathan L     } else {
999982f33eSPeyton, Jonathan L       fprintf(stderr, "syntax error: unexpected character: '%c (%d)'\n", c, c);
1009982f33eSPeyton, Jonathan L       status = EXIT_FAILURE;
1019982f33eSPeyton, Jonathan L       break;
1029982f33eSPeyton, Jonathan L     }
1039982f33eSPeyton, Jonathan L   }
1049982f33eSPeyton, Jonathan L   fclose(f);
1059982f33eSPeyton, Jonathan L   if (status == EXIT_FAILURE) {
1069982f33eSPeyton, Jonathan L     affinity_mask_free(mask);
1079982f33eSPeyton, Jonathan L     mask = NULL;
1089982f33eSPeyton, Jonathan L   }
1099982f33eSPeyton, Jonathan L   return mask;
1109982f33eSPeyton, Jonathan L }
1119982f33eSPeyton, Jonathan L 
topology_get_num_cpus()1129982f33eSPeyton, Jonathan L static int topology_get_num_cpus() {
1139982f33eSPeyton, Jonathan L   char buf[1024];
1149982f33eSPeyton, Jonathan L   // Count the number of cpus
1159982f33eSPeyton, Jonathan L   int cpu = 0;
1169982f33eSPeyton, Jonathan L   while (1) {
1179982f33eSPeyton, Jonathan L     snprintf(buf, sizeof(buf), "/sys/devices/system/cpu/cpu%d", cpu);
1189982f33eSPeyton, Jonathan L     DIR *dir = opendir(buf);
1199982f33eSPeyton, Jonathan L     if (dir) {
1209982f33eSPeyton, Jonathan L       closedir(dir);
1219982f33eSPeyton, Jonathan L       cpu++;
1229982f33eSPeyton, Jonathan L     } else {
1239982f33eSPeyton, Jonathan L       break;
1249982f33eSPeyton, Jonathan L     }
1259982f33eSPeyton, Jonathan L   }
1269982f33eSPeyton, Jonathan L   if (cpu == 0)
1279982f33eSPeyton, Jonathan L     cpu = 1;
1289982f33eSPeyton, Jonathan L   return cpu;
1299982f33eSPeyton, Jonathan L }
1309982f33eSPeyton, Jonathan L 
1319982f33eSPeyton, Jonathan L // Return whether the current thread has access to all logical processors
topology_using_full_mask()1329982f33eSPeyton, Jonathan L static int topology_using_full_mask() {
1339982f33eSPeyton, Jonathan L   int cpu;
1349982f33eSPeyton, Jonathan L   int has_all = 1;
1359982f33eSPeyton, Jonathan L   int num_cpus = topology_get_num_cpus();
1369982f33eSPeyton, Jonathan L   affinity_mask_t *mask = affinity_mask_alloc();
1379982f33eSPeyton, Jonathan L   get_thread_affinity(mask);
1389982f33eSPeyton, Jonathan L   for (cpu = 0; cpu < num_cpus; ++cpu) {
1399982f33eSPeyton, Jonathan L     if (!affinity_mask_isset(mask, cpu)) {
1409982f33eSPeyton, Jonathan L       has_all = 0;
1419982f33eSPeyton, Jonathan L       break;
1429982f33eSPeyton, Jonathan L     }
1439982f33eSPeyton, Jonathan L   }
1449982f33eSPeyton, Jonathan L   affinity_mask_free(mask);
1459982f33eSPeyton, Jonathan L   return has_all;
1469982f33eSPeyton, Jonathan L }
1479982f33eSPeyton, Jonathan L 
1489982f33eSPeyton, Jonathan L // Return array of masks representing OMP_PLACES keyword (e.g., sockets, cores,
1499982f33eSPeyton, Jonathan L // threads)
topology_alloc_type_places(topology_obj_type_t type)1509982f33eSPeyton, Jonathan L static place_list_t *topology_alloc_type_places(topology_obj_type_t type) {
1519982f33eSPeyton, Jonathan L   char buf[1024];
1529982f33eSPeyton, Jonathan L   int i, cpu, num_places, num_unique;
153*50b68a3dSPeyton, Jonathan L   int *place_nums;
1549982f33eSPeyton, Jonathan L   int num_cpus = topology_get_num_cpus();
1559982f33eSPeyton, Jonathan L   place_list_t *places = (place_list_t *)malloc(sizeof(place_list_t));
1569982f33eSPeyton, Jonathan L   affinity_mask_t **masks =
1579982f33eSPeyton, Jonathan L       (affinity_mask_t **)malloc(sizeof(affinity_mask_t *) * num_cpus);
1589982f33eSPeyton, Jonathan L   num_unique = 0;
1599982f33eSPeyton, Jonathan L   for (cpu = 0; cpu < num_cpus; ++cpu) {
1609982f33eSPeyton, Jonathan L     affinity_mask_t *mask;
1619982f33eSPeyton, Jonathan L     if (type == TOPOLOGY_OBJ_CORE) {
1629982f33eSPeyton, Jonathan L       snprintf(buf, sizeof(buf),
1639982f33eSPeyton, Jonathan L                "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list",
1649982f33eSPeyton, Jonathan L                cpu);
1659982f33eSPeyton, Jonathan L       mask = topology_get_mask_from_file(buf);
1669982f33eSPeyton, Jonathan L     } else if (type == TOPOLOGY_OBJ_SOCKET) {
1679982f33eSPeyton, Jonathan L       snprintf(buf, sizeof(buf),
1689982f33eSPeyton, Jonathan L                "/sys/devices/system/cpu/cpu%d/topology/core_siblings_list",
1699982f33eSPeyton, Jonathan L                cpu);
1709982f33eSPeyton, Jonathan L       mask = topology_get_mask_from_file(buf);
1719982f33eSPeyton, Jonathan L     } else if (type == TOPOLOGY_OBJ_THREAD) {
1729982f33eSPeyton, Jonathan L       mask = affinity_mask_alloc();
1739982f33eSPeyton, Jonathan L       affinity_mask_set(mask, cpu);
1749982f33eSPeyton, Jonathan L     } else {
1759982f33eSPeyton, Jonathan L       fprintf(stderr, "Unknown topology type (%d)\n", (int)type);
1769982f33eSPeyton, Jonathan L       exit(EXIT_FAILURE);
1779982f33eSPeyton, Jonathan L     }
1789982f33eSPeyton, Jonathan L     // Check for unique topology objects above the thread level
1799982f33eSPeyton, Jonathan L     if (type != TOPOLOGY_OBJ_THREAD) {
1809982f33eSPeyton, Jonathan L       for (i = 0; i < num_unique; ++i) {
1819982f33eSPeyton, Jonathan L         if (affinity_mask_equal(masks[i], mask)) {
1829982f33eSPeyton, Jonathan L           affinity_mask_free(mask);
1839982f33eSPeyton, Jonathan L           mask = NULL;
1849982f33eSPeyton, Jonathan L           break;
1859982f33eSPeyton, Jonathan L         }
1869982f33eSPeyton, Jonathan L       }
1879982f33eSPeyton, Jonathan L     }
1889982f33eSPeyton, Jonathan L     if (mask)
1899982f33eSPeyton, Jonathan L       masks[num_unique++] = mask;
1909982f33eSPeyton, Jonathan L   }
191*50b68a3dSPeyton, Jonathan L   place_nums = (int *)malloc(sizeof(int) * num_unique);
192*50b68a3dSPeyton, Jonathan L   for (i = 0; i < num_unique; ++i)
193*50b68a3dSPeyton, Jonathan L     place_nums[i] = i;
1949982f33eSPeyton, Jonathan L   places->num_places = num_unique;
1959982f33eSPeyton, Jonathan L   places->masks = masks;
196*50b68a3dSPeyton, Jonathan L   places->place_nums = place_nums;
197*50b68a3dSPeyton, Jonathan L   places->current_place = -1;
1989982f33eSPeyton, Jonathan L   return places;
1999982f33eSPeyton, Jonathan L }
2009982f33eSPeyton, Jonathan L 
topology_alloc_openmp_places()2019982f33eSPeyton, Jonathan L static place_list_t *topology_alloc_openmp_places() {
2029982f33eSPeyton, Jonathan L   int place, i;
2039982f33eSPeyton, Jonathan L   int num_places = omp_get_num_places();
2049982f33eSPeyton, Jonathan L   place_list_t *places = (place_list_t *)malloc(sizeof(place_list_t));
2059982f33eSPeyton, Jonathan L   affinity_mask_t **masks =
2069982f33eSPeyton, Jonathan L       (affinity_mask_t **)malloc(sizeof(affinity_mask_t *) * num_places);
207*50b68a3dSPeyton, Jonathan L   int *place_nums = (int *)malloc(sizeof(int) * num_places);
2089982f33eSPeyton, Jonathan L   for (place = 0; place < num_places; ++place) {
2099982f33eSPeyton, Jonathan L     int num_procs = omp_get_place_num_procs(place);
2109982f33eSPeyton, Jonathan L     int *ids = (int *)malloc(sizeof(int) * num_procs);
2119982f33eSPeyton, Jonathan L     omp_get_place_proc_ids(place, ids);
2129982f33eSPeyton, Jonathan L     affinity_mask_t *mask = affinity_mask_alloc();
2139982f33eSPeyton, Jonathan L     for (i = 0; i < num_procs; ++i)
2149982f33eSPeyton, Jonathan L       affinity_mask_set(mask, ids[i]);
2159982f33eSPeyton, Jonathan L     masks[place] = mask;
216*50b68a3dSPeyton, Jonathan L     place_nums[place] = place;
2179982f33eSPeyton, Jonathan L   }
2189982f33eSPeyton, Jonathan L   places->num_places = num_places;
219*50b68a3dSPeyton, Jonathan L   places->place_nums = place_nums;
2209982f33eSPeyton, Jonathan L   places->masks = masks;
221*50b68a3dSPeyton, Jonathan L   places->current_place = omp_get_place_num();
222*50b68a3dSPeyton, Jonathan L   return places;
223*50b68a3dSPeyton, Jonathan L }
224*50b68a3dSPeyton, Jonathan L 
topology_alloc_openmp_partition()225*50b68a3dSPeyton, Jonathan L static place_list_t *topology_alloc_openmp_partition() {
226*50b68a3dSPeyton, Jonathan L   int p, i;
227*50b68a3dSPeyton, Jonathan L   int num_places = omp_get_partition_num_places();
228*50b68a3dSPeyton, Jonathan L   place_list_t *places = (place_list_t *)malloc(sizeof(place_list_t));
229*50b68a3dSPeyton, Jonathan L   int *place_nums = (int *)malloc(sizeof(int) * num_places);
230*50b68a3dSPeyton, Jonathan L   affinity_mask_t **masks =
231*50b68a3dSPeyton, Jonathan L       (affinity_mask_t **)malloc(sizeof(affinity_mask_t *) * num_places);
232*50b68a3dSPeyton, Jonathan L   omp_get_partition_place_nums(place_nums);
233*50b68a3dSPeyton, Jonathan L   for (p = 0; p < num_places; ++p) {
234*50b68a3dSPeyton, Jonathan L     int place = place_nums[p];
235*50b68a3dSPeyton, Jonathan L     int num_procs = omp_get_place_num_procs(place);
236*50b68a3dSPeyton, Jonathan L     int *ids = (int *)malloc(sizeof(int) * num_procs);
237*50b68a3dSPeyton, Jonathan L     if (num_procs == 0) {
238*50b68a3dSPeyton, Jonathan L       fprintf(stderr, "place %d has 0 procs?\n", place);
239*50b68a3dSPeyton, Jonathan L       exit(EXIT_FAILURE);
240*50b68a3dSPeyton, Jonathan L     }
241*50b68a3dSPeyton, Jonathan L     omp_get_place_proc_ids(place, ids);
242*50b68a3dSPeyton, Jonathan L     affinity_mask_t *mask = affinity_mask_alloc();
243*50b68a3dSPeyton, Jonathan L     for (i = 0; i < num_procs; ++i)
244*50b68a3dSPeyton, Jonathan L       affinity_mask_set(mask, ids[i]);
245*50b68a3dSPeyton, Jonathan L     if (affinity_mask_count(mask) == 0) {
246*50b68a3dSPeyton, Jonathan L       fprintf(stderr, "place %d has 0 procs set?\n", place);
247*50b68a3dSPeyton, Jonathan L       exit(EXIT_FAILURE);
248*50b68a3dSPeyton, Jonathan L     }
249*50b68a3dSPeyton, Jonathan L     masks[p] = mask;
250*50b68a3dSPeyton, Jonathan L   }
251*50b68a3dSPeyton, Jonathan L   places->num_places = num_places;
252*50b68a3dSPeyton, Jonathan L   places->place_nums = place_nums;
253*50b68a3dSPeyton, Jonathan L   places->masks = masks;
254*50b68a3dSPeyton, Jonathan L   places->current_place = omp_get_place_num();
2559982f33eSPeyton, Jonathan L   return places;
2569982f33eSPeyton, Jonathan L }
2579982f33eSPeyton, Jonathan L 
2589982f33eSPeyton, Jonathan L // Free the array of masks from one of: topology_alloc_type_masks()
2599982f33eSPeyton, Jonathan L // or topology_alloc_openmp_masks()
topology_free_places(place_list_t * places)2609982f33eSPeyton, Jonathan L static void topology_free_places(place_list_t *places) {
2619982f33eSPeyton, Jonathan L   int i;
2629982f33eSPeyton, Jonathan L   for (i = 0; i < places->num_places; ++i)
2639982f33eSPeyton, Jonathan L     affinity_mask_free(places->masks[i]);
2649982f33eSPeyton, Jonathan L   free(places->masks);
265*50b68a3dSPeyton, Jonathan L   free(places->place_nums);
2669982f33eSPeyton, Jonathan L   free(places);
2679982f33eSPeyton, Jonathan L }
2689982f33eSPeyton, Jonathan L 
topology_print_places(const place_list_t * p)2699982f33eSPeyton, Jonathan L static void topology_print_places(const place_list_t *p) {
2709982f33eSPeyton, Jonathan L   int i;
2719982f33eSPeyton, Jonathan L   char buf[1024];
2729982f33eSPeyton, Jonathan L   for (i = 0; i < p->num_places; ++i) {
2739982f33eSPeyton, Jonathan L     affinity_mask_snprintf(buf, sizeof(buf), p->masks[i]);
274*50b68a3dSPeyton, Jonathan L     printf("Place %d: %s\n", p->place_nums[i], buf);
2759982f33eSPeyton, Jonathan L   }
2769982f33eSPeyton, Jonathan L }
2779982f33eSPeyton, Jonathan L 
278*50b68a3dSPeyton, Jonathan L // Print out an error message, possibly with two problem place lists,
279*50b68a3dSPeyton, Jonathan L // and then exit with failure
proc_bind_die(omp_proc_bind_t proc_bind,int T,int P,const char * format,...)280*50b68a3dSPeyton, Jonathan L static void proc_bind_die(omp_proc_bind_t proc_bind, int T, int P,
281*50b68a3dSPeyton, Jonathan L                           const char *format, ...) {
282*50b68a3dSPeyton, Jonathan L   va_list args;
283*50b68a3dSPeyton, Jonathan L   va_start(args, format);
284*50b68a3dSPeyton, Jonathan L   const char *pb;
285*50b68a3dSPeyton, Jonathan L   switch (proc_bind) {
286*50b68a3dSPeyton, Jonathan L   case omp_proc_bind_false:
287*50b68a3dSPeyton, Jonathan L     pb = "False";
288*50b68a3dSPeyton, Jonathan L     break;
289*50b68a3dSPeyton, Jonathan L   case omp_proc_bind_true:
290*50b68a3dSPeyton, Jonathan L     pb = "True";
291*50b68a3dSPeyton, Jonathan L     break;
292*50b68a3dSPeyton, Jonathan L   case omp_proc_bind_master:
293*50b68a3dSPeyton, Jonathan L     pb = "Master (Primary)";
294*50b68a3dSPeyton, Jonathan L     break;
295*50b68a3dSPeyton, Jonathan L   case omp_proc_bind_close:
296*50b68a3dSPeyton, Jonathan L     pb = "Close";
297*50b68a3dSPeyton, Jonathan L     break;
298*50b68a3dSPeyton, Jonathan L   case omp_proc_bind_spread:
299*50b68a3dSPeyton, Jonathan L     pb = "Spread";
300*50b68a3dSPeyton, Jonathan L     break;
301*50b68a3dSPeyton, Jonathan L   default:
302*50b68a3dSPeyton, Jonathan L     pb = "(Unknown Proc Bind Type)";
303*50b68a3dSPeyton, Jonathan L     break;
304*50b68a3dSPeyton, Jonathan L   }
305*50b68a3dSPeyton, Jonathan L   if (proc_bind == omp_proc_bind_spread || proc_bind == omp_proc_bind_close) {
306*50b68a3dSPeyton, Jonathan L     if (T <= P) {
307*50b68a3dSPeyton, Jonathan L       fprintf(stderr, "%s : (T(%d) <= P(%d)) : ", pb, T, P);
308*50b68a3dSPeyton, Jonathan L     } else {
309*50b68a3dSPeyton, Jonathan L       fprintf(stderr, "%s : (T(%d) > P(%d)) : ", pb, T, P);
310*50b68a3dSPeyton, Jonathan L     }
311*50b68a3dSPeyton, Jonathan L   } else {
312*50b68a3dSPeyton, Jonathan L     fprintf(stderr, "%s : T = %d, P = %d : ", pb, T, P);
313*50b68a3dSPeyton, Jonathan L   }
314*50b68a3dSPeyton, Jonathan L   vfprintf(stderr, format, args);
315*50b68a3dSPeyton, Jonathan L   va_end(args);
316*50b68a3dSPeyton, Jonathan L 
317*50b68a3dSPeyton, Jonathan L   exit(EXIT_FAILURE);
318*50b68a3dSPeyton, Jonathan L }
319*50b68a3dSPeyton, Jonathan L 
320*50b68a3dSPeyton, Jonathan L // Return 1 on failure, 0 on success.
proc_bind_check(omp_proc_bind_t proc_bind,const place_list_t * parent,place_list_t ** children,int nchildren)321*50b68a3dSPeyton, Jonathan L static void proc_bind_check(omp_proc_bind_t proc_bind,
322*50b68a3dSPeyton, Jonathan L                             const place_list_t *parent, place_list_t **children,
323*50b68a3dSPeyton, Jonathan L                             int nchildren) {
324*50b68a3dSPeyton, Jonathan L   place_list_t *partition;
325*50b68a3dSPeyton, Jonathan L   int T, i, j, place, low, high, first, last, count, current_place, num_places;
326*50b68a3dSPeyton, Jonathan L   const int *place_nums;
327*50b68a3dSPeyton, Jonathan L   int P = parent->num_places;
328*50b68a3dSPeyton, Jonathan L 
329*50b68a3dSPeyton, Jonathan L   // Find the correct T (there could be null entries in children)
330*50b68a3dSPeyton, Jonathan L   place_list_t **partitions =
331*50b68a3dSPeyton, Jonathan L       (place_list_t **)malloc(sizeof(place_list_t *) * nchildren);
332*50b68a3dSPeyton, Jonathan L   T = 0;
333*50b68a3dSPeyton, Jonathan L   for (i = 0; i < nchildren; ++i)
334*50b68a3dSPeyton, Jonathan L     if (children[i])
335*50b68a3dSPeyton, Jonathan L       partitions[T++] = children[i];
336*50b68a3dSPeyton, Jonathan L   // Only able to check spread, close, master (primary)
337*50b68a3dSPeyton, Jonathan L   if (proc_bind != omp_proc_bind_spread && proc_bind != omp_proc_bind_close &&
338*50b68a3dSPeyton, Jonathan L       proc_bind != omp_proc_bind_master)
339*50b68a3dSPeyton, Jonathan L     proc_bind_die(proc_bind, T, P, NULL, NULL,
340*50b68a3dSPeyton, Jonathan L                   "Cannot check this proc bind type\n");
341*50b68a3dSPeyton, Jonathan L 
342*50b68a3dSPeyton, Jonathan L   if (proc_bind == omp_proc_bind_spread) {
343*50b68a3dSPeyton, Jonathan L     if (T <= P) {
344*50b68a3dSPeyton, Jonathan L       // Run through each subpartition
345*50b68a3dSPeyton, Jonathan L       for (i = 0; i < T; ++i) {
346*50b68a3dSPeyton, Jonathan L         partition = partitions[i];
347*50b68a3dSPeyton, Jonathan L         place_nums = partition->place_nums;
348*50b68a3dSPeyton, Jonathan L         num_places = partition->num_places;
349*50b68a3dSPeyton, Jonathan L         current_place = partition->current_place;
350*50b68a3dSPeyton, Jonathan L         // Correct count?
351*50b68a3dSPeyton, Jonathan L         low = P / T;
352*50b68a3dSPeyton, Jonathan L         high = P / T + (P % T ? 1 : 0);
353*50b68a3dSPeyton, Jonathan L         if (num_places != low && num_places != high) {
354*50b68a3dSPeyton, Jonathan L           proc_bind_die(proc_bind, T, P,
355*50b68a3dSPeyton, Jonathan L                         "Incorrect number of places for thread %d: %d. "
356*50b68a3dSPeyton, Jonathan L                         "Expecting between %d and %d\n",
357*50b68a3dSPeyton, Jonathan L                         i, num_places, low, high);
358*50b68a3dSPeyton, Jonathan L         }
359*50b68a3dSPeyton, Jonathan L         // Consecutive places?
360*50b68a3dSPeyton, Jonathan L         for (j = 1; j < num_places; ++j) {
361*50b68a3dSPeyton, Jonathan L           if (place_nums[j] != (place_nums[j - 1] + 1) % P) {
362*50b68a3dSPeyton, Jonathan L             proc_bind_die(proc_bind, T, P,
363*50b68a3dSPeyton, Jonathan L                           "Not consecutive places: %d, %d in partition\n",
364*50b68a3dSPeyton, Jonathan L                           place_nums[j - 1], place_nums[j]);
365*50b68a3dSPeyton, Jonathan L           }
366*50b68a3dSPeyton, Jonathan L         }
367*50b68a3dSPeyton, Jonathan L         first = place_nums[0];
368*50b68a3dSPeyton, Jonathan L         last = place_nums[num_places - 1];
369*50b68a3dSPeyton, Jonathan L         // Primary thread executes on place of the parent thread?
370*50b68a3dSPeyton, Jonathan L         if (i == 0) {
371*50b68a3dSPeyton, Jonathan L           if (current_place != parent->current_place) {
372*50b68a3dSPeyton, Jonathan L             proc_bind_die(
373*50b68a3dSPeyton, Jonathan L                 proc_bind, T, P,
374*50b68a3dSPeyton, Jonathan L                 "Primary thread not on same place (%d) as parent thread (%d)\n",
375*50b68a3dSPeyton, Jonathan L                 current_place, parent->current_place);
376*50b68a3dSPeyton, Jonathan L           }
377*50b68a3dSPeyton, Jonathan L         } else {
378*50b68a3dSPeyton, Jonathan L           // Thread's current place is first place within it's partition?
379*50b68a3dSPeyton, Jonathan L           if (current_place != first) {
380*50b68a3dSPeyton, Jonathan L             proc_bind_die(proc_bind, T, P,
381*50b68a3dSPeyton, Jonathan L                           "Thread's current place (%d) is not the first place "
382*50b68a3dSPeyton, Jonathan L                           "in its partition [%d, %d]\n",
383*50b68a3dSPeyton, Jonathan L                           current_place, first, last);
384*50b68a3dSPeyton, Jonathan L           }
385*50b68a3dSPeyton, Jonathan L         }
386*50b68a3dSPeyton, Jonathan L         // Partitions don't have intersections?
387*50b68a3dSPeyton, Jonathan L         int f1 = first;
388*50b68a3dSPeyton, Jonathan L         int l1 = last;
389*50b68a3dSPeyton, Jonathan L         for (j = 0; j < i; ++j) {
390*50b68a3dSPeyton, Jonathan L           int f2 = partitions[j]->place_nums[0];
391*50b68a3dSPeyton, Jonathan L           int l2 = partitions[j]->place_nums[partitions[j]->num_places - 1];
392*50b68a3dSPeyton, Jonathan L           if (f1 > l1 && f2 > l2) {
393*50b68a3dSPeyton, Jonathan L             proc_bind_die(proc_bind, T, P,
394*50b68a3dSPeyton, Jonathan L                           "partitions intersect. [%d, %d] and [%d, %d]\n", f1,
395*50b68a3dSPeyton, Jonathan L                           l1, f2, l2);
396*50b68a3dSPeyton, Jonathan L           }
397*50b68a3dSPeyton, Jonathan L           if (f1 > l1 && f2 <= l2)
398*50b68a3dSPeyton, Jonathan L             if (f1 < l2 || l1 > f2) {
399*50b68a3dSPeyton, Jonathan L               proc_bind_die(proc_bind, T, P,
400*50b68a3dSPeyton, Jonathan L                             "partitions intersect. [%d, %d] and [%d, %d]\n", f1,
401*50b68a3dSPeyton, Jonathan L                             l1, f2, l2);
402*50b68a3dSPeyton, Jonathan L             }
403*50b68a3dSPeyton, Jonathan L           if (f1 <= l1 && f2 > l2)
404*50b68a3dSPeyton, Jonathan L             if (f2 < l1 || l2 > f1) {
405*50b68a3dSPeyton, Jonathan L               proc_bind_die(proc_bind, T, P,
406*50b68a3dSPeyton, Jonathan L                             "partitions intersect. [%d, %d] and [%d, %d]\n", f1,
407*50b68a3dSPeyton, Jonathan L                             l1, f2, l2);
408*50b68a3dSPeyton, Jonathan L             }
409*50b68a3dSPeyton, Jonathan L           if (f1 <= l1 && f2 <= l2)
410*50b68a3dSPeyton, Jonathan L             if (!(f2 > l1 || l2 < f1)) {
411*50b68a3dSPeyton, Jonathan L               proc_bind_die(proc_bind, T, P,
412*50b68a3dSPeyton, Jonathan L                             "partitions intersect. [%d, %d] and [%d, %d]\n", f1,
413*50b68a3dSPeyton, Jonathan L                             l1, f2, l2);
414*50b68a3dSPeyton, Jonathan L             }
415*50b68a3dSPeyton, Jonathan L         }
416*50b68a3dSPeyton, Jonathan L       }
417*50b68a3dSPeyton, Jonathan L     } else {
418*50b68a3dSPeyton, Jonathan L       // T > P
419*50b68a3dSPeyton, Jonathan L       // Each partition has only one place?
420*50b68a3dSPeyton, Jonathan L       for (i = 0; i < T; ++i) {
421*50b68a3dSPeyton, Jonathan L         if (partitions[i]->num_places != 1) {
422*50b68a3dSPeyton, Jonathan L           proc_bind_die(
423*50b68a3dSPeyton, Jonathan L               proc_bind, T, P,
424*50b68a3dSPeyton, Jonathan L               "Incorrect number of places for thread %d: %d. Expecting 1\n", i,
425*50b68a3dSPeyton, Jonathan L               partitions[i]->num_places);
426*50b68a3dSPeyton, Jonathan L         }
427*50b68a3dSPeyton, Jonathan L       }
428*50b68a3dSPeyton, Jonathan L       // Correct number of consecutive threads per partition?
429*50b68a3dSPeyton, Jonathan L       low = T / P;
430*50b68a3dSPeyton, Jonathan L       high = T / P + (T % P ? 1 : 0);
431*50b68a3dSPeyton, Jonathan L       for (i = 1, count = 1; i < T; ++i) {
432*50b68a3dSPeyton, Jonathan L         if (partitions[i]->place_nums[0] == partitions[i - 1]->place_nums[0]) {
433*50b68a3dSPeyton, Jonathan L           count++;
434*50b68a3dSPeyton, Jonathan L           if (count > high) {
435*50b68a3dSPeyton, Jonathan L             proc_bind_die(
436*50b68a3dSPeyton, Jonathan L                 proc_bind, T, P,
437*50b68a3dSPeyton, Jonathan L                 "Too many threads have place %d for their partition\n",
438*50b68a3dSPeyton, Jonathan L                 partitions[i]->place_nums[0]);
439*50b68a3dSPeyton, Jonathan L           }
440*50b68a3dSPeyton, Jonathan L         } else {
441*50b68a3dSPeyton, Jonathan L           if (count < low) {
442*50b68a3dSPeyton, Jonathan L             proc_bind_die(
443*50b68a3dSPeyton, Jonathan L                 proc_bind, T, P,
444*50b68a3dSPeyton, Jonathan L                 "Not enough threads have place %d for their partition\n",
445*50b68a3dSPeyton, Jonathan L                 partitions[i]->place_nums[0]);
446*50b68a3dSPeyton, Jonathan L           }
447*50b68a3dSPeyton, Jonathan L           count = 1;
448*50b68a3dSPeyton, Jonathan L         }
449*50b68a3dSPeyton, Jonathan L       }
450*50b68a3dSPeyton, Jonathan L       // Primary thread executes on place of the parent thread?
451*50b68a3dSPeyton, Jonathan L       current_place = partitions[0]->place_nums[0];
452*50b68a3dSPeyton, Jonathan L       if (parent->current_place != -1 &&
453*50b68a3dSPeyton, Jonathan L           current_place != parent->current_place) {
454*50b68a3dSPeyton, Jonathan L         proc_bind_die(
455*50b68a3dSPeyton, Jonathan L             proc_bind, T, P,
456*50b68a3dSPeyton, Jonathan L             "Primary thread not on same place (%d) as parent thread (%d)\n",
457*50b68a3dSPeyton, Jonathan L             current_place, parent->current_place);
458*50b68a3dSPeyton, Jonathan L       }
459*50b68a3dSPeyton, Jonathan L     }
460*50b68a3dSPeyton, Jonathan L   } else if (proc_bind == omp_proc_bind_close ||
461*50b68a3dSPeyton, Jonathan L              proc_bind == omp_proc_bind_master) {
462*50b68a3dSPeyton, Jonathan L     // Check that each subpartition is the same as the parent
463*50b68a3dSPeyton, Jonathan L     for (i = 0; i < T; ++i) {
464*50b68a3dSPeyton, Jonathan L       partition = partitions[i];
465*50b68a3dSPeyton, Jonathan L       place_nums = partition->place_nums;
466*50b68a3dSPeyton, Jonathan L       num_places = partition->num_places;
467*50b68a3dSPeyton, Jonathan L       current_place = partition->current_place;
468*50b68a3dSPeyton, Jonathan L       if (parent->num_places != num_places) {
469*50b68a3dSPeyton, Jonathan L         proc_bind_die(proc_bind, T, P,
470*50b68a3dSPeyton, Jonathan L                       "Number of places in subpartition (%d) does not match "
471*50b68a3dSPeyton, Jonathan L                       "parent (%d)\n",
472*50b68a3dSPeyton, Jonathan L                       num_places, parent->num_places);
473*50b68a3dSPeyton, Jonathan L       }
474*50b68a3dSPeyton, Jonathan L       for (j = 0; j < num_places; ++j) {
475*50b68a3dSPeyton, Jonathan L         if (parent->place_nums[j] != place_nums[j]) {
476*50b68a3dSPeyton, Jonathan L           proc_bind_die(proc_bind, T, P,
477*50b68a3dSPeyton, Jonathan L                         "Subpartition place (%d) does not match "
478*50b68a3dSPeyton, Jonathan L                         "parent partition place (%d)\n",
479*50b68a3dSPeyton, Jonathan L                         place_nums[j], parent->place_nums[j]);
480*50b68a3dSPeyton, Jonathan L         }
481*50b68a3dSPeyton, Jonathan L       }
482*50b68a3dSPeyton, Jonathan L     }
483*50b68a3dSPeyton, Jonathan L     // Find index into place_nums of current place for parent
484*50b68a3dSPeyton, Jonathan L     for (j = 0; j < parent->num_places; ++j)
485*50b68a3dSPeyton, Jonathan L       if (parent->place_nums[j] == parent->current_place)
486*50b68a3dSPeyton, Jonathan L         break;
487*50b68a3dSPeyton, Jonathan L     if (proc_bind == omp_proc_bind_close) {
488*50b68a3dSPeyton, Jonathan L       if (T <= P) {
489*50b68a3dSPeyton, Jonathan L         // close T <= P
490*50b68a3dSPeyton, Jonathan L         // check place assignment for each thread
491*50b68a3dSPeyton, Jonathan L         for (i = 0; i < T; ++i) {
492*50b68a3dSPeyton, Jonathan L           partition = partitions[i];
493*50b68a3dSPeyton, Jonathan L           current_place = partition->current_place;
494*50b68a3dSPeyton, Jonathan L           if (current_place != parent->place_nums[j]) {
495*50b68a3dSPeyton, Jonathan L             proc_bind_die(
496*50b68a3dSPeyton, Jonathan L                 proc_bind, T, P,
497*50b68a3dSPeyton, Jonathan L                 "Thread %d's current place (%d) is incorrect. expected %d\n", i,
498*50b68a3dSPeyton, Jonathan L                 current_place, parent->place_nums[j]);
499*50b68a3dSPeyton, Jonathan L           }
500*50b68a3dSPeyton, Jonathan L           j = (j + 1) % parent->num_places;
501*50b68a3dSPeyton, Jonathan L         }
502*50b68a3dSPeyton, Jonathan L       } else {
503*50b68a3dSPeyton, Jonathan L         // close T > P
504*50b68a3dSPeyton, Jonathan L         // check place assignment for each thread
505*50b68a3dSPeyton, Jonathan L         low = T / P;
506*50b68a3dSPeyton, Jonathan L         high = T / P + (T % P ? 1 : 0);
507*50b68a3dSPeyton, Jonathan L         count = 1;
508*50b68a3dSPeyton, Jonathan L         if (partitions[0]->current_place != parent->current_place) {
509*50b68a3dSPeyton, Jonathan L           proc_bind_die(
510*50b68a3dSPeyton, Jonathan L               proc_bind, T, P,
511*50b68a3dSPeyton, Jonathan L               "Primary thread's place (%d) is not parent thread's place (%d)\n",
512*50b68a3dSPeyton, Jonathan L               partitions[0]->current_place, parent->current_place);
513*50b68a3dSPeyton, Jonathan L         }
514*50b68a3dSPeyton, Jonathan L         for (i = 1; i < T; ++i) {
515*50b68a3dSPeyton, Jonathan L           current_place = partitions[i]->current_place;
516*50b68a3dSPeyton, Jonathan L           if (current_place == parent->place_nums[j]) {
517*50b68a3dSPeyton, Jonathan L             count++;
518*50b68a3dSPeyton, Jonathan L             if (count > high) {
519*50b68a3dSPeyton, Jonathan L               proc_bind_die(
520*50b68a3dSPeyton, Jonathan L                   proc_bind, T, P,
521*50b68a3dSPeyton, Jonathan L                   "Too many threads have place %d for their current place\n",
522*50b68a3dSPeyton, Jonathan L                   current_place);
523*50b68a3dSPeyton, Jonathan L             }
524*50b68a3dSPeyton, Jonathan L           } else {
525*50b68a3dSPeyton, Jonathan L             if (count < low) {
526*50b68a3dSPeyton, Jonathan L               proc_bind_die(
527*50b68a3dSPeyton, Jonathan L                   proc_bind, T, P,
528*50b68a3dSPeyton, Jonathan L                   "Not enough threads have place %d for their current place\n",
529*50b68a3dSPeyton, Jonathan L                   parent->place_nums[j]);
530*50b68a3dSPeyton, Jonathan L             }
531*50b68a3dSPeyton, Jonathan L             j = (j + 1) % parent->num_places;
532*50b68a3dSPeyton, Jonathan L             if (current_place != parent->place_nums[j]) {
533*50b68a3dSPeyton, Jonathan L               proc_bind_die(
534*50b68a3dSPeyton, Jonathan L                   proc_bind, T, P,
535*50b68a3dSPeyton, Jonathan L                   "Thread %d's place (%d) is not corret. Expected %d\n", i,
536*50b68a3dSPeyton, Jonathan L                   partitions[i]->current_place, parent->place_nums[j]);
537*50b68a3dSPeyton, Jonathan L             }
538*50b68a3dSPeyton, Jonathan L             count = 1;
539*50b68a3dSPeyton, Jonathan L           }
540*50b68a3dSPeyton, Jonathan L         }
541*50b68a3dSPeyton, Jonathan L       }
542*50b68a3dSPeyton, Jonathan L     } else {
543*50b68a3dSPeyton, Jonathan L       // proc_bind_primary
544*50b68a3dSPeyton, Jonathan L       // Every thread should be assigned to the primary thread's place
545*50b68a3dSPeyton, Jonathan L       for (i = 0; i < T; ++i) {
546*50b68a3dSPeyton, Jonathan L         if (partitions[i]->current_place != parent->current_place) {
547*50b68a3dSPeyton, Jonathan L           proc_bind_die(
548*50b68a3dSPeyton, Jonathan L               proc_bind, T, P,
549*50b68a3dSPeyton, Jonathan L               "Thread %d's place (%d) is not the primary thread's place (%d)\n",
550*50b68a3dSPeyton, Jonathan L               i, partitions[i]->current_place, parent->current_place);
551*50b68a3dSPeyton, Jonathan L         }
552*50b68a3dSPeyton, Jonathan L       }
553*50b68a3dSPeyton, Jonathan L     }
554*50b68a3dSPeyton, Jonathan L   }
555*50b68a3dSPeyton, Jonathan L 
556*50b68a3dSPeyton, Jonathan L   // Check that each partition's current place is within the partition
557*50b68a3dSPeyton, Jonathan L   for (i = 0; i < T; ++i) {
558*50b68a3dSPeyton, Jonathan L     current_place = partitions[i]->current_place;
559*50b68a3dSPeyton, Jonathan L     num_places = partitions[i]->num_places;
560*50b68a3dSPeyton, Jonathan L     first = partitions[i]->place_nums[0];
561*50b68a3dSPeyton, Jonathan L     last = partitions[i]->place_nums[num_places - 1];
562*50b68a3dSPeyton, Jonathan L     for (j = 0; j < num_places; ++j)
563*50b68a3dSPeyton, Jonathan L       if (partitions[i]->place_nums[j] == current_place)
564*50b68a3dSPeyton, Jonathan L         break;
565*50b68a3dSPeyton, Jonathan L     if (j == num_places) {
566*50b68a3dSPeyton, Jonathan L       proc_bind_die(proc_bind, T, P,
567*50b68a3dSPeyton, Jonathan L                     "Thread %d's current place (%d) is not within its "
568*50b68a3dSPeyton, Jonathan L                     "partition [%d, %d]\n",
569*50b68a3dSPeyton, Jonathan L                     i, current_place, first, last);
570*50b68a3dSPeyton, Jonathan L     }
571*50b68a3dSPeyton, Jonathan L   }
572*50b68a3dSPeyton, Jonathan L 
573*50b68a3dSPeyton, Jonathan L   free(partitions);
574*50b68a3dSPeyton, Jonathan L }
575*50b68a3dSPeyton, Jonathan L 
5769982f33eSPeyton, Jonathan L #endif
577