2018-10-04 06:52:51 +08:00
|
|
|
/*
|
2021-04-03 01:01:51 +08:00
|
|
|
* Copyright (C) 2018-2021 Intel Corporation
|
2018-10-04 06:52:51 +08:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: MIT
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2020-02-24 05:44:01 +08:00
|
|
|
#include "shared/source/os_interface/windows/wddm_residency_controller.h"
|
2019-02-27 18:39:32 +08:00
|
|
|
|
2020-02-24 05:44:01 +08:00
|
|
|
#include "shared/source/debug_settings/debug_settings_manager.h"
|
|
|
|
#include "shared/source/os_interface/windows/wddm/wddm.h"
|
|
|
|
#include "shared/source/os_interface/windows/wddm_allocation.h"
|
|
|
|
#include "shared/source/os_interface/windows/wddm_residency_allocations_container.h"
|
|
|
|
#include "shared/source/utilities/spinlock.h"
|
2018-10-04 06:52:51 +08:00
|
|
|
|
2019-03-26 18:59:46 +08:00
|
|
|
namespace NEO {
|
2018-10-04 06:52:51 +08:00
|
|
|
|
2018-10-30 21:40:02 +08:00
|
|
|
WddmResidencyController::WddmResidencyController(Wddm &wddm, uint32_t osContextId) : wddm(wddm), osContextId(osContextId) {
|
2018-11-14 21:35:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void WddmResidencyController::registerCallback() {
|
2018-11-15 18:44:37 +08:00
|
|
|
this->trimCallbackHandle = wddm.registerTrimCallback(WddmResidencyController::trimCallback, *this);
|
2018-10-30 21:40:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
WddmResidencyController::~WddmResidencyController() {
|
|
|
|
auto lock = this->acquireTrimCallbackLock();
|
2018-11-15 18:44:37 +08:00
|
|
|
wddm.unregisterTrimCallback(WddmResidencyController::trimCallback, this->trimCallbackHandle);
|
2018-10-30 21:40:02 +08:00
|
|
|
lock.unlock();
|
|
|
|
|
|
|
|
// Wait for lock to ensure trimCallback ended
|
|
|
|
lock.lock();
|
|
|
|
}
|
2018-10-04 06:52:51 +08:00
|
|
|
|
2018-10-16 21:53:39 +08:00
|
|
|
std::unique_lock<SpinLock> WddmResidencyController::acquireLock() {
|
|
|
|
return std::unique_lock<SpinLock>{this->lock};
|
2018-10-04 06:52:51 +08:00
|
|
|
}
|
|
|
|
|
2018-10-16 21:53:39 +08:00
|
|
|
std::unique_lock<SpinLock> WddmResidencyController::acquireTrimCallbackLock() {
|
|
|
|
return std::unique_lock<SpinLock>{this->trimCallbackLock};
|
2018-10-15 23:12:55 +08:00
|
|
|
}
|
|
|
|
|
2018-10-04 06:52:51 +08:00
|
|
|
WddmAllocation *WddmResidencyController::getTrimCandidateHead() {
|
|
|
|
uint32_t i = 0;
|
|
|
|
const size_t size = trimCandidateList.size();
|
|
|
|
|
|
|
|
if (size == 0) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
while ((trimCandidateList[i] == nullptr) && (i < size))
|
|
|
|
i++;
|
|
|
|
|
2019-03-05 16:25:18 +08:00
|
|
|
return static_cast<WddmAllocation *>(trimCandidateList[i]);
|
2018-10-04 06:52:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void WddmResidencyController::addToTrimCandidateList(GraphicsAllocation *allocation) {
|
|
|
|
WddmAllocation *wddmAllocation = (WddmAllocation *)allocation;
|
|
|
|
size_t position = trimCandidateList.size();
|
|
|
|
|
|
|
|
DEBUG_BREAK_IF(trimCandidatesCount > trimCandidateList.size());
|
|
|
|
|
2018-10-09 23:03:07 +08:00
|
|
|
if (wddmAllocation->getTrimCandidateListPosition(this->osContextId) == trimListUnusedPosition) {
|
2018-10-04 06:52:51 +08:00
|
|
|
trimCandidatesCount++;
|
|
|
|
trimCandidateList.push_back(allocation);
|
2018-10-09 23:03:07 +08:00
|
|
|
wddmAllocation->setTrimCandidateListPosition(this->osContextId, position);
|
2018-10-04 06:52:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
checkTrimCandidateCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
void WddmResidencyController::removeFromTrimCandidateList(GraphicsAllocation *allocation, bool compactList) {
|
|
|
|
WddmAllocation *wddmAllocation = (WddmAllocation *)allocation;
|
2018-10-09 23:03:07 +08:00
|
|
|
size_t position = wddmAllocation->getTrimCandidateListPosition(this->osContextId);
|
2018-10-04 06:52:51 +08:00
|
|
|
|
|
|
|
DEBUG_BREAK_IF(!(trimCandidatesCount > (trimCandidatesCount - 1)));
|
|
|
|
DEBUG_BREAK_IF(trimCandidatesCount > trimCandidateList.size());
|
|
|
|
|
|
|
|
trimCandidatesCount--;
|
|
|
|
|
|
|
|
trimCandidateList[position] = nullptr;
|
|
|
|
|
|
|
|
checkTrimCandidateCount();
|
|
|
|
|
|
|
|
if (position == trimCandidateList.size() - 1) {
|
|
|
|
size_t erasePosition = position;
|
|
|
|
|
|
|
|
if (position == 0) {
|
|
|
|
trimCandidateList.resize(0);
|
|
|
|
} else {
|
|
|
|
while (trimCandidateList[erasePosition] == nullptr && erasePosition > 0) {
|
|
|
|
erasePosition--;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t sizeRemaining = erasePosition + 1;
|
|
|
|
if (erasePosition == 0 && trimCandidateList[erasePosition] == nullptr) {
|
|
|
|
sizeRemaining = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
trimCandidateList.resize(sizeRemaining);
|
|
|
|
}
|
|
|
|
}
|
2018-10-09 23:03:07 +08:00
|
|
|
wddmAllocation->setTrimCandidateListPosition(this->osContextId, trimListUnusedPosition);
|
2018-10-04 06:52:51 +08:00
|
|
|
|
|
|
|
if (compactList && checkTrimCandidateListCompaction()) {
|
|
|
|
compactTrimCandidateList();
|
|
|
|
}
|
|
|
|
|
|
|
|
checkTrimCandidateCount();
|
|
|
|
}
|
|
|
|
|
2018-10-09 23:03:07 +08:00
|
|
|
void WddmResidencyController::removeFromTrimCandidateListIfUsed(WddmAllocation *allocation, bool compactList) {
|
|
|
|
if (allocation->getTrimCandidateListPosition(this->osContextId) != trimListUnusedPosition) {
|
|
|
|
this->removeFromTrimCandidateList(allocation, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-04 06:52:51 +08:00
|
|
|
void WddmResidencyController::checkTrimCandidateCount() {
|
|
|
|
if (DebugManager.flags.ResidencyDebugEnable.get()) {
|
|
|
|
uint32_t sum = 0;
|
2019-07-29 19:35:55 +08:00
|
|
|
for (auto trimCandidate : trimCandidateList) {
|
|
|
|
if (trimCandidate != nullptr) {
|
2018-10-04 06:52:51 +08:00
|
|
|
sum++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DEBUG_BREAK_IF(sum != trimCandidatesCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WddmResidencyController::checkTrimCandidateListCompaction() {
|
2019-02-28 18:21:01 +08:00
|
|
|
return 2 * trimCandidatesCount <= trimCandidateList.size();
|
2018-10-04 06:52:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void WddmResidencyController::compactTrimCandidateList() {
|
|
|
|
size_t size = trimCandidateList.size();
|
|
|
|
size_t freePosition = 0;
|
|
|
|
|
|
|
|
if (size == 0 || size == trimCandidatesCount) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG_BREAK_IF(!(trimCandidateList[size - 1] != nullptr));
|
|
|
|
|
2021-05-20 21:48:33 +08:00
|
|
|
[[maybe_unused]] uint32_t previousCount = trimCandidatesCount;
|
2018-10-04 06:52:51 +08:00
|
|
|
DEBUG_BREAK_IF(trimCandidatesCount > trimCandidateList.size());
|
|
|
|
|
|
|
|
while (freePosition < trimCandidatesCount && trimCandidateList[freePosition] != nullptr)
|
|
|
|
freePosition++;
|
|
|
|
|
|
|
|
for (uint32_t i = 1; i < size; i++) {
|
|
|
|
|
|
|
|
if (trimCandidateList[i] != nullptr && freePosition < i) {
|
|
|
|
trimCandidateList[freePosition] = trimCandidateList[i];
|
|
|
|
trimCandidateList[i] = nullptr;
|
2018-10-09 23:03:07 +08:00
|
|
|
static_cast<WddmAllocation *>(trimCandidateList[freePosition])->setTrimCandidateListPosition(this->osContextId, freePosition);
|
2018-10-04 06:52:51 +08:00
|
|
|
freePosition++;
|
|
|
|
|
|
|
|
// Last element was moved, erase elements from freePosition
|
|
|
|
if (i == size - 1) {
|
|
|
|
trimCandidateList.resize(freePosition);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DEBUG_BREAK_IF(trimCandidatesCount > trimCandidateList.size());
|
|
|
|
DEBUG_BREAK_IF(trimCandidatesCount != previousCount);
|
|
|
|
|
|
|
|
checkTrimCandidateCount();
|
|
|
|
}
|
|
|
|
|
2018-10-22 21:59:26 +08:00
|
|
|
void WddmResidencyController::resetMonitoredFenceParams(D3DKMT_HANDLE &handle, uint64_t *cpuAddress, D3DGPU_VIRTUAL_ADDRESS &gpuAddress) {
|
|
|
|
monitoredFence.lastSubmittedFence = 0;
|
|
|
|
monitoredFence.currentFenceValue = 1;
|
|
|
|
monitoredFence.fenceHandle = handle;
|
|
|
|
monitoredFence.cpuAddress = cpuAddress;
|
|
|
|
monitoredFence.gpuAddress = gpuAddress;
|
|
|
|
}
|
|
|
|
|
2019-09-05 17:02:40 +08:00
|
|
|
bool WddmResidencyController::makeResidentResidencyAllocations(const ResidencyContainer &allocationsForResidency) {
|
2018-11-15 21:45:35 +08:00
|
|
|
const size_t residencyCount = allocationsForResidency.size();
|
2020-04-21 19:16:45 +08:00
|
|
|
constexpr uint32_t stackAllocations = 64;
|
|
|
|
constexpr uint32_t stackHandlesCount = NEO::maxFragmentsCount * EngineLimits::maxHandleCount * stackAllocations;
|
|
|
|
StackVec<D3DKMT_HANDLE, stackHandlesCount> handlesForResidency;
|
2018-11-05 22:47:32 +08:00
|
|
|
uint32_t totalHandlesCount = 0;
|
2020-03-17 19:19:38 +08:00
|
|
|
size_t totalSize = 0;
|
2018-11-05 22:47:32 +08:00
|
|
|
|
|
|
|
auto lock = this->acquireLock();
|
|
|
|
|
|
|
|
DBG_LOG(ResidencyDebugEnable, "Residency:", __FUNCTION__, "currentFenceValue =", this->getMonitoredFence().currentFenceValue);
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < residencyCount; i++) {
|
2019-03-05 16:25:18 +08:00
|
|
|
WddmAllocation *allocation = static_cast<WddmAllocation *>(allocationsForResidency[i]);
|
2018-11-15 21:45:35 +08:00
|
|
|
ResidencyData &residencyData = allocation->getResidencyData();
|
2021-06-09 21:53:41 +08:00
|
|
|
static constexpr int maxFragments = 3;
|
|
|
|
bool fragmentResidency[maxFragments] = {false, false, false};
|
2020-03-17 19:19:38 +08:00
|
|
|
totalSize += allocation->getAlignedSize();
|
2018-11-05 22:47:32 +08:00
|
|
|
|
2018-11-28 18:01:41 +08:00
|
|
|
DBG_LOG(ResidencyDebugEnable, "Residency:", __FUNCTION__, "allocation =", allocation, residencyData.resident[osContextId] ? "resident" : "not resident");
|
2018-11-05 22:47:32 +08:00
|
|
|
|
2021-06-09 21:53:41 +08:00
|
|
|
UNRECOVERABLE_IF(allocation->fragmentsStorage.fragmentCount > maxFragments);
|
2018-11-05 22:47:32 +08:00
|
|
|
if (allocation->getTrimCandidateListPosition(this->osContextId) != trimListUnusedPosition) {
|
|
|
|
DBG_LOG(ResidencyDebugEnable, "Residency:", __FUNCTION__, "allocation =", allocation, "on trimCandidateList");
|
|
|
|
this->removeFromTrimCandidateList(allocation, false);
|
|
|
|
} else {
|
|
|
|
for (uint32_t allocationId = 0; allocationId < allocation->fragmentsStorage.fragmentCount; allocationId++) {
|
2018-11-28 18:01:41 +08:00
|
|
|
fragmentResidency[allocationId] = allocation->fragmentsStorage.fragmentStorageData[allocationId].residency->resident[osContextId];
|
2021-04-03 01:01:51 +08:00
|
|
|
DBG_LOG(ResidencyDebugEnable, "Residency:", __FUNCTION__, "fragment handle =",
|
|
|
|
static_cast<OsHandleWin *>(allocation->fragmentsStorage.fragmentStorageData[allocationId].osHandleStorage)->handle,
|
|
|
|
fragmentResidency[allocationId] ? "resident" : "not resident");
|
2018-11-05 22:47:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-15 21:45:35 +08:00
|
|
|
if (allocation->fragmentsStorage.fragmentCount > 0) {
|
2018-11-05 22:47:32 +08:00
|
|
|
for (uint32_t allocationId = 0; allocationId < allocation->fragmentsStorage.fragmentCount; allocationId++) {
|
2020-04-21 19:16:45 +08:00
|
|
|
if (!fragmentResidency[allocationId]) {
|
2021-04-03 01:01:51 +08:00
|
|
|
handlesForResidency.push_back(static_cast<OsHandleWin *>(allocation->fragmentsStorage.fragmentStorageData[allocationId].osHandleStorage)->handle);
|
2020-04-21 19:16:45 +08:00
|
|
|
totalHandlesCount++;
|
|
|
|
}
|
2018-11-05 22:47:32 +08:00
|
|
|
}
|
2018-11-28 18:01:41 +08:00
|
|
|
} else if (!residencyData.resident[osContextId]) {
|
2020-04-21 19:16:45 +08:00
|
|
|
for (uint32_t gmmId = 0; gmmId < allocation->getNumGmms(); ++gmmId) {
|
|
|
|
handlesForResidency.push_back(allocation->getHandle(gmmId));
|
|
|
|
totalHandlesCount++;
|
|
|
|
}
|
2018-11-05 22:47:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool result = true;
|
|
|
|
if (totalHandlesCount) {
|
|
|
|
uint64_t bytesToTrim = 0;
|
2020-04-21 19:16:45 +08:00
|
|
|
while ((result = wddm.makeResident(&handlesForResidency[0], totalHandlesCount, false, &bytesToTrim, totalSize)) == false) {
|
2018-11-05 22:47:32 +08:00
|
|
|
this->setMemoryBudgetExhausted();
|
2018-11-15 21:45:35 +08:00
|
|
|
const bool trimmingDone = this->trimResidencyToBudget(bytesToTrim);
|
|
|
|
if (!trimmingDone) {
|
2019-07-12 22:50:14 +08:00
|
|
|
auto evictionStatus = wddm.getTemporaryResourcesContainer()->evictAllResources();
|
2019-08-29 19:46:49 +08:00
|
|
|
if (evictionStatus == MemoryOperationsStatus::SUCCESS) {
|
2019-01-16 22:09:33 +08:00
|
|
|
continue;
|
|
|
|
}
|
2019-08-29 19:46:49 +08:00
|
|
|
DEBUG_BREAK_IF(evictionStatus != MemoryOperationsStatus::MEMORY_NOT_FOUND);
|
2020-04-21 19:16:45 +08:00
|
|
|
result = wddm.makeResident(&handlesForResidency[0], totalHandlesCount, true, &bytesToTrim, totalSize);
|
2018-11-05 22:47:32 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result == true) {
|
|
|
|
for (uint32_t i = 0; i < residencyCount; i++) {
|
2019-03-05 16:25:18 +08:00
|
|
|
WddmAllocation *allocation = static_cast<WddmAllocation *>(allocationsForResidency[i]);
|
2018-11-05 22:47:32 +08:00
|
|
|
// Update fence value not to early destroy / evict allocation
|
2018-11-15 21:45:35 +08:00
|
|
|
const auto currentFence = this->getMonitoredFence().currentFenceValue;
|
2018-11-05 22:47:32 +08:00
|
|
|
allocation->getResidencyData().updateCompletionData(currentFence, this->osContextId);
|
2018-11-28 18:01:41 +08:00
|
|
|
allocation->getResidencyData().resident[osContextId] = true;
|
2018-11-05 22:47:32 +08:00
|
|
|
|
|
|
|
for (uint32_t allocationId = 0; allocationId < allocation->fragmentsStorage.fragmentCount; allocationId++) {
|
|
|
|
auto residencyData = allocation->fragmentsStorage.fragmentStorageData[allocationId].residency;
|
|
|
|
// Update fence value not to remove the fragment referenced by different GA in trimming callback
|
|
|
|
residencyData->updateCompletionData(currentFence, this->osContextId);
|
2018-11-28 18:01:41 +08:00
|
|
|
residencyData->resident[osContextId] = true;
|
2018-11-05 22:47:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-09-05 17:02:40 +08:00
|
|
|
void WddmResidencyController::makeNonResidentEvictionAllocations(const ResidencyContainer &evictionAllocations) {
|
2018-11-05 22:47:32 +08:00
|
|
|
auto lock = this->acquireLock();
|
|
|
|
const size_t residencyCount = evictionAllocations.size();
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < residencyCount; i++) {
|
2019-03-05 16:25:18 +08:00
|
|
|
WddmAllocation *allocation = static_cast<WddmAllocation *>(evictionAllocations[i]);
|
2018-11-05 22:47:32 +08:00
|
|
|
this->addToTrimCandidateList(allocation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-19 21:02:05 +08:00
|
|
|
bool WddmResidencyController::isInitialized() const {
|
2021-05-21 07:17:57 +08:00
|
|
|
bool requiresTrimCallbacks = OSInterface::requiresSupportForWddmTrimNotification;
|
|
|
|
requiresTrimCallbacks = requiresTrimCallbacks && (false == DebugManager.flags.DoNotRegisterTrimCallback.get());
|
|
|
|
if (requiresTrimCallbacks) {
|
2019-12-19 21:02:05 +08:00
|
|
|
return trimCallbackHandle != nullptr;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-03-26 18:59:46 +08:00
|
|
|
} // namespace NEO
|