feature: Add sync host event handling on windows

Resolves: NEO-13744
Signed-off-by: Jemale Lockett <jemale.lockett@intel.com>
This commit is contained in:
Jemale Lockett 2025-05-09 15:48:51 +00:00 committed by Compute-Runtime-Automation
parent fa1e3fd6a2
commit 8b508fd15f
10 changed files with 146 additions and 59 deletions

View File

@ -1682,7 +1682,9 @@ ze_result_t DebugSessionImp::isValidNode(uint64_t vmHandle, uint64_t gpuVa, SIP:
ze_result_t DebugSessionImp::readFifo(uint64_t vmHandle, std::vector<EuThread::ThreadId> &threadsWithAttention) {
auto stateSaveAreaHeader = getStateSaveAreaHeader();
if (stateSaveAreaHeader->versionHeader.version.major != 3) {
if (!stateSaveAreaHeader) {
return ZE_RESULT_ERROR_UNKNOWN;
} else if (stateSaveAreaHeader->versionHeader.version.major != 3) {
return ZE_RESULT_SUCCESS;
}

View File

@ -180,7 +180,7 @@ struct DebugSessionImp : DebugSession {
int64_t interruptTimeout = 2000;
std::unordered_map<uint64_t, AttentionEventFields> attentionEventContext{};
std::chrono::milliseconds lastFifoReadTime = std::chrono::milliseconds(0);
virtual void updateStoppedThreadsAndCheckTriggerEvents(const AttentionEventFields &attention, uint32_t tileIndex, std::vector<EuThread::ThreadId> &threadsWithAttention) = 0;
virtual ze_result_t updateStoppedThreadsAndCheckTriggerEvents(const AttentionEventFields &attention, uint32_t tileIndex, std::vector<EuThread::ThreadId> &threadsWithAttention) = 0;
std::chrono::high_resolution_clock::time_point interruptTime;
std::atomic<bool> interruptSent = false;

View File

@ -684,10 +684,10 @@ ze_result_t DebugSessionLinux::getElfOffset(const zet_debug_memory_space_desc_t
return status;
}
void DebugSessionLinux::updateStoppedThreadsAndCheckTriggerEvents(const AttentionEventFields &attention, uint32_t tileIndex, std::vector<EuThread::ThreadId> &threadsWithAttention) {
ze_result_t DebugSessionLinux::updateStoppedThreadsAndCheckTriggerEvents(const AttentionEventFields &attention, uint32_t tileIndex, std::vector<EuThread::ThreadId> &threadsWithAttention) {
auto vmHandle = getVmHandleFromClientAndlrcHandle(attention.clientHandle, attention.lrcHandle);
if (vmHandle == invalidHandle) {
return;
return ZE_RESULT_ERROR_UNKNOWN;
}
auto hwInfo = connectedDevice->getHwInfo();
@ -745,6 +745,7 @@ void DebugSessionLinux::updateStoppedThreadsAndCheckTriggerEvents(const Attentio
} else {
checkTriggerEventsForAttention();
}
return ZE_RESULT_SUCCESS;
}
ze_result_t DebugSessionLinux::getISAVMHandle(uint32_t deviceIndex, const zet_debug_memory_space_desc_t *desc, size_t size, uint64_t &vmHandle) {

View File

@ -253,7 +253,7 @@ struct DebugSessionLinux : DebugSessionImp {
return allInstancesRemoved;
}
void updateStoppedThreadsAndCheckTriggerEvents(const AttentionEventFields &attention, uint32_t tileIndex, std::vector<EuThread::ThreadId> &threadsWithAttention) override;
ze_result_t updateStoppedThreadsAndCheckTriggerEvents(const AttentionEventFields &attention, uint32_t tileIndex, std::vector<EuThread::ThreadId> &threadsWithAttention) override;
virtual void updateContextAndLrcHandlesForThreadsWithAttention(EuThread::ThreadId threadId, const AttentionEventFields &attention) = 0;
virtual uint64_t getVmHandleFromClientAndlrcHandle(uint64_t clientHandle, uint64_t lrcHandle) = 0;
virtual std::unique_lock<std::mutex> getThreadStateMutexForTileSession(uint32_t tileIndex) = 0;

View File

@ -1003,7 +1003,9 @@ void DebugSessionLinuxi915::handleAttentionEvent(prelim_drm_i915_debug_event_eu_
attentionEventFields.contextHandle = attention->ctx_handle;
attentionEventFields.lrcHandle = attention->lrc_handle;
return updateStoppedThreadsAndCheckTriggerEvents(attentionEventFields, tileIndex, threadsWithAttention);
if (updateStoppedThreadsAndCheckTriggerEvents(attentionEventFields, tileIndex, threadsWithAttention) != ZE_RESULT_SUCCESS) {
PRINT_DEBUGGER_ERROR_LOG("Failed to update stopped threads and check trigger events\n", "");
}
}
std::unique_lock<std::mutex> DebugSessionLinuxi915::getThreadStateMutexForTileSession(uint32_t tileIndex) {

View File

@ -749,7 +749,9 @@ void DebugSessionLinuxXe::handleAttentionEvent(NEO::EuDebugEventEuAttention *att
attentionEventFields.contextHandle = attention->execQueueHandle;
attentionEventFields.lrcHandle = attention->lrcHandle;
return updateStoppedThreadsAndCheckTriggerEvents(attentionEventFields, 0, threadsWithAttention);
if (updateStoppedThreadsAndCheckTriggerEvents(attentionEventFields, 0, threadsWithAttention) != ZE_RESULT_SUCCESS) {
PRINT_DEBUGGER_ERROR_LOG("Failed to update stopped threads and check trigger events\n", "");
}
}
int DebugSessionLinuxXe::threadControlInterruptAll() {

View File

@ -126,6 +126,7 @@ void *DebugSessionWindows::asyncThreadFunction(void *arg) {
while (self->asyncThread.threadActive) {
self->readAndHandleEvent(100);
self->pollFifo();
self->generateEventsAndResumeStoppedThreads();
self->sendInterrupts();
}
@ -195,6 +196,8 @@ ze_result_t DebugSessionWindows::readAndHandleEvent(uint64_t timeoutMs) {
return handleDeviceCreateDestroyEvent(eventParamsBuffer.eventParamsBuffer.DeviceCreateDestroyEventParams);
case DBGUMD_READ_EVENT_CREATE_DEBUG_DATA:
return handleCreateDebugDataEvent(eventParamsBuffer.eventParamsBuffer.ReadCreateDebugDataParams);
case DBGUMD_READ_EVENT_SYNC_HOST:
return handleSyncHostEvent(eventParamsBuffer.eventParamsBuffer.SyncHostDataParams);
default:
break;
}
@ -242,57 +245,15 @@ ze_result_t DebugSessionWindows::handleEuAttentionBitsEvent(DBGUMD_READ_EVENT_EU
euAttentionBitsParams.hContextHandle, euAttentionBitsParams.LRCA,
euAttentionBitsParams.BitMaskSizeInBytes, &euAttentionBitsParams.BitmaskArrayPtr);
auto hwInfo = connectedDevice->getHwInfo();
auto &l0GfxCoreHelper = connectedDevice->getNEODevice()->getRootDeviceEnvironment().getHelper<L0GfxCoreHelper>();
std::vector<EuThread::ThreadId> threadsWithAttention;
newAttentionRaised();
AttentionEventFields attentionEventFields;
attentionEventFields.bitmask = reinterpret_cast<uint8_t *>(&euAttentionBitsParams.BitmaskArrayPtr);
attentionEventFields.bitmaskSize = euAttentionBitsParams.BitMaskSizeInBytes;
attentionEventFields.contextHandle = euAttentionBitsParams.hContextHandle;
attentionEventFields.lrcHandle = euAttentionBitsParams.LRCA;
auto threadsWithAttention = l0GfxCoreHelper.getThreadsFromAttentionBitmask(hwInfo, 0u,
reinterpret_cast<uint8_t *>(&euAttentionBitsParams.BitmaskArrayPtr),
euAttentionBitsParams.BitMaskSizeInBytes);
printBitmask(reinterpret_cast<uint8_t *>(&euAttentionBitsParams.BitmaskArrayPtr), euAttentionBitsParams.BitMaskSizeInBytes);
PRINT_DEBUGGER_THREAD_LOG("ATTENTION received for thread count = %d\n", (int)threadsWithAttention.size());
if (threadsWithAttention.size() > 0) {
uint64_t memoryHandle = DebugSessionWindows::invalidHandle;
{
if (allContexts.empty()) {
return ZE_RESULT_ERROR_UNINITIALIZED;
}
memoryHandle = *allContexts.begin();
}
auto gpuVa = getContextStateSaveAreaGpuVa(memoryHandle);
auto stateSaveAreaSize = getContextStateSaveAreaSize(memoryHandle);
auto stateSaveReadResult = ZE_RESULT_ERROR_UNKNOWN;
std::unique_lock<std::mutex> lock(threadStateMutex);
if (gpuVa != 0 && stateSaveAreaSize != 0) {
std::vector<EuThread::ThreadId> newThreads;
getNotStoppedThreads(threadsWithAttention, newThreads);
if (newThreads.size() > 0) {
allocateStateSaveAreaMemory(stateSaveAreaSize);
stateSaveReadResult = readGpuMemory(memoryHandle, stateSaveAreaMemory.data(), stateSaveAreaSize, gpuVa);
}
} else {
PRINT_DEBUGGER_ERROR_LOG("Context state save area bind info invalid\n", "");
DEBUG_BREAK_IF(true);
}
if (stateSaveReadResult == ZE_RESULT_SUCCESS) {
for (auto &threadId : threadsWithAttention) {
PRINT_DEBUGGER_THREAD_LOG("ATTENTION event for thread: %s\n", EuThread::toString(threadId).c_str());
addThreadToNewlyStoppedFromRaisedAttention(threadId, memoryHandle, stateSaveAreaMemory.data());
}
}
}
checkTriggerEventsForAttention();
return ZE_RESULT_SUCCESS;
return updateStoppedThreadsAndCheckTriggerEvents(attentionEventFields, 0, threadsWithAttention);
}
ze_result_t DebugSessionWindows::handleAllocationDataEvent(uint32_t seqNo, DBGUMD_READ_EVENT_READ_ALLOCATION_DATA_PARAMS &allocationDataParams) {
@ -395,6 +356,85 @@ ze_result_t DebugSessionWindows::handleCreateDebugDataEvent(DBGUMD_READ_EVENT_CR
return ZE_RESULT_SUCCESS;
}
ze_result_t DebugSessionWindows::handleSyncHostEvent(DBGUMD_READ_EVENT_SYNC_HOST_DATA_PARAMS &readEventSyncHostDataParams) {
PRINT_DEBUGGER_INFO_LOG("DBGUMD_READ_EVENT_SYNC_HOST: hContextHandle=0x%llX\n",
readEventSyncHostDataParams.hContextHandle);
uint64_t memoryHandle = DebugSessionWindows::invalidHandle;
{
std::unique_lock<std::mutex> lock(asyncThreadMutex);
if (allContexts.empty()) {
return ZE_RESULT_ERROR_UNINITIALIZED;
}
memoryHandle = *allContexts.begin();
}
AttentionEventFields attentionEventFields = {};
attentionEventFields.clientHandle = debugHandle;
attentionEventFields.contextHandle = readEventSyncHostDataParams.hContextHandle;
attentionEventContext[memoryHandle] = attentionEventFields;
handleStoppedThreads();
return ZE_RESULT_SUCCESS;
}
ze_result_t DebugSessionWindows::updateStoppedThreadsAndCheckTriggerEvents(const AttentionEventFields &attention, uint32_t tileIndex, std::vector<EuThread::ThreadId> &threadsWithAttention) {
auto hwInfo = connectedDevice->getHwInfo();
auto &l0GfxCoreHelper = connectedDevice->getL0GfxCoreHelper();
if (threadsWithAttention.size() == 0) {
threadsWithAttention = l0GfxCoreHelper.getThreadsFromAttentionBitmask(hwInfo, 0u,
attention.bitmask, attention.bitmaskSize);
printBitmask(attention.bitmask, attention.bitmaskSize);
}
PRINT_DEBUGGER_THREAD_LOG("ATTENTION for tile = %d thread count = %d\n", tileIndex, (int)threadsWithAttention.size());
if (threadsWithAttention.size() > 0) {
uint64_t memoryHandle = DebugSessionWindows::invalidHandle;
{
std::unique_lock<std::mutex> lock(asyncThreadMutex);
if (allContexts.empty()) {
PRINT_DEBUGGER_ERROR_LOG("No contexts found\n", "");
return ZE_RESULT_ERROR_UNINITIALIZED;
}
memoryHandle = *allContexts.begin();
}
auto gpuVa = getContextStateSaveAreaGpuVa(memoryHandle);
auto stateSaveAreaSize = getContextStateSaveAreaSize(memoryHandle);
auto stateSaveReadResult = ZE_RESULT_ERROR_UNKNOWN;
std::unique_lock<std::mutex> lock(threadStateMutex);
if (gpuVa != 0 && stateSaveAreaSize != 0) {
std::vector<EuThread::ThreadId> newThreads;
getNotStoppedThreads(threadsWithAttention, newThreads);
if (newThreads.size() > 0) {
allocateStateSaveAreaMemory(stateSaveAreaSize);
stateSaveReadResult = readGpuMemory(memoryHandle, stateSaveAreaMemory.data(), stateSaveAreaSize, gpuVa);
}
} else {
PRINT_DEBUGGER_ERROR_LOG("Context state save area bind info invalid\n", "");
DEBUG_BREAK_IF(true);
}
if (stateSaveReadResult == ZE_RESULT_SUCCESS) {
for (auto &threadId : threadsWithAttention) {
PRINT_DEBUGGER_THREAD_LOG("ATTENTION event for thread: %s\n", EuThread::toString(threadId).c_str());
addThreadToNewlyStoppedFromRaisedAttention(threadId, memoryHandle, stateSaveAreaMemory.data());
}
}
}
checkTriggerEventsForAttention();
return ZE_RESULT_SUCCESS;
}
ze_result_t DebugSessionWindows::acknowledgeEventImp(uint32_t seqNo, uint32_t eventType) {
PRINT_DEBUGGER_INFO_LOG("DBGUMD_ACTION_ACKNOWLEDGE_EVENT: seqNo: %d eventType: %d\n", seqNo, eventType);
KM_ESCAPE_INFO escapeInfo = {};

View File

@ -78,6 +78,7 @@ struct DebugSessionWindows : DebugSessionImp {
ze_result_t handleContextCreateDestroyEvent(DBGUMD_READ_EVENT_CONTEXT_CREATE_DESTROY_EVENT_PARAMS &contextCreateDestroyParams);
ze_result_t handleDeviceCreateDestroyEvent(DBGUMD_READ_EVENT_DEVICE_CREATE_DESTROY_EVENT_PARAMS &deviceCreateDestroyParams);
ze_result_t handleCreateDebugDataEvent(DBGUMD_READ_EVENT_CREATE_DEBUG_DATA_PARAMS &createDebugDataParams);
ze_result_t handleSyncHostEvent(DBGUMD_READ_EVENT_SYNC_HOST_DATA_PARAMS &syncHostDataParams);
ze_result_t readAllocationDebugData(uint32_t seqNo, uint64_t umdDataBufferPtr, void *outBuf, size_t outBufSize);
void enqueueApiEvent(zet_debug_event_t &debugEvent) override;
@ -95,7 +96,7 @@ struct DebugSessionWindows : DebugSessionImp {
UNRECOVERABLE_IF(true);
}
void updateStoppedThreadsAndCheckTriggerEvents(const AttentionEventFields &attention, uint32_t tileIndex, std::vector<EuThread::ThreadId> &threadsWithAttention) override {}
ze_result_t updateStoppedThreadsAndCheckTriggerEvents(const AttentionEventFields &attention, uint32_t tileIndex, std::vector<EuThread::ThreadId> &threadsWithAttention) override;
static void *asyncThreadFunction(void *arg);

View File

@ -351,7 +351,7 @@ struct MockDebugSession : public L0::DebugSessionImp {
return DebugSessionImp::readThreadScratchRegisters(thread, start, count, pRegisterValues);
}
void updateStoppedThreadsAndCheckTriggerEvents(const AttentionEventFields &attention, uint32_t tileIndex, std::vector<EuThread::ThreadId> &threadsWithAttention) override {}
ze_result_t updateStoppedThreadsAndCheckTriggerEvents(const AttentionEventFields &attention, uint32_t tileIndex, std::vector<EuThread::ThreadId> &threadsWithAttention) override { return ZE_RESULT_SUCCESS; }
void resumeAccidentallyStoppedThreads(const std::vector<EuThread::ThreadId> &threadIds) override {
resumeAccidentallyStoppedCalled++;
return DebugSessionImp::resumeAccidentallyStoppedThreads(threadIds);

View File

@ -33,6 +33,7 @@ struct MockDebugSessionWindows : DebugSessionWindows {
using DebugSessionWindows::allModules;
using DebugSessionWindows::allThreads;
using DebugSessionWindows::asyncThread;
using DebugSessionWindows::attentionEventContext;
using DebugSessionWindows::calculateThreadSlotOffset;
using DebugSessionWindows::closeAsyncThread;
using DebugSessionWindows::debugArea;
@ -2021,5 +2022,43 @@ TEST_F(DebugApiWindowsTest, GivenResumeImpCalledThenBitmaskIsCorrect) {
EXPECT_EQ(0u, bitmask[4]);
}
TEST_F(DebugApiWindowsTest, givenSyncHostEventReceivedThenEventIsHandledAndAttentionEventContextUpdated) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto session = std::make_unique<MockDebugSessionWindows>(config, device);
session->wddm = mockWddm;
session->allContexts = {};
session->allContexts.insert(0x01);
auto &l0GfxCoreHelper = neoDevice->getRootDeviceEnvironment().getHelper<L0GfxCoreHelper>();
if (l0GfxCoreHelper.threadResumeRequiresUnlock()) {
mockWddm->numEvents = 1;
mockWddm->eventQueue[0].readEventType = DBGUMD_READ_EVENT_SYNC_HOST;
mockWddm->eventQueue[0].eventParamsBuffer.eventParamsBuffer.SyncHostDataParams.hContextHandle = 0x12345;
EXPECT_EQ(ZE_RESULT_SUCCESS, session->readAndHandleEvent(100));
EXPECT_EQ(1u, session->attentionEventContext.size());
}
}
TEST_F(DebugApiWindowsTest, givenErrorCasesWhenHandlingSyncHostThenErrorIsReturned) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto session = std::make_unique<MockDebugSessionWindows>(config, device);
session->wddm = mockWddm;
session->allContexts = {};
auto &l0GfxCoreHelper = neoDevice->getRootDeviceEnvironment().getHelper<L0GfxCoreHelper>();
if (l0GfxCoreHelper.threadResumeRequiresUnlock()) {
mockWddm->numEvents = 1;
mockWddm->eventQueue[0].readEventType = DBGUMD_READ_EVENT_SYNC_HOST;
mockWddm->eventQueue[0].eventParamsBuffer.eventParamsBuffer.SyncHostDataParams.hContextHandle = 0x12345;
EXPECT_EQ(ZE_RESULT_ERROR_UNINITIALIZED, session->readAndHandleEvent(100));
}
}
} // namespace ult
} // namespace L0