Skip to content

Commit 5ba64c3

Browse files
againullAlexeySachkov
authored andcommitted
[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 5ae8b6f commit 5ba64c3

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
@@ -269,9 +269,12 @@ std::vector<ur_event_handle_t> Command::getUrEventsBlocking(
269269
if (EventImpl->isDefaultConstructed() || EventImpl->isHost() ||
270270
EventImpl->isNOP())
271271
continue;
272-
// In this path nullptr native event means that the command has not been
273-
// enqueued. It may happen if async enqueue in a host task is involved.
274-
if (!EventImpl->isEnqueued()) {
272+
273+
// If command has not been enqueued then we have to enqueue it.
274+
// It may happen if async enqueue in a host task is involved.
275+
// Interoperability events are special cases and they are not enqueued, as
276+
// they don't have an associated queue and command.
277+
if (!EventImpl->isInterop() && !EventImpl->isEnqueued()) {
275278
if (!EventImpl->getCommand() ||
276279
!static_cast<Command *>(EventImpl->getCommand())->producesPiEvent())
277280
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)