2018-10-04 00:52:51 +02:00
/*
2024-05-22 14:12:59 +00:00
* Copyright ( C ) 2018 - 2024 Intel Corporation
2018-10-04 00:52:51 +02:00
*
* SPDX - License - Identifier : MIT
*
*/
2020-02-23 22:44:01 +01:00
# include "shared/source/os_interface/windows/wddm_residency_controller.h"
2019-02-27 11:39:32 +01:00
2020-02-23 22:44:01 +01: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 00:52:51 +02:00
2019-03-26 11:59:46 +01:00
namespace NEO {
2018-10-04 00:52:51 +02:00
2018-10-30 14:40:02 +01:00
WddmResidencyController : : WddmResidencyController ( Wddm & wddm , uint32_t osContextId ) : wddm ( wddm ) , osContextId ( osContextId ) {
2018-11-14 14:35:45 +01:00
}
void WddmResidencyController : : registerCallback ( ) {
2018-11-15 11:44:37 +01:00
this - > trimCallbackHandle = wddm . registerTrimCallback ( WddmResidencyController : : trimCallback , * this ) ;
2018-10-30 14:40:02 +01:00
}
WddmResidencyController : : ~ WddmResidencyController ( ) {
auto lock = this - > acquireTrimCallbackLock ( ) ;
2018-11-15 11:44:37 +01:00
wddm . unregisterTrimCallback ( WddmResidencyController : : trimCallback , this - > trimCallbackHandle ) ;
2018-10-30 14:40:02 +01:00
lock . unlock ( ) ;
// Wait for lock to ensure trimCallback ended
lock . lock ( ) ;
}
2018-10-04 00:52:51 +02:00
2018-10-16 15:53:39 +02:00
std : : unique_lock < SpinLock > WddmResidencyController : : acquireLock ( ) {
return std : : unique_lock < SpinLock > { this - > lock } ;
2018-10-04 00:52:51 +02:00
}
2018-10-16 15:53:39 +02:00
std : : unique_lock < SpinLock > WddmResidencyController : : acquireTrimCallbackLock ( ) {
return std : : unique_lock < SpinLock > { this - > trimCallbackLock } ;
2018-10-15 17:12:55 +02:00
}
2018-10-04 00:52:51 +02: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 09:25:18 +01:00
return static_cast < WddmAllocation * > ( trimCandidateList [ i ] ) ;
2018-10-04 00:52:51 +02:00
}
void WddmResidencyController : : addToTrimCandidateList ( GraphicsAllocation * allocation ) {
WddmAllocation * wddmAllocation = ( WddmAllocation * ) allocation ;
size_t position = trimCandidateList . size ( ) ;
DEBUG_BREAK_IF ( trimCandidatesCount > trimCandidateList . size ( ) ) ;
2018-10-09 17:03:07 +02:00
if ( wddmAllocation - > getTrimCandidateListPosition ( this - > osContextId ) = = trimListUnusedPosition ) {
2018-10-04 00:52:51 +02:00
trimCandidatesCount + + ;
trimCandidateList . push_back ( allocation ) ;
2018-10-09 17:03:07 +02:00
wddmAllocation - > setTrimCandidateListPosition ( this - > osContextId , position ) ;
2018-10-04 00:52:51 +02:00
}
checkTrimCandidateCount ( ) ;
}
void WddmResidencyController : : removeFromTrimCandidateList ( GraphicsAllocation * allocation , bool compactList ) {
WddmAllocation * wddmAllocation = ( WddmAllocation * ) allocation ;
2018-10-09 17:03:07 +02:00
size_t position = wddmAllocation - > getTrimCandidateListPosition ( this - > osContextId ) ;
2018-10-04 00:52:51 +02: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 17:03:07 +02:00
wddmAllocation - > setTrimCandidateListPosition ( this - > osContextId , trimListUnusedPosition ) ;
2018-10-04 00:52:51 +02:00
if ( compactList & & checkTrimCandidateListCompaction ( ) ) {
compactTrimCandidateList ( ) ;
}
checkTrimCandidateCount ( ) ;
}
2018-10-09 17:03:07 +02:00
void WddmResidencyController : : removeFromTrimCandidateListIfUsed ( WddmAllocation * allocation , bool compactList ) {
if ( allocation - > getTrimCandidateListPosition ( this - > osContextId ) ! = trimListUnusedPosition ) {
this - > removeFromTrimCandidateList ( allocation , true ) ;
}
}
2018-10-04 00:52:51 +02:00
void WddmResidencyController : : checkTrimCandidateCount ( ) {
2023-11-30 08:32:25 +00:00
if ( debugManager . flags . ResidencyDebugEnable . get ( ) ) {
2023-10-10 00:53:05 +00:00
[[maybe_unused]] uint32_t sum = 0 ;
2019-07-29 13:35:55 +02:00
for ( auto trimCandidate : trimCandidateList ) {
if ( trimCandidate ! = nullptr ) {
2018-10-04 00:52:51 +02:00
sum + + ;
}
}
DEBUG_BREAK_IF ( sum ! = trimCandidatesCount ) ;
}
}
bool WddmResidencyController : : checkTrimCandidateListCompaction ( ) {
2019-02-28 11:21:01 +01:00
return 2 * trimCandidatesCount < = trimCandidateList . size ( ) ;
2018-10-04 00:52:51 +02: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 13:48:33 +00:00
[[maybe_unused]] uint32_t previousCount = trimCandidatesCount ;
2018-10-04 00:52:51 +02: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 17:03:07 +02:00
static_cast < WddmAllocation * > ( trimCandidateList [ freePosition ] ) - > setTrimCandidateListPosition ( this - > osContextId , freePosition ) ;
2018-10-04 00:52:51 +02: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 15:59:26 +02: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 ;
}
2019-09-05 11:02:40 +02:00
bool WddmResidencyController : : makeResidentResidencyAllocations ( const ResidencyContainer & allocationsForResidency ) {
2018-11-15 14:45:35 +01:00
const size_t residencyCount = allocationsForResidency . size ( ) ;
2020-04-21 13:16:45 +02:00
constexpr uint32_t stackAllocations = 64 ;
constexpr uint32_t stackHandlesCount = NEO : : maxFragmentsCount * EngineLimits : : maxHandleCount * stackAllocations ;
StackVec < D3DKMT_HANDLE , stackHandlesCount > handlesForResidency ;
2018-11-05 15:47:32 +01:00
uint32_t totalHandlesCount = 0 ;
2020-03-17 12:19:38 +01:00
size_t totalSize = 0 ;
2018-11-05 15:47:32 +01: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 09:25:18 +01:00
WddmAllocation * allocation = static_cast < WddmAllocation * > ( allocationsForResidency [ i ] ) ;
2018-11-15 14:45:35 +01:00
ResidencyData & residencyData = allocation - > getResidencyData ( ) ;
2021-06-09 13:53:41 +00:00
static constexpr int maxFragments = 3 ;
bool fragmentResidency [ maxFragments ] = { false , false , false } ;
2020-03-17 12:19:38 +01:00
totalSize + = allocation - > getAlignedSize ( ) ;
2018-11-05 15:47:32 +01:00
2024-05-23 08:23:44 +00:00
DBG_LOG ( ResidencyDebugEnable , " Residency: " , __FUNCTION__ , " allocation, gpu address = " , std : : hex , allocation - > getGpuAddress ( ) , residencyData . resident [ osContextId ] ? " resident " : " not resident " ) ;
2018-11-05 15:47:32 +01:00
2021-06-10 19:43:22 +00:00
const auto fragmentCount = allocation - > fragmentsStorage . fragmentCount ;
UNRECOVERABLE_IF ( fragmentCount > maxFragments ) ;
2018-11-05 15:47:32 +01:00
if ( allocation - > getTrimCandidateListPosition ( this - > osContextId ) ! = trimListUnusedPosition ) {
2024-05-23 08:23:44 +00:00
DBG_LOG ( ResidencyDebugEnable , " Residency: " , __FUNCTION__ , " allocation, gpu address = " , std : : hex , allocation - > getGpuAddress ( ) , " on trimCandidateList " ) ;
2018-11-05 15:47:32 +01:00
this - > removeFromTrimCandidateList ( allocation , false ) ;
} else {
2021-06-10 19:43:22 +00:00
for ( uint32_t allocationId = 0 ; allocationId < fragmentCount ; allocationId + + ) {
2018-11-28 11:01:41 +01:00
fragmentResidency [ allocationId ] = allocation - > fragmentsStorage . fragmentStorageData [ allocationId ] . residency - > resident [ osContextId ] ;
2021-04-02 17:01:51 +00: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 15:47:32 +01:00
}
}
2021-06-10 19:43:22 +00:00
if ( fragmentCount > 0 ) {
for ( uint32_t allocationId = 0 ; allocationId < fragmentCount ; allocationId + + ) {
2020-04-21 13:16:45 +02:00
if ( ! fragmentResidency [ allocationId ] ) {
2021-04-02 17:01:51 +00:00
handlesForResidency . push_back ( static_cast < OsHandleWin * > ( allocation - > fragmentsStorage . fragmentStorageData [ allocationId ] . osHandleStorage ) - > handle ) ;
2020-04-21 13:16:45 +02:00
totalHandlesCount + + ;
}
2018-11-05 15:47:32 +01:00
}
2018-11-28 11:01:41 +01:00
} else if ( ! residencyData . resident [ osContextId ] ) {
2020-04-21 13:16:45 +02:00
for ( uint32_t gmmId = 0 ; gmmId < allocation - > getNumGmms ( ) ; + + gmmId ) {
handlesForResidency . push_back ( allocation - > getHandle ( gmmId ) ) ;
totalHandlesCount + + ;
}
2018-11-05 15:47:32 +01:00
}
}
bool result = true ;
if ( totalHandlesCount ) {
uint64_t bytesToTrim = 0 ;
2020-04-21 13:16:45 +02:00
while ( ( result = wddm . makeResident ( & handlesForResidency [ 0 ] , totalHandlesCount , false , & bytesToTrim , totalSize ) ) = = false ) {
2018-11-05 15:47:32 +01:00
this - > setMemoryBudgetExhausted ( ) ;
2018-11-15 14:45:35 +01:00
const bool trimmingDone = this - > trimResidencyToBudget ( bytesToTrim ) ;
if ( ! trimmingDone ) {
2019-07-12 16:50:14 +02:00
auto evictionStatus = wddm . getTemporaryResourcesContainer ( ) - > evictAllResources ( ) ;
2023-12-13 09:17:24 +00:00
if ( evictionStatus = = MemoryOperationsStatus : : success ) {
2019-01-16 15:09:33 +01:00
continue ;
}
2023-12-13 09:17:24 +00:00
DEBUG_BREAK_IF ( evictionStatus ! = MemoryOperationsStatus : : memoryNotFound ) ;
2023-05-31 13:55:08 +00:00
do {
result = wddm . makeResident ( & handlesForResidency [ 0 ] , totalHandlesCount , true , & bytesToTrim , totalSize ) ;
2023-11-30 08:32:25 +00:00
} while ( debugManager . flags . WaitForMemoryRelease . get ( ) & & result = = false ) ;
2018-11-05 15:47:32 +01:00
break ;
}
}
}
if ( result = = true ) {
for ( uint32_t i = 0 ; i < residencyCount ; i + + ) {
2019-03-05 09:25:18 +01:00
WddmAllocation * allocation = static_cast < WddmAllocation * > ( allocationsForResidency [ i ] ) ;
2018-11-05 15:47:32 +01:00
// Update fence value not to early destroy / evict allocation
2018-11-15 14:45:35 +01:00
const auto currentFence = this - > getMonitoredFence ( ) . currentFenceValue ;
2024-05-23 08:23:44 +00:00
DBG_LOG ( ResidencyDebugEnable , " Residency: " , __FUNCTION__ , " allocation, gpu address = " , std : : hex , allocation - > getGpuAddress ( ) , " fence value to reach for eviction = " , currentFence ) ;
2018-11-05 15:47:32 +01:00
allocation - > getResidencyData ( ) . updateCompletionData ( currentFence , this - > osContextId ) ;
2018-11-28 11:01:41 +01:00
allocation - > getResidencyData ( ) . resident [ osContextId ] = true ;
2018-11-05 15:47:32 +01: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 11:01:41 +01:00
residencyData - > resident [ osContextId ] = true ;
2018-11-05 15:47:32 +01:00
}
}
}
return result ;
}
2019-09-05 11:02:40 +02:00
void WddmResidencyController : : makeNonResidentEvictionAllocations ( const ResidencyContainer & evictionAllocations ) {
2018-11-05 15:47:32 +01:00
auto lock = this - > acquireLock ( ) ;
const size_t residencyCount = evictionAllocations . size ( ) ;
for ( uint32_t i = 0 ; i < residencyCount ; i + + ) {
2019-03-05 09:25:18 +01:00
WddmAllocation * allocation = static_cast < WddmAllocation * > ( evictionAllocations [ i ] ) ;
2018-11-05 15:47:32 +01:00
this - > addToTrimCandidateList ( allocation ) ;
}
}
2019-12-19 14:02:05 +01:00
bool WddmResidencyController : : isInitialized ( ) const {
2021-05-21 01:17:57 +02:00
bool requiresTrimCallbacks = OSInterface : : requiresSupportForWddmTrimNotification ;
2023-11-30 08:32:25 +00:00
requiresTrimCallbacks = requiresTrimCallbacks & & ( false = = debugManager . flags . DoNotRegisterTrimCallback . get ( ) ) ;
2021-05-21 01:17:57 +02:00
if ( requiresTrimCallbacks ) {
2019-12-19 14:02:05 +01:00
return trimCallbackHandle ! = nullptr ;
}
return true ;
}
2019-03-26 11:59:46 +01:00
} // namespace NEO