Skip to content

Commit 24ec33c

Browse files
[SYCL] Fix PI event leak in memcpy2d device-host fallback (#8878)
The fallback mechanism for memcpy2d and copy2d between host and device enqueues a number of memcpy operations to/from device and inserts a marker event to signify the convergence. Currently the intermediate events are not correctly released, causing them to leak. This commit fixes this by utilizing an existing RAII PI event managed object to manage the lifetime of these events. --------- Signed-off-by: Larsen, Steffen <[email protected]>
1 parent 3bfa978 commit 24ec33c

File tree

4 files changed

+73
-45
lines changed

4 files changed

+73
-45
lines changed

sycl/source/detail/device_global_map_entry.cpp

-12
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,6 @@ namespace sycl {
1717
__SYCL_INLINE_VER_NAMESPACE(_V1) {
1818
namespace detail {
1919

20-
OwnedPiEvent::OwnedPiEvent(RT::PiEvent Event, const plugin &Plugin)
21-
: MEvent(Event), MPlugin(Plugin) {
22-
// Retain the event to share ownership of it.
23-
MPlugin.call<PiApiKind::piEventRetain>(*MEvent);
24-
}
25-
26-
OwnedPiEvent::~OwnedPiEvent() {
27-
// Release the event if the ownership was not transferred.
28-
if (MEvent.has_value())
29-
MPlugin.call<PiApiKind::piEventRelease>(*MEvent);
30-
}
31-
3220
DeviceGlobalUSMMem::~DeviceGlobalUSMMem() {
3321
// removeAssociatedResources is expected to have cleaned up both the pointer
3422
// and the event. When asserts are enabled the values are set, so we check

sycl/source/detail/device_global_map_entry.hpp

+1-33
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
#include <optional>
1616
#include <set>
1717

18+
#include <detail/pi_utils.hpp>
1819
#include <sycl/detail/defines_elementary.hpp>
19-
#include <sycl/detail/pi.hpp>
2020

2121
namespace sycl {
2222
__SYCL_INLINE_VER_NAMESPACE(_V1) {
@@ -28,38 +28,6 @@ class device_impl;
2828
class platform_impl;
2929
class queue_impl;
3030

31-
// RAII object for keeping ownership of a PI event.
32-
struct OwnedPiEvent {
33-
OwnedPiEvent(const plugin &Plugin) : MEvent{std::nullopt}, MPlugin{Plugin} {}
34-
OwnedPiEvent(RT::PiEvent Event, const plugin &Plugin);
35-
~OwnedPiEvent();
36-
37-
OwnedPiEvent(OwnedPiEvent &&Other)
38-
: MEvent(Other.MEvent), MPlugin(Other.MPlugin) {
39-
Other.MEvent = std::nullopt;
40-
}
41-
42-
// Copy constructor explicitly deleted for simplicity as it is not currently
43-
// used. Implement if needed.
44-
OwnedPiEvent(const OwnedPiEvent &Other) = delete;
45-
46-
operator bool() { return MEvent.has_value(); }
47-
48-
RT::PiEvent GetEvent() { return *MEvent; }
49-
50-
// Transfers the ownership of the event to the caller. The destructor will
51-
// no longer release the event.
52-
RT::PiEvent TransferOwnership() {
53-
RT::PiEvent Event = *MEvent;
54-
MEvent = std::nullopt;
55-
return Event;
56-
}
57-
58-
private:
59-
std::optional<RT::PiEvent> MEvent;
60-
const plugin &MPlugin;
61-
};
62-
6331
struct DeviceGlobalUSMMem {
6432
DeviceGlobalUSMMem(void *Ptr) : MPtr(Ptr) {}
6533
~DeviceGlobalUSMMem();

sycl/source/detail/memory_manager.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <detail/event_impl.hpp>
1212
#include <detail/mem_alloc_helper.hpp>
1313
#include <detail/memory_manager.hpp>
14+
#include <detail/pi_utils.hpp>
1415
#include <detail/queue_impl.hpp>
1516
#include <detail/xpti_registry.hpp>
1617

@@ -963,13 +964,18 @@ void MemoryManager::copy_2d_usm(const void *SrcMem, size_t SrcPitch,
963964
#endif // NDEBUG
964965

965966
// The fallback in this case is to insert a copy per row.
967+
std::vector<OwnedPiEvent> CopyEventsManaged;
968+
CopyEventsManaged.reserve(Height);
969+
// We'll need continuous range of events for a wait later as well.
966970
std::vector<RT::PiEvent> CopyEvents(Height);
967971
for (size_t I = 0; I < Height; ++I) {
968972
char *DstItBegin = static_cast<char *>(DstMem) + I * DstPitch;
969973
const char *SrcItBegin = static_cast<const char *>(SrcMem) + I * SrcPitch;
970974
Plugin.call<PiApiKind::piextUSMEnqueueMemcpy>(
971975
Queue->getHandleRef(), /* blocking */ PI_FALSE, DstItBegin, SrcItBegin,
972976
Width, DepEvents.size(), DepEvents.data(), CopyEvents.data() + I);
977+
CopyEventsManaged.emplace_back(CopyEvents[I], Plugin,
978+
/*TakeOwnership=*/true);
973979
}
974980

975981
// Then insert a wait to coalesce the copy events.

sycl/source/detail/pi_utils.hpp

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//==------------- pi_utils.hpp - Common PI utilities -----------------------==//
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+
#pragma once
10+
11+
#include <detail/plugin.hpp>
12+
#include <sycl/detail/defines_elementary.hpp>
13+
#include <sycl/detail/pi.hpp>
14+
15+
#include <optional>
16+
17+
namespace sycl {
18+
__SYCL_INLINE_VER_NAMESPACE(_V1) {
19+
namespace detail {
20+
21+
// RAII object for keeping ownership of a PI event.
22+
struct OwnedPiEvent {
23+
OwnedPiEvent(const plugin &Plugin) : MEvent{std::nullopt}, MPlugin{Plugin} {}
24+
OwnedPiEvent(RT::PiEvent Event, const plugin &Plugin,
25+
bool TakeOwnership = false)
26+
: MEvent(Event), MPlugin(Plugin) {
27+
// If it is not instructed to take ownership, retain the event to share
28+
// ownership of it.
29+
if (!TakeOwnership)
30+
MPlugin.call<PiApiKind::piEventRetain>(*MEvent);
31+
}
32+
~OwnedPiEvent() {
33+
// Release the event if the ownership was not transferred.
34+
if (MEvent.has_value())
35+
MPlugin.call<PiApiKind::piEventRelease>(*MEvent);
36+
}
37+
38+
OwnedPiEvent(OwnedPiEvent &&Other)
39+
: MEvent(Other.MEvent), MPlugin(Other.MPlugin) {
40+
Other.MEvent = std::nullopt;
41+
}
42+
43+
// Copy constructor explicitly deleted for simplicity as it is not currently
44+
// used. Implement if needed.
45+
OwnedPiEvent(const OwnedPiEvent &Other) = delete;
46+
47+
operator bool() { return MEvent.has_value(); }
48+
49+
RT::PiEvent GetEvent() { return *MEvent; }
50+
51+
// Transfers the ownership of the event to the caller. The destructor will
52+
// no longer release the event.
53+
RT::PiEvent TransferOwnership() {
54+
RT::PiEvent Event = *MEvent;
55+
MEvent = std::nullopt;
56+
return Event;
57+
}
58+
59+
private:
60+
std::optional<RT::PiEvent> MEvent;
61+
const plugin &MPlugin;
62+
};
63+
64+
} // namespace detail
65+
} // __SYCL_INLINE_VER_NAMESPACE(_V1)
66+
} // namespace sycl

0 commit comments

Comments
 (0)