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:
parent
403b49e987
commit
12c7f32679
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue