xref: /llvm-project/openmp/tools/archer/tests/task/omp_task_depend_all.c (revision 73d411d1b2c9c842bbaa167606720fed6ffc2243)
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
thunk_m(int gtid,task_t * ptask)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("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("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("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
thunk_s(int gtid,task_t * ptask)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("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("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("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 = {0, 2, 0, 0, ";file;func;0;0;;"};
126 #ifdef __cplusplus
127 } // extern "C"
128 #endif
129 // End of internal data
130 // ---------------------------------------------------------------------------
131 
main()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("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("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("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("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("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("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, gtid, TIED, sizeof(task_t), 0, 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, gtid, ptr, 2, sdep, 0, 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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("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("task 8_%d, th %d, checker %d\n", t, th, lcheck);
316         if (lcheck != 1) {
317           err++;
318           printf("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("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("passed\n");
334     return 0;
335   } else {
336     printf("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