diff --git a/opencl/test/unit_test/test_files/igdrcl.config b/opencl/test/unit_test/test_files/igdrcl.config index 32d952526e..b673f79712 100644 --- a/opencl/test/unit_test/test_files/igdrcl.config +++ b/opencl/test/unit_test/test_files/igdrcl.config @@ -401,4 +401,5 @@ UseTileMemoryBankInVirtualMemoryCreation = -1 DisableScratchPages = 0 ForceAllResourcesUncached = 0 ForcePreParserEnabledForMiArbCheck = -1 -BatchBufferStartPrepatchingWaEnabled = -1 \ No newline at end of file +BatchBufferStartPrepatchingWaEnabled = -1 +DirectSubmissionForceLocalMemoryStorageMode = -1 diff --git a/shared/source/debug_settings/debug_variables_base.inl b/shared/source/debug_settings/debug_variables_base.inl index 70afc464ee..b1bda921aa 100644 --- a/shared/source/debug_settings/debug_variables_base.inl +++ b/shared/source/debug_settings/debug_variables_base.inl @@ -282,6 +282,7 @@ DECLARE_DEBUG_VARIABLE(int32_t, DirectSubmissionNewResourceTlbFlush, -1, "-1: dr DECLARE_DEBUG_VARIABLE(int32_t, DirectSubmissionDisableMonitorFence, -1, "Disable dispatching monitor fence commands") DECLARE_DEBUG_VARIABLE(int32_t, EnableDirectSubmissionController, -1, "Enable direct submission terminating after given timeout, -1: default, 0: disabled, 1: enabled") DECLARE_DEBUG_VARIABLE(int32_t, DirectSubmissionControllerTimeout, -1, "Set direct submission controller timeout, -1: default 5 ms, >=0: timeout in ms") +DECLARE_DEBUG_VARIABLE(int32_t, DirectSubmissionForceLocalMemoryStorageMode, -1, "Force first memory bank storage for command/ring/semaphore buffer, -1: default - for multiOsContextCapable engine, 0: disabled, 1: for multiOsContextCapable engine, 2: for all engines") /* IMPLICIT SCALING */ DECLARE_DEBUG_VARIABLE(int32_t, EnableWalkerPartition, -1, "-1: default, 0: disable, 1: enable, Enables Walker Partitioning via WPARID.") diff --git a/shared/source/direct_submission/direct_submission_hw.inl b/shared/source/direct_submission/direct_submission_hw.inl index e69db14440..820a6bc121 100644 --- a/shared/source/direct_submission/direct_submission_hw.inl +++ b/shared/source/direct_submission/direct_submission_hw.inl @@ -66,7 +66,7 @@ bool DirectSubmissionHw::allocateResources() { const AllocationProperties commandStreamAllocationProperties{device.getRootDeviceIndex(), true, allocationSize, AllocationType::RING_BUFFER, - isMultiOsContextCapable, osContext.getDeviceBitfield()}; + isMultiOsContextCapable, false, osContext.getDeviceBitfield()}; ringBuffer = memoryManager->allocateGraphicsMemoryWithProperties(commandStreamAllocationProperties); UNRECOVERABLE_IF(ringBuffer == nullptr); allocations.push_back(ringBuffer); @@ -78,7 +78,7 @@ bool DirectSubmissionHw::allocateResources() { const AllocationProperties semaphoreAllocationProperties{device.getRootDeviceIndex(), true, MemoryConstants::pageSize, AllocationType::SEMAPHORE_BUFFER, - isMultiOsContextCapable, osContext.getDeviceBitfield()}; + isMultiOsContextCapable, false, osContext.getDeviceBitfield()}; semaphores = memoryManager->allocateGraphicsMemoryWithProperties(semaphoreAllocationProperties); UNRECOVERABLE_IF(semaphores == nullptr); allocations.push_back(semaphores); diff --git a/shared/source/memory_manager/definitions/storage_info.cpp b/shared/source/memory_manager/definitions/storage_info.cpp index ba5642ae41..032a2bfb72 100644 --- a/shared/source/memory_manager/definitions/storage_info.cpp +++ b/shared/source/memory_manager/definitions/storage_info.cpp @@ -153,6 +153,34 @@ StorageInfo MemoryManager::createStorageInfoFromProperties(const AllocationPrope default: break; } + + bool forceLocalMemoryForDirectSubmission = properties.flags.multiOsContextCapable; + switch (DebugManager.flags.DirectSubmissionForceLocalMemoryStorageMode.get()) { + case 0: + forceLocalMemoryForDirectSubmission = false; + break; + case 2: + forceLocalMemoryForDirectSubmission = true; + break; + default: + break; + } + + if (forceLocalMemoryForDirectSubmission) { + if (properties.allocationType == AllocationType::COMMAND_BUFFER || + properties.allocationType == AllocationType::RING_BUFFER || + properties.allocationType == AllocationType::SEMAPHORE_BUFFER) { + storageInfo.memoryBanks = {}; + for (auto bank = 0u; bank < deviceCount; bank++) { + if (allTilesValue.test(bank)) { + storageInfo.memoryBanks.set(bank); + break; + } + } + UNRECOVERABLE_IF(storageInfo.memoryBanks.none()); + } + } + return storageInfo; } uint32_t StorageInfo::getNumBanks() const { diff --git a/shared/source/xe_hpc_core/hw_helper_xe_hpc_core.cpp b/shared/source/xe_hpc_core/hw_helper_xe_hpc_core.cpp index 72cf4e250e..45ecee2394 100644 --- a/shared/source/xe_hpc_core/hw_helper_xe_hpc_core.cpp +++ b/shared/source/xe_hpc_core/hw_helper_xe_hpc_core.cpp @@ -239,6 +239,28 @@ void HwHelperHw::setExtraAllocationData(AllocationData &allocationData, allocationData.flags.useSystemMemory = false; } + bool forceLocalMemoryForDirectSubmission = properties.flags.multiOsContextCapable; + switch (DebugManager.flags.DirectSubmissionForceLocalMemoryStorageMode.get()) { + case 0: + forceLocalMemoryForDirectSubmission = false; + break; + case 2: + forceLocalMemoryForDirectSubmission = true; + break; + default: + break; + } + + if (forceLocalMemoryForDirectSubmission) { + if (properties.allocationType == AllocationType::COMMAND_BUFFER || + properties.allocationType == AllocationType::RING_BUFFER || + properties.allocationType == AllocationType::SEMAPHORE_BUFFER) { + allocationData.flags.useSystemMemory = false; + allocationData.flags.requiresCpuAccess = true; + allocationData.flags.resource48Bit = true; + } + } + allocationData.cacheRegion = properties.cacheRegion; if (allocationData.flags.requiresCpuAccess && !allocationData.flags.useSystemMemory && diff --git a/shared/test/unit_test/memory_manager/memory_manager_allocate_in_device_pool_tests.cpp b/shared/test/unit_test/memory_manager/memory_manager_allocate_in_device_pool_tests.cpp index cc1c3279a1..1d26ffc433 100644 --- a/shared/test/unit_test/memory_manager/memory_manager_allocate_in_device_pool_tests.cpp +++ b/shared/test/unit_test/memory_manager/memory_manager_allocate_in_device_pool_tests.cpp @@ -628,3 +628,125 @@ TEST(MemoryManagerTest, givenExternalAllocationTypeWhenIsAllocatedInDevicePoolTh EXPECT_EQ(0u, memoryManager.externalLocalMemoryUsageBankSelector[mockRootDeviceIndex]->getOccupiedMemorySizeForBank(0)); EXPECT_EQ(0u, memoryManager.internalLocalMemoryUsageBankSelector[mockRootDeviceIndex]->getOccupiedMemorySizeForBank(0)); } + +struct MemoryManagerDirectSubmissionImplicitScalingTest : public ::testing::Test { + + void SetUp() override { + DebugManager.flags.CreateMultipleSubDevices.set(numSubDevices); + executionEnvironment = std::make_unique(defaultHwInfo.get()); + auto allTilesMask = executionEnvironment->rootDeviceEnvironments[mockRootDeviceIndex]->deviceAffinityMask.getGenericSubDevicesMask(); + + allocationProperties = std::make_unique(mockRootDeviceIndex, MemoryConstants::pageSize, AllocationType::UNKNOWN, allTilesMask); + allocationProperties->flags.multiOsContextCapable = true; + + constexpr auto enableLocalMemory = true; + memoryManager = std::make_unique(false, enableLocalMemory, *executionEnvironment); + + memoryManager->internalLocalMemoryUsageBankSelector[mockRootDeviceIndex]->reserveOnBanks(1u, MemoryConstants::pageSize2Mb); + EXPECT_NE(0u, memoryManager->internalLocalMemoryUsageBankSelector[mockRootDeviceIndex]->getLeastOccupiedBank(allTilesMask)); + } + + DebugManagerStateRestore restorer{}; + + constexpr static DeviceBitfield firstTileMask{1u}; + constexpr static auto numSubDevices = 2u; + std::unique_ptr executionEnvironment{}; + std::unique_ptr allocationProperties{}; + std::unique_ptr memoryManager{}; +}; + +HWTEST2_F(MemoryManagerDirectSubmissionImplicitScalingTest, givenCommandBufferTypeWhenIsAllocatedForMultiOsContextThenMemoryIsPlacedOnFirstAvailableMemoryBankInLocalMemory, IsXeHpcCore) { + + allocationProperties->allocationType = AllocationType::COMMAND_BUFFER; + auto allocation = memoryManager->allocateGraphicsMemoryInPreferredPool(*allocationProperties, nullptr); + + EXPECT_NE(nullptr, allocation); + + EXPECT_EQ(MemoryPool::LocalMemory, allocation->getMemoryPool()); + EXPECT_EQ(firstTileMask, allocation->storageInfo.getMemoryBanks()); + memoryManager->freeGraphicsMemory(allocation); +} + +HWTEST2_F(MemoryManagerDirectSubmissionImplicitScalingTest, givenRingBufferTypeWhenIsAllocatedForMultiOsContextThenMemoryIsPlacedOnFirstAvailableMemoryBankInLocalMemory, IsXeHpcCore) { + + allocationProperties->allocationType = AllocationType::RING_BUFFER; + auto allocation = memoryManager->allocateGraphicsMemoryInPreferredPool(*allocationProperties, nullptr); + + EXPECT_NE(nullptr, allocation); + + EXPECT_EQ(MemoryPool::LocalMemory, allocation->getMemoryPool()); + EXPECT_EQ(firstTileMask, allocation->storageInfo.getMemoryBanks()); + memoryManager->freeGraphicsMemory(allocation); +} + +HWTEST2_F(MemoryManagerDirectSubmissionImplicitScalingTest, givenSemaphoreBufferTypeWhenIsAllocatedForMultiOsContextThenMemoryIsPlacedOnFirstAvailableMemoryBankInLocalMemory, IsXeHpcCore) { + + allocationProperties->allocationType = AllocationType::SEMAPHORE_BUFFER; + auto allocation = memoryManager->allocateGraphicsMemoryInPreferredPool(*allocationProperties, nullptr); + + EXPECT_NE(nullptr, allocation); + + EXPECT_EQ(MemoryPool::LocalMemory, allocation->getMemoryPool()); + EXPECT_EQ(firstTileMask, allocation->storageInfo.getMemoryBanks()); + memoryManager->freeGraphicsMemory(allocation); +} + +HWTEST2_F(MemoryManagerDirectSubmissionImplicitScalingTest, givenDirectSubmissionForceLocalMemoryStorageDisabledWhenAllocatingMemoryForRingOrSemaphoreBufferThenAllocateInSystemMemory, IsXeHpcCore) { + DebugManager.flags.DirectSubmissionForceLocalMemoryStorageMode.set(0); + for (auto &multiTile : ::testing::Bool()) { + for (auto &allocationType : {AllocationType::RING_BUFFER, AllocationType::SEMAPHORE_BUFFER}) { + allocationProperties->allocationType = allocationType; + allocationProperties->flags.multiOsContextCapable = multiTile; + auto allocation = memoryManager->allocateGraphicsMemoryInPreferredPool(*allocationProperties, nullptr); + + EXPECT_NE(nullptr, allocation); + + EXPECT_NE(MemoryPool::LocalMemory, allocation->getMemoryPool()); + EXPECT_NE(firstTileMask, allocation->storageInfo.getMemoryBanks()); + + memoryManager->freeGraphicsMemory(allocation); + } + } +} + +HWTEST2_F(MemoryManagerDirectSubmissionImplicitScalingTest, givenDirectSubmissionForceLocalMemoryStorageEnabledForMultiTileEsWhenAllocatingMemoryForCommandOrRingOrSemaphoreBufferThenFirstBankIsSelectedOnlyForMultiTileEngines, IsXeHpcCore) { + DebugManager.flags.DirectSubmissionForceLocalMemoryStorageMode.set(1); + for (auto &multiTile : ::testing::Bool()) { + for (auto &allocationType : {AllocationType::COMMAND_BUFFER, AllocationType::RING_BUFFER, AllocationType::SEMAPHORE_BUFFER}) { + allocationProperties->allocationType = allocationType; + allocationProperties->flags.multiOsContextCapable = multiTile; + auto allocation = memoryManager->allocateGraphicsMemoryInPreferredPool(*allocationProperties, nullptr); + + EXPECT_NE(nullptr, allocation); + + if (multiTile) { + EXPECT_EQ(MemoryPool::LocalMemory, allocation->getMemoryPool()); + EXPECT_EQ(firstTileMask, allocation->storageInfo.getMemoryBanks()); + } else { + if (allocationType != AllocationType::COMMAND_BUFFER) { + EXPECT_NE(firstTileMask, allocation->storageInfo.getMemoryBanks()); + EXPECT_NE(firstTileMask, allocation->storageInfo.getMemoryBanks()); + } + } + memoryManager->freeGraphicsMemory(allocation); + } + } +} + +HWTEST2_F(MemoryManagerDirectSubmissionImplicitScalingTest, givenDirectSubmissionForceLocalMemoryStorageEnabledForAllEnginesWhenAllocatingMemoryForCommandOrRingOrSemaphoreBufferThenFirstBankIsSelected, IsXeHpcCore) { + DebugManager.flags.DirectSubmissionForceLocalMemoryStorageMode.set(2); + for (auto &multiTile : ::testing::Bool()) { + for (auto &allocationType : {AllocationType::COMMAND_BUFFER, AllocationType::RING_BUFFER, AllocationType::SEMAPHORE_BUFFER}) { + allocationProperties->allocationType = allocationType; + allocationProperties->flags.multiOsContextCapable = multiTile; + auto allocation = memoryManager->allocateGraphicsMemoryInPreferredPool(*allocationProperties, nullptr); + + EXPECT_NE(nullptr, allocation); + + EXPECT_EQ(MemoryPool::LocalMemory, allocation->getMemoryPool()); + EXPECT_EQ(firstTileMask, allocation->storageInfo.getMemoryBanks()); + + memoryManager->freeGraphicsMemory(allocation); + } + } +} \ No newline at end of file diff --git a/shared/test/unit_test/memory_manager/storage_info_tests.cpp b/shared/test/unit_test/memory_manager/storage_info_tests.cpp index 7b99945dfb..203def3cf1 100644 --- a/shared/test/unit_test/memory_manager/storage_info_tests.cpp +++ b/shared/test/unit_test/memory_manager/storage_info_tests.cpp @@ -160,11 +160,12 @@ TEST_F(MultiDeviceStorageInfoTest, givenSingleTileCsrWhenCreatingStorageInfoForL EXPECT_FALSE(storageInfo.tileInstanced); } -TEST_F(MultiDeviceStorageInfoTest, givenMultiTileCsrWhenCreatingStorageInfoForCommandBufferThenSingleMemoryBankIsOnAndPageTableClonningIsRequired) { +TEST_F(MultiDeviceStorageInfoTest, givenMultiTileCsrWhenCreatingStorageInfoForCommandBufferThenFirstAvailableMemoryBankIsOnAndPageTableClonningIsRequired) { + const DeviceBitfield firstTileMask{static_cast(1u)}; AllocationProperties properties{mockRootDeviceIndex, false, 0u, AllocationType::COMMAND_BUFFER, true, false, singleTileMask}; auto storageInfo = memoryManager->createStorageInfoFromProperties(properties); EXPECT_TRUE(storageInfo.cloningOfPageTables); - EXPECT_EQ(singleTileMask, storageInfo.memoryBanks); + EXPECT_EQ(firstTileMask, storageInfo.memoryBanks); EXPECT_EQ(allTilesMask, storageInfo.pageTablesVisibility); } @@ -462,3 +463,160 @@ TEST_F(MultiDeviceStorageInfoTest, EXPECT_FALSE(storageInfo.tileInstanced); EXPECT_EQ(allTilesMask, storageInfo.pageTablesVisibility); } + +TEST_F(MultiDeviceStorageInfoTest, givenSingleTileWhenCreatingStorageInfoForSemaphoreBufferThenProvidedMemoryBankIsSelected) { + AllocationProperties properties{mockRootDeviceIndex, false, numDevices * MemoryConstants::pageSize64k, AllocationType::SEMAPHORE_BUFFER, false, singleTileMask}; + properties.flags.multiOsContextCapable = false; + auto storageInfo = memoryManager->createStorageInfoFromProperties(properties); + EXPECT_EQ(singleTileMask, storageInfo.memoryBanks); +} + +TEST_F(MultiDeviceStorageInfoTest, givenSingleTileWhenCreatingStorageInfoForCommandBufferThenProvidedMemoryBankIsSelected) { + AllocationProperties properties{mockRootDeviceIndex, false, numDevices * MemoryConstants::pageSize64k, AllocationType::COMMAND_BUFFER, false, singleTileMask}; + properties.flags.multiOsContextCapable = false; + auto storageInfo = memoryManager->createStorageInfoFromProperties(properties); + EXPECT_EQ(singleTileMask, storageInfo.memoryBanks); +} + +TEST_F(MultiDeviceStorageInfoTest, givenSingleTileWhenCreatingStorageInfoForRingBufferThenProvidedMemoryBankIsSelected) { + AllocationProperties properties{mockRootDeviceIndex, false, numDevices * MemoryConstants::pageSize64k, AllocationType::RING_BUFFER, false, singleTileMask}; + properties.flags.multiOsContextCapable = false; + auto storageInfo = memoryManager->createStorageInfoFromProperties(properties); + EXPECT_EQ(singleTileMask, storageInfo.memoryBanks); +} + +TEST_F(MultiDeviceStorageInfoTest, givenMultiTileWhenCreatingStorageInfoForSemaphoreBufferThenFirstBankIsSelectedEvenIfOtherTileIsLessOccupied) { + constexpr uint32_t firstAvailableTileMask = 2u; + + memoryManager->internalLocalMemoryUsageBankSelector[mockRootDeviceIndex]->reserveOnBanks(firstAvailableTileMask, MemoryConstants::pageSize2Mb); + EXPECT_NE(1u, memoryManager->internalLocalMemoryUsageBankSelector[mockRootDeviceIndex]->getLeastOccupiedBank(allTilesMask)); + + AffinityMaskHelper affinityMaskHelper{false}; + affinityMaskHelper.enableGenericSubDevice(1); + affinityMaskHelper.enableGenericSubDevice(2); + affinityMaskHelper.enableGenericSubDevice(3); + + memoryManager->peekExecutionEnvironment().rootDeviceEnvironments[mockRootDeviceIndex]->deviceAffinityMask = affinityMaskHelper; + + AllocationProperties properties{mockRootDeviceIndex, false, numDevices * MemoryConstants::pageSize64k, AllocationType::SEMAPHORE_BUFFER, false, affinityMaskHelper.getGenericSubDevicesMask()}; + properties.flags.multiOsContextCapable = true; + auto storageInfo = memoryManager->createStorageInfoFromProperties(properties); + EXPECT_EQ(DeviceBitfield{firstAvailableTileMask}, storageInfo.memoryBanks); +} + +TEST_F(MultiDeviceStorageInfoTest, givenMultiTileWhenCreatingStorageInfoForCommandBufferThenFirstBankIsSelectedEvenIfOtherTileIsLessOccupied) { + constexpr uint32_t firstAvailableTileMask = 2u; + + memoryManager->internalLocalMemoryUsageBankSelector[mockRootDeviceIndex]->reserveOnBanks(firstAvailableTileMask, MemoryConstants::pageSize2Mb); + EXPECT_NE(1u, memoryManager->internalLocalMemoryUsageBankSelector[mockRootDeviceIndex]->getLeastOccupiedBank(allTilesMask)); + + AffinityMaskHelper affinityMaskHelper{false}; + affinityMaskHelper.enableGenericSubDevice(1); + affinityMaskHelper.enableGenericSubDevice(2); + affinityMaskHelper.enableGenericSubDevice(3); + + memoryManager->peekExecutionEnvironment().rootDeviceEnvironments[mockRootDeviceIndex]->deviceAffinityMask = affinityMaskHelper; + + AllocationProperties properties{mockRootDeviceIndex, false, numDevices * MemoryConstants::pageSize64k, AllocationType::COMMAND_BUFFER, false, affinityMaskHelper.getGenericSubDevicesMask()}; + properties.flags.multiOsContextCapable = true; + auto storageInfo = memoryManager->createStorageInfoFromProperties(properties); + EXPECT_EQ(DeviceBitfield{firstAvailableTileMask}, storageInfo.memoryBanks); +} + +TEST_F(MultiDeviceStorageInfoTest, givenMultiTileWhenCreatingStorageInfoForRingBufferThenFirstBankIsSelectedEvenIfOtherTileIsLessOccupied) { + constexpr uint32_t firstAvailableTileMask = 2u; + + memoryManager->internalLocalMemoryUsageBankSelector[mockRootDeviceIndex]->reserveOnBanks(firstAvailableTileMask, MemoryConstants::pageSize2Mb); + EXPECT_NE(1u, memoryManager->internalLocalMemoryUsageBankSelector[mockRootDeviceIndex]->getLeastOccupiedBank(allTilesMask)); + + AffinityMaskHelper affinityMaskHelper{false}; + affinityMaskHelper.enableGenericSubDevice(1); + affinityMaskHelper.enableGenericSubDevice(2); + affinityMaskHelper.enableGenericSubDevice(3); + + memoryManager->peekExecutionEnvironment().rootDeviceEnvironments[mockRootDeviceIndex]->deviceAffinityMask = affinityMaskHelper; + + AllocationProperties properties{mockRootDeviceIndex, false, numDevices * MemoryConstants::pageSize64k, AllocationType::RING_BUFFER, false, affinityMaskHelper.getGenericSubDevicesMask()}; + properties.flags.multiOsContextCapable = true; + auto storageInfo = memoryManager->createStorageInfoFromProperties(properties); + EXPECT_EQ(DeviceBitfield{firstAvailableTileMask}, storageInfo.memoryBanks); +} + +TEST_F(MultiDeviceStorageInfoTest, givenDirectSubmissionForceLocalMemoryStorageDisabledWhenCreatingStorageInfoForCommandRingOrSemaphoreBufferThenPreferredBankIsSelected) { + DebugManagerStateRestore restorer; + + DebugManager.flags.DirectSubmissionForceLocalMemoryStorageMode.set(0); + constexpr uint32_t firstAvailableTileMask = 2u; + + memoryManager->internalLocalMemoryUsageBankSelector[mockRootDeviceIndex]->reserveOnBanks(firstAvailableTileMask, MemoryConstants::pageSize2Mb); + EXPECT_NE(1u, memoryManager->internalLocalMemoryUsageBankSelector[mockRootDeviceIndex]->getLeastOccupiedBank(allTilesMask)); + + AffinityMaskHelper affinityMaskHelper{false}; + affinityMaskHelper.enableGenericSubDevice(1); + affinityMaskHelper.enableGenericSubDevice(2); + affinityMaskHelper.enableGenericSubDevice(3); + memoryManager->peekExecutionEnvironment().rootDeviceEnvironments[mockRootDeviceIndex]->deviceAffinityMask = affinityMaskHelper; + + for (auto &multiTile : ::testing::Bool()) { + for (auto &allocationType : {AllocationType::COMMAND_BUFFER, AllocationType::RING_BUFFER, AllocationType::SEMAPHORE_BUFFER}) { + AllocationProperties properties{mockRootDeviceIndex, false, numDevices * MemoryConstants::pageSize64k, allocationType, false, affinityMaskHelper.getGenericSubDevicesMask()}; + properties.flags.multiOsContextCapable = multiTile; + auto storageInfo = memoryManager->createStorageInfoFromProperties(properties); + EXPECT_NE(DeviceBitfield{firstAvailableTileMask}, storageInfo.memoryBanks); + } + } +} + +TEST_F(MultiDeviceStorageInfoTest, givenDirectSubmissionForceLocalMemoryStorageEnabledForMultiTileEnginesWhenCreatingStorageInfoForCommandRingOrSemaphoreBufferThenFirstBankIsSelectedOnlyForMultiTileEngines) { + DebugManagerStateRestore restorer; + + DebugManager.flags.DirectSubmissionForceLocalMemoryStorageMode.set(1); + constexpr uint32_t firstAvailableTileMask = 2u; + + memoryManager->internalLocalMemoryUsageBankSelector[mockRootDeviceIndex]->reserveOnBanks(firstAvailableTileMask, MemoryConstants::pageSize2Mb); + EXPECT_NE(1u, memoryManager->internalLocalMemoryUsageBankSelector[mockRootDeviceIndex]->getLeastOccupiedBank(allTilesMask)); + + AffinityMaskHelper affinityMaskHelper{false}; + affinityMaskHelper.enableGenericSubDevice(1); + affinityMaskHelper.enableGenericSubDevice(2); + affinityMaskHelper.enableGenericSubDevice(3); + memoryManager->peekExecutionEnvironment().rootDeviceEnvironments[mockRootDeviceIndex]->deviceAffinityMask = affinityMaskHelper; + + for (auto &multiTile : ::testing::Bool()) { + for (auto &allocationType : {AllocationType::COMMAND_BUFFER, AllocationType::RING_BUFFER, AllocationType::SEMAPHORE_BUFFER}) { + AllocationProperties properties{mockRootDeviceIndex, false, numDevices * MemoryConstants::pageSize64k, allocationType, false, affinityMaskHelper.getGenericSubDevicesMask()}; + properties.flags.multiOsContextCapable = multiTile; + auto storageInfo = memoryManager->createStorageInfoFromProperties(properties); + if (multiTile) { + EXPECT_EQ(DeviceBitfield{firstAvailableTileMask}, storageInfo.memoryBanks); + } else { + EXPECT_NE(DeviceBitfield{firstAvailableTileMask}, storageInfo.memoryBanks); + } + } + } +} + +TEST_F(MultiDeviceStorageInfoTest, givenDirectSubmissionForceLocalMemoryStorageEnabledForAllEnginesWhenCreatingStorageInfoForCommandRingOrSemaphoreBufferThenFirstBankIsSelected) { + DebugManagerStateRestore restorer; + + DebugManager.flags.DirectSubmissionForceLocalMemoryStorageMode.set(2); + constexpr uint32_t firstAvailableTileMask = 2u; + + memoryManager->internalLocalMemoryUsageBankSelector[mockRootDeviceIndex]->reserveOnBanks(firstAvailableTileMask, MemoryConstants::pageSize2Mb); + EXPECT_NE(1u, memoryManager->internalLocalMemoryUsageBankSelector[mockRootDeviceIndex]->getLeastOccupiedBank(allTilesMask)); + + AffinityMaskHelper affinityMaskHelper{false}; + affinityMaskHelper.enableGenericSubDevice(1); + affinityMaskHelper.enableGenericSubDevice(2); + affinityMaskHelper.enableGenericSubDevice(3); + memoryManager->peekExecutionEnvironment().rootDeviceEnvironments[mockRootDeviceIndex]->deviceAffinityMask = affinityMaskHelper; + + for (auto &multiTile : ::testing::Bool()) { + for (auto &allocationType : {AllocationType::COMMAND_BUFFER, AllocationType::RING_BUFFER, AllocationType::SEMAPHORE_BUFFER}) { + AllocationProperties properties{mockRootDeviceIndex, false, numDevices * MemoryConstants::pageSize64k, allocationType, false, affinityMaskHelper.getGenericSubDevicesMask()}; + properties.flags.multiOsContextCapable = multiTile; + auto storageInfo = memoryManager->createStorageInfoFromProperties(properties); + EXPECT_EQ(DeviceBitfield{firstAvailableTileMask}, storageInfo.memoryBanks); + } + } +} \ No newline at end of file