Try To Recover From MakeResident Failure
Per MSDN recommendations, Dawn should handle MakeResident failures by evicting some more and attempting MakeResident again. Bug: dawn:193 Change-Id: I0a9d326dcd000360f6eafb5691efb4987a77e8d5 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/22280 Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Brandon Jones <brandon1.jones@intel.com>
This commit is contained in:
parent
2f02207805
commit
0395ca9b66
|
@ -37,11 +37,11 @@ namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
// If the heap isn't already resident, make it resident.
|
// If the heap isn't already resident, make it resident.
|
||||||
if (!pageable->IsInResidencyLRUCache() && !pageable->IsResidencyLocked()) {
|
if (!pageable->IsInResidencyLRUCache() && !pageable->IsResidencyLocked()) {
|
||||||
DAWN_TRY(EnsureCanMakeResident(pageable->GetSize(),
|
|
||||||
GetMemorySegmentInfo(pageable->GetMemorySegment())));
|
|
||||||
ID3D12Pageable* d3d12Pageable = pageable->GetD3D12Pageable();
|
ID3D12Pageable* d3d12Pageable = pageable->GetD3D12Pageable();
|
||||||
DAWN_TRY(CheckHRESULT(mDevice->GetD3D12Device()->MakeResident(1, &d3d12Pageable),
|
uint64_t size = pageable->GetSize();
|
||||||
"Making a scheduled-to-be-used resource resident"));
|
|
||||||
|
DAWN_TRY(MakeAllocationsResident(GetMemorySegmentInfo(pageable->GetMemorySegment()),
|
||||||
|
size, 1, &d3d12Pageable));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since we can't evict the heap, it's unnecessary to track the heap in the LRU Cache.
|
// Since we can't evict the heap, it's unnecessary to track the heap in the LRU Cache.
|
||||||
|
@ -181,13 +181,18 @@ namespace dawn_native { namespace d3d12 {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return EnsureCanMakeResident(allocationSize, GetMemorySegmentInfo(memorySegment));
|
uint64_t bytesEvicted;
|
||||||
|
DAWN_TRY_ASSIGN(bytesEvicted,
|
||||||
|
EnsureCanMakeResident(allocationSize, GetMemorySegmentInfo(memorySegment)));
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any time we need to make something resident, we must check that we have enough free memory to
|
// Any time we need to make something resident, we must check that we have enough free memory to
|
||||||
// make the new object resident while also staying within budget. If there isn't enough
|
// make the new object resident while also staying within budget. If there isn't enough
|
||||||
// memory, we should evict until there is.
|
// memory, we should evict until there is. Returns the number of bytes evicted.
|
||||||
MaybeError ResidencyManager::EnsureCanMakeResident(uint64_t sizeToMakeResident,
|
ResultOrError<uint64_t> ResidencyManager::EnsureCanMakeResident(
|
||||||
|
uint64_t sizeToMakeResident,
|
||||||
MemorySegmentInfo* memorySegment) {
|
MemorySegmentInfo* memorySegment) {
|
||||||
ASSERT(mResidencyManagementEnabled);
|
ASSERT(mResidencyManagementEnabled);
|
||||||
|
|
||||||
|
@ -197,7 +202,7 @@ namespace dawn_native { namespace d3d12 {
|
||||||
|
|
||||||
// Return when we can call MakeResident and remain under budget.
|
// Return when we can call MakeResident and remain under budget.
|
||||||
if (memoryUsageAfterMakeResident < memorySegment->budget) {
|
if (memoryUsageAfterMakeResident < memorySegment->budget) {
|
||||||
return {};
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ID3D12Pageable*> resourcesToEvict;
|
std::vector<ID3D12Pageable*> resourcesToEvict;
|
||||||
|
@ -222,7 +227,7 @@ namespace dawn_native { namespace d3d12 {
|
||||||
"Evicting resident heaps to free memory"));
|
"Evicting resident heaps to free memory"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return sizeEvicted;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a list of heaps that are pending usage, this function will estimate memory needed,
|
// Given a list of heaps that are pending usage, this function will estimate memory needed,
|
||||||
|
@ -233,7 +238,8 @@ namespace dawn_native { namespace d3d12 {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ID3D12Pageable*> heapsToMakeResident;
|
std::vector<ID3D12Pageable*> localHeapsToMakeResident;
|
||||||
|
std::vector<ID3D12Pageable*> nonLocalHeapsToMakeResident;
|
||||||
uint64_t localSizeToMakeResident = 0;
|
uint64_t localSizeToMakeResident = 0;
|
||||||
uint64_t nonLocalSizeToMakeResident = 0;
|
uint64_t nonLocalSizeToMakeResident = 0;
|
||||||
|
|
||||||
|
@ -251,11 +257,12 @@ namespace dawn_native { namespace d3d12 {
|
||||||
// update its position in the LRU.
|
// update its position in the LRU.
|
||||||
heap->RemoveFromList();
|
heap->RemoveFromList();
|
||||||
} else {
|
} else {
|
||||||
heapsToMakeResident.push_back(heap->GetD3D12Pageable());
|
|
||||||
if (heap->GetMemorySegment() == MemorySegment::Local) {
|
if (heap->GetMemorySegment() == MemorySegment::Local) {
|
||||||
localSizeToMakeResident += heap->GetSize();
|
localSizeToMakeResident += heap->GetSize();
|
||||||
|
localHeapsToMakeResident.push_back(heap->GetD3D12Pageable());
|
||||||
} else {
|
} else {
|
||||||
nonLocalSizeToMakeResident += heap->GetSize();
|
nonLocalSizeToMakeResident += heap->GetSize();
|
||||||
|
nonLocalHeapsToMakeResident.push_back(heap->GetD3D12Pageable());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,25 +277,56 @@ namespace dawn_native { namespace d3d12 {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (localSizeToMakeResident > 0) {
|
if (localSizeToMakeResident > 0) {
|
||||||
DAWN_TRY(EnsureCanMakeResident(localSizeToMakeResident, &mVideoMemoryInfo.local));
|
return MakeAllocationsResident(&mVideoMemoryInfo.local, localSizeToMakeResident,
|
||||||
|
localHeapsToMakeResident.size(),
|
||||||
|
localHeapsToMakeResident.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nonLocalSizeToMakeResident > 0) {
|
if (nonLocalSizeToMakeResident > 0) {
|
||||||
ASSERT(!mDevice->GetDeviceInfo().isUMA);
|
ASSERT(!mDevice->GetDeviceInfo().isUMA);
|
||||||
DAWN_TRY(EnsureCanMakeResident(nonLocalSizeToMakeResident, &mVideoMemoryInfo.nonLocal));
|
return MakeAllocationsResident(&mVideoMemoryInfo.nonLocal, nonLocalSizeToMakeResident,
|
||||||
|
nonLocalHeapsToMakeResident.size(),
|
||||||
|
nonLocalHeapsToMakeResident.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (heapsToMakeResident.size() != 0) {
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeError ResidencyManager::MakeAllocationsResident(MemorySegmentInfo* segment,
|
||||||
|
uint64_t sizeToMakeResident,
|
||||||
|
uint64_t numberOfObjectsToMakeResident,
|
||||||
|
ID3D12Pageable** allocations) {
|
||||||
|
uint64_t bytesEvicted;
|
||||||
|
DAWN_TRY_ASSIGN(bytesEvicted, EnsureCanMakeResident(sizeToMakeResident, segment));
|
||||||
|
|
||||||
// Note that MakeResident is a synchronous function and can add a significant
|
// Note that MakeResident is a synchronous function and can add a significant
|
||||||
// overhead to command recording. In the future, it may be possible to decrease this
|
// overhead to command recording. In the future, it may be possible to decrease this
|
||||||
// overhead by using MakeResident on a secondary thread, or by instead making use of
|
// overhead by using MakeResident on a secondary thread, or by instead making use of
|
||||||
// the EnqueueMakeResident function (which is not available on all Windows 10
|
// the EnqueueMakeResident function (which is not available on all Windows 10
|
||||||
// platforms).
|
// platforms).
|
||||||
// TODO(brandon1.jones@intel.com): If MakeResident fails, try evicting some more and
|
HRESULT hr =
|
||||||
// call MakeResident again.
|
mDevice->GetD3D12Device()->MakeResident(numberOfObjectsToMakeResident, allocations);
|
||||||
DAWN_TRY(CheckHRESULT(mDevice->GetD3D12Device()->MakeResident(
|
|
||||||
heapsToMakeResident.size(), heapsToMakeResident.data()),
|
// A MakeResident call can fail if there's not enough available memory. This
|
||||||
"Making scheduled-to-be-used resources resident"));
|
// could occur when there's significant fragmentation or if the allocation size
|
||||||
|
// estimates are incorrect. We may be able to continue execution by evicting some
|
||||||
|
// more memory and calling MakeResident again.
|
||||||
|
while (FAILED(hr)) {
|
||||||
|
constexpr uint32_t kAdditonalSizeToEvict = 50000000; // 50MB
|
||||||
|
|
||||||
|
uint64_t sizeEvicted = 0;
|
||||||
|
|
||||||
|
DAWN_TRY_ASSIGN(sizeEvicted, EnsureCanMakeResident(kAdditonalSizeToEvict, segment));
|
||||||
|
|
||||||
|
// If nothing can be evicted after MakeResident has failed, we cannot continue
|
||||||
|
// execution and must throw a fatal error.
|
||||||
|
if (sizeEvicted == 0) {
|
||||||
|
return DAWN_OUT_OF_MEMORY_ERROR(
|
||||||
|
"MakeResident has failed due to excessive video memory usage.");
|
||||||
|
}
|
||||||
|
|
||||||
|
hr =
|
||||||
|
mDevice->GetD3D12Device()->MakeResident(numberOfObjectsToMakeResident, allocations);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -62,8 +62,13 @@ namespace dawn_native { namespace d3d12 {
|
||||||
};
|
};
|
||||||
|
|
||||||
MemorySegmentInfo* GetMemorySegmentInfo(MemorySegment memorySegment);
|
MemorySegmentInfo* GetMemorySegmentInfo(MemorySegment memorySegment);
|
||||||
MaybeError EnsureCanMakeResident(uint64_t allocationSize, MemorySegmentInfo* memorySegment);
|
ResultOrError<uint64_t> EnsureCanMakeResident(uint64_t allocationSize,
|
||||||
|
MemorySegmentInfo* memorySegment);
|
||||||
ResultOrError<Pageable*> RemoveSingleEntryFromLRU(MemorySegmentInfo* memorySegment);
|
ResultOrError<Pageable*> RemoveSingleEntryFromLRU(MemorySegmentInfo* memorySegment);
|
||||||
|
MaybeError MakeAllocationsResident(MemorySegmentInfo* segment,
|
||||||
|
uint64_t sizeToMakeResident,
|
||||||
|
uint64_t numberOfObjectsToMakeResident,
|
||||||
|
ID3D12Pageable** allocations);
|
||||||
void UpdateVideoMemoryInfo();
|
void UpdateVideoMemoryInfo();
|
||||||
void UpdateMemorySegmentInfo(MemorySegmentInfo* segmentInfo);
|
void UpdateMemorySegmentInfo(MemorySegmentInfo* segmentInfo);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue