Skip to content

Commit 0ab7cd2

Browse files
Add unit tests
1 parent eaabc1f commit 0ab7cd2

File tree

2 files changed

+211
-0
lines changed

2 files changed

+211
-0
lines changed

sycl/unittests/queue/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
add_sycl_unittest(QueueTests OBJECT
22
EventClear.cpp
3+
Wait.cpp
34
)

sycl/unittests/queue/Wait.cpp

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
//==--------------------- Wait.cpp --- queue unit tests --------------------==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include <CL/sycl.hpp>
10+
#include <detail/event_impl.hpp>
11+
#include <detail/scheduler/commands.hpp>
12+
#include <gtest/gtest.h>
13+
#include <helpers/PiMock.hpp>
14+
15+
#include <memory>
16+
17+
namespace {
18+
using namespace cl::sycl;
19+
20+
struct TestCtx {
21+
bool SupportOOO = true;
22+
bool PiQueueFinishCalled = false;
23+
int NEventsWaitedFor = 0;
24+
int EventReferenceCount = 0;
25+
};
26+
static TestCtx TestContext;
27+
28+
pi_result redefinedQueueCreate(pi_context context, pi_device device,
29+
pi_queue_properties properties,
30+
pi_queue *queue) {
31+
if (!TestContext.SupportOOO &&
32+
properties & PI_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE) {
33+
return PI_INVALID_QUEUE_PROPERTIES;
34+
}
35+
return PI_SUCCESS;
36+
}
37+
38+
pi_result redefinedQueueRelease(pi_queue Queue) { return PI_SUCCESS; }
39+
40+
pi_result redefinedUSMEnqueueMemset(pi_queue Queue, void *Ptr, pi_int32 Value,
41+
size_t Count,
42+
pi_uint32 Num_events_in_waitlist,
43+
const pi_event *Events_waitlist,
44+
pi_event *Event) {
45+
// Provide a dummy non-nullptr value
46+
TestContext.EventReferenceCount = 1;
47+
*Event = reinterpret_cast<pi_event>(1);
48+
return PI_SUCCESS;
49+
}
50+
pi_result redefinedEnqueueMemBufferFill(pi_queue Queue, pi_mem Buffer,
51+
const void *Pattern, size_t PatternSize,
52+
size_t Offset, size_t Size,
53+
pi_uint32 NumEventsInWaitList,
54+
const pi_event *EventWaitList,
55+
pi_event *Event) {
56+
// Provide a dummy non-nullptr value
57+
TestContext.EventReferenceCount = 1;
58+
*Event = reinterpret_cast<pi_event>(1);
59+
return PI_SUCCESS;
60+
}
61+
62+
pi_result redefinedQueueFinish(pi_queue Queue) {
63+
TestContext.PiQueueFinishCalled = true;
64+
return PI_SUCCESS;
65+
}
66+
pi_result redefinedEventsWait(pi_uint32 num_events,
67+
const pi_event *event_list) {
68+
++TestContext.NEventsWaitedFor;
69+
return PI_SUCCESS;
70+
}
71+
72+
pi_result redefinedEventGetInfo(pi_event event, pi_event_info param_name,
73+
size_t param_value_size, void *param_value,
74+
size_t *param_value_size_ret) {
75+
#if 0
76+
EXPECT_EQ(param_name, PI_EVENT_INFO_COMMAND_EXECUTION_STATUS)
77+
<< "Unexpected event info requested";
78+
// Report first half of events as complete.
79+
// Report second half of events as running.
80+
// This is important, because removal algorithm assumes that
81+
// events are likely to be removed oldest first, and stops removing
82+
// at the first non-completed event.
83+
static int Counter = 0;
84+
auto *Result = reinterpret_cast<pi_event_status *>(param_value);
85+
*Result = (Counter < (ExpectedEventThreshold / 2)) ? PI_EVENT_COMPLETE
86+
: PI_EVENT_RUNNING;
87+
Counter++;
88+
#endif
89+
return PI_SUCCESS;
90+
}
91+
92+
pi_result redefinedEventRetain(pi_event event) {
93+
++TestContext.EventReferenceCount;
94+
return PI_SUCCESS;
95+
}
96+
97+
pi_result redefinedEventRelease(pi_event event) {
98+
--TestContext.EventReferenceCount;
99+
return PI_SUCCESS;
100+
}
101+
102+
bool preparePiMock(platform &Plt) {
103+
if (Plt.is_host()) {
104+
std::cout << "Not run on host - no PI events created in that case"
105+
<< std::endl;
106+
return false;
107+
}
108+
// TODO: Skip tests for CUDA temporarily
109+
if (detail::getSyclObjImpl(Plt)->getPlugin().getBackend() == backend::cuda) {
110+
std::cout << "Not run on CUDA - usm is not supported for CUDA backend yet"
111+
<< std::endl;
112+
return false;
113+
}
114+
115+
unittest::PiMock Mock{Plt};
116+
Mock.redefine<detail::PiApiKind::piQueueCreate>(redefinedQueueCreate);
117+
Mock.redefine<detail::PiApiKind::piQueueRelease>(redefinedQueueRelease);
118+
Mock.redefine<detail::PiApiKind::piQueueFinish>(redefinedQueueFinish);
119+
Mock.redefine<detail::PiApiKind::piextUSMEnqueueMemset>(
120+
redefinedUSMEnqueueMemset);
121+
Mock.redefine<detail::PiApiKind::piEventsWait>(redefinedEventsWait);
122+
Mock.redefine<detail::PiApiKind::piEnqueueMemBufferFill>(
123+
redefinedEnqueueMemBufferFill);
124+
Mock.redefine<detail::PiApiKind::piEventGetInfo>(redefinedEventGetInfo);
125+
Mock.redefine<detail::PiApiKind::piEventRetain>(redefinedEventRetain);
126+
Mock.redefine<detail::PiApiKind::piEventRelease>(redefinedEventRelease);
127+
return true;
128+
}
129+
130+
TEST(QueueWait, Finish) {
131+
platform Plt{default_selector()};
132+
if (!preparePiMock(Plt))
133+
return;
134+
context Ctx{Plt};
135+
queue Q{Ctx, default_selector()};
136+
137+
unsigned char *HostAlloc = (unsigned char *)malloc_host(1, Ctx);
138+
139+
// USM API event
140+
TestContext = {};
141+
Q.memset(HostAlloc, 42, 1);
142+
// No need to keep the event since we'll use piQueueFinish.
143+
ASSERT_EQ(TestContext.EventReferenceCount, 0);
144+
Q.wait();
145+
ASSERT_EQ(TestContext.NEventsWaitedFor, 0);
146+
ASSERT_TRUE(TestContext.PiQueueFinishCalled);
147+
148+
// Events with temporary ownership
149+
{
150+
TestContext = {};
151+
buffer<int, 1> buf{range<1>(1)};
152+
Q.submit([&](handler &Cgh) {
153+
auto acc = buf.template get_access<access::mode::read_write>(Cgh);
154+
Cgh.fill(acc, 42);
155+
});
156+
Q.wait();
157+
// Still owned by the execution graph
158+
ASSERT_EQ(TestContext.EventReferenceCount, 1);
159+
ASSERT_EQ(TestContext.NEventsWaitedFor, 0);
160+
ASSERT_TRUE(TestContext.PiQueueFinishCalled);
161+
}
162+
163+
// Blocked commands
164+
TestContext = {};
165+
buffer<int, 1> buf{range<1>(1)};
166+
event HostTaskEvent = Q.submit([&](handler &Cgh) {
167+
auto acc = buf.template get_access<access::mode::read>(Cgh);
168+
Cgh.host_task([=]() { (void)acc; });
169+
});
170+
std::shared_ptr<detail::event_impl> HostTaskEventImpl =
171+
detail::getSyclObjImpl(HostTaskEvent);
172+
auto *Cmd = static_cast<detail::Command *>(HostTaskEventImpl->getCommand());
173+
detail::Command *EmptyTask = *Cmd->MUsers.begin();
174+
ASSERT_EQ(EmptyTask->getType(), detail::Command::EMPTY_TASK);
175+
HostTaskEvent.wait();
176+
// Use the empty task produced by the host task to block the next commands
177+
while (EmptyTask->MEnqueueStatus !=
178+
detail::EnqueueResultT::SyclEnqueueSuccess)
179+
continue;
180+
EmptyTask->MEnqueueStatus = detail::EnqueueResultT::SyclEnqueueBlocked;
181+
Q.submit([&](handler &Cgh) {
182+
auto acc = buf.template get_access<access::mode::discard_write>(Cgh);
183+
Cgh.fill(acc, 42);
184+
});
185+
Q.submit([&](handler &Cgh) {
186+
auto acc = buf.template get_access<access::mode::discard_write>(Cgh);
187+
Cgh.fill(acc, 42);
188+
});
189+
// Unblock the empty task to allow the submitted events to complete once
190+
// enqueued.
191+
EmptyTask->MEnqueueStatus = detail::EnqueueResultT::SyclEnqueueSuccess;
192+
Q.wait();
193+
// Only a single event (the last one) should be waited for here.
194+
ASSERT_EQ(TestContext.NEventsWaitedFor, 1);
195+
ASSERT_TRUE(TestContext.PiQueueFinishCalled);
196+
197+
// Test behaviour for emulating an OOO queue with multiple in-order ones.
198+
TestContext = {};
199+
TestContext.SupportOOO = false;
200+
Q = {Ctx, default_selector()};
201+
Q.memset(HostAlloc, 42, 1);
202+
// The event is kept alive in this case to call wait.
203+
ASSERT_EQ(TestContext.EventReferenceCount, 1);
204+
Q.wait();
205+
ASSERT_EQ(TestContext.EventReferenceCount, 0);
206+
ASSERT_EQ(TestContext.NEventsWaitedFor, 1);
207+
ASSERT_FALSE(TestContext.PiQueueFinishCalled);
208+
}
209+
210+
} // namespace

0 commit comments

Comments
 (0)