Skip to content

Commit 4785f47

Browse files
[SYCL] Release commands with no dependencies after they're enqueued (#2492)
Presently, commands that do not have memory dependencies are only released if .wait() is called. If it is not, several resources (event, queue, command, kernel) are held onto. This fix deletes stores that command event in the USMEvents ( so it is 'owned') and then deletes the command itself. Added a lit test to verify resource release. Signed-off-by: Chris Perkins <[email protected]>
1 parent dbf31c3 commit 4785f47

File tree

4 files changed

+58
-16
lines changed

4 files changed

+58
-16
lines changed

sycl/source/detail/queue_impl.cpp

+21-10
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ event queue_impl::memset(const shared_ptr_class<detail::queue_impl> &Self,
6060
return event();
6161

6262
event ResEvent = prepareUSMEvent(Self, NativeEvent);
63-
addUSMEvent(ResEvent);
63+
addSharedEvent(ResEvent);
6464
return ResEvent;
6565
}
6666

@@ -74,7 +74,7 @@ event queue_impl::memcpy(const shared_ptr_class<detail::queue_impl> &Self,
7474
return event();
7575

7676
event ResEvent = prepareUSMEvent(Self, NativeEvent);
77-
addUSMEvent(ResEvent);
77+
addSharedEvent(ResEvent);
7878
return ResEvent;
7979
}
8080

@@ -92,19 +92,30 @@ event queue_impl::mem_advise(const shared_ptr_class<detail::queue_impl> &Self,
9292
Advice, &NativeEvent);
9393

9494
event ResEvent = prepareUSMEvent(Self, NativeEvent);
95-
addUSMEvent(ResEvent);
95+
addSharedEvent(ResEvent);
9696
return ResEvent;
9797
}
9898

9999
void queue_impl::addEvent(const event &Event) {
100-
std::weak_ptr<event_impl> EventWeakPtr{getSyclObjImpl(Event)};
101-
std::lock_guard<mutex_class> Lock(MMutex);
102-
MEvents.push_back(std::move(EventWeakPtr));
100+
EventImplPtr Eimpl = getSyclObjImpl(Event);
101+
Command *Cmd = (Command *)(Eimpl->getCommand());
102+
if (!Cmd) {
103+
// if there is no command on the event, we cannot track it with MEventsWeak
104+
// as that will leave it with no owner. Track in MEventsShared
105+
addSharedEvent(Event);
106+
} else {
107+
std::weak_ptr<event_impl> EventWeakPtr{Eimpl};
108+
std::lock_guard<mutex_class> Lock{MMutex};
109+
MEventsWeak.push_back(std::move(EventWeakPtr));
110+
}
103111
}
104112

105-
void queue_impl::addUSMEvent(const event &Event) {
113+
/// addSharedEvent - queue_impl tracks events with weak pointers
114+
/// but some events have no other owner. In this case,
115+
/// addSharedEvent will have the queue track the events via a shared pointer.
116+
void queue_impl::addSharedEvent(const event &Event) {
106117
std::lock_guard<mutex_class> Lock(MMutex);
107-
MUSMEvents.push_back(Event);
118+
MEventsShared.push_back(Event);
108119
}
109120

110121
void *queue_impl::instrumentationProlog(const detail::code_location &CodeLoc,
@@ -204,8 +215,8 @@ void queue_impl::wait(const detail::code_location &CodeLoc) {
204215
vector_class<event> USMEvents;
205216
{
206217
std::lock_guard<mutex_class> Lock(MMutex);
207-
Events = std::move(MEvents);
208-
USMEvents = std::move(MUSMEvents);
218+
Events = std::move(MEventsWeak);
219+
USMEvents = std::move(MEventsShared);
209220
}
210221

211222
for (std::weak_ptr<event_impl> &EventImplWeakPtr : Events)

sycl/source/detail/queue_impl.hpp

+12-6
Original file line numberDiff line numberDiff line change
@@ -400,10 +400,12 @@ class queue_impl {
400400

401401
void initHostTaskAndEventCallbackThreadPool();
402402

403-
/// Stores a USM operation event that should be associated with the queue
403+
/// queue_impl.addEvent tracks events with weak pointers
404+
/// but some events have no other owners. addSharedEvent()
405+
/// follows events with a shared pointer.
404406
///
405407
/// \param Event is the event to be stored
406-
void addUSMEvent(const event &Event);
408+
void addSharedEvent(const event &Event);
407409

408410
/// Stores an event that should be associated with the queue
409411
///
@@ -415,10 +417,14 @@ class queue_impl {
415417

416418
DeviceImplPtr MDevice;
417419
const ContextImplPtr MContext;
418-
vector_class<std::weak_ptr<event_impl>> MEvents;
419-
// USM operations are not added to the scheduler command graph,
420-
// queue is the only owner on the runtime side.
421-
vector_class<event> MUSMEvents;
420+
421+
/// These events are tracked, but not owned, by the queue.
422+
vector_class<std::weak_ptr<event_impl>> MEventsWeak;
423+
424+
/// Events without data dependencies (such as USM) need an owner,
425+
/// additionally, USM operations are not added to the scheduler command graph,
426+
/// queue is the only owner on the runtime side.
427+
vector_class<event> MEventsShared;
422428
exception_list MExceptions;
423429
const async_handler MAsyncHandler;
424430
const property_list MPropList;

sycl/source/detail/scheduler/scheduler.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ EventImplPtr Scheduler::addCG(std::unique_ptr<detail::CG> CommandGroup,
101101

102102
if (IsKernel)
103103
Streams = ((ExecCGCommand *)NewCmd)->getStreams();
104+
105+
if (NewCmd->MDeps.size() == 0 && NewCmd->MUsers.size() == 0) {
106+
NewEvent->setCommand(nullptr); // if there are no memory dependencies,
107+
// decouple and free the command
108+
delete NewCmd;
109+
}
104110
}
105111
}
106112

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %clangxx -fsycl -fsycl-targets=%sycl_triple %s -o %t.out
2+
// RUN: env SYCL_PI_TRACE=2 %GPU_RUN_PLACEHOLDER %t.out | FileCheck %s
3+
4+
#include <CL/sycl.hpp>
5+
int main() {
6+
sycl::queue q;
7+
8+
q.single_task<class test>([]() {});
9+
// no wait. Ensure resources are released anyway.
10+
11+
return 0;
12+
}
13+
14+
//CHECK: ---> piEnqueueKernelLaunch(
15+
//CHECK: ---> piQueueRelease(
16+
//CHECK: ---> piEventRelease(
17+
//CHECK: ---> piContextRelease(
18+
//CHECK: ---> piKernelRelease(
19+
//CHECK: ---> piProgramRelease(

0 commit comments

Comments
 (0)