Retry Wddm mapGPUVA after failure when deferred deleter is set

mapGPUVA will fail when allocation is still in deferred deleter and using
the same base pointer to map, while there is no reserveGPUVA for SVM range.
In that case driver should drain deleter and retry mapGPUVA call

Change-Id: I4ded7d79e0cd935ec62d7fae785d66570c847535
This commit is contained in:
Zdanowicz, Zbigniew 2018-02-06 22:43:38 +01:00 committed by sys_ocldev
parent ea021f8d69
commit a1db4ddd7a
10 changed files with 159 additions and 45 deletions

View File

@ -442,23 +442,15 @@ NTSTATUS Wddm::createAllocation(WddmAllocation *alloc) {
CreateAllocation.pAllocationInfo = &AllocationInfo;
CreateAllocation.hDevice = device;
while (status != STATUS_SUCCESS) {
status = gdi->createAllocation(&CreateAllocation);
if (status != STATUS_SUCCESS) {
DEBUG_BREAK_IF(true);
break;
}
alloc->handle = AllocationInfo.hAllocation;
status = mapGpuVirtualAddress(alloc, alloc->getAlignedCpuPtr(), size, alloc->is32BitAllocation, false) == true ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
if (status != STATUS_SUCCESS) {
DEBUG_BREAK_IF(true);
break;
}
kmDafListener->notifyWriteTarget(featureTable->ftrKmdDaf, adapter, device, alloc->handle, gdi->escape);
status = gdi->createAllocation(&CreateAllocation);
if (status != STATUS_SUCCESS) {
DEBUG_BREAK_IF(true);
return status;
}
alloc->handle = AllocationInfo.hAllocation;
kmDafListener->notifyWriteTarget(featureTable->ftrKmdDaf, adapter, device, alloc->handle, gdi->escape);
return status;
}
@ -481,7 +473,6 @@ bool Wddm::createAllocation64k(WddmAllocation *alloc) {
CreateAllocation.hDevice = device;
while (!success) {
status = gdi->createAllocation(&CreateAllocation);
if (status != STATUS_SUCCESS) {
@ -538,7 +529,6 @@ bool Wddm::createAllocationsAndMapGpuVa(OsHandleStorage &osHandles) {
CreateAllocation.hDevice = device;
while (!success) {
status = gdi->createAllocation(&CreateAllocation);
if (status != STATUS_SUCCESS) {

View File

@ -59,7 +59,6 @@ WddmMemoryManager::WddmMemoryManager(bool enable64kbPages, Wddm *wddm) : MemoryM
}
void APIENTRY WddmMemoryManager::trimCallback(_Inout_ D3DKMT_TRIMNOTIFICATION *trimNotification) {
WddmMemoryManager *wddmMemMngr = (WddmMemoryManager *)trimNotification->Context;
DEBUG_BREAK_IF(wddmMemMngr == nullptr);
@ -73,17 +72,13 @@ GraphicsAllocation *WddmMemoryManager::allocateGraphicsMemoryForImage(ImageInfo
}
WddmAllocation allocation(nullptr, imgInfo.size, nullptr);
allocation.gmm = gmm;
auto status = wddm->createAllocation(&allocation);
if (status == STATUS_GRAPHICS_NO_VIDEO_MEMORY && deferredDeleter) {
deferredDeleter->drain(true);
status = wddm->createAllocation(&allocation);
}
allocation.setGpuAddress(allocation.gpuPtr);
if (status == STATUS_SUCCESS) {
auto status = WddmMemoryManager::createWddmAllocation(&allocation);
if (status) {
auto *wddmAllocation = new WddmAllocation(allocation);
return wddmAllocation;
} else {
return nullptr;
}
return nullptr;
}
GraphicsAllocation *WddmMemoryManager::allocateGraphicsMemory64kb(size_t size, size_t alignment, bool forcePin) {
@ -108,7 +103,8 @@ GraphicsAllocation *WddmMemoryManager::allocateGraphicsMemory64kb(size_t size, s
wddmAllocation->setAlignedCpuPtr(cpuPtr);
// 64kb map is not needed
wddm->mapGpuVirtualAddress(wddmAllocation, cpuPtr, sizeAligned, false, false);
auto status = wddm->mapGpuVirtualAddress(wddmAllocation, cpuPtr, sizeAligned, false, false);
DEBUG_BREAK_IF(!status);
wddmAllocation->setCpuPtrAndGpuAddress(cpuPtr, (uint64_t)wddmAllocation->gpuPtr);
return wddmAllocation;
@ -136,8 +132,8 @@ GraphicsAllocation *WddmMemoryManager::allocateGraphicsMemory(size_t size, size_
while (success) {
allocation.gmm = gmm;
success = wddm->createAllocation(&allocation) == STATUS_SUCCESS;
bool success = createWddmAllocation(&allocation);
if (!success)
break;
@ -173,8 +169,7 @@ GraphicsAllocation *WddmMemoryManager::allocateGraphicsMemory(size_t size, const
Gmm *gmm = Gmm::create(ptrAligned, sizeAligned, false);
allocation->gmm = gmm;
if (wddm->createAllocation(allocation) == STATUS_SUCCESS) {
allocation->setGpuAddress(allocation->gpuPtr);
if (createWddmAllocation(allocation)) {
return allocation;
}
freeGraphicsMemory(allocation);
@ -208,24 +203,21 @@ GraphicsAllocation *WddmMemoryManager::allocate32BitGraphicsMemory(size_t size,
cpuPtrAllocated = true;
}
WddmAllocation allocation((void *)ptrAligned, sizeAligned, (void *)ptrAligned, sizeAligned, nullptr);
WddmAllocation allocation(const_cast<void *>(ptrAligned), sizeAligned, const_cast<void *>(ptrAligned), sizeAligned, nullptr);
allocation.cpuPtrAllocated = cpuPtrAllocated;
allocation.is32BitAllocation = true;
allocation.allocationOffset = offset;
gmm = Gmm::create(ptrAligned, sizeAligned, false);
while (success) {
allocation.gmm = gmm;
success = wddm->createAllocation(&allocation) == STATUS_SUCCESS;
success = createWddmAllocation(&allocation);
if (!success)
break;
allocation.setGpuAddress(allocation.gpuPtr);
allocation.allocationOffset = offset;
auto *wddmAllocation = new WddmAllocation(allocation);
graphicsAllocation = wddmAllocation;
graphicsAllocation->is32BitAllocation = true;
graphicsAllocation->gpuBaseAddress = Gmm::canonize(allocator32Bit->getBase());
@ -265,8 +257,8 @@ GraphicsAllocation *WddmMemoryManager::createAllocationFromHandle(osHandle handl
allocation.is32BitAllocation = true;
allocation.gpuBaseAddress = Gmm::canonize(allocator32Bit->getBase());
}
wddm->mapGpuVirtualAddress(&allocation, ptr, size, is32BitAllocation, false);
auto status = wddm->mapGpuVirtualAddress(&allocation, ptr, size, is32BitAllocation, false);
DEBUG_BREAK_IF(!status);
allocation.setGpuAddress(allocation.gpuPtr);
return new WddmAllocation(allocation);
@ -776,4 +768,25 @@ AlignedMallocRestrictions *WddmMemoryManager::getAlignedMallocRestrictions() {
return &mallocRestrictions;
}
bool WddmMemoryManager::createWddmAllocation(WddmAllocation *allocation) {
auto wddmSuccess = wddm->createAllocation(allocation);
if (wddmSuccess == STATUS_GRAPHICS_NO_VIDEO_MEMORY && deferredDeleter) {
deferredDeleter->drain(true);
wddmSuccess = wddm->createAllocation(allocation);
}
if (wddmSuccess == STATUS_SUCCESS) {
bool mapSuccess = wddm->mapGpuVirtualAddress(allocation, allocation->getAlignedCpuPtr(), allocation->getAlignedSize(), allocation->is32BitAllocation, false);
if (!mapSuccess && deferredDeleter) {
deferredDeleter->drain(true);
mapSuccess = wddm->mapGpuVirtualAddress(allocation, allocation->getAlignedCpuPtr(), allocation->getAlignedSize(), allocation->is32BitAllocation, false);
}
if (!mapSuccess) {
wddm->destroyAllocations(&allocation->handle, 1, 0, allocation->resourceHandle);
wddmSuccess = STATUS_UNSUCCESSFUL;
}
allocation->setGpuAddress(allocation->gpuPtr);
}
return (wddmSuccess == STATUS_SUCCESS);
}
} // namespace OCLRT

View File

@ -109,6 +109,7 @@ class WddmMemoryManager : public MemoryManager {
static bool validateAllocation(WddmAllocation *alloc);
bool checkTrimCandidateListCompaction();
void checkTrimCandidateCount();
bool createWddmAllocation(WddmAllocation *allocation);
ResidencyContainer trimCandidateList;
std::mutex trimCandidateListMutex;
std::atomic<bool> residencyLock;

View File

@ -72,3 +72,4 @@ SetMockCreateDeviceParams
getMockAllocation
getAdapterInfoAddress
getLastCallMapGpuVaArg
setMapGpuVaFailConfig

View File

@ -32,6 +32,8 @@
ADAPTER_INFO gAdapterInfo = {0};
D3DDDI_MAPGPUVIRTUALADDRESS gLastCallMapGpuVaArg = {0};
uint32_t gMapGpuVaFailConfigCount = 0;
uint32_t gMapGpuVaFailConfigMax = 0;
#ifdef __cplusplus // If used by C++ code,
extern "C" { // we need to export the C interface
@ -255,6 +257,13 @@ NTSTATUS __stdcall D3DKMTMapGpuVirtualAddress(IN OUT D3DDDI_MAPGPUVIRTUALADDRESS
mapGpuVA->VirtualAddress = mapGpuVA->BaseAddress;
}
if (gMapGpuVaFailConfigMax != 0) {
if (gMapGpuVaFailConfigMax > gMapGpuVaFailConfigCount) {
gMapGpuVaFailConfigCount++;
return STATUS_UNSUCCESSFUL;
}
}
mapGpuVA->PagingFenceValue = 1;
return STATUS_PENDING;
}
@ -421,3 +430,8 @@ ADAPTER_INFO *getAdapterInfoAddress() {
D3DDDI_MAPGPUVIRTUALADDRESS *getLastCallMapGpuVaArg() {
return &gLastCallMapGpuVaArg;
}
void setMapGpuVaFailConfig(uint32_t count, uint32_t max) {
gMapGpuVaFailConfigCount = count;
gMapGpuVaFailConfigMax = max;
}

View File

@ -81,3 +81,4 @@ void SetMockCreateDeviceParams(D3DKMT_CREATEDEVICE params);
D3DKMT_CREATEALLOCATION *getMockAllocation();
ADAPTER_INFO *getAdapterInfoAddress();
D3DDDI_MAPGPUVIRTUALADDRESS *getLastCallMapGpuVaArg();
void setMapGpuVaFailConfig(uint32_t count, uint32_t max);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Intel Corporation
* Copyright (c) 2017 - 2018, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -32,6 +32,7 @@ class MockWddmMemoryManager : public WddmMemoryManager {
using BaseClass::addToTrimCandidateList;
using BaseClass::checkTrimCandidateListCompaction;
using BaseClass::compactTrimCandidateList;
using BaseClass::createWddmAllocation;
using BaseClass::lastPeriodicTrimFenceValue;
using BaseClass::removeFromTrimCandidateList;
using BaseClass::trimCandidateList;

View File

@ -66,6 +66,7 @@ class WddmMock : public Wddm {
using Wddm::device;
using Wddm::gdi;
using Wddm::getSystemInfo;
using Wddm::pagingQueue;
WddmMock() : makeResidentResult(),
makeNonResidentResult(),
@ -126,7 +127,12 @@ class WddmMock : public Wddm {
bool mapGpuVirtualAddressImpl(Gmm *gmm, D3DKMT_HANDLE handle, void *cpuPtr, uint64_t size, D3DGPU_VIRTUAL_ADDRESS &gpuPtr, bool allocation32Bit, bool use64kbPages) override {
mapGpuVirtualAddressResult.called++;
mapGpuVirtualAddressResult.cpuPtrPassed = cpuPtr;
return mapGpuVirtualAddressResult.success = Wddm::mapGpuVirtualAddressImpl(gmm, handle, cpuPtr, size, gpuPtr, allocation32Bit, use64kbPages);
if (callBaseMapGpuVa) {
return mapGpuVirtualAddressResult.success = Wddm::mapGpuVirtualAddressImpl(gmm, handle, cpuPtr, size, gpuPtr, allocation32Bit, use64kbPages);
} else {
gpuPtr = reinterpret_cast<D3DGPU_VIRTUAL_ADDRESS>(cpuPtr);
return mapGpuVaStatus;
}
}
bool freeGpuVirtualAddres(D3DGPU_VIRTUAL_ADDRESS &gpuPtr, uint64_t size) override {
freeGpuVirtualAddresResult.called++;
@ -135,12 +141,14 @@ class WddmMock : public Wddm {
NTSTATUS createAllocation(WddmAllocation *alloc) override {
createAllocationResult.called++;
if (callBaseDestroyAllocations) {
createAllocationResult.success = Wddm::createAllocation(alloc) == STATUS_SUCCESS;
createAllocationStatus = Wddm::createAllocation(alloc);
createAllocationResult.success = createAllocationStatus == STATUS_SUCCESS;
} else {
createAllocationResult.success = true;
alloc->handle = ALLOCATION_HANDLE;
return createAllocationStatus;
}
return STATUS_SUCCESS;
return createAllocationStatus;
}
bool createAllocation64k(WddmAllocation *alloc) override {
createAllocationResult.called++;
@ -310,8 +318,10 @@ class WddmMock : public Wddm {
CallResult releaseReservedAddressResult;
CallResult reserveValidAddressRangeResult;
NTSTATUS createAllocationStatus;
bool mapGpuVaStatus;
bool callBaseDestroyAllocations = true;
bool failOpenSharedHandle = false;
bool callBaseMapGpuVa = true;
std::set<void *> reservedAddresses;
uintptr_t virtualAllocAddress;
};
@ -377,6 +387,7 @@ class WddmFixture {
decltype(&getMockAllocation) getMockAllocationFcn;
decltype(&getAdapterInfoAddress) getAdapterInfoAddressFcn;
decltype(&getLastCallMapGpuVaArg) getLastCallMapGpuVaArgFcn;
decltype(&setMapGpuVaFailConfig) setMapGpuVaFailConfigFcn = nullptr;
public:
virtual void SetUp() {
@ -396,6 +407,8 @@ class WddmFixture {
getMockAllocationFcn = reinterpret_cast<decltype(&getMockAllocation)>(mockGdiDll->getProcAddress("getMockAllocation"));
getAdapterInfoAddressFcn = reinterpret_cast<decltype(&getAdapterInfoAddress)>(mockGdiDll->getProcAddress("getAdapterInfoAddress"));
getLastCallMapGpuVaArgFcn = reinterpret_cast<decltype(&getLastCallMapGpuVaArg)>(mockGdiDll->getProcAddress("getLastCallMapGpuVaArg"));
setMapGpuVaFailConfigFcn = reinterpret_cast<decltype(&setMapGpuVaFailConfig)>(mockGdiDll->getProcAddress("setMapGpuVaFailConfig"));
setMapGpuVaFailConfigFcn(0, 0);
wddm = Wddm::createWddm();
mockWddm = static_cast<WddmMock *>(wddm);
wddm->registryReader.reset(new RegistryReaderMock());
@ -415,6 +428,9 @@ class WddmFixture {
delete wddm;
}
if (mockGdiDll != nullptr) {
if (setMapGpuVaFailConfigFcn != nullptr) {
setMapGpuVaFailConfigFcn(0, 0);
}
delete mockGdiDll;
}
}

View File

@ -571,6 +571,69 @@ HWTEST_F(WddmMemoryManagerTest, givenWddmMemoryManagerWhenCpuMemNotMeetRestricti
mm->freeGraphicsMemory(allocation);
}
HWTEST_F(WddmMemoryManagerTest, givenManagerWithDisabledDeferredDeleterWhenMapGpuVaFailThenFailToCreateAllocation) {
SetUpMm<FamilyType>();
void *ptr = reinterpret_cast<void *>(0x1000);
size_t size = 0x1000;
std::unique_ptr<Gmm> gmm(Gmm::create(ptr, size, false));
WddmMock *mockedWddm = new WddmMock;
EXPECT_TRUE(mockedWddm->init<FamilyType>());
MockWddmMemoryManager mockMemoryManager(mockedWddm);
mockMemoryManager.setDeferredDeleter(nullptr);
setMapGpuVaFailConfigFcn(0, 1);
WddmAllocation allocation(ptr, size, nullptr);
allocation.gmm = gmm.get();
bool ret = mockMemoryManager.createWddmAllocation(&allocation);
EXPECT_FALSE(ret);
}
HWTEST_F(WddmMemoryManagerTest, givenManagerWithEnabledDeferredDeleterWhenFirstMapGpuVaFailSecondAfterDrainSuccessThenCreateAllocation) {
SetUpMm<FamilyType>();
void *ptr = reinterpret_cast<void *>(0x1000);
size_t size = 0x1000;
std::unique_ptr<Gmm> gmm(Gmm::create(ptr, size, false));
WddmMock *mockedWddm = new WddmMock;
EXPECT_TRUE(mockedWddm->init<FamilyType>());
MockDeferredDeleter *deleter = new MockDeferredDeleter;
MockWddmMemoryManager mockMemoryManager(mockedWddm);
mockMemoryManager.setDeferredDeleter(deleter);
setMapGpuVaFailConfigFcn(0, 1);
WddmAllocation allocation(ptr, size, nullptr);
allocation.gmm = gmm.get();
bool ret = mockMemoryManager.createWddmAllocation(&allocation);
EXPECT_TRUE(ret);
EXPECT_EQ(reinterpret_cast<uint64_t>(ptr), allocation.getGpuAddress());
}
HWTEST_F(WddmMemoryManagerTest, givenManagerWithEnabledDeferredDeleterWhenFirstAndMapGpuVaFailSecondAfterDrainFailThenFailToCreateAllocation) {
SetUpMm<FamilyType>();
void *ptr = reinterpret_cast<void *>(0x1000);
size_t size = 0x1000;
std::unique_ptr<Gmm> gmm(Gmm::create(ptr, size, false));
WddmMock *mockedWddm = new WddmMock;
EXPECT_TRUE(mockedWddm->init<FamilyType>());
MockDeferredDeleter *deleter = new MockDeferredDeleter;
MockWddmMemoryManager mockMemoryManager(mockedWddm);
mockMemoryManager.setDeferredDeleter(deleter);
setMapGpuVaFailConfigFcn(0, 2);
WddmAllocation allocation(ptr, size, nullptr);
allocation.gmm = gmm.get();
bool ret = mockMemoryManager.createWddmAllocation(&allocation);
EXPECT_FALSE(ret);
}
HWTEST_F(WddmMemoryManagerResidencyTest, addToTrimCandidateListPlacesAllocationInContainerAndAssignsPosition) {
SetUpMm<FamilyType>();
WddmAllocation allocation;
@ -1599,11 +1662,15 @@ TEST(WddmMemoryManagerWithAsyncDeleterTest, givenMemoryManagerWithAsyncDeleterWh
ImageInfo imgInfo;
imgInfo.imgDesc = &imgDesc;
wddm->createAllocationStatus = STATUS_SUCCESS;
wddm->mapGpuVaStatus = true;
wddm->callBaseMapGpuVa = false;
EXPECT_EQ(0, deleter->drainCalled);
EXPECT_EQ(0u, wddm->createAllocationResult.called);
EXPECT_EQ(0u, wddm->mapGpuVirtualAddressResult.called);
auto allocation = memoryManager.allocateGraphicsMemoryForImage(imgInfo, nullptr);
EXPECT_EQ(0, deleter->drainCalled);
EXPECT_EQ(1u, wddm->createAllocationResult.called);
EXPECT_EQ(1u, wddm->mapGpuVirtualAddressResult.called);
memoryManager.freeGraphicsMemory(allocation);
}

View File

@ -151,10 +151,13 @@ HWTEST_F(WddmTest, givenAllocationSmallerUnderlyingThanAlignedSizeWhenCreatedThe
EXPECT_EQ(STATUS_SUCCESS, status);
EXPECT_NE(0, allocation.handle);
bool ret = wddm->mapGpuVirtualAddress(&allocation, allocation.getAlignedCpuPtr(), allocation.getAlignedSize(), allocation.is32BitAllocation, false);
EXPECT_TRUE(ret);
EXPECT_EQ(alignedPages, getLastCallMapGpuVaArgFcn()->SizeInPages);
EXPECT_NE(underlyingPages, getLastCallMapGpuVaArgFcn()->SizeInPages);
auto ret = mockWddm->destroyAllocation(&allocation);
ret = mockWddm->destroyAllocation(&allocation);
EXPECT_TRUE(ret);
releaseGmm(gmm);
@ -187,6 +190,9 @@ HWTEST_F(WddmTest, createAllocation32bit) {
EXPECT_EQ(STATUS_SUCCESS, status);
EXPECT_TRUE(allocation.handle != 0);
bool ret = wddm->mapGpuVirtualAddress(&allocation, allocation.getAlignedCpuPtr(), allocation.getAlignedSize(), allocation.is32BitAllocation, false);
EXPECT_TRUE(ret);
EXPECT_EQ(1u, wddmMock->mapGpuVirtualAddressResult.called);
EXPECT_LE(heap32baseAddress, allocation.gpuPtr);
@ -276,8 +282,12 @@ HWTEST_F(WddmTest, givenNullAllocationWhenCreateThenAllocateAndMap) {
allocation.gmm = gmm;
auto status = wddm->createAllocation(&allocation);
EXPECT_EQ(STATUS_SUCCESS, status);
EXPECT_TRUE(allocation.gpuPtr != 0);
EXPECT_TRUE(allocation.gpuPtr == Gmm::canonize(allocation.gpuPtr));
bool ret = wddm->mapGpuVirtualAddress(&allocation, allocation.getAlignedCpuPtr(), allocation.getAlignedSize(), allocation.is32BitAllocation, false);
EXPECT_TRUE(ret);
EXPECT_NE(0u, allocation.gpuPtr);
EXPECT_EQ(allocation.gpuPtr, Gmm::canonize(allocation.gpuPtr));
releaseGmm(gmm);
mm.freeSystemMemory(allocation.getUnderlyingBuffer());