feature: adapt usm pool manager

Change behavior to continue allocating usm pools as needed.
Intended to replace singular usm pools.

Related-To: NEO-16084

Signed-off-by: Dominik Dabek <dominik.dabek@intel.com>
This commit is contained in:
Dominik Dabek
2025-09-24 09:30:47 +00:00
committed by Compute-Runtime-Automation
parent 841dab8e2b
commit f54e3fda41
14 changed files with 271 additions and 571 deletions

View File

@@ -12,12 +12,10 @@ namespace NEO {
class MockUsmMemAllocPool : public UsmMemAllocPool {
public:
using UsmMemAllocPool::allocations;
using UsmMemAllocPool::maxServicedSize;
using UsmMemAllocPool::minServicedSize;
using UsmMemAllocPool::pool;
using UsmMemAllocPool::poolEnd;
using UsmMemAllocPool::poolInfo;
using UsmMemAllocPool::poolMemoryType;
using UsmMemAllocPool::poolSize;
bool initialize(SVMAllocsManager *svmMemoryManager, const UnifiedMemoryProperties &memoryProperties, size_t poolSize, size_t minServicedSize, size_t maxServicedSize) override {
if (callBaseInitialize) {
@@ -62,13 +60,13 @@ class MockUsmMemAllocPoolsManager : public UsmMemAllocPoolsManager {
using UsmMemAllocPoolsManager::pools;
using UsmMemAllocPoolsManager::totalSize;
using UsmMemAllocPoolsManager::UsmMemAllocPoolsManager;
uint64_t getFreeMemory() override {
if (callBaseGetFreeMemory) {
return UsmMemAllocPoolsManager::getFreeMemory();
bool canAddPool(PoolInfo poolInfo) override {
if (canAddPoolCallBase) {
return UsmMemAllocPoolsManager::canAddPool(poolInfo);
}
return mockFreeMemory;
return canAddPools;
}
uint64_t mockFreeMemory = 0u;
bool callBaseGetFreeMemory = false;
bool canAddPools = true;
bool canAddPoolCallBase = false;
};
} // namespace NEO

View File

@@ -614,7 +614,6 @@ WaitForPagingFenceInController = -1
DirectSubmissionPrintSemaphoreUsage = -1
ForceNonCoherentModeForTimestamps = -1
SetAssumeNotInUse = 1
ExperimentalUSMAllocationReuseVersion = -1
ForceNonWalkerSplitMemoryCopy = -1
FinalizerInputType = unk
FinalizerLibraryName = unk
@@ -670,5 +669,6 @@ Disable2MBSizeAlignment = 0
InOrderCopyMiFlushSync = -1
SplitBcsForCopyOffload = -1
LimitIsaPrefetchSize = -1
EnableUsmAllocationPoolManager = -1
ForceTotalWMTPDataSize = -1
# Please don't edit below this line

View File

@@ -2577,74 +2577,6 @@ TEST_F(DeviceTests, givenDebuggerRequestedByUserWhenDeviceWithSubDevicesCreatedT
EXPECT_NE(nullptr, deviceFactory.rootDevices[0]->getL0Debugger());
}
TEST_F(DeviceTests, givenNewUsmPoolingEnabledWhenDeviceInitializedThenUsmMemAllocPoolsManagerIsCreatedButNotInitialized) {
VariableBackup<bool> backupIsDeviceUsmPoolingEnabledForUlts(&isDeviceUsmPoolingEnabledForUlts);
isDeviceUsmPoolingEnabledForUlts = true;
{
DebugManagerStateRestore restorer;
debugManager.flags.ExperimentalUSMAllocationReuseVersion.set(2);
auto executionEnvironment = MockDevice::prepareExecutionEnvironment(defaultHwInfo.get(), 0u);
auto mockProductHelper = new MockProductHelper;
executionEnvironment->rootDeviceEnvironments[0]->productHelper.reset(mockProductHelper);
mockProductHelper->isDeviceUsmPoolAllocatorSupportedResult = true;
UltDeviceFactory deviceFactory{1, 1, *executionEnvironment};
auto device = deviceFactory.rootDevices[0];
auto usmMemAllocPoolsManager = device->getUsmMemAllocPoolsManager();
ASSERT_NE(nullptr, usmMemAllocPoolsManager);
EXPECT_FALSE(usmMemAllocPoolsManager->isInitialized());
}
{
DebugManagerStateRestore restorer;
debugManager.flags.ExperimentalUSMAllocationReuseVersion.set(-1);
auto executionEnvironment = MockDevice::prepareExecutionEnvironment(defaultHwInfo.get(), 0u);
auto mockProductHelper = new MockProductHelper;
executionEnvironment->rootDeviceEnvironments[0]->productHelper.reset(mockProductHelper);
mockProductHelper->isDeviceUsmPoolAllocatorSupportedResult = true;
UltDeviceFactory deviceFactory{1, 1, *executionEnvironment};
auto device = deviceFactory.rootDevices[0];
auto usmMemAllocPoolsManager = device->getUsmMemAllocPoolsManager();
EXPECT_EQ(nullptr, usmMemAllocPoolsManager);
}
{
DebugManagerStateRestore restorer;
debugManager.flags.ExperimentalUSMAllocationReuseVersion.set(2);
auto executionEnvironment = MockDevice::prepareExecutionEnvironment(defaultHwInfo.get(), 0u);
auto mockProductHelper = new MockProductHelper;
executionEnvironment->rootDeviceEnvironments[0]->productHelper.reset(mockProductHelper);
mockProductHelper->isDeviceUsmPoolAllocatorSupportedResult = false;
UltDeviceFactory deviceFactory{1, 1, *executionEnvironment};
auto device = deviceFactory.rootDevices[0];
auto usmMemAllocPoolsManager = device->getUsmMemAllocPoolsManager();
EXPECT_EQ(nullptr, usmMemAllocPoolsManager);
}
isDeviceUsmPoolingEnabledForUlts = false;
{
DebugManagerStateRestore restorer;
debugManager.flags.ExperimentalUSMAllocationReuseVersion.set(2);
auto executionEnvironment = MockDevice::prepareExecutionEnvironment(defaultHwInfo.get(), 0u);
auto mockProductHelper = new MockProductHelper;
executionEnvironment->rootDeviceEnvironments[0]->productHelper.reset(mockProductHelper);
mockProductHelper->isDeviceUsmPoolAllocatorSupportedResult = true;
UltDeviceFactory deviceFactory{1, 1, *executionEnvironment};
auto device = deviceFactory.rootDevices[0];
auto usmMemAllocPoolsManager = device->getUsmMemAllocPoolsManager();
EXPECT_EQ(nullptr, usmMemAllocPoolsManager);
}
{
DebugManagerStateRestore restorer;
debugManager.flags.ExperimentalUSMAllocationReuseVersion.set(2);
debugManager.flags.EnableDeviceUsmAllocationPool.set(1);
auto executionEnvironment = MockDevice::prepareExecutionEnvironment(defaultHwInfo.get(), 0u);
auto mockProductHelper = new MockProductHelper;
executionEnvironment->rootDeviceEnvironments[0]->productHelper.reset(mockProductHelper);
mockProductHelper->isDeviceUsmPoolAllocatorSupportedResult = true;
UltDeviceFactory deviceFactory{1, 1, *executionEnvironment};
auto device = deviceFactory.rootDevices[0];
auto usmMemAllocPoolsManager = device->getUsmMemAllocPoolsManager();
ASSERT_NE(nullptr, usmMemAllocPoolsManager);
EXPECT_FALSE(usmMemAllocPoolsManager->isInitialized());
}
}
TEST(DeviceWithoutAILTest, givenNoAILWhenCreateDeviceThenDeviceIsCreated) {
DebugManagerStateRestore dbgRestorer;
debugManager.flags.EnableAIL.set(false);
@@ -2697,13 +2629,22 @@ TEST(Device, givenDeviceWhenCallingUsmAllocationPoolMethodsThenCorrectValueRetur
EXPECT_EQ(nullptr, device->getUsmMemAllocPool());
device->cleanupUsmAllocationPool();
MockUsmMemAllocPool *usmAllocPool = new MockUsmMemAllocPool;
auto *usmAllocPool = new MockUsmMemAllocPool;
device->resetUsmAllocationPool(usmAllocPool);
EXPECT_EQ(usmAllocPool, device->getUsmMemAllocPool());
usmAllocPool->callBaseCleanup = false;
EXPECT_EQ(0u, usmAllocPool->cleanupCalled);
device->cleanupUsmAllocationPool();
EXPECT_EQ(1u, usmAllocPool->cleanupCalled);
EXPECT_EQ(nullptr, device->getUsmMemAllocPoolsManager());
RootDeviceIndicesContainer rootDeviceIndices = {device->getRootDeviceIndex()};
std::map<uint32_t, DeviceBitfield> deviceBitfields{{device->getRootDeviceIndex(), device->getDeviceBitfield()}};
MockUsmMemAllocPoolsManager *usmAllocPoolManager = new MockUsmMemAllocPoolsManager(InternalMemoryType::deviceUnifiedMemory, rootDeviceIndices, deviceBitfields, device.get());
device->resetUsmAllocationPoolManager(usmAllocPoolManager);
EXPECT_EQ(usmAllocPoolManager, device->getUsmMemAllocPoolsManager());
usmAllocPoolManager->canAddPoolCallBase = true;
EXPECT_TRUE(usmAllocPoolManager->canAddPool(UsmMemAllocPoolsManager::poolInfos[0]));
}
TEST(GroupDevicesTest, whenMultipleDevicesAreCreatedThenGroupDevicesCreatesVectorPerEachProductFamilySortedOverGpuTypeAndProductFamily) {

View File

@@ -291,37 +291,27 @@ TEST_F(UnifiedMemoryPoolingManagerStaticTest, givenUsmMemAllocPoolsManagerWhenCa
EXPECT_FALSE(MockUsmMemAllocPoolsManager::canBePooled(UsmMemAllocPoolsManager::maxPoolableSize, unifiedMemoryProperties));
}
class UnifiedMemoryPoolingManagerTest : public SVMMemoryAllocatorFixture<true>, public ::testing::TestWithParam<std::tuple<InternalMemoryType, bool>> {
class UnifiedMemoryPoolingManagerTest : public SVMMemoryAllocatorFixture<true>, public ::testing::TestWithParam<std::tuple<InternalMemoryType>> {
public:
void SetUp() override {
REQUIRE_64BIT_OR_SKIP();
SVMMemoryAllocatorFixture::setUp();
poolMemoryType = std::get<0>(GetParam());
failAllocation = std::get<1>(GetParam());
deviceFactory = std::unique_ptr<UltDeviceFactory>(new UltDeviceFactory(1, 1));
device = deviceFactory->rootDevices[0];
RootDeviceIndicesContainer rootDeviceIndicesPool;
rootDeviceIndicesPool.pushUnique(device->getRootDeviceIndex());
std::map<uint32_t, DeviceBitfield> deviceBitfieldsPool;
deviceBitfieldsPool.emplace(device->getRootDeviceIndex(), device->getDeviceBitfield());
usmMemAllocPoolsManager.reset(new MockUsmMemAllocPoolsManager(device->getMemoryManager(),
rootDeviceIndicesPool,
deviceBitfieldsPool,
device,
poolMemoryType));
usmMemAllocPoolsManager.reset(new MockUsmMemAllocPoolsManager(poolMemoryType,
rootDeviceIndices,
deviceBitfields,
poolMemoryType == InternalMemoryType::deviceUnifiedMemory ? device : nullptr));
ASSERT_NE(nullptr, usmMemAllocPoolsManager);
EXPECT_FALSE(usmMemAllocPoolsManager->isInitialized());
poolInfo0To4Kb = usmMemAllocPoolsManager->poolInfos[0];
poolInfo4KbTo64Kb = usmMemAllocPoolsManager->poolInfos[1];
poolInfo64KbTo2Mb = usmMemAllocPoolsManager->poolInfos[2];
poolInfo2MbTo16Mb = usmMemAllocPoolsManager->poolInfos[3];
poolInfo16MbTo64Mb = usmMemAllocPoolsManager->poolInfos[4];
poolInfo64MbTo256Mb = usmMemAllocPoolsManager->poolInfos[5];
svmManager = std::make_unique<MockSVMAllocsManager>(device->getMemoryManager());
mockMemoryManager = static_cast<MockMemoryManager *>(device->getMemoryManager());
mockMemoryManager->failInDevicePoolWithError = failAllocation;
if (InternalMemoryType::deviceUnifiedMemory == poolMemoryType) {
mockMemoryManager->localMemorySupported[mockRootDeviceIndex] = true;
}
@@ -364,65 +354,68 @@ class UnifiedMemoryPoolingManagerTest : public SVMMemoryAllocatorFixture<true>,
std::unique_ptr<SVMAllocsManager::UnifiedMemoryProperties> poolMemoryProperties;
MockMemoryManager *mockMemoryManager;
InternalMemoryType poolMemoryType;
bool failAllocation;
uint64_t nextMockGraphicsAddress = alignUp(std::numeric_limits<uint64_t>::max() - MemoryConstants::teraByte, MemoryConstants::pageSize2M);
UsmMemAllocPoolsManager::PoolInfo poolInfo0To4Kb;
UsmMemAllocPoolsManager::PoolInfo poolInfo4KbTo64Kb;
UsmMemAllocPoolsManager::PoolInfo poolInfo64KbTo2Mb;
UsmMemAllocPoolsManager::PoolInfo poolInfo2MbTo16Mb;
UsmMemAllocPoolsManager::PoolInfo poolInfo16MbTo64Mb;
UsmMemAllocPoolsManager::PoolInfo poolInfo64MbTo256Mb;
};
INSTANTIATE_TEST_SUITE_P(
UnifiedMemoryPoolingManagerTestParameterized,
UnifiedMemoryPoolingManagerTest,
::testing::Combine(
::testing::Values(InternalMemoryType::deviceUnifiedMemory, InternalMemoryType::hostUnifiedMemory),
::testing::Values(false)));
::testing::Values(InternalMemoryType::deviceUnifiedMemory, InternalMemoryType::hostUnifiedMemory)));
TEST_P(UnifiedMemoryPoolingManagerTest, givenNotInitializedPoolsManagerWhenUsingPoolThenMethodsSucceed) {
void *ptr = reinterpret_cast<void *>(0x1u);
const void *constPtr = const_cast<const void *>(ptr);
EXPECT_FALSE(usmMemAllocPoolsManager->freeSVMAlloc(constPtr, true));
EXPECT_EQ(nullptr, usmMemAllocPoolsManager->getPooledAllocationBasePtr(constPtr));
EXPECT_EQ(0u, usmMemAllocPoolsManager->getPooledAllocationSize(constPtr));
EXPECT_FALSE(usmMemAllocPoolsManager->recycleSVMAlloc(ptr, true));
EXPECT_EQ(0u, usmMemAllocPoolsManager->getOffsetInPool(constPtr));
EXPECT_EQ(nullptr, usmMemAllocPoolsManager->getPoolContainingAlloc(constPtr));
usmMemAllocPoolsManager->trim();
TEST_P(UnifiedMemoryPoolingManagerTest, givenInitializationFailsForOneOfTheSmallPoolsWhenInitializingPoolsManagerThenPoolsAreCleanedUp) {
mockMemoryManager->maxSuccessAllocatedGraphicsMemoryIndex = mockMemoryManager->successAllocatedGraphicsMemoryIndex + 2;
EXPECT_FALSE(usmMemAllocPoolsManager->initialize(svmManager.get()));
EXPECT_FALSE(usmMemAllocPoolsManager->isInitialized());
EXPECT_EQ(0u, usmMemAllocPoolsManager->pools[poolInfo0To4Kb].size());
EXPECT_EQ(0u, usmMemAllocPoolsManager->pools[poolInfo4KbTo64Kb].size());
EXPECT_EQ(0u, usmMemAllocPoolsManager->pools[poolInfo64KbTo2Mb].size());
}
auto mockDevice = reinterpret_cast<MockDevice *>(usmMemAllocPoolsManager->device);
usmMemAllocPoolsManager->callBaseGetFreeMemory = true;
mockDevice->deviceInfo.localMemSize = 4 * MemoryConstants::gigaByte;
mockDevice->deviceInfo.globalMemSize = 8 * MemoryConstants::gigaByte;
mockMemoryManager->localMemAllocsSize[mockDevice->getRootDeviceIndex()].store(1 * MemoryConstants::gigaByte);
auto mutableHwInfo = mockDevice->getRootDeviceEnvironment().getMutableHardwareInfo();
EXPECT_EQ(mutableHwInfo, &mockDevice->getHardwareInfo());
mutableHwInfo->capabilityTable.isIntegratedDevice = false;
EXPECT_EQ(3 * MemoryConstants::gigaByte, usmMemAllocPoolsManager->getFreeMemory());
TEST_P(UnifiedMemoryPoolingManagerTest, givenInitializedPoolsManagerWhenAllocatingGreaterThan2MBOrWrongAlignmentOrWrongFlagsThenDoNotPool) {
ASSERT_TRUE(usmMemAllocPoolsManager->initialize(svmManager.get()));
ASSERT_TRUE(usmMemAllocPoolsManager->isInitialized());
auto allocOverLimit = usmMemAllocPoolsManager->createUnifiedMemoryAllocation(2 * MemoryConstants::megaByte + 1u, *poolMemoryProperties.get());
EXPECT_EQ(nullptr, allocOverLimit);
mutableHwInfo->capabilityTable.isIntegratedDevice = true;
EXPECT_EQ(7 * MemoryConstants::gigaByte, usmMemAllocPoolsManager->getFreeMemory());
poolMemoryProperties->allocationFlags.allFlags = 1u;
auto allocWithExtraFlags = usmMemAllocPoolsManager->createUnifiedMemoryAllocation(1u, *poolMemoryProperties.get());
EXPECT_EQ(nullptr, allocWithExtraFlags);
poolMemoryProperties->allocationFlags.allFlags = 0u;
poolMemoryProperties->alignment = 4 * MemoryConstants::megaByte;
auto allocWithWrongAlignment = usmMemAllocPoolsManager->createUnifiedMemoryAllocation(1u, *poolMemoryProperties.get());
EXPECT_EQ(nullptr, allocWithWrongAlignment);
usmMemAllocPoolsManager->cleanup();
}
TEST_P(UnifiedMemoryPoolingManagerTest, givenInitializationFailsForOneOfTheSmallPoolsWhenInitializingPoolsManagerThenPoolsAreCleanedUp) {
mockMemoryManager->maxSuccessAllocatedGraphicsMemoryIndex = mockMemoryManager->successAllocatedGraphicsMemoryIndex + 2;
EXPECT_FALSE(usmMemAllocPoolsManager->ensureInitialized(svmManager.get()));
EXPECT_FALSE(usmMemAllocPoolsManager->isInitialized());
ASSERT_EQ(1u, usmMemAllocPoolsManager->pools[poolInfo0To4Kb].size());
EXPECT_FALSE(usmMemAllocPoolsManager->pools[poolInfo0To4Kb][0]->isInitialized());
ASSERT_EQ(1u, usmMemAllocPoolsManager->pools[poolInfo4KbTo64Kb].size());
EXPECT_FALSE(usmMemAllocPoolsManager->pools[poolInfo4KbTo64Kb][0]->isInitialized());
ASSERT_EQ(1u, usmMemAllocPoolsManager->pools[poolInfo64KbTo2Mb].size());
EXPECT_FALSE(usmMemAllocPoolsManager->pools[poolInfo64KbTo2Mb][0]->isInitialized());
TEST_P(UnifiedMemoryPoolingManagerTest, givenInitializedPoolsManagerWhenCallingMethodsWithNotAllocatedPointersThenReturnCorrectValues) {
ASSERT_TRUE(usmMemAllocPoolsManager->initialize(svmManager.get()));
ASSERT_TRUE(usmMemAllocPoolsManager->isInitialized());
void *ptrOutsidePools = addrToPtr(0x1);
EXPECT_FALSE(usmMemAllocPoolsManager->freeSVMAlloc(ptrOutsidePools, true));
EXPECT_EQ(0u, usmMemAllocPoolsManager->getPooledAllocationSize(ptrOutsidePools));
EXPECT_EQ(0u, usmMemAllocPoolsManager->getPooledAllocationBasePtr(ptrOutsidePools));
EXPECT_EQ(0u, usmMemAllocPoolsManager->getOffsetInPool(ptrOutsidePools));
void *notAllocatedPtrInPoolAddressSpace = addrToPtr(usmMemAllocPoolsManager->pools[poolInfo0To4Kb][0]->getPoolAddress());
EXPECT_FALSE(usmMemAllocPoolsManager->freeSVMAlloc(notAllocatedPtrInPoolAddressSpace, true));
EXPECT_EQ(0u, usmMemAllocPoolsManager->getPooledAllocationSize(notAllocatedPtrInPoolAddressSpace));
EXPECT_EQ(0u, usmMemAllocPoolsManager->getPooledAllocationBasePtr(notAllocatedPtrInPoolAddressSpace));
EXPECT_EQ(0u, usmMemAllocPoolsManager->getOffsetInPool(notAllocatedPtrInPoolAddressSpace));
usmMemAllocPoolsManager->cleanup();
}
TEST_P(UnifiedMemoryPoolingManagerTest, givenInitializedPoolsManagerWhenAllocatingNotGreaterThan2MBThenSmallPoolsAreUsed) {
EXPECT_TRUE(usmMemAllocPoolsManager->ensureInitialized(svmManager.get()));
EXPECT_TRUE(usmMemAllocPoolsManager->isInitialized());
TEST_P(UnifiedMemoryPoolingManagerTest, givenInitializedPoolsManagerWhenAllocatingNotGreaterThan2MBThenPoolsAreUsed) {
ASSERT_TRUE(usmMemAllocPoolsManager->initialize(svmManager.get()));
ASSERT_TRUE(usmMemAllocPoolsManager->isInitialized());
ASSERT_EQ(1u, usmMemAllocPoolsManager->pools[poolInfo0To4Kb].size());
EXPECT_TRUE(usmMemAllocPoolsManager->pools[poolInfo0To4Kb][0]->isInitialized());
ASSERT_EQ(1u, usmMemAllocPoolsManager->pools[poolInfo4KbTo64Kb].size());
@@ -500,116 +493,38 @@ TEST_P(UnifiedMemoryPoolingManagerTest, givenInitializedPoolsManagerWhenAllocati
EXPECT_TRUE(usmMemAllocPoolsManager->pools[poolInfo64KbTo2Mb][0]->isInPool(thirdPoolAlloc2MB));
EXPECT_EQ(20 * MemoryConstants::megaByte, usmMemAllocPoolsManager->totalSize);
for (auto i = 0u; i < 7; ++i) { // use all memory in third pool
usmMemAllocPoolsManager->canAddPools = false;
std::vector<void *> ptrsToFree;
for (auto i = 0u; i < 9; ++i) { // use all memory in third pool
auto ptr = usmMemAllocPoolsManager->createUnifiedMemoryAllocation(2 * MemoryConstants::megaByte, *poolMemoryProperties.get());
if (nullptr == ptr) {
break;
}
const auto address = castToUint64(ptr);
const auto offset = usmMemAllocPoolsManager->getOffsetInPool(ptr);
const auto pool = usmMemAllocPoolsManager->getPoolContainingAlloc(ptr);
const auto poolAddress = pool->getPoolAddress();
EXPECT_EQ(ptrOffset(poolAddress, offset), address);
ptrsToFree.push_back(ptr);
}
EXPECT_EQ(1u, usmMemAllocPoolsManager->pools[poolInfo64KbTo2Mb].size());
usmMemAllocPoolsManager->canAddPools = true;
auto thirdPoolAlloc2MBOverCapacity = usmMemAllocPoolsManager->createUnifiedMemoryAllocation(2 * MemoryConstants::megaByte, *poolMemoryProperties.get());
EXPECT_EQ(nullptr, thirdPoolAlloc2MBOverCapacity);
EXPECT_NE(nullptr, thirdPoolAlloc2MBOverCapacity);
EXPECT_EQ(36 * MemoryConstants::megaByte, usmMemAllocPoolsManager->totalSize);
ASSERT_EQ(2u, usmMemAllocPoolsManager->pools[poolInfo64KbTo2Mb].size());
auto &newPool = usmMemAllocPoolsManager->pools[poolInfo64KbTo2Mb][1];
EXPECT_NE(nullptr, newPool->getPooledAllocationBasePtr(thirdPoolAlloc2MBOverCapacity));
ptrsToFree.push_back(thirdPoolAlloc2MB);
ptrsToFree.push_back(thirdPoolAlloc2MBOverCapacity);
for (auto ptr : ptrsToFree) {
EXPECT_TRUE(usmMemAllocPoolsManager->freeSVMAlloc(ptr, true));
}
EXPECT_EQ(1u, usmMemAllocPoolsManager->pools[poolInfo64KbTo2Mb].size());
usmMemAllocPoolsManager->cleanup();
}
TEST_P(UnifiedMemoryPoolingManagerTest, givenInitializedPoolsManagerWhenAllocatingGreaterThan2MBAndNotGreaterThan256BMThenBigPoolsAreUsed) {
void *ptr = reinterpret_cast<void *>(0x1u);
const void *constPtr = const_cast<const void *>(ptr);
EXPECT_TRUE(usmMemAllocPoolsManager->ensureInitialized(svmManager.get()));
EXPECT_TRUE(usmMemAllocPoolsManager->isInitialized());
EXPECT_TRUE(usmMemAllocPoolsManager->ensureInitialized(svmManager.get()));
EXPECT_EQ(0u, usmMemAllocPoolsManager->pools[poolInfo2MbTo16Mb].size());
EXPECT_EQ(0u, usmMemAllocPoolsManager->pools[poolInfo16MbTo64Mb].size());
EXPECT_EQ(0u, usmMemAllocPoolsManager->pools[poolInfo64MbTo256Mb].size());
poolMemoryProperties->alignment = UsmMemAllocPool::chunkAlignment;
const auto allocSize = 14 * MemoryConstants::megaByte;
auto normalAlloc = createAlloc(allocSize, *poolMemoryProperties.get());
EXPECT_NE(nullptr, normalAlloc);
size_t freeMemoryThreshold = static_cast<size_t>((allocSize + usmMemAllocPoolsManager->totalSize) / UsmMemAllocPool::getPercentOfFreeMemoryForRecycling(poolMemoryType));
const auto toleranceForFloatingPointArithmetic = static_cast<size_t>(1 / UsmMemAllocPool::getPercentOfFreeMemoryForRecycling(poolMemoryType));
usmMemAllocPoolsManager->mockFreeMemory = freeMemoryThreshold - toleranceForFloatingPointArithmetic;
EXPECT_FALSE(usmMemAllocPoolsManager->recycleSVMAlloc(normalAlloc, true));
EXPECT_EQ(0u, usmMemAllocPoolsManager->pools[poolInfo2MbTo16Mb].size());
const auto totalSizeStart = usmMemAllocPoolsManager->totalSize;
usmMemAllocPoolsManager->mockFreeMemory = freeMemoryThreshold + toleranceForFloatingPointArithmetic;
EXPECT_TRUE(usmMemAllocPoolsManager->recycleSVMAlloc(normalAlloc, true));
EXPECT_EQ(1u, usmMemAllocPoolsManager->pools[poolInfo2MbTo16Mb].size());
EXPECT_EQ(totalSizeStart + allocSize, usmMemAllocPoolsManager->totalSize);
auto firstPool = reinterpret_cast<MockUsmMemAllocPool *>(usmMemAllocPoolsManager->pools[poolInfo2MbTo16Mb][0].get());
EXPECT_EQ(2 * MemoryConstants::megaByte + 1, firstPool->minServicedSize);
EXPECT_EQ(allocSize, firstPool->maxServicedSize);
auto poolAlloc8MB = usmMemAllocPoolsManager->createUnifiedMemoryAllocation(8 * MemoryConstants::megaByte, *poolMemoryProperties.get());
EXPECT_NE(nullptr, poolAlloc8MB);
EXPECT_TRUE(firstPool->isInPool(poolAlloc8MB));
EXPECT_EQ(8 * MemoryConstants::megaByte, usmMemAllocPoolsManager->getPooledAllocationSize(poolAlloc8MB));
EXPECT_EQ(poolAlloc8MB, usmMemAllocPoolsManager->getPooledAllocationBasePtr(poolAlloc8MB));
EXPECT_EQ(firstPool->getOffsetInPool(poolAlloc8MB), usmMemAllocPoolsManager->getOffsetInPool(poolAlloc8MB));
auto allocationNotFitInPool = usmMemAllocPoolsManager->createUnifiedMemoryAllocation(8 * MemoryConstants::megaByte, *poolMemoryProperties.get());
EXPECT_EQ(nullptr, allocationNotFitInPool);
auto alloc64MB = createAlloc(64 * MemoryConstants::megaByte, *poolMemoryProperties.get());
freeMemoryThreshold = static_cast<size_t>((64 * MemoryConstants::megaByte + usmMemAllocPoolsManager->totalSize) / UsmMemAllocPool::getPercentOfFreeMemoryForRecycling(poolMemoryType));
usmMemAllocPoolsManager->mockFreeMemory = freeMemoryThreshold + toleranceForFloatingPointArithmetic;
EXPECT_TRUE(usmMemAllocPoolsManager->recycleSVMAlloc(alloc64MB, true));
auto poolAlloc64MB = usmMemAllocPoolsManager->createUnifiedMemoryAllocation(64 * MemoryConstants::megaByte, *poolMemoryProperties.get());
EXPECT_NE(nullptr, poolAlloc64MB);
auto secondPool = reinterpret_cast<MockUsmMemAllocPool *>(usmMemAllocPoolsManager->pools[poolInfo16MbTo64Mb][0].get());
EXPECT_TRUE(secondPool->isInPool(poolAlloc64MB));
EXPECT_EQ(64 * MemoryConstants::megaByte, usmMemAllocPoolsManager->getPooledAllocationSize(poolAlloc64MB));
EXPECT_EQ(poolAlloc64MB, usmMemAllocPoolsManager->getPooledAllocationBasePtr(poolAlloc64MB));
allocationNotFitInPool = usmMemAllocPoolsManager->createUnifiedMemoryAllocation(64 * MemoryConstants::megaByte, *poolMemoryProperties.get());
EXPECT_EQ(nullptr, allocationNotFitInPool);
EXPECT_EQ(nullptr, usmMemAllocPoolsManager->getPoolContainingAlloc(constPtr));
auto alloc256MB = createAlloc(256 * MemoryConstants::megaByte, *poolMemoryProperties.get());
freeMemoryThreshold = static_cast<size_t>((256 * MemoryConstants::megaByte + usmMemAllocPoolsManager->totalSize) / UsmMemAllocPool::getPercentOfFreeMemoryForRecycling(poolMemoryType));
usmMemAllocPoolsManager->mockFreeMemory = freeMemoryThreshold + toleranceForFloatingPointArithmetic;
EXPECT_TRUE(usmMemAllocPoolsManager->recycleSVMAlloc(alloc256MB, true));
auto poolAlloc256MB = usmMemAllocPoolsManager->createUnifiedMemoryAllocation(256 * MemoryConstants::megaByte, *poolMemoryProperties.get());
EXPECT_NE(nullptr, poolAlloc256MB);
auto thirdPool = reinterpret_cast<MockUsmMemAllocPool *>(usmMemAllocPoolsManager->pools[poolInfo64MbTo256Mb][0].get());
EXPECT_TRUE(thirdPool->isInPool(poolAlloc256MB));
EXPECT_EQ(256 * MemoryConstants::megaByte, usmMemAllocPoolsManager->getPooledAllocationSize(poolAlloc256MB));
EXPECT_EQ(poolAlloc256MB, usmMemAllocPoolsManager->getPooledAllocationBasePtr(poolAlloc256MB));
allocationNotFitInPool = usmMemAllocPoolsManager->createUnifiedMemoryAllocation(256 * MemoryConstants::megaByte, *poolMemoryProperties.get());
EXPECT_EQ(nullptr, allocationNotFitInPool);
auto alloc256MBForTrim = createAlloc(256 * MemoryConstants::megaByte, *poolMemoryProperties.get());
freeMemoryThreshold = static_cast<size_t>((256 * MemoryConstants::megaByte + usmMemAllocPoolsManager->totalSize) / UsmMemAllocPool::getPercentOfFreeMemoryForRecycling(poolMemoryType));
usmMemAllocPoolsManager->mockFreeMemory = freeMemoryThreshold + toleranceForFloatingPointArithmetic;
EXPECT_TRUE(usmMemAllocPoolsManager->recycleSVMAlloc(alloc256MBForTrim, true));
EXPECT_EQ(1u, usmMemAllocPoolsManager->pools[poolInfo2MbTo16Mb].size());
EXPECT_EQ(1u, usmMemAllocPoolsManager->pools[poolInfo16MbTo64Mb].size());
EXPECT_EQ(2u, usmMemAllocPoolsManager->pools[poolInfo64MbTo256Mb].size());
usmMemAllocPoolsManager->trim();
EXPECT_EQ(1u, usmMemAllocPoolsManager->pools[poolInfo2MbTo16Mb].size());
EXPECT_EQ(1u, usmMemAllocPoolsManager->pools[poolInfo16MbTo64Mb].size());
EXPECT_EQ(1u, usmMemAllocPoolsManager->pools[poolInfo64MbTo256Mb].size());
auto smallAlloc = createAlloc(2 * MemoryConstants::megaByte - 1, *poolMemoryProperties.get());
EXPECT_NE(nullptr, smallAlloc);
freeMemoryThreshold = static_cast<size_t>((2 * MemoryConstants::megaByte + usmMemAllocPoolsManager->totalSize) / UsmMemAllocPool::getPercentOfFreeMemoryForRecycling(poolMemoryType));
usmMemAllocPoolsManager->mockFreeMemory = freeMemoryThreshold + toleranceForFloatingPointArithmetic;
EXPECT_FALSE(usmMemAllocPoolsManager->recycleSVMAlloc(smallAlloc, true));
auto bigAlloc = createAlloc(256 * MemoryConstants::megaByte + 1, *poolMemoryProperties.get());
EXPECT_NE(nullptr, bigAlloc);
freeMemoryThreshold = static_cast<size_t>((256 * MemoryConstants::megaByte + 1 + usmMemAllocPoolsManager->totalSize) / UsmMemAllocPool::getPercentOfFreeMemoryForRecycling(poolMemoryType));
usmMemAllocPoolsManager->mockFreeMemory = freeMemoryThreshold + toleranceForFloatingPointArithmetic;
EXPECT_FALSE(usmMemAllocPoolsManager->recycleSVMAlloc(bigAlloc, true));
svmManager->freeSVMAlloc(smallAlloc);
svmManager->freeSVMAlloc(bigAlloc);
auto allocationOverMaxSize = usmMemAllocPoolsManager->createUnifiedMemoryAllocation(256 * MemoryConstants::megaByte + 1, *poolMemoryProperties.get());
EXPECT_EQ(nullptr, allocationOverMaxSize);
EXPECT_EQ(nullptr, usmMemAllocPoolsManager->getPoolContainingAlloc(constPtr));
usmMemAllocPoolsManager->cleanup();
}