From 9159e2acd41eafa3385311f5aadbef7d4cd5490c Mon Sep 17 00:00:00 2001 From: Dominik Dabek Date: Tue, 8 Oct 2024 10:56:02 +0000 Subject: [PATCH] fix: limit max size for allocation reuse Limit max size for allocation reuse mechanism to 256MB. Related-To: NEO-6893 Signed-off-by: Dominik Dabek --- .../memory_manager/unified_memory_manager.cpp | 6 ++ .../memory_manager/unified_memory_manager.h | 8 ++- .../unified_memory_manager_cache_tests.cpp | 64 +++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/shared/source/memory_manager/unified_memory_manager.cpp b/shared/source/memory_manager/unified_memory_manager.cpp index 413005ba89..d6c8d95337 100644 --- a/shared/source/memory_manager/unified_memory_manager.cpp +++ b/shared/source/memory_manager/unified_memory_manager.cpp @@ -44,6 +44,9 @@ void SVMAllocsManager::MapBasedAllocationTracker::remove(const SvmAllocationData } bool SVMAllocsManager::SvmAllocationCache::insert(size_t size, void *ptr) { + if (false == sizeAllowed(size)) { + return false; + } std::lock_guard lock(this->mtx); if (size + this->totalSize > this->maxSize) { return false; @@ -62,6 +65,9 @@ bool SVMAllocsManager::SvmAllocationCache::allocUtilizationAllows(size_t request } void *SVMAllocsManager::SvmAllocationCache::get(size_t size, const UnifiedMemoryProperties &unifiedMemoryProperties, SVMAllocsManager *svmAllocsManager) { + if (false == sizeAllowed(size)) { + return nullptr; + } std::lock_guard lock(this->mtx); for (auto allocationIter = std::lower_bound(allocations.begin(), allocations.end(), size); allocationIter != allocations.end(); diff --git a/shared/source/memory_manager/unified_memory_manager.h b/shared/source/memory_manager/unified_memory_manager.h index eef2eaa3eb..44850c4d0c 100644 --- a/shared/source/memory_manager/unified_memory_manager.h +++ b/shared/source/memory_manager/unified_memory_manager.h @@ -157,12 +157,16 @@ class SVMAllocsManager { }; struct SvmAllocationCache { + static constexpr size_t maxServicedSize = 256 * MemoryConstants::megaByte; + static constexpr size_t minimalSizeToCheckUtilization = 4 * MemoryConstants::pageSize64k; + static constexpr double minimalAllocUtilization = 0.5; + + static bool sizeAllowed(size_t size) { return size <= SvmAllocationCache::maxServicedSize; } bool insert(size_t size, void *); static bool allocUtilizationAllows(size_t requestedSize, size_t reuseCandidateSize); void *get(size_t size, const UnifiedMemoryProperties &unifiedMemoryProperties, SVMAllocsManager *svmAllocsManager); void trim(SVMAllocsManager *svmAllocsManager); - static constexpr size_t minimalSizeToCheckUtilization = 4 * MemoryConstants::pageSize64k; - static constexpr double minimalAllocUtilization = 0.5; + std::vector allocations; std::mutex mtx; size_t maxSize = 0; diff --git a/shared/test/unit_test/memory_manager/unified_memory_manager_cache_tests.cpp b/shared/test/unit_test/memory_manager/unified_memory_manager_cache_tests.cpp index af3b195ef1..9853a01737 100644 --- a/shared/test/unit_test/memory_manager/unified_memory_manager_cache_tests.cpp +++ b/shared/test/unit_test/memory_manager/unified_memory_manager_cache_tests.cpp @@ -99,6 +99,11 @@ TEST(SvmAllocationCacheSimpleTest, givenDifferentSizesWhenCheckingIfAllocUtiliza EXPECT_TRUE(SVMAllocsManager::SvmAllocationCache::allocUtilizationAllows(allocationSizeBasis, allocationSizeBasis)); } +TEST(SvmAllocationCacheSimpleTest, givenDifferentSizesWhenCheckingIfSizeAllowsThenReturnCorrectValue) { + EXPECT_TRUE(SVMAllocsManager::SvmAllocationCache::sizeAllowed(256 * MemoryConstants::megaByte)); + EXPECT_FALSE(SVMAllocsManager::SvmAllocationCache::sizeAllowed(256 * MemoryConstants::megaByte + 1)); +} + struct SvmAllocationCacheTestFixture { SvmAllocationCacheTestFixture() : executionEnvironment(defaultHwInfo.get()) {} void setUp() { @@ -376,6 +381,36 @@ TEST_F(SvmDeviceAllocationCacheTest, givenAllocationsWithDifferentSizesWhenAlloc EXPECT_EQ(svmManager->usmDeviceAllocationsCache.allocations.size(), 0u); } +TEST_F(SvmDeviceAllocationCacheTest, givenAllocationOverSizeLimitWhenAllocatingAfterFreeThenDontSaveForReuse) { + std::unique_ptr deviceFactory(new UltDeviceFactory(1, 1)); + RootDeviceIndicesContainer rootDeviceIndices = {mockRootDeviceIndex}; + std::map deviceBitfields{{mockRootDeviceIndex, mockDeviceBitfield}}; + DebugManagerStateRestore restore; + debugManager.flags.ExperimentalEnableDeviceAllocationCache.set(1); + auto device = deviceFactory->rootDevices[0]; + auto svmManager = std::make_unique(device->getMemoryManager(), false); + svmManager->initUsmAllocationsCaches(*device); + ASSERT_TRUE(svmManager->usmDeviceAllocationsCacheEnabled); + svmManager->usmDeviceAllocationsCache.maxSize = 1 * MemoryConstants::gigaByte; + const auto notAcceptedAllocSize = SVMAllocsManager::SvmAllocationCache::maxServicedSize + 1; + + SVMAllocsManager::UnifiedMemoryProperties unifiedMemoryProperties(InternalMemoryType::deviceUnifiedMemory, 1, rootDeviceIndices, deviceBitfields); + unifiedMemoryProperties.device = device; + auto mockMemoryManager = reinterpret_cast(device->getMemoryManager()); + auto mockGa = std::make_unique(mockRootDeviceIndex, nullptr, notAcceptedAllocSize); + mockGa->gpuAddress = 0xbadf00; + mockGa->cpuPtr = reinterpret_cast(0xbadf00); + mockGa->setAllocationType(AllocationType::svmGpu); + mockMemoryManager->mockGa = mockGa.release(); + mockMemoryManager->returnMockGAFromDevicePool = true; + auto allocation = svmManager->createUnifiedMemoryAllocation(notAcceptedAllocSize, unifiedMemoryProperties); + EXPECT_EQ(reinterpret_cast(0xbadf00), allocation); + + svmManager->freeSVMAlloc(allocation); + + EXPECT_EQ(0u, svmManager->usmDeviceAllocationsCache.allocations.size()); +} + TEST_F(SvmDeviceAllocationCacheTest, givenMultipleAllocationsWhenAllocatingAfterFreeThenReturnAllocationsInCacheStartingFromSmallest) { std::unique_ptr deviceFactory(new UltDeviceFactory(1, 1)); RootDeviceIndicesContainer rootDeviceIndices = {mockRootDeviceIndex}; @@ -872,6 +907,35 @@ TEST_F(SvmHostAllocationCacheTest, givenAllocationsWithDifferentSizesWhenAllocat EXPECT_EQ(svmManager->usmHostAllocationsCache.allocations.size(), 0u); } +TEST_F(SvmHostAllocationCacheTest, givenAllocationOverSizeLimitWhenAllocatingAfterFreeThenDontSaveForReuse) { + std::unique_ptr deviceFactory(new UltDeviceFactory(1, 1)); + RootDeviceIndicesContainer rootDeviceIndices = {mockRootDeviceIndex}; + std::map deviceBitfields{{mockRootDeviceIndex, mockDeviceBitfield}}; + DebugManagerStateRestore restore; + debugManager.flags.ExperimentalEnableHostAllocationCache.set(1); + auto device = deviceFactory->rootDevices[0]; + auto svmManager = std::make_unique(device->getMemoryManager(), false); + svmManager->initUsmAllocationsCaches(*device); + ASSERT_TRUE(svmManager->usmHostAllocationsCacheEnabled); + svmManager->usmHostAllocationsCache.maxSize = 1 * MemoryConstants::gigaByte; + const auto notAcceptedAllocSize = SVMAllocsManager::SvmAllocationCache::maxServicedSize + 1; + + SVMAllocsManager::UnifiedMemoryProperties unifiedMemoryProperties(InternalMemoryType::hostUnifiedMemory, 1, rootDeviceIndices, deviceBitfields); + auto mockMemoryManager = reinterpret_cast(device->getMemoryManager()); + auto mockGa = std::make_unique(mockRootDeviceIndex, nullptr, notAcceptedAllocSize); + mockGa->gpuAddress = 0xbadf00; + mockGa->cpuPtr = reinterpret_cast(0xbadf00); + mockGa->setAllocationType(AllocationType::svmCpu); + mockMemoryManager->mockGa = mockGa.release(); + mockMemoryManager->returnMockGAFromHostPool = true; + auto allocation = svmManager->createHostUnifiedMemoryAllocation(notAcceptedAllocSize, unifiedMemoryProperties); + EXPECT_EQ(reinterpret_cast(0xbadf00), allocation); + + svmManager->freeSVMAlloc(allocation); + + EXPECT_EQ(0u, svmManager->usmHostAllocationsCache.allocations.size()); +} + TEST_F(SvmHostAllocationCacheTest, givenMultipleAllocationsWhenAllocatingAfterFreeThenReturnAllocationsInCacheStartingFromSmallest) { std::unique_ptr deviceFactory(new UltDeviceFactory(1, 1)); RootDeviceIndicesContainer rootDeviceIndices = {mockRootDeviceIndex};