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