Skip to content

Commit 72ada5a

Browse files
author
Peyton, Jonathan L
committed
[OpenMP] Introduce GOMP mutexinoutset in the runtime
Encapsulate GOMP task dependencies in separate class and introduce the new mutexinoutset dependency type. This separate class allows future GOMP task APIs easier access to the task dependency functionality and better ability to propagate new dependency types to all existing GOMP task APIs which use task dependencies. Differential Revision: https://reviews.llvm.org/D87267
1 parent ea34d95 commit 72ada5a

File tree

3 files changed

+168
-9
lines changed

3 files changed

+168
-9
lines changed

openmp/runtime/src/i18n/en_US.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ AffHWSubsetManyProcs "KMP_HW_SUBSET ignored: too many Procs requested."
426426
HierSchedInvalid "Hierarchy ignored: unsupported level: %1$s."
427427
AffFormatDefault "OMP: pid %1$s tid %2$s thread %3$s bound to OS proc set {%4$s}"
428428
APIDeprecated "%1$s routine deprecated, please use %2$s instead."
429+
GompFeatureNotSupported "libgomp compatibility layer does not support OpenMP feature: %1$s"
429430

430431
# --------------------------------------------------------------------------------------------------
431432
-*- HINTS -*-

openmp/runtime/src/kmp_gsupport.cpp

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,67 @@
1717
#include "ompt-specific.h"
1818
#endif
1919

