Skip to content

Commit 255b422

Browse files
committed
Clear resource pool when running out of memory
Signed-off-by: Steffen Larsen <[email protected]>
1 parent 7c2f400 commit 255b422

File tree

6 files changed

+120
-48
lines changed

6 files changed

+120
-48
lines changed

sycl/include/CL/sycl/detail/resource_pool.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,11 @@ class __SYCL_EXPORT ResourcePool {
184184
MPlatform = Platform;
185185
}
186186

187+
/// Returns true if the resource pool is enabled and false otherwise.
188+
///
189+
/// \return a boolean value specifying whether the pool is enabled.
190+
bool isEnabled() { return MIsPoolingEnabled; }
191+
187192
/// Creates a managed resource from the pool.
188193
///
189194
/// \param Range is the range of the resulting buffer.

sycl/source/detail/device_image_impl.hpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,14 +194,12 @@ class device_image_impl {
194194
RT::PiMem &get_spec_const_buffer_ref() noexcept {
195195
std::lock_guard<std::mutex> Lock{MSpecConstAccessMtx};
196196
if (nullptr == MSpecConstsBuffer && !MSpecConstsBlob.empty()) {
197-
const detail::plugin &Plugin = getSyclObjImpl(MContext)->getPlugin();
198197
// Uses PI_MEM_FLAGS_HOST_PTR_COPY instead of PI_MEM_FLAGS_HOST_PTR_USE
199198
// since post-enqueue cleanup might trigger destruction of
200199
// device_image_impl and, as a result, destruction of MSpecConstsBlob
201200
// while MSpecConstsBuffer is still in use.
202201
// TODO consider changing the lifetime of device_image_impl instead
203-
memBufferCreateHelper(Plugin,
204-
detail::getSyclObjImpl(MContext)->getHandleRef(),
202+
memBufferCreateHelper(detail::getSyclObjImpl(MContext),
205203
PI_MEM_FLAGS_ACCESS_RW | PI_MEM_FLAGS_HOST_PTR_COPY,
206204
MSpecConstsBlob.size(), MSpecConstsBlob.data(),
207205
&MSpecConstsBuffer, nullptr);

sycl/source/detail/mem_alloc_helper.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
__SYCL_INLINE_NAMESPACE(cl) {
1414
namespace sycl {
1515
namespace detail {
16-
void memBufferCreateHelper(const plugin &Plugin, pi_context Ctx,
16+
class context_impl;
17+
18+
void memBufferCreateHelper(std::shared_ptr<context_impl> CtxImpl,
1719
pi_mem_flags Flags, size_t Size, void *HostPtr,
1820
pi_mem *RetMem,
1921
const pi_mem_properties *Props = nullptr);

sycl/source/detail/memory_manager.cpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,11 @@ static void waitForEvents(const std::vector<EventImplPtr> &Events) {
124124
}
125125
}
126126

127-
void memBufferCreateHelper(const plugin &Plugin, pi_context Ctx,
128-
pi_mem_flags Flags, size_t Size, void *HostPtr,
129-
pi_mem *RetMem, const pi_mem_properties *Props) {
127+
static pi_result memBufferCreateNocheckHelper(const plugin &Plugin,
128+
pi_context Ctx,
129+
pi_mem_flags Flags, size_t Size,
130+
void *HostPtr, pi_mem *RetMem,
131+
const pi_mem_properties *Props) {
130132
#ifdef XPTI_ENABLE_INSTRUMENTATION
131133
uint64_t CorrID = 0;
132134
#endif
@@ -147,11 +149,30 @@ void memBufferCreateHelper(const plugin &Plugin, pi_context Ctx,
147149
CorrID);
148150
}};
149151
#endif
150-
Plugin.call<PiApiKind::piMemBufferCreate>(Ctx, Flags, Size, HostPtr, RetMem,
151-
Props);
152+
return Plugin.call_nocheck<PiApiKind::piMemBufferCreate>(
153+
Ctx, Flags, Size, HostPtr, RetMem, Props);
152154
}
153155
}
154156

157+
void memBufferCreateHelper(std::shared_ptr<context_impl> CtxImpl,
158+
pi_mem_flags Flags, size_t Size, void *HostPtr,
159+
pi_mem *RetMem, const pi_mem_properties *Props) {
160+
const detail::plugin &Plugin = CtxImpl->getPlugin();
161+
RT::PiResult Err = memBufferCreateNocheckHelper(
162+
Plugin, CtxImpl->getHandleRef(), Flags, Size, HostPtr, RetMem, Props);
163+
164+
ResourcePool &Resources = CtxImpl->getResourcePool();
165+
if (Err == PI_MEM_OBJECT_ALLOCATION_FAILURE && Resources.isEnabled()) {
166+
// Clear resource pool and retry allocation.
167+
Resources.clear();
168+
Err = memBufferCreateNocheckHelper(Plugin, CtxImpl->getHandleRef(), Flags,
169+
Size, HostPtr, RetMem, Props);
170+
}
171+
172+
if (Err != PI_SUCCESS)
173+
Plugin.reportPiError(Err, "memBufferCreateHelper()");
174+
}
175+
155176
void memReleaseHelper(const plugin &Plugin, pi_mem Mem) {
156177
// FIXME piMemRelease does not guarante memory release. It is only true if
157178
// reference counter is 1. However, SYCL runtime currently only calls
@@ -361,9 +382,8 @@ MemoryManager::allocateBufferObject(ContextImplPtr TargetContext, void *UserPtr,
361382
CreationFlags |= PI_MEM_FLAGS_HOST_PTR_ALLOC;
362383

363384
RT::PiMem NewMem = nullptr;
364-
const detail::plugin &Plugin = TargetContext->getPlugin();
365-
memBufferCreateHelper(Plugin, TargetContext->getHandleRef(), CreationFlags,
366-
Size, UserPtr, &NewMem, nullptr);
385+
memBufferCreateHelper(TargetContext, CreationFlags, Size, UserPtr, &NewMem,
386+
nullptr);
367387
return NewMem;
368388
}
369389

sycl/source/detail/resource_pool.cpp

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,21 @@ ResourcePool::FreeEntry ResourcePool::getOrAllocateEntry(
4242
assert(Size && "Size must be greater than 0");
4343
assert(ContextImplPtr->getPlatformImpl() == MPlatform &&
4444
"Context platform does not match the resource pool platform.");
45-
std::lock_guard<std::mutex> Lock{MMutex};
45+
{
46+
std::lock_guard<std::mutex> Lock{MMutex};
4647

47-
// Find the free entry with the smallest suitable size.
48-
auto FoundFreeEntry = MFreeEntries.upper_bound(Size - 1);
48+
// Find the free entry with the smallest suitable size.
49+
auto FoundFreeEntry = MFreeEntries.upper_bound(Size - 1);
4950

50-
// If there was a fitting free entry in the pool, remove and return it.
51-
const bool IsOldEntry = FoundFreeEntry != MFreeEntries.end();
52-
if (IsNewEntry)
53-
*IsNewEntry = !IsOldEntry;
54-
if (IsOldEntry) {
55-
FreeEntry Entry = *FoundFreeEntry;
56-
MFreeEntries.erase(FoundFreeEntry);
57-
return Entry;
51+
// If there was a fitting free entry in the pool, remove and return it.
52+
const bool IsOldEntry = FoundFreeEntry != MFreeEntries.end();
53+
if (IsNewEntry)
54+
*IsNewEntry = !IsOldEntry;
55+
if (IsOldEntry) {
56+
FreeEntry Entry = *FoundFreeEntry;
57+
MFreeEntries.erase(FoundFreeEntry);
58+
return Entry;
59+
}
5860
}
5961

6062
// If there was no suitable free entry we allocate memory and return it in a
@@ -63,8 +65,8 @@ ResourcePool::FreeEntry ResourcePool::getOrAllocateEntry(
6365
if (DataPtr)
6466
MemFlags |= PI_MEM_FLAGS_HOST_PTR_COPY;
6567
RT::PiMem NewResMem;
66-
memBufferCreateHelper(MPlatform->getPlugin(), ContextImplPtr->getHandleRef(),
67-
MemFlags, Size, DataPtr, &NewResMem, nullptr);
68+
memBufferCreateHelper(ContextImplPtr, MemFlags, Size, DataPtr, &NewResMem,
69+
nullptr);
6870
++MAllocCount;
6971
return {Size, NewResMem};
7072
}

sycl/source/detail/usm/usm_impl.cpp

Lines changed: 68 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,15 @@ using alloc = cl::sycl::usm::alloc;
4343
namespace detail {
4444
namespace usm {
4545

46-
void *alignedAllocHost(size_t Alignment, size_t Size, const context &Ctxt,
47-
alloc Kind, const detail::code_location &CL) {
46+
static pi_result alignedAllocHostHelper(size_t Alignment, size_t Size,
47+
const context &Ctxt, alloc Kind,
48+
const detail::code_location &CL,
49+
void **OutPtr) {
4850
XPTI_CREATE_TRACEPOINT(CL);
49-
void *RetVal = nullptr;
50-
if (Size == 0)
51-
return nullptr;
51+
if (Size == 0) {
52+
*OutPtr = nullptr;
53+
return PI_SUCCESS;
54+
}
5255
if (Ctxt.is_host()) {
5356
if (!Alignment) {
5457
// worst case default
@@ -57,10 +60,11 @@ void *alignedAllocHost(size_t Alignment, size_t Size, const context &Ctxt,
5760

5861
aligned_allocator<char> Alloc(Alignment);
5962
try {
60-
RetVal = Alloc.allocate(Size);
63+
*OutPtr = Alloc.allocate(Size);
6164
} catch (const std::bad_alloc &) {
6265
// Conform with Specification behavior
63-
RetVal = nullptr;
66+
*OutPtr = nullptr;
67+
return PI_MEM_OBJECT_ALLOCATION_FAILURE;
6468
}
6569
} else {
6670
std::shared_ptr<context_impl> CtxImpl = detail::getSyclObjImpl(Ctxt);
@@ -71,13 +75,13 @@ void *alignedAllocHost(size_t Alignment, size_t Size, const context &Ctxt,
7175
switch (Kind) {
7276
case alloc::host: {
7377
Error = Plugin.call_nocheck<PiApiKind::piextUSMHostAlloc>(
74-
&RetVal, C, nullptr, Size, Alignment);
78+
OutPtr, C, nullptr, Size, Alignment);
7579
break;
7680
}
7781
case alloc::device:
7882
case alloc::shared:
7983
case alloc::unknown: {
80-
RetVal = nullptr;
84+
*OutPtr = nullptr;
8185
Error = PI_INVALID_VALUE;
8286
break;
8387
}
@@ -86,21 +90,41 @@ void *alignedAllocHost(size_t Alignment, size_t Size, const context &Ctxt,
8690
// Error is for debugging purposes.
8791
// The spec wants a nullptr returned, not an exception.
8892
if (Error != PI_SUCCESS)
89-
return nullptr;
93+
*OutPtr = nullptr;
94+
95+
return Error;
96+
}
97+
return PI_SUCCESS;
98+
}
99+
100+
void *alignedAllocHost(size_t Alignment, size_t Size, const context &Ctxt,
101+
alloc Kind, const detail::code_location &CL) {
102+
void *RetVal;
103+
pi_result Err =
104+
alignedAllocHostHelper(Alignment, Size, Ctxt, Kind, CL, &RetVal);
105+
106+
std::shared_ptr<context_impl> CtxImpl = detail::getSyclObjImpl(Ctxt);
107+
ResourcePool &Resources = CtxImpl->getResourcePool();
108+
if (Err == PI_OUT_OF_RESOURCES && Resources.isEnabled()) {
109+
// Clear resource pool and retry allocation.
110+
Resources.clear();
111+
alignedAllocHostHelper(Alignment, Size, Ctxt, Kind, CL, &RetVal);
90112
}
91113
return RetVal;
92114
}
93115

94-
void *alignedAlloc(size_t Alignment, size_t Size, const context &Ctxt,
95-
const device &Dev, alloc Kind,
96-
const detail::code_location &CL) {
116+
static pi_result alignedAllocHelper(size_t Alignment, size_t Size,
117+
const context &Ctxt, const device &Dev,
118+
alloc Kind, const detail::code_location &CL,
119+
void **OutPtr) {
97120
XPTI_CREATE_TRACEPOINT(CL);
98-
void *RetVal = nullptr;
99-
if (Size == 0)
100-
return nullptr;
121+
if (Size == 0) {
122+
*OutPtr = nullptr;
123+
return PI_SUCCESS;
124+
}
101125
if (Ctxt.is_host()) {
102126
if (Kind == alloc::unknown) {
103-
RetVal = nullptr;
127+
*OutPtr = nullptr;
104128
} else {
105129
if (!Alignment) {
106130
// worst case default
@@ -109,10 +133,11 @@ void *alignedAlloc(size_t Alignment, size_t Size, const context &Ctxt,
109133

110134
aligned_allocator<char> Alloc(Alignment);
111135
try {
112-
RetVal = Alloc.allocate(Size);
136+
*OutPtr = Alloc.allocate(Size);
113137
} catch (const std::bad_alloc &) {
114138
// Conform with Specification behavior
115-
RetVal = nullptr;
139+
*OutPtr = nullptr;
140+
return PI_MEM_OBJECT_ALLOCATION_FAILURE;
116141
}
117142
}
118143
} else {
@@ -126,18 +151,18 @@ void *alignedAlloc(size_t Alignment, size_t Size, const context &Ctxt,
126151
case alloc::device: {
127152
Id = detail::getSyclObjImpl(Dev)->getHandleRef();
128153
Error = Plugin.call_nocheck<PiApiKind::piextUSMDeviceAlloc>(
129-
&RetVal, C, Id, nullptr, Size, Alignment);
154+
OutPtr, C, Id, nullptr, Size, Alignment);
130155
break;
131156
}
132157
case alloc::shared: {
133158
Id = detail::getSyclObjImpl(Dev)->getHandleRef();
134159
Error = Plugin.call_nocheck<PiApiKind::piextUSMSharedAlloc>(
135-
&RetVal, C, Id, nullptr, Size, Alignment);
160+
OutPtr, C, Id, nullptr, Size, Alignment);
136161
break;
137162
}
138163
case alloc::host:
139164
case alloc::unknown: {
140-
RetVal = nullptr;
165+
*OutPtr = nullptr;
141166
Error = PI_INVALID_VALUE;
142167
break;
143168
}
@@ -146,7 +171,27 @@ void *alignedAlloc(size_t Alignment, size_t Size, const context &Ctxt,
146171
// Error is for debugging purposes.
147172
// The spec wants a nullptr returned, not an exception.
148173
if (Error != PI_SUCCESS)
149-
return nullptr;
174+
*OutPtr = nullptr;
175+
176+
return Error;
177+
}
178+
179+
return PI_SUCCESS;
180+
}
181+
182+
void *alignedAlloc(size_t Alignment, size_t Size, const context &Ctxt,
183+
const device &Dev, alloc Kind,
184+
const detail::code_location &CL) {
185+
void *RetVal;
186+
pi_result Err =
187+
alignedAllocHelper(Alignment, Size, Ctxt, Dev, Kind, CL, &RetVal);
188+
189+
std::shared_ptr<context_impl> CtxImpl = detail::getSyclObjImpl(Ctxt);
190+
ResourcePool &Resources = CtxImpl->getResourcePool();
191+
if (Err == PI_OUT_OF_RESOURCES && Resources.isEnabled()) {
192+
// Clear resource pool and retry allocation.
193+
Resources.clear();
194+
alignedAllocHelper(Alignment, Size, Ctxt, Dev, Kind, CL, &RetVal);
150195
}
151196
return RetVal;
152197
}

0 commit comments

Comments
 (0)