Skip to content

Commit 9089b4a

Browse files
author
Peyton, Jonathan L
committed
[OpenMP] Introduce GOMP taskwait depend in the runtime
This change introduces the GOMP_taskwait_depend() function. It implements the OpenMP 5.0 feature of #pragma omp taskwait with depend() clause by wrapping around __kmpc_omp_wait_deps(). Differential Revision: https://reviews.llvm.org/D87269
1 parent 72ada5a commit 9089b4a

File tree

3 files changed

+123
-0
lines changed

3 files changed

+123
-0
lines changed

openmp/runtime/src/kmp_ftn_os.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,5 +680,6 @@
680680
#define KMP_API_NAME_GOMP_PARALLEL_LOOP_MAYBE_NONMONOTONIC_RUNTIME \
681681
GOMP_parallel_loop_maybe_nonmonotonic_runtime
682682
#define KMP_API_NAME_GOMP_TEAMS_REG GOMP_teams_reg
683+
#define KMP_API_NAME_GOMP_TASKWAIT_DEPEND GOMP_taskwait_depend
683684

684685
#endif /* KMP_FTN_OS_H */

openmp/runtime/src/kmp_gsupport.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1867,6 +1867,19 @@ void KMP_EXPAND_NAME(KMP_API_NAME_GOMP_TEAMS_REG)(void (*fn)(void *),
18671867
KA_TRACE(20, ("GOMP_teams_reg exit: T#%d\n", gtid));
18681868
}
18691869

1870+
void KMP_EXPAND_NAME(KMP_API_NAME_GOMP_TASKWAIT_DEPEND)(void **depend) {
1871+
MKLOC(loc, "GOMP_taskwait_depend");
1872+
int gtid = __kmp_entry_gtid();
1873+
KA_TRACE(20, ("GOMP_taskwait_depend: T#%d\n", gtid));
1874+
kmp_gomp_depends_info_t gomp_depends(depend);
1875+
kmp_int32 ndeps = gomp_depends.get_num_deps();
1876+
kmp_depend_info_t dep_list[ndeps];
1877+
for (kmp_int32 i = 0; i < ndeps; i++)
1878+
dep_list[i] = gomp_depends.get_kmp_depend(i);
1879+
__kmpc_omp_wait_deps(&loc, gtid, ndeps, dep_list, 0, NULL);
1880+
KA_TRACE(20, ("GOMP_taskwait_depend exit: T#%d\n", gtid));
1881+
}
1882+
18701883
/* The following sections of code create aliases for the GOMP_* functions, then
18711884
create versioned symbols using the assembler directive .symver. This is only
18721885
pertinent for ELF .so library. The KMP_VERSION_SYMBOL macro is defined in
@@ -2039,6 +2052,7 @@ KMP_VERSION_SYMBOL(KMP_API_NAME_GOMP_PARALLEL_LOOP_NONMONOTONIC_RUNTIME, 50,
20392052
KMP_VERSION_SYMBOL(KMP_API_NAME_GOMP_PARALLEL_LOOP_MAYBE_NONMONOTONIC_RUNTIME,
20402053
50, "GOMP_5.0");
20412054
KMP_VERSION_SYMBOL(KMP_API_NAME_GOMP_TEAMS_REG, 50, "GOMP_5.0");
2055+
KMP_VERSION_SYMBOL(KMP_API_NAME_GOMP_TASKWAIT_DEPEND, 50, "GOMP_5.0");
20422056

20432057
#endif // KMP_USE_VERSION_SYMBOLS
20442058

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// RUN: %libomp-compile-and-run
2+
// UNSUPPORTED: gcc-4, gcc-5, gcc-6, gcc-7, gcc-8
3+
// clang does not yet support taskwait with depend clause
4+
// clang-12 introduced parsing, but no codegen
5+
// TODO: update expected result when codegen in clang is added
6+
// icc does not yet support taskwait with depend clause
7+
// TODO: update expected result when support for icc is added
8+
// XFAIL: clang, icc
9+
10+
#include <stdio.h>
11+
#include <stdlib.h>
12+
#include <omp.h>
13+
#include "omp_my_sleep.h"
14+
15+
int a = 0, b = 0;
16+
int task_grabbed = 0, task_can_proceed = 0;
17+
int task2_grabbed = 0, task2_can_proceed = 0;
18+
19+
static void wait_on_flag(int *flag) {
20+
int flag_value;
21+
int timelimit = 30;
22+
int secs = 0;
23+
do {
24+
#pragma omp atomic read
25+
flag_value = *flag;
26+
my_sleep(1.0);
27+
secs++;
28+
if (secs == timelimit) {
29+
fprintf(stderr, "error: timeout in wait_on_flag()\n");
30+
exit(EXIT_FAILURE);
31+
}
32+
} while (flag_value == 0);
33+
}
34+
35+
static void signal_flag(int *flag) {
36+
#pragma omp atomic
37+
(*flag)++;
38+
}
39+
40+
int main(int argc, char** argv) {
41+
42+
// Ensure two threads are running
43+
int num_threads = omp_get_max_threads();
44+
if (num_threads < 2)
45+
omp_set_num_threads(2);
46+
47+
#pragma omp parallel shared(a)
48+
{
49+
int a_value;
50+
// Let us be extra safe here
51+
if (omp_get_num_threads() > 1) {
52+
#pragma omp single nowait
53+
{
54+
// Schedule independent child task that
55+
// waits to be flagged after sebsequent taskwait depend()
56+
#pragma omp task
57+
{
58+
signal_flag(&task_grabbed);
59+
wait_on_flag(&task_can_proceed);
60+
}
61+
// Let another worker thread grab the task to execute
62+
wait_on_flag(&task_grabbed);
63+
// This should be ignored since the task above has
64+
// no dependency information
65+
#pragma omp taskwait depend(inout: a)
66+
// Signal the independent task to proceed
67+
signal_flag(&task_can_proceed);
68+
69+
// Schedule child task with dependencies that taskwait does
70+
// not care about
71+
#pragma omp task depend(inout: b)
72+
{
73+
signal_flag(&task2_grabbed);
74+
wait_on_flag(&task2_can_proceed);
75+
#pragma omp atomic
76+
b++;
77+
}
78+
// Let another worker thread grab the task to execute
79+
wait_on_flag(&task2_grabbed);
80+
// This should be ignored since the task above has
81+
// dependency information on b instead of a
82+
#pragma omp taskwait depend(inout: a)
83+
// Signal the task to proceed
84+
signal_flag(&task2_can_proceed);
85+
86+
// Generate one child task for taskwait
87+
#pragma omp task shared(a) depend(inout: a)
88+
{
89+
my_sleep(1.0);
90+
#pragma omp atomic
91+
a++;
92+
}
93+
#pragma omp taskwait depend(inout: a)
94+
95+
#pragma omp atomic read
96+
a_value = a;
97+
98+
if (a_value != 1) {
99+
fprintf(stderr, "error: dependent task was not executed before "
100+
"taskwait finished\n");
101+
exit(EXIT_FAILURE);
102+
}
103+
} // #pragma omp single
104+
} // if (num_threads > 1)
105+
} // #pragma omp parallel
106+
107+
return EXIT_SUCCESS;
108+
}

0 commit comments

Comments
 (0)