diff --git a/runtime/mem_obj/mem_obj.cpp b/runtime/mem_obj/mem_obj.cpp index 8c480c4922..e687d6742a 100644 --- a/runtime/mem_obj/mem_obj.cpp +++ b/runtime/mem_obj/mem_obj.cpp @@ -67,7 +67,10 @@ MemObj::~MemObj() { } if (memoryManager) { - if (graphicsAllocation && !associatedMemObject && !isObjectRedescribed && !isHostPtrSVM) { + if (peekSharingHandler()) { + peekSharingHandler()->releaseReusedGraphicsAllocation(); + } + if (graphicsAllocation && !associatedMemObject && !isObjectRedescribed && !isHostPtrSVM && graphicsAllocation->reuseCount == 0) { bool doAsyncDestrucions = DebugManager.flags.EnableAsyncDestroyAllocations.get(); if (!doAsyncDestrucions) { needWait = true; diff --git a/runtime/memory_manager/graphics_allocation.h b/runtime/memory_manager/graphics_allocation.h index 53820085d3..75e619d837 100644 --- a/runtime/memory_manager/graphics_allocation.h +++ b/runtime/memory_manager/graphics_allocation.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "runtime/helpers/debug_helpers.h" #include "runtime/memory_manager/host_ptr_defines.h" @@ -116,6 +117,7 @@ class GraphicsAllocation : public IDNode { uint64_t gpuBaseAddress = 0; Gmm *gmm = nullptr; uint64_t allocationOffset = 0u; + std::atomic reuseCount{0}; // GraphicsAllocation can be reused by shared resources int residencyTaskCount = ObjectNotResident; diff --git a/runtime/sharings/sharing.h b/runtime/sharings/sharing.h index 3ab62b8e9d..cc3d7384ac 100644 --- a/runtime/sharings/sharing.h +++ b/runtime/sharings/sharing.h @@ -55,6 +55,7 @@ class SharingHandler { virtual ~SharingHandler() = default; virtual void getMemObjectInfo(size_t ¶mValueSize, void *¶mValue){}; + virtual void releaseReusedGraphicsAllocation(){}; protected: virtual void synchronizeHandler(UpdateData *updateData); diff --git a/unit_tests/mem_obj/mem_obj_tests.cpp b/unit_tests/mem_obj/mem_obj_tests.cpp index a83f8ae99a..386d21c9cf 100644 --- a/unit_tests/mem_obj/mem_obj_tests.cpp +++ b/unit_tests/mem_obj/mem_obj_tests.cpp @@ -27,6 +27,7 @@ #include "unit_tests/mocks/mock_deferred_deleter.h" #include "unit_tests/mocks/mock_graphics_allocation.h" #include "unit_tests/mocks/mock_memory_manager.h" +#include "unit_tests/fixtures/memory_management_fixture.h" #include "gtest/gtest.h" using namespace OCLRT; @@ -305,3 +306,47 @@ TEST(MemObj, givenDefaultWhenAskedForCpuMappingThenReturnTrue) { EXPECT_FALSE(memObj.peekSharingHandler()); EXPECT_TRUE(memObj.mappingOnCpuAllowed()); } + +TEST(MemObj, givenMultipleMemObjectsWithReusedGraphicsAllocationWhenDestroyedThenFreeAllocationOnce) { + // Each SharingHandler should have own implementation of reuseCount management + struct MySharingHandler : public SharingHandler { + MySharingHandler(GraphicsAllocation *allocation) : allocation(allocation) { + allocation->reuseCount++; + } + void releaseReusedGraphicsAllocation() override { + allocation->reuseCount--; + } + + GraphicsAllocation *allocation = nullptr; + }; + + MockMemoryManager memoryManager; + MockContext context; + context.setMemoryManager(&memoryManager); + + MemoryManagementFixture memoryLeaksCheck; + memoryLeaksCheck.SetUp(); + + auto allocation = memoryManager.allocateGraphicsMemory(1); + + auto memObj1 = new MemObj(&context, CL_MEM_OBJECT_BUFFER, 0, 1, nullptr, nullptr, allocation, true, false, false); + memObj1->setSharingHandler(new MySharingHandler(allocation)); + + auto memObj2 = new MemObj(&context, CL_MEM_OBJECT_BUFFER, 0, 1, nullptr, nullptr, allocation, true, false, false); + memObj2->setSharingHandler(new MySharingHandler(allocation)); + + auto memObj3 = new MemObj(&context, CL_MEM_OBJECT_BUFFER, 0, 1, nullptr, nullptr, allocation, true, false, false); + memObj3->setSharingHandler(new MySharingHandler(allocation)); + + EXPECT_EQ(3u, allocation->reuseCount.load()); + + delete memObj3; + EXPECT_EQ(2u, allocation->reuseCount.load()); + delete memObj1; + EXPECT_EQ(1u, allocation->reuseCount.load()); + + delete memObj2; + + // GraphicsAllocation should be removed by last memObj + memoryLeaksCheck.TearDown(); +}