1 | // RUN--: %libarcher-compile-and-run | FileCheck %s --check-prefix=NOENV |
2 | // RUN: %libarcher-compile && env ARCHER_OPTIONS="all_memory=1" \ |
3 | // RUN: %libarcher-run | FileCheck %s --check-prefix=ENV |
4 | // REQUIRES: tsan |
5 | |
6 | // The runtime currently does not get dependency information from GCC. |
7 | // UNSUPPORTED: gcc |
8 | |
9 | // Tests OMP 5.x task dependence "omp_all_memory", |
10 | // emulates compiler codegen versions for new dep kind |
11 | // |
12 | // Task tree created: |
13 | // task0 - task1 (in: i1, i2) |
14 | // \ |
15 | // task2 (inoutset: i2), (in: i1) |
16 | // / |
17 | // task3 (omp_all_memory) via flag=0x80 |
18 | // / |
19 | // task4 - task5 (in: i1, i2) |
20 | // / |
21 | // task6 (omp_all_memory) via addr=-1 |
22 | // / |
23 | // task7 (omp_all_memory) via flag=0x80 |
24 | // / |
25 | // task8 (in: i3) |
26 | // |
27 | |
28 | #include <omp.h> |
29 | #include <stdio.h> |
30 | |
31 | #ifdef _WIN32 |
32 | #include <windows.h> |
33 | #define mysleep(n) Sleep(n) |
34 | #else |
35 | #include <unistd.h> |
36 | #define mysleep(n) usleep((n)*1000) |
37 | #endif |
38 | |
39 | // to check the # of concurrent tasks (must be 1 for MTX, <3 for other kinds) |
40 | static int checker = 0; |
41 | static int err = 0; |
42 | #ifndef DELAY |
43 | #define DELAY 100 |
44 | #endif |
45 | |
46 | // --------------------------------------------------------------------------- |
47 | // internal data to emulate compiler codegen |
48 | typedef struct DEP { |
49 | size_t addr; |
50 | size_t len; |
51 | unsigned char flags; |
52 | } dep; |
53 | #define DEP_ALL_MEM 0x80 |
54 | typedef struct task { |
55 | void **shareds; |
56 | void *entry; |
57 | int part_id; |
58 | void *destr_thunk; |
59 | int priority; |
60 | long long device_id; |
61 | int f_priv; |
62 | } task_t; |
63 | #define TIED 1 |
64 | typedef int (*entry_t)(int, task_t *); |
65 | typedef struct ID { |
66 | int reserved_1; |
67 | int flags; |
68 | int reserved_2; |
69 | int reserved_3; |
70 | char *psource; |
71 | } id; |
72 | // thunk routine for tasks with ALL dependency |
73 | int thunk_m(int gtid, task_t *ptask) { |
74 | int lcheck, th; |
75 | #pragma omp atomic capture |
76 | lcheck = ++checker; |
77 | th = omp_get_thread_num(); |
78 | printf(format: "task m_%d, th %d, checker %d\n" , ptask->f_priv, th, lcheck); |
79 | if (lcheck != 1) { // no more than 1 task at a time |
80 | err++; |
81 | printf(format: "Error m1, checker %d != 1\n" , lcheck); |
82 | } |
83 | mysleep(DELAY); |
84 | #pragma omp atomic read |
85 | lcheck = checker; // must still be equal to 1 |
86 | if (lcheck != 1) { |
87 | err++; |
88 | printf(format: "Error m2, checker %d != 1\n" , lcheck); |
89 | } |
90 | #pragma omp atomic |
91 | --checker; |
92 | return 0; |
93 | } |
94 | // thunk routine for tasks with inoutset dependency |
95 | int thunk_s(int gtid, task_t *ptask) { |
96 | int lcheck, th; |
97 | #pragma omp atomic capture |
98 | lcheck = ++checker; // 1 |
99 | th = omp_get_thread_num(); |
100 | printf(format: "task 2_%d, th %d, checker %d\n" , ptask->f_priv, th, lcheck); |
101 | if (lcheck != 1) { // no more than 1 task at a time |
102 | err++; |
103 | printf(format: "Error s1, checker %d != 1\n" , lcheck); |
104 | } |
105 | mysleep(DELAY); |
106 | #pragma omp atomic read |
107 | lcheck = checker; // must still be equal to 1 |
108 | if (lcheck != 1) { |
109 | err++; |
110 | printf(format: "Error s2, checker %d != 1\n" , lcheck); |
111 | } |
112 | #pragma omp atomic |
113 | --checker; |
114 | return 0; |
115 | } |
116 | |
117 | #ifdef __cplusplus |
118 | extern "C" { |
119 | #endif |
120 | int __kmpc_global_thread_num(id *); |
121 | task_t *__kmpc_omp_task_alloc(id *loc, int gtid, int flags, size_t sz, |
122 | size_t shar, entry_t rtn); |
123 | int __kmpc_omp_task_with_deps(id *loc, int gtid, task_t *task, int ndeps, |
124 | dep *dep_lst, int nd_noalias, dep *noalias_lst); |
125 | static id loc = {.reserved_1: 0, .flags: 2, .reserved_2: 0, .reserved_3: 0, .psource: ";file;func;0;0;;" }; |
126 | #ifdef __cplusplus |
127 | } // extern "C" |
128 | #endif |
129 | // End of internal data |
130 | // --------------------------------------------------------------------------- |
131 | |
132 | int main() { |
133 | char *ompx_all_memory = (void *)0xffffffffffffffff; |
134 | int i1, i2, i3; |
135 | omp_set_num_threads(8); |
136 | omp_set_dynamic(0); |
137 | #pragma omp parallel |
138 | { |
139 | #pragma omp single nowait |
140 | { |
141 | dep sdep[2]; |
142 | task_t *ptr; |
143 | int gtid = __kmpc_global_thread_num(&loc); |
144 | int t = omp_get_thread_num(); |
145 | #pragma omp task depend(in : i1, i2) |
146 | { // task 0 |
147 | int lcheck, th; |
148 | #pragma omp atomic capture |
149 | lcheck = ++checker; // 1 or 2 |
150 | th = omp_get_thread_num(); |
151 | printf(format: "task 0_%d, th %d, checker %d\n" , t, th, lcheck); |
152 | if (lcheck > 2 || lcheck < 1) { |
153 | err++; // no more than 2 tasks concurrently |
154 | printf(format: "Error1, checker %d, not 1 or 2\n" , lcheck); |
155 | } |
156 | mysleep(DELAY); |
157 | #pragma omp atomic read |
158 | lcheck = checker; // 1 or 2 |
159 | if (lcheck > 2 || lcheck < 1) { |
160 | #pragma omp atomic |
161 | err++; |
162 | printf(format: "Error2, checker %d, not 1 or 2\n" , lcheck); |
163 | } |
164 | #pragma omp atomic |
165 | --checker; |
166 | } |
167 | #pragma omp task depend(in : i1, i2) |
168 | { // task 1 |
169 | int lcheck, th; |
170 | #pragma omp atomic capture |
171 | lcheck = ++checker; // 1 or 2 |
172 | th = omp_get_thread_num(); |
173 | printf(format: "task 1_%d, th %d, checker %d\n" , t, th, lcheck); |
174 | if (lcheck > 2 || lcheck < 1) { |
175 | err++; // no more than 2 tasks concurrently |
176 | printf(format: "Error3, checker %d, not 1 or 2\n" , lcheck); |
177 | } |
178 | mysleep(DELAY); |
179 | #pragma omp atomic read |
180 | lcheck = checker; // 1 or 2 |
181 | if (lcheck > 2 || lcheck < 1) { |
182 | err++; |
183 | printf(format: "Error4, checker %d, not 1 or 2\n" , lcheck); |
184 | } |
185 | #pragma omp atomic |
186 | --checker; |
187 | } |
188 | // compiler codegen start |
189 | // task2 |
190 | ptr = __kmpc_omp_task_alloc(loc: &loc, gtid, TIED, sz: sizeof(task_t), shar: 0, rtn: thunk_s); |
191 | sdep[0].addr = (size_t)&i1; |
192 | sdep[0].len = 0; // not used |
193 | sdep[0].flags = 1; // IN |
194 | sdep[1].addr = (size_t)&i2; |
195 | sdep[1].len = 0; // not used |
196 | sdep[1].flags = 8; // INOUTSET |
197 | ptr->f_priv = t + 10; // init single first-private variable |
198 | __kmpc_omp_task_with_deps(loc: &loc, gtid, task: ptr, ndeps: 2, dep_lst: sdep, nd_noalias: 0, noalias_lst: 0); |
199 | |
200 | // task3 |
201 | #pragma omp task depend(in : i1) depend(inout : ompx_all_memory[0]) |
202 | { |
203 | int lcheck, th; |
204 | #pragma omp atomic capture |
205 | lcheck = ++checker; |
206 | th = omp_get_thread_num(); |
207 | printf(format: "task 3_%d, th %d, checker %d\n" , t, th, lcheck); |
208 | if (lcheck != 1) { // no more than 1 task at a time |
209 | err++; |
210 | printf(format: "Error m1, checker %d != 1\n" , lcheck); |
211 | } |
212 | mysleep(DELAY); |
213 | #pragma omp atomic read |
214 | lcheck = checker; // must still be equal to 1 |
215 | if (lcheck != 1) { |
216 | err++; |
217 | printf(format: "Error m2, checker %d != 1\n" , lcheck); |
218 | } |
219 | #pragma omp atomic |
220 | --checker; |
221 | } |
222 | // compiler codegen end |
223 | #pragma omp task depend(in : i1, i2) |
224 | { // task 4 |
225 | int lcheck, th; |
226 | #pragma omp atomic capture |
227 | lcheck = ++checker; // 1 or 2 |
228 | th = omp_get_thread_num(); |
229 | printf(format: "task 4_%d, th %d, checker %d\n" , t, th, lcheck); |
230 | if (lcheck > 2 || lcheck < 1) { |
231 | err++; // no more than 2 tasks concurrently |
232 | printf(format: "Error5, checker %d, not 1 or 2\n" , lcheck); |
233 | } |
234 | mysleep(DELAY); |
235 | #pragma omp atomic read |
236 | lcheck = checker; // 1 or 2 |
237 | if (lcheck > 2 || lcheck < 1) { |
238 | err++; |
239 | printf(format: "Error6, checker %d, not 1 or 2\n" , lcheck); |
240 | } |
241 | #pragma omp atomic |
242 | --checker; |
243 | } |
244 | #pragma omp task depend(in : i1, i2) |
245 | { // task 5 |
246 | int lcheck, th; |
247 | #pragma omp atomic capture |
248 | lcheck = ++checker; // 1 or 2 |
249 | th = omp_get_thread_num(); |
250 | printf(format: "task 5_%d, th %d, checker %d\n" , t, th, lcheck); |
251 | if (lcheck > 2 || lcheck < 1) { |
252 | err++; // no more than 2 tasks concurrently |
253 | printf(format: "Error7, checker %d, not 1 or 2\n" , lcheck); |
254 | } |
255 | mysleep(DELAY); |
256 | #pragma omp atomic read |
257 | lcheck = checker; // 1 or 2 |
258 | if (lcheck > 2 || lcheck < 1) { |
259 | err++; |
260 | printf(format: "Error8, checker %d, not 1 or 2\n" , lcheck); |
261 | } |
262 | #pragma omp atomic |
263 | --checker; |
264 | } |
265 | // task6 |
266 | #pragma omp task depend(inout : ompx_all_memory[0]) |
267 | { |
268 | int lcheck, th; |
269 | #pragma omp atomic capture |
270 | lcheck = ++checker; |
271 | th = omp_get_thread_num(); |
272 | printf(format: "task 6_%d, th %d, checker %d\n" , t, th, lcheck); |
273 | if (lcheck != 1) { // no more than 1 task at a time |
274 | err++; |
275 | printf(format: "Error m1, checker %d != 1\n" , lcheck); |
276 | } |
277 | mysleep(DELAY); |
278 | #pragma omp atomic read |
279 | lcheck = checker; // must still be equal to 1 |
280 | if (lcheck != 1) { |
281 | err++; |
282 | printf(format: "Error m2, checker %d != 1\n" , lcheck); |
283 | } |
284 | #pragma omp atomic |
285 | --checker; |
286 | } |
287 | // task7 |
288 | #pragma omp task depend(inout : ompx_all_memory[0]) depend(mutexinoutset : i3) |
289 | { |
290 | int lcheck, th; |
291 | #pragma omp atomic capture |
292 | lcheck = ++checker; |
293 | th = omp_get_thread_num(); |
294 | printf(format: "task 7_%d, th %d, checker %d\n" , t, th, lcheck); |
295 | if (lcheck != 1) { // no more than 1 task at a time |
296 | err++; |
297 | printf(format: "Error m1, checker %d != 1\n" , lcheck); |
298 | } |
299 | mysleep(DELAY); |
300 | #pragma omp atomic read |
301 | lcheck = checker; // must still be equal to 1 |
302 | if (lcheck != 1) { |
303 | err++; |
304 | printf(format: "Error m2, checker %d != 1\n" , lcheck); |
305 | } |
306 | #pragma omp atomic |
307 | --checker; |
308 | } |
309 | #pragma omp task depend(in : i3) |
310 | { // task 8 |
311 | int lcheck, th; |
312 | #pragma omp atomic capture |
313 | lcheck = ++checker; // 1 |
314 | th = omp_get_thread_num(); |
315 | printf(format: "task 8_%d, th %d, checker %d\n" , t, th, lcheck); |
316 | if (lcheck != 1) { |
317 | err++; |
318 | printf(format: "Error9, checker %d, != 1\n" , lcheck); |
319 | } |
320 | mysleep(DELAY); |
321 | #pragma omp atomic read |
322 | lcheck = checker; |
323 | if (lcheck != 1) { |
324 | err++; |
325 | printf(format: "Error10, checker %d, != 1\n" , lcheck); |
326 | } |
327 | #pragma omp atomic |
328 | --checker; |
329 | } |
330 | } // single |
331 | } // parallel |
332 | if (err == 0 && checker == 0) { |
333 | printf(format: "passed\n" ); |
334 | return 0; |
335 | } else { |
336 | printf(format: "failed, err = %d, checker = %d\n" , err, checker); |
337 | return 1; |
338 | } |
339 | } |
340 | |
341 | // NOENV-NOT: ThreadSanitizer: data race |
342 | // NOENV-NOT: ThreadSanitizer: reported |
343 | // NOENV: omp_all_memory |
344 | // NOENV-NOT: ThreadSanitizer: data race |
345 | // NOENV-NOT: ThreadSanitizer: reported |
346 | // NOENV: passed |
347 | |
348 | // ENV-NOT: ThreadSanitizer: data race |
349 | // ENV-NOT: ThreadSanitizer: reported |
350 | // ENV: passed |
351 | |