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)
40static int checker = 0;
41static int err = 0;
42#ifndef DELAY
43#define DELAY 100
44#endif
45
46// ---------------------------------------------------------------------------
47// internal data to emulate compiler codegen
48typedef struct DEP {
49 size_t addr;
50 size_t len;
51 unsigned char flags;
52} dep;
53#define DEP_ALL_MEM 0x80
54typedef 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
64typedef int (*entry_t)(int, task_t *);
65typedef 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
73int 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
95int 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
118extern "C" {
119#endif
120int __kmpc_global_thread_num(id *);
121task_t *__kmpc_omp_task_alloc(id *loc, int gtid, int flags, size_t sz,
122 size_t shar, entry_t rtn);
123int __kmpc_omp_task_with_deps(id *loc, int gtid, task_t *task, int ndeps,
124 dep *dep_lst, int nd_noalias, dep *noalias_lst);
125static 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
132int 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

source code of openmp/tools/archer/tests/task/omp_task_depend_all.c