Non-Local Residency 1: Get Non-Local Memory Info

Adds functionality to query VideoMemoryInfo for the NON_LOCAL memory
segment.

Bug: dawn:193
Change-Id: I63c2f5a649c37617e7b39a60faa2d3b5b5077156
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/19900
Commit-Queue: Brandon Jones <brandon1.jones@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Brandon Jones 2020-04-22 21:57:00 +00:00 committed by Commit Bot service account
parent b4eccc8227
commit f56f19059b
5 changed files with 89 additions and 34 deletions

View File

@ -51,11 +51,13 @@ namespace dawn_native { namespace d3d12 {
: ExternalImageDescriptor(ExternalImageDescriptorType::DXGISharedHandle) { : ExternalImageDescriptor(ExternalImageDescriptorType::DXGISharedHandle) {
} }
uint64_t SetExternalMemoryReservation(WGPUDevice device, uint64_t requestedReservationSize) { uint64_t SetExternalMemoryReservation(WGPUDevice device,
uint64_t requestedReservationSize,
MemorySegment memorySegment) {
Device* backendDevice = reinterpret_cast<Device*>(device); Device* backendDevice = reinterpret_cast<Device*>(device);
return backendDevice->GetResidencyManager()->SetExternalMemoryReservation( return backendDevice->GetResidencyManager()->SetExternalMemoryReservation(
requestedReservationSize); memorySegment, requestedReservationSize);
} }
WGPUTexture WrapSharedHandle(WGPUDevice device, WGPUTexture WrapSharedHandle(WGPUDevice device,

View File

@ -1,3 +1,4 @@
#include "ResidencyManagerD3D12.h"
// Copyright 2020 The Dawn Authors // Copyright 2020 The Dawn Authors
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -20,8 +21,6 @@
#include "dawn_native/d3d12/Forward.h" #include "dawn_native/d3d12/Forward.h"
#include "dawn_native/d3d12/HeapD3D12.h" #include "dawn_native/d3d12/HeapD3D12.h"
#include "dawn_native/d3d12/d3d12_platform.h"
namespace dawn_native { namespace d3d12 { namespace dawn_native { namespace d3d12 {
ResidencyManager::ResidencyManager(Device* device) ResidencyManager::ResidencyManager(Device* device)
@ -84,24 +83,43 @@ namespace dawn_native { namespace d3d12 {
} }
} }
// Allows an application component external to Dawn to cap Dawn's residency budget to prevent // Allows an application component external to Dawn to cap Dawn's residency budgets to prevent
// competition for device local memory. Returns the amount of memory reserved, which may be less // competition for device memory. Returns the amount of memory reserved, which may be less
// that the requested reservation when under pressure. // that the requested reservation when under pressure.
uint64_t ResidencyManager::SetExternalMemoryReservation(uint64_t requestedReservationSize) { uint64_t ResidencyManager::SetExternalMemoryReservation(MemorySegment segment,
mVideoMemoryInfo.externalRequest = requestedReservationSize; uint64_t requestedReservationSize) {
UpdateVideoMemoryInfo(); MemorySegmentInfo* segmentInfo = nullptr;
return mVideoMemoryInfo.externalReservation; switch (segment) {
case MemorySegment::Local:
segmentInfo = &mVideoMemoryInfo.local;
break;
case MemorySegment::NonLocal:
segmentInfo = &mVideoMemoryInfo.nonLocal;
break;
default:
UNREACHABLE();
}
segmentInfo->externalRequest = requestedReservationSize;
UpdateMemorySegmentInfo(segmentInfo);
return segmentInfo->externalReservation;
} }
void ResidencyManager::UpdateVideoMemoryInfo() { void ResidencyManager::UpdateVideoMemoryInfo() {
if (!mResidencyManagementEnabled) { UpdateMemorySegmentInfo(&mVideoMemoryInfo.local);
return; if (!mDevice->GetDeviceInfo().isUMA) {
UpdateMemorySegmentInfo(&mVideoMemoryInfo.nonLocal);
} }
}
void ResidencyManager::UpdateMemorySegmentInfo(MemorySegmentInfo* segmentInfo) {
DXGI_QUERY_VIDEO_MEMORY_INFO queryVideoMemoryInfo; DXGI_QUERY_VIDEO_MEMORY_INFO queryVideoMemoryInfo;
ToBackend(mDevice->GetAdapter()) ToBackend(mDevice->GetAdapter())
->GetHardwareAdapter() ->GetHardwareAdapter()
->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &queryVideoMemoryInfo); ->QueryVideoMemoryInfo(0, segmentInfo->dxgiSegment, &queryVideoMemoryInfo);
// The video memory budget provided by QueryVideoMemoryInfo is defined by the operating // The video memory budget provided by QueryVideoMemoryInfo is defined by the operating
// system, and may be lower than expected in certain scenarios. Under memory pressure, we // system, and may be lower than expected in certain scenarios. Under memory pressure, we
@ -109,11 +127,10 @@ namespace dawn_native { namespace d3d12 {
// component from consuming a disproportionate share of memory and ensures that Dawn can // component from consuming a disproportionate share of memory and ensures that Dawn can
// continue to make forward progress. Note the choice to halve memory is arbitrarily chosen // continue to make forward progress. Note the choice to halve memory is arbitrarily chosen
// and subject to future experimentation. // and subject to future experimentation.
mVideoMemoryInfo.externalReservation = segmentInfo->externalReservation =
std::min(queryVideoMemoryInfo.Budget / 2, mVideoMemoryInfo.externalRequest); std::min(queryVideoMemoryInfo.Budget / 2, segmentInfo->externalRequest);
mVideoMemoryInfo.dawnUsage = segmentInfo->usage = queryVideoMemoryInfo.CurrentUsage - segmentInfo->externalReservation;
queryVideoMemoryInfo.CurrentUsage - mVideoMemoryInfo.externalReservation;
// If we're restricting the budget for testing, leave the budget as is. // If we're restricting the budget for testing, leave the budget as is.
if (mRestrictBudgetForTesting) { if (mRestrictBudgetForTesting) {
@ -125,8 +142,8 @@ namespace dawn_native { namespace d3d12 {
// for both Dawn and other applications on the system. Note the value of 95% is arbitrarily // for both Dawn and other applications on the system. Note the value of 95% is arbitrarily
// chosen and subject to future experimentation. // chosen and subject to future experimentation.
static constexpr float kBudgetCap = 0.95; static constexpr float kBudgetCap = 0.95;
mVideoMemoryInfo.dawnBudget = segmentInfo->budget =
(queryVideoMemoryInfo.Budget - mVideoMemoryInfo.externalReservation) * kBudgetCap; (queryVideoMemoryInfo.Budget - segmentInfo->externalReservation) * kBudgetCap;
} }
// Removes from the LRU and returns the least recently used heap when possible. Returns nullptr // Removes from the LRU and returns the least recently used heap when possible. Returns nullptr
@ -161,18 +178,18 @@ namespace dawn_native { namespace d3d12 {
return {}; return {};
} }
UpdateVideoMemoryInfo(); UpdateMemorySegmentInfo(&mVideoMemoryInfo.local);
uint64_t memoryUsageAfterMakeResident = sizeToMakeResident + mVideoMemoryInfo.dawnUsage; uint64_t memoryUsageAfterMakeResident = sizeToMakeResident + mVideoMemoryInfo.local.usage;
// Return when we can call MakeResident and remain under budget. // Return when we can call MakeResident and remain under budget.
if (memoryUsageAfterMakeResident < mVideoMemoryInfo.dawnBudget) { if (memoryUsageAfterMakeResident < mVideoMemoryInfo.local.budget) {
return {}; return {};
} }
std::vector<ID3D12Pageable*> resourcesToEvict; std::vector<ID3D12Pageable*> resourcesToEvict;
uint64_t sizeNeededToBeUnderBudget = uint64_t sizeNeededToBeUnderBudget =
memoryUsageAfterMakeResident - mVideoMemoryInfo.dawnBudget; memoryUsageAfterMakeResident - mVideoMemoryInfo.local.budget;
uint64_t sizeEvicted = 0; uint64_t sizeEvicted = 0;
while (sizeEvicted < sizeNeededToBeUnderBudget) { while (sizeEvicted < sizeNeededToBeUnderBudget) {
Heap* heap; Heap* heap;
@ -301,7 +318,11 @@ namespace dawn_native { namespace d3d12 {
// value can vary depending on the environment Dawn is running in. By adding this in // value can vary depending on the environment Dawn is running in. By adding this in
// addition to the artificial budget cap, we can create a predictable and reproducible // addition to the artificial budget cap, we can create a predictable and reproducible
// budget for testing. // budget for testing.
mVideoMemoryInfo.dawnBudget = mVideoMemoryInfo.dawnUsage + artificialBudgetCap; mVideoMemoryInfo.local.budget = mVideoMemoryInfo.local.usage + artificialBudgetCap;
if (!mDevice->GetDeviceInfo().isUMA) {
mVideoMemoryInfo.nonLocal.budget =
mVideoMemoryInfo.nonLocal.usage + artificialBudgetCap;
}
} }
}} // namespace dawn_native::d3d12 }} // namespace dawn_native::d3d12

View File

@ -17,9 +17,12 @@
#include "common/LinkedList.h" #include "common/LinkedList.h"
#include "common/Serial.h" #include "common/Serial.h"
#include "dawn_native/D3D12Backend.h"
#include "dawn_native/Error.h" #include "dawn_native/Error.h"
#include "dawn_native/dawn_platform.h" #include "dawn_native/dawn_platform.h"
#include "dawn_native/d3d12/d3d12_platform.h"
namespace dawn_native { namespace d3d12 { namespace dawn_native { namespace d3d12 {
class Device; class Device;
@ -34,22 +37,31 @@ namespace dawn_native { namespace d3d12 {
MaybeError EnsureCanMakeResident(uint64_t allocationSize); MaybeError EnsureCanMakeResident(uint64_t allocationSize);
MaybeError EnsureHeapsAreResident(Heap** heaps, size_t heapCount); MaybeError EnsureHeapsAreResident(Heap** heaps, size_t heapCount);
uint64_t SetExternalMemoryReservation(uint64_t requestedReservationSize); uint64_t SetExternalMemoryReservation(MemorySegment segment,
uint64_t requestedReservationSize);
void TrackResidentAllocation(Heap* heap); void TrackResidentAllocation(Heap* heap);
void RestrictBudgetForTesting(uint64_t); void RestrictBudgetForTesting(uint64_t artificialBudgetCap);
private: private:
struct VideoMemoryInfo { struct MemorySegmentInfo {
uint64_t dawnBudget; const DXGI_MEMORY_SEGMENT_GROUP dxgiSegment;
uint64_t dawnUsage; uint64_t budget;
uint64_t usage;
uint64_t externalReservation; uint64_t externalReservation;
uint64_t externalRequest; uint64_t externalRequest;
}; };
struct VideoMemoryInfo {
MemorySegmentInfo local = {DXGI_MEMORY_SEGMENT_GROUP_LOCAL, 0, 0, 0, 0};
MemorySegmentInfo nonLocal = {DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, 0, 0, 0, 0};
};
ResultOrError<Heap*> RemoveSingleEntryFromLRU(); ResultOrError<Heap*> RemoveSingleEntryFromLRU();
bool ShouldTrackHeap(Heap* heap) const; bool ShouldTrackHeap(Heap* heap) const;
void UpdateVideoMemoryInfo(); void UpdateVideoMemoryInfo();
void UpdateMemorySegmentInfo(MemorySegmentInfo* segmentInfo);
Device* mDevice; Device* mDevice;
LinkedList<Heap> mLRUCache; LinkedList<Heap> mLRUCache;

View File

@ -30,6 +30,15 @@ namespace dawn_native { namespace d3d12 {
DAWN_NATIVE_EXPORT WGPUTextureFormat DAWN_NATIVE_EXPORT WGPUTextureFormat
GetNativeSwapChainPreferredFormat(const DawnSwapChainImplementation* swapChain); GetNativeSwapChainPreferredFormat(const DawnSwapChainImplementation* swapChain);
enum MemorySegment {
Local,
NonLocal,
};
DAWN_NATIVE_EXPORT uint64_t SetExternalMemoryReservation(WGPUDevice device,
uint64_t requestedReservationSize,
MemorySegment memorySegment);
struct DAWN_NATIVE_EXPORT ExternalImageDescriptorDXGISharedHandle : ExternalImageDescriptor { struct DAWN_NATIVE_EXPORT ExternalImageDescriptorDXGISharedHandle : ExternalImageDescriptor {
public: public:
ExternalImageDescriptorDXGISharedHandle(); ExternalImageDescriptorDXGISharedHandle();
@ -39,9 +48,6 @@ namespace dawn_native { namespace d3d12 {
bool isSwapChainTexture = false; bool isSwapChainTexture = false;
}; };
DAWN_NATIVE_EXPORT uint64_t SetExternalMemoryReservation(WGPUDevice device,
uint64_t requestedReservationSize);
// Note: SharedHandle must be a handle to a texture object. // Note: SharedHandle must be a handle to a texture object.
DAWN_NATIVE_EXPORT WGPUTexture DAWN_NATIVE_EXPORT WGPUTexture
WrapSharedHandle(WGPUDevice device, const ExternalImageDescriptorDXGISharedHandle* descriptor); WrapSharedHandle(WGPUDevice device, const ExternalImageDescriptorDXGISharedHandle* descriptor);

View File

@ -12,11 +12,10 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "dawn_native/ResourceMemoryAllocation.h" #include "dawn_native/D3D12Backend.h"
#include "dawn_native/d3d12/BufferD3D12.h" #include "dawn_native/d3d12/BufferD3D12.h"
#include "dawn_native/d3d12/DeviceD3D12.h" #include "dawn_native/d3d12/DeviceD3D12.h"
#include "dawn_native/d3d12/ResidencyManagerD3D12.h" #include "dawn_native/d3d12/ResidencyManagerD3D12.h"
#include "dawn_native/d3d12/ResourceHeapAllocationD3D12.h"
#include "tests/DawnTest.h" #include "tests/DawnTest.h"
#include "utils/WGPUHelpers.h" #include "utils/WGPUHelpers.h"
@ -301,4 +300,19 @@ TEST_P(D3D12ResidencyTests, OvercommitInASingleSubmit) {
} }
} }
TEST_P(D3D12ResidencyTests, SetExternalReservation) {
// Set an external reservation of 20% the budget. We should succesfully reserve the amount we
// request.
uint64_t amountReserved = dawn_native::d3d12::SetExternalMemoryReservation(
device.Get(), kRestrictedBudgetSize * .2, dawn_native::d3d12::MemorySegment::Local);
EXPECT_EQ(amountReserved, kRestrictedBudgetSize * .2);
// If we're on a non-UMA device, we should also check the NON_LOCAL memory segment.
if (!IsUMA()) {
amountReserved = dawn_native::d3d12::SetExternalMemoryReservation(
device.Get(), kRestrictedBudgetSize * .2, dawn_native::d3d12::MemorySegment::NonLocal);
EXPECT_EQ(amountReserved, kRestrictedBudgetSize * .2);
}
}
DAWN_INSTANTIATE_TEST(D3D12ResidencyTests, D3D12Backend()); DAWN_INSTANTIATE_TEST(D3D12ResidencyTests, D3D12Backend());