diff --git a/level_zero/tools/source/debug/debug_session_imp.cpp b/level_zero/tools/source/debug/debug_session_imp.cpp index 8cac9a39b1..782afab037 100644 --- a/level_zero/tools/source/debug/debug_session_imp.cpp +++ b/level_zero/tools/source/debug/debug_session_imp.cpp @@ -677,7 +677,7 @@ bool DebugSessionImp::readSystemRoutineIdent(EuThread *thread, uint64_t memoryHa return true; } -void DebugSessionImp::markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(EuThread::ThreadId threadId, uint64_t memoryHandle) { +void DebugSessionImp::addThreadToNewlyStoppedFromRaisedAttention(EuThread::ThreadId threadId, uint64_t memoryHandle) { SIP::sr_ident srMagic = {{0}}; srMagic.count = 0; @@ -702,24 +702,7 @@ void DebugSessionImp::markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttentio allThreads[threadId]->stopThread(memoryHandle); } - bool threadWasInterrupted = false; - - for (auto &request : pendingInterrupts) { - ze_device_thread_t apiThread = convertToApi(threadId); - - auto isInterrupted = checkSingleThreadWithinDeviceThread(apiThread, request.first); - - if (isInterrupted) { - // mark pending interrupt as completed successfully only when new thread has been stopped - if (!wasStopped) { - request.second = true; - } - threadWasInterrupted = true; - allThreads[threadId]->reportAsStopped(); - } - } - - if (!threadWasInterrupted && !wasStopped) { + if (!wasStopped) { newlyStoppedThreads.push_back(threadId); } } @@ -737,8 +720,9 @@ void DebugSessionImp::generateEventsAndResumeStoppedThreads() { if (triggerEvents) { std::vector resumeThreads; std::vector stoppedThreadsToReport; + std::vector interruptedThreads; - fillResumeAndStoppedThreadsFromNewlyStopped(resumeThreads, stoppedThreadsToReport); + fillResumeAndStoppedThreadsFromNewlyStopped(resumeThreads, stoppedThreadsToReport, interruptedThreads); resumeAccidentallyStoppedThreads(resumeThreads); generateEventsForPendingInterrupts(); @@ -756,7 +740,7 @@ bool DebugSessionImp::isForceExceptionOrForceExternalHaltOnlyExceptionReason(uin return (((cr0[1] & cr0ExceptionBitmask) & (~cr0ForcedExcpetionBitmask)) == 0); } -void DebugSessionImp::fillResumeAndStoppedThreadsFromNewlyStopped(std::vector &resumeThreads, std::vector &stoppedThreadsToReport) { +void DebugSessionImp::fillResumeAndStoppedThreadsFromNewlyStopped(std::vector &resumeThreads, std::vector &stoppedThreadsToReport, std::vector &interruptedThreads) { if (newlyStoppedThreads.empty()) { return; @@ -770,8 +754,27 @@ void DebugSessionImp::fillResumeAndStoppedThreadsFromNewlyStopped(std::vectortoString().c_str()); - resumeThreads.push_back(newlyStopped); + bool threadWasInterrupted = false; + + for (auto &request : pendingInterrupts) { + ze_device_thread_t apiThread = convertToApi(newlyStopped); + + auto isInterrupted = checkSingleThreadWithinDeviceThread(apiThread, request.first); + + if (isInterrupted) { + // mark pending interrupt as completed successfully + request.second = true; + threadWasInterrupted = true; + allThreads[newlyStopped]->reportAsStopped(); + } + } + + if (threadWasInterrupted) { + interruptedThreads.push_back(newlyStopped); + } else { + PRINT_DEBUGGER_THREAD_LOG("RESUME accidentally stopped thread = %s\n", allThreads[newlyStopped]->toString().c_str()); + resumeThreads.push_back(newlyStopped); + } } else { PRINT_DEBUGGER_THREAD_LOG("Newly stopped thread = %s, exception bits = %#010" PRIx32 "\n", allThreads[newlyStopped]->toString().c_str(), reg[1]); stoppedThreadsToReport.push_back(newlyStopped); diff --git a/level_zero/tools/source/debug/debug_session_imp.h b/level_zero/tools/source/debug/debug_session_imp.h index f4cd6282f8..b5c9fe206a 100644 --- a/level_zero/tools/source/debug/debug_session_imp.h +++ b/level_zero/tools/source/debug/debug_session_imp.h @@ -95,8 +95,8 @@ struct DebugSessionImp : DebugSession { ze_result_t readSbaRegisters(EuThread::ThreadId thread, uint32_t start, uint32_t count, void *pRegisterValues); MOCKABLE_VIRTUAL bool isForceExceptionOrForceExternalHaltOnlyExceptionReason(uint32_t *cr0); void sendInterrupts(); - MOCKABLE_VIRTUAL void markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(EuThread::ThreadId threadId, uint64_t memoryHandle); - MOCKABLE_VIRTUAL void fillResumeAndStoppedThreadsFromNewlyStopped(std::vector &resumeThreads, std::vector &stoppedThreadsToReport); + MOCKABLE_VIRTUAL void addThreadToNewlyStoppedFromRaisedAttention(EuThread::ThreadId threadId, uint64_t memoryHandle); + MOCKABLE_VIRTUAL void fillResumeAndStoppedThreadsFromNewlyStopped(std::vector &resumeThreads, std::vector &stoppedThreadsToReport, std::vector &interruptedThreads); MOCKABLE_VIRTUAL void generateEventsAndResumeStoppedThreads(); MOCKABLE_VIRTUAL void resumeAccidentallyStoppedThreads(const std::vector &threadIds); MOCKABLE_VIRTUAL void generateEventsForStoppedThreads(const std::vector &threadIds); diff --git a/level_zero/tools/source/debug/linux/prelim/debug_session.cpp b/level_zero/tools/source/debug/linux/prelim/debug_session.cpp index 645f66590c..5123d247b7 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session.cpp +++ b/level_zero/tools/source/debug/linux/prelim/debug_session.cpp @@ -333,12 +333,12 @@ void *DebugSessionLinux::asyncThreadFunction(void *arg) { if (self->tileSessionsEnabled) { for (size_t tileIndex = 0; tileIndex < self->tileSessions.size(); tileIndex++) { - static_cast(self->tileSessions[tileIndex].first)->sendInterrupts(); static_cast(self->tileSessions[tileIndex].first)->generateEventsAndResumeStoppedThreads(); + static_cast(self->tileSessions[tileIndex].first)->sendInterrupts(); } } else { - self->sendInterrupts(); self->generateEventsAndResumeStoppedThreads(); + self->sendInterrupts(); } } @@ -1296,9 +1296,9 @@ void DebugSessionLinux::handleAttentionEvent(prelim_drm_i915_debug_event_eu_atte PRINT_DEBUGGER_THREAD_LOG("ATTENTION event for thread: %s\n", EuThread::toString(threadId).c_str()); if (tileSessionsEnabled) { - static_cast(tileSessions[tileIndex].first)->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(threadId, vmHandle); + static_cast(tileSessions[tileIndex].first)->addThreadToNewlyStoppedFromRaisedAttention(threadId, vmHandle); } else { - markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(threadId, vmHandle); + addThreadToNewlyStoppedFromRaisedAttention(threadId, vmHandle); } } diff --git a/level_zero/tools/source/debug/windows/debug_session.cpp b/level_zero/tools/source/debug/windows/debug_session.cpp index 48eb300372..15c17c1009 100644 --- a/level_zero/tools/source/debug/windows/debug_session.cpp +++ b/level_zero/tools/source/debug/windows/debug_session.cpp @@ -126,8 +126,8 @@ void *DebugSessionWindows::asyncThreadFunction(void *arg) { while (self->asyncThread.threadActive) { self->readAndHandleEvent(100); - self->sendInterrupts(); self->generateEventsAndResumeStoppedThreads(); + self->sendInterrupts(); } PRINT_DEBUGGER_INFO_LOG("Debugger async thread closing\n", ""); @@ -264,7 +264,7 @@ ze_result_t DebugSessionWindows::handleEuAttentionBitsEvent(DBGUMD_READ_EVENT_EU for (auto &threadId : threadsWithAttention) { PRINT_DEBUGGER_THREAD_LOG("ATTENTION event for thread: %s\n", EuThread::toString(threadId).c_str()); - markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(threadId, memoryHandle); + addThreadToNewlyStoppedFromRaisedAttention(threadId, memoryHandle); } checkTriggerEventsForAttention(); diff --git a/level_zero/tools/test/unit_tests/sources/debug/debug_session_tests.cpp b/level_zero/tools/test/unit_tests/sources/debug/debug_session_tests.cpp index 13dbdf0faa..0bac596e9e 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/debug_session_tests.cpp +++ b/level_zero/tools/test/unit_tests/sources/debug/debug_session_tests.cpp @@ -223,11 +223,36 @@ TEST(DebugSessionTest, givenPendingInteruptWhenHandlingThreadWithAttentionThenPe EXPECT_EQ(ZE_RESULT_SUCCESS, result); sessionMock->sendInterrupts(); - sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(thread, 1u); + sessionMock->addThreadToNewlyStoppedFromRaisedAttention(thread, 1u); EXPECT_TRUE(sessionMock->allThreads[thread]->isStopped()); + EXPECT_FALSE(sessionMock->pendingInterrupts[0].second); + EXPECT_EQ(1u, sessionMock->newlyStoppedThreads.size()); + + sessionMock->triggerEvents = true; + + std::vector resumeThreads; + std::vector stoppedThreadsToReport; + std::vector interruptedThreads; + + sessionMock->fillResumeAndStoppedThreadsFromNewlyStopped(resumeThreads, stoppedThreadsToReport, interruptedThreads); + EXPECT_EQ(1u, interruptedThreads.size()); EXPECT_TRUE(sessionMock->pendingInterrupts[0].second); + + sessionMock->generateEventsForPendingInterrupts(); + + ASSERT_EQ(1u, sessionMock->apiEvents.size()); + + zet_debug_event_t debugEvent = {}; + sessionMock->readEvent(0, &debugEvent); + + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_THREAD_STOPPED, debugEvent.type); + EXPECT_EQ(apiThread.thread, debugEvent.info.thread.thread.thread); + EXPECT_EQ(apiThread.eu, debugEvent.info.thread.thread.eu); + EXPECT_EQ(apiThread.subslice, debugEvent.info.thread.thread.subslice); + EXPECT_EQ(apiThread.slice, debugEvent.info.thread.thread.slice); + EXPECT_EQ(0u, sessionMock->newlyStoppedThreads.size()); } @@ -253,7 +278,7 @@ TEST(DebugSessionTest, givenPreviouslyStoppedThreadAndPendingInterruptWhenHandli sessionMock->onlyForceException = false; sessionMock->allThreads[thread]->stopThread(1u); - sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(thread, 1u); + sessionMock->addThreadToNewlyStoppedFromRaisedAttention(thread, 1u); EXPECT_TRUE(sessionMock->allThreads[thread]->isStopped()); @@ -269,6 +294,85 @@ TEST(DebugSessionTest, givenPreviouslyStoppedThreadAndPendingInterruptWhenHandli EXPECT_TRUE(DebugSession::areThreadsEqual(apiThread, sessionMock->apiEvents.front().info.thread.thread)); } +TEST(DebugSessionTest, givenThreadsStoppedOnBreakpointAndInterruptedWhenHandlingThreadsStateThenThreadsWithBreakpointExceptionsHaveDistinctEventsTriggered) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + auto hwInfo = *NEO::defaultHwInfo.get(); + + NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + + auto sessionMock = std::make_unique(config, &deviceImp); + + sessionMock->callBaseIsForceExceptionOrForceExternalHaltOnlyExceptionReason = true; + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + { + auto pStateSaveAreaHeader = reinterpret_cast(sessionMock->stateSaveAreaHeader.data()); + auto size = pStateSaveAreaHeader->versionHeader.size * 8 + + pStateSaveAreaHeader->regHeader.state_area_offset + + pStateSaveAreaHeader->regHeader.state_save_size * 16; + sessionMock->stateSaveAreaHeader.resize(size); + } + + auto *regdesc = &(reinterpret_cast(sessionMock->stateSaveAreaHeader.data()))->regHeader.cr; + uint32_t cr0[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + + ze_device_thread_t interruptThread = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX}; + ze_device_thread_t bpThread = {0, 0, 0, 0}; + EuThread::ThreadId threadWithBp(0, 0, 0, 0, 0); + EuThread::ThreadId threadWithFe(0, 0, 0, 0, 1); + + auto result = sessionMock->interrupt(interruptThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + sessionMock->sendInterrupts(); + + cr0[1] = 1 << 15 | 1 << 31; + sessionMock->registersAccessHelper(sessionMock->allThreads[threadWithBp].get(), regdesc, 0, 1, cr0, true); + + cr0[1] = 1 << 26; + sessionMock->registersAccessHelper(sessionMock->allThreads[threadWithFe].get(), regdesc, 0, 1, cr0, true); + + sessionMock->addThreadToNewlyStoppedFromRaisedAttention(threadWithBp, 1u); + sessionMock->addThreadToNewlyStoppedFromRaisedAttention(threadWithFe, 1u); + + EXPECT_TRUE(sessionMock->allThreads[threadWithBp]->isStopped()); + EXPECT_TRUE(sessionMock->allThreads[threadWithFe]->isStopped()); + + sessionMock->expectedAttentionEvents = 0; + sessionMock->checkTriggerEventsForAttention(); + + sessionMock->generateEventsAndResumeStoppedThreads(); + + EXPECT_EQ(2u, sessionMock->apiEvents.size()); + + uint32_t stoppedEvents = 0; + bool interruptEventFound = false; + bool bpThreadFound = false; + for (uint32_t i = 0; i < 2; i++) { + + zet_debug_event_t outputEvent = {}; + auto result = sessionMock->readEvent(0, &outputEvent); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + if (result == ZE_RESULT_SUCCESS) { + if (outputEvent.type == ZET_DEBUG_EVENT_TYPE_THREAD_STOPPED) { + stoppedEvents++; + if (DebugSession::areThreadsEqual(interruptThread, outputEvent.info.thread.thread)) { + interruptEventFound = true; + } else if (DebugSession::areThreadsEqual(bpThread, outputEvent.info.thread.thread)) { + bpThreadFound = true; + } + } + } + } + + EXPECT_EQ(2u, stoppedEvents); + EXPECT_TRUE(bpThreadFound); + EXPECT_TRUE(interruptEventFound); +} + TEST(DebugSessionTest, givenStoppedThreadWhenAddingNewlyStoppedThenThreadIsNotAdded) { zet_debug_config_t config = {}; config.pid = 0x1234; @@ -282,7 +386,7 @@ TEST(DebugSessionTest, givenStoppedThreadWhenAddingNewlyStoppedThenThreadIsNotAd EuThread::ThreadId thread(0, 0, 0, 0, 0); sessionMock->allThreads[thread]->stopThread(1u); - sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(thread, 1u); + sessionMock->addThreadToNewlyStoppedFromRaisedAttention(thread, 1u); EXPECT_EQ(0u, sessionMock->newlyStoppedThreads.size()); } @@ -302,7 +406,7 @@ TEST(DebugSessionTest, givenNoPendingInterruptAndStoppedThreadWithForceException sessionMock->threadStopped = true; sessionMock->onlyForceException = true; - sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(thread, 1u); + sessionMock->addThreadToNewlyStoppedFromRaisedAttention(thread, 1u); EXPECT_EQ(1u, sessionMock->newlyStoppedThreads.size()); EXPECT_FALSE(sessionMock->allThreads[thread]->isReportedAsStopped()); @@ -324,7 +428,7 @@ TEST(DebugSessionTest, givenNoPendingInterruptAndStoppedThreadWhenGeneratingEven sessionMock->onlyForceException = false; sessionMock->triggerEvents = true; - sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(thread, 1u); + sessionMock->addThreadToNewlyStoppedFromRaisedAttention(thread, 1u); EXPECT_EQ(1u, sessionMock->newlyStoppedThreads.size()); EXPECT_FALSE(sessionMock->allThreads[thread]->isReportedAsStopped()); @@ -352,7 +456,7 @@ TEST(DebugSessionTest, givenNoStoppedThreadWhenAddingNewlyStoppedThenThreadIsNot sessionMock->threadStopped = 0; EuThread::ThreadId thread(0, 0, 0, 0, 0); - sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(thread, 1u); + sessionMock->addThreadToNewlyStoppedFromRaisedAttention(thread, 1u); EXPECT_EQ(0u, sessionMock->newlyStoppedThreads.size()); } @@ -389,7 +493,7 @@ TEST(DebugSessionTest, givenTriggerEventsWhenGenerateEventsAndResumeCalledThenEv ze_device_thread_t apiThread2 = {0, 0, 1, 1}; sessionMock->pendingInterrupts.push_back({apiThread, true}); - sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(EuThread::ThreadId(0, apiThread2), 1u); + sessionMock->addThreadToNewlyStoppedFromRaisedAttention(EuThread::ThreadId(0, apiThread2), 1u); sessionMock->triggerEvents = true; sessionMock->interruptSent = true; @@ -481,7 +585,7 @@ TEST(DebugSessionTest, givenErrorFromReadSystemRoutineIdentWhenCheckingThreadSta sessionMock->readSystemRoutineIdentRetVal = false; EuThread::ThreadId thread(0, 0, 0, 0, 0); - sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(thread, 1u); + sessionMock->addThreadToNewlyStoppedFromRaisedAttention(thread, 1u); EXPECT_FALSE(sessionMock->allThreads[thread]->isStopped()); EXPECT_EQ(0u, sessionMock->newlyStoppedThreads.size()); @@ -552,11 +656,12 @@ TEST(DebugSessionTest, givenStoppedThreadsWhenFillingResumeAndStoppedThreadsFrom { std::vector resumeThreads; std::vector stoppedThreads; + std::vector interruptedThreads; sessionMock->allThreads[thread]->stopThread(1u); sessionMock->allThreads[thread2]->stopThread(1u); - sessionMock->fillResumeAndStoppedThreadsFromNewlyStopped(resumeThreads, stoppedThreads); + sessionMock->fillResumeAndStoppedThreadsFromNewlyStopped(resumeThreads, stoppedThreads, interruptedThreads); EXPECT_EQ(2u, resumeThreads.size()); EXPECT_EQ(0u, stoppedThreads.size()); } @@ -569,11 +674,12 @@ TEST(DebugSessionTest, givenStoppedThreadsWhenFillingResumeAndStoppedThreadsFrom { std::vector resumeThreads; std::vector stoppedThreads; + std::vector interruptedThreads; sessionMock->allThreads[thread]->stopThread(1u); sessionMock->allThreads[thread2]->stopThread(1u); - sessionMock->fillResumeAndStoppedThreadsFromNewlyStopped(resumeThreads, stoppedThreads); + sessionMock->fillResumeAndStoppedThreadsFromNewlyStopped(resumeThreads, stoppedThreads, interruptedThreads); EXPECT_EQ(0u, resumeThreads.size()); EXPECT_EQ(2u, stoppedThreads.size()); } @@ -590,8 +696,9 @@ TEST(DebugSessionTest, givenNoThreadsStoppedWhenCallingfillResumeAndStoppedThrea auto sessionMock = std::make_unique(config, &deviceImp); std::vector resumeThreads; std::vector stoppedThreads; + std::vector interruptedThreads; - sessionMock->fillResumeAndStoppedThreadsFromNewlyStopped(resumeThreads, stoppedThreads); + sessionMock->fillResumeAndStoppedThreadsFromNewlyStopped(resumeThreads, stoppedThreads, interruptedThreads); EXPECT_EQ(0u, sessionMock->readStateSaveAreaHeaderCalled); } diff --git a/level_zero/tools/test/unit_tests/sources/debug/linux/debug_session_fixtures_linux.h b/level_zero/tools/test/unit_tests/sources/debug/linux/debug_session_fixtures_linux.h index a6bd663fe8..48eb11c37e 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/linux/debug_session_fixtures_linux.h +++ b/level_zero/tools/test/unit_tests/sources/debug/linux/debug_session_fixtures_linux.h @@ -254,6 +254,8 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux { using L0::DebugSessionImp::detachTile; using L0::DebugSessionImp::enqueueApiEvent; using L0::DebugSessionImp::expectedAttentionEvents; + using L0::DebugSessionImp::fillResumeAndStoppedThreadsFromNewlyStopped; + using L0::DebugSessionImp::generateEventsForPendingInterrupts; using L0::DebugSessionImp::interruptSent; using L0::DebugSessionImp::isValidGpuAddress; using L0::DebugSessionImp::newAttentionRaised; @@ -456,9 +458,9 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux { return DebugSessionLinux::checkStoppedThreadsAndGenerateEvents(threads, memoryHandle, deviceIndex); } - void markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(EuThread::ThreadId threadId, uint64_t memoryHandle) override { - markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttentionCallCount++; - return DebugSessionImp::markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(threadId, memoryHandle); + void addThreadToNewlyStoppedFromRaisedAttention(EuThread::ThreadId threadId, uint64_t memoryHandle) override { + addThreadToNewlyStoppedFromRaisedAttentionCallCount++; + return DebugSessionImp::addThreadToNewlyStoppedFromRaisedAttention(threadId, memoryHandle); } TileDebugSessionLinux *createTileSession(const zet_debug_config_t &config, L0::Device *device, L0::DebugSessionImp *rootDebugSession) override; @@ -480,7 +482,7 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux { uint32_t interruptedDevice = std::numeric_limits::max(); uint32_t processPendingVmBindEventsCalled = 0; uint32_t checkStoppedThreadsAndGenerateEventsCallCount = 0; - uint32_t markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttentionCallCount = 0; + uint32_t addThreadToNewlyStoppedFromRaisedAttentionCallCount = 0; std::vector resumedDevices; std::vector> resumedThreads; diff --git a/level_zero/tools/test/unit_tests/sources/debug/linux/test_debug_api_linux.cpp b/level_zero/tools/test/unit_tests/sources/debug/linux/test_debug_api_linux.cpp index c420d46693..7e409d73e1 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/linux/test_debug_api_linux.cpp +++ b/level_zero/tools/test/unit_tests/sources/debug/linux/test_debug_api_linux.cpp @@ -5969,9 +5969,41 @@ TEST_F(DebugApiLinuxAttentionTest, GivenInterruptedThreadsWhenOnlySomeThreadsRai sessionMock->handleEvent(reinterpret_cast(data)); - EXPECT_EQ(0u, sessionMock->newlyStoppedThreads.size()); + EXPECT_EQ(1u, sessionMock->newlyStoppedThreads.size()); + EXPECT_FALSE(sessionMock->pendingInterrupts[0].second); + EXPECT_FALSE(sessionMock->pendingInterrupts[1].second); + + std::vector resumeThreads; + std::vector stoppedThreadsToReport; + std::vector interruptedThreads; + + sessionMock->fillResumeAndStoppedThreadsFromNewlyStopped(resumeThreads, stoppedThreadsToReport, interruptedThreads); + EXPECT_EQ(1u, interruptedThreads.size()); EXPECT_TRUE(sessionMock->pendingInterrupts[0].second); EXPECT_FALSE(sessionMock->pendingInterrupts[1].second); + + sessionMock->generateEventsForPendingInterrupts(); + // 2 pending interrupts + EXPECT_EQ(2u, sessionMock->apiEvents.size()); + + uint32_t stoppedEvents = 0; + uint32_t notAvailableEvents = 0; + + for (uint32_t i = 0; i < 2u; i++) { + zet_debug_event_t outputEvent = {}; + auto result = sessionMock->readEvent(0, &outputEvent); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + if (result == ZE_RESULT_SUCCESS) { + if (outputEvent.type == ZET_DEBUG_EVENT_TYPE_THREAD_STOPPED) { + stoppedEvents++; + } else if (outputEvent.type == ZET_DEBUG_EVENT_TYPE_THREAD_UNAVAILABLE) { + notAvailableEvents++; + } + } + } + EXPECT_EQ(1u, stoppedEvents); + EXPECT_EQ(1u, notAvailableEvents); } TEST_F(DebugApiLinuxAttentionTest, GivenSentInterruptWhenHandlingAttEventThenAttBitsAreSynchronouslyScannedAgainAndAllNewThreadsChecked) { @@ -6031,10 +6063,9 @@ TEST_F(DebugApiLinuxAttentionTest, GivenSentInterruptWhenHandlingAttEventThenAtt sessionMock->handleEvent(reinterpret_cast(data)); - EXPECT_EQ(0u, sessionMock->newlyStoppedThreads.size()); - EXPECT_TRUE(sessionMock->pendingInterrupts[0].second); + EXPECT_EQ(2u, sessionMock->newlyStoppedThreads.size()); auto expectedThreadsToCheck = (hwInfo.capabilityTable.fusedEuEnabled && hwInfo.gtSystemInfo.MaxEuPerSubSlice != 8) ? 4u : 2u; - EXPECT_EQ(expectedThreadsToCheck, sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttentionCallCount); + EXPECT_EQ(expectedThreadsToCheck, sessionMock->addThreadToNewlyStoppedFromRaisedAttentionCallCount); } TEST_F(DebugApiLinuxAttentionTest, GivenSentInterruptWhenSynchronouslyScannedAttBitsAreAllZeroOrErrorWhileHandlingAttEventThenThreadsFromEventAreChecked) { @@ -6094,10 +6125,9 @@ TEST_F(DebugApiLinuxAttentionTest, GivenSentInterruptWhenSynchronouslyScannedAtt sessionMock->handleEvent(reinterpret_cast(data)); - EXPECT_EQ(1u, sessionMock->newlyStoppedThreads.size()); - EXPECT_TRUE(sessionMock->pendingInterrupts[0].second); + EXPECT_EQ(2u, sessionMock->newlyStoppedThreads.size()); auto expectedThreadsToCheck = hwInfo.capabilityTable.fusedEuEnabled ? 4u : 2u; - EXPECT_EQ(expectedThreadsToCheck, sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttentionCallCount); + EXPECT_EQ(expectedThreadsToCheck, sessionMock->addThreadToNewlyStoppedFromRaisedAttentionCallCount); sessionMock->stoppedThreads[threads[0].packed] = 3; sessionMock->stoppedThreads[threads[1].packed] = 3; @@ -6106,14 +6136,13 @@ TEST_F(DebugApiLinuxAttentionTest, GivenSentInterruptWhenSynchronouslyScannedAtt sessionMock->newlyStoppedThreads.clear(); sessionMock->pendingInterrupts[0].second = false; - sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttentionCallCount = 0; + sessionMock->addThreadToNewlyStoppedFromRaisedAttentionCallCount = 0; handler->ioctlRetVal = -1; sessionMock->handleEvent(reinterpret_cast(data)); - EXPECT_EQ(1u, sessionMock->newlyStoppedThreads.size()); - EXPECT_TRUE(sessionMock->pendingInterrupts[0].second); - EXPECT_EQ(expectedThreadsToCheck, sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttentionCallCount); + EXPECT_EQ(2u, sessionMock->newlyStoppedThreads.size()); + EXPECT_EQ(expectedThreadsToCheck, sessionMock->addThreadToNewlyStoppedFromRaisedAttentionCallCount); } TEST_F(DebugApiLinuxAttentionTest, GivenInterruptedThreadsWhenAttentionEventReceivedThenEventsTriggeredAfterExpectedAttentionEventCount) { @@ -6681,14 +6710,14 @@ TEST_F(DebugApiLinuxAsyncThreadTest, GivenInterruptedThreadsWhenNoAttentionEvent auto handler = new MockIoctlHandler; session->ioctlHandler.reset(handler); session->returnTimeDiff = DebugSessionLinux::interruptTimeout * 10; - - session->startAsyncThread(); + session->synchronousInternalEventRead = true; ze_device_thread_t thread = {0, 0, 0, UINT32_MAX}; auto result = session->interrupt(thread); EXPECT_EQ(ZE_RESULT_SUCCESS, result); + session->startAsyncThread(); - while (session->getInternalEventCounter == 0) + while (session->getInternalEventCounter < 2) ; session->closeAsyncThread(); diff --git a/level_zero/tools/test/unit_tests/sources/debug/linux/tile_debug_session_linux_tests.cpp b/level_zero/tools/test/unit_tests/sources/debug/linux/tile_debug_session_linux_tests.cpp index 5bd2acf1a1..0967990480 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/linux/tile_debug_session_linux_tests.cpp +++ b/level_zero/tools/test/unit_tests/sources/debug/linux/tile_debug_session_linux_tests.cpp @@ -1015,9 +1015,10 @@ TEST_F(TileAttachAsyncThreadTest, GivenInterruptedThreadsWhenNoAttentionEventIsR auto result = tileSessions[0]->interrupt(thread); EXPECT_EQ(ZE_RESULT_SUCCESS, result); + rootSession->synchronousInternalEventRead = true; rootSession->startAsyncThread(); - while (rootSession->getInternalEventCounter == 0) + while (rootSession->getInternalEventCounter < 2) ; rootSession->closeAsyncThread(); diff --git a/level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h b/level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h index b9f0bc22ab..514aac35b6 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h +++ b/level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h @@ -138,6 +138,7 @@ struct MockDebugSession : public L0::DebugSessionImp { using L0::DebugSession::allThreads; using L0::DebugSession::debugArea; + using L0::DebugSessionImp::addThreadToNewlyStoppedFromRaisedAttention; using L0::DebugSessionImp::apiEvents; using L0::DebugSessionImp::applyResumeWa; using L0::DebugSessionImp::calculateThreadSlotOffset; @@ -148,7 +149,6 @@ struct MockDebugSession : public L0::DebugSessionImp { using L0::DebugSessionImp::generateEventsForStoppedThreads; using L0::DebugSessionImp::getRegisterSize; using L0::DebugSessionImp::getStateSaveAreaHeader; - using L0::DebugSessionImp::markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention; using L0::DebugSessionImp::newAttentionRaised; using L0::DebugSessionImp::readSbaRegisters; using L0::DebugSessionImp::registersAccessHelper; @@ -310,6 +310,9 @@ struct MockDebugSession : public L0::DebugSessionImp { } bool isForceExceptionOrForceExternalHaltOnlyExceptionReason(uint32_t *cr0) override { + if (callBaseIsForceExceptionOrForceExternalHaltOnlyExceptionReason) { + return isForceExceptionOrForceExternalHaltOnlyExceptionReasonBase(cr0); + } return onlyForceException; } @@ -437,6 +440,7 @@ struct MockDebugSession : public L0::DebugSessionImp { ze_result_t interruptImpResult = ZE_RESULT_SUCCESS; ze_result_t resumeImpResult = ZE_RESULT_SUCCESS; bool onlyForceException = true; + bool callBaseIsForceExceptionOrForceExternalHaltOnlyExceptionReason = false; bool threadStopped = true; int areRequestedThreadsStoppedReturnValue = -1; bool readSystemRoutineIdentRetVal = true; diff --git a/level_zero/tools/test/unit_tests/sources/debug/windows/test_debug_api_windows.cpp b/level_zero/tools/test/unit_tests/sources/debug/windows/test_debug_api_windows.cpp index afd975da04..6a5891aa87 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/windows/test_debug_api_windows.cpp +++ b/level_zero/tools/test/unit_tests/sources/debug/windows/test_debug_api_windows.cpp @@ -263,7 +263,7 @@ TEST_F(DebugApiWindowsAttentionTest, GivenEuAttentionEventEmptyBitmaskWhenHandli EXPECT_FALSE(sessionMock->triggerEvents); } -TEST_F(DebugApiWindowsAttentionTest, GivenInterruptedThreadsWhenOnlySomeThreadsRaisesAttentionThenPendingInterruptsAreMarked) { +TEST_F(DebugApiWindowsAttentionTest, GivenInterruptedThreadsWithOnlySomeThreadsRaisingAttentionWhenHandlingEventThenInterruptedThreadsAreAddedToNewlyStopped) { zet_debug_config_t config = {}; config.pid = 0x1234; @@ -295,8 +295,8 @@ TEST_F(DebugApiWindowsAttentionTest, GivenInterruptedThreadsWhenOnlySomeThreadsR auto result = sessionMock->readAndHandleEvent(100); EXPECT_EQ(ZE_RESULT_SUCCESS, result); - EXPECT_EQ(0u, sessionMock->newlyStoppedThreads.size()); - EXPECT_TRUE(sessionMock->pendingInterrupts[0].second); + EXPECT_EQ(1u, sessionMock->newlyStoppedThreads.size()); + EXPECT_FALSE(sessionMock->pendingInterrupts[0].second); EXPECT_FALSE(sessionMock->pendingInterrupts[1].second); }