L0 Win Debugger - implement thread control

Resolves: NEO-6722

Signed-off-by: Yates, Brandon <brandon.yates@intel.com>
Signed-off-by: Igor Venevtsev <igor.venevtsev@intel.com>
This commit is contained in:
Yates, Brandon 2022-07-26 19:02:54 +00:00 committed by Compute-Runtime-Automation
parent 403b49e987
commit 12c7f32679
8 changed files with 182 additions and 25 deletions

View File

@ -388,6 +388,24 @@ DebugSessionImp::Error DebugSessionImp::resumeThreadsWithinDevice(uint32_t devic
return retVal;
}
void DebugSessionImp::applyResumeWa(uint8_t *bitmask, size_t bitmaskSize) {
UNRECOVERABLE_IF(bitmaskSize % 8 != 0);
auto hwInfo = connectedDevice->getHwInfo();
auto &l0HwHelper = L0HwHelper::get(hwInfo.platform.eRenderCoreFamily);
if (l0HwHelper.isResumeWARequired()) {
uint32_t *dwordBitmask = reinterpret_cast<uint32_t *>(bitmask);
for (uint32_t i = 0; i < bitmaskSize / sizeof(uint32_t) - 1; i = i + 2) {
dwordBitmask[i] = dwordBitmask[i] | dwordBitmask[i + 1];
dwordBitmask[i + 1] = dwordBitmask[i] | dwordBitmask[i + 1];
}
}
return;
}
bool DebugSessionImp::writeResumeCommand(const std::vector<EuThread::ThreadId> &threadIds) {
auto stateSaveAreaHeader = getStateSaveAreaHeader();
bool success = true;

View File

@ -63,6 +63,7 @@ struct DebugSessionImp : DebugSession {
MOCKABLE_VIRTUAL ze_result_t writeRegistersImp(EuThread::ThreadId thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues);
Error resumeThreadsWithinDevice(uint32_t deviceIndex, ze_device_thread_t physicalThread);
MOCKABLE_VIRTUAL bool writeResumeCommand(const std::vector<EuThread::ThreadId> &threadIds);
void applyResumeWa(uint8_t *bitmask, size_t bitmaskSize);
MOCKABLE_VIRTUAL bool checkThreadIsResumed(const EuThread::ThreadId &threadID);
virtual ze_result_t resumeImp(const std::vector<EuThread::ThreadId> &threads, uint32_t deviceIndex) = 0;

View File

@ -1616,24 +1616,6 @@ uint64_t DebugSessionLinux::getContextStateSaveAreaGpuVa(uint64_t memoryHandle)
return bindInfo->second.gpuVa;
}
void DebugSessionLinux::applyResumeWa(uint8_t *bitmask, size_t bitmaskSize) {
UNRECOVERABLE_IF(bitmaskSize % 8 != 0);
auto hwInfo = connectedDevice->getHwInfo();
auto &l0HwHelper = L0HwHelper::get(hwInfo.platform.eRenderCoreFamily);
if (l0HwHelper.isResumeWARequired()) {
uint32_t *dwordBitmask = reinterpret_cast<uint32_t *>(bitmask);
for (uint32_t i = 0; i < bitmaskSize / sizeof(uint32_t) - 1; i = i + 2) {
dwordBitmask[i] = dwordBitmask[i] | dwordBitmask[i + 1];
dwordBitmask[i + 1] = dwordBitmask[i] | dwordBitmask[i + 1];
}
}
return;
}
uint32_t DebugSessionLinux::getDeviceIndexFromApiThread(ze_device_thread_t thread) {
uint32_t deviceIndex = 0;
auto deviceCount = std::max(1u, connectedDevice->getNEODevice()->getNumSubDevices());

View File

@ -248,8 +248,6 @@ struct DebugSessionLinux : DebugSessionImp {
ze_result_t readSbaBuffer(EuThread::ThreadId, NEO::SbaTrackedAddresses &sbaBuffer) override;
void readStateSaveAreaHeader() override;
void applyResumeWa(uint8_t *bitmask, size_t bitmaskSize);
ze_result_t readGpuMemory(uint64_t vmHandle, char *output, size_t size, uint64_t gpuVa) override;
ze_result_t writeGpuMemory(uint64_t vmHandle, const char *input, size_t size, uint64_t gpuVa) override;
ze_result_t getISAVMHandle(uint32_t deviceIndex, const zet_debug_memory_space_desc_t *desc, size_t size, uint64_t &vmHandle);

View File

@ -376,7 +376,7 @@ ze_result_t DebugSessionWindows::acknowledgeEventImp(uint32_t seqNo, uint32_t ev
return DebugSessionWindows::translateEscapeReturnStatusToZeResult(escapeInfo.KmEuDbgL0EscapeInfo.EscapeReturnStatus);
}
PRINT_DEBUGGER_INFO_LOG("DBGUMD_ACTION_ACKNOWLEDGE_EVENT - Success\n", status, escapeInfo.KmEuDbgL0EscapeInfo.EscapeReturnStatus);
PRINT_DEBUGGER_INFO_LOG("DBGUMD_ACTION_ACKNOWLEDGE_EVENT - Success\n");
return ZE_RESULT_SUCCESS;
}
@ -520,11 +520,51 @@ ze_result_t DebugSessionWindows::acknowledgeEvent(const zet_debug_event_t *event
}
ze_result_t DebugSessionWindows::resumeImp(const std::vector<EuThread::ThreadId> &threads, uint32_t deviceIndex) {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
auto hwInfo = connectedDevice->getHwInfo();
auto &l0HwHelper = L0HwHelper::get(hwInfo.platform.eRenderCoreFamily);
std::unique_ptr<uint8_t[]> bitmask;
size_t bitmaskSize = 0;
l0HwHelper.getAttentionBitmaskForSingleThreads(threads, hwInfo, bitmask, bitmaskSize);
applyResumeWa(bitmask.get(), bitmaskSize);
printBitmask(bitmask.get(), bitmaskSize);
KM_ESCAPE_INFO escapeInfo = {0};
escapeInfo.KmEuDbgL0EscapeInfo.EscapeActionType = DBGUMD_ACTION_EU_CONTROL_CLR_ATT_BIT;
escapeInfo.KmEuDbgL0EscapeInfo.EuControlClrAttBitParams.BitmaskArrayPtr = reinterpret_cast<uint64_t>(bitmask.get());
escapeInfo.KmEuDbgL0EscapeInfo.EuControlClrAttBitParams.BitMaskSizeInBytes = static_cast<uint32_t>(bitmaskSize);
auto status = runEscape(escapeInfo);
if (STATUS_SUCCESS != status) {
PRINT_DEBUGGER_ERROR_LOG("DBGUMD_ACTION_EU_CONTROL_CLR_ATT_BIT: Failed - Status: 0x%llX EscapeReturnStatus: %d\n", status, escapeInfo.KmEuDbgL0EscapeInfo.EscapeReturnStatus);
return DebugSessionWindows::translateNtStatusToZeResult(status);
}
if (DBGUMD_RETURN_ESCAPE_SUCCESS != escapeInfo.KmEuDbgL0EscapeInfo.EscapeReturnStatus) {
PRINT_DEBUGGER_ERROR_LOG("DBGUMD_ACTION_EU_CONTROL_CLR_ATT_BIT: Failed - Status: 0x%llX EscapeReturnStatus: %d\n", status, escapeInfo.KmEuDbgL0EscapeInfo.EscapeReturnStatus);
return DebugSessionWindows::translateEscapeReturnStatusToZeResult(escapeInfo.KmEuDbgL0EscapeInfo.EscapeReturnStatus);
}
PRINT_DEBUGGER_INFO_LOG("DBGUMD_ACTION_EU_CONTROL_CLR_ATT_BIT - Success\n");
return ZE_RESULT_SUCCESS;
}
ze_result_t DebugSessionWindows::interruptImp(uint32_t deviceIndex) {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
KM_ESCAPE_INFO escapeInfo = {0};
escapeInfo.KmEuDbgL0EscapeInfo.EscapeActionType = DBGUMD_ACTION_EU_CONTROL_INT_ALL;
auto status = runEscape(escapeInfo);
if (STATUS_SUCCESS != status) {
PRINT_DEBUGGER_ERROR_LOG("DBGUMD_ACTION_EU_CONTROL_INT_ALL: Failed - Status: 0x%llX EscapeReturnStatus: %d\n", status, escapeInfo.KmEuDbgL0EscapeInfo.EscapeReturnStatus);
return DebugSessionWindows::translateNtStatusToZeResult(status);
}
if (DBGUMD_RETURN_ESCAPE_SUCCESS != escapeInfo.KmEuDbgL0EscapeInfo.EscapeReturnStatus) {
PRINT_DEBUGGER_ERROR_LOG("DBGUMD_ACTION_EU_CONTROL_INT_ALL: Failed - Status: 0x%llX EscapeReturnStatus: %d\n", status, escapeInfo.KmEuDbgL0EscapeInfo.EscapeReturnStatus);
return DebugSessionWindows::translateEscapeReturnStatusToZeResult(escapeInfo.KmEuDbgL0EscapeInfo.EscapeReturnStatus);
}
PRINT_DEBUGGER_INFO_LOG("DBGUMD_ACTION_EU_CONTROL_INT_ALL - Success\n");
return ZE_RESULT_SUCCESS;
}
ze_result_t DebugSessionWindows::readGpuMemory(uint64_t memoryHandle, char *output, size_t size, uint64_t gpuVa) {

View File

@ -57,6 +57,9 @@ void initStateSaveArea(std::vector<char> &stateSaveArea, SIP::version version) {
// grfs for 0/0/0/0 - very first eu thread
fillRegsetForThread(&pStateSaveAreaHeader->regHeader.grf, 0, 0, 0, 0, 'a');
// grfs for 0/0/4/0 - requred to test resumeWA
fillRegsetForThread(&pStateSaveAreaHeader->regHeader.grf, 0, 0, 4, 0, 'a');
if (version.major < 2) {
// grfs for 0/3/7/3 - somewhere in the middle
fillRegsetForThread(&pStateSaveAreaHeader->regHeader.grf, 0, 3, 7, 3, 'a');

View File

@ -28,7 +28,9 @@ struct MockDebugSessionWindows : DebugSessionWindows {
using DebugSessionWindows::allContexts;
using DebugSessionWindows::allElfs;
using DebugSessionWindows::allModules;
using DebugSessionWindows::allThreads;
using DebugSessionWindows::asyncThread;
using DebugSessionWindows::calculateThreadSlotOffset;
using DebugSessionWindows::closeAsyncThread;
using DebugSessionWindows::debugArea;
using DebugSessionWindows::debugAreaVA;
@ -37,6 +39,7 @@ struct MockDebugSessionWindows : DebugSessionWindows {
using DebugSessionWindows::eventsToAck;
using DebugSessionWindows::getSbaBufferGpuVa;
using DebugSessionWindows::initialize;
using DebugSessionWindows::interruptImp;
using DebugSessionWindows::invalidHandle;
using DebugSessionWindows::moduleDebugAreaCaptured;
using DebugSessionWindows::processId;
@ -47,13 +50,13 @@ struct MockDebugSessionWindows : DebugSessionWindows {
using DebugSessionWindows::readModuleDebugArea;
using DebugSessionWindows::readSbaBuffer;
using DebugSessionWindows::readStateSaveAreaHeader;
using DebugSessionWindows::resumeImp;
using DebugSessionWindows::runEscape;
using DebugSessionWindows::startAsyncThread;
using DebugSessionWindows::stateSaveAreaCaptured;
using DebugSessionWindows::stateSaveAreaVA;
using DebugSessionWindows::wddm;
using DebugSessionWindows::writeGpuMemory;
using L0::DebugSessionImp::allThreads;
using L0::DebugSessionImp::apiEvents;
using L0::DebugSessionImp::attachTile;
using L0::DebugSessionImp::cleanRootSessionAfterDetach;
@ -1688,5 +1691,96 @@ TEST_F(DebugApiWindowsTest, GivenErrorCasesWhenReadingStateSaveAreThenMemoryIsNo
ASSERT_EQ(1, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_READ_GFX_MEMORY]);
}
TEST_F(DebugApiWindowsTest, GivenErrorCasesWhenInterruptImpIsCalledThenErrorIsReturned) {
auto session = std::make_unique<MockDebugSessionWindows>(zet_debug_config_t{0x1234}, device);
ASSERT_NE(nullptr, session);
session->wddm = mockWddm;
session->debugHandle = MockDebugSessionWindows::mockDebugHandle;
mockWddm->ntStatus = STATUS_WAIT_1;
EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, session->interruptImp(0));
EXPECT_EQ(1u, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_EU_CONTROL_INT_ALL]);
mockWddm->ntStatus = STATUS_SUCCESS;
mockWddm->escapeReturnStatus = DBGUMD_RETURN_DEBUGGER_ATTACH_DEVICE_BUSY;
EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, session->interruptImp(0));
EXPECT_EQ(2u, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_EU_CONTROL_INT_ALL]);
}
TEST_F(DebugApiWindowsTest, GivenInterruptImpSucceededThenSuccessIsReturned) {
auto session = std::make_unique<MockDebugSessionWindows>(zet_debug_config_t{0x1234}, device);
ASSERT_NE(nullptr, session);
session->wddm = mockWddm;
session->debugHandle = MockDebugSessionWindows::mockDebugHandle;
EXPECT_EQ(ZE_RESULT_SUCCESS, session->interruptImp(0));
EXPECT_EQ(1u, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_EU_CONTROL_INT_ALL]);
}
TEST_F(DebugApiWindowsTest, GivenErrorCasesWhenResumeImpIsCalledThenErrorIsReturned) {
auto session = std::make_unique<MockDebugSessionWindows>(zet_debug_config_t{0x1234}, device);
ASSERT_NE(nullptr, session);
session->wddm = mockWddm;
session->debugHandle = MockDebugSessionWindows::mockDebugHandle;
std::vector<EuThread::ThreadId> threads{{0, 0, 0, 0, 0}, {0, 0, 0, 0, 1}};
mockWddm->ntStatus = STATUS_WAIT_1;
EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, session->resumeImp(threads, 0));
EXPECT_EQ(1u, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_EU_CONTROL_CLR_ATT_BIT]);
mockWddm->ntStatus = STATUS_SUCCESS;
mockWddm->escapeReturnStatus = DBGUMD_RETURN_DEBUGGER_ATTACH_DEVICE_BUSY;
EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, session->resumeImp(threads, 0));
EXPECT_EQ(2u, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_EU_CONTROL_CLR_ATT_BIT]);
}
TEST_F(DebugApiWindowsTest, GivenResumeWARequiredWhenCallingResumeThenWaIsAppliedToBitmask) {
auto session = std::make_unique<MockDebugSessionWindows>(zet_debug_config_t{0x1234}, device);
ASSERT_NE(nullptr, session);
SIP::version version = {2, 0, 0};
initStateSaveArea(session->stateSaveAreaHeader, version);
session->stateSaveAreaVA = reinterpret_cast<uint64_t>(session->stateSaveAreaHeader.data());
session->debugHandle = MockDebugSessionWindows::mockDebugHandle;
mockWddm->srcReadBuffer = mockWddm->dstWriteBuffer = session->stateSaveAreaHeader.data();
mockWddm->srcReadBufferBaseAddress = mockWddm->dstWriteBufferBaseAddress = session->stateSaveAreaVA;
session->wddm = mockWddm;
ze_device_thread_t thread = {0, 0, 0, 0};
session->allThreads[EuThread::ThreadId(0, thread)]->stopThread(1u);
auto result = session->resume(thread);
EXPECT_EQ(result, ZE_RESULT_SUCCESS);
EXPECT_EQ(1, mockWddm->dbgUmdEscapeActionCalled[DBGUMD_ACTION_EU_CONTROL_CLR_ATT_BIT]);
auto bitmask = mockWddm->euControlBitmask.get();
EXPECT_EQ(1u, bitmask[0]);
auto &l0HwHelper = L0HwHelper::get(neoDevice->getHardwareInfo().platform.eRenderCoreFamily);
if (l0HwHelper.isResumeWARequired()) {
EXPECT_EQ(1u, bitmask[4]);
} else {
EXPECT_EQ(0u, bitmask[4]);
}
thread = {0, 0, 4, 0};
session->allThreads[EuThread::ThreadId(0, thread)]->stopThread(1u);
result = session->resume(thread);
EXPECT_EQ(result, ZE_RESULT_SUCCESS);
bitmask = mockWddm->euControlBitmask.get();
if (l0HwHelper.isResumeWARequired()) {
EXPECT_EQ(1u, bitmask[0]);
EXPECT_EQ(1u, bitmask[4]);
} else {
EXPECT_EQ(0u, bitmask[0]);
EXPECT_EQ(1u, bitmask[4]);
}
}
} // namespace ult
} // namespace L0

