diff --git a/sycl/source/detail/scheduler/commands.cpp b/sycl/source/detail/scheduler/commands.cpp index 22624546e78e9..278d665ee2675 100644 --- a/sycl/source/detail/scheduler/commands.cpp +++ b/sycl/source/detail/scheduler/commands.cpp @@ -1737,7 +1737,8 @@ void DispatchNativeKernel(void *Blob) { } cl_int ExecCGCommand::enqueueImp() { - waitForPreparedHostEvents(); + if (getCG().getType() != CG::CGTYPE::CODEPLAY_HOST_TASK) + waitForPreparedHostEvents(); std::vector EventImpls = MPreparedDepsEvents; auto RawEvents = getPiEvents(EventImpls); diff --git a/sycl/source/detail/scheduler/commands.hpp b/sycl/source/detail/scheduler/commands.hpp index 7406f82331bf4..c900be04ce236 100644 --- a/sycl/source/detail/scheduler/commands.hpp +++ b/sycl/source/detail/scheduler/commands.hpp @@ -217,6 +217,10 @@ class Command { friend class DispatchHostTask; public: + const std::vector getPreparedHostDepsEvents() const { + return MPreparedHostDepsEvents; + } + /// Contains list of dependencies(edges) std::vector MDeps; /// Contains list of commands that depend on the command. diff --git a/sycl/source/detail/scheduler/graph_processor.cpp b/sycl/source/detail/scheduler/graph_processor.cpp index bc7f813069f39..0e7a3fbbbaa0f 100644 --- a/sycl/source/detail/scheduler/graph_processor.cpp +++ b/sycl/source/detail/scheduler/graph_processor.cpp @@ -71,6 +71,22 @@ bool Scheduler::GraphProcessor::enqueueCommand(Command *Cmd, return false; } + // Asynchronous host operations (amongst dependencies of an arbitrary command) + // are not supported (see Command::processDepEvent method). This impacts + // operation of host-task feature a lot with hangs and long-runs. Hence we + // have this workaround here. + // This workaround is safe as long as the only asynchronous host operation we + // have is a host task. + // This may iterate over some of dependencies in Cmd->MDeps. Though, the + // enqueue operation is idempotent and the second call will result in no-op. + // TODO remove the workaround when proper fix for host-task dispatching is + // implemented. + for (const EventImplPtr &Event : Cmd->getPreparedHostDepsEvents()) { + if (Command *DepCmd = static_cast(Event->getCommand())) + if (!enqueueCommand(DepCmd, EnqueueResult, Blocking)) + return false; + } + return Cmd->enqueue(EnqueueResult, Blocking); } diff --git a/sycl/test/host-interop-task/host-task-dependency2.cpp b/sycl/test/host-interop-task/host-task-dependency2.cpp index 4e0e76b1bcdd9..0d162c9478ed1 100644 --- a/sycl/test/host-interop-task/host-task-dependency2.cpp +++ b/sycl/test/host-interop-task/host-task-dependency2.cpp @@ -1,12 +1,12 @@ // RUN: %clangxx -fsycl -fsycl-targets=%sycl_triple %s -o %t.out -// RUNx: %CPU_RUN_PLACEHOLDER %t.out -// RUNx: %GPU_RUN_PLACEHOLDER %t.out -// RUNx: %ACC_RUN_PLACEHOLDER %t.out +// RUN: %CPU_RUN_PLACEHOLDER %t.out +// RUN: %GPU_RUN_PLACEHOLDER %t.out +// RUN: %ACC_RUN_PLACEHOLDER %t.out -// RUNx: %CPU_RUN_PLACEHOLDER %t.out 10 -// RUNx: %GPU_RUN_PLACEHOLDER %t.out 10 -// RUNx: %ACC_RUN_PLACEHOLDER %t.out 10 +// RUN: %CPU_RUN_PLACEHOLDER %t.out 10 +// RUN: %GPU_RUN_PLACEHOLDER %t.out 10 +// RUN: %ACC_RUN_PLACEHOLDER %t.out 10 #include #include diff --git a/sycl/test/host-interop-task/host-task-dependency3.cpp b/sycl/test/host-interop-task/host-task-dependency3.cpp index b6e7adf3e1634..43a5a05448827 100644 --- a/sycl/test/host-interop-task/host-task-dependency3.cpp +++ b/sycl/test/host-interop-task/host-task-dependency3.cpp @@ -1,12 +1,12 @@ // RUN: %clangxx -fsycl -fsycl-targets=%sycl_triple %s -o %t.out -// RUNx: %CPU_RUN_PLACEHOLDER %t.out -// RUNx: %GPU_RUN_PLACEHOLDER %t.out -// RUNx: %ACC_RUN_PLACEHOLDER %t.out +// RUN: %CPU_RUN_PLACEHOLDER %t.out +// RUN: %GPU_RUN_PLACEHOLDER %t.out +// RUN: %ACC_RUN_PLACEHOLDER %t.out -// RUNx: %CPU_RUN_PLACEHOLDER %t.out 10 -// RUNx: %GPU_RUN_PLACEHOLDER %t.out 10 -// RUNx: %ACC_RUN_PLACEHOLDER %t.out 10 +// RUN: %CPU_RUN_PLACEHOLDER %t.out 10 +// RUN: %GPU_RUN_PLACEHOLDER %t.out 10 +// RUN: %ACC_RUN_PLACEHOLDER %t.out 10 #include #include diff --git a/sycl/test/host-interop-task/host-task-dependency4.cpp b/sycl/test/host-interop-task/host-task-dependency4.cpp index 600ec43cac937..e95edc3c078a1 100644 --- a/sycl/test/host-interop-task/host-task-dependency4.cpp +++ b/sycl/test/host-interop-task/host-task-dependency4.cpp @@ -1,8 +1,8 @@ // RUN: %clangxx -fsycl -fsycl-targets=%sycl_triple %s -o %t.out -// RUNx: %CPU_RUN_PLACEHOLDER %t.out -// RUNx: %GPU_RUN_PLACEHOLDER %t.out -// RUNx: %ACC_RUN_PLACEHOLDER %t.out +// RUN: %CPU_RUN_PLACEHOLDER %t.out +// RUN: %GPU_RUN_PLACEHOLDER %t.out +// RUN: %ACC_RUN_PLACEHOLDER %t.out #include diff --git a/sycl/unittests/scheduler/BlockedCommands.cpp b/sycl/unittests/scheduler/BlockedCommands.cpp index 5ed22606d495e..c447a8f1e606b 100644 --- a/sycl/unittests/scheduler/BlockedCommands.cpp +++ b/sycl/unittests/scheduler/BlockedCommands.cpp @@ -130,3 +130,42 @@ TEST_F(SchedulerTest, EnqueueBlockedCommandEarlyExit) { << "Result of enqueueing blocked command should be BLOCKED.\n"; ASSERT_EQ(&B, Res.MCmd) << "Expected different failed command.\n"; } + +// This unit test is for workaround described in GraphProcessor::enqueueCommand +// method. +TEST_F(SchedulerTest, EnqueueHostDependency) { + MockCommand A(detail::getSyclObjImpl(MQueue)); + A.MEnqueueStatus = detail::EnqueueResultT::SyclEnqueueReady; + A.MIsBlockable = true; + A.MRetVal = CL_SUCCESS; + + MockCommand B(detail::getSyclObjImpl(MQueue)); + B.MEnqueueStatus = detail::EnqueueResultT::SyclEnqueueReady; + B.MIsBlockable = true; + B.MRetVal = CL_SUCCESS; + + cl::sycl::detail::EventImplPtr DepEvent{ + new cl::sycl::detail::event_impl(detail::getSyclObjImpl(MQueue))}; + DepEvent->setCommand(&B); + + A.addDep(DepEvent); + + // We have such a "graph": + // + // A + // | + // B + // + // A depends on B. B is host command. + // "Graph" is quoted as we don't have this dependency in MDeps. Instead, we + // have this dependecy as result of handler::depends_on() call. + + EXPECT_CALL(A, enqueue(_, _)).Times(1); + EXPECT_CALL(B, enqueue(_, _)).Times(1); + + detail::EnqueueResultT Res; + bool Enqueued = MockScheduler::enqueueCommand(&A, Res, detail::NON_BLOCKING); + ASSERT_TRUE(Enqueued) << "The command should be enqueued\n"; + ASSERT_EQ(detail::EnqueueResultT::SyclEnqueueSuccess, Res.MResult) + << "Enqueue operation should return successfully.\n"; +}