WSL - fixing resource cleanup on process shutdown

Resolves issues with coexistance of NEO L0 and NEO OCL libraries
within a single process running in WSL and using WDDM GPU PV

Signed-off-by: Jaroslaw Chodor <jaroslaw.chodor@intel.com>
This commit is contained in:
Jaroslaw Chodor
2021-11-19 22:58:46 +01:00
committed by Compute-Runtime-Automation
parent c77fe0bffc
commit c4e802f01b
13 changed files with 120 additions and 26 deletions

View File

@ -875,3 +875,11 @@ TEST(DrmQueryTest, GivenRpsMaxFreqFileDoesntExistWhenFrequencyIsQueriedThenFallb
EXPECT_EQ(expectedMaxFrequency, maxFrequency);
}
TEST(DrmTest, whenCheckedIfResourcesCleanupCanBeSkippedThenReturnsFalse) {
auto executionEnvironment = std::make_unique<ExecutionEnvironment>();
executionEnvironment->prepareRootDeviceEnvironments(1);
DrmMock *pDrm = new DrmMock(*executionEnvironment->rootDeviceEnvironments[0]);
EXPECT_FALSE(pDrm->skipResourceCleanup());
delete pDrm;
}

View File

@ -211,7 +211,15 @@ bool CommandStreamReceiver::isRcs() const {
return this->osContext->getEngineType() == aub_stream::ENGINE_RCS;
}
bool CommandStreamReceiver::skipResourceCleanup() const {
return this->getOSInterface() && this->getOSInterface()->getDriverModel() && this->getOSInterface()->getDriverModel()->skipResourceCleanup();
}
void CommandStreamReceiver::cleanupResources() {
if (this->skipResourceCleanup()) {
return;
}
waitForTaskCountAndCleanAllocationList(this->latestFlushedTaskCount, TEMPORARY_ALLOCATION);
waitForTaskCountAndCleanAllocationList(this->latestFlushedTaskCount, REUSABLE_ALLOCATION);

View File

@ -288,6 +288,8 @@ class CommandStreamReceiver {
return activePartitions;
}
bool skipResourceCleanup() const;
std::unique_ptr<GmmPageTableMngr> pageTableManager;
protected:

View File

@ -36,10 +36,15 @@ Device::Device(ExecutionEnvironment *executionEnvironment)
}
Device::~Device() {
getMemoryManager()->freeGraphicsMemory(rtMemoryBackedBuffer);
rtMemoryBackedBuffer = nullptr;
if (false == commandStreamReceivers.empty()) {
if (commandStreamReceivers[0]->skipResourceCleanup()) {
return;
}
}
DEBUG_BREAK_IF(nullptr == executionEnvironment->memoryManager.get());
getMemoryManager()->freeGraphicsMemory(rtMemoryBackedBuffer);
rtMemoryBackedBuffer = nullptr;
if (performanceCounters) {
performanceCounters->shutdown();

View File

@ -83,6 +83,10 @@ class DriverModel : public NonCopyableClass {
return std::numeric_limits<size_t>::max();
}
virtual bool skipResourceCleanup() const {
return false;
}
protected:
DriverModelType driverModelType;
};

View File

@ -87,6 +87,7 @@ set(NEO_CORE_OS_INTERFACE_WDDM
${CMAKE_CURRENT_SOURCE_DIR}/wddm/set_gmm_input_args_${DRIVER_MODEL}.cpp
${CMAKE_CURRENT_SOURCE_DIR}/wddm/max_mem_alloc_size_${DRIVER_MODEL}.cpp
${CMAKE_CURRENT_SOURCE_DIR}/wddm/helper_${DRIVER_MODEL}.cpp
${CMAKE_CURRENT_SOURCE_DIR}/wddm/skip_resource_cleanup_${DRIVER_MODEL}.cpp
${CMAKE_CURRENT_SOURCE_DIR}/wddm/wddm.cpp
${CMAKE_CURRENT_SOURCE_DIR}/wddm/wddm.h
${CMAKE_CURRENT_SOURCE_DIR}/wddm/wddm_defs.h

View File

@ -39,7 +39,7 @@ void OsContextWin::initializeContext() {
};
OsContextWin::~OsContextWin() {
if (contextInitialized) {
if (contextInitialized && (false == this->wddm.skipResourceCleanup())) {
wddm.getWddmInterface()->destroyHwQueue(hardwareQueue.handle);
wddm.getWddmInterface()->destroyMonitorFence(residencyController.getMonitoredFence());
wddm.destroyContext(wddmContextHandle);

View File

@ -159,7 +159,7 @@ bool ensureGpuAddressRangeIsReserved(uint64_t address, size_t size, D3DKMT_HANDL
rangeDesc.MaximumAddress = alignUp(address + size, MemoryConstants::pageSize64k);
rangeDesc.Size = MemoryConstants::pageSize64k;
status = gdi.reserveGpuVirtualAddress(&rangeDesc);
if (status != STATUS_SUCCESS) {
if (status == STATUS_SUCCESS) {
DEBUG_BREAK_IF(true);
return false;
}

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/source/os_interface/windows/gdi_interface.h"
#include "shared/source/os_interface/windows/wddm/wddm.h"
namespace NEO {
bool Wddm::skipResourceCleanup() const {
D3DKMT_GETDEVICESTATE deviceState = {};
deviceState.hDevice = device;
deviceState.StateType = D3DKMT_DEVICESTATE_PRESENT;
NTSTATUS status = STATUS_SUCCESS;
status = getGdi()->getDeviceState(&deviceState);
return status != STATUS_SUCCESS;
}
} // namespace NEO

View File

@ -0,0 +1,16 @@
/*
* Copyright (C) 2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/source/os_interface/windows/wddm/wddm.h"
namespace NEO {
bool Wddm::skipResourceCleanup() const {
return false;
}
} // namespace NEO

View File

@ -189,6 +189,7 @@ class Wddm : public DriverModel {
PhysicalDevicePciBusInfo getPciBusInfo() const override;
size_t getMaxMemAllocSize() const override;
bool skipResourceCleanup() const override;
static std::vector<std::unique_ptr<HwDeviceId>> discoverDevices(ExecutionEnvironment &executionEnvironment);

View File

@ -118,6 +118,9 @@ struct GdiMockConfig {
D3DKMT_LOCK2 receivedLock2Args = {};
D3DKMT_DESTROYALLOCATION2 receivedDestroyAllocation2Args = {};
uint32_t mockAllocationHandle = 7U;
D3DKMT_GETDEVICESTATE receivedGetDeviceStateArgs = {};
GdiMockCallbackWithReturn getDeviceStateClb = {};
} gdiMockConfig;
NTSTATUS __stdcall reserveDeviceAddressSpaceMock(D3DDDI_RESERVEGPUVIRTUALADDRESS *arg) {
@ -185,6 +188,15 @@ NTSTATUS __stdcall escapeMock(const D3DKMT_ESCAPE *arg) {
return gdiMockConfig.escapeClb.returnValue;
}
NTSTATUS __stdcall getDeviceStateMock(D3DKMT_GETDEVICESTATE *arg) {
gdiMockConfig.receivedGetDeviceStateArgs = *arg;
gdiMockConfig.getDeviceStateClb.callCount += 1;
if (gdiMockConfig.getDeviceStateClb.callback) {
gdiMockConfig.getDeviceStateClb.callback();
}
return gdiMockConfig.getDeviceStateClb.returnValue;
}
struct WddmLinuxTest : public ::testing::Test {
void SetUp() override {
mockRootDeviceEnvironment = std::make_unique<NEO::MockRootDeviceEnvironment>(mockExecEnv);
@ -248,9 +260,16 @@ TEST_F(WddmLinuxConfigureDeviceAddressSpaceTest, givenPreReservedSvmAddressSpace
}
this->osEnvironment->gdi->reserveGpuVirtualAddress = reserveDeviceAddressSpaceMock;
gdiMockConfig.reserveGpuVaClb.returnValue = -2;
gdiMockConfig.reserveGpuVaClb.callback = []() { gdiMockConfig.reserveGpuVaClb.returnValue += 1; };
auto cantReserveWholeGpuVAButCanReservePortion = []() {
gdiMockConfig.reserveGpuVaClb.returnValue = (gdiMockConfig.reserveGpuVaClb.callCount == 1) ? -1 : 0;
};
gdiMockConfig.reserveGpuVaClb.callback = cantReserveWholeGpuVAButCanReservePortion;
bool success = this->wddm->configureDeviceAddressSpace();
EXPECT_FALSE(success);
auto cantReserveWholeGpuVAAndCantReservePortion = []() { gdiMockConfig.reserveGpuVaClb.returnValue = -1; };
gdiMockConfig.reserveGpuVaClb.callback = cantReserveWholeGpuVAAndCantReservePortion;
success = this->wddm->configureDeviceAddressSpace();
EXPECT_TRUE(success);
auto svmSize = this->getMaxSvmSize();
@ -261,19 +280,6 @@ TEST_F(WddmLinuxConfigureDeviceAddressSpaceTest, givenPreReservedSvmAddressSpace
EXPECT_EQ(wddm->getAdapter(), gdiMockConfig.receivedReserveGpuVaArgs.hAdapter);
}
TEST_F(WddmLinuxConfigureDeviceAddressSpaceTest, givenSvmAddressSpaceWhenCouldNotReserveGpuVAForSvmThenFail) {
if (NEO::hardwareInfoTable[productFamily]->capabilityTable.gpuAddressSpace < MemoryConstants::max64BitAppAddress) {
GTEST_SKIP();
}
osEnvironment->gdi->reserveGpuVirtualAddress = reserveDeviceAddressSpaceMock;
this->osEnvironment->gdi->reserveGpuVirtualAddress = reserveDeviceAddressSpaceMock;
gdiMockConfig.reserveGpuVaClb.returnValue = -1;
bool success = this->wddm->configureDeviceAddressSpace();
EXPECT_FALSE(success);
}
TEST_F(WddmLinuxConfigureDeviceAddressSpaceTest, givenNonSvmAddressSpaceThenReserveGpuVAForUSMIsNotCalled) {
if (NEO::hardwareInfoTable[productFamily]->capabilityTable.gpuAddressSpace >= MemoryConstants::max64BitAppAddress) {
GTEST_SKIP();
@ -531,10 +537,13 @@ TEST_F(WddmLinuxConfigureReduced48bitDeviceAddressSpaceTest, givenTwoSvmAddressS
}
this->wddm->featureTable->ftrCCSRing = 1;
gdiMockConfig.reserveGpuVaClb.returnValue = -1;
osEnvironment->gdi->escape = escapeMock;
osEnvironment->gdi->reserveGpuVirtualAddress = reserveDeviceAddressSpaceMock;
auto cantReserveWholeGpuVAButCanReservePortion = []() {
gdiMockConfig.reserveGpuVaClb.returnValue = (gdiMockConfig.reserveGpuVaClb.callCount == 1) ? -1 : 0;
};
gdiMockConfig.reserveGpuVaClb.callback = cantReserveWholeGpuVAButCanReservePortion;
bool success = this->wddm->configureDeviceAddressSpace();
EXPECT_FALSE(success);
EXPECT_EQ(1U, this->wddm->validAddressRangeReservations.size());
@ -549,14 +558,12 @@ TEST_F(WddmLinuxConfigureReduced48bitDeviceAddressSpaceTest, givenTwoSvmAddressS
}
this->wddm->featureTable->ftrCCSRing = 1;
gdiMockConfig.reserveGpuVaClb.callback = []() {
if (gdiMockConfig.reserveGpuVaClb.callCount > 1) {
gdiMockConfig.reserveGpuVaClb.returnValue = -1;
};
};
osEnvironment->gdi->escape = escapeMock;
osEnvironment->gdi->reserveGpuVirtualAddress = reserveDeviceAddressSpaceMock;
auto cantReserveWholeGpuVAOfSecondButCanReservePortionOfSecont = []() {
gdiMockConfig.reserveGpuVaClb.returnValue = (gdiMockConfig.reserveGpuVaClb.callCount == 2) ? -1 : 0;
};
gdiMockConfig.reserveGpuVaClb.callback = cantReserveWholeGpuVAOfSecondButCanReservePortionOfSecont;
bool success = this->wddm->configureDeviceAddressSpace();
EXPECT_FALSE(success);
EXPECT_EQ(1U, this->wddm->validAddressRangeReservations.size());
@ -605,6 +612,20 @@ TEST_F(WddmLinuxTest, givenRequestFor32bitAllocationWithoutPreexistingHostPtrWhe
memoryManager.freeGraphicsMemoryImpl(alloc);
}
TEST_F(WddmLinuxTest, whenCheckedIfResourcesCleanupCanBeSkippedAndDeviceIsAliveThenReturnsFalse) {
osEnvironment->gdi->getDeviceState = getDeviceStateMock;
gdiMockConfig.getDeviceStateClb.returnValue = STATUS_SUCCESS;
EXPECT_FALSE(this->wddm->skipResourceCleanup());
EXPECT_EQ(1, gdiMockConfig.getDeviceStateClb.callCount);
}
TEST_F(WddmLinuxTest, whenCheckedIfResourcesCleanupCanBeSkippedAndDeviceIsLostThenReturnsTrue) {
osEnvironment->gdi->getDeviceState = getDeviceStateMock;
gdiMockConfig.getDeviceStateClb.returnValue = -1;
EXPECT_TRUE(this->wddm->skipResourceCleanup());
EXPECT_EQ(1, gdiMockConfig.getDeviceStateClb.callCount);
}
class MockOsTimeLinux : public NEO::OSTimeLinux {
public:
MockOsTimeLinux(NEO::OSInterface *osInterface, std::unique_ptr<NEO::DeviceTime> deviceTime) : NEO::OSTimeLinux(osInterface, std::move(deviceTime)) {}

View File

@ -70,4 +70,9 @@ TEST_F(WddmTests, givenWddmWhenPassesIncorrectHandleToVerifyNTHandleThenReturnFa
EXPECT_FALSE(wddm->verifyNTHandle(handle));
}
TEST_F(WddmTests, whenCheckedIfResourcesCleanupCanBeSkippedThenReturnsFalse) {
init();
EXPECT_FALSE(wddm->skipResourceCleanup());
}
} // namespace NEO