diff --git a/level_zero/tools/source/debug/debug_session_imp.cpp b/level_zero/tools/source/debug/debug_session_imp.cpp index bbac219ddf..24e315a17a 100644 --- a/level_zero/tools/source/debug/debug_session_imp.cpp +++ b/level_zero/tools/source/debug/debug_session_imp.cpp @@ -296,6 +296,8 @@ DebugSession *DebugSessionImp::attachTileDebugSession(Device *device) { if (attached) { return nullptr; } + + tileSessions[subDeviceIndex].first->attachTile(); attached = true; PRINT_DEBUGGER_INFO_LOG("TileDebugSession attached, deviceIndex = %lu\n", subDeviceIndex); @@ -306,7 +308,10 @@ void DebugSessionImp::detachTileDebugSession(DebugSession *tileSession) { std::unique_lock lock(asyncThreadMutex); uint32_t subDeviceIndex = Math::log2(static_cast(tileSession->getConnectedDevice()->getNEODevice()->getDeviceBitfield().to_ulong())); + tileSessions[subDeviceIndex].second = false; + tileSessions[subDeviceIndex].first->detachTile(); + cleanRootSessionAfterDetach(subDeviceIndex); PRINT_DEBUGGER_INFO_LOG("TileDebugSession detached, deviceIndex = %lu\n", subDeviceIndex); } diff --git a/level_zero/tools/source/debug/debug_session_imp.h b/level_zero/tools/source/debug/debug_session_imp.h index 6397cc3414..68a443e8e8 100644 --- a/level_zero/tools/source/debug/debug_session_imp.h +++ b/level_zero/tools/source/debug/debug_session_imp.h @@ -48,6 +48,10 @@ struct DebugSessionImp : DebugSession { void detachTileDebugSession(DebugSession *tileSession) override; bool areAllTileDebugSessionDetached() override; + virtual void attachTile() = 0; + virtual void detachTile() = 0; + virtual void cleanRootSessionAfterDetach(uint32_t deviceIndex) = 0; + static const SIP::regset_desc *getSbaRegsetDesc(); static uint32_t typeToRegsetFlags(uint32_t type); constexpr static int64_t interruptTimeout = 2000; 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 464c4855f2..e2193d6f22 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session.cpp +++ b/level_zero/tools/source/debug/linux/prelim/debug_session.cpp @@ -429,7 +429,7 @@ void DebugSessionLinux::readInternalEventsAsync() { maxLoopCount--; if (result == ZE_RESULT_SUCCESS) { - std::unique_lock lock(internalEventThreadMutex); + std::lock_guard lock(internalEventThreadMutex); auto memory = std::make_unique(maxEventSize / sizeof(uint64_t)); memcpy(memory.get(), event, maxEventSize); @@ -515,6 +515,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)->processExit(); static_cast(tileSessions[deviceIndex].first)->pushApiEvent(debugEvent, nullptr); } else if (uuidL0CommandQueueHandleToDevice.size() == 0) { pushApiEvent(debugEvent, nullptr); @@ -558,7 +559,7 @@ void DebugSessionLinux::handleEvent(prelim_drm_i915_debug_event *event) { if (tileSessionsEnabled) { UNRECOVERABLE_IF(uuidL0CommandQueueHandleToDevice.find(uuid->handle) != uuidL0CommandQueueHandleToDevice.end()); - + static_cast(tileSessions[deviceIndex].first)->processEntry(); static_cast(tileSessions[deviceIndex].first)->pushApiEvent(debugEvent, nullptr); } else if (uuidL0CommandQueueHandleToDevice.size() == 0) { pushApiEvent(debugEvent, nullptr); @@ -704,7 +705,7 @@ void DebugSessionLinux::readStateSaveAreaHeader() { size_t totalSize = 0; { - std::unique_lock lock(asyncThreadMutex); + std::lock_guard lock(asyncThreadMutex); if (clientHandleToConnection[clientHandle]->vmToContextStateSaveAreaBindInfo.size() > 0) { vm = clientHandleToConnection[clientHandle]->vmToContextStateSaveAreaBindInfo.begin()->first; gpuVa = clientHandleToConnection[clientHandle]->vmToContextStateSaveAreaBindInfo.begin()->second.gpuVa; @@ -775,7 +776,7 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v if (connection->classHandleToIndex.find(classUuid) != connection->classHandleToIndex.end()) { - std::unique_lock lock(asyncThreadMutex); + std::lock_guard lock(asyncThreadMutex); if (connection->classHandleToIndex[classUuid].second == static_cast(NEO::DrmResourceClass::SbaTrackingBuffer)) { @@ -883,8 +884,12 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v if (perKernelModules) { debugEvent.flags = apiEventNeedsAck ? ZET_DEBUG_EVENT_FLAG_NEED_ACK : 0; + if (tileSessionsEnabled) { - static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); + auto tileAttached = static_cast(tileSessions[tileIndex].first)->insertModule(debugEvent.info.module); + if (tileAttached) { + static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); + } } else { pushApiEvent(debugEvent, nullptr); } @@ -892,7 +897,7 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v } if (createEvent) { - std::unique_lock lock(asyncThreadMutex); + std::lock_guard lock(asyncThreadMutex); if (!connection->isaMap[tileIndex][vmBind->va_start]->moduleLoadEventAck && perKernelModules) { PRINT_DEBUGGER_INFO_LOG("Add event to ack, seqno = %llu", (uint64_t)vmBind->base.seqno); connection->isaMap[tileIndex][vmBind->va_start]->ackEvents.push_back(vmBind->base); @@ -921,6 +926,7 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v if (perKernelModules) { if (tileSessionsEnabled) { + static_cast(tileSessions[tileIndex].first)->removeModule(debugEvent.info.module); static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); } else { pushApiEvent(debugEvent, nullptr); @@ -961,10 +967,10 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v pushApiEvent(debugEvent, &vmBind->base); shouldAckEvent = false; } else { - auto tileAttached = tileSessions[tileIndex].second; - if (!tileAttached) { - static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); - } else { + + auto tileAttached = static_cast(tileSessions[tileIndex].first)->insertModule(debugEvent.info.module); + + if (tileAttached) { static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, &vmBind->base); shouldAckEvent = false; } @@ -987,7 +993,13 @@ 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) { - static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); + + auto tileAttached = static_cast(tileSessions[tileIndex].first)->removeModule(debugEvent.info.module); + + if (tileAttached) { + static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); + } + } else { pushApiEvent(debugEvent, nullptr); } @@ -1314,7 +1326,7 @@ bool DebugSessionLinux::tryReadElf(const zet_debug_memory_space_desc_t *desc, si const char *elfData = nullptr; uint64_t offset = 0; - std::unique_lock memLock(asyncThreadMutex); + std::lock_guard memLock(asyncThreadMutex); status = getElfOffset(desc, size, elfData, offset); if (status == ZE_RESULT_ERROR_INVALID_ARGUMENT) { @@ -1436,7 +1448,7 @@ bool DebugSessionLinux::tryAccessIsa(uint32_t deviceIndex, const zet_debug_memor uint64_t vmHandle = invalidHandle; bool isaAccess = false; { - std::unique_lock memLock(asyncThreadMutex); + std::lock_guard memLock(asyncThreadMutex); status = getISAVMHandle(desc, size, vmHandle); if (status == ZE_RESULT_SUCCESS) { @@ -1484,7 +1496,7 @@ ze_result_t DebugSessionLinux::accessDefaultMemForThreadAll(const zet_debug_memo } bool DebugSessionLinux::ackIsaEvents(uint32_t deviceIndex, uint64_t isaVa) { - std::unique_lock lock(asyncThreadMutex); + std::lock_guard lock(asyncThreadMutex); auto connection = clientHandleToConnection[clientHandle].get(); @@ -1514,11 +1526,34 @@ bool DebugSessionLinux::ackIsaEvents(uint32_t deviceIndex, uint64_t isaVa) { return false; } +void DebugSessionLinux::cleanRootSessionAfterDetach(uint32_t deviceIndex) { + auto connection = clientHandleToConnection[clientHandle].get(); + + for (const auto &isa : connection->isaMap[deviceIndex]) { + + //zebin modules do not store ackEvents per ISA + UNRECOVERABLE_IF(isa.second->ackEvents.size() > 0 && isa.second->perKernelModule == false); + + for (auto &event : isa.second->ackEvents) { + prelim_drm_i915_debug_event_ack eventToAck = {}; + eventToAck.type = event.type; + eventToAck.seqno = event.seqno; + eventToAck.flags = 0; + + auto ret = ioctl(PRELIM_I915_DEBUG_IOCTL_ACK_EVENT, &eventToAck); + PRINT_DEBUGGER_INFO_LOG("PRELIM_I915_DEBUG_IOCTL_ACK_EVENT seqno = %llu, ret = %d errno = %d\n", (uint64_t)event.seqno, ret, ret != 0 ? errno : 0); + } + + isa.second->ackEvents.clear(); + isa.second->moduleLoadEventAck = true; + } +} + ze_result_t DebugSessionLinux::acknowledgeEvent(const zet_debug_event_t *event) { const zet_debug_event_t apiEventToAck = *event; { - std::unique_lock lock(asyncThreadMutex); + std::lock_guard lock(asyncThreadMutex); for (size_t i = 0; i < eventsToAck.size(); i++) { if (apiEventCompare(apiEventToAck, eventsToAck[i].first)) { @@ -1580,7 +1615,7 @@ ze_result_t DebugSessionLinux::readSbaBuffer(EuThread::ThreadId threadId, NEO::S } uint64_t DebugSessionLinux::getSbaBufferGpuVa(uint64_t memoryHandle) { - std::unique_lock lock(asyncThreadMutex); + std::lock_guard lock(asyncThreadMutex); auto bindInfo = clientHandleToConnection[clientHandle]->vmToStateBaseAreaBindInfo.find(memoryHandle); if (bindInfo == clientHandleToConnection[clientHandle]->vmToStateBaseAreaBindInfo.end()) { return 0; @@ -1590,7 +1625,7 @@ uint64_t DebugSessionLinux::getSbaBufferGpuVa(uint64_t memoryHandle) { } uint64_t DebugSessionLinux::getContextStateSaveAreaGpuVa(uint64_t memoryHandle) { - std::unique_lock lock(asyncThreadMutex); + std::lock_guard lock(asyncThreadMutex); auto bindInfo = clientHandleToConnection[clientHandle]->vmToContextStateSaveAreaBindInfo.find(memoryHandle); if (bindInfo == clientHandleToConnection[clientHandle]->vmToContextStateSaveAreaBindInfo.end()) { return 0; @@ -1696,4 +1731,77 @@ void TileDebugSessionLinux::readStateSaveAreaHeader() { } }; +bool TileDebugSessionLinux::insertModule(zet_debug_event_info_module_t module) { + std::lock_guard lock(asyncThreadMutex); + modules.insert({module.load, module}); + return isAttached; +} + +bool TileDebugSessionLinux::removeModule(zet_debug_event_info_module_t module) { + std::lock_guard lock(asyncThreadMutex); + modules.erase(module.load); + return isAttached; +} + +bool TileDebugSessionLinux::processEntry() { + std::lock_guard lock(asyncThreadMutex); + processEntryState = true; + return isAttached; +} + +bool TileDebugSessionLinux::processExit() { + std::lock_guard lock(asyncThreadMutex); + processEntryState = false; + return isAttached; +} + +void TileDebugSessionLinux::attachTile() { + std::lock_guard lock(asyncThreadMutex); + + // clear apiEvents queue + apiEvents = decltype(apiEvents){}; + + if (detached) { + zet_debug_event_t debugEvent = {}; + debugEvent.type = ZET_DEBUG_EVENT_TYPE_DETACHED; + debugEvent.info.detached.reason = ZET_DEBUG_DETACH_REASON_INVALID; + + apiEvents.push(debugEvent); + } else { + if (processEntryState) { + zet_debug_event_t event = {}; + event.type = ZET_DEBUG_EVENT_TYPE_PROCESS_ENTRY; + event.flags = 0; + apiEvents.push(event); + } + + if (modules.size()) { + zet_debug_event_t event = {}; + event.type = ZET_DEBUG_EVENT_TYPE_MODULE_LOAD; + event.flags = 0; + + for (const auto &module : modules) { + memcpy_s(&event.info.module, sizeof(event.info.module), &module.second, sizeof(module.second)); + apiEvents.push(event); + } + } + } + isAttached = true; +} + +void TileDebugSessionLinux::detachTile() { + { + std::lock_guard lock(asyncThreadMutex); + isAttached = false; + + for (size_t i = 0; i < eventsToAck.size(); i++) { + + auto eventToAck = eventsToAck[i].second; + auto ret = ioctl(PRELIM_I915_DEBUG_IOCTL_ACK_EVENT, &eventToAck); + PRINT_DEBUGGER_INFO_LOG("PRELIM_I915_DEBUG_IOCTL_ACK_EVENT seqno = %llu, ret = %d errno = %d\n", (uint64_t)eventToAck.seqno, ret, ret != 0 ? errno : 0); + } + eventsToAck.clear(); + } +} + } // 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 43006eb239..568e34c5c7 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session.h +++ b/level_zero/tools/source/debug/linux/prelim/debug_session.h @@ -233,6 +233,14 @@ struct DebugSessionLinux : DebugSessionImp { void handleEnginesEvent(prelim_drm_i915_debug_event_engines *engines); virtual bool ackIsaEvents(uint32_t deviceIndex, uint64_t isaVa); + void attachTile() override { + UNRECOVERABLE_IF(true); + } + void detachTile() override { + UNRECOVERABLE_IF(true); + } + void cleanRootSessionAfterDetach(uint32_t deviceIndex) override; + void extractUuidData(uint64_t client, const UuidData &uuidData); uint64_t extractVaFromUuidString(std::string &uuid); @@ -293,8 +301,16 @@ struct TileDebugSessionLinux : DebugSessionLinux { bool closeConnection() override { return true; } ze_result_t initialize() override { return ZE_RESULT_SUCCESS; } + bool insertModule(zet_debug_event_info_module_t module); + bool removeModule(zet_debug_event_info_module_t module); + bool processEntry(); + bool processExit(); + void attachTile() override; + void detachTile() override; + protected: void startAsyncThread() override { UNRECOVERABLE_IF(true); }; + void cleanRootSessionAfterDetach(uint32_t deviceIndex) override { UNRECOVERABLE_IF(true); }; bool readModuleDebugArea() override { return true; }; @@ -347,6 +363,10 @@ struct TileDebugSessionLinux : DebugSessionLinux { DebugSessionLinux *rootDebugSession = nullptr; uint32_t tileIndex = std::numeric_limits::max(); + bool isAttached = false; + bool processEntryState = false; + + std::unordered_map modules; }; } // namespace L0 diff --git a/level_zero/tools/source/debug/windows/debug_session.h b/level_zero/tools/source/debug/windows/debug_session.h index 844f817665..041adc84f0 100644 --- a/level_zero/tools/source/debug/windows/debug_session.h +++ b/level_zero/tools/source/debug/windows/debug_session.h @@ -71,6 +71,17 @@ struct DebugSessionWindows : DebugSessionImp { bool readModuleDebugArea() override; void startAsyncThread() override; void closeAsyncThread(); + + void attachTile() override { + UNRECOVERABLE_IF(true); + } + void detachTile() override { + UNRECOVERABLE_IF(true); + } + void cleanRootSessionAfterDetach(uint32_t deviceIndex) override { + UNRECOVERABLE_IF(true); + } + static void *asyncThreadFunction(void *arg); MOCKABLE_VIRTUAL void getSbaBufferGpuVa(uint64_t &gpuVa); 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 330bf5d10f..f14cf85456 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 @@ -89,6 +89,10 @@ struct MockDebugSession : public L0::DebugSessionImp { return ZE_RESULT_SUCCESS; } + void attachTile() override { attachTileCalled = true; }; + void detachTile() override { detachTileCalled = true; }; + void cleanRootSessionAfterDetach(uint32_t deviceIndex) override { cleanRootSessionDeviceIndices.push_back(deviceIndex); }; + ze_result_t readEvent(uint64_t timeout, zet_debug_event_t *event) override { return ZE_RESULT_SUCCESS; } @@ -275,6 +279,10 @@ struct MockDebugSession : public L0::DebugSessionImp { int returnTimeDiff = -1; bool returnStateSaveAreaGpuVa = true; + + bool attachTileCalled = false; + bool detachTileCalled = false; + std::vector cleanRootSessionDeviceIndices; }; using DebugSessionTest = ::testing::Test; @@ -2474,6 +2482,7 @@ TEST_F(MultiTileDebugSessionTest, givenTileAttachEnabledWhenAttachingToTileDevic auto subDevice0 = neoDevice->getSubDevice(0)->getSpecializedDevice(); auto subDevice1 = neoDevice->getSubDevice(1)->getSpecializedDevice(); + auto tileSession1 = static_cast(sessionMock->tileSessions[1].first); auto result = zetDebugAttach(subDevice0->toHandle(), &config, &debugSession0); @@ -2485,6 +2494,7 @@ TEST_F(MultiTileDebugSessionTest, givenTileAttachEnabledWhenAttachingToTileDevic EXPECT_NE(nullptr, deviceImp->getDebugSession(config)); + EXPECT_FALSE(tileSession1->attachTileCalled); result = zetDebugAttach(subDevice1->toHandle(), &config, &debugSession1); EXPECT_EQ(ZE_RESULT_SUCCESS, result); @@ -2492,6 +2502,8 @@ TEST_F(MultiTileDebugSessionTest, givenTileAttachEnabledWhenAttachingToTileDevic EXPECT_TRUE(sessionMock->tileSessions[1].second); EXPECT_EQ(sessionMock->tileSessions[1].first, L0::DebugSession::fromHandle(debugSession1)); + EXPECT_TRUE(tileSession1->attachTileCalled); + EXPECT_FALSE(tileSession1->detachTileCalled); result = zetDebugDetach(debugSession1); @@ -2499,6 +2511,10 @@ TEST_F(MultiTileDebugSessionTest, givenTileAttachEnabledWhenAttachingToTileDevic EXPECT_NE(nullptr, deviceImp->getDebugSession(config)); EXPECT_FALSE(sessionMock->tileSessions[1].second); + EXPECT_TRUE(tileSession1->detachTileCalled); + ASSERT_EQ(1u, sessionMock->cleanRootSessionDeviceIndices.size()); + EXPECT_EQ(1u, sessionMock->cleanRootSessionDeviceIndices[0]); + result = zetDebugDetach(debugSession0); EXPECT_EQ(ZE_RESULT_SUCCESS, result); 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 7a4f9c3a28..9cfb14614f 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 @@ -56,6 +56,7 @@ struct MockIoctlHandler : public L0::DebugSessionLinux::IoctlHandler { } else if ((request == PRELIM_I915_DEBUG_IOCTL_ACK_EVENT) && (arg != nullptr)) { auto debugEvent = reinterpret_cast(arg); debugEventAcked = *debugEvent; + ackCount++; return 0; } else if ((request == PRELIM_I915_DEBUG_IOCTL_READ_UUID) && (arg != nullptr)) { prelim_drm_i915_debug_read_uuid *uuid = reinterpret_cast(arg); @@ -229,11 +230,14 @@ struct MockIoctlHandler : public L0::DebugSessionLinux::IoctlHandler { std::atomic pollCounter = 0; EventQueue eventQueue; uint64_t euControlOutputSeqno = 10; + uint32_t ackCount = 0; }; struct MockDebugSessionLinux : public L0::DebugSessionLinux { using L0::DebugSessionImp::allThreads; using L0::DebugSessionImp::apiEvents; + using L0::DebugSessionImp::attachTile; + using L0::DebugSessionImp::detachTile; using L0::DebugSessionImp::enqueueApiEvent; using L0::DebugSessionImp::expectedAttentionEvents; using L0::DebugSessionImp::interruptSent; @@ -412,6 +416,7 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux { struct MockTileDebugSessionLinux : TileDebugSessionLinux { using DebugSession::allThreads; + using DebugSessionImp::apiEvents; using DebugSessionImp::checkTriggerEventsForAttention; using DebugSessionImp::expectedAttentionEvents; using DebugSessionImp::interruptImp; @@ -420,9 +425,15 @@ struct MockTileDebugSessionLinux : TileDebugSessionLinux { using DebugSessionImp::sendInterrupts; using DebugSessionImp::stateSaveAreaHeader; using DebugSessionImp::triggerEvents; + using DebugSessionLinux::detached; + using DebugSessionLinux::pushApiEvent; + using TileDebugSessionLinux::cleanRootSessionAfterDetach; using TileDebugSessionLinux::getAllMemoryHandles; using TileDebugSessionLinux::getContextStateSaveAreaGpuVa; using TileDebugSessionLinux::getSbaBufferGpuVa; + using TileDebugSessionLinux::isAttached; + using TileDebugSessionLinux::modules; + using TileDebugSessionLinux::processEntryState; using TileDebugSessionLinux::readGpuMemory; using TileDebugSessionLinux::readModuleDebugArea; using TileDebugSessionLinux::readSbaBuffer; 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 002516f71e..fbe98a3f2c 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 @@ -400,6 +400,23 @@ TEST(DebugSessionTest, GivenRootDebugSessionWhenCreateTileSessionCalledThenSessi EXPECT_NE(nullptr, tileSession); } +TEST(DebugSessionTest, GivenRootLinuxSessionWhenCallingTileSepcificFunctionsThenUnrecoverableIsCalled) { + auto hwInfo = *NEO::defaultHwInfo.get(); + NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + + auto mockDrm = new DrmQueryMock(*neoDevice->executionEnvironment->rootDeviceEnvironments[0]); + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface); + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface->setDriverModel(std::unique_ptr(mockDrm)); + + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + + auto sessionMock = std::make_unique(zet_debug_config_t{0x1234}, &deviceImp, 10); + ASSERT_NE(nullptr, sessionMock); + + EXPECT_THROW(sessionMock->attachTile(), std::exception); + EXPECT_THROW(sessionMock->detachTile(), std::exception); +} + using DebugApiLinuxTest = Test; TEST_F(DebugApiLinuxTest, givenDeviceWhenCallingDebugAttachThenSuccessAndValidSessionHandleAreReturned) { 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 c94eed99db..441799309f 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 @@ -44,6 +44,7 @@ TEST(TileDebugSessionLinuxTest, GivenTileDebugSessionWhenCallingFunctionsThenImp EXPECT_EQ(ZE_RESULT_SUCCESS, session->initialize()); EXPECT_THROW(session->startAsyncThread(), std::exception); + EXPECT_THROW(session->cleanRootSessionAfterDetach(0), std::exception); } TEST(TileDebugSessionLinuxTest, GivenTileDebugSessionWhenCallingFunctionsThenCallsAreRedirectedToRootSession) { @@ -313,6 +314,7 @@ TEST_F(TileAttachTest, givenCmdQsCreatedAndDestroyedWhenReadingEventsThenProcess ze_result_t result = zetDebugReadEvent(tileSessions[1]->toHandle(), 0, &event); EXPECT_EQ(ZE_RESULT_SUCCESS, result); EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_PROCESS_ENTRY, event.type); + EXPECT_TRUE(tileSessions[1]->processEntryState); notification.subDeviceCount = 2; notification.subDeviceIndex = 0; @@ -326,6 +328,7 @@ TEST_F(TileAttachTest, givenCmdQsCreatedAndDestroyedWhenReadingEventsThenProcess result = zetDebugReadEvent(tileSessions[0]->toHandle(), 0, &event); EXPECT_EQ(ZE_RESULT_SUCCESS, result); EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_PROCESS_ENTRY, event.type); + EXPECT_TRUE(tileSessions[0]->processEntryState); // Handle UUID destroy for commandQueue on subdevice 0 uuid.base.flags = PRELIM_DRM_I915_DEBUG_EVENT_DESTROY; @@ -335,6 +338,7 @@ TEST_F(TileAttachTest, givenCmdQsCreatedAndDestroyedWhenReadingEventsThenProcess result = zetDebugReadEvent(tileSessions[0]->toHandle(), 0, &event); EXPECT_EQ(ZE_RESULT_SUCCESS, result); EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_PROCESS_EXIT, event.type); + EXPECT_FALSE(tileSessions[0]->processEntryState); // Handle UUID destroy for commandQueue on subdevice 1 uuid.handle = 2; @@ -344,6 +348,34 @@ TEST_F(TileAttachTest, givenCmdQsCreatedAndDestroyedWhenReadingEventsThenProcess result = zetDebugReadEvent(tileSessions[1]->toHandle(), 0, &event); EXPECT_EQ(ZE_RESULT_SUCCESS, result); EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_PROCESS_EXIT, event.type); + EXPECT_FALSE(tileSessions[1]->processEntryState); +} + +TEST_F(TileAttachTest, givenTileSessionWhenAttchingThenProcessEntryEventIsGeneratedBasedOnEntryState) { + + tileSessions[1]->processEntryState = true; + + tileSessions[1]->attachTile(); + ASSERT_EQ(1u, tileSessions[1]->apiEvents.size()); + + auto event = tileSessions[1]->apiEvents.front(); + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_PROCESS_ENTRY, event.type); + + tileSessions[1]->detachTile(); + tileSessions[1]->processEntryState = false; + + tileSessions[1]->attachTile(); + EXPECT_EQ(0u, tileSessions[1]->apiEvents.size()); +} + +TEST_F(TileAttachTest, givenDetachedRootSessionWhenAttchingTileThenDetachedEventIsGenerated) { + tileSessions[1]->detached = true; + + tileSessions[1]->attachTile(); + ASSERT_EQ(1u, tileSessions[1]->apiEvents.size()); + + auto event = tileSessions[1]->apiEvents.front(); + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_DETACHED, event.type); } TEST_F(TileAttachTest, givenPollReturnsErrorAndEinvalWhenReadingEventsThenProcessDetachedEventForAllTilesIsReturned) { @@ -729,6 +761,66 @@ TEST_F(TileAttachTest, givenStoppedThreadsWhenHandlingAttentionEventThenStoppedT EXPECT_TRUE(tileSessions[1]->triggerEvents); } +TEST_F(TileAttachTest, GivenEventsWithOsEventToAckWhenDetachingTileThenAllEventsAreAcked) { + uint64_t vmBindIsaData[sizeof(prelim_drm_i915_debug_event_vm_bind) / sizeof(uint64_t) + 3 * sizeof(typeOfUUID)]; + prelim_drm_i915_debug_event_vm_bind *vmBindIsa = reinterpret_cast(&vmBindIsaData); + vmBindIsa->base.type = PRELIM_DRM_I915_DEBUG_EVENT_VM_BIND; + vmBindIsa->base.flags = PRELIM_DRM_I915_DEBUG_EVENT_CREATE | PRELIM_DRM_I915_DEBUG_EVENT_NEED_ACK; + vmBindIsa->base.size = sizeof(prelim_drm_i915_debug_event_vm_bind) + 3 * sizeof(typeOfUUID); + vmBindIsa->base.seqno = 10; + vmBindIsa->client_handle = MockDebugSessionLinux::mockClientHandle; + vmBindIsa->va_start = isaGpuVa; + vmBindIsa->va_length = isaSize; + vmBindIsa->vm_handle = vm0; + vmBindIsa->num_uuids = 0; + + auto handler = new MockIoctlHandler; + rootSession->ioctlHandler.reset(handler); + + zet_debug_event_t debugEvent = {}; + debugEvent.type = ZET_DEBUG_EVENT_TYPE_MODULE_LOAD; + debugEvent.info.module.format = ZET_MODULE_DEBUG_INFO_FORMAT_ELF_DWARF; + debugEvent.info.module.load = isaGpuVa; + debugEvent.info.module.moduleBegin = 0; + debugEvent.info.module.moduleEnd = 0; + + tileSessions[0]->pushApiEvent(debugEvent, &vmBindIsa->base); + + debugEvent.info.module.load = 0x999000; + vmBindIsa->va_start = 0x999000; + tileSessions[0]->pushApiEvent(debugEvent, &vmBindIsa->base); + + debugEvent.info.module.load = 0x12000; + vmBindIsa->va_start = 0x12000; + tileSessions[0]->pushApiEvent(debugEvent, &vmBindIsa->base); + + tileSessions[0]->detachTile(); + EXPECT_EQ(3u, handler->ackCount); + EXPECT_EQ(vmBindIsa->base.seqno, handler->debugEventAcked.seqno); + EXPECT_EQ(vmBindIsa->base.type, handler->debugEventAcked.type); +} + +TEST_F(TileAttachTest, GivenTileAttachedAndIsaWithOsEventToAckWhenDetachingTileThenAllEventsAreAcked) { + auto handler = new MockIoctlHandler; + rootSession->ioctlHandler.reset(handler); + + rootSession->tileSessions[0].second = true; + tileSessions[0]->attachTile(); + + addIsaVmBindEvent(rootSession, vm0, true, true); + + EXPECT_EQ(0u, handler->ackCount); + rootSession->detachTileDebugSession(tileSessions[0]); + + EXPECT_EQ(1u, handler->ackCount); + EXPECT_EQ(20u, handler->debugEventAcked.seqno); + EXPECT_EQ(static_cast(PRELIM_DRM_I915_DEBUG_EVENT_VM_BIND), handler->debugEventAcked.type); + + auto isa = rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->isaMap[0][isaGpuVa].get(); + EXPECT_EQ(0u, isa->ackEvents.size()); + EXPECT_TRUE(isa->moduleLoadEventAck); +} + using TileAttachAsyncThreadTest = Test; TEST_F(TileAttachAsyncThreadTest, GivenInterruptedThreadsWhenNoAttentionEventIsReadThenThreadUnavailableEventIsGenerated) { @@ -758,13 +850,13 @@ TEST_F(TileAttachAsyncThreadTest, GivenInterruptedThreadsWhenNoAttentionEventIsR } TEST_F(TileAttachTest, GivenEventWithL0ZebinModuleWhenHandlingEventThenModuleLoadAndUnloadEventsAreReportedForLastKernel) { - uint64_t isaGpuVa = 0x345000; uint64_t isaGpuVa2 = 0x340000; - uint64_t isaSize = 0x2000; uint64_t vmBindIsaData[sizeof(prelim_drm_i915_debug_event_vm_bind) / sizeof(uint64_t) + 3 * sizeof(typeOfUUID)]; prelim_drm_i915_debug_event_vm_bind *vmBindIsa = reinterpret_cast(&vmBindIsaData); rootSession->tileSessions[0].second = true; + tileSessions[0]->isAttached = true; + auto handler = new MockIoctlHandler; rootSession->ioctlHandler.reset(handler); @@ -827,7 +919,10 @@ TEST_F(TileAttachTest, GivenEventWithL0ZebinModuleWhenHandlingEventThenModuleLoa bool attachedAfterModuleLoaded = false; if (rootSession->tileSessions[tile].second == false) { - rootSession->tileSessions[tile].second = true; + zet_debug_session_handle_t session = nullptr; + zet_debug_config_t config = {}; + config.pid = 0x1234; + zetDebugAttach(neoDevice->getSubDevice(tile)->getSpecializedDevice()->toHandle(), &config, &session); attachedAfterModuleLoaded = true; } @@ -909,5 +1004,54 @@ TEST_F(TileAttachTest, GivenEventWithL0ZebinModuleWhenHandlingEventThenModuleLoa } } +TEST_F(TileAttachTest, GivenZebinModuleDestroyedBeforeAttachWhenAttachingThenModuleLoadEventIsNotReported) { + uint64_t isaGpuVa2 = 0x340000; + uint64_t vmBindIsaData[sizeof(prelim_drm_i915_debug_event_vm_bind) / sizeof(uint64_t) + 3 * sizeof(typeOfUUID)]; + prelim_drm_i915_debug_event_vm_bind *vmBindIsa = reinterpret_cast(&vmBindIsaData); + uint64_t vmHandle = vm1; + + vmBindIsa->base.type = PRELIM_DRM_I915_DEBUG_EVENT_VM_BIND; + vmBindIsa->base.flags = PRELIM_DRM_I915_DEBUG_EVENT_CREATE | PRELIM_DRM_I915_DEBUG_EVENT_NEED_ACK; + vmBindIsa->base.size = sizeof(prelim_drm_i915_debug_event_vm_bind) + 3 * sizeof(typeOfUUID); + vmBindIsa->base.seqno = 10; + vmBindIsa->client_handle = MockDebugSessionLinux::mockClientHandle; + vmBindIsa->va_start = isaGpuVa; + vmBindIsa->va_length = isaSize; + vmBindIsa->vm_handle = vmHandle; + vmBindIsa->num_uuids = 4; + auto *uuids = reinterpret_cast(ptrOffset(vmBindIsaData, sizeof(prelim_drm_i915_debug_event_vm_bind))); + typeOfUUID uuidsTemp[4]; + uuidsTemp[0] = static_cast(isaUUID); + uuidsTemp[1] = static_cast(cookieUUID); + uuidsTemp[2] = static_cast(elfUUID); + uuidsTemp[3] = static_cast(zebinModuleUUID); + + memcpy(uuids, uuidsTemp, sizeof(uuidsTemp)); + rootSession->handleEvent(&vmBindIsa->base); + + vmBindIsa->va_start = isaGpuVa2; + vmBindIsa->base.seqno = 11; + + rootSession->handleEvent(&vmBindIsa->base); + + EXPECT_EQ(1u, rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule.size()); + EXPECT_EQ(1u, tileSessions[1]->modules.size()); + EXPECT_EQ(isaGpuVa2, tileSessions[1]->modules.begin()->second.load); + + vmBindIsa->base.flags = PRELIM_DRM_I915_DEBUG_EVENT_DESTROY; + vmBindIsa->va_start = isaGpuVa2; + + rootSession->handleEvent(&vmBindIsa->base); + + EXPECT_EQ(0u, rootSession->apiEvents.size()); + + vmBindIsa->base.flags = PRELIM_DRM_I915_DEBUG_EVENT_DESTROY; + vmBindIsa->va_start = isaGpuVa; + + rootSession->handleEvent(&vmBindIsa->base); + + EXPECT_EQ(0u, tileSessions[1]->modules.size()); +} + } // namespace ult } // namespace L0 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 877d63a955..ae5232c879 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 @@ -52,6 +52,9 @@ struct MockDebugSessionWindows : DebugSessionWindows { using DebugSessionWindows::wddm; using DebugSessionWindows::writeGpuMemory; using L0::DebugSessionImp::apiEvents; + using L0::DebugSessionImp::attachTile; + using L0::DebugSessionImp::cleanRootSessionAfterDetach; + using L0::DebugSessionImp::detachTile; using L0::DebugSessionImp::getStateSaveAreaHeader; using L0::DebugSessionImp::isValidGpuAddress; @@ -115,6 +118,16 @@ struct DebugApiWindowsFixture : public DeviceFixture { using DebugApiWindowsTest = Test; +TEST_F(DebugApiWindowsTest, GivenSessionWhenCallingUnsupportedMethodsThenUnrecoverableIsCalled) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto session = std::make_unique(config, device); + EXPECT_THROW(session->attachTile(), std::exception); + EXPECT_THROW(session->detachTile(), std::exception); + EXPECT_THROW(session->cleanRootSessionAfterDetach(0), std::exception); +} + TEST_F(DebugApiWindowsTest, GivenReadOfGpuVaFailDueToEscapeCallFailureWhenTryingToReadSbaThenErrorIsReported) { zet_debug_config_t config = {}; config.pid = 0x1234;