Skip to content
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
10 changes: 6 additions & 4 deletions sycl/source/detail/scheduler/commands.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,10 +388,12 @@ class Command {
/// removal).
bool MMarkedForCleanup = false;

/// Contains list of commands that depends on the host command explicitly (by
/// depends_on). Not involved in the cleanup process since it is one-way link
/// and does not hold resources.
/// Using EventImplPtr since enqueueUnblockedCommands and event.wait may
/// Events of root commands whose enqueue was deferred because this command
/// is blocking: a host task that is not complete yet, or a command blocked
/// by a live host accessor. They are re-enqueued by retryEnqueueBlockedUsers
/// when this command stops blocking. Not involved in the cleanup process
/// since it is one-way link and does not hold resources.
/// Using EventImplPtr since retryEnqueueBlockedUsers and event.wait may
/// intersect with command enqueue.
std::vector<EventImplPtr> MBlockedUsers;
std::mutex MBlockedUsersMutex;
Expand Down
12 changes: 7 additions & 5 deletions sycl/source/detail/scheduler/scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ void Scheduler::releaseHostAccessor(Requirement *Req) {
BlockedCmd->MEnqueueStatus = EnqueueResultT::SyclEnqueueReady;
}
// Commands whose blocking waiters deferred on BlockedCmd.
enqueueUnblockedCommands(BlockedCmd->MBlockedUsers, Lock, ToCleanUp);
retryEnqueueBlockedUsers(BlockedCmd->MBlockedUsers, Lock, ToCleanUp);

enqueueLeavesOfReqUnlocked(Req, Lock, ToCleanUp);
}
Expand All @@ -423,16 +423,18 @@ void Scheduler::enqueueLeavesOfReqUnlocked(const Requirement *const Req,
EnqueueLeaves(Record->MWriteLeaves);
}

void Scheduler::enqueueUnblockedCommands(events_range ToEnqueue,
void Scheduler::retryEnqueueBlockedUsers(events_range ToEnqueue,
ReadLockT &GraphReadLock,
std::vector<Command *> &ToCleanUp) {
for (event_impl &Event : ToEnqueue) {
Command *Cmd = Event.getCommand();
if (!Cmd)
continue;
EnqueueResultT Res;
bool Enqueued =
GraphProcessor::enqueueCommand(Cmd, GraphReadLock, Res, ToCleanUp, Cmd);
// BLOCKING re-registers Cmd on any command that still blocks it, so that
// its waiter is not lost.
bool Enqueued = GraphProcessor::enqueueCommand(Cmd, GraphReadLock, Res,
ToCleanUp, Cmd, BLOCKING);
if (!Enqueued && EnqueueResultT::SyclEnqueueFailed == Res.MResult)
throw exception(make_error_code(errc::runtime),
"Enqueue process failed.");
Expand Down Expand Up @@ -538,7 +540,7 @@ void Scheduler::NotifyHostTaskCompletion(Command *Cmd) {
// update self-event status
CmdEvent->setComplete();
}
Scheduler::enqueueUnblockedCommands(Cmd->MBlockedUsers, Lock, ToCleanUp);
Scheduler::retryEnqueueBlockedUsers(Cmd->MBlockedUsers, Lock, ToCleanUp);
}
QueueImpl->revisitUnenqueuedCommandsState(CmdEvent);

Expand Down
2 changes: 1 addition & 1 deletion sycl/source/detail/scheduler/scheduler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ class Scheduler {
ReadLockT &GraphReadLock,
std::vector<Command *> &ToCleanUp);

static void enqueueUnblockedCommands(events_range ToEnqueue,
static void retryEnqueueBlockedUsers(events_range ToEnqueue,
ReadLockT &GraphReadLock,
std::vector<Command *> &ToCleanUp);

Expand Down
38 changes: 38 additions & 0 deletions sycl/unittests/scheduler/BlockedCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,41 @@ TEST_F(SchedulerTest, EnqueueHostDependency) {
ASSERT_EQ(detail::EnqueueResultT::SyclEnqueueSuccess, Res.MResult)
<< "Enqueue operation should return successfully.\n";
}

// When a blocked user is unblocked by A but is still blocked by B, it must be
// re-registered on B, or its waiter is never woken up.
TEST_F(SchedulerTest, BlockedUserReRegisteredOnNextBlockedCommand) {
sycl::unittest::UrMock<> Mock;
sycl::queue Q{sycl::platform().get_devices()[0], MAsyncHandler};
sycl::detail::queue_impl &QueueImpl = *detail::getSyclObjImpl(Q);

// Root
// / \
// A B (both blocked, e.g. by live read host accessors)
MockCommand A(&QueueImpl), B(&QueueImpl), Root(&QueueImpl);
std::vector<detail::Command *> ToCleanUp;
for (MockCommand *Dep : {&A, &B}) {
Dep->MEnqueueStatus = detail::EnqueueResultT::SyclEnqueueBlocked;
Dep->MIsBlockable = true;
auto DepEvent = detail::event_impl::create_device_event(QueueImpl);
DepEvent->setCommand(Dep);
(void)Root.addDep(DepEvent, ToCleanUp);
}

MockScheduler MS;
auto Lock = MS.acquireGraphReadLock();
detail::EnqueueResultT Res;
ASSERT_FALSE(MockScheduler::enqueueCommand(&Root, Res, detail::BLOCKING));
ASSERT_EQ(1u, A.MBlockedUsers.size());
ASSERT_EQ(0u, B.MBlockedUsers.size());

A.MEnqueueStatus = detail::EnqueueResultT::SyclEnqueueReady;
MockScheduler::retryEnqueueBlockedUsers(A.MBlockedUsers, Lock, ToCleanUp);
ASSERT_FALSE(Root.isSuccessfullyEnqueued());
ASSERT_EQ(1u, B.MBlockedUsers.size());
ASSERT_EQ(Root.getEvent(), B.MBlockedUsers[0]);

B.MEnqueueStatus = detail::EnqueueResultT::SyclEnqueueReady;
MockScheduler::retryEnqueueBlockedUsers(B.MBlockedUsers, Lock, ToCleanUp);
ASSERT_TRUE(Root.isSuccessfullyEnqueued());
}
2 changes: 1 addition & 1 deletion sycl/unittests/scheduler/FailedCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ TEST(FailedCommandsTest, CheckUREventReleaseWithBarrier) {

// Regression for the deferred-enqueue-failure hang identified in PR #22993
// review. When Command::enqueue's re-attempt on a ThreadPool worker (via
// NotifyHostTaskCompletion -> enqueueUnblockedCommands) fails, a caller
// NotifyHostTaskCompletion -> retryEnqueueBlockedUsers) fails, a caller
// that deferred via MBlockedUsers and parked in event_impl::waitInternal's
// cv.wait must still wake. The failure itself surfaces via
// reportAsyncException on the queue's async handler.
Expand Down
1 change: 1 addition & 0 deletions sycl/unittests/scheduler/SchedulerTestUtils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class MockScheduler : public sycl::detail::Scheduler {
using sycl::detail::Scheduler::checkLeavesCompletion;
using sycl::detail::Scheduler::cleanupCommands;
using sycl::detail::Scheduler::MDeferredMemObjRelease;
using sycl::detail::Scheduler::retryEnqueueBlockedUsers;

sycl::detail::MemObjRecord *
getOrInsertMemObjRecord(sycl::detail::queue_impl *Queue,
Expand Down
Loading