Skip to content

Commit c7ba937

Browse files
[SYCL] Fix sync of host task vs kernel for in-order queue (#5551)
Fix + unit test SchedulerTest.InOrderQueueHostTaskDepsExt
1 parent d7166ba commit c7ba937

File tree

3 files changed

+130
-5
lines changed

3 files changed

+130
-5
lines changed

sycl/source/detail/queue_impl.hpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -439,27 +439,41 @@ class queue_impl {
439439
return MAssertHappenedBuffer;
440440
}
441441

442-
private:
443-
void finalizeHandler(handler &Handler, const CG::CGTYPE &Type,
442+
protected:
443+
// template is needed for proper unit testing
444+
template <typename HandlerType = handler>
445+
void finalizeHandler(HandlerType &Handler, const CG::CGTYPE &Type,
444446
event &EventRet) {
445447
if (MIsInorder) {
446-
bool NeedSeparateDependencyMgmt =
447-
(Type == CG::CGTYPE::CodeplayHostTask ||
448-
Type == CG::CGTYPE::CodeplayInteropTask);
448+
449+
auto IsExpDepManaged = [](const CG::CGTYPE &Type) {
450+
return (Type == CG::CGTYPE::CodeplayHostTask ||
451+
Type == CG::CGTYPE::CodeplayInteropTask);
452+
};
453+
449454
// Accessing and changing of an event isn't atomic operation.
450455
// Hence, here is the lock for thread-safety.
451456
std::lock_guard<std::mutex> Lock{MLastEventMtx};
452457

458+
if (MLastCGType == CG::CGTYPE::None)
459+
MLastCGType = Type;
460+
// Also handles case when sync model changes. E.g. Last is host, new is
461+
// kernel.
462+
bool NeedSeparateDependencyMgmt =
463+
IsExpDepManaged(Type) || IsExpDepManaged(MLastCGType);
464+
453465
if (NeedSeparateDependencyMgmt)
454466
Handler.depends_on(MLastEvent);
455467

456468
EventRet = Handler.finalize();
457469

458470
MLastEvent = EventRet;
471+
MLastCGType = Type;
459472
} else
460473
EventRet = Handler.finalize();
461474
}
462475

476+
private:
463477
/// Performs command group submission to the queue.
464478
///
465479
/// \param CGF is a function object containing command group.
@@ -560,6 +574,10 @@ class queue_impl {
560574
// Access to the event should be guarded with MLastEventMtx
561575
event MLastEvent;
562576
std::mutex MLastEventMtx;
577+
// Used for in-order queues in pair with MLastEvent
578+
// Host tasks are explicitly synchronized in RT, pi tasks - implicitly by
579+
// backend. Using type to setup explicit sync between host and pi tasks.
580+
CG::CGTYPE MLastCGType = CG::CGTYPE::None;
563581

564582
const bool MIsInorder;
565583

sycl/unittests/scheduler/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ add_sycl_unittest(SchedulerTests OBJECT
2020
Regression.cpp
2121
utils.cpp
2222
LeafLimitDiffContexts.cpp
23+
InOrderQueueSyncCheck.cpp
2324
)
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//==---------- InOrderQueueSyncCheck.cpp --- Scheduler unit tests ----------==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "SchedulerTest.hpp"
10+
#include "SchedulerTestUtils.hpp"
11+
#include <CL/sycl.hpp>
12+
#include <detail/queue_impl.hpp>
13+
#include <detail/scheduler/commands.hpp>
14+
15+
#include <gtest/gtest.h>
16+
17+
using namespace sycl;
18+
19+
// Define type with the only methods called by finalizeHandler
20+
class LimitedHandler {
21+
public:
22+
virtual void depends_on(sycl::event){};
23+
24+
virtual event finalize() {
25+
cl::sycl::detail::EventImplPtr NewEvent =
26+
std::make_shared<detail::event_impl>();
27+
return sycl::detail::createSyclObjFromImpl<sycl::event>(NewEvent);
28+
};
29+
};
30+
31+
// Needed to use EXPECT_CALL to verify depends_on that originally appends lst
32+
// event as dependency to the new CG
33+
class LimitedHandlerSimulation : public LimitedHandler {
34+
public:
35+
MOCK_METHOD1(depends_on, void(sycl::event));
36+
};
37+
38+
class MockQueueImpl : public sycl::detail::queue_impl {
39+
public:
40+
MockQueueImpl(const sycl::detail::DeviceImplPtr &Device,
41+
const sycl::async_handler &AsyncHandler,
42+
const sycl::property_list &PropList)
43+
: sycl::detail::queue_impl(Device, AsyncHandler, PropList) {}
44+
using sycl::detail::queue_impl::finalizeHandler;
45+
};
46+
47+
// Only check events dependency in queue_impl::finalizeHandler
48+
TEST_F(SchedulerTest, InOrderQueueSyncCheck) {
49+
sycl::platform Plt{sycl::default_selector()};
50+
if (Plt.is_host() || Plt.get_backend() == sycl::backend::ext_oneapi_cuda ||
51+
Plt.get_backend() == sycl::backend::ext_oneapi_hip) {
52+
std::cerr << "Test is not supported on "
53+
<< Plt.get_info<sycl::info::platform::name>() << ", skipping\n";
54+
GTEST_SKIP(); // test is not supported on selected platform.
55+
}
56+
57+
const sycl::device Dev = Plt.get_devices()[0];
58+
auto Queue = std::make_shared<MockQueueImpl>(
59+
sycl::detail::getSyclObjImpl(Dev), sycl::async_handler{},
60+
sycl::property::queue::in_order());
61+
62+
// What we are testing here:
63+
// Task type | Must depend on
64+
// host | yes - always, separate sync management
65+
// host | yes - always, separate sync management
66+
// kernel | yes - change of sync approach
67+
// kernel | no - sync between pi calls must be done by backend
68+
// host | yes - always, separate sync management
69+
70+
sycl::event Event;
71+
// host task
72+
{
73+
LimitedHandlerSimulation MockCGH;
74+
EXPECT_CALL(MockCGH, depends_on).Times(1);
75+
Queue->finalizeHandler<LimitedHandlerSimulation>(
76+
MockCGH, detail::CG::CGTYPE::CodeplayHostTask, Event);
77+
}
78+
// host task
79+
{
80+
LimitedHandlerSimulation MockCGH;
81+
EXPECT_CALL(MockCGH, depends_on).Times(1);
82+
Queue->finalizeHandler<LimitedHandlerSimulation>(
83+
MockCGH, detail::CG::CGTYPE::CodeplayHostTask, Event);
84+
}
85+
// kernel task
86+
{
87+
LimitedHandlerSimulation MockCGH;
88+
EXPECT_CALL(MockCGH, depends_on).Times(1);
89+
Queue->finalizeHandler<LimitedHandlerSimulation>(
90+
MockCGH, detail::CG::CGTYPE::Kernel, Event);
91+
}
92+
// kernel task
93+
{
94+
LimitedHandlerSimulation MockCGH;
95+
EXPECT_CALL(MockCGH, depends_on).Times(0);
96+
Queue->finalizeHandler<LimitedHandlerSimulation>(
97+
MockCGH, detail::CG::CGTYPE::Kernel, Event);
98+
}
99+
// host task
100+
{
101+
LimitedHandlerSimulation MockCGH;
102+
EXPECT_CALL(MockCGH, depends_on).Times(1);
103+
Queue->finalizeHandler<LimitedHandlerSimulation>(
104+
MockCGH, detail::CG::CGTYPE::CodeplayHostTask, Event);
105+
}
106+
}

0 commit comments

Comments
 (0)