1 #ifndef LIBOMP_TEST_TOPOLOGY_H
2 #define LIBOMP_TEST_TOPOLOGY_H
3
4 #include "libomp_test_affinity.h"
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
12 typedef enum topology_obj_type_t {
13 TOPOLOGY_OBJ_THREAD,
14 TOPOLOGY_OBJ_CORE,
15 TOPOLOGY_OBJ_SOCKET,
16 TOPOLOGY_OBJ_MAX
17 } topology_obj_type_t;
18
19 typedef struct place_list_t {
20 int num_places;
21 affinity_mask_t **masks;
22 } place_list_t;
23
24 // Return the first character in file 'f' that is not a whitespace character
25 // including newlines and carriage returns
get_first_nonspace_from_file(FILE * f)26 static int get_first_nonspace_from_file(FILE *f) {
27 int c;
28 do {
29 c = fgetc(f);
30 } while (c != EOF && (isspace(c) || c == '\n' || c == '\r'));
31 return c;
32 }
33
34 // Read an integer from file 'f' into 'number'
35 // Return 1 on successful read of integer,
36 // 0 on unsuccessful read of integer,
37 // EOF on end of file.
get_integer_from_file(FILE * f,int * number)38 static int get_integer_from_file(FILE *f, int *number) {
39 int n;
40 n = fscanf(f, "%d", number);
41 if (feof(f))
42 return EOF;
43 if (n != 1)
44 return 0;
45 return 1;
46 }
47
48 // Read a siblings list file from Linux /sys/devices/system/cpu/cpu?/topology/*
topology_get_mask_from_file(const char * filename)49 static affinity_mask_t *topology_get_mask_from_file(const char *filename) {
50 int status = EXIT_SUCCESS;
51 FILE *f = fopen(filename, "r");
52 if (!f) {
53 perror(filename);
54 exit(EXIT_FAILURE);
55 }
56 affinity_mask_t *mask = affinity_mask_alloc();
57 while (1) {
58 int c, i, n, lower, upper;
59 // Read the first integer
60 n = get_integer_from_file(f, &lower);
61 if (n == EOF) {
62 break;
63 } else if (n == 0) {
64 fprintf(stderr, "syntax error: expected integer\n");
65 status = EXIT_FAILURE;
66 break;
67 }
68
69 // Now either a , or -
70 c = get_first_nonspace_from_file(f);
71 if (c == EOF || c == ',') {
72 affinity_mask_set(mask, lower);
73 if (c == EOF)
74 break;
75 } else if (c == '-') {
76 n = get_integer_from_file(f, &upper);
77 if (n == EOF || n == 0) {
78 fprintf(stderr, "syntax error: expected integer\n");
79 status = EXIT_FAILURE;
80 break;
81 }
82 for (i = lower; i <= upper; ++i)
83 affinity_mask_set(mask, i);
84 c = get_first_nonspace_from_file(f);
85 if (c == EOF) {
86 break;
87 } else if (c == ',') {
88 continue;
89 } else {
90 fprintf(stderr, "syntax error: unexpected character: '%c (%d)'\n", c,
91 c);
92 status = EXIT_FAILURE;
93 break;
94 }
95 } else {
96 fprintf(stderr, "syntax error: unexpected character: '%c (%d)'\n", c, c);
97 status = EXIT_FAILURE;
98 break;
99 }
100 }
101 fclose(f);
102 if (status == EXIT_FAILURE) {
103 affinity_mask_free(mask);
104 mask = NULL;
105 }
106 return mask;
107 }
108
topology_get_num_cpus()109 static int topology_get_num_cpus() {
110 char buf[1024];
111 // Count the number of cpus
112 int cpu = 0;
113 while (1) {
114 snprintf(buf, sizeof(buf), "/sys/devices/system/cpu/cpu%d", cpu);
115 DIR *dir = opendir(buf);
116 if (dir) {
117 closedir(dir);
118 cpu++;
119 } else {
120 break;
121 }
122 }
123 if (cpu == 0)
124 cpu = 1;
125 return cpu;
126 }
127
128 // Return whether the current thread has access to all logical processors
topology_using_full_mask()129 static int topology_using_full_mask() {
130 int cpu;
131 int has_all = 1;
132 int num_cpus = topology_get_num_cpus();
133 affinity_mask_t *mask = affinity_mask_alloc();
134 get_thread_affinity(mask);
135 for (cpu = 0; cpu < num_cpus; ++cpu) {
136 if (!affinity_mask_isset(mask, cpu)) {
137 has_all = 0;
138 break;
139 }
140 }
141 affinity_mask_free(mask);
142 return has_all;
143 }
144
145 // Return array of masks representing OMP_PLACES keyword (e.g., sockets, cores,
146 // threads)
topology_alloc_type_places(topology_obj_type_t type)147 static place_list_t *topology_alloc_type_places(topology_obj_type_t type) {
148 char buf[1024];
149 int i, cpu, num_places, num_unique;
150 int num_cpus = topology_get_num_cpus();
151 place_list_t *places = (place_list_t *)malloc(sizeof(place_list_t));
152 affinity_mask_t **masks =
153 (affinity_mask_t **)malloc(sizeof(affinity_mask_t *) * num_cpus);
154 num_unique = 0;
155 for (cpu = 0; cpu < num_cpus; ++cpu) {
156 affinity_mask_t *mask;
157 if (type == TOPOLOGY_OBJ_CORE) {
158 snprintf(buf, sizeof(buf),
159 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list",
160 cpu);
161 mask = topology_get_mask_from_file(buf);
162 } else if (type == TOPOLOGY_OBJ_SOCKET) {
163 snprintf(buf, sizeof(buf),
164 "/sys/devices/system/cpu/cpu%d/topology/core_siblings_list",
165 cpu);
166 mask = topology_get_mask_from_file(buf);
167 } else if (type == TOPOLOGY_OBJ_THREAD) {
168 mask = affinity_mask_alloc();
169 affinity_mask_set(mask, cpu);
170 } else {
171 fprintf(stderr, "Unknown topology type (%d)\n", (int)type);
172 exit(EXIT_FAILURE);
173 }
174 // Check for unique topology objects above the thread level
175 if (type != TOPOLOGY_OBJ_THREAD) {
176 for (i = 0; i < num_unique; ++i) {
177 if (affinity_mask_equal(masks[i], mask)) {
178 affinity_mask_free(mask);
179 mask = NULL;
180 break;
181 }
182 }
183 }
184 if (mask)
185 masks[num_unique++] = mask;
186 }
187 places->num_places = num_unique;
188 places->masks = masks;
189 return places;
190 }
191
topology_alloc_openmp_places()192 static place_list_t *topology_alloc_openmp_places() {
193 int place, i;
194 int num_places = omp_get_num_places();
195 place_list_t *places = (place_list_t *)malloc(sizeof(place_list_t));
196 affinity_mask_t **masks =
197 (affinity_mask_t **)malloc(sizeof(affinity_mask_t *) * num_places);
198 for (place = 0; place < num_places; ++place) {
199 int num_procs = omp_get_place_num_procs(place);
200 int *ids = (int *)malloc(sizeof(int) * num_procs);
201 omp_get_place_proc_ids(place, ids);
202 affinity_mask_t *mask = affinity_mask_alloc();
203 for (i = 0; i < num_procs; ++i)
204 affinity_mask_set(mask, ids[i]);
205 masks[place] = mask;
206 }
207 places->num_places = num_places;
208 places->masks = masks;
209 return places;
210 }
211
212 // Free the array of masks from one of: topology_alloc_type_masks()
213 // or topology_alloc_openmp_masks()
topology_free_places(place_list_t * places)214 static void topology_free_places(place_list_t *places) {
215 int i;
216 for (i = 0; i < places->num_places; ++i)
217 affinity_mask_free(places->masks[i]);
218 free(places->masks);
219 free(places);
220 }
221
topology_print_places(const place_list_t * p)222 static void topology_print_places(const place_list_t *p) {
223 int i;
224 char buf[1024];
225 for (i = 0; i < p->num_places; ++i) {
226 affinity_mask_snprintf(buf, sizeof(buf), p->masks[i]);
227 printf("Place %d: %s\n", i, buf);
228 }
229 }
230
231 #endif
232