refactor: add new diagnostic mode for device state

Related-To: NEO-8395

Signed-off-by: Zbigniew Zdanowicz <zbigniew.zdanowicz@intel.com>
This commit is contained in:
Zbigniew Zdanowicz
2023-10-30 15:45:17 +00:00
committed by Compute-Runtime-Automation
parent 3665d6e258
commit db10e85526
7 changed files with 201 additions and 15 deletions

View File

@@ -1033,20 +1033,56 @@ bool Wddm::submit(uint64_t commandBuffer, size_t size, void *commandHeader, Wddm
return status;
}
bool Wddm::getDeviceState() {
if (checkDeviceState) {
bool Wddm::getDeviceExecutionState(D3DKMT_DEVICESTATE_TYPE stateType, void *privateData) {
D3DKMT_GETDEVICESTATE getDevState = {};
NTSTATUS status = STATUS_SUCCESS;
getDevState.hDevice = device;
getDevState.StateType = D3DKMT_DEVICESTATE_EXECUTION;
getDevState.StateType = stateType;
status = getGdi()->getDeviceState(&getDevState);
DEBUG_BREAK_IF(status != STATUS_SUCCESS);
PRINT_DEBUG_STRING(getDevState.ExecutionState == D3DKMT_DEVICEEXECUTION_ERROR_OUTOFMEMORY, stderr, "Device execution error, out of memory %d\n", getDevState.ExecutionState);
if (status == STATUS_SUCCESS) {
DEBUG_BREAK_IF(getDevState.ExecutionState != D3DKMT_DEVICEEXECUTION_ACTIVE);
return getDevState.ExecutionState == D3DKMT_DEVICEEXECUTION_ACTIVE;
if (status != STATUS_SUCCESS) {
return false;
}
if (stateType == D3DKMT_DEVICESTATE_PAGE_FAULT) {
if (privateData != nullptr) {
*reinterpret_cast<D3DKMT_DEVICEPAGEFAULT_STATE *>(privateData) = getDevState.PageFaultState;
}
return true;
} else if (stateType == D3DKMT_DEVICESTATE_EXECUTION) {
if (privateData != nullptr) {
*reinterpret_cast<D3DKMT_DEVICEEXECUTION_STATE *>(privateData) = getDevState.ExecutionState;
}
return true;
} else {
return false;
}
}
bool Wddm::getDeviceState() {
if (checkDeviceState) {
D3DKMT_DEVICEEXECUTION_STATE executionState = D3DKMT_DEVICEEXECUTION_ACTIVE;
auto status = getDeviceExecutionState(D3DKMT_DEVICESTATE_EXECUTION, &executionState);
if (status) {
DEBUG_BREAK_IF(executionState != D3DKMT_DEVICEEXECUTION_ACTIVE);
if (executionState == D3DKMT_DEVICEEXECUTION_ERROR_OUTOFMEMORY) {
PRINT_DEBUG_STRING(true, stderr, "Device execution error, out of memory %d\n", executionState);
} else if (executionState == D3DKMT_DEVICEEXECUTION_ERROR_DMAPAGEFAULT) {
PRINT_DEBUG_STRING(true, stderr, "Device execution error, page fault\n", executionState);
D3DKMT_DEVICEPAGEFAULT_STATE pageFaultState = {};
status = getDeviceExecutionState(D3DKMT_DEVICESTATE_PAGE_FAULT, &pageFaultState);
if (status) {
PRINT_DEBUG_STRING(true, stderr, "faulted gpuva 0x%" PRIx64 ", ", pageFaultState.FaultedVirtualAddress);
PRINT_DEBUG_STRING(true, stderr, "pipeline stage %d, bind table entry %u, flags 0x%x, error code(is device) %u, error code %u\n",
pageFaultState.FaultedPipelineStage, pageFaultState.FaultedBindTableEntry, pageFaultState.PageFaultFlags,
pageFaultState.FaultErrorCode.IsDeviceSpecificCodeReservedBit, pageFaultState.FaultErrorCode.DeviceSpecificCode);
}
} else if (executionState != D3DKMT_DEVICEEXECUTION_ACTIVE) {
PRINT_DEBUG_STRING(true, stderr, "Device execution error %d\n", executionState);
}
return executionState == D3DKMT_DEVICEEXECUTION_ACTIVE;
}
return false;
}

View File

@@ -214,6 +214,9 @@ class Wddm : public DriverModel {
}
}
bool getDeviceExecutionState(D3DKMT_DEVICESTATE_TYPE stateType, void *privateData);
bool getDeviceState();
protected:
bool translateTopologyInfo(TopologyMapping &mapping);
@@ -223,7 +226,6 @@ class Wddm : public DriverModel {
bool createPagingQueue();
bool destroyPagingQueue();
bool destroyDevice();
bool getDeviceState();
MOCKABLE_VIRTUAL void createPagingFenceLogger();
bool setLowPriorityContextParam(D3DKMT_HANDLE contextHandle);
bool adjustEvictNeededParameter(bool evictNeeded) {

View File

@@ -23,6 +23,8 @@ uint64_t gGpuAddressSpace = 0ull;
uint32_t gLastPriority = 0ull;
ADAPTER_BDF gAdapterBDF{};
D3DKMT_DEVICEEXECUTION_STATE gExecutionState = D3DKMT_DEVICEEXECUTION_ACTIVE;
NTSTATUS gGetDeviceStateExecutionReturnValue = STATUS_SUCCESS;
NTSTATUS gGetDeviceStatePageFaultReturnValue = STATUS_SUCCESS;
NTSTATUS __stdcall mockD3DKMTEscape(IN CONST D3DKMT_ESCAPE *pData) {
static int perfTicks = 0;
@@ -646,7 +648,19 @@ NTSTATUS __stdcall mockD3DKMTEvict(IN OUT D3DKMT_EVICT *) {
}
NTSTATUS __stdcall mockD3DKMTGetDeviceState(IN OUT D3DKMT_GETDEVICESTATE *getDevState) {
if (getDevState->StateType == D3DKMT_DEVICESTATE_EXECUTION) {
getDevState->ExecutionState = gExecutionState;
return gGetDeviceStateExecutionReturnValue;
} else if (getDevState->StateType == D3DKMT_DEVICESTATE_PAGE_FAULT) {
getDevState->PageFaultState = {};
getDevState->PageFaultState.FaultedPipelineStage = DXGK_RENDER_PIPELINE_STAGE_UNKNOWN;
getDevState->PageFaultState.FaultedBindTableEntry = 2;
getDevState->PageFaultState.PageFaultFlags = DXGK_PAGE_FAULT_WRITE;
getDevState->PageFaultState.FaultErrorCode.IsDeviceSpecificCodeReservedBit = 1;
getDevState->PageFaultState.FaultErrorCode.DeviceSpecificCode = 10;
getDevState->PageFaultState.FaultedVirtualAddress = 0xABC000;
return gGetDeviceStatePageFaultReturnValue;
}
return STATUS_SUCCESS;
}
@@ -756,3 +770,11 @@ D3DKMT_SETCONTEXTSCHEDULINGPRIORITY *getSetContextSchedulingPriorityDataCall() {
void setMockDeviceExecutionState(D3DKMT_DEVICEEXECUTION_STATE newState) {
gExecutionState = newState;
}
void setMockGetDeviceStateReturnValue(NTSTATUS newReturnValue, bool execution) {
if (execution) {
gGetDeviceStateExecutionReturnValue = newReturnValue;
} else {
gGetDeviceStatePageFaultReturnValue = newReturnValue;
}
}

View File

@@ -104,5 +104,5 @@ bool *getRegisterTrimNotificationFailCall();
uint32_t getLastPriority();
void setAdapterBDF(ADAPTER_BDF &adapterBDF);
void setMockDeviceExecutionState(D3DKMT_DEVICEEXECUTION_STATE newState);
void setMockGetDeviceStateReturnValue(NTSTATUS newReturnValue, bool execution);
void initGfxPartition();

View File

@@ -133,6 +133,9 @@ void *MockOsLibrary::getProcAddress(const std::string &procName) {
if (procName == "setMockDeviceExecutionState") {
return reinterpret_cast<void *>(setMockDeviceExecutionState);
}
if (procName == "setMockGetDeviceStateReturnValue") {
return reinterpret_cast<void *>(setMockGetDeviceStateReturnValue);
}
if (procName == "getMockAllocation") {
return reinterpret_cast<void *>(getMockAllocation);
}

View File

@@ -58,6 +58,7 @@ struct GdiDllFixture {
setAdapterBDFFcn =
reinterpret_cast<decltype(&setAdapterBDF)>(mockGdiDll->getProcAddress("setAdapterBDF"));
setMockDeviceExecutionStateFcn = reinterpret_cast<decltype(&setMockDeviceExecutionState)>(mockGdiDll->getProcAddress("setMockDeviceExecutionState"));
setMockGetDeviceStateReturnValueFcn = reinterpret_cast<decltype(&setMockGetDeviceStateReturnValue)>(mockGdiDll->getProcAddress("setMockGetDeviceStateReturnValue"));
setMockLastDestroyedResHandleFcn((D3DKMT_HANDLE)0);
*getDestroySynchronizationObjectDataFcn() = {};
*getCreateSynchronizationObject2FailCallFcn() = false;
@@ -104,4 +105,5 @@ struct GdiDllFixture {
decltype(&getLastPriority) getLastPriorityFcn = nullptr;
decltype(&setAdapterBDF) setAdapterBDFFcn = nullptr;
decltype(&setMockDeviceExecutionState) setMockDeviceExecutionStateFcn = nullptr;
decltype(&setMockGetDeviceStateReturnValue) setMockGetDeviceStateReturnValueFcn = nullptr;
};

View File

@@ -490,12 +490,37 @@ TEST_F(WddmTests, givenCheckDeviceStateSetToTrueWhenCallGetDeviceStateAndForceEx
wddm->checkDeviceState = true;
auto executionState = D3DKMT_DEVICEEXECUTION_ERROR_OUTOFMEMORY;
setMockDeviceExecutionStateFcn(executionState);
::testing::internal::CaptureStderr();
EXPECT_FALSE(wddm->getDeviceState());
std::string output = testing::internal::GetCapturedStderr();
EXPECT_EQ(std::string("Device execution error, out of memory " + std::to_string(executionState) + "\n"), output);
setMockDeviceExecutionStateFcn(D3DKMT_DEVICEEXECUTION_ACTIVE);
::testing::internal::CaptureStderr();
EXPECT_TRUE(wddm->getDeviceState());
output = testing::internal::GetCapturedStderr();
EXPECT_EQ(std::string(""), output);
}
TEST_F(WddmTests, givenCheckDeviceStateSetToTrueWhenCallGetDeviceStateReturnsFailThenNoMessageIsVisible) {
DebugManagerStateRestore restorer{};
DebugManager.flags.EnableDebugBreak.set(false);
wddm->checkDeviceState = true;
auto executionState = D3DKMT_DEVICEEXECUTION_ERROR_OUTOFMEMORY;
setMockDeviceExecutionStateFcn(executionState);
setMockGetDeviceStateReturnValueFcn(STATUS_SUCCESS + 1, true);
::testing::internal::CaptureStderr();
EXPECT_FALSE(wddm->getDeviceState());
std::string output = testing::internal::GetCapturedStderr();
EXPECT_EQ(std::string(""), output);
setMockDeviceExecutionStateFcn(D3DKMT_DEVICEEXECUTION_ACTIVE);
setMockGetDeviceStateReturnValueFcn(STATUS_SUCCESS, true);
::testing::internal::CaptureStderr();
EXPECT_TRUE(wddm->getDeviceState());
output = testing::internal::GetCapturedStderr();
@@ -509,18 +534,114 @@ TEST_F(WddmTests, givenCheckDeviceStateSetToFalseWhenCallGetDeviceStateAndForceE
wddm->checkDeviceState = false;
auto executionState = D3DKMT_DEVICEEXECUTION_ERROR_OUTOFMEMORY;
setMockDeviceExecutionStateFcn(executionState);
::testing::internal::CaptureStderr();
EXPECT_TRUE(wddm->getDeviceState());
std::string output = testing::internal::GetCapturedStderr();
EXPECT_EQ(std::string(""), output);
setMockDeviceExecutionStateFcn(D3DKMT_DEVICEEXECUTION_ACTIVE);
::testing::internal::CaptureStderr();
EXPECT_TRUE(wddm->getDeviceState());
output = testing::internal::GetCapturedStderr();
EXPECT_EQ(std::string(""), output);
}
TEST_F(WddmTests, givenCheckDeviceStateSetToTrueWhenCallGetDeviceStateReturnsPageFaultThenProperMessageIsVisible) {
DebugManagerStateRestore restorer{};
DebugManager.flags.EnableDebugBreak.set(false);
wddm->checkDeviceState = true;
setMockDeviceExecutionStateFcn(D3DKMT_DEVICEEXECUTION_ERROR_DMAPAGEFAULT);
::testing::internal::CaptureStderr();
EXPECT_FALSE(wddm->getDeviceState());
std::string output = testing::internal::GetCapturedStderr();
std::string expected = "Device execution error, page fault\nfaulted gpuva 0xabc000, pipeline stage 0, bind table entry 2, flags 0x1, error code(is device) 1, error code 10\n";
EXPECT_EQ(expected, output);
setMockDeviceExecutionStateFcn(D3DKMT_DEVICEEXECUTION_ACTIVE);
::testing::internal::CaptureStderr();
EXPECT_TRUE(wddm->getDeviceState());
output = testing::internal::GetCapturedStderr();
EXPECT_EQ(std::string(""), output);
}
TEST_F(WddmTests, givenCheckDeviceStateSetToTrueWhenCallGetDeviceStateReturnsFailureThenBasicMessageDisplayed) {
DebugManagerStateRestore restorer{};
DebugManager.flags.EnableDebugBreak.set(false);
wddm->checkDeviceState = true;
setMockDeviceExecutionStateFcn(D3DKMT_DEVICEEXECUTION_ERROR_DMAPAGEFAULT);
setMockGetDeviceStateReturnValueFcn(STATUS_SUCCESS + 1, false);
::testing::internal::CaptureStderr();
EXPECT_FALSE(wddm->getDeviceState());
std::string output = testing::internal::GetCapturedStderr();
std::string expected = "Device execution error, page fault\n";
EXPECT_EQ(expected, output);
setMockDeviceExecutionStateFcn(D3DKMT_DEVICEEXECUTION_ACTIVE);
setMockGetDeviceStateReturnValueFcn(STATUS_SUCCESS, false);
::testing::internal::CaptureStderr();
EXPECT_TRUE(wddm->getDeviceState());
output = testing::internal::GetCapturedStderr();
EXPECT_EQ(std::string(""), output);
}
TEST_F(WddmTests, givenCheckDeviceStateSetToTrueWhenCallGetDeviceStateReturnsOtherNonActiveStateThenGenericMessageDisplayed) {
DebugManagerStateRestore restorer{};
DebugManager.flags.EnableDebugBreak.set(false);
wddm->checkDeviceState = true;
auto executionState = D3DKMT_DEVICEEXECUTION_RESET;
setMockDeviceExecutionStateFcn(executionState);
::testing::internal::CaptureStderr();
EXPECT_FALSE(wddm->getDeviceState());
std::string output = testing::internal::GetCapturedStderr();
std::string expected = std::string("Device execution error " + std::to_string(executionState) + "\n");
EXPECT_EQ(expected, output);
setMockDeviceExecutionStateFcn(D3DKMT_DEVICEEXECUTION_ACTIVE);
::testing::internal::CaptureStderr();
EXPECT_TRUE(wddm->getDeviceState());
output = testing::internal::GetCapturedStderr();
EXPECT_EQ(std::string(""), output);
}
TEST_F(WddmTests, givenGetDeviceExecutionStatusWhenGdiCallFailsThenReturnFalse) {
setMockGetDeviceStateReturnValueFcn(STATUS_SUCCESS + 1, true);
setMockDeviceExecutionStateFcn(D3DKMT_DEVICEEXECUTION_ACTIVE);
auto status = wddm->getDeviceExecutionState(D3DKMT_DEVICESTATE_EXECUTION, nullptr);
EXPECT_FALSE(status);
setMockGetDeviceStateReturnValueFcn(STATUS_SUCCESS, true);
status = wddm->getDeviceExecutionState(D3DKMT_DEVICESTATE_EXECUTION, nullptr);
EXPECT_TRUE(status);
}
TEST_F(WddmTests, givenGetDeviceExecutionStatusWhenUnsupportedStatusProvidedThenReturnsFalse) {
auto status = wddm->getDeviceExecutionState(D3DKMT_DEVICESTATE_PRESENT, nullptr);
EXPECT_FALSE(status);
}
TEST_F(WddmTests, givenGetDeviceExecutionStatusWhenGettingPageFaultStatusReturnsFailThenReturnFalse) {
setMockGetDeviceStateReturnValueFcn(STATUS_SUCCESS + 1, false);
auto status = wddm->getDeviceExecutionState(D3DKMT_DEVICESTATE_PAGE_FAULT, nullptr);
EXPECT_FALSE(status);
setMockGetDeviceStateReturnValueFcn(STATUS_SUCCESS, false);
status = wddm->getDeviceExecutionState(D3DKMT_DEVICESTATE_PAGE_FAULT, nullptr);
EXPECT_TRUE(status);
}
TEST(WddmConstructorTest, givenEnableDeviceStateVerificationSetTrueWhenCreateWddmThenCheckDeviceStateIsTrue) {
DebugManagerStateRestore restorer{};
DebugManager.flags.EnableDeviceStateVerification.set(1);