Skip to content

Commit 081b74c

Browse files
authored
[Offload] Add olWaitEvents (llvm#150036)
This function causes a queue to wait until all the provided events have completed before running any future scheduled work.
1 parent 2c6eec2 commit 081b74c

File tree

6 files changed

+202
-1
lines changed

6 files changed

+202
-1
lines changed

offload/liboffload/API/Queue.td

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,23 @@ def : Function {
4141
let returns = [];
4242
}
4343

44+
def : Function {
45+
let name = "olWaitEvents";
46+
let desc = "Make any future work submitted to this queue wait until the provided events are complete.";
47+
let details = [
48+
"All events in `Events` must complete before the queue is unblocked.",
49+
"The input events can be from any queue on any device provided by the same platform as `Queue`.",
50+
];
51+
let params = [
52+
Param<"ol_queue_handle_t", "Queue", "handle of the queue", PARAM_IN>,
53+
Param<"ol_event_handle_t *", "Events", "list of `NumEvents` events to wait for", PARAM_IN>,
54+
Param<"size_t", "NumEvents", "size of `Events`", PARAM_IN>,
55+
];
56+
let returns = [
57+
Return<"OL_ERRC_INVALID_NULL_HANDLE", ["Any event handle in the list is NULL"]>,
58+
];
59+
}
60+
4461
def : Enum {
4562
let name = "ol_queue_info_t";
4663
let desc = "Supported queue info.";

offload/liboffload/src/OffloadImpl.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,28 @@ Error olSyncQueue_impl(ol_queue_handle_t Queue) {
500500
return Error::success();
501501
}
502502

503+
Error olWaitEvents_impl(ol_queue_handle_t Queue, ol_event_handle_t *Events,
504+
size_t NumEvents) {
505+
auto *Device = Queue->Device->Device;
506+
507+
for (size_t I = 0; I < NumEvents; I++) {
508+
auto *Event = Events[I];
509+
510+
if (!Event)
511+
return Plugin::error(ErrorCode::INVALID_NULL_HANDLE,
512+
"olWaitEvents asked to wait on a NULL event");
513+
514+
// Do nothing if the event is for this queue
515+
if (Event->Queue == Queue)
516+
continue;
517+
518+
if (auto Err = Device->waitEvent(Event->EventInfo, Queue->AsyncInfo))
519+
return Err;
520+
}
521+
522+
return Error::success();
523+
}
524+
503525
Error olGetQueueInfoImplDetail(ol_queue_handle_t Queue,
504526
ol_queue_info_t PropName, size_t PropSize,
505527
void *PropValue, size_t *PropSizeRet) {

offload/unittests/OffloadAPI/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ add_offload_unittest("queue"
3939
queue/olSyncQueue.cpp
4040
queue/olDestroyQueue.cpp
4141
queue/olGetQueueInfo.cpp
42-
queue/olGetQueueInfoSize.cpp)
42+
queue/olGetQueueInfoSize.cpp
43+
queue/olWaitEvents.cpp)
4344

4445
add_offload_unittest("symbol"
4546
symbol/olGetSymbol.cpp

offload/unittests/OffloadAPI/device_code/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ add_offload_test_device_code(localmem_static.c localmem_static)
88
add_offload_test_device_code(global.c global)
99
add_offload_test_device_code(global_ctor.c global_ctor)
1010
add_offload_test_device_code(global_dtor.c global_dtor)
11+
add_offload_test_device_code(sequence.c sequence)
1112

1213
add_custom_target(offload_device_binaries DEPENDS
1314
foo.bin
@@ -19,5 +20,6 @@ add_custom_target(offload_device_binaries DEPENDS
1920
global.bin
2021
global_ctor.bin
2122
global_dtor.bin
23+
sequence.bin
2224
)
2325
set(OFFLOAD_TEST_DEVICE_CODE_PATH ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <gpuintrin.h>
2+
#include <stdint.h>
3+
4+
__gpu_kernel void sequence(uint32_t idx, uint32_t *inout) {
5+
if (idx == 0)
6+
inout[idx] = 0;
7+
else if (idx == 1)
8+
inout[idx] = 1;
9+
else
10+
inout[idx] = inout[idx - 1] + inout[idx - 2];
11+
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
//===------- Offload API tests - olWaitEvents -----------------------------===//
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 "../common/Fixtures.hpp"
10+
#include <OffloadAPI.h>
11+
#include <gtest/gtest.h>
12+
13+
struct olWaitEventsTest : OffloadProgramTest {
14+
void SetUp() override {
15+
RETURN_ON_FATAL_FAILURE(OffloadProgramTest::SetUpWith("sequence"));
16+
ASSERT_SUCCESS(
17+
olGetSymbol(Program, "sequence", OL_SYMBOL_KIND_KERNEL, &Kernel));
18+
LaunchArgs.Dimensions = 1;
19+
LaunchArgs.GroupSize = {1, 1, 1};
20+
LaunchArgs.NumGroups = {1, 1, 1};
21+
LaunchArgs.DynSharedMemory = 0;
22+
}
23+
24+
void TearDown() override {
25+
RETURN_ON_FATAL_FAILURE(OffloadProgramTest::TearDown());
26+
}
27+
28+
ol_symbol_handle_t Kernel = nullptr;
29+
ol_kernel_launch_size_args_t LaunchArgs{};
30+
};
31+
OFFLOAD_TESTS_INSTANTIATE_DEVICE_FIXTURE(olWaitEventsTest);
32+
33+
TEST_P(olWaitEventsTest, Success) {
34+
constexpr size_t NUM_KERNELS = 16;
35+
ol_queue_handle_t Queues[NUM_KERNELS];
36+
ol_event_handle_t Events[NUM_KERNELS];
37+
38+
void *Mem;
39+
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_MANAGED,
40+
NUM_KERNELS * sizeof(uint32_t), &Mem));
41+
struct {
42+
uint32_t Idx;
43+
void *Mem;
44+
} Args{0, Mem};
45+
46+
for (size_t I = 0; I < NUM_KERNELS; I++) {
47+
Args.Idx = I;
48+
49+
ASSERT_SUCCESS(olCreateQueue(Device, &Queues[I]));
50+
51+
if (I > 0)
52+
ASSERT_SUCCESS(olWaitEvents(Queues[I], &Events[I - 1], 1));
53+
54+
ASSERT_SUCCESS(olLaunchKernel(Queues[I], Device, Kernel, &Args,
55+
sizeof(Args), &LaunchArgs, &Events[I]));
56+
}
57+
58+
ASSERT_SUCCESS(olSyncEvent(Events[NUM_KERNELS - 1]));
59+
60+
uint32_t *Data = (uint32_t *)Mem;
61+
for (uint32_t i = 2; i < NUM_KERNELS; i++) {
62+
ASSERT_EQ(Data[i], Data[i - 1] + Data[i - 2]);
63+
}
64+
}
65+
66+
TEST_P(olWaitEventsTest, SuccessSingleQueue) {
67+
constexpr size_t NUM_KERNELS = 16;
68+
ol_queue_handle_t Queue;
69+
ol_event_handle_t Events[NUM_KERNELS];
70+
71+
ASSERT_SUCCESS(olCreateQueue(Device, &Queue));
72+
73+
void *Mem;
74+
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_MANAGED,
75+
NUM_KERNELS * sizeof(uint32_t), &Mem));
76+
struct {
77+
uint32_t Idx;
78+
void *Mem;
79+
} Args{0, Mem};
80+
81+
for (size_t I = 0; I < NUM_KERNELS; I++) {
82+
Args.Idx = I;
83+
84+
if (I > 0)
85+
ASSERT_SUCCESS(olWaitEvents(Queue, &Events[I - 1], 1));
86+
87+
ASSERT_SUCCESS(olLaunchKernel(Queue, Device, Kernel, &Args, sizeof(Args),
88+
&LaunchArgs, &Events[I]));
89+
}
90+
91+
ASSERT_SUCCESS(olSyncEvent(Events[NUM_KERNELS - 1]));
92+
93+
uint32_t *Data = (uint32_t *)Mem;
94+
for (uint32_t i = 2; i < NUM_KERNELS; i++) {
95+
ASSERT_EQ(Data[i], Data[i - 1] + Data[i - 2]);
96+
}
97+
}
98+
99+
TEST_P(olWaitEventsTest, SuccessMultipleEvents) {
100+
constexpr size_t NUM_KERNELS = 16;
101+
ol_queue_handle_t Queues[NUM_KERNELS];
102+
ol_event_handle_t Events[NUM_KERNELS];
103+
104+
void *Mem;
105+
ASSERT_SUCCESS(olMemAlloc(Device, OL_ALLOC_TYPE_MANAGED,
106+
NUM_KERNELS * sizeof(uint32_t), &Mem));
107+
struct {
108+
uint32_t Idx;
109+
void *Mem;
110+
} Args{0, Mem};
111+
112+
for (size_t I = 0; I < NUM_KERNELS; I++) {
113+
Args.Idx = I;
114+
115+
ASSERT_SUCCESS(olCreateQueue(Device, &Queues[I]));
116+
117+
if (I > 0)
118+
ASSERT_SUCCESS(olWaitEvents(Queues[I], Events, I));
119+
120+
ASSERT_SUCCESS(olLaunchKernel(Queues[I], Device, Kernel, &Args,
121+
sizeof(Args), &LaunchArgs, &Events[I]));
122+
}
123+
124+
ASSERT_SUCCESS(olSyncEvent(Events[NUM_KERNELS - 1]));
125+
126+
uint32_t *Data = (uint32_t *)Mem;
127+
for (uint32_t i = 2; i < NUM_KERNELS; i++) {
128+
ASSERT_EQ(Data[i], Data[i - 1] + Data[i - 2]);
129+
}
130+
}
131+
132+
TEST_P(olWaitEventsTest, InvalidNullQueue) {
133+
ol_event_handle_t Event;
134+
ASSERT_ERROR(OL_ERRC_INVALID_NULL_HANDLE, olWaitEvents(nullptr, &Event, 1));
135+
}
136+
137+
TEST_P(olWaitEventsTest, InvalidNullEvent) {
138+
ol_queue_handle_t Queue;
139+
ASSERT_SUCCESS(olCreateQueue(Device, &Queue));
140+
ASSERT_ERROR(OL_ERRC_INVALID_NULL_POINTER, olWaitEvents(Queue, nullptr, 1));
141+
}
142+
143+
TEST_P(olWaitEventsTest, InvalidNullInnerEvent) {
144+
ol_queue_handle_t Queue;
145+
ASSERT_SUCCESS(olCreateQueue(Device, &Queue));
146+
ol_event_handle_t Event = nullptr;
147+
ASSERT_ERROR(OL_ERRC_INVALID_NULL_HANDLE, olWaitEvents(Queue, &Event, 1));
148+
}

0 commit comments

Comments
 (0)