2018-10-04 06:52:51 +08:00
/*
2024-05-22 22:12:59 +08:00
* Copyright ( C ) 2018 - 2024 Intel Corporation
2018-10-04 06:52:51 +08:00
*
* SPDX - License - Identifier : MIT
*
*/
2020-02-24 05:44:01 +08:00
# include "shared/source/os_interface/windows/wddm_residency_controller.h"
2019-02-27 18:39:32 +08:00
2020-02-24 05:44:01 +08:00
# include "shared/source/debug_settings/debug_settings_manager.h"
# include "shared/source/os_interface/windows/wddm/wddm.h"
# include "shared/source/os_interface/windows/wddm_allocation.h"
# include "shared/source/os_interface/windows/wddm_residency_allocations_container.h"
# include "shared/source/utilities/spinlock.h"
2018-10-04 06:52:51 +08:00
2019-03-26 18:59:46 +08:00
namespace NEO {
2018-10-04 06:52:51 +08:00
2018-10-30 21:40:02 +08:00
WddmResidencyController : : WddmResidencyController ( Wddm & wddm , uint32_t osContextId ) : wddm ( wddm ) , osContextId ( osContextId ) {
2018-11-14 21:35:45 +08:00
}
void WddmResidencyController : : registerCallback ( ) {
2018-11-15 18:44:37 +08:00
this - > trimCallbackHandle = wddm . registerTrimCallback ( WddmResidencyController : : trimCallback , * this ) ;
2018-10-30 21:40:02 +08:00
}
WddmResidencyController : : ~ WddmResidencyController ( ) {
auto lock = this - > acquireTrimCallbackLock ( ) ;
2018-11-15 18:44:37 +08:00
wddm . unregisterTrimCallback ( WddmResidencyController : : trimCallback , this - > trimCallbackHandle ) ;
2018-10-30 21:40:02 +08:00
lock . unlock ( ) ;
// Wait for lock to ensure trimCallback ended
lock . lock ( ) ;
}
2018-10-04 06:52:51 +08:00
2018-10-16 21:53:39 +08:00
std : : unique_lock < SpinLock > WddmResidencyController : : acquireLock ( ) {
return std : : unique_lock < SpinLock > { this - > lock } ;
2018-10-04 06:52:51 +08:00
}
2018-10-16 21:53:39 +08:00
std : : unique_lock < SpinLock > WddmResidencyController : : acquireTrimCallbackLock ( ) {
return std : : unique_lock < SpinLock > { this - > trimCallbackLock } ;
2018-10-15 23:12:55 +08:00
}
2018-10-04 06:52:51 +08:00
WddmAllocation * WddmResidencyController : : getTrimCandidateHead ( ) {
uint32_t i = 0 ;
const size_t size = trimCandidateList . size ( ) ;
if ( size = = 0 ) {
return nullptr ;
}
while ( ( trimCandidateList [ i ] = = nullptr ) & & ( i < size ) )
i + + ;
2019-03-05 16:25:18 +08:00
return static_cast < WddmAllocation * > ( trimCandidateList [ i ] ) ;
2018-10-04 06:52:51 +08:00
}
void WddmResidencyController : : addToTrimCandidateList ( GraphicsAllocation * allocation ) {
WddmAllocation * wddmAllocation = ( WddmAllocation * ) allocation ;
size_t position = trimCandidateList . size ( ) ;
DEBUG_BREAK_IF ( trimCandidatesCount > trimCandidateList . size ( ) ) ;
2018-10-09 23:03:07 +08:00
if ( wddmAllocation - > getTrimCandidateListPosition ( this - > osContextId ) = = trimListUnusedPosition ) {
2018-10-04 06:52:51 +08:00
trimCandidatesCount + + ;
trimCandidateList . push_back ( allocation ) ;
2018-10-09 23:03:07 +08:00
wddmAllocation - > setTrimCandidateListPosition ( this - > osContextId , position ) ;
2018-10-04 06:52:51 +08:00
}
checkTrimCandidateCount ( ) ;
}
void WddmResidencyController : : removeFromTrimCandidateList ( GraphicsAllocation * allocation , bool compactList ) {
WddmAllocation * wddmAllocation = ( WddmAllocation * ) allocation ;
2018-10-09 23:03:07 +08:00
size_t position = wddmAllocation - > getTrimCandidateListPosition ( this - > osContextId ) ;
2018-10-04 06:52:51 +08:00
DEBUG_BREAK_IF ( ! ( trimCandidatesCount > ( trimCandidatesCount - 1 ) ) ) ;
DEBUG_BREAK_IF ( trimCandidatesCount > trimCandidateList . size ( ) ) ;
trimCandidatesCount - - ;
trimCandidateList [ position ] = nullptr ;
checkTrimCandidateCount ( ) ;
if ( position = = trimCandidateList . size ( ) - 1 ) {
size_t erasePosition = position ;
if ( position = = 0 ) {
trimCandidateList . resize ( 0 ) ;
} else {
while ( trimCandidateList [ erasePosition ] = = nullptr & & erasePosition > 0 ) {
erasePosition - - ;
}
size_t sizeRemaining = erasePosition + 1 ;
if ( erasePosition = = 0 & & trimCandidateList [ erasePosition ] = = nullptr ) {
sizeRemaining = 0 ;
}
trimCandidateList . resize ( sizeRemaining ) ;
}
}
2018-10-09 23:03:07 +08:00
wddmAllocation - > setTrimCandidateListPosition ( this - > osContextId , trimListUnusedPosition ) ;
2018-10-04 06:52:51 +08:00
if ( compactList & & checkTrimCandidateListCompaction ( ) ) {
compactTrimCandidateList ( ) ;
}
checkTrimCandidateCount ( ) ;
}
2018-10-09 23:03:07 +08:00
void WddmResidencyController : : removeFromTrimCandidateListIfUsed ( WddmAllocation * allocation , bool compactList ) {
if ( allocation - > getTrimCandidateListPosition ( this - > osContextId ) ! = trimListUnusedPosition ) {
this - > removeFromTrimCandidateList ( allocation , true ) ;
}
}
2018-10-04 06:52:51 +08:00
void WddmResidencyController : : checkTrimCandidateCount ( ) {
2023-11-30 16:32:25 +08:00
if ( debugManager . flags . ResidencyDebugEnable . get ( ) ) {
2023-10-10 08:53:05 +08:00
[[maybe_unused]] uint32_t sum = 0 ;
2019-07-29 19:35:55 +08:00
for ( auto trimCandidate : trimCandidateList ) {
if ( trimCandidate ! = nullptr ) {
2018-10-04 06:52:51 +08:00
sum + + ;
}
}
DEBUG_BREAK_IF ( sum ! = trimCandidatesCount ) ;
}
}
bool WddmResidencyController : : checkTrimCandidateListCompaction ( ) {
2019-02-28 18:21:01 +08:00
return 2 * trimCandidatesCount < = trimCandidateList . size ( ) ;
2018-10-04 06:52:51 +08:00
}
void WddmResidencyController : : compactTrimCandidateList ( ) {
size_t size = trimCandidateList . size ( ) ;
size_t freePosition = 0 ;
if ( size = = 0 | | size = = trimCandidatesCount ) {
return ;
}
DEBUG_BREAK_IF ( ! ( trimCandidateList [ size - 1 ] ! = nullptr ) ) ;
2021-05-20 21:48:33 +08:00
[[maybe_unused]] uint32_t previousCount = trimCandidatesCount ;
2018-10-04 06:52:51 +08:00
DEBUG_BREAK_IF ( trimCandidatesCount > trimCandidateList . size ( ) ) ;
while ( freePosition < trimCandidatesCount & & trimCandidateList [ freePosition ] ! = nullptr )
freePosition + + ;
for ( uint32_t i = 1 ; i < size ; i + + ) {
if ( trimCandidateList [ i ] ! = nullptr & & freePosition < i ) {
trimCandidateList [ freePosition ] = trimCandidateList [ i ] ;
trimCandidateList [ i ] = nullptr ;
2018-10-09 23:03:07 +08:00
static_cast < WddmAllocation * > ( trimCandidateList [ freePosition ] ) - > setTrimCandidateListPosition ( this - > osContextId , freePosition ) ;
2018-10-04 06:52:51 +08:00
freePosition + + ;
// Last element was moved, erase elements from freePosition
if ( i = = size - 1 ) {
trimCandidateList . resize ( freePosition ) ;
}
}
}
DEBUG_BREAK_IF ( trimCandidatesCount > trimCandidateList . size ( ) ) ;
DEBUG_BREAK_IF ( trimCandidatesCount ! = previousCount ) ;
checkTrimCandidateCount ( ) ;
}
2018-10-22 21:59:26 +08:00
void WddmResidencyController : : resetMonitoredFenceParams ( D3DKMT_HANDLE & handle , uint64_t * cpuAddress , D3DGPU_VIRTUAL_ADDRESS & gpuAddress ) {
monitoredFence . lastSubmittedFence = 0 ;
monitoredFence . currentFenceValue = 1 ;
monitoredFence . fenceHandle = handle ;
monitoredFence . cpuAddress = cpuAddress ;
monitoredFence . gpuAddress = gpuAddress ;
}
2024-08-07 00:13:06 +08:00
/**
* @ brief Makes resident passed allocations on a device
*
* @ param [ in ] allocationsForResidency container of allocations which need to be resident .
* @ param [ out ] requiresBlockingResidencyHandling flag indicating whether wait for paging fence must be handled in user thread .
* Setting to false means that it can be handled in background thread , which will signal semaphore after paging fence reaches required value .
*
* @ note This method skips allocations which are already resident .
*
* @ return returns true if all allocations either succeeded or are pending to be resident
*/
bool WddmResidencyController : : makeResidentResidencyAllocations ( const ResidencyContainer & allocationsForResidency , bool & requiresBlockingResidencyHandling ) {
2018-11-15 21:45:35 +08:00
const size_t residencyCount = allocationsForResidency . size ( ) ;
2020-04-21 19:16:45 +08:00
constexpr uint32_t stackAllocations = 64 ;
constexpr uint32_t stackHandlesCount = NEO : : maxFragmentsCount * EngineLimits : : maxHandleCount * stackAllocations ;
StackVec < D3DKMT_HANDLE , stackHandlesCount > handlesForResidency ;
2018-11-05 22:47:32 +08:00
uint32_t totalHandlesCount = 0 ;
2020-03-17 19:19:38 +08:00
size_t totalSize = 0 ;
2024-08-07 17:31:59 +08:00
requiresBlockingResidencyHandling = false ;
2024-08-07 00:13:06 +08:00
if ( debugManager . flags . WaitForPagingFenceInController . get ( ) ! = - 1 ) {
requiresBlockingResidencyHandling = ! debugManager . flags . WaitForPagingFenceInController . get ( ) ;
}
2018-11-05 22:47:32 +08:00
auto lock = this - > acquireLock ( ) ;
DBG_LOG ( ResidencyDebugEnable , " Residency: " , __FUNCTION__ , " currentFenceValue = " , this - > getMonitoredFence ( ) . currentFenceValue ) ;
for ( uint32_t i = 0 ; i < residencyCount ; i + + ) {
2019-03-05 16:25:18 +08:00
WddmAllocation * allocation = static_cast < WddmAllocation * > ( allocationsForResidency [ i ] ) ;
2018-11-15 21:45:35 +08:00
ResidencyData & residencyData = allocation - > getResidencyData ( ) ;
2021-06-09 21:53:41 +08:00
static constexpr int maxFragments = 3 ;
bool fragmentResidency [ maxFragments ] = { false , false , false } ;
2020-03-17 19:19:38 +08:00
totalSize + = allocation - > getAlignedSize ( ) ;
2018-11-05 22:47:32 +08:00
2024-05-23 16:23:44 +08:00
DBG_LOG ( ResidencyDebugEnable , " Residency: " , __FUNCTION__ , " allocation, gpu address = " , std : : hex , allocation - > getGpuAddress ( ) , residencyData . resident [ osContextId ] ? " resident " : " not resident " ) ;
2018-11-05 22:47:32 +08:00
2021-06-11 03:43:22 +08:00
const auto fragmentCount = allocation - > fragmentsStorage . fragmentCount ;
UNRECOVERABLE_IF ( fragmentCount > maxFragments ) ;
2018-11-05 22:47:32 +08:00
if ( allocation - > getTrimCandidateListPosition ( this - > osContextId ) ! = trimListUnusedPosition ) {
2024-05-23 16:23:44 +08:00
DBG_LOG ( ResidencyDebugEnable , " Residency: " , __FUNCTION__ , " allocation, gpu address = " , std : : hex , allocation - > getGpuAddress ( ) , " on trimCandidateList " ) ;
2018-11-05 22:47:32 +08:00
this - > removeFromTrimCandidateList ( allocation , false ) ;
} else {
2021-06-11 03:43:22 +08:00
for ( uint32_t allocationId = 0 ; allocationId < fragmentCount ; allocationId + + ) {
2018-11-28 18:01:41 +08:00
fragmentResidency [ allocationId ] = allocation - > fragmentsStorage . fragmentStorageData [ allocationId ] . residency - > resident [ osContextId ] ;
2021-04-03 01:01:51 +08:00
DBG_LOG ( ResidencyDebugEnable , " Residency: " , __FUNCTION__ , " fragment handle = " ,
static_cast < OsHandleWin * > ( allocation - > fragmentsStorage . fragmentStorageData [ allocationId ] . osHandleStorage ) - > handle ,
fragmentResidency [ allocationId ] ? " resident " : " not resident " ) ;
2018-11-05 22:47:32 +08:00
}
}
2021-06-11 03:43:22 +08:00
if ( fragmentCount > 0 ) {
for ( uint32_t allocationId = 0 ; allocationId < fragmentCount ; allocationId + + ) {
2020-04-21 19:16:45 +08:00
if ( ! fragmentResidency [ allocationId ] ) {
2021-04-03 01:01:51 +08:00
handlesForResidency . push_back ( static_cast < OsHandleWin * > ( allocation - > fragmentsStorage . fragmentStorageData [ allocationId ] . osHandleStorage ) - > handle ) ;
2020-04-21 19:16:45 +08:00
totalHandlesCount + + ;
2024-08-07 00:13:06 +08:00
requiresBlockingResidencyHandling | = ( allocation - > getAllocationType ( ) ! = AllocationType : : buffer & & allocation - > getAllocationType ( ) ! = AllocationType : : bufferHostMemory ) ;
2020-04-21 19:16:45 +08:00
}
2018-11-05 22:47:32 +08:00
}
2018-11-28 18:01:41 +08:00
} else if ( ! residencyData . resident [ osContextId ] ) {
2020-04-21 19:16:45 +08:00
for ( uint32_t gmmId = 0 ; gmmId < allocation - > getNumGmms ( ) ; + + gmmId ) {
handlesForResidency . push_back ( allocation - > getHandle ( gmmId ) ) ;
totalHandlesCount + + ;
2024-08-07 00:13:06 +08:00
requiresBlockingResidencyHandling | = ( allocation - > getAllocationType ( ) ! = AllocationType : : buffer & & allocation - > getAllocationType ( ) ! = AllocationType : : bufferHostMemory ) ;
2020-04-21 19:16:45 +08:00
}
2018-11-05 22:47:32 +08:00
}
}
bool result = true ;
if ( totalHandlesCount ) {
uint64_t bytesToTrim = 0 ;
2020-04-21 19:16:45 +08:00
while ( ( result = wddm . makeResident ( & handlesForResidency [ 0 ] , totalHandlesCount , false , & bytesToTrim , totalSize ) ) = = false ) {
2018-11-05 22:47:32 +08:00
this - > setMemoryBudgetExhausted ( ) ;
2024-08-08 22:49:39 +08:00
const bool trimmingDone = this - > trimResidencyToBudget ( bytesToTrim , lock ) ;
2018-11-15 21:45:35 +08:00
if ( ! trimmingDone ) {
2019-07-12 22:50:14 +08:00
auto evictionStatus = wddm . getTemporaryResourcesContainer ( ) - > evictAllResources ( ) ;
2023-12-13 17:17:24 +08:00
if ( evictionStatus = = MemoryOperationsStatus : : success ) {
2019-01-16 22:09:33 +08:00
continue ;
}
2023-12-13 17:17:24 +08:00
DEBUG_BREAK_IF ( evictionStatus ! = MemoryOperationsStatus : : memoryNotFound ) ;
2023-05-31 21:55:08 +08:00
do {
result = wddm . makeResident ( & handlesForResidency [ 0 ] , totalHandlesCount , true , & bytesToTrim , totalSize ) ;
2023-11-30 16:32:25 +08:00
} while ( debugManager . flags . WaitForMemoryRelease . get ( ) & & result = = false ) ;
2018-11-05 22:47:32 +08:00
break ;
}
}
}
if ( result = = true ) {
for ( uint32_t i = 0 ; i < residencyCount ; i + + ) {
2019-03-05 16:25:18 +08:00
WddmAllocation * allocation = static_cast < WddmAllocation * > ( allocationsForResidency [ i ] ) ;
2018-11-05 22:47:32 +08:00
// Update fence value not to early destroy / evict allocation
2018-11-15 21:45:35 +08:00
const auto currentFence = this - > getMonitoredFence ( ) . currentFenceValue ;
2024-05-23 16:23:44 +08:00
DBG_LOG ( ResidencyDebugEnable , " Residency: " , __FUNCTION__ , " allocation, gpu address = " , std : : hex , allocation - > getGpuAddress ( ) , " fence value to reach for eviction = " , currentFence ) ;
2018-11-05 22:47:32 +08:00
allocation - > getResidencyData ( ) . updateCompletionData ( currentFence , this - > osContextId ) ;
2018-11-28 18:01:41 +08:00
allocation - > getResidencyData ( ) . resident [ osContextId ] = true ;
2018-11-05 22:47:32 +08:00
for ( uint32_t allocationId = 0 ; allocationId < allocation - > fragmentsStorage . fragmentCount ; allocationId + + ) {
auto residencyData = allocation - > fragmentsStorage . fragmentStorageData [ allocationId ] . residency ;
// Update fence value not to remove the fragment referenced by different GA in trimming callback
residencyData - > updateCompletionData ( currentFence , this - > osContextId ) ;
2018-11-28 18:01:41 +08:00
residencyData - > resident [ osContextId ] = true ;
2018-11-05 22:47:32 +08:00
}
}
}
return result ;
}
2019-09-05 17:02:40 +08:00
void WddmResidencyController : : makeNonResidentEvictionAllocations ( const ResidencyContainer & evictionAllocations ) {
2018-11-05 22:47:32 +08:00
auto lock = this - > acquireLock ( ) ;
const size_t residencyCount = evictionAllocations . size ( ) ;
for ( uint32_t i = 0 ; i < residencyCount ; i + + ) {
2019-03-05 16:25:18 +08:00
WddmAllocation * allocation = static_cast < WddmAllocation * > ( evictionAllocations [ i ] ) ;
2018-11-05 22:47:32 +08:00
this - > addToTrimCandidateList ( allocation ) ;
}
}
2019-12-19 21:02:05 +08:00
bool WddmResidencyController : : isInitialized ( ) const {
2021-05-21 07:17:57 +08:00
bool requiresTrimCallbacks = OSInterface : : requiresSupportForWddmTrimNotification ;
2023-11-30 16:32:25 +08:00
requiresTrimCallbacks = requiresTrimCallbacks & & ( false = = debugManager . flags . DoNotRegisterTrimCallback . get ( ) ) ;
2021-05-21 07:17:57 +08:00
if ( requiresTrimCallbacks ) {
2019-12-19 21:02:05 +08:00
return trimCallbackHandle ! = nullptr ;
}
return true ;
}
2019-03-26 18:59:46 +08:00
} // namespace NEO