From 4bd53be1958b0086fbecefa486768d76dafe94d5 Mon Sep 17 00:00:00 2001 From: Mateusz Hoppe Date: Fri, 19 Aug 2022 15:11:22 +0000 Subject: [PATCH] L0Debug - tile attach - add missing implementation - interrupt / resume - read/write registers Related-To: NEO-5784 Signed-off-by: Mateusz Hoppe --- .../tools/source/debug/debug_session_imp.cpp | 51 +++- .../tools/source/debug/debug_session_imp.h | 2 +- .../debug/linux/prelim/debug_session.cpp | 65 ++--- .../source/debug/linux/prelim/debug_session.h | 39 +-- .../sources/debug/debug_session_tests.cpp | 77 +++++- .../linux/debug_session_fixtures_linux.h | 46 ++++ .../debug/linux/test_debug_api_linux.cpp | 43 --- .../linux/tile_debug_session_linux_tests.cpp | 245 ++++++++++++++++-- 8 files changed, 443 insertions(+), 125 deletions(-) diff --git a/level_zero/tools/source/debug/debug_session_imp.cpp b/level_zero/tools/source/debug/debug_session_imp.cpp index a2f2b9ef41..bbac219ddf 100644 --- a/level_zero/tools/source/debug/debug_session_imp.cpp +++ b/level_zero/tools/source/debug/debug_session_imp.cpp @@ -37,7 +37,13 @@ void DebugSession::createEuThreads() { const uint32_t numThreadsPerEu = (hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount); uint32_t subDeviceCount = std::max(1u, connectedDevice->getNEODevice()->getNumSubDevices()); + UNRECOVERABLE_IF(isSubDevice && subDeviceCount > 1); + for (uint32_t tileIndex = 0; tileIndex < subDeviceCount; tileIndex++) { + + if (isSubDevice) { + tileIndex = Math::log2(static_cast(connectedDevice->getNEODevice()->getDeviceBitfield().to_ulong())); + } for (uint32_t sliceID = 0; sliceID < hwInfo.gtSystemInfo.MaxSlicesSupported; sliceID++) { for (uint32_t subsliceID = 0; subsliceID < numSubslicesPerSlice; subsliceID++) { for (uint32_t euID = 0; euID < numEuPerSubslice; euID++) { @@ -176,18 +182,28 @@ bool DebugSession::areRequestedThreadsStopped(ze_device_thread_t thread) { auto deviceCount = std::max(1u, connectedDevice->getNEODevice()->getNumSubDevices()); uint32_t deviceIndex = getDeviceIndexFromApiThread(thread); - for (uint32_t i = 0; i < deviceCount; i++) { - if (i == deviceIndex || deviceIndex == UINT32_MAX) { - auto physicalThread = convertToPhysicalWithinDevice(thread, i); - auto singleThreads = getSingleThreadsForDevice(i, physicalThread, hwInfo); + auto areAllThreadsStopped = [this, &hwInfo](uint32_t deviceIndex, const ze_device_thread_t &thread) -> bool { + auto physicalThread = convertToPhysicalWithinDevice(thread, deviceIndex); + auto singleThreads = getSingleThreadsForDevice(deviceIndex, physicalThread, hwInfo); - for (auto &threadId : singleThreads) { + for (auto &threadId : singleThreads) { - if (allThreads[threadId]->isStopped()) { - continue; - } - return false; + if (allThreads[threadId]->isStopped()) { + continue; } + return false; + } + return true; + }; + + if (deviceIndex != UINT32_MAX) { + return areAllThreadsStopped(deviceIndex, thread); + } + + for (uint32_t i = 0; i < deviceCount; i++) { + + if (areAllThreadsStopped(i, thread) == false) { + return false; } } @@ -282,6 +298,7 @@ DebugSession *DebugSessionImp::attachTileDebugSession(Device *device) { } attached = true; + PRINT_DEBUGGER_INFO_LOG("TileDebugSession attached, deviceIndex = %lu\n", subDeviceIndex); return tileSession; } @@ -290,6 +307,8 @@ void DebugSessionImp::detachTileDebugSession(DebugSession *tileSession) { uint32_t subDeviceIndex = Math::log2(static_cast(tileSession->getConnectedDevice()->getNEODevice()->getDeviceBitfield().to_ulong())); tileSessions[subDeviceIndex].second = false; + + PRINT_DEBUGGER_INFO_LOG("TileDebugSession detached, deviceIndex = %lu\n", subDeviceIndex); } bool DebugSessionImp::areAllTileDebugSessionDetached() { @@ -461,8 +480,13 @@ ze_result_t DebugSessionImp::resume(ze_device_thread_t thread) { if (singleDevice) { uint32_t deviceIndex = 0; - if (thread.slice != UINT32_MAX) { - deviceIndex = getDeviceIndexFromApiThread(thread); + + if (connectedDevice->getNEODevice()->isSubDevice()) { + deviceIndex = Math::log2(static_cast(connectedDevice->getNEODevice()->getDeviceBitfield().to_ulong())); + } else { + if (thread.slice != UINT32_MAX) { + deviceIndex = getDeviceIndexFromApiThread(thread); + } } auto physicalThread = convertToPhysicalWithinDevice(thread, deviceIndex); auto result = resumeThreadsWithinDevice(deviceIndex, physicalThread); @@ -521,6 +545,11 @@ void DebugSessionImp::sendInterrupts() { if (deviceCount == 1) { uint32_t deviceIndex = 0; + + if (connectedDevice->getNEODevice()->isSubDevice()) { + deviceIndex = Math::log2(static_cast(connectedDevice->getNEODevice()->getDeviceBitfield().to_ulong())); + } + ze_result_t result; { std::unique_lock lock(threadStateMutex); diff --git a/level_zero/tools/source/debug/debug_session_imp.h b/level_zero/tools/source/debug/debug_session_imp.h index 72a0dc1844..6397cc3414 100644 --- a/level_zero/tools/source/debug/debug_session_imp.h +++ b/level_zero/tools/source/debug/debug_session_imp.h @@ -133,7 +133,7 @@ struct DebugSessionImp : DebugSession { std::vector newlyStoppedThreads; std::vector stateSaveAreaHeader; - std::vector> tileSessions; // DebugSession, attached + std::vector> tileSessions; // DebugSession, attached bool tileAttachEnabled = false; bool tileSessionsEnabled = false; 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 2ae631f543..1ac6fae2ce 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session.cpp +++ b/level_zero/tools/source/debug/linux/prelim/debug_session.cpp @@ -284,7 +284,7 @@ void DebugSessionLinux::createTileSessionsIfEnabled() { for (uint32_t i = 0; i < numTiles; i++) { auto subDevice = connectedDevice->getNEODevice()->getSubDevice(i)->getSpecializedDevice(); - tileSessions[i] = std::pair{createTileSession(config, subDevice, this), false}; + tileSessions[i] = std::pair{createTileSession(config, subDevice, this), false}; } tileSessionsEnabled = true; } @@ -301,8 +301,15 @@ void *DebugSessionLinux::asyncThreadFunction(void *arg) { while (self->asyncThread.threadActive) { self->handleEventsAsync(); - self->sendInterrupts(); - self->generateEventsAndResumeStoppedThreads(); + 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(); + } + } else { + self->sendInterrupts(); + self->generateEventsAndResumeStoppedThreads(); + } } PRINT_DEBUGGER_INFO_LOG("Debugger async thread closing\n", ""); @@ -382,8 +389,8 @@ void DebugSessionLinux::readInternalEventsAsync() { if (tileSessionsEnabled) { auto numTiles = connectedDevice->getNEODevice()->getNumSubDevices(); for (uint32_t tileIndex = 0; tileIndex < numTiles; tileIndex++) { - reinterpret_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); - reinterpret_cast(tileSessions[tileIndex].first)->detached = true; + static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); + static_cast(tileSessions[tileIndex].first)->detached = true; } } else { pushApiEvent(debugEvent, nullptr); @@ -502,7 +509,7 @@ void DebugSessionLinux::handleEvent(prelim_drm_i915_debug_event *event) { debugEvent.type = ZET_DEBUG_EVENT_TYPE_PROCESS_EXIT; if (tileSessionsEnabled) { - reinterpret_cast(tileSessions[deviceIndex].first)->pushApiEvent(debugEvent, nullptr); + static_cast(tileSessions[deviceIndex].first)->pushApiEvent(debugEvent, nullptr); } else if (uuidL0CommandQueueHandleToDevice.size() == 0) { pushApiEvent(debugEvent, nullptr); } @@ -546,7 +553,7 @@ void DebugSessionLinux::handleEvent(prelim_drm_i915_debug_event *event) { if (tileSessionsEnabled) { UNRECOVERABLE_IF(uuidL0CommandQueueHandleToDevice.find(uuid->handle) != uuidL0CommandQueueHandleToDevice.end()); - reinterpret_cast(tileSessions[deviceIndex].first)->pushApiEvent(debugEvent, nullptr); + static_cast(tileSessions[deviceIndex].first)->pushApiEvent(debugEvent, nullptr); } else if (uuidL0CommandQueueHandleToDevice.size() == 0) { pushApiEvent(debugEvent, nullptr); } @@ -781,7 +788,7 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v } if (connection->uuidMap[uuid].classIndex == NEO::DrmResourceClass::Isa) { - PRINT_DEBUGGER_INFO_LOG("ISA vm_handle = %llu", (uint64_t)vmHandle); + PRINT_DEBUGGER_INFO_LOG("ISA vm_handle = %llu, tileIndex = %lu", (uint64_t)vmHandle, tileIndex); const auto isaUuidHandle = connection->uuidMap[uuid].handle; bool perKernelModules = true; @@ -858,17 +865,20 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v if (tileSessionsEnabled) { auto tileAttached = tileSessions[tileIndex].second; + if (!tileAttached) { isaMap[vmBind->va_start]->moduleLoadEventAck = true; apiEventNeedsAck = false; } + + PRINT_DEBUGGER_INFO_LOG("TileDebugSession attached = %d, tileIndex = %lu, apiEventNeedsAck = %d", (int)tileAttached, tileIndex, (int)apiEventNeedsAck); } memLock.unlock(); if (perKernelModules) { debugEvent.flags = apiEventNeedsAck ? ZET_DEBUG_EVENT_FLAG_NEED_ACK : 0; if (tileSessionsEnabled) { - reinterpret_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); + static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); } else { pushApiEvent(debugEvent, nullptr); } @@ -905,7 +915,7 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v if (perKernelModules) { if (tileSessionsEnabled) { - reinterpret_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); + static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); } else { pushApiEvent(debugEvent, nullptr); } @@ -947,9 +957,9 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v } else { auto tileAttached = tileSessions[tileIndex].second; if (!tileAttached) { - reinterpret_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); + static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); } else { - reinterpret_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, &vmBind->base); + static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, &vmBind->base); shouldAckEvent = false; } } @@ -971,7 +981,7 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v debugEvent.info.module.moduleEnd = connection->uuidMap[module.elfUuidHandle].ptr + connection->uuidMap[module.elfUuidHandle].dataSize; if (tileSessionsEnabled) { - reinterpret_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); + static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); } else { pushApiEvent(debugEvent, nullptr); } @@ -1083,10 +1093,18 @@ void DebugSessionLinux::handleAttentionEvent(prelim_drm_i915_debug_event_eu_atte for (auto &threadId : threadsWithAttention) { PRINT_DEBUGGER_THREAD_LOG("ATTENTION event for thread: %s\n", EuThread::toString(threadId).c_str()); - markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(threadId, vmHandle); + if (tileSessionsEnabled) { + static_cast(tileSessions[tileIndex].first)->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(threadId, vmHandle); + } else { + markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(threadId, vmHandle); + } } - checkTriggerEventsForAttention(); + if (tileSessionsEnabled) { + static_cast(tileSessions[tileIndex].first)->checkTriggerEventsForAttention(); + } else { + checkTriggerEventsForAttention(); + } } void DebugSessionLinux::handleEnginesEvent(prelim_drm_i915_debug_event_engines *engines) { @@ -1672,21 +1690,4 @@ void TileDebugSessionLinux::readStateSaveAreaHeader() { } }; -ze_result_t TileDebugSessionLinux::interrupt(ze_device_thread_t thread) { - return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; -}; - -ze_result_t TileDebugSessionLinux::resume(ze_device_thread_t thread) { - - return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; -}; - -ze_result_t TileDebugSessionLinux::readRegisters(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) { - return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; -}; - -ze_result_t TileDebugSessionLinux::writeRegisters(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) { - return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; -}; - } // namespace L0 diff --git a/level_zero/tools/source/debug/linux/prelim/debug_session.h b/level_zero/tools/source/debug/linux/prelim/debug_session.h index 55def40a42..58a1cc5748 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session.h +++ b/level_zero/tools/source/debug/linux/prelim/debug_session.h @@ -258,7 +258,7 @@ struct DebugSessionLinux : DebugSessionImp { MOCKABLE_VIRTUAL int threadControl(const std::vector &threads, uint32_t tile, ThreadControlCmd threadCmd, std::unique_ptr &bitmask, size_t &bitmaskSize); uint64_t getContextStateSaveAreaGpuVa(uint64_t memoryHandle) override; - uint64_t getSbaBufferGpuVa(uint64_t memoryHandle); + virtual uint64_t getSbaBufferGpuVa(uint64_t memoryHandle); void printContextVms(); ThreadHelper internalEventThread; @@ -282,16 +282,14 @@ struct DebugSessionLinux : DebugSessionImp { struct TileDebugSessionLinux : DebugSessionLinux { TileDebugSessionLinux(zet_debug_config_t config, Device *device, DebugSessionImp *rootDebugSession) : DebugSessionLinux(config, device, 0), - rootDebugSession(reinterpret_cast(rootDebugSession)){}; + rootDebugSession(reinterpret_cast(rootDebugSession)) { + tileIndex = Math::log2(static_cast(connectedDevice->getNEODevice()->getDeviceBitfield().to_ulong())); + } + ~TileDebugSessionLinux() override = default; - bool closeConnection() override { return true; }; - ze_result_t initialize() override { return ZE_RESULT_SUCCESS; }; - - ze_result_t interrupt(ze_device_thread_t thread) override; - ze_result_t resume(ze_device_thread_t thread) override; - ze_result_t readRegisters(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) override; - ze_result_t writeRegisters(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) override; + bool closeConnection() override { return true; } + ze_result_t initialize() override { return ZE_RESULT_SUCCESS; } protected: void startAsyncThread() override { UNRECOVERABLE_IF(true); }; @@ -304,6 +302,10 @@ struct TileDebugSessionLinux : DebugSessionLinux { void readStateSaveAreaHeader() override; + uint64_t getSbaBufferGpuVa(uint64_t memoryHandle) override { + return rootDebugSession->getSbaBufferGpuVa(memoryHandle); + } + int ioctl(unsigned long request, void *arg) override { return rootDebugSession->ioctl(request, arg); } @@ -322,22 +324,27 @@ struct TileDebugSessionLinux : DebugSessionLinux { } bool ackIsaEvents(uint32_t deviceIndex, uint64_t isaVa) override { - auto tile = Math::log2(static_cast(connectedDevice->getNEODevice()->getDeviceBitfield().to_ulong())); - return rootDebugSession->ackIsaEvents(tile, isaVa); + return rootDebugSession->ackIsaEvents(this->tileIndex, isaVa); } ze_result_t readGpuMemory(uint64_t vmHandle, char *output, size_t size, uint64_t gpuVa) override { return rootDebugSession->readGpuMemory(vmHandle, output, size, gpuVa); - }; + } + ze_result_t writeGpuMemory(uint64_t vmHandle, const char *input, size_t size, uint64_t gpuVa) override { return rootDebugSession->writeGpuMemory(vmHandle, input, size, gpuVa); - }; + } - ze_result_t readSbaBuffer(EuThread::ThreadId threadId, NEO::SbaTrackedAddresses &sbaBuffer) override { - return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; - }; + ze_result_t resumeImp(const std::vector &threads, uint32_t deviceIndex) override { + return rootDebugSession->resumeImp(threads, this->tileIndex); + } + + ze_result_t interruptImp(uint32_t deviceIndex) override { + return rootDebugSession->interruptImp(this->tileIndex); + } DebugSessionLinux *rootDebugSession = nullptr; + uint32_t tileIndex = std::numeric_limits::max(); }; } // namespace L0 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 1d21f66332..330bf5d10f 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 @@ -60,6 +60,7 @@ struct MockDebugSession : public L0::DebugSessionImp { using L0::DebugSessionImp::newlyStoppedThreads; using L0::DebugSessionImp::pendingInterrupts; using L0::DebugSessionImp::readStateSaveAreaHeader; + using L0::DebugSessionImp::tileAttachEnabled; using L0::DebugSessionImp::tileSessions; MockDebugSession(const zet_debug_config_t &config, L0::Device *device) : DebugSessionImp(config, device) { @@ -81,7 +82,7 @@ struct MockDebugSession : public L0::DebugSessionImp { for (uint32_t i = 0; i < numTiles; i++) { auto subDevice = connectedDevice->getNEODevice()->getSubDevice(i)->getSpecializedDevice(); - tileSessions[i] = std::pair{new MockDebugSession(config, subDevice), false}; + tileSessions[i] = std::pair{new MockDebugSession(config, subDevice), false}; } } @@ -1550,6 +1551,41 @@ TEST_F(MultiTileDebugSessionTest, givenTwoDevicesInRequestsWhenSendingInterrupts EXPECT_EQ(2u, sessionMock->expectedAttentionEvents); } +TEST_F(MultiTileDebugSessionTest, givenTileAttachEnabledWhenSendingInterruptsThenInterruptIsSentWithCorrectDeviceIndex) { + DebugManagerStateRestore restorer; + NEO::DebugManager.flags.ExperimentalEnableTileAttach.set(1); + zet_debug_config_t config = {}; + config.pid = 0x1234; + + L0::Device *device = driverHandle->devices[0]; + L0::DeviceImp *deviceImp = static_cast(device); + + auto sessionMock = std::make_unique(config, deviceImp); + + sessionMock->interruptImpResult = ZE_RESULT_SUCCESS; + sessionMock->tileAttachEnabled = true; + sessionMock->initialize(); + + auto tileSession1 = static_cast(sessionMock->tileSessions[1].first); + auto tileSession0 = static_cast(sessionMock->tileSessions[0].first); + + ze_device_thread_t apiThread = {0, 0, 0, 0}; + + auto result = tileSession1->interrupt(apiThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + result = tileSession0->interrupt(apiThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + tileSession1->sendInterrupts(); + tileSession0->sendInterrupts(); + + EXPECT_TRUE(tileSession1->interruptSent); + EXPECT_TRUE(tileSession0->interruptSent); + EXPECT_EQ(1u, tileSession1->interruptedDevices[0]); + EXPECT_EQ(0u, tileSession0->interruptedDevices[0]); +} + TEST_F(MultiTileDebugSessionTest, givenAllSlicesInRequestWhenSendingInterruptsThenTwoInterruptsCalled) { zet_debug_config_t config = {}; config.pid = 0x1234; @@ -1681,6 +1717,45 @@ TEST_F(MultiTileDebugSessionTest, givenAllSlicesInRequestWhenAllInterruptsReturn EXPECT_TRUE(DebugSession::areThreadsEqual(apiThread, sessionMock->events[0].info.thread.thread)); } +TEST_F(MultiTileDebugSessionTest, GivenMultitileDeviceWhenCallingAreRequestedThreadsStoppedThenCorrectValueIsReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + L0::Device *device = driverHandle->devices[0]; + L0::DeviceImp *deviceImp = static_cast(device); + + auto sessionMock = std::make_unique(config, deviceImp); + ASSERT_NE(nullptr, sessionMock); + + ze_device_thread_t thread = {0, 0, 0, 0}; + ze_device_thread_t allSlices = {UINT32_MAX, 0, 0, 0}; + + sessionMock->allThreads[EuThread::ThreadId(0, thread)]->stopThread(1u); + sessionMock->allThreads[EuThread::ThreadId(1, thread)]->stopThread(1u); + + auto stopped = sessionMock->areRequestedThreadsStopped(thread); + EXPECT_TRUE(stopped); + + stopped = sessionMock->areRequestedThreadsStopped(allSlices); + EXPECT_FALSE(stopped); + + for (uint32_t i = 0; i < sliceCount; i++) { + EuThread::ThreadId threadId(0, i, 0, 0, 0); + sessionMock->allThreads[threadId]->stopThread(1u); + } + + stopped = sessionMock->areRequestedThreadsStopped(allSlices); + EXPECT_FALSE(stopped); + + for (uint32_t i = 0; i < sliceCount; i++) { + EuThread::ThreadId threadId(1, i, 0, 0, 0); + sessionMock->allThreads[threadId]->stopThread(1u); + } + + stopped = sessionMock->areRequestedThreadsStopped(allSlices); + EXPECT_TRUE(stopped); +} + struct DebugSessionRegistersAccess { void setUp() { zet_debug_config_t config = {}; 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 204c752fb8..a158a19b1a 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 @@ -238,6 +238,7 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux { using L0::DebugSessionImp::expectedAttentionEvents; using L0::DebugSessionImp::interruptSent; using L0::DebugSessionImp::isValidGpuAddress; + using L0::DebugSessionImp::newAttentionRaised; using L0::DebugSessionImp::stateSaveAreaHeader; using L0::DebugSessionImp::tileAttachEnabled; using L0::DebugSessionImp::tileSessions; @@ -256,6 +257,7 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux { using L0::DebugSessionLinux::eventsToAck; using L0::DebugSessionLinux::extractVaFromUuidString; using L0::DebugSessionLinux::getRegisterSetProperties; + using L0::DebugSessionLinux::getSbaBufferGpuVa; using L0::DebugSessionLinux::getStateSaveAreaHeader; using L0::DebugSessionLinux::handleEvent; using L0::DebugSessionLinux::handleEventsAsync; @@ -320,6 +322,11 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux { return L0::DebugSessionLinux::resumeImp(threads, deviceIndex); } + ze_result_t interruptImp(uint32_t deviceIndex) override { + interruptedDevice = deviceIndex; + return L0::DebugSessionLinux::interruptImp(deviceIndex); + } + void handleEvent(prelim_drm_i915_debug_event *event) override { handleEventCalledCount++; L0::DebugSessionLinux::handleEvent(event); @@ -391,6 +398,7 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux { uint32_t writeResumeCommandCalled = 0; bool skipcheckThreadIsResumed = true; uint32_t checkThreadIsResumedCalled = 0; + uint32_t interruptedDevice = std::numeric_limits::max(); std::vector resumedDevices; std::vector> resumedThreads; @@ -403,9 +411,17 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux { struct MockTileDebugSessionLinux : TileDebugSessionLinux { using DebugSession::allThreads; + using DebugSessionImp::checkTriggerEventsForAttention; + using DebugSessionImp::expectedAttentionEvents; + using DebugSessionImp::interruptImp; + using DebugSessionImp::newlyStoppedThreads; + using DebugSessionImp::resumeImp; + using DebugSessionImp::sendInterrupts; using DebugSessionImp::stateSaveAreaHeader; + using DebugSessionImp::triggerEvents; using TileDebugSessionLinux::getAllMemoryHandles; using TileDebugSessionLinux::getContextStateSaveAreaGpuVa; + using TileDebugSessionLinux::getSbaBufferGpuVa; using TileDebugSessionLinux::readGpuMemory; using TileDebugSessionLinux::readModuleDebugArea; using TileDebugSessionLinux::readSbaBuffer; @@ -421,6 +437,36 @@ struct MockTileDebugSessionLinux : TileDebugSessionLinux { } allThreads[threadId]->stopThread(vmHandle); } + + bool writeResumeCommand(const std::vector &threadIds) override { + if (writeResumeResult != -1) { + return writeResumeResult == 0 ? false : true; + } + return writeResumeCommand(threadIds); + } + + bool readSystemRoutineIdent(EuThread *thread, uint64_t vmHandle, SIP::sr_ident &srIdent) override { + srIdent.count = 0; + if (stoppedThreads.size()) { + auto entry = stoppedThreads.find(thread->getThreadId()); + if (entry != stoppedThreads.end()) { + srIdent.count = entry->second; + } + return true; + } + return L0::DebugSessionLinux::readSystemRoutineIdent(thread, vmHandle, srIdent); + } + + int64_t getTimeDifferenceMilliseconds(std::chrono::high_resolution_clock::time_point time) override { + if (returnTimeDiff != -1) { + return returnTimeDiff; + } + return L0::DebugSessionLinux::getTimeDifferenceMilliseconds(time); + } + + int writeResumeResult = -1; + int64_t returnTimeDiff = -1; + std::unordered_map stoppedThreads; }; size_t threadSlotOffset(SIP::StateSaveAreaHeader *pStateSaveAreaHeader, int slice, int subslice, int eu, int thread); 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 a7fd73207b..e1169dbb27 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 @@ -6216,48 +6216,5 @@ TEST_F(DebugApiLinuxMultitileTest, givenApiThreadAndMultipleTilesWhenGettingDevi EXPECT_EQ(1u, deviceIndex); } -TEST_F(DebugApiLinuxMultitileTest, GivenMultitileDeviceWhenCallingAreRequestedThreadsStoppedThenCorrectValueIsReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - - auto sessionMock = std::make_unique(config, deviceImp, 10); - ASSERT_NE(nullptr, sessionMock); - SIP::version version = {2, 0, 0}; - initStateSaveArea(sessionMock->stateSaveAreaHeader, version); - - auto handler = new MockIoctlHandler; - sessionMock->ioctlHandler.reset(handler); - sessionMock->clientHandle = MockDebugSessionLinux::mockClientHandle; - sessionMock->clientHandleToConnection[sessionMock->clientHandle]->vmToContextStateSaveAreaBindInfo[1u] = {0x1000, 0x1000}; - - ze_device_thread_t thread = {0, 0, 0, 0}; - ze_device_thread_t allSlices = {UINT32_MAX, 0, 0, 0}; - - sessionMock->allThreads[EuThread::ThreadId(0, thread)]->stopThread(1u); - sessionMock->allThreads[EuThread::ThreadId(1, thread)]->stopThread(1u); - - auto stopped = sessionMock->areRequestedThreadsStopped(thread); - EXPECT_TRUE(stopped); - - stopped = sessionMock->areRequestedThreadsStopped(allSlices); - EXPECT_FALSE(stopped); - - for (uint32_t i = 0; i < sliceCount; i++) { - EuThread::ThreadId threadId(0, i, 0, 0, 0); - sessionMock->allThreads[threadId]->stopThread(1u); - } - - stopped = sessionMock->areRequestedThreadsStopped(allSlices); - EXPECT_FALSE(stopped); - - for (uint32_t i = 0; i < sliceCount; i++) { - EuThread::ThreadId threadId(1, i, 0, 0, 0); - sessionMock->allThreads[threadId]->stopThread(1u); - } - - stopped = sessionMock->areRequestedThreadsStopped(allSlices); - EXPECT_TRUE(stopped); -} - } // namespace ult } // namespace L0 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 1e65c4f62e..1ded55d0f5 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 @@ -18,7 +18,7 @@ namespace L0 { namespace ult { -TEST(TileDebugSessionLinuxTest, GivenTileDebugSessionWhenCallingFunctionsThenUnsupportedErrorIsReturnedOrImplementationIsEmpty) { +TEST(TileDebugSessionLinuxTest, GivenTileDebugSessionWhenCallingFunctionsThenImplementationIsEmpty) { auto hwInfo = *NEO::defaultHwInfo.get(); NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); @@ -29,23 +29,6 @@ TEST(TileDebugSessionLinuxTest, GivenTileDebugSessionWhenCallingFunctionsThenUns auto session = std::make_unique(zet_debug_config_t{0x1234}, &deviceImp, nullptr); ASSERT_NE(nullptr, session); - ze_device_thread_t thread = {0, 0, 0, 0}; - - EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, session->interrupt(thread)); - EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, session->resume(thread)); - - uint32_t type = 0; - uint32_t start = 0; - uint32_t count = 1; - - EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, session->readRegisters(thread, type, start, count, nullptr)); - EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, session->writeRegisters(thread, type, start, count, nullptr)); - - EuThread::ThreadId threadId{0, 0, 0, 0, 0}; - NEO::SbaTrackedAddresses sbaBuffer = {}; - - EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, session->readSbaBuffer(threadId, sbaBuffer)); - EXPECT_TRUE(session->closeConnection()); EXPECT_TRUE(session->readModuleDebugArea()); @@ -79,6 +62,17 @@ TEST(TileDebugSessionLinuxTest, GivenTileDebugSessionWhenCallingFunctionsThenCal allVms = session->getAllMemoryHandles(); EXPECT_EQ(1u, allVms.size()); EXPECT_EQ(6u, allVms[0]); + + auto sbaGpuVa = session->getSbaBufferGpuVa(5); + EXPECT_EQ(0u, sbaGpuVa); + + DebugSessionLinux::BindInfo sbaInfo = {0x567000, 0x200}; + rootSession->clientHandleToConnection[rootSession->clientHandle]->vmToStateBaseAreaBindInfo[5] = sbaInfo; + + sbaGpuVa = session->getSbaBufferGpuVa(5); + auto rootSbaGpuVa = rootSession->getSbaBufferGpuVa(5); + EXPECT_EQ(0x567000u, sbaGpuVa); + EXPECT_EQ(rootSbaGpuVa, sbaGpuVa); } TEST(TileDebugSessionLinuxTest, GivenTileDebugSessionWhenReadingContextStateSaveAreaHeaderThenHeaderIsCopiedFromRootSession) { @@ -120,8 +114,8 @@ struct TileAttachFixture : public DebugApiLinuxMultiDeviceFixture, public MockDe session->createTileSessionsIfEnabled(); rootSession = session.get(); - tileSessions[0] = reinterpret_cast(rootSession->tileSessions[0].first); - tileSessions[1] = reinterpret_cast(rootSession->tileSessions[1].first); + tileSessions[0] = static_cast(rootSession->tileSessions[0].first); + tileSessions[1] = static_cast(rootSession->tileSessions[1].first); setupSessionClassHandlesAndUuidMap(session.get()); setupVmToTile(session.get()); @@ -169,6 +163,18 @@ TEST_F(TileAttachTest, GivenTileAttachEnabledAndMultitileDeviceWhenInitializingD EXPECT_FALSE(session->tileSessions[0].second); EXPECT_FALSE(session->tileSessions[1].second); + + auto threadId0 = tileSessions[0]->allThreads.begin()->second->getThreadId(); + auto threadId1 = tileSessions[1]->allThreads.begin()->second->getThreadId(); + + EXPECT_EQ(0u, threadId0.tileIndex); + EXPECT_EQ(1u, threadId1.tileIndex); + + threadId0 = tileSessions[0]->allThreads.rbegin()->second->getThreadId(); + threadId1 = tileSessions[1]->allThreads.rbegin()->second->getThreadId(); + + EXPECT_EQ(0u, threadId0.tileIndex); + EXPECT_EQ(1u, threadId1.tileIndex); } TEST_F(TileAttachTest, GivenTileAttachDisabledAndMultitileDeviceWhenCreatingTileSessionsThenSessionsAreNotCreated) { @@ -229,7 +235,7 @@ TEST_F(TileAttachTest, givenTileDeviceWhenCallingDebugAttachAndDetachManyTimesTh EXPECT_EQ(ZE_RESULT_SUCCESS, result); } -TEST_F(TileAttachTest, givenTileDeviceWhenCallingDebugAttachTwiceThenTheSameSessionIsRrturned) { +TEST_F(TileAttachTest, givenTileDeviceWhenCallingDebugAttachTwiceThenTheSameSessionIsReturned) { zet_debug_config_t config = {}; config.pid = 0x1234; zet_debug_session_handle_t debugSession0 = nullptr, debugSession0Second = nullptr; @@ -522,6 +528,203 @@ TEST_F(TileAttachTest, WhenCallingReadWriteMemoryforASingleThreadThenMemoryIsRea EXPECT_EQ(1u, handler->pwriteCalled); } +TEST_F(TileAttachTest, givenExecutingThreadWhenInterruptingAndResumingThenCallsAreSentThroughRootSession) { + // deubg attach both tiles + rootSession->tileSessions[0].second = true; + rootSession->tileSessions[1].second = true; + + SIP::version version = {2, 0, 0}; + initStateSaveArea(rootSession->stateSaveAreaHeader, version); + + ze_device_thread_t apiThread = {0, 0, 0, 0}; + + for (uint32_t tile = 0; tile < 2; tile++) { + EuThread::ThreadId threadId = {tile, apiThread}; + + auto result = zetDebugInterrupt(tileSessions[tile]->toHandle(), apiThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + tileSessions[tile]->sendInterrupts(); + EXPECT_EQ(tile, rootSession->interruptedDevice); + + tileSessions[tile]->ensureThreadStopped(apiThread, 4); + tileSessions[tile]->writeResumeResult = 1; + + result = zetDebugResume(tileSessions[tile]->toHandle(), apiThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + ASSERT_EQ(1u, rootSession->resumedThreads.size()); + ASSERT_EQ(1u, rootSession->resumedDevices.size()); + EXPECT_EQ(threadId.slice, rootSession->resumedThreads[0][0].slice); + EXPECT_EQ(threadId.subslice, rootSession->resumedThreads[0][0].subslice); + EXPECT_EQ(threadId.eu, rootSession->resumedThreads[0][0].eu); + EXPECT_EQ(threadId.thread, rootSession->resumedThreads[0][0].thread); + EXPECT_EQ(threadId.tileIndex, rootSession->resumedThreads[0][0].tileIndex); + EXPECT_EQ(tile, rootSession->resumedDevices[0]); + + rootSession->resumedThreads.clear(); + rootSession->resumedDevices.clear(); + } +} + +TEST_F(TileAttachTest, givenTwoInterruptsSentWhenCheckingTriggerEventsThenTriggerEventsIsSetForTiles) { + // deubg attach both tiles + rootSession->tileSessions[0].second = true; + rootSession->tileSessions[1].second = true; + + ze_device_thread_t apiThread = {0, 0, 0, 0}; + + auto result = zetDebugInterrupt(tileSessions[0]->toHandle(), apiThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + tileSessions[0]->sendInterrupts(); + EXPECT_EQ(0u, tileSessions[0]->expectedAttentionEvents); + EXPECT_EQ(0u, rootSession->interruptedDevice); + + rootSession->newAttentionRaised(0); + + tileSessions[0]->checkTriggerEventsForAttention(); + EXPECT_TRUE(tileSessions[0]->triggerEvents); + + result = zetDebugInterrupt(tileSessions[1]->toHandle(), apiThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + EXPECT_EQ(0u, tileSessions[1]->expectedAttentionEvents); + + tileSessions[1]->sendInterrupts(); + EXPECT_EQ(0u, tileSessions[1]->expectedAttentionEvents); + EXPECT_FALSE(tileSessions[1]->triggerEvents); + EXPECT_EQ(1u, rootSession->interruptedDevice); + + rootSession->newAttentionRaised(1); + EXPECT_EQ(0u, tileSessions[1]->expectedAttentionEvents); + tileSessions[1]->checkTriggerEventsForAttention(); + + EXPECT_TRUE(tileSessions[1]->triggerEvents); +} + +TEST_F(TileAttachTest, givenInterruptSentWhenHandlingAttentionEventThenTriggerEventsIsSetForTileSession) { + // deubg attach both tiles + rootSession->tileSessions[0].second = true; + rootSession->tileSessions[1].second = true; + + ze_device_thread_t apiThread = {0, 0, 0, 0}; + + auto result = zetDebugInterrupt(tileSessions[1]->toHandle(), apiThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + tileSessions[1]->sendInterrupts(); + + uint64_t ctxHandle = 2; + uint64_t vmHandle = 7; + uint64_t lrcHandle = 8; + + rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->contextsCreated[ctxHandle].vm = vmHandle; + rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->lrcToContextHandle[lrcHandle] = ctxHandle; + rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->vmToTile[vmHandle] = 1; + + uint8_t data[sizeof(prelim_drm_i915_debug_event_eu_attention) + 128]; + + tileSessions[1]->ensureThreadStopped(apiThread, vmHandle); + + auto engineInfo = mockDrm->getEngineInfo(); + auto engineInstance = engineInfo->getEngineInstance(1, hwInfo.capabilityTable.defaultEngineType); + + prelim_drm_i915_debug_event_eu_attention attention = {}; + attention.base.type = PRELIM_DRM_I915_DEBUG_EVENT_EU_ATTENTION; + attention.base.flags = PRELIM_DRM_I915_DEBUG_EVENT_STATE_CHANGE; + attention.base.size = sizeof(prelim_drm_i915_debug_event_eu_attention); + attention.base.seqno = 2; + attention.client_handle = MockDebugSessionLinux::mockClientHandle; + attention.lrc_handle = lrcHandle; + attention.flags = 0; + attention.ci.engine_class = engineInstance->engineClass; + attention.ci.engine_instance = engineInstance->engineInstance; + attention.bitmask_size = 0; + + memcpy(data, &attention, sizeof(prelim_drm_i915_debug_event_eu_attention)); + rootSession->handleEvent(reinterpret_cast(data)); + + EXPECT_TRUE(tileSessions[1]->triggerEvents); +} + +TEST_F(TileAttachTest, givenStoppedThreadsWhenHandlingAttentionEventThenStoppedThreadsFromRaisedAttentionAreProcessed) { + // deubg attach both tiles + rootSession->tileSessions[0].second = true; + rootSession->tileSessions[1].second = true; + + uint64_t ctxHandle = 2; + uint64_t vmHandle = 7; + uint64_t lrcHandle = 8; + + rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->contextsCreated[ctxHandle].vm = vmHandle; + rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->lrcToContextHandle[lrcHandle] = ctxHandle; + rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->vmToTile[vmHandle] = 1; + + uint8_t data[sizeof(prelim_drm_i915_debug_event_eu_attention) + 128]; + + auto engineInfo = mockDrm->getEngineInfo(); + auto engineInstance = engineInfo->getEngineInstance(1, hwInfo.capabilityTable.defaultEngineType); + + EuThread::ThreadId thread = {1, 0, 0, 0, 0}; + tileSessions[1]->stoppedThreads[thread.packed] = 1; + + std::unique_ptr bitmask; + size_t bitmaskSize = 0; + auto &hwInfo = neoDevice->getHardwareInfo(); + auto &l0HwHelper = L0HwHelper::get(hwInfo.platform.eRenderCoreFamily); + + l0HwHelper.getAttentionBitmaskForSingleThreads({thread}, hwInfo, bitmask, bitmaskSize); + + prelim_drm_i915_debug_event_eu_attention attention = {}; + attention.base.type = PRELIM_DRM_I915_DEBUG_EVENT_EU_ATTENTION; + attention.base.flags = PRELIM_DRM_I915_DEBUG_EVENT_STATE_CHANGE; + attention.base.size = sizeof(prelim_drm_i915_debug_event_eu_attention); + attention.base.seqno = 2; + attention.client_handle = MockDebugSessionLinux::mockClientHandle; + attention.lrc_handle = lrcHandle; + attention.flags = 0; + attention.ci.engine_class = engineInstance->engineClass; + attention.ci.engine_instance = engineInstance->engineInstance; + attention.bitmask_size = static_cast(bitmaskSize); + + memcpy(data, &attention, sizeof(prelim_drm_i915_debug_event_eu_attention)); + memcpy(ptrOffset(data, offsetof(prelim_drm_i915_debug_event_eu_attention, bitmask)), bitmask.get(), std::min(size_t(128), bitmaskSize)); + + rootSession->handleEvent(reinterpret_cast(data)); + + EXPECT_EQ(1u, tileSessions[1]->newlyStoppedThreads.size()); + EXPECT_TRUE(tileSessions[1]->triggerEvents); +} + +using TileAttachAsyncThreadTest = Test; + +TEST_F(TileAttachAsyncThreadTest, GivenInterruptedThreadsWhenNoAttentionEventIsReadThenThreadUnavailableEventIsGenerated) { + rootSession->tileSessions[0].second = true; + tileSessions[0]->returnTimeDiff = DebugSessionLinux::interruptTimeout * 10; + + ze_device_thread_t thread = {0, 0, 0, 0}; + auto result = tileSessions[0]->interrupt(thread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + rootSession->startAsyncThread(); + + while (rootSession->getInternalEventCounter == 0) + ; + + rootSession->closeAsyncThread(); + + zet_debug_event_t event = {}; + result = zetDebugReadEvent(tileSessions[0]->toHandle(), 0, &event); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_THREAD_UNAVAILABLE, event.type); + EXPECT_EQ(0u, event.info.thread.thread.slice); + EXPECT_EQ(0u, event.info.thread.thread.subslice); + EXPECT_EQ(0u, event.info.thread.thread.eu); + EXPECT_EQ(0u, event.info.thread.thread.thread); +} + TEST_F(TileAttachTest, GivenEventWithL0ZebinModuleWhenHandlingEventThenModuleLoadAndUnloadEventsAreReportedForLastKernel) { uint64_t isaGpuVa = 0x345000; uint64_t isaGpuVa2 = 0x340000;