diff --git a/runtime/os_interface/windows/wddm/wddm.cpp b/runtime/os_interface/windows/wddm/wddm.cpp index 4585d7b539..46dfc040f7 100644 --- a/runtime/os_interface/windows/wddm/wddm.cpp +++ b/runtime/os_interface/windows/wddm/wddm.cpp @@ -637,6 +637,11 @@ bool Wddm::openNTHandle(HANDLE handle, WddmAllocation *alloc) { } void *Wddm::lockResource(WddmAllocation *wddmAllocation) { + + if (wddmAllocation->needsMakeResidentBeforeLock) { + applyBlockingMakeResident(wddmAllocation); + } + NTSTATUS status = STATUS_UNSUCCESSFUL; D3DKMT_LOCK2 lock2 = {}; @@ -947,4 +952,60 @@ bool Wddm::init(PreemptionMode preemptionMode) { } return initialized; } + +EvictionStatus Wddm::evictAllTemporaryResources() { + decltype(temporaryResources) resourcesToEvict; + auto &lock = acquireLock(temporaryResourcesLock); + temporaryResources.swap(resourcesToEvict); + if (resourcesToEvict.empty()) { + return EvictionStatus::NOT_APPLIED; + } + uint64_t sizeToTrim = 0; + bool error = false; + for (auto &handle : resourcesToEvict) { + if (!evict(&handle, 1, sizeToTrim)) { + error = true; + } + } + return error ? EvictionStatus::FAILED : EvictionStatus::SUCCESS; +} + +EvictionStatus Wddm::evictTemporaryResource(WddmAllocation *allocation) { + auto &lock = acquireLock(temporaryResourcesLock); + auto position = std::find(temporaryResources.begin(), temporaryResources.end(), allocation->handle); + if (position == temporaryResources.end()) { + return EvictionStatus::NOT_APPLIED; + } + *position = temporaryResources.back(); + temporaryResources.pop_back(); + uint64_t sizeToTrim = 0; + if (!evict(&allocation->handle, 1, sizeToTrim)) { + return EvictionStatus::FAILED; + } + return EvictionStatus::SUCCESS; +} +void Wddm::applyBlockingMakeResident(WddmAllocation *allocation) { + bool madeResident = false; + while (!(madeResident = makeResident(&allocation->handle, 1, false, nullptr))) { + if (evictAllTemporaryResources() == EvictionStatus::SUCCESS) { + continue; + } + if (!makeResident(&allocation->handle, 1, false, nullptr)) { + DEBUG_BREAK_IF(true); + return; + }; + break; + } + DEBUG_BREAK_IF(!madeResident); + auto &lock = acquireLock(temporaryResourcesLock); + temporaryResources.push_back(allocation->handle); + lock.unlock(); + while (currentPagingFenceValue > *getPagingFenceAddress()) + ; +} + +std::unique_lock Wddm::acquireLock(SpinLock &lock) { + return std::unique_lock{lock}; +} + } // namespace OCLRT diff --git a/runtime/os_interface/windows/wddm/wddm.h b/runtime/os_interface/windows/wddm/wddm.h index a00236b120..6eb5463d93 100644 --- a/runtime/os_interface/windows/wddm/wddm.h +++ b/runtime/os_interface/windows/wddm/wddm.h @@ -19,9 +19,11 @@ #include "runtime/utilities/debug_settings_reader.h" #include "runtime/gmm_helper/gmm_lib.h" #include "runtime/helpers/hw_info.h" +#include "runtime/utilities/spinlock.h" #include "gmm_memory.h" #include #include +#include namespace OCLRT { @@ -40,6 +42,13 @@ enum class WddmInterfaceVersion { Wddm23 = 23, }; +enum class EvictionStatus { + SUCCESS, + FAILED, + NOT_APPLIED, + UNKNOWN +}; + class Wddm { public: typedef HRESULT(WINAPI *CreateDXGIFactoryFcn)(REFIID riid, void **ppFactory); @@ -142,6 +151,10 @@ class Wddm { MOCKABLE_VIRTUAL uint64_t *getPagingFenceAddress() { return pagingFenceAddress; } + MOCKABLE_VIRTUAL EvictionStatus evictAllTemporaryResources(); + MOCKABLE_VIRTUAL EvictionStatus evictTemporaryResource(WddmAllocation *allocation); + MOCKABLE_VIRTUAL void applyBlockingMakeResident(WddmAllocation *allocation); + MOCKABLE_VIRTUAL std::unique_lock acquireLock(SpinLock &lock); protected: bool initialized = false; @@ -192,5 +205,7 @@ class Wddm { std::unique_ptr kmDafListener; std::unique_ptr wddmInterface; + std::vector temporaryResources; + SpinLock temporaryResourcesLock; }; } // namespace OCLRT diff --git a/runtime/os_interface/windows/wddm_allocation.h b/runtime/os_interface/windows/wddm_allocation.h index 10a9bca7f5..407a9754ef 100644 --- a/runtime/os_interface/windows/wddm_allocation.h +++ b/runtime/os_interface/windows/wddm_allocation.h @@ -80,6 +80,7 @@ class WddmAllocation : public GraphicsAllocation { this->reservedAddressSpace = reserveMem; } void setGpuAddress(uint64_t graphicsAddress) { this->gpuAddress = graphicsAddress; } + bool needsMakeResidentBeforeLock = false; std::string getAllocationInfoString() const { std::stringstream ss; diff --git a/runtime/os_interface/windows/wddm_memory_manager.cpp b/runtime/os_interface/windows/wddm_memory_manager.cpp index 67f76d242a..fabbe5bc8a 100644 --- a/runtime/os_interface/windows/wddm_memory_manager.cpp +++ b/runtime/os_interface/windows/wddm_memory_manager.cpp @@ -301,6 +301,11 @@ void WddmMemoryManager::freeGraphicsMemoryImpl(GraphicsAllocation *gfxAllocation return; } + if (input->isLocked() && input->needsMakeResidentBeforeLock) { + auto evictionStatus = wddm->evictTemporaryResource(input); + DEBUG_BREAK_IF(evictionStatus == EvictionStatus::FAILED); + } + for (auto &osContext : this->registeredOsContexts) { if (osContext) { auto &residencyController = osContext->get()->getResidencyController(); diff --git a/runtime/os_interface/windows/wddm_residency_controller.cpp b/runtime/os_interface/windows/wddm_residency_controller.cpp index a26ebe0417..0c884e4db0 100644 --- a/runtime/os_interface/windows/wddm_residency_controller.cpp +++ b/runtime/os_interface/windows/wddm_residency_controller.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018-2019 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -346,6 +346,11 @@ bool WddmResidencyController::makeResidentResidencyAllocations(ResidencyContaine this->setMemoryBudgetExhausted(); const bool trimmingDone = this->trimResidencyToBudget(bytesToTrim); if (!trimmingDone) { + auto evictionStatus = wddm.evictAllTemporaryResources(); + if (evictionStatus == EvictionStatus::SUCCESS) { + continue; + } + DEBUG_BREAK_IF(evictionStatus != EvictionStatus::NOT_APPLIED); result = wddm.makeResident(handlesForResidency.get(), totalHandlesCount, true, &bytesToTrim); break; } diff --git a/unit_tests/mocks/mock_wddm.cpp b/unit_tests/mocks/mock_wddm.cpp index 41f1e28b9a..1178bc1fa5 100644 --- a/unit_tests/mocks/mock_wddm.cpp +++ b/unit_tests/mocks/mock_wddm.cpp @@ -225,6 +225,29 @@ VOID *WddmMock::registerTrimCallback(PFND3DKMT_TRIMNOTIFICATIONCALLBACK callback return Wddm::registerTrimCallback(callback, residencyController); } +EvictionStatus WddmMock::evictAllTemporaryResources() { + evictAllTemporaryResourcesResult.called++; + evictAllTemporaryResourcesResult.status = Wddm::evictAllTemporaryResources(); + return evictAllTemporaryResourcesResult.status; +} + +EvictionStatus WddmMock::evictTemporaryResource(WddmAllocation *allocation) { + evictTemporaryResourceResult.called++; + evictTemporaryResourceResult.status = Wddm::evictTemporaryResource(allocation); + return evictTemporaryResourceResult.status; +} + +void WddmMock::applyBlockingMakeResident(WddmAllocation *allocation) { + applyBlockingMakeResidentResult.called++; + return Wddm::applyBlockingMakeResident(allocation); +} + +std::unique_lock WddmMock::acquireLock(SpinLock &lock) { + acquireLockResult.called++; + acquireLockResult.uint64ParamPassed = reinterpret_cast(&lock); + return Wddm::acquireLock(lock); +} + GmmMemory *WddmMock::getGmmMemory() const { return gmmMemory.get(); } @@ -234,3 +257,11 @@ uint64_t *WddmMock::getPagingFenceAddress() { mockPagingFence++; return &mockPagingFence; } + +void *GmockWddm::virtualAllocWrapper(void *inPtr, size_t size, uint32_t flags, uint32_t type) { + void *tmp = reinterpret_cast(virtualAllocAddress); + size += MemoryConstants::pageSize; + size -= size % MemoryConstants::pageSize; + virtualAllocAddress += size; + return tmp; +} diff --git a/unit_tests/mocks/mock_wddm.h b/unit_tests/mocks/mock_wddm.h index ea86c114b3..ac552b767d 100644 --- a/unit_tests/mocks/mock_wddm.h +++ b/unit_tests/mocks/mock_wddm.h @@ -8,6 +8,7 @@ #pragma once #include "runtime/os_interface/windows/wddm/wddm.h" +#include "gmock/gmock.h" #include #include @@ -27,6 +28,9 @@ struct MakeResidentCall : public CallResult { std::vector handlePack; uint32_t handleCount = 0; }; +struct EvictCallResult : public CallResult { + EvictionStatus status = EvictionStatus::UNKNOWN; +}; struct KmDafLockCall : public CallResult { std::vector lockedAllocations; }; @@ -43,6 +47,8 @@ class WddmMock : public Wddm { using Wddm::gmmMemory; using Wddm::pagingFenceAddress; using Wddm::pagingQueue; + using Wddm::temporaryResources; + using Wddm::temporaryResourcesLock; using Wddm::wddmInterface; WddmMock() : Wddm(){}; @@ -77,6 +83,10 @@ class WddmMock : public Wddm { int virtualFree(void *ptr, size_t size, unsigned long flags) override; void releaseReservedAddress(void *reservedAddress) override; VOID *registerTrimCallback(PFND3DKMT_TRIMNOTIFICATIONCALLBACK callback, WddmResidencyController &residencyController) override; + EvictionStatus evictAllTemporaryResources() override; + EvictionStatus evictTemporaryResource(WddmAllocation *allocation) override; + void applyBlockingMakeResident(WddmAllocation *allocation) override; + std::unique_lock acquireLock(SpinLock &lock) override; bool reserveValidAddressRange(size_t size, void *&reservedMem); GmmMemory *getGmmMemory() const; PLATFORM *getGfxPlatform() { return gfxPlatform.get(); } @@ -111,6 +121,10 @@ class WddmMock : public Wddm { WddmMockHelpers::CallResult waitFromCpuResult; WddmMockHelpers::CallResult releaseReservedAddressResult; WddmMockHelpers::CallResult reserveValidAddressRangeResult; + WddmMockHelpers::EvictCallResult evictAllTemporaryResourcesResult; + WddmMockHelpers::EvictCallResult evictTemporaryResourceResult; + WddmMockHelpers::CallResult applyBlockingMakeResidentResult; + WddmMockHelpers::CallResult acquireLockResult; WddmMockHelpers::CallResult registerTrimCallbackResult; WddmMockHelpers::CallResult getPagingFenceAddressResult; @@ -122,6 +136,26 @@ class WddmMock : public Wddm { std::set reservedAddresses; uintptr_t virtualAllocAddress = OCLRT::windowsMinAddress; bool kmDafEnabled = false; - uint64_t mockPagingFence; + uint64_t mockPagingFence = 0u; +}; + +struct GmockWddm : WddmMock { + GmockWddm() { + virtualAllocAddress = OCLRT::windowsMinAddress; + } + ~GmockWddm() = default; + bool virtualFreeWrapper(void *ptr, size_t size, uint32_t flags) { + return true; + } + + void *virtualAllocWrapper(void *inPtr, size_t size, uint32_t flags, uint32_t type); + uintptr_t virtualAllocAddress; + MOCK_METHOD4(makeResident, bool(D3DKMT_HANDLE *handles, uint32_t count, bool cantTrimFurther, uint64_t *numberOfBytesToTrim)); + MOCK_METHOD3(evict, bool(D3DKMT_HANDLE *handles, uint32_t num, uint64_t &sizeToTrim)); + MOCK_METHOD1(createAllocationsAndMapGpuVa, NTSTATUS(OsHandleStorage &osHandles)); + + NTSTATUS baseCreateAllocationAndMapGpuVa(OsHandleStorage &osHandles) { + return Wddm::createAllocationsAndMapGpuVa(osHandles); + } }; } // namespace OCLRT diff --git a/unit_tests/os_interface/windows/wddm20_tests.cpp b/unit_tests/os_interface/windows/wddm20_tests.cpp index ee1a63599e..ad53d546c7 100644 --- a/unit_tests/os_interface/windows/wddm20_tests.cpp +++ b/unit_tests/os_interface/windows/wddm20_tests.cpp @@ -819,3 +819,177 @@ TEST_F(Wddm20Tests, givenNullTrimCallbackHandleWhenUnregisteringTrimCallbackThen EXPECT_EQ(callbackBefore, gdi->getUnregisterTrimNotificationArg().Callback); EXPECT_EQ(trimCallbackHandleBefore, gdi->getUnregisterTrimNotificationArg().Handle); } + +TEST_F(Wddm20Tests, givenAllocationThatDoesntNeedMakeResidentBeforeLockWhenLockThenDontStoreItOrCallMakeResident) { + WddmAllocation allocation{nullptr, 0, nullptr, MemoryPool::MemoryNull, 1u, false}; + EXPECT_FALSE(allocation.needsMakeResidentBeforeLock); + EXPECT_TRUE(wddm->temporaryResources.empty()); + EXPECT_EQ(0u, wddm->makeResidentResult.called); + wddm->lockResource(&allocation); + EXPECT_TRUE(wddm->temporaryResources.empty()); + EXPECT_EQ(0u, wddm->makeResidentResult.called); + wddm->unlockResource(&allocation); +} +TEST_F(Wddm20Tests, givenAllocationThatNeedsMakeResidentBeforeLockWhenLockThenCallBlockingMakeResident) { + WddmAllocation allocation{nullptr, 0, nullptr, MemoryPool::MemoryNull, 1u, false}; + allocation.needsMakeResidentBeforeLock = true; + wddm->lockResource(&allocation); + EXPECT_EQ(1u, wddm->applyBlockingMakeResidentResult.called); +} +TEST_F(Wddm20Tests, givenAllocationWhenApplyBlockingMakeResidentThenAcquireUniqueLock) { + WddmAllocation allocation{nullptr, 0, nullptr, MemoryPool::MemoryNull, 1u, false}; + wddm->applyBlockingMakeResident(&allocation); + EXPECT_EQ(1u, wddm->acquireLockResult.called); + EXPECT_EQ(reinterpret_cast(&wddm->temporaryResourcesLock), wddm->acquireLockResult.uint64ParamPassed); +} +TEST_F(Wddm20Tests, givenAllocationWhenApplyBlockingMakeResidentThenCallMakeResidentAndStoreAllocation) { + WddmAllocation allocation{nullptr, 0, nullptr, MemoryPool::MemoryNull, 1u, false}; + wddm->applyBlockingMakeResident(&allocation); + EXPECT_EQ(1u, wddm->makeResidentResult.called); + EXPECT_EQ(allocation.handle, wddm->temporaryResources.back()); +} +TEST_F(Wddm20Tests, givenAllocationWhenApplyBlockingMakeResidentThenWaitForCurrentPagingFenceValue) { + WddmAllocation allocation{nullptr, 0, nullptr, MemoryPool::MemoryNull, 1u, false}; + wddm->mockPagingFence = 0u; + wddm->currentPagingFenceValue = 3u; + wddm->applyBlockingMakeResident(&allocation); + EXPECT_EQ(1u, wddm->makeResidentResult.called); + EXPECT_EQ(3u, wddm->mockPagingFence); + EXPECT_EQ(3u, wddm->getPagingFenceAddressResult.called); +} +TEST_F(Wddm20Tests, givenAllocationWhenApplyBlockingMakeResidentAndMakeResidentCallFailsThenEvictTemporaryResourcesAndRetry) { + WddmAllocation allocation{nullptr, 0, nullptr, MemoryPool::MemoryNull, 1u, false}; + GmockWddm gmockWddm; + EXPECT_CALL(gmockWddm, makeResident(&allocation.handle, ::testing::_, ::testing::_, ::testing::_)).Times(2).WillRepeatedly(::testing::Return(false)); + gmockWddm.applyBlockingMakeResident(&allocation); + EXPECT_EQ(1u, gmockWddm.evictAllTemporaryResourcesResult.called); +} +TEST_F(Wddm20Tests, whenApplyBlockingMakeResidentAndTemporaryResourcesAreEvictedSuccessfullyThenCallMakeResidentOneMoreTime) { + WddmAllocation allocation{nullptr, 0, nullptr, MemoryPool::MemoryNull, 1u, false}; + GmockWddm gmockWddm; + gmockWddm.temporaryResources.push_back(allocation.handle); + EXPECT_CALL(gmockWddm, evict(::testing::_, ::testing::_, ::testing::_)).Times(1).WillRepeatedly(::testing::Return(true)); + EXPECT_CALL(gmockWddm, makeResident(&allocation.handle, ::testing::_, ::testing::_, ::testing::_)).Times(3).WillRepeatedly(::testing::Return(false)); + gmockWddm.applyBlockingMakeResident(&allocation); + EXPECT_EQ(2u, gmockWddm.evictAllTemporaryResourcesResult.called); +} +TEST_F(Wddm20Tests, whenApplyBlockingMakeResidentAndMakeResidentStillFailsThenDontStoreTemporaryResource) { + WddmAllocation allocation{nullptr, 0, nullptr, MemoryPool::MemoryNull, 1u, false}; + allocation.handle = 0x2; + GmockWddm gmockWddm; + gmockWddm.temporaryResources.push_back(0x1); + EXPECT_CALL(gmockWddm, evict(::testing::_, ::testing::_, ::testing::_)).Times(1).WillRepeatedly(::testing::Return(true)); + EXPECT_CALL(gmockWddm, makeResident(&allocation.handle, ::testing::_, ::testing::_, ::testing::_)).Times(3).WillRepeatedly(::testing::Return(false)); + EXPECT_EQ(1u, gmockWddm.temporaryResources.size()); + gmockWddm.applyBlockingMakeResident(&allocation); + EXPECT_EQ(0u, gmockWddm.temporaryResources.size()); +} +TEST_F(Wddm20Tests, whenApplyBlockingMakeResidentAndMakeResidentPassesAfterEvictThenStoreTemporaryResource) { + WddmAllocation allocation{nullptr, 0, nullptr, MemoryPool::MemoryNull, 1u, false}; + allocation.handle = 0x2; + GmockWddm gmockWddm; + gmockWddm.temporaryResources.push_back(0x1); + EXPECT_CALL(gmockWddm, evict(::testing::_, ::testing::_, ::testing::_)).Times(1).WillRepeatedly(::testing::Return(true)); + EXPECT_CALL(gmockWddm, makeResident(&allocation.handle, ::testing::_, ::testing::_, ::testing::_)).Times(2).WillOnce(::testing::Return(false)).WillOnce(::testing::Return(true)); + EXPECT_EQ(1u, gmockWddm.temporaryResources.size()); + gmockWddm.applyBlockingMakeResident(&allocation); + EXPECT_EQ(1u, gmockWddm.temporaryResources.size()); + EXPECT_EQ(0x2, gmockWddm.temporaryResources.back()); +} +TEST_F(Wddm20Tests, whenApplyBlockingMakeResidentAndMakeResidentPassesThenStoreTemporaryResource) { + WddmAllocation allocation{nullptr, 0, nullptr, MemoryPool::MemoryNull, 1u, false}; + allocation.handle = 0x2; + GmockWddm gmockWddm; + gmockWddm.temporaryResources.push_back(0x1); + EXPECT_CALL(gmockWddm, makeResident(&allocation.handle, ::testing::_, ::testing::_, ::testing::_)).Times(1).WillOnce(::testing::Return(true)); + gmockWddm.applyBlockingMakeResident(&allocation); + EXPECT_EQ(2u, gmockWddm.temporaryResources.size()); + EXPECT_EQ(0x2, gmockWddm.temporaryResources.back()); +} +TEST_F(Wddm20Tests, givenNoTemporaryResourcesWhenEvictingAllTemporaryResourcesThenEvictionIsNotApplied) { + wddm->evictAllTemporaryResources(); + EXPECT_EQ(EvictionStatus::NOT_APPLIED, wddm->evictAllTemporaryResourcesResult.status); +} +TEST_F(Wddm20Tests, whenEvictingAllTemporaryResourcesThenAcquireTemporaryResourcesLock) { + wddm->evictAllTemporaryResources(); + EXPECT_EQ(1u, wddm->acquireLockResult.called); + EXPECT_EQ(reinterpret_cast(&wddm->temporaryResourcesLock), wddm->acquireLockResult.uint64ParamPassed); +} +TEST_F(Wddm20Tests, whenEvictingAllTemporaryResourcesAndAllEvictionsSucceedThenReturnSuccess) { + WddmAllocation allocation{nullptr, 0, nullptr, MemoryPool::MemoryNull, 1u, false}; + GmockWddm gmockWddm; + gmockWddm.temporaryResources.push_back(allocation.handle); + EXPECT_CALL(gmockWddm, evict(::testing::_, ::testing::_, ::testing::_)).Times(1).WillOnce(::testing::Return(true)); + gmockWddm.evictAllTemporaryResources(); + EXPECT_EQ(1u, gmockWddm.evictAllTemporaryResourcesResult.called); + EXPECT_EQ(EvictionStatus::SUCCESS, gmockWddm.evictAllTemporaryResourcesResult.status); +} +TEST_F(Wddm20Tests, givenThreeAllocationsWhenEvictingAllTemporaryResourcesThenCallEvictForEachAllocationAndCleanList) { + GmockWddm gmockWddm; + constexpr uint32_t numAllocations = 3u; + for (auto i = 0u; i < numAllocations; i++) { + gmockWddm.temporaryResources.push_back(i); + } + EXPECT_CALL(gmockWddm, evict(::testing::_, ::testing::_, ::testing::_)).Times(3).WillRepeatedly(::testing::Return(true)); + gmockWddm.evictAllTemporaryResources(); + EXPECT_TRUE(gmockWddm.temporaryResources.empty()); +} +TEST_F(Wddm20Tests, givenThreeAllocationsWhenEvictingAllTemporaryResourcesAndOneOfThemFailsThenReturnFail) { + GmockWddm gmockWddm; + constexpr uint32_t numAllocations = 3u; + for (auto i = 0u; i < numAllocations; i++) { + gmockWddm.temporaryResources.push_back(i); + } + EXPECT_CALL(gmockWddm, evict(::testing::_, ::testing::_, ::testing::_)).Times(3).WillOnce(::testing::Return(false)).WillRepeatedly(::testing::Return(true)); + gmockWddm.evictAllTemporaryResources(); + EXPECT_EQ(EvictionStatus::FAILED, gmockWddm.evictAllTemporaryResourcesResult.status); +} +TEST_F(Wddm20Tests, givenNoTemporaryResourcesWhenEvictingTemporaryResourceThenEvictionIsNotApplied) { + wddm->evictTemporaryResource(nullptr); + EXPECT_EQ(EvictionStatus::NOT_APPLIED, wddm->evictTemporaryResourceResult.status); +} +TEST_F(Wddm20Tests, whenEvictingTemporaryResourceThenAcquireTemporaryResourcesLock) { + wddm->evictTemporaryResource(nullptr); + EXPECT_EQ(1u, wddm->acquireLockResult.called); + EXPECT_EQ(reinterpret_cast(&wddm->temporaryResourcesLock), wddm->acquireLockResult.uint64ParamPassed); +} +TEST_F(Wddm20Tests, whenEvictingNonExistingTemporaryResourceThenEvictIsNotAppliedAndTemporaryResourcesAreRestored) { + WddmAllocation allocation{nullptr, 0, nullptr, MemoryPool::MemoryNull, 1u, false}; + allocation.handle = 0x1; + wddm->temporaryResources.push_back(0x2); + EXPECT_FALSE(wddm->temporaryResources.empty()); + wddm->evictTemporaryResource(&allocation); + EXPECT_FALSE(wddm->temporaryResources.empty()); + EXPECT_EQ(EvictionStatus::NOT_APPLIED, wddm->evictTemporaryResourceResult.status); +} +TEST_F(Wddm20Tests, whenEvictingTemporaryResourceAndEvictFailsThenReturnFail) { + WddmAllocation allocation{nullptr, 0, nullptr, MemoryPool::MemoryNull, 1u, false}; + GmockWddm gmockWddm; + gmockWddm.temporaryResources.push_back(allocation.handle); + EXPECT_CALL(gmockWddm, evict(::testing::_, ::testing::_, ::testing::_)).Times(1).WillOnce(::testing::Return(false)); + gmockWddm.evictTemporaryResource(&allocation); + EXPECT_TRUE(gmockWddm.temporaryResources.empty()); + EXPECT_EQ(EvictionStatus::FAILED, gmockWddm.evictTemporaryResourceResult.status); +} +TEST_F(Wddm20Tests, whenEvictingTemporaryResourceAndEvictSucceedThenReturnSuccess) { + WddmAllocation allocation{nullptr, 0, nullptr, MemoryPool::MemoryNull, 1u, false}; + GmockWddm gmockWddm; + gmockWddm.temporaryResources.push_back(allocation.handle); + EXPECT_CALL(gmockWddm, evict(::testing::_, ::testing::_, ::testing::_)).Times(1).WillOnce(::testing::Return(true)); + gmockWddm.evictTemporaryResource(&allocation); + EXPECT_TRUE(gmockWddm.temporaryResources.empty()); + EXPECT_EQ(EvictionStatus::SUCCESS, gmockWddm.evictTemporaryResourceResult.status); +} +TEST_F(Wddm20Tests, whenEvictingTemporaryResourceThenOtherResourcesRemainOnTheList) { + wddm->temporaryResources.push_back(0x1); + wddm->temporaryResources.push_back(0x2); + wddm->temporaryResources.push_back(0x3); + + WddmAllocation allocation{nullptr, 0, nullptr, MemoryPool::MemoryNull, 1u, false}; + allocation.handle = 0x2; + wddm->evictTemporaryResource(&allocation); + + EXPECT_EQ(2u, wddm->temporaryResources.size()); + EXPECT_EQ(0x1, wddm->temporaryResources.front()); + EXPECT_EQ(0x3, wddm->temporaryResources.back()); +} 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 624b6d0d65..f17b735f16 100644 --- a/unit_tests/os_interface/windows/wddm_memory_manager_tests.cpp +++ b/unit_tests/os_interface/windows/wddm_memory_manager_tests.cpp @@ -1516,4 +1516,33 @@ TEST_F(MockWddmMemoryManagerTest, givenWddmAllocationWhenEnableMakeResidentOnMap ASSERT_TRUE(result); EXPECT_EQ(5u, wddm.getPagingFenceAddressResult.called); +} + +TEST_F(WddmMemoryManagerSimpleTest, whenDestroyingLockedAllocationThatDoesntNeedMakeResidentBeforeLockThenDontEvictAllocationFromWddmTemporaryResources) { + auto allocation = static_cast(memoryManager->allocateGraphicsMemoryWithProperties(MockAllocationProperties{MemoryConstants::pageSize})); + allocation->setLocked(true); + EXPECT_FALSE(allocation->needsMakeResidentBeforeLock); + memoryManager->freeGraphicsMemory(allocation); + EXPECT_EQ(0u, wddm->evictTemporaryResourceResult.called); +} +TEST_F(WddmMemoryManagerSimpleTest, whenDestroyingNotLockedAllocationThatDoesntNeedMakeResidentBeforeLockThenDontEvictAllocationFromWddmTemporaryResources) { + auto allocation = static_cast(memoryManager->allocateGraphicsMemoryWithProperties(MockAllocationProperties{MemoryConstants::pageSize})); + allocation->setLocked(false); + EXPECT_FALSE(allocation->needsMakeResidentBeforeLock); + memoryManager->freeGraphicsMemory(allocation); + EXPECT_EQ(0u, wddm->evictTemporaryResourceResult.called); +} +TEST_F(WddmMemoryManagerSimpleTest, whenDestroyingLockedAllocationThatNeedsMakeResidentBeforeLockThenEvictAllocationFromWddmTemporaryResources) { + auto allocation = static_cast(memoryManager->allocateGraphicsMemoryWithProperties(MockAllocationProperties{MemoryConstants::pageSize})); + allocation->needsMakeResidentBeforeLock = true; + allocation->setLocked(true); + memoryManager->freeGraphicsMemory(allocation); + EXPECT_EQ(1u, wddm->evictTemporaryResourceResult.called); +} +TEST_F(WddmMemoryManagerSimpleTest, whenDestroyingNotLockedAllocationThatNeedsMakeResidentBeforeLockThenDontEvictAllocationFromWddmTemporaryResources) { + auto allocation = static_cast(memoryManager->allocateGraphicsMemoryWithProperties(MockAllocationProperties{MemoryConstants::pageSize})); + allocation->needsMakeResidentBeforeLock = true; + allocation->setLocked(false); + memoryManager->freeGraphicsMemory(allocation); + EXPECT_EQ(0u, wddm->evictTemporaryResourceResult.called); } \ No newline at end of file diff --git a/unit_tests/os_interface/windows/wddm_memory_manager_tests.h b/unit_tests/os_interface/windows/wddm_memory_manager_tests.h index fe8887d3b4..538ea544bc 100644 --- a/unit_tests/os_interface/windows/wddm_memory_manager_tests.h +++ b/unit_tests/os_interface/windows/wddm_memory_manager_tests.h @@ -75,35 +75,6 @@ class MockWddmMemoryManagerFixture : public GmmEnvironmentFixture { typedef ::Test WddmMemoryManagerResidencyTest; -class GmockWddm : public Wddm { - public: - using Wddm::device; - - GmockWddm() { - virtualAllocAddress = OCLRT::windowsMinAddress; - } - ~GmockWddm() = default; - - bool virtualFreeWrapper(void *ptr, size_t size, uint32_t flags) { - return true; - } - - void *virtualAllocWrapper(void *inPtr, size_t size, uint32_t flags, uint32_t type) { - void *tmp = reinterpret_cast(virtualAllocAddress); - size += MemoryConstants::pageSize; - size -= size % MemoryConstants::pageSize; - virtualAllocAddress += size; - return tmp; - } - uintptr_t virtualAllocAddress; - MOCK_METHOD4(makeResident, bool(D3DKMT_HANDLE *handles, uint32_t count, bool cantTrimFurther, uint64_t *numberOfBytesToTrim)); - MOCK_METHOD1(createAllocationsAndMapGpuVa, NTSTATUS(OsHandleStorage &osHandles)); - - NTSTATUS baseCreateAllocationAndMapGpuVa(OsHandleStorage &osHandles) { - return Wddm::createAllocationsAndMapGpuVa(osHandles); - } -}; - class WddmMemoryManagerFixtureWithGmockWddm : public GmmEnvironmentFixture { public: MockWddmMemoryManager *memoryManager = nullptr; diff --git a/unit_tests/os_interface/windows/wddm_residency_controller_tests.cpp b/unit_tests/os_interface/windows/wddm_residency_controller_tests.cpp index 03847c9d4a..0fd56f441c 100644 --- a/unit_tests/os_interface/windows/wddm_residency_controller_tests.cpp +++ b/unit_tests/os_interface/windows/wddm_residency_controller_tests.cpp @@ -76,11 +76,6 @@ struct WddmResidencyControllerWithGdiTest : ::testing::Test { }; struct WddmResidencyControllerWithMockWddmTest : public WddmResidencyControllerTest { - struct GmockWddm : Wddm { - using Wddm::gdi; - MOCK_METHOD4(makeResident, bool(D3DKMT_HANDLE *handles, uint32_t count, bool cantTrimFurther, uint64_t *numberOfBytesToTrim)); - }; - void SetUp() { executionEnvironment = std::make_unique(); executionEnvironment->initGmm(*platformDevices);