Skip to content

Commit 811db84

Browse files
authored
[SYCL] Fix handling of interop events for barrier with waitlist (#15352)
Currently Command::getUrEventsBlocking is responsible for preparing a waitlist of UR events for the barrier. This method used wrong assumption that if isEnqueued() returns false for the event then it doesn't have UR handle because it was not enqueued. So if there is an associated command we would enqueue it to get the desired UR handle, or we would just ignore this event if there is no associated command. Problem is that sycl::event created with interoperability constructor has isEnqueued() as false (as it is not enqueued by SYCL RT) but it has UR handle provided by user. Before this patch we just ignored such event as it doesn't have associated command and we didn't put it to the resulting list. This patch fixes this problem by handling interop events properly in this code path.
1 parent 40e2f62 commit 811db84

File tree

3 files changed

+60
-3
lines changed

3 files changed

+60
-3
lines changed

sycl/source/detail/event_impl.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,13 @@ class event_impl {
329329

330330
bool isProfilingTagEvent() const noexcept { return MProfilingTagEvent; }
331331

332+
// Check if this event is an interoperability event.
333+
bool isInterop() const noexcept {
334+
// As an indication of interoperability event, we use the absence of the
335+
// queue and command, as well as the fact that it is not in enqueued state.
336+
return MEvent && MQueue.expired() && !MIsEnqueued && !MCommand;
337+
}
338+
332339
protected:
333340
// When instrumentation is enabled emits trace event for event wait begin and
334341
// returns the telemetry event generated for the wait

sycl/source/detail/scheduler/commands.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -265,9 +265,12 @@ std::vector<ur_event_handle_t> Command::getUrEventsBlocking(
265265
if (EventImpl->isDefaultConstructed() || EventImpl->isHost() ||
266266
EventImpl->isNOP())
267267
continue;
268-
// In this path nullptr native event means that the command has not been
269-
// enqueued. It may happen if async enqueue in a host task is involved.
270-
if (!EventImpl->isEnqueued()) {
268+
269+
// If command has not been enqueued then we have to enqueue it.
270+
// It may happen if async enqueue in a host task is involved.
271+
// Interoperability events are special cases and they are not enqueued, as
272+
// they don't have an associated queue and command.
273+
if (!EventImpl->isInterop() && !EventImpl->isEnqueued()) {
271274
if (!EventImpl->getCommand() ||
272275
!static_cast<Command *>(EventImpl->getCommand())->producesPiEvent())
273276
continue;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// REQUIRES: level_zero, level_zero_dev_kit
2+
// RUN: %{build} %level_zero_options -o %t.out
3+
// RUN: %{run} %t.out
4+
// UNSUPPORTED: ze_debug
5+
6+
#include <level_zero/ze_api.h>
7+
#include <sycl/detail/core.hpp>
8+
#include <sycl/ext/oneapi/backend/level_zero.hpp>
9+
#include <sycl/usm.hpp>
10+
11+
// Test checks the case when an interoperability event is passed as a dependency
12+
// to the barrier. In such case, waiting for the event produced by barrier must
13+
// guarantee completion of the interoperability event.
14+
15+
using namespace sycl;
16+
17+
int main() {
18+
sycl::queue Queue;
19+
if (!Queue.get_device().get_info<info::device::usm_shared_allocations>())
20+
return 0;
21+
22+
const size_t N = 1024;
23+
int *Data = sycl::malloc_shared<int>(N, Queue);
24+
auto FillEvent = Queue.fill(Data, 0, N);
25+
auto FillZeEvent = get_native<backend::ext_oneapi_level_zero>(FillEvent);
26+
27+
backend_input_t<backend::ext_oneapi_level_zero, event> EventInteropInput = {
28+
FillZeEvent};
29+
EventInteropInput.Ownership = sycl::ext::oneapi::level_zero::ownership::keep;
30+
auto EventInterop = make_event<backend::ext_oneapi_level_zero>(
31+
EventInteropInput, Queue.get_context());
32+
33+
auto BarrierEvent = Queue.ext_oneapi_submit_barrier({EventInterop});
34+
BarrierEvent.wait();
35+
36+
if (EventInterop.get_info<sycl::info::event::command_execution_status>() !=
37+
sycl::info::event_command_status::complete) {
38+
Queue.wait();
39+
sycl::free(Data, Queue);
40+
return -1;
41+
}
42+
43+
// Free the USM memory
44+
sycl::free(Data, Queue);
45+
46+
return 0;
47+
}

0 commit comments

Comments
 (0)