From f12b5861fd17e2eabb13e129f56607a41a4837a1 Mon Sep 17 00:00:00 2001 From: Mateusz Jablonski Date: Mon, 8 Jan 2018 16:31:29 +0100 Subject: [PATCH] Drain deferred deletions when cannot allocate memory for tiled image Change-Id: I68b15269da4b5a58e02571a9c594c52b9a95edeb --- runtime/os_interface/windows/wddm.cpp | 15 ++--- runtime/os_interface/windows/wddm.h | 2 +- .../windows/wddm_memory_manager.cpp | 19 +++++-- .../os_interface/windows/wddm_fixture.h | 15 ++++- .../windows/wddm_memory_manager_tests.cpp | 56 +++++++++++++++++++ .../os_interface/windows/wddm_tests.cpp | 27 ++++----- 6 files changed, 103 insertions(+), 31 deletions(-) diff --git a/runtime/os_interface/windows/wddm.cpp b/runtime/os_interface/windows/wddm.cpp index df347c9138..a3d475d628 100644 --- a/runtime/os_interface/windows/wddm.cpp +++ b/runtime/os_interface/windows/wddm.cpp @@ -515,11 +515,10 @@ bool Wddm::freeGpuVirtualAddres(D3DGPU_VIRTUAL_ADDRESS &gpuPtr, uint64_t size) { return status == STATUS_SUCCESS; } -bool Wddm::createAllocation(WddmAllocation *alloc) { - NTSTATUS status = STATUS_SUCCESS; +NTSTATUS Wddm::createAllocation(WddmAllocation *alloc) { + NTSTATUS status = STATUS_UNSUCCESSFUL; D3DDDI_ALLOCATIONINFO AllocationInfo = {0}; D3DKMT_CREATEALLOCATION CreateAllocation = {0}; - bool success = false; size_t size; if (alloc == nullptr) @@ -547,7 +546,7 @@ bool Wddm::createAllocation(WddmAllocation *alloc) { CreateAllocation.pAllocationInfo = &AllocationInfo; CreateAllocation.hDevice = device; - while (!success) { + while (status != STATUS_SUCCESS) { status = gdi->createAllocation(&CreateAllocation); @@ -557,16 +556,14 @@ bool Wddm::createAllocation(WddmAllocation *alloc) { } alloc->handle = AllocationInfo.hAllocation; - success = mapGpuVirtualAddress(alloc, alloc->getAlignedCpuPtr(), size, alloc->is32BitAllocation, false); + status = mapGpuVirtualAddress(alloc, alloc->getAlignedCpuPtr(), size, alloc->is32BitAllocation, false) == true ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; - if (!success) { + if (status != STATUS_SUCCESS) { DEBUG_BREAK_IF(true); break; } - - success = true; } - return success; + return status; } bool Wddm::createAllocation64k(WddmAllocation *alloc) { diff --git a/runtime/os_interface/windows/wddm.h b/runtime/os_interface/windows/wddm.h index 34526dac95..e71a2714c5 100644 --- a/runtime/os_interface/windows/wddm.h +++ b/runtime/os_interface/windows/wddm.h @@ -79,7 +79,7 @@ class Wddm { bool mapGpuVirtualAddress(AllocationStorageData *allocationStorageData, bool allocation32bit, bool use64kbPages); MOCKABLE_VIRTUAL D3DKMT_HANDLE createContext(); MOCKABLE_VIRTUAL bool freeGpuVirtualAddres(D3DGPU_VIRTUAL_ADDRESS &gpuPtr, uint64_t size); - MOCKABLE_VIRTUAL bool createAllocation(WddmAllocation *alloc); + MOCKABLE_VIRTUAL NTSTATUS createAllocation(WddmAllocation *alloc); MOCKABLE_VIRTUAL bool createAllocation64k(WddmAllocation *alloc); bool createAllocationsAndMapGpuVa(OsHandleStorage &osHandles); MOCKABLE_VIRTUAL bool destroyAllocations(D3DKMT_HANDLE *handles, uint32_t allocationCount, uint64_t lastFenceValue, D3DKMT_HANDLE resourceHandle); diff --git a/runtime/os_interface/windows/wddm_memory_manager.cpp b/runtime/os_interface/windows/wddm_memory_manager.cpp index 330e883124..c289da3307 100644 --- a/runtime/os_interface/windows/wddm_memory_manager.cpp +++ b/runtime/os_interface/windows/wddm_memory_manager.cpp @@ -31,6 +31,11 @@ #include "runtime/os_interface/windows/wddm_allocation.h" #include "runtime/os_interface/windows/wddm.h" #include +#pragma warning(push) +#pragma warning(disable : 4005) +#include +#pragma warning(pop) + #undef max namespace OCLRT { @@ -63,13 +68,15 @@ GraphicsAllocation *WddmMemoryManager::allocateGraphicsMemoryForImage(ImageInfo delete gmm; return allocateGraphicsMemory(imgInfo.size, MemoryConstants::preferredAlignment); } - WddmAllocation allocation(nullptr, imgInfo.size); allocation.gmm = gmm; - bool success = wddm->createAllocation(&allocation); + 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 (success) { + if (status == STATUS_SUCCESS) { auto *wddmAllocation = new WddmAllocation(allocation); return wddmAllocation; } @@ -126,7 +133,7 @@ GraphicsAllocation *WddmMemoryManager::allocateGraphicsMemory(size_t size, size_ while (success) { allocation.gmm = gmm; - success = wddm->createAllocation(&allocation); + success = wddm->createAllocation(&allocation) == STATUS_SUCCESS; if (!success) break; @@ -182,7 +189,7 @@ GraphicsAllocation *WddmMemoryManager::allocate32BitGraphicsMemory(size_t size, while (success) { allocation.gmm = gmm; - success = wddm->createAllocation(&allocation); + success = wddm->createAllocation(&allocation) == STATUS_SUCCESS; if (!success) break; diff --git a/unit_tests/os_interface/windows/wddm_fixture.h b/unit_tests/os_interface/windows/wddm_fixture.h index 3f0152a98b..8558325177 100644 --- a/unit_tests/os_interface/windows/wddm_fixture.h +++ b/unit_tests/os_interface/windows/wddm_fixture.h @@ -34,6 +34,10 @@ #include "unit_tests/mock_gdi/mock_gdi.h" #include "unit_tests/mocks/mock_gmm_memory.h" #include "unit_tests//os_interface/windows/mock_gdi_interface.h" +#pragma warning(push) +#pragma warning(disable : 4005) +#include +#pragma warning(pop) using namespace OCLRT; @@ -103,9 +107,15 @@ class WddmMock : public Wddm { freeGpuVirtualAddresResult.called++; return freeGpuVirtualAddresResult.success = Wddm::freeGpuVirtualAddres(gpuPtr, size); } - bool createAllocation(WddmAllocation *alloc) override { + NTSTATUS createAllocation(WddmAllocation *alloc) override { createAllocationResult.called++; - return createAllocationResult.success = Wddm::createAllocation(alloc); + if (callBaseDestroyAllocations) { + createAllocationResult.success = Wddm::createAllocation(alloc) == STATUS_SUCCESS; + } else { + createAllocationResult.success = true; + return createAllocationStatus; + } + return STATUS_SUCCESS; } bool createAllocation64k(WddmAllocation *alloc) override { createAllocationResult.called++; @@ -246,6 +256,7 @@ class WddmMock : public Wddm { CallResult unlockResult; CallResult waitFromCpuResult; CallResult releaseGpuPtrResult; + NTSTATUS createAllocationStatus; bool callBaseDestroyAllocations = true; bool failOpenSharedHandle = false; }; diff --git a/unit_tests/os_interface/windows/wddm_memory_manager_tests.cpp b/unit_tests/os_interface/windows/wddm_memory_manager_tests.cpp index 439a0221c8..21476b3ad0 100644 --- a/unit_tests/os_interface/windows/wddm_memory_manager_tests.cpp +++ b/unit_tests/os_interface/windows/wddm_memory_manager_tests.cpp @@ -1475,6 +1475,62 @@ TEST(WddmMemoryManagerWithAsyncDeleterTest, givenWddmWhenAsyncDeleterIsDisabledT EXPECT_EQ(1u, wddm->releaseGpuPtrResult.called); } +TEST(WddmMemoryManagerWithAsyncDeleterTest, givenMemoryManagerWithAsyncDeleterWhenCannotAllocateMemoryForTiledImageThenDrainIsCalledAndCreateAllocationIsCalledTwice) { + WddmMock *wddm = new WddmMock; + wddm->callBaseDestroyAllocations = false; + MockDeferredDeleter *deleter = new MockDeferredDeleter; + MockWddmMemoryManager memoryManager(wddm); + memoryManager.setDeferredDeleter(deleter); + + cl_image_desc imgDesc; + imgDesc.image_type = CL_MEM_OBJECT_IMAGE3D; + ImageInfo imgInfo; + imgInfo.imgDesc = &imgDesc; + wddm->createAllocationStatus = STATUS_GRAPHICS_NO_VIDEO_MEMORY; + EXPECT_EQ(0, deleter->drainCalled); + EXPECT_EQ(0u, wddm->createAllocationResult.called); + deleter->expectDrainBlockingValue(true); + memoryManager.allocateGraphicsMemoryForImage(imgInfo, nullptr); + EXPECT_EQ(1, deleter->drainCalled); + EXPECT_EQ(2u, wddm->createAllocationResult.called); +} + +TEST(WddmMemoryManagerWithAsyncDeleterTest, givenMemoryManagerWithAsyncDeleterWhenCanAllocateMemoryForTiledImageThenDrainIsNotCalledAndCreateAllocationIsCalledOnce) { + WddmMock *wddm = new WddmMock; + wddm->callBaseDestroyAllocations = false; + MockDeferredDeleter *deleter = new MockDeferredDeleter; + MockWddmMemoryManager memoryManager(wddm); + memoryManager.setDeferredDeleter(deleter); + + cl_image_desc imgDesc; + imgDesc.image_type = CL_MEM_OBJECT_IMAGE3D; + ImageInfo imgInfo; + imgInfo.imgDesc = &imgDesc; + wddm->createAllocationStatus = STATUS_SUCCESS; + EXPECT_EQ(0, deleter->drainCalled); + EXPECT_EQ(0u, wddm->createAllocationResult.called); + auto allocation = memoryManager.allocateGraphicsMemoryForImage(imgInfo, nullptr); + EXPECT_EQ(0, deleter->drainCalled); + EXPECT_EQ(1u, wddm->createAllocationResult.called); + memoryManager.freeGraphicsMemory(allocation); +} + +TEST(WddmMemoryManagerWithAsyncDeleterTest, givenMemoryManagerWithoutAsyncDeleterWhenCannotAllocateMemoryForTiledImageThenCreateAllocationIsCalledOnce) { + WddmMock *wddm = new WddmMock; + wddm->callBaseDestroyAllocations = false; + MockWddmMemoryManager memoryManager(wddm); + memoryManager.setDeferredDeleter(nullptr); + + cl_image_desc imgDesc; + imgDesc.image_type = CL_MEM_OBJECT_IMAGE3D; + ImageInfo imgInfo; + imgInfo.imgDesc = &imgDesc; + wddm->createAllocationStatus = STATUS_GRAPHICS_NO_VIDEO_MEMORY; + EXPECT_EQ(0u, wddm->createAllocationResult.called); + memoryManager.allocateGraphicsMemoryForImage(imgInfo, nullptr); + EXPECT_EQ(1u, wddm->createAllocationResult.called); +} + HWTEST_F(MockWddmMemoryManagerTest, givenValidateAllocationFunctionWhenItIsCalledWithTripleAllocationThenSuccessIsReturned) { WddmMock *wddm = new WddmMock; EXPECT_TRUE(wddm->init()); diff --git a/unit_tests/os_interface/windows/wddm_tests.cpp b/unit_tests/os_interface/windows/wddm_tests.cpp index 70b5a4174d..d2740e7b0a 100644 --- a/unit_tests/os_interface/windows/wddm_tests.cpp +++ b/unit_tests/os_interface/windows/wddm_tests.cpp @@ -105,12 +105,12 @@ HWTEST_F(WddmTest, allocation) { ASSERT_NE(gmm, nullptr); allocation.gmm = gmm; - bool error = wddm->createAllocation(&allocation); + auto status = wddm->createAllocation(&allocation); - EXPECT_TRUE(error); + EXPECT_EQ(STATUS_SUCCESS, status); EXPECT_TRUE(allocation.handle != 0); - error = mockWddm->destroyAllocation(&allocation); + auto error = mockWddm->destroyAllocation(&allocation); EXPECT_TRUE(error); releaseGmm(gmm); @@ -139,9 +139,9 @@ HWTEST_F(WddmTest, createAllocation32bit) { allocation.gmm = gmm; allocation.is32BitAllocation = true; // mark 32 bit allocation - bool success = wddm->createAllocation(&allocation); + auto status = wddm->createAllocation(&allocation); - EXPECT_TRUE(success); + EXPECT_EQ(STATUS_SUCCESS, status); EXPECT_TRUE(allocation.handle != 0); EXPECT_EQ(1u, wddmMock->mapGpuVirtualAddressResult.called); @@ -149,7 +149,7 @@ HWTEST_F(WddmTest, createAllocation32bit) { EXPECT_LE(heap32baseAddress, allocation.gpuPtr); EXPECT_GT(heap32baseAddress + heap32Size, allocation.gpuPtr); - success = mockWddm->destroyAllocation(&allocation); + auto success = mockWddm->destroyAllocation(&allocation); EXPECT_TRUE(success); releaseGmm(gmm); @@ -200,12 +200,12 @@ HWTEST_F(WddmTest, mapAndFreeGpuVa) { ASSERT_NE(gmm, nullptr); allocation.gmm = gmm; - bool error = wddm->createAllocation(&allocation); + auto status = wddm->createAllocation(&allocation); - EXPECT_TRUE(error); + EXPECT_EQ(STATUS_SUCCESS, status); EXPECT_TRUE(allocation.handle != 0); - error = wddm->mapGpuVirtualAddress(&allocation, allocation.getAlignedCpuPtr(), allocation.getUnderlyingBufferSize(), false, false); + auto error = wddm->mapGpuVirtualAddress(&allocation, allocation.getAlignedCpuPtr(), allocation.getUnderlyingBufferSize(), false, false); EXPECT_TRUE(error); EXPECT_TRUE(allocation.gpuPtr != 0); @@ -231,7 +231,8 @@ HWTEST_F(WddmTest, givenNullAllocationWhenCreateThenAllocateAndMap) { ASSERT_NE(gmm, nullptr); allocation.gmm = gmm; - bool error = wddm->createAllocation(&allocation); + auto status = wddm->createAllocation(&allocation); + EXPECT_EQ(STATUS_SUCCESS, status); EXPECT_TRUE(allocation.gpuPtr != 0); EXPECT_TRUE(allocation.gpuPtr == Gmm::canonize(allocation.gpuPtr)); @@ -251,12 +252,12 @@ HWTEST_F(WddmTest, makeResidentNonResident) { ASSERT_NE(gmm, nullptr); allocation.gmm = gmm; - bool error = wddm->createAllocation(&allocation); + auto status = wddm->createAllocation(&allocation); - EXPECT_TRUE(error); + EXPECT_EQ(STATUS_SUCCESS, status); EXPECT_TRUE(allocation.handle != 0); - error = wddm->mapGpuVirtualAddress(&allocation, allocation.getAlignedCpuPtr(), allocation.getUnderlyingBufferSize(), false, false); + auto error = wddm->mapGpuVirtualAddress(&allocation, allocation.getAlignedCpuPtr(), allocation.getUnderlyingBufferSize(), false, false); EXPECT_TRUE(error); EXPECT_TRUE(allocation.gpuPtr != 0);