Skip to content

Commit 067d3b3

Browse files
authored
[SYCL] Preserve in-order queue dependency chain between usm & host tasks (#6840)
Currently last event is not updated for usm commands, so dependency chain is incorrect if usm commands are interleaved with host tasks. Also we need to wait if the last event is associated with host task before submitting usm command. E2E test: intel/llvm-test-suite#1283
1 parent f3ca156 commit 067d3b3

File tree

1 file changed

+79
-18
lines changed

1 file changed

+79
-18
lines changed

sycl/source/detail/queue_impl.cpp

Lines changed: 79 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,34 @@ event queue_impl::memset(const std::shared_ptr<detail::queue_impl> &Self,
6767
getOrWaitEvents(DepEvents, MContext), nullptr);
6868
return createDiscardedEvent();
6969
}
70-
RT::PiEvent NativeEvent{};
71-
MemoryManager::fill_usm(Ptr, Self, Count, Value,
72-
getOrWaitEvents(DepEvents, MContext), &NativeEvent);
70+
event ResEvent;
71+
{
72+
// We need to submit command and update the last event under same lock if we
73+
// have in-order queue.
74+
auto ScopeLock = isInOrder() ? std::unique_lock(MLastEventMtx)
75+
: std::unique_lock<std::mutex>();
76+
// If the last submitted command in the in-order queue is host_task then
77+
// wait for it before submitting usm command.
78+
if (isInOrder() && (MLastCGType == CG::CGTYPE::CodeplayHostTask ||
79+
MLastCGType == CG::CGTYPE::CodeplayInteropTask))
80+
MLastEvent.wait();
7381

74-
if (MContext->is_host())
75-
return MDiscardEvents ? createDiscardedEvent() : event();
82+
RT::PiEvent NativeEvent{};
83+
MemoryManager::fill_usm(Ptr, Self, Count, Value,
84+
getOrWaitEvents(DepEvents, MContext), &NativeEvent);
7685

77-
event ResEvent = prepareUSMEvent(Self, NativeEvent);
86+
if (MContext->is_host())
87+
return MDiscardEvents ? createDiscardedEvent() : event();
88+
89+
ResEvent = prepareUSMEvent(Self, NativeEvent);
90+
if (isInOrder()) {
91+
MLastEvent = ResEvent;
92+
// We don't create a command group for usm commands, so set it to None.
93+
// This variable is used to perform explicit dependency management when
94+
// required.
95+
MLastCGType = CG::CGTYPE::None;
96+
}
97+
}
7898
// Track only if we won't be able to handle it with piQueueFinish.
7999
if (!MSupportOOO)
80100
addSharedEvent(ResEvent);
@@ -89,14 +109,34 @@ event queue_impl::memcpy(const std::shared_ptr<detail::queue_impl> &Self,
89109
getOrWaitEvents(DepEvents, MContext), nullptr);
90110
return createDiscardedEvent();
91111
}
92-
RT::PiEvent NativeEvent{};
93-
MemoryManager::copy_usm(Src, Self, Count, Dest,
94-
getOrWaitEvents(DepEvents, MContext), &NativeEvent);
112+
event ResEvent;
113+
{
114+
// We need to submit command and update the last event under same lock if we
115+
// have in-order queue.
116+
auto ScopeLock = isInOrder() ? std::unique_lock(MLastEventMtx)
117+
: std::unique_lock<std::mutex>();
118+
// If the last submitted command in the in-order queue is host_task then
119+
// wait for it before submitting usm command.
120+
if (isInOrder() && (MLastCGType == CG::CGTYPE::CodeplayHostTask ||
121+
MLastCGType == CG::CGTYPE::CodeplayInteropTask))
122+
MLastEvent.wait();
123+
124+
RT::PiEvent NativeEvent{};
125+
MemoryManager::copy_usm(Src, Self, Count, Dest,
126+
getOrWaitEvents(DepEvents, MContext), &NativeEvent);
95127

96-
if (MContext->is_host())
97-
return MDiscardEvents ? createDiscardedEvent() : event();
128+
if (MContext->is_host())
129+
return MDiscardEvents ? createDiscardedEvent() : event();
98130

99-
event ResEvent = prepareUSMEvent(Self, NativeEvent);
131+
ResEvent = prepareUSMEvent(Self, NativeEvent);
132+
if (isInOrder()) {
133+
MLastEvent = ResEvent;
134+
// We don't create a command group for usm commands, so set it to None.
135+
// This variable is used to perform explicit dependency management when
136+
// required.
137+
MLastCGType = CG::CGTYPE::None;
138+
}
139+
}
100140
// Track only if we won't be able to handle it with piQueueFinish.
101141
if (!MSupportOOO)
102142
addSharedEvent(ResEvent);
@@ -112,14 +152,35 @@ event queue_impl::mem_advise(const std::shared_ptr<detail::queue_impl> &Self,
112152
getOrWaitEvents(DepEvents, MContext), nullptr);
113153
return createDiscardedEvent();
114154
}
115-
RT::PiEvent NativeEvent{};
116-
MemoryManager::advise_usm(Ptr, Self, Length, Advice,
117-
getOrWaitEvents(DepEvents, MContext), &NativeEvent);
155+
event ResEvent;
156+
{
157+
// We need to submit command and update the last event under same lock if we
158+
// have in-order queue.
159+
auto ScopeLock = isInOrder() ? std::unique_lock(MLastEventMtx)
160+
: std::unique_lock<std::mutex>();
161+
// If the last submitted command in the in-order queue is host_task then
162+
// wait for it before submitting usm command.
163+
if (isInOrder() && (MLastCGType == CG::CGTYPE::CodeplayHostTask ||
164+
MLastCGType == CG::CGTYPE::CodeplayInteropTask))
165+
MLastEvent.wait();
118166

119-
if (MContext->is_host())
120-
return MDiscardEvents ? createDiscardedEvent() : event();
167+
RT::PiEvent NativeEvent{};
168+
MemoryManager::advise_usm(Ptr, Self, Length, Advice,
169+
getOrWaitEvents(DepEvents, MContext),
170+
&NativeEvent);
171+
172+
if (MContext->is_host())
173+
return MDiscardEvents ? createDiscardedEvent() : event();
121174

122-
event ResEvent = prepareUSMEvent(Self, NativeEvent);
175+
ResEvent = prepareUSMEvent(Self, NativeEvent);
176+
if (isInOrder()) {
177+
MLastEvent = ResEvent;
178+
// We don't create a command group for usm commands, so set it to None.
179+
// This variable is used to perform explicit dependency management when
180+
// required.
181+
MLastCGType = CG::CGTYPE::None;
182+
}
183+
}
123184
// Track only if we won't be able to handle it with piQueueFinish.
124185
if (!MSupportOOO)
125186
addSharedEvent(ResEvent);

0 commit comments

Comments
 (0)