Skip to content
This repository was archived by the owner on Mar 28, 2023. It is now read-only.

Commit adeb4f5

Browse files
authored
[SYCL] add host-task-dependency test (#46)
Signed-off-by: Alexander Flegontov <[email protected]>
1 parent 06d1b04 commit adeb4f5

File tree

2 files changed

+194
-0
lines changed

2 files changed

+194
-0
lines changed

SYCL/Basic/host-task-dependency.cpp

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
// RUN: %clangxx -fsycl -fsycl-targets=%sycl_triple %s -o %t.out %threads_lib
2+
// RUN: %CPU_RUN_PLACEHOLDER SYCL_PI_TRACE=-1 %t.out 2>&1 %CPU_CHECK_PLACEHOLDER
3+
// RUN: %GPU_RUN_PLACEHOLDER SYCL_PI_TRACE=-1 %t.out 2>&1 %GPU_CHECK_PLACEHOLDER
4+
// RUN: %ACC_RUN_PLACEHOLDER SYCL_PI_TRACE=-1 %t.out 2>&1 %ACC_CHECK_PLACEHOLDER
5+
//
6+
// TODO: Behaviour is unstable for level zero on Windows. Enable when fixed.
7+
// UNSUPPORTED: windows && level_zero
8+
9+
#include <atomic>
10+
#include <condition_variable>
11+
#include <future>
12+
#include <mutex>
13+
#include <thread>
14+
15+
#include <CL/sycl.hpp>
16+
17+
namespace S = cl::sycl;
18+
19+
struct Context {
20+
std::atomic_bool Flag;
21+
S::queue &Queue;
22+
S::buffer<int, 1> Buf1;
23+
S::buffer<int, 1> Buf2;
24+
S::buffer<int, 1> Buf3;
25+
std::mutex Mutex;
26+
std::condition_variable CV;
27+
};
28+
29+
void Thread1Fn(Context *Ctx) {
30+
// 0. initialize resulting buffer with apriori wrong result
31+
{
32+
S::accessor<int, 1, S::access::mode::write, S::access::target::host_buffer>
33+
Acc(Ctx->Buf1);
34+
35+
for (size_t Idx = 0; Idx < Acc.get_count(); ++Idx)
36+
Acc[Idx] = -1;
37+
}
38+
39+
{
40+
S::accessor<int, 1, S::access::mode::write, S::access::target::host_buffer>
41+
Acc(Ctx->Buf2);
42+
43+
for (size_t Idx = 0; Idx < Acc.get_count(); ++Idx)
44+
Acc[Idx] = -2;
45+
}
46+
47+
{
48+
S::accessor<int, 1, S::access::mode::write, S::access::target::host_buffer>
49+
Acc(Ctx->Buf3);
50+
51+
for (size_t Idx = 0; Idx < Acc.get_count(); ++Idx)
52+
Acc[Idx] = -3;
53+
}
54+
55+
// 1. submit task writing to buffer 1
56+
Ctx->Queue.submit([&](S::handler &CGH) {
57+
S::accessor<int, 1, S::access::mode::write,
58+
S::access::target::global_buffer>
59+
GeneratorAcc(Ctx->Buf1, CGH);
60+
61+
auto GeneratorKernel = [GeneratorAcc] {
62+
for (size_t Idx = 0; Idx < GeneratorAcc.get_count(); ++Idx)
63+
GeneratorAcc[Idx] = Idx;
64+
};
65+
66+
CGH.single_task<class GeneratorTask>(GeneratorKernel);
67+
});
68+
69+
// 2. submit host task writing from buf 1 to buf 2
70+
auto HostTaskEvent = Ctx->Queue.submit([&](S::handler &CGH) {
71+
S::accessor<int, 1, S::access::mode::read, S::access::target::host_buffer>
72+
CopierSrcAcc(Ctx->Buf1, CGH);
73+
S::accessor<int, 1, S::access::mode::write, S::access::target::host_buffer>
74+
CopierDstAcc(Ctx->Buf2, CGH);
75+
76+
auto CopierHostTask = [CopierSrcAcc, CopierDstAcc, &Ctx] {
77+
for (size_t Idx = 0; Idx < CopierDstAcc.get_count(); ++Idx)
78+
CopierDstAcc[Idx] = CopierSrcAcc[Idx];
79+
80+
bool Expected = false;
81+
bool Desired = true;
82+
assert(Ctx->Flag.compare_exchange_strong(Expected, Desired));
83+
84+
{
85+
std::lock_guard<std::mutex> Lock(Ctx->Mutex);
86+
Ctx->CV.notify_all();
87+
}
88+
};
89+
90+
CGH.codeplay_host_task(CopierHostTask);
91+
});
92+
93+
// 3. submit simple task to move data between two buffers
94+
Ctx->Queue.submit([&](S::handler &CGH) {
95+
S::accessor<int, 1, S::access::mode::read, S::access::target::global_buffer>
96+
SrcAcc(Ctx->Buf2, CGH);
97+
S::accessor<int, 1, S::access::mode::write,
98+
S::access::target::global_buffer>
99+
DstAcc(Ctx->Buf3, CGH);
100+
101+
CGH.depends_on(HostTaskEvent);
102+
103+
auto CopierKernel = [SrcAcc, DstAcc] {
104+
for (size_t Idx = 0; Idx < DstAcc.get_count(); ++Idx)
105+
DstAcc[Idx] = SrcAcc[Idx];
106+
};
107+
108+
CGH.single_task<class CopierTask>(CopierKernel);
109+
});
110+
111+
// 4. check data in buffer #3
112+
{
113+
S::accessor<int, 1, S::access::mode::read, S::access::target::host_buffer>
114+
Acc(Ctx->Buf3);
115+
116+
bool Failure = false;
117+
118+
for (size_t Idx = 0; Idx < Acc.get_count(); ++Idx) {
119+
fprintf(stderr, "Third buffer [%3zu] = %i\n", Idx, Acc[Idx]);
120+
121+
Failure |= (Acc[Idx] != Idx);
122+
}
123+
124+
assert(!Failure && "Invalid data in third buffer");
125+
}
126+
}
127+
128+
void Thread2Fn(Context *Ctx) {
129+
std::unique_lock<std::mutex> Lock(Ctx->Mutex);
130+
131+
// T2.1. Wait until flag F is set eq true.
132+
Ctx->CV.wait(Lock, [Ctx] { return Ctx->Flag.load(); });
133+
134+
assert(Ctx->Flag.load());
135+
}
136+
137+
void test() {
138+
auto EH = [](S::exception_list EL) {
139+
for (const std::exception_ptr &E : EL) {
140+
throw E;
141+
}
142+
};
143+
144+
S::queue Queue(EH);
145+
146+
Context Ctx{{false}, Queue, {10}, {10}, {10}, {}, {}};
147+
148+
// 0. setup: thread 1 T1: exec smth; thread 2 T2: waits; init flag F = false
149+
auto A1 = std::async(std::launch::async, Thread1Fn, &Ctx);
150+
auto A2 = std::async(std::launch::async, Thread2Fn, &Ctx);
151+
152+
A1.get();
153+
A2.get();
154+
155+
assert(Ctx.Flag.load());
156+
157+
// 3. check via host accessor that buf 2 contains valid data
158+
{
159+
S::accessor<int, 1, S::access::mode::read, S::access::target::host_buffer>
160+
ResultAcc(Ctx.Buf2);
161+
162+
bool Failure = false;
163+
for (size_t Idx = 0; Idx < ResultAcc.get_count(); ++Idx) {
164+
fprintf(stderr, "Second buffer [%3zu] = %i\n", Idx, ResultAcc[Idx]);
165+
166+
Failure |= (ResultAcc[Idx] != Idx);
167+
}
168+
169+
assert(!Failure && "Invalid data in result buffer");
170+
}
171+
}
172+
173+
int main() {
174+
test();
175+
176+
return 0;
177+
}
178+
179+
// launch of GeneratorTask kernel
180+
// CHECK:---> piKernelCreate(
181+
// CHECK: GeneratorTask
182+
// CHECK:---> piEnqueueKernelLaunch(
183+
// prepare for host task
184+
// CHECK:---> piEnqueueMemBufferMap(
185+
// launch of CopierTask kernel
186+
// CHECK:---> piKernelCreate(
187+
// CHECK: CopierTask
188+
// CHECK:---> piEnqueueKernelLaunch(
189+
// TODO need to check for piEventsWait as "wait on dependencies of host task".
190+
// At the same time this piEventsWait may occur anywhere after
191+
// piEnqueueMemBufferMap ("prepare for host task").

SYCL/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ if( NOT OpenCL_LIBRARY )
22
find_package(OpenCL)
33
endif()
44

5+
find_package(Threads REQUIRED)
6+
set(SYCL_THREADS_LIB ${CMAKE_THREAD_LIBS_INIT})
7+
58
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in" "${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg")
69

710
if(CHECK_SYCL_ALL)

0 commit comments

Comments
 (0)