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