From adef8fbc8d0613496784295b7318d2ee5cc692a2 Mon Sep 17 00:00:00 2001 From: Jitendra Sharma Date: Thu, 1 Feb 2024 16:08:46 +0000 Subject: [PATCH] feature: Implement Process entry/exit event with xe Related-To: NEO-9671 Signed-off-by: Jitendra Sharma --- .../source/debug/linux/xe/debug_session.cpp | 23 +++++ .../source/debug/linux/xe/debug_session.h | 1 + .../linux/xe/test_debug_api_linux_xe.cpp | 93 +++++++++++++++++++ 3 files changed, 117 insertions(+) diff --git a/level_zero/tools/source/debug/linux/xe/debug_session.cpp b/level_zero/tools/source/debug/linux/xe/debug_session.cpp index 2d7a55ad2e..1595df282c 100644 --- a/level_zero/tools/source/debug/linux/xe/debug_session.cpp +++ b/level_zero/tools/source/debug/linux/xe/debug_session.cpp @@ -231,6 +231,14 @@ void DebugSessionLinuxXe::handleEvent(drm_xe_eudebug_event *event) { if (event->flags & DRM_XE_EUDEBUG_EVENT_CREATE) { UNRECOVERABLE_IF(clientHandleToConnection.find(execQueue->client_handle) == clientHandleToConnection.end()); + + if (!processEntryEventGenerated) { + zet_debug_event_t debugEvent = {}; + debugEvent.type = ZET_DEBUG_EVENT_TYPE_PROCESS_ENTRY; + pushApiEvent(debugEvent); + processEntryEventGenerated = true; + } + clientHandleToConnection[execQueue->client_handle]->execQueues[execQueue->exec_queue_handle].vmHandle = execQueue->vm_handle; clientHandleToConnection[execQueue->client_handle]->execQueues[execQueue->exec_queue_handle].engineClass = execQueue->engine_class; for (uint16_t idx = 0; idx < execQueue->width; idx++) { @@ -243,6 +251,21 @@ void DebugSessionLinuxXe::handleEvent(drm_xe_eudebug_event *event) { clientHandleToConnection[execQueue->client_handle]->lrcHandleToVmHandle.erase(execQueue->lrc_handle[idx]); } clientHandleToConnection[execQueue->client_handle]->execQueues.erase(execQueue->exec_queue_handle); + { + bool lastExecQueue = true; + for (const auto &connection : clientHandleToConnection) { + if (!connection.second->execQueues.empty()) { + lastExecQueue = false; + break; + } + } + if (lastExecQueue) { + zet_debug_event_t debugEvent = {}; + debugEvent.type = ZET_DEBUG_EVENT_TYPE_PROCESS_EXIT; + pushApiEvent(debugEvent); + processEntryEventGenerated = false; + } + } } PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE flags = %u len = %lu client_handle = %llu\ diff --git a/level_zero/tools/source/debug/linux/xe/debug_session.h b/level_zero/tools/source/debug/linux/xe/debug_session.h index 280ca587de..75b44fa7c2 100644 --- a/level_zero/tools/source/debug/linux/xe/debug_session.h +++ b/level_zero/tools/source/debug/linux/xe/debug_session.h @@ -164,6 +164,7 @@ struct DebugSessionLinuxXe : DebugSessionLinux { ze_result_t readEventImp(drm_xe_eudebug_event *drmDebugEvent); int ioctl(unsigned long request, void *arg); + std::atomic processEntryEventGenerated = false; }; } // namespace L0 diff --git a/level_zero/tools/test/unit_tests/sources/debug/linux/xe/test_debug_api_linux_xe.cpp b/level_zero/tools/test/unit_tests/sources/debug/linux/xe/test_debug_api_linux_xe.cpp index 9c86423203..5a3582e744 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/linux/xe/test_debug_api_linux_xe.cpp +++ b/level_zero/tools/test/unit_tests/sources/debug/linux/xe/test_debug_api_linux_xe.cpp @@ -744,5 +744,98 @@ TEST_F(DebugApiLinuxTestXe, GivenEuDebugExecQueueEventWithEventDestroyFlagWhenHa EXPECT_TRUE(session->clientHandleToConnection[execQueue->client_handle]->lrcHandleToVmHandle.empty()); } +TEST_F(DebugApiLinuxTestXe, whenHandleExecQueueEventThenProcessEnterAndProcessExitEventTriggeredUponFirstExecQueueCreateAndLastExecQueueDestroyRespectively) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto session = std::make_unique(config, device, 10); + ASSERT_NE(nullptr, session); + + session->clientHandleToConnection.clear(); + + // First client connection + drm_xe_eudebug_event_client client1; + client1.base.type = DRM_XE_EUDEBUG_EVENT_OPEN; + client1.base.flags = DRM_XE_EUDEBUG_EVENT_CREATE; + client1.client_handle = 0x123456789; + session->handleEvent(reinterpret_cast(&client1)); + + uint64_t execQueueData[sizeof(drm_xe_eudebug_event_exec_queue) / sizeof(uint64_t) + 3 * sizeof(typeOfLrcHandle)]; + auto *lrcHandle = reinterpret_cast(ptrOffset(execQueueData, sizeof(drm_xe_eudebug_event_exec_queue))); + typeOfLrcHandle lrcHandleTemp[3]; + const uint64_t lrcHandle0 = 2; + const uint64_t lrcHandle1 = 3; + const uint64_t lrcHandle2 = 5; + lrcHandleTemp[0] = static_cast(lrcHandle0); + lrcHandleTemp[1] = static_cast(lrcHandle1); + lrcHandleTemp[2] = static_cast(lrcHandle2); + + drm_xe_eudebug_event_exec_queue *execQueue = reinterpret_cast(&execQueueData); + execQueue->base.type = DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE; + execQueue->base.flags = DRM_XE_EUDEBUG_EVENT_CREATE; + execQueue->client_handle = client1.client_handle; + execQueue->vm_handle = 0x1234; + execQueue->exec_queue_handle = 0x100; + execQueue->engine_class = DRM_XE_ENGINE_CLASS_COMPUTE; + execQueue->width = 3; + memcpy(lrcHandle, lrcHandleTemp, sizeof(lrcHandleTemp)); + session->handleEvent(&execQueue->base); // ExecQueue create event handle for first client + + zet_debug_event_t event1 = {}; + ze_result_t result = zetDebugReadEvent(session->toHandle(), 0, &event1); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_PROCESS_ENTRY, event1.type); + + // second client connection + drm_xe_eudebug_event_client client2; + client2.base.type = DRM_XE_EUDEBUG_EVENT_OPEN; + client2.base.flags = DRM_XE_EUDEBUG_EVENT_CREATE; + client2.client_handle = 0x123456788; + session->handleEvent(reinterpret_cast(&client2)); + + execQueue->client_handle = client2.client_handle; + execQueue->vm_handle = 0x1235; + execQueue->exec_queue_handle = 0x101; + session->handleEvent(&execQueue->base); // ExecQueue1 create event handle for second client + + zet_debug_event_t event2 = {}; + result = zetDebugReadEvent(session->toHandle(), 0, &event2); + EXPECT_EQ(ZE_RESULT_NOT_READY, result); + + execQueue->client_handle = client2.client_handle; + execQueue->vm_handle = 0x1236; + execQueue->exec_queue_handle = 0x102; + session->handleEvent(&execQueue->base); // ExecQueue2 create event handle for second client + result = zetDebugReadEvent(session->toHandle(), 0, &event2); + EXPECT_EQ(ZE_RESULT_NOT_READY, result); + + // ExecQueue Destroy event handle + execQueue->base.type = DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE; + execQueue->base.flags = DRM_XE_EUDEBUG_EVENT_DESTROY; + execQueue->client_handle = client1.client_handle; + execQueue->vm_handle = 0x1234; + execQueue->exec_queue_handle = 0x100; + execQueue->engine_class = DRM_XE_ENGINE_CLASS_COMPUTE; + execQueue->width = 3; + session->handleEvent(&execQueue->base); + result = zetDebugReadEvent(session->toHandle(), 0, &event2); + EXPECT_EQ(ZE_RESULT_NOT_READY, result); + + execQueue->client_handle = client2.client_handle; + execQueue->vm_handle = 0x1235; + execQueue->exec_queue_handle = 0x101; + session->handleEvent(&execQueue->base); + result = zetDebugReadEvent(session->toHandle(), 0, &event2); + EXPECT_EQ(ZE_RESULT_NOT_READY, result); + + execQueue->client_handle = client2.client_handle; + execQueue->vm_handle = 0x1236; + execQueue->exec_queue_handle = 0x102; + session->handleEvent(&execQueue->base); + result = zetDebugReadEvent(session->toHandle(), 0, &event2); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_PROCESS_EXIT, event2.type); +} + } // namespace ult } // namespace L0 \ No newline at end of file