20+
// This class helps convert gomp dependency info into
21+
// kmp_depend_info_t structures
22+
class kmp_gomp_depends_info_t {
23+
void **depend;
24+
kmp_int32 num_deps;
25+
size_t num_out, num_mutexinout, num_in;
26+
size_t offset;
27+
28+
public:
29+
kmp_gomp_depends_info_t(void **depend) : depend(depend) {
30+
size_t ndeps = (kmp_intptr_t)depend[0];
31+
size_t num_doable;
32+
// GOMP taskdep structure:
33+
// if depend[0] != 0:
34+
// depend = [ ndeps | nout | &out | ... | &out | &in | ... | &in ]
35+
//
36+
// if depend[0] == 0:
37+
// depend = [ 0 | ndeps | nout | nmtx | nin | &out | ... | &out | &mtx |
38+
// ... | &mtx | &in | ... | &in | &depobj | ... | &depobj ]
39+
if (ndeps) {
40+
num_out = (kmp_intptr_t)depend[1];
41+
num_in = ndeps - num_out;
42+
num_mutexinout = 0;
43+
num_doable = ndeps;
44+
offset = 2;
45+
} else {
46+
ndeps = (kmp_intptr_t)depend[1];
47+
num_out = (kmp_intptr_t)depend[2];
48+
num_mutexinout = (kmp_intptr_t)depend[3];
49+
num_in = (kmp_intptr_t)depend[4];
50+
num_doable = num_out + num_mutexinout + num_in;
51+
offset = 5;
52+
}
53+
// TODO: Support gomp depobj
54+
if (ndeps != num_doable) {
55+
KMP_FATAL(GompFeatureNotSupported, "depobj");
56+
}
57+
num_deps = static_cast<kmp_int32>(ndeps);
58+
}
59+
kmp_int32 get_num_deps() const { return num_deps; }
60+
kmp_depend_info_t get_kmp_depend(size_t index) const {
61+
kmp_depend_info_t retval;
62+
memset(&retval, '\0', sizeof(retval));
63+
KMP_ASSERT(index < (size_t)num_deps);
64+
retval.base_addr = (kmp_intptr_t)depend[offset + index];
65+
retval.len = 0;
66+
// Because inout and out are logically equivalent,
67+
// use inout and in dependency flags. GOMP does not provide a
68+
// way to distinguish if user specified out vs. inout.
69+
if (index < num_out) {
70+
retval.flags.in = 1;
71+
retval.flags.out = 1;
72+
} else if (index >= num_out && index < (num_out + num_mutexinout)) {
73+
retval.flags.mtx = 1;
74+
} else {
75+
retval.flags.in = 1;
76+
}
77+
return retval;
78+
}
79+
};
80+
2081
#ifdef __cplusplus
2182
extern "C" {
2283
#endif // __cplusplus
@@ -1164,16 +1225,11 @@ void KMP_EXPAND_NAME(KMP_API_NAME_GOMP_TASK)(void (*func)(void *), void *data,
11641225
if (if_cond) {
11651226
if (gomp_flags & 8) {
11661227
KMP_ASSERT(depend);
1167-
const size_t ndeps = (kmp_intptr_t)depend[0];
1168-
const size_t nout = (kmp_intptr_t)depend[1];
1228+
kmp_gomp_depends_info_t gomp_depends(depend);
1229+
kmp_int32 ndeps = gomp_depends.get_num_deps();
11691230
kmp_depend_info_t dep_list[ndeps];
1170-
1171-
for (size_t i = 0U; i < ndeps; i++) {
1172-
dep_list[i].base_addr = (kmp_intptr_t)depend[2U + i];
1173-
dep_list[i].len = 0U;
1174-
dep_list[i].flags.in = 1;
1175-
dep_list[i].flags.out = (i < nout);
1176-
}
1231+
for (kmp_int32 i = 0; i < ndeps; i++)
1232+
dep_list[i] = gomp_depends.get_kmp_depend(i);
11771233
__kmpc_omp_task_with_deps(&loc, gtid, task, ndeps, dep_list, 0, NULL);
11781234
} else {
11791235
__kmpc_omp_task(&loc, gtid, task);
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// RUN: %libomp-compile-and-run
2+
// UNSUPPORTED: gcc-4, gcc-5, gcc-6, gcc-7, gcc-8
3+
// UNSUPPORTED: clang-3, clang-4, clang-5, clang-6, clang-7, clang-8
4+
// TODO: update expected result when icc supports mutexinoutset
5+
// XFAIL: icc
6+
7+
// Tests OMP 5.0 task dependences "mutexinoutset", emulates compiler codegen
8+
// Mutually exclusive tasks get same input dependency info array
9+
//
10+
// Task tree created:
11+
// task0 task1
12+
// \ / \
13+
// task2 task5
14+
// / \
15+
// task3 task4
16+
// / \
17+
// task6 <-->task7 (these two are mutually exclusive)
18+
// \ /
19+
// task8
20+
//
21+
#include <stdio.h>
22+
#include <omp.h>
23+
#include "omp_my_sleep.h"
24+
25+
static int checker = 0; // to check if two tasks run simultaneously
26+
static int err = 0;
27+
#ifndef DELAY
28+
#define DELAY 0.1
29+
#endif
30+
31+
int mutex_task(int task_id) {
32+
int th = omp_get_thread_num();
33+
#pragma omp atomic
34+
++checker;
35+
printf("task %d, th %d\n", task_id, th);
36+
if (checker != 1) {
37+
err++;
38+
printf("Error1, checker %d != 1\n", checker);
39+
}
40+
my_sleep(DELAY);
41+
if (checker != 1) {
42+
err++;
43+
printf("Error2, checker %d != 1\n", checker);
44+
}
45+
#pragma omp atomic
46+
--checker;
47+
return 0;
48+
}
49+
50+
int main()
51+
{
52+
int i1,i2,i3,i4;
53+
omp_set_num_threads(2);
54+
#pragma omp parallel
55+
{
56+
#pragma omp single nowait
57+
{
58+
int t = omp_get_thread_num();
59+
#pragma omp task depend(in: i1, i2)
60+
{ int th = omp_get_thread_num();
61+
printf("task 0_%d, th %d\n", t, th);
62+
my_sleep(DELAY); }
63+
#pragma omp task depend(in: i1, i3)
64+
{ int th = omp_get_thread_num();
65+
printf("task 1_%d, th %d\n", t, th);
66+
my_sleep(DELAY); }
67+
#pragma omp task depend(in: i2) depend(out: i1)
68+
{ int th = omp_get_thread_num();
69+
printf("task 2_%d, th %d\n", t, th);
70+
my_sleep(DELAY); }
71+
#pragma omp task depend(in: i1)
72+
{ int th = omp_get_thread_num();
73+
printf("task 3_%d, th %d\n", t, th);
74+
my_sleep(DELAY); }
75+
#pragma omp task depend(out: i2)
76+
{ int th = omp_get_thread_num();
77+
printf("task 4_%d, th %d\n", t, th);
78+
my_sleep(DELAY+0.1); } // wait a bit longer than task 3
79+
#pragma omp task depend(out: i3)
80+
{ int th = omp_get_thread_num();
81+
printf("task 5_%d, th %d\n", t, th);
82+
my_sleep(DELAY); }
83+
84+
#pragma omp task depend(mutexinoutset: i1, i4)
85+
{ mutex_task(6); }
86+
#pragma omp task depend(mutexinoutset: i1, i4)
87+
{ mutex_task(7); }
88+
89+
#pragma omp task depend(in: i1)
90+
{ int th = omp_get_thread_num();
91+
printf("task 8_%d, th %d\n", t, th);
92+
my_sleep(DELAY); }
93+
} // single
94+
} // parallel
95+
if (err == 0) {
96+
printf("passed\n");
97+
return 0;
98+
} else {
99+
printf("failed\n");
100+
return 1;
101+
}
102+
}

0 commit comments

Comments
 (0)