Skip to content

[SYCL] Do not wait for uninitialized events on queue barrier #4369

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sycl/plugins/level_zero/pi_level_zero.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,7 @@ pi_result _pi_ze_event_list_t::createAndRetainPiZeEventList(

if (EventListLength > 0) {
for (pi_uint32 I = 0; I < EventListLength; I++) {
PI_ASSERT(EventList[I] != nullptr, PI_INVALID_VALUE);
auto ZeEvent = EventList[I]->ZeEvent;

if (FilterEventWaitList) {
Expand Down
11 changes: 7 additions & 4 deletions sycl/source/detail/scheduler/commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,11 @@ static std::string commandToName(Command::CommandType Type) {
static std::vector<RT::PiEvent>
getPiEvents(const std::vector<EventImplPtr> &EventImpls) {
std::vector<RT::PiEvent> RetPiEvents;
for (auto &EventImpl : EventImpls)
RetPiEvents.push_back(EventImpl->getHandleRef());
for (auto &EventImpl : EventImpls) {
if (EventImpl->getHandleRef() != nullptr)
RetPiEvents.push_back(EventImpl->getHandleRef());
}

return RetPiEvents;
}

Expand Down Expand Up @@ -2231,12 +2234,12 @@ cl_int ExecCGCommand::enqueueImp() {
case CG::CGTYPE::BarrierWaitlist: {
CGBarrier *Barrier = static_cast<CGBarrier *>(MCommandGroup.get());
std::vector<detail::EventImplPtr> Events = Barrier->MEventsWaitWithBarrier;
if (MQueue->get_device().is_host() || Events.empty()) {
std::vector<RT::PiEvent> PiEvents = getPiEvents(Events);
if (MQueue->get_device().is_host() || PiEvents.empty()) {
// NOP for host device.
// If Events is empty, then the barrier has no effect.
return PI_SUCCESS;
}
std::vector<RT::PiEvent> PiEvents = getPiEvents(Events);
const detail::plugin &Plugin = MQueue->getPlugin();
Plugin.call<PiApiKind::piEnqueueEventsWaitWithBarrier>(
MQueue->getHandleRef(), PiEvents.size(), &PiEvents[0], &Event);
Expand Down
1 change: 1 addition & 0 deletions sycl/unittests/scheduler/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
add_sycl_unittest(SchedulerTests OBJECT
BlockedCommands.cpp
Commands.cpp
FailedCommands.cpp
FinishedCmdCleanup.cpp
LeafLimit.cpp
Expand Down
93 changes: 93 additions & 0 deletions sycl/unittests/scheduler/Commands.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
//==----------- Commands.cpp --- Commands unit tests -----------------------==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "SchedulerTest.hpp"
#include "SchedulerTestUtils.hpp"
#include <helpers/PiMock.hpp>

#include <iostream>

using namespace cl::sycl;

pi_result redefinePiEnqueueEventsWaitWithBarrier(pi_queue Queue,
pi_uint32 NumEventsInWaitList,
const pi_event *EventWaitList,
pi_event *Event) {

for (pi_uint32 i = 0; i != NumEventsInWaitList; ++i)
EXPECT_NE(EventWaitList[i], nullptr);

return PI_SUCCESS;
}

// Hack that allows to return a context in redefinePiEventGetInfo
RT::PiContext queue_global_context = nullptr;

pi_result redefinePiEventGetInfo(pi_event, pi_event_info, size_t,
void *param_value, size_t *) {
*reinterpret_cast<RT::PiContext *>(param_value) = queue_global_context;
return PI_SUCCESS;
}

pi_result redefinePiEventRetain(pi_event) { return PI_SUCCESS; }

pi_result redefinePiEventRelease(pi_event) { return PI_SUCCESS; }

//
// This test checks a handling of empty events in WaitWithBarrier command.
// Original reproducer for l0 plugin led to segfault(nullptr dereference):
//
// #include <CL/sycl.hpp>
// int main() {
// sycl::queue q;
// sycl::event e;
// q.submit_barrier({e});
// }
//
TEST_F(SchedulerTest, WaitEmptyEventWithBarrier) {
// NB! This test requires at least one non-host environmet
// For example, OpenCL.
default_selector Selector{};
if (Selector.select_device().is_host()) {
std::cerr << "Not run due to host-only environment\n";
return;
}

platform Plt{Selector};
unittest::PiMock Mock{Plt};

Mock.redefine<detail::PiApiKind::piEnqueueEventsWaitWithBarrier>(
redefinePiEnqueueEventsWaitWithBarrier);

queue Queue{Plt.get_devices()[0]};
cl::sycl::detail::QueueImplPtr QueueImpl = detail::getSyclObjImpl(Queue);

queue_global_context =
detail::getSyclObjImpl(Queue.get_context())->getHandleRef();

Mock.redefine<detail::PiApiKind::piEventGetInfo>(redefinePiEventGetInfo);
Mock.redefine<detail::PiApiKind::piEventRetain>(redefinePiEventRetain);
Mock.redefine<detail::PiApiKind::piEventRelease>(redefinePiEventRelease);

auto EmptyEvent = std::make_shared<detail::event_impl>();
auto Event = std::make_shared<detail::event_impl>(
reinterpret_cast<RT::PiEvent>(0x01), Queue.get_context());

using EventList = std::vector<detail::EventImplPtr>;
std::vector<EventList> InputEventWaitLists = {
{EmptyEvent}, {Event, Event}, {EmptyEvent, Event}};

MockScheduler MS;

for (auto &Arg : InputEventWaitLists) {
std::unique_ptr<detail::CG> CommandGroup(
new detail::CGBarrier(std::move(Arg), {}, {}, {}, {}, {},
detail::CG::CGTYPE::BarrierWaitlist, {}));
MS.Scheduler::addCG(std::move(CommandGroup), QueueImpl);
}
}