Skip to content

Commit 4551c42

Browse files
committed
[Bindless][UR][LevelZero] Fix memory leak caused by not destroying sampler handles
1 parent a91b7ce commit 4551c42

File tree

2 files changed

+36
-8
lines changed

2 files changed

+36
-8
lines changed

unified-runtime/source/adapters/level_zero/device.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,10 @@ struct ur_device_handle_t_ : ur_object {
237237
std::unordered_map<ur_exp_image_native_handle_t, ze_image_handle_t>
238238
ZeOffsetToImageHandleMap;
239239

240+
// Map (sampled) bindless image handle to its corresponding sampler.
241+
std::unordered_map<ur_exp_image_native_handle_t, ze_sampler_handle_t>
242+
ZeImageToSamplerMap;
243+
240244
// unique ephemeral identifer of the device in the adapter
241245
std::optional<DeviceId> Id;
242246
};

unified-runtime/source/adapters/level_zero/image_common.cpp

+32-8
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,8 @@ ur_result_t bindlessImagesCreateImpl(ur_context_handle_t hContext,
308308
ZeImageDesc.pNext = &BindlessDesc;
309309

310310
ZeStruct<ze_sampler_desc_t> ZeSamplerDesc;
311-
if (hSampler) {
311+
const bool WithSampler = hSampler != nullptr;
312+
if (WithSampler) {
312313
ZeSamplerDesc = hSampler->ZeSamplerDesc;
313314
BindlessDesc.pNext = &ZeSamplerDesc;
314315
BindlessDesc.flags |= ZE_IMAGE_BINDLESS_EXP_FLAG_SAMPLED_IMAGE;
@@ -338,7 +339,7 @@ ur_result_t bindlessImagesCreateImpl(ur_context_handle_t hContext,
338339
MemAllocProperties.type == ZE_MEMORY_TYPE_SHARED) {
339340
ZeStruct<ze_image_pitched_exp_desc_t> PitchedDesc;
340341
PitchedDesc.ptr = reinterpret_cast<void *>(hImageMem);
341-
if (hSampler) {
342+
if (WithSampler) {
342343
ZeSamplerDesc.pNext = &PitchedDesc;
343344
} else {
344345
BindlessDesc.pNext = &PitchedDesc;
@@ -372,9 +373,19 @@ ur_result_t bindlessImagesCreateImpl(ur_context_handle_t hContext,
372373
(ZeImageTranslated, &DeviceOffset));
373374
*phImage = DeviceOffset;
374375

375-
std::shared_lock<ur_shared_mutex> Lock(hDevice->Mutex);
376-
hDevice->ZeOffsetToImageHandleMap[*phImage] = ZeImage;
377-
Lock.release();
376+
std::shared_lock<ur_shared_mutex> Lock(hDevice->Mutex, std::defer_lock);
377+
if (WithSampler) {
378+
// Get a non-exclsuive (shared) read-access to the sampler handle.
379+
std::shared_lock<ur_shared_mutex> SLock(hSampler->Mutex, std::defer_lock);
380+
std::scoped_lock LockAll(Lock, SLock);
381+
// Associate the bindless image with host object handle and sampler handle.
382+
hDevice->ZeOffsetToImageHandleMap[*phImage] = ZeImage;
383+
hDevice->ZeImageToSamplerMap[*phImage] = hSampler->ZeSampler;
384+
} else {
385+
Lock.lock();
386+
hDevice->ZeOffsetToImageHandleMap[*phImage] = ZeImage;
387+
Lock.release();
388+
}
378389
return UR_RESULT_SUCCESS;
379390
}
380391

@@ -1006,9 +1017,22 @@ ur_result_t urBindlessImagesSampledImageHandleDestroyExp(
10061017
ur_context_handle_t hContext, ur_device_handle_t hDevice,
10071018
ur_exp_image_native_handle_t hImage) {
10081019
// Sampled image is a combination of unsampled image and sampler.
1009-
// Sampler is released in urSamplerRelease.
1010-
return ur::level_zero::urBindlessImagesUnsampledImageHandleDestroyExp(
1011-
hContext, hDevice, hImage);
1020+
// We destroy the unsampled image image handle first; then the sampler handle.
1021+
UR_CALL(ur::level_zero::urBindlessImagesUnsampledImageHandleDestroyExp(
1022+
hContext, hDevice, hImage));
1023+
1024+
std::shared_lock<ur_shared_mutex> Lock(hDevice->Mutex);
1025+
auto Item = hDevice->ZeImageToSamplerMap.find(hImage);
1026+
if (Item != hDevice->ZeImageToSamplerMap.end()) {
1027+
hDevice->ZeImageToSamplerMap.erase(Item);
1028+
Lock.release();
1029+
ZE2UR_CALL(zeSamplerDestroy, (Item->second));
1030+
} else {
1031+
Lock.release();
1032+
return UR_RESULT_ERROR_INVALID_NULL_HANDLE;
1033+
}
1034+
1035+
return UR_RESULT_SUCCESS;
10121036
}
10131037

10141038
ur_result_t

0 commit comments

Comments
 (0)