fix: track usm reuse usage in multiple contexts

Add tracking of memory used for usm reuse mechanism when multiple cl
contexts are used.
Tracking for device added to NEO::Device, for host added to
NEO::MemoryManager.

This fixes usm reuse using x% of memory per each context instead of
globally.

Related-To: NEO-13308

Signed-off-by: Dominik Dabek <dominik.dabek@intel.com>
This commit is contained in:
Dominik Dabek 2024-11-26 13:02:19 +00:00 committed by Compute-Runtime-Automation
parent 250171688f
commit e55aa958b7
5 changed files with 255 additions and 45 deletions

View File

@ -216,6 +216,22 @@ class Device : public ReferenceTrackedObject<Device> {
std::atomic<uint32_t> debugExecutionCounter = 0;
std::unique_lock<std::mutex> obtainAllocationsReuseLock() const {
return std::unique_lock<std::mutex>(allocationsReuseMtx);
}
void recordAllocationSaveForReuse(size_t size) {
allocationsSavedForReuseSize += size;
}
void recordAllocationGetFromReuse(size_t size) {
allocationsSavedForReuseSize -= size;
}
size_t getAllocationsSavedForReuseSize() const {
return allocationsSavedForReuseSize;
}
protected:
Device() = delete;
Device(ExecutionEnvironment *executionEnvironment, const uint32_t rootDeviceIndex);
@ -292,6 +308,9 @@ class Device : public ReferenceTrackedObject<Device> {
ISAPoolAllocator isaPoolAllocator;
std::unique_ptr<UsmMemAllocPoolsManager> deviceUsmMemAllocPoolsManager;
size_t allocationsSavedForReuseSize = 0u;
mutable std::mutex allocationsReuseMtx;
struct {
bool isValid = false;
std::array<uint8_t, ProductHelper::uuidSize> id;

View File

@ -326,6 +326,22 @@ class MemoryManager {
virtual void getExtraDeviceProperties(uint32_t rootDeviceIndex, uint32_t *moduleId, uint16_t *serverType) { return; }
std::unique_lock<std::mutex> obtainHostAllocationsReuseLock() const {
return std::unique_lock<std::mutex>(hostAllocationsReuseMtx);
}
void recordHostAllocationSaveForReuse(size_t size) {
hostAllocationsSavedForReuseSize += size;
}
void recordHostAllocationGetFromReuse(size_t size) {
hostAllocationsSavedForReuseSize -= size;
}
size_t getHostAllocationsSavedForReuseSize() const {
return hostAllocationsSavedForReuseSize;
}
protected:
bool getAllocationData(AllocationData &allocationData, const AllocationProperties &properties, const void *hostPtr, const StorageInfo &storageInfo);
static void overrideAllocationData(AllocationData &allocationData, const AllocationProperties &properties);
@ -398,6 +414,8 @@ class MemoryManager {
std::mutex physicalMemoryAllocationMapMutex;
std::unique_ptr<std::atomic<size_t>[]> localMemAllocsSize;
std::atomic<size_t> sysMemAllocsSize;
size_t hostAllocationsSavedForReuseSize = 0u;
mutable std::mutex hostAllocationsReuseMtx;
};
std::unique_ptr<DeferredDeleter> createDeferredDeleter();

View File

@ -54,16 +54,27 @@ void SVMAllocsManager::MapBasedAllocationTracker::freeAllocations(NEO::MemoryMan
}
}
bool SVMAllocsManager::SvmAllocationCache::insert(size_t size, void *ptr) {
bool SVMAllocsManager::SvmAllocationCache::insert(size_t size, void *ptr, SvmAllocationData *svmData, MemoryManager *memoryManager) {
if (false == sizeAllowed(size)) {
return false;
}
std::lock_guard<std::mutex> lock(this->mtx);
if (size + this->totalSize > this->maxSize) {
return false;
if (auto device = svmData->device) {
auto lock = device->obtainAllocationsReuseLock();
const auto usedSize = device->getAllocationsSavedForReuseSize();
if (size + usedSize > this->maxSize) {
return false;
}
device->recordAllocationSaveForReuse(size);
} else {
auto lock = memoryManager->obtainHostAllocationsReuseLock();
const auto usedSize = memoryManager->getHostAllocationsSavedForReuseSize();
if (size + usedSize > this->maxSize) {
return false;
}
memoryManager->recordHostAllocationSaveForReuse(size);
}
allocations.emplace(std::lower_bound(allocations.begin(), allocations.end(), size), size, ptr);
this->totalSize += size;
return true;
}
@ -75,7 +86,7 @@ bool SVMAllocsManager::SvmAllocationCache::allocUtilizationAllows(size_t request
return true;
}
void *SVMAllocsManager::SvmAllocationCache::get(size_t size, const UnifiedMemoryProperties &unifiedMemoryProperties, SVMAllocsManager *svmAllocsManager) {
void *SVMAllocsManager::SvmAllocationCache::get(size_t size, const UnifiedMemoryProperties &unifiedMemoryProperties, SVMAllocsManager *svmAllocsManager, MemoryManager *memoryManager) {
if (false == sizeAllowed(size)) {
return nullptr;
}
@ -92,7 +103,13 @@ void *SVMAllocsManager::SvmAllocationCache::get(size_t size, const UnifiedMemory
if (svmAllocData->device == unifiedMemoryProperties.device &&
svmAllocData->allocationFlagsProperty.allFlags == unifiedMemoryProperties.allocationFlags.allFlags &&
svmAllocData->allocationFlagsProperty.allAllocFlags == unifiedMemoryProperties.allocationFlags.allAllocFlags) {
totalSize -= allocationIter->allocationSize;
if (svmAllocData->device) {
auto lock = svmAllocData->device->obtainAllocationsReuseLock();
svmAllocData->device->recordAllocationGetFromReuse(allocationIter->allocationSize);
} else {
auto lock = memoryManager->obtainHostAllocationsReuseLock();
memoryManager->recordHostAllocationGetFromReuse(allocationIter->allocationSize);
}
allocations.erase(allocationIter);
return allocationPtr;
}
@ -100,15 +117,21 @@ void *SVMAllocsManager::SvmAllocationCache::get(size_t size, const UnifiedMemory
return nullptr;
}
void SVMAllocsManager::SvmAllocationCache::trim(SVMAllocsManager *svmAllocsManager) {
void SVMAllocsManager::SvmAllocationCache::trim(SVMAllocsManager *svmAllocsManager, MemoryManager *memoryManager) {
std::lock_guard<std::mutex> lock(this->mtx);
for (auto &cachedAllocationInfo : this->allocations) {
SvmAllocationData *svmData = svmAllocsManager->getSVMAlloc(cachedAllocationInfo.allocation);
DEBUG_BREAK_IF(nullptr == svmData);
if (svmData->device) {
auto lock = svmData->device->obtainAllocationsReuseLock();
svmData->device->recordAllocationGetFromReuse(cachedAllocationInfo.allocationSize);
} else {
auto lock = memoryManager->obtainHostAllocationsReuseLock();
memoryManager->recordHostAllocationGetFromReuse(cachedAllocationInfo.allocationSize);
}
svmAllocsManager->freeSVMAllocImpl(cachedAllocationInfo.allocation, FreePolicyType::none, svmData);
}
this->allocations.clear();
this->totalSize = 0u;
}
SvmAllocationData *SVMAllocsManager::MapBasedAllocationTracker::get(const void *ptr) {
@ -251,7 +274,7 @@ void *SVMAllocsManager::createHostUnifiedMemoryAllocation(size_t size,
unifiedMemoryProperties.cacheRegion = MemoryPropertiesHelper::getCacheRegion(memoryProperties.allocationFlags);
if (this->usmHostAllocationsCacheEnabled) {
void *allocationFromCache = this->usmHostAllocationsCache.get(size, memoryProperties, this);
void *allocationFromCache = this->usmHostAllocationsCache.get(size, memoryProperties, this, memoryManager);
if (allocationFromCache) {
return allocationFromCache;
}
@ -329,7 +352,7 @@ void *SVMAllocsManager::createUnifiedMemoryAllocation(size_t size,
unifiedMemoryProperties.flags.isUSMDeviceAllocation = true;
if (this->usmDeviceAllocationsCacheEnabled &&
false == memoryProperties.isInternalAllocation) {
void *allocationFromCache = this->usmDeviceAllocationsCache.get(size, memoryProperties, this);
void *allocationFromCache = this->usmDeviceAllocationsCache.get(size, memoryProperties, this, memoryManager);
if (allocationFromCache) {
return allocationFromCache;
}
@ -478,13 +501,13 @@ bool SVMAllocsManager::freeSVMAlloc(void *ptr, bool blocking) {
if (InternalMemoryType::deviceUnifiedMemory == svmData->memoryType &&
false == svmData->isInternalAllocation &&
this->usmDeviceAllocationsCacheEnabled) {
if (this->usmDeviceAllocationsCache.insert(svmData->gpuAllocations.getDefaultGraphicsAllocation()->getUnderlyingBufferSize(), ptr)) {
if (this->usmDeviceAllocationsCache.insert(svmData->gpuAllocations.getDefaultGraphicsAllocation()->getUnderlyingBufferSize(), ptr, svmData, memoryManager)) {
return true;
}
}
if (InternalMemoryType::hostUnifiedMemory == svmData->memoryType &&
this->usmHostAllocationsCacheEnabled) {
if (this->usmHostAllocationsCache.insert(svmData->size, ptr)) {
if (this->usmHostAllocationsCache.insert(svmData->size, ptr, svmData, memoryManager)) {
return true;
}
}
@ -508,13 +531,13 @@ bool SVMAllocsManager::freeSVMAllocDefer(void *ptr) {
if (svmData) {
if (InternalMemoryType::deviceUnifiedMemory == svmData->memoryType &&
this->usmDeviceAllocationsCacheEnabled) {
if (this->usmDeviceAllocationsCache.insert(svmData->size, ptr)) {
if (this->usmDeviceAllocationsCache.insert(svmData->size, ptr, svmData, memoryManager)) {
return true;
}
}
if (InternalMemoryType::hostUnifiedMemory == svmData->memoryType &&
this->usmHostAllocationsCacheEnabled) {
if (this->usmHostAllocationsCache.insert(svmData->size, ptr)) {
if (this->usmHostAllocationsCache.insert(svmData->size, ptr, svmData, memoryManager)) {
return true;
}
}
@ -585,11 +608,11 @@ void SVMAllocsManager::freeSVMAllocDeferImpl() {
}
void SVMAllocsManager::trimUSMDeviceAllocCache() {
this->usmDeviceAllocationsCache.trim(this);
this->usmDeviceAllocationsCache.trim(this, memoryManager);
}
void SVMAllocsManager::trimUSMHostAllocCache() {
this->usmHostAllocationsCache.trim(this);
this->usmHostAllocationsCache.trim(this, memoryManager);
}
void *SVMAllocsManager::createZeroCopySvmAllocation(size_t size, const SvmAllocationProperties &svmProperties,

View File

@ -165,15 +165,14 @@ class SVMAllocsManager {
static constexpr double minimalAllocUtilization = 0.5;
static bool sizeAllowed(size_t size) { return size <= SvmAllocationCache::maxServicedSize; }
bool insert(size_t size, void *);
bool insert(size_t size, void *ptr, SvmAllocationData *svmData, MemoryManager *memoryManager);
static bool allocUtilizationAllows(size_t requestedSize, size_t reuseCandidateSize);
void *get(size_t size, const UnifiedMemoryProperties &unifiedMemoryProperties, SVMAllocsManager *svmAllocsManager);
void trim(SVMAllocsManager *svmAllocsManager);
void *get(size_t size, const UnifiedMemoryProperties &unifiedMemoryProperties, SVMAllocsManager *svmAllocsManager, MemoryManager *memoryManager);
void trim(SVMAllocsManager *svmAllocsManager, MemoryManager *memoryManager);
std::vector<SvmCacheAllocationInfo> allocations;
std::mutex mtx;
size_t maxSize = 0;
size_t totalSize = 0;
};
enum class FreePolicyType : uint32_t {

View File

@ -252,56 +252,128 @@ TEST_F(SvmDeviceAllocationCacheTest, givenAllocationCacheEnabledWhenFreeingDevic
{
auto allocation = svmManager->createUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
ASSERT_NE(allocation, nullptr);
auto allocation2 = svmManager->createUnifiedMemoryAllocation(1u, unifiedMemoryProperties);
auto allocation2 = svmManager->createUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
ASSERT_NE(allocation2, nullptr);
EXPECT_EQ(0u, svmManager->usmDeviceAllocationsCache.allocations.size());
EXPECT_EQ(0u, svmManager->usmDeviceAllocationsCache.totalSize);
EXPECT_EQ(0u, device->getAllocationsSavedForReuseSize());
svmManager->freeSVMAlloc(allocation);
EXPECT_EQ(1u, svmManager->usmDeviceAllocationsCache.allocations.size());
EXPECT_EQ(allocationSize, svmManager->usmDeviceAllocationsCache.totalSize);
EXPECT_EQ(allocationSize, device->getAllocationsSavedForReuseSize());
svmManager->freeSVMAlloc(allocation2);
EXPECT_EQ(1u, svmManager->usmDeviceAllocationsCache.allocations.size());
EXPECT_EQ(allocationSize, svmManager->usmDeviceAllocationsCache.totalSize);
EXPECT_EQ(allocationSize, device->getAllocationsSavedForReuseSize());
auto recycledAllocation = svmManager->createUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
EXPECT_EQ(recycledAllocation, allocation);
EXPECT_EQ(svmManager->usmDeviceAllocationsCache.allocations.size(), 0u);
EXPECT_EQ(0u, svmManager->usmDeviceAllocationsCache.totalSize);
EXPECT_EQ(0u, device->getAllocationsSavedForReuseSize());
svmManager->freeSVMAlloc(recycledAllocation);
svmManager->trimUSMDeviceAllocCache();
EXPECT_EQ(svmManager->usmDeviceAllocationsCache.allocations.size(), 0u);
EXPECT_EQ(0u, svmManager->usmDeviceAllocationsCache.totalSize);
EXPECT_EQ(0u, device->getAllocationsSavedForReuseSize());
}
{
auto allocation = svmManager->createUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
ASSERT_NE(allocation, nullptr);
auto allocation2 = svmManager->createUnifiedMemoryAllocation(1u, unifiedMemoryProperties);
auto allocation2 = svmManager->createUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
ASSERT_NE(allocation2, nullptr);
EXPECT_EQ(0u, svmManager->usmDeviceAllocationsCache.allocations.size());
EXPECT_EQ(0u, svmManager->usmDeviceAllocationsCache.totalSize);
EXPECT_EQ(0u, device->getAllocationsSavedForReuseSize());
svmManager->freeSVMAllocDefer(allocation);
EXPECT_EQ(1u, svmManager->usmDeviceAllocationsCache.allocations.size());
EXPECT_EQ(allocationSize, svmManager->usmDeviceAllocationsCache.totalSize);
EXPECT_EQ(allocationSize, device->getAllocationsSavedForReuseSize());
svmManager->freeSVMAllocDefer(allocation2);
EXPECT_EQ(1u, svmManager->usmDeviceAllocationsCache.allocations.size());
EXPECT_EQ(allocationSize, svmManager->usmDeviceAllocationsCache.totalSize);
EXPECT_EQ(allocationSize, device->getAllocationsSavedForReuseSize());
auto recycledAllocation = svmManager->createUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
EXPECT_EQ(recycledAllocation, allocation);
EXPECT_EQ(svmManager->usmDeviceAllocationsCache.allocations.size(), 0u);
EXPECT_EQ(0u, svmManager->usmDeviceAllocationsCache.totalSize);
EXPECT_EQ(0u, device->getAllocationsSavedForReuseSize());
svmManager->freeSVMAllocDefer(recycledAllocation);
svmManager->trimUSMDeviceAllocCache();
EXPECT_EQ(svmManager->usmDeviceAllocationsCache.allocations.size(), 0u);
EXPECT_EQ(0u, svmManager->usmDeviceAllocationsCache.totalSize);
EXPECT_EQ(0u, device->getAllocationsSavedForReuseSize());
}
}
TEST_F(SvmDeviceAllocationCacheTest, givenAllocationCacheEnabledAndMultipleSVMManagersWhenFreeingDeviceAllocationThenItIsPutIntoCacheOnlyIfMaxSizeWillNotBeExceeded) {
std::unique_ptr<UltDeviceFactory> deviceFactory(new UltDeviceFactory(1, 1));
RootDeviceIndicesContainer rootDeviceIndices = {mockRootDeviceIndex};
std::map<uint32_t, DeviceBitfield> deviceBitfields{{mockRootDeviceIndex, mockDeviceBitfield}};
DebugManagerStateRestore restore;
debugManager.flags.ExperimentalEnableDeviceAllocationCache.set(1);
auto device = deviceFactory->rootDevices[0];
auto svmManager = std::make_unique<MockSVMAllocsManager>(device->getMemoryManager(), false);
auto secondSvmManager = std::make_unique<MockSVMAllocsManager>(device->getMemoryManager(), false);
svmManager->initUsmAllocationsCaches(*device);
secondSvmManager->initUsmAllocationsCaches(*device);
ASSERT_TRUE(svmManager->usmDeviceAllocationsCacheEnabled);
ASSERT_TRUE(secondSvmManager->usmDeviceAllocationsCacheEnabled);
constexpr auto allocationSize = MemoryConstants::pageSize64k;
svmManager->usmDeviceAllocationsCache.maxSize = allocationSize;
secondSvmManager->usmDeviceAllocationsCache.maxSize = allocationSize;
SVMAllocsManager::UnifiedMemoryProperties unifiedMemoryProperties(InternalMemoryType::deviceUnifiedMemory, 1, rootDeviceIndices, deviceBitfields);
unifiedMemoryProperties.device = device;
{
auto allocation = svmManager->createUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
ASSERT_NE(allocation, nullptr);
auto allocation2 = secondSvmManager->createUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
ASSERT_NE(allocation2, nullptr);
svmManager->freeSVMAlloc(allocation);
EXPECT_EQ(1u, svmManager->usmDeviceAllocationsCache.allocations.size());
EXPECT_EQ(allocationSize, device->getAllocationsSavedForReuseSize());
secondSvmManager->freeSVMAlloc(allocation2);
EXPECT_EQ(0u, secondSvmManager->usmDeviceAllocationsCache.allocations.size());
EXPECT_EQ(allocationSize, device->getAllocationsSavedForReuseSize());
auto recycledAllocation = svmManager->createUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
EXPECT_EQ(recycledAllocation, allocation);
EXPECT_EQ(0u, svmManager->usmDeviceAllocationsCache.allocations.size());
EXPECT_EQ(0u, device->getAllocationsSavedForReuseSize());
svmManager->freeSVMAlloc(recycledAllocation);
svmManager->trimUSMDeviceAllocCache();
EXPECT_EQ(svmManager->usmDeviceAllocationsCache.allocations.size(), 0u);
EXPECT_EQ(0u, device->getAllocationsSavedForReuseSize());
}
{
auto allocation = svmManager->createUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
ASSERT_NE(allocation, nullptr);
auto allocation2 = secondSvmManager->createUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
ASSERT_NE(allocation2, nullptr);
secondSvmManager->freeSVMAlloc(allocation2);
EXPECT_EQ(1u, secondSvmManager->usmDeviceAllocationsCache.allocations.size());
EXPECT_EQ(allocationSize, device->getAllocationsSavedForReuseSize());
svmManager->freeSVMAlloc(allocation);
EXPECT_EQ(0u, svmManager->usmDeviceAllocationsCache.allocations.size());
EXPECT_EQ(allocationSize, device->getAllocationsSavedForReuseSize());
auto recycledAllocation = secondSvmManager->createUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
EXPECT_EQ(recycledAllocation, allocation2);
EXPECT_EQ(0u, secondSvmManager->usmDeviceAllocationsCache.allocations.size());
EXPECT_EQ(0u, device->getAllocationsSavedForReuseSize());
secondSvmManager->freeSVMAlloc(recycledAllocation);
secondSvmManager->trimUSMDeviceAllocCache();
EXPECT_EQ(secondSvmManager->usmDeviceAllocationsCache.allocations.size(), 0u);
EXPECT_EQ(0u, device->getAllocationsSavedForReuseSize());
}
}
@ -699,7 +771,7 @@ struct SvmHostAllocationCacheSimpleTestDataType {
void *allocation;
};
TEST_F(SvmHostAllocationCacheTest, givenAllocationCacheEnabledWhenFreeingDeviceAllocationThenItIsPutIntoCache) {
TEST_F(SvmHostAllocationCacheTest, givenAllocationCacheEnabledWhenFreeingHostAllocationThenItIsPutIntoCache) {
std::unique_ptr<UltDeviceFactory> deviceFactory(new UltDeviceFactory(1, 1));
RootDeviceIndicesContainer rootDeviceIndices = {mockRootDeviceIndex};
std::map<uint32_t, DeviceBitfield> deviceBitfields{{mockRootDeviceIndex, mockDeviceBitfield}};
@ -759,14 +831,15 @@ TEST_F(SvmHostAllocationCacheTest, givenAllocationCacheEnabledWhenInitializedThe
EXPECT_EQ(expectedMaxSize, svmManager->usmHostAllocationsCache.maxSize);
}
TEST_F(SvmHostAllocationCacheTest, givenAllocationCacheEnabledWhenFreeingDeviceAllocationThenItIsPutIntoCacheOnlyIfMaxSizeWillNotBeExceeded) {
TEST_F(SvmHostAllocationCacheTest, givenAllocationCacheEnabledWhenFreeingHostAllocationThenItIsPutIntoCacheOnlyIfMaxSizeWillNotBeExceeded) {
std::unique_ptr<UltDeviceFactory> deviceFactory(new UltDeviceFactory(1, 1));
RootDeviceIndicesContainer rootDeviceIndices = {mockRootDeviceIndex};
std::map<uint32_t, DeviceBitfield> deviceBitfields{{mockRootDeviceIndex, mockDeviceBitfield}};
DebugManagerStateRestore restore;
debugManager.flags.ExperimentalEnableHostAllocationCache.set(1);
auto device = deviceFactory->rootDevices[0];
auto svmManager = std::make_unique<MockSVMAllocsManager>(device->getMemoryManager(), false);
auto memoryManager = device->getMemoryManager();
auto svmManager = std::make_unique<MockSVMAllocsManager>(memoryManager, false);
svmManager->initUsmAllocationsCaches(*device);
ASSERT_TRUE(svmManager->usmHostAllocationsCacheEnabled);
@ -780,26 +853,26 @@ TEST_F(SvmHostAllocationCacheTest, givenAllocationCacheEnabledWhenFreeingDeviceA
auto allocation2 = svmManager->createHostUnifiedMemoryAllocation(1u, unifiedMemoryProperties);
ASSERT_NE(allocation2, nullptr);
EXPECT_EQ(0u, svmManager->usmHostAllocationsCache.allocations.size());
EXPECT_EQ(0u, svmManager->usmHostAllocationsCache.totalSize);
EXPECT_EQ(0u, memoryManager->getHostAllocationsSavedForReuseSize());
svmManager->freeSVMAlloc(allocation);
EXPECT_EQ(1u, svmManager->usmHostAllocationsCache.allocations.size());
EXPECT_EQ(allocationSize, svmManager->usmHostAllocationsCache.totalSize);
EXPECT_EQ(allocationSize, memoryManager->getHostAllocationsSavedForReuseSize());
svmManager->freeSVMAlloc(allocation2);
EXPECT_EQ(1u, svmManager->usmHostAllocationsCache.allocations.size());
EXPECT_EQ(allocationSize, svmManager->usmHostAllocationsCache.totalSize);
EXPECT_EQ(allocationSize, memoryManager->getHostAllocationsSavedForReuseSize());
auto recycledAllocation = svmManager->createHostUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
EXPECT_EQ(recycledAllocation, allocation);
EXPECT_EQ(svmManager->usmHostAllocationsCache.allocations.size(), 0u);
EXPECT_EQ(0u, svmManager->usmHostAllocationsCache.totalSize);
EXPECT_EQ(0u, memoryManager->getHostAllocationsSavedForReuseSize());
svmManager->freeSVMAlloc(recycledAllocation);
svmManager->trimUSMHostAllocCache();
EXPECT_EQ(svmManager->usmHostAllocationsCache.allocations.size(), 0u);
EXPECT_EQ(0u, svmManager->usmHostAllocationsCache.totalSize);
EXPECT_EQ(0u, memoryManager->getHostAllocationsSavedForReuseSize());
}
{
auto allocation = svmManager->createHostUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
@ -807,26 +880,104 @@ TEST_F(SvmHostAllocationCacheTest, givenAllocationCacheEnabledWhenFreeingDeviceA
auto allocation2 = svmManager->createHostUnifiedMemoryAllocation(1u, unifiedMemoryProperties);
ASSERT_NE(allocation2, nullptr);
EXPECT_EQ(0u, svmManager->usmHostAllocationsCache.allocations.size());
EXPECT_EQ(0u, svmManager->usmHostAllocationsCache.totalSize);
EXPECT_EQ(0u, memoryManager->getHostAllocationsSavedForReuseSize());
svmManager->freeSVMAllocDefer(allocation);
EXPECT_EQ(1u, svmManager->usmHostAllocationsCache.allocations.size());
EXPECT_EQ(allocationSize, svmManager->usmHostAllocationsCache.totalSize);
EXPECT_EQ(allocationSize, memoryManager->getHostAllocationsSavedForReuseSize());
svmManager->freeSVMAllocDefer(allocation2);
EXPECT_EQ(1u, svmManager->usmHostAllocationsCache.allocations.size());
EXPECT_EQ(allocationSize, svmManager->usmHostAllocationsCache.totalSize);
EXPECT_EQ(allocationSize, memoryManager->getHostAllocationsSavedForReuseSize());
auto recycledAllocation = svmManager->createHostUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
EXPECT_EQ(recycledAllocation, allocation);
EXPECT_EQ(svmManager->usmHostAllocationsCache.allocations.size(), 0u);
EXPECT_EQ(0u, svmManager->usmHostAllocationsCache.totalSize);
EXPECT_EQ(0u, memoryManager->getHostAllocationsSavedForReuseSize());
svmManager->freeSVMAllocDefer(recycledAllocation);
svmManager->trimUSMHostAllocCache();
EXPECT_EQ(svmManager->usmHostAllocationsCache.allocations.size(), 0u);
EXPECT_EQ(0u, svmManager->usmHostAllocationsCache.totalSize);
EXPECT_EQ(0u, memoryManager->getHostAllocationsSavedForReuseSize());
}
}
TEST_F(SvmHostAllocationCacheTest, givenAllocationCacheEnabledAndMultipleSVMManagersWhenFreeingHostAllocationThenItIsPutIntoCacheOnlyIfMaxSizeWillNotBeExceeded) {
std::unique_ptr<UltDeviceFactory> deviceFactory(new UltDeviceFactory(1, 1));
RootDeviceIndicesContainer rootDeviceIndices = {mockRootDeviceIndex};
std::map<uint32_t, DeviceBitfield> deviceBitfields{{mockRootDeviceIndex, mockDeviceBitfield}};
DebugManagerStateRestore restore;
debugManager.flags.ExperimentalEnableHostAllocationCache.set(1);
auto device = deviceFactory->rootDevices[0];
auto memoryManager = device->getMemoryManager();
auto svmManager = std::make_unique<MockSVMAllocsManager>(memoryManager, false);
auto secondSvmManager = std::make_unique<MockSVMAllocsManager>(memoryManager, false);
svmManager->initUsmAllocationsCaches(*device);
secondSvmManager->initUsmAllocationsCaches(*device);
ASSERT_TRUE(svmManager->usmHostAllocationsCacheEnabled);
ASSERT_TRUE(secondSvmManager->usmHostAllocationsCacheEnabled);
constexpr auto allocationSize = MemoryConstants::pageSize64k;
svmManager->usmHostAllocationsCache.maxSize = allocationSize;
secondSvmManager->usmHostAllocationsCache.maxSize = allocationSize;
SVMAllocsManager::UnifiedMemoryProperties unifiedMemoryProperties(InternalMemoryType::hostUnifiedMemory, 1, rootDeviceIndices, deviceBitfields);
{
auto allocation = svmManager->createHostUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
ASSERT_NE(allocation, nullptr);
auto allocation2 = secondSvmManager->createHostUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
ASSERT_NE(allocation2, nullptr);
EXPECT_EQ(0u, svmManager->usmHostAllocationsCache.allocations.size());
EXPECT_EQ(0u, secondSvmManager->usmHostAllocationsCache.allocations.size());
EXPECT_EQ(0u, memoryManager->getHostAllocationsSavedForReuseSize());
svmManager->freeSVMAlloc(allocation);
EXPECT_EQ(1u, svmManager->usmHostAllocationsCache.allocations.size());
EXPECT_EQ(allocationSize, memoryManager->getHostAllocationsSavedForReuseSize());
secondSvmManager->freeSVMAlloc(allocation2);
EXPECT_EQ(0u, secondSvmManager->usmHostAllocationsCache.allocations.size());
EXPECT_EQ(allocationSize, memoryManager->getHostAllocationsSavedForReuseSize());
auto recycledAllocation = svmManager->createHostUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
EXPECT_EQ(recycledAllocation, allocation);
EXPECT_EQ(svmManager->usmHostAllocationsCache.allocations.size(), 0u);
EXPECT_EQ(0u, memoryManager->getHostAllocationsSavedForReuseSize());
svmManager->freeSVMAlloc(recycledAllocation);
svmManager->trimUSMHostAllocCache();
EXPECT_EQ(svmManager->usmHostAllocationsCache.allocations.size(), 0u);
EXPECT_EQ(0u, memoryManager->getHostAllocationsSavedForReuseSize());
}
{
auto allocation = svmManager->createHostUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
ASSERT_NE(allocation, nullptr);
auto allocation2 = secondSvmManager->createHostUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
ASSERT_NE(allocation2, nullptr);
EXPECT_EQ(0u, svmManager->usmHostAllocationsCache.allocations.size());
EXPECT_EQ(0u, secondSvmManager->usmHostAllocationsCache.allocations.size());
EXPECT_EQ(0u, memoryManager->getHostAllocationsSavedForReuseSize());
secondSvmManager->freeSVMAlloc(allocation2);
EXPECT_EQ(1u, secondSvmManager->usmHostAllocationsCache.allocations.size());
EXPECT_EQ(allocationSize, memoryManager->getHostAllocationsSavedForReuseSize());
svmManager->freeSVMAlloc(allocation);
EXPECT_EQ(0u, svmManager->usmHostAllocationsCache.allocations.size());
EXPECT_EQ(allocationSize, memoryManager->getHostAllocationsSavedForReuseSize());
auto recycledAllocation = secondSvmManager->createHostUnifiedMemoryAllocation(allocationSize, unifiedMemoryProperties);
EXPECT_EQ(recycledAllocation, allocation2);
EXPECT_EQ(secondSvmManager->usmHostAllocationsCache.allocations.size(), 0u);
EXPECT_EQ(0u, memoryManager->getHostAllocationsSavedForReuseSize());
secondSvmManager->freeSVMAlloc(recycledAllocation);
secondSvmManager->trimUSMHostAllocCache();
EXPECT_EQ(secondSvmManager->usmHostAllocationsCache.allocations.size(), 0u);
EXPECT_EQ(0u, memoryManager->getHostAllocationsSavedForReuseSize());
}
}