View File

@ -102,7 +102,12 @@ struct WddmEuDebugInterfaceMock : public WddmMock {
case DBGUMD_ACTION_WRITE_GFX_MEMORY: {
void *src = reinterpret_cast<void *>(pEscapeInfo->KmEuDbgL0EscapeInfo.ReadGfxMemoryParams.MemoryBufferPtr);
size_t size = pEscapeInfo->KmEuDbgL0EscapeInfo.ReadGfxMemoryParams.MemoryBufferSize;
memcpy(testBuffer, src, size);
if (dstWriteBuffer) {
auto offsetInMemory = pEscapeInfo->KmEuDbgL0EscapeInfo.ReadGfxMemoryParams.GpuVirtualAddr - dstWriteBufferBaseAddress;
memcpy(reinterpret_cast<char *>(dstWriteBuffer) + offsetInMemory, src, size);
} else {
memcpy(testBuffer, src, size);
}
pEscapeInfo->KmEuDbgL0EscapeInfo.EscapeReturnStatus = escapeReturnStatus;
break;
}
@ -123,6 +128,17 @@ struct WddmEuDebugInterfaceMock : public WddmMock {
pEscapeInfo->KmEuDbgL0EscapeInfo.EscapeReturnStatus = escapeReturnStatus;
break;
}
case DBGUMD_ACTION_EU_CONTROL_CLR_ATT_BIT: {
if (pEscapeInfo->KmEuDbgL0EscapeInfo.EuControlClrAttBitParams.BitMaskSizeInBytes != 0) {
euControlBitmaskSize = pEscapeInfo->KmEuDbgL0EscapeInfo.EuControlClrAttBitParams.BitMaskSizeInBytes;
euControlBitmask = std::make_unique<uint8_t[]>(euControlBitmaskSize);
memcpy(euControlBitmask.get(), reinterpret_cast<void *>(pEscapeInfo->KmEuDbgL0EscapeInfo.EuControlClrAttBitParams.BitmaskArrayPtr), euControlBitmaskSize);
}
break;
}
case DBGUMD_ACTION_EU_CONTROL_INT_ALL: {
break;
}
}
return ntStatus;
@ -179,6 +195,11 @@ struct WddmEuDebugInterfaceMock : public WddmMock {
uint64_t mockGpuVa = 0x12345678;
void *srcReadBuffer = nullptr;
uint64_t srcReadBufferBaseAddress = 0;
void *dstWriteBuffer = nullptr;
uint64_t dstWriteBufferBaseAddress = 0;
std::unique_ptr<uint8_t[]> euControlBitmask;
size_t euControlBitmaskSize = 0;
};
} // namespace NEO