From b34e8646acc55bfb6342341ca844e79642a75f54 Mon Sep 17 00:00:00 2001 From: Jitendra Sharma Date: Thu, 18 Jan 2024 18:39:41 +0000 Subject: [PATCH] feature: Implement Xe Eu debug Open and Exec Queue events Related-To: NEO-8407 Signed-off-by: Jitendra Sharma --- .../source/debug/linux/debug_session.cpp | 7 +- .../tools/source/debug/linux/debug_session.h | 3 +- .../debug/linux/prelim/debug_session.cpp | 7 +- .../source/debug/linux/prelim/debug_session.h | 3 +- .../source/debug/linux/xe/debug_session.cpp | 85 +++++- .../source/debug/linux/xe/debug_session.h | 94 ++++--- .../xe/debug_session_fixtures_linux_xe.h | 36 +++ .../linux/xe/test_debug_api_linux_xe.cpp | 252 +++++++++++++++++- 8 files changed, 433 insertions(+), 54 deletions(-) diff --git a/level_zero/tools/source/debug/linux/debug_session.cpp b/level_zero/tools/source/debug/linux/debug_session.cpp index 9c05a5c4c4..d81adaa64a 100644 --- a/level_zero/tools/source/debug/linux/debug_session.cpp +++ b/level_zero/tools/source/debug/linux/debug_session.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2023 Intel Corporation + * Copyright (C) 2021-2024 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -116,4 +116,9 @@ std::unique_ptr DebugSessionLinux::getInternalEvent() { return eventMemory; } +void DebugSessionLinux::closeAsyncThread() { + asyncThread.close(); + internalEventThread.close(); +} + } // namespace L0 diff --git a/level_zero/tools/source/debug/linux/debug_session.h b/level_zero/tools/source/debug/linux/debug_session.h index b8c5f748f3..183a1155e5 100644 --- a/level_zero/tools/source/debug/linux/debug_session.h +++ b/level_zero/tools/source/debug/linux/debug_session.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Intel Corporation + * Copyright (C) 2023-2024 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -20,6 +20,7 @@ struct DebugSessionLinux : DebugSessionImp { DebugSessionLinux(const zet_debug_config_t &config, Device *device, int fd) : DebugSessionImp(config, device), fd(fd){}; static ze_result_t translateDebuggerOpenErrno(int error); bool closeFd(); + void closeAsyncThread(); int fd = 0; std::atomic internalThreadHasStarted{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 73aa0fa708..686537f7e6 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session.cpp +++ b/level_zero/tools/source/debug/linux/prelim/debug_session.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Intel Corporation + * Copyright (C) 2022-2024 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -322,11 +322,6 @@ void DebugSessionLinuxi915::startAsyncThread() { asyncThread.thread = NEO::Thread::create(asyncThreadFunction, reinterpret_cast(this)); } -void DebugSessionLinuxi915::closeAsyncThread() { - asyncThread.close(); - internalEventThread.close(); -} - void DebugSessionLinuxi915::handleEventsAsync() { auto eventMemory = getInternalEvent(); if (eventMemory != nullptr) { 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 fcb39a628f..6d818cacce 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session.h +++ b/level_zero/tools/source/debug/linux/prelim/debug_session.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Intel Corporation + * Copyright (C) 2022-2024 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -195,7 +195,6 @@ struct DebugSessionLinuxi915 : DebugSessionLinux { static void *asyncThreadFunction(void *arg); void startAsyncThread() override; - void closeAsyncThread(); virtual std::vector getAllMemoryHandles() { std::vector allVms; 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 95c8db83ee..cc4c45fa2a 100644 --- a/level_zero/tools/source/debug/linux/xe/debug_session.cpp +++ b/level_zero/tools/source/debug/linux/xe/debug_session.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Intel Corporation + * Copyright (C) 2023-2024 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -30,7 +30,7 @@ DebugSessionLinuxXe::DebugSessionLinuxXe(const zet_debug_config_t &config, Devic }; DebugSessionLinuxXe::~DebugSessionLinuxXe() { - // closeAsyncThread(); + closeAsyncThread(); closeInternalEventsThread(); closeFd(); } @@ -83,6 +83,31 @@ ze_result_t DebugSessionLinuxXe::initialize() { return ZE_RESULT_SUCCESS; } +void DebugSessionLinuxXe::handleEventsAsync() { + auto eventMemory = getInternalEvent(); + if (eventMemory != nullptr) { + auto debugEvent = reinterpret_cast(eventMemory.get()); + handleEvent(debugEvent); + } +} + +void *DebugSessionLinuxXe::asyncThreadFunction(void *arg) { + DebugSessionLinuxXe *self = reinterpret_cast(arg); + PRINT_DEBUGGER_INFO_LOG("Debugger async thread start\n", ""); + + while (self->asyncThread.threadActive) { + self->handleEventsAsync(); + } + + PRINT_DEBUGGER_INFO_LOG("Debugger async thread closing\n", ""); + + return nullptr; +} + +void DebugSessionLinuxXe::startAsyncThread() { + asyncThread.thread = NEO::Thread::create(asyncThreadFunction, reinterpret_cast(this)); +} + void DebugSessionLinuxXe::readInternalEventsAsync() { struct pollfd pollFd = { @@ -159,4 +184,60 @@ bool DebugSessionLinuxXe::closeConnection() { return closeFd(); } +void DebugSessionLinuxXe::handleEvent(drm_xe_eudebug_event *event) { + auto type = event->type; + + PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type = %u flags = %u seqno = %llu len = %lu", + (uint16_t)event->type, (uint16_t)event->flags, (uint64_t)event->seqno, (uint32_t)event->len); + + switch (type) { + case DRM_XE_EUDEBUG_EVENT_OPEN: { + auto clientEvent = reinterpret_cast(event); + + if (event->flags & DRM_XE_EUDEBUG_EVENT_CREATE) { + DEBUG_BREAK_IF(clientHandleToConnection.find(clientEvent->client_handle) != clientHandleToConnection.end()); + clientHandleToConnection[clientEvent->client_handle].reset(new ClientConnection); + clientHandleToConnection[clientEvent->client_handle]->client = *clientEvent; + } + + if (event->flags & DRM_XE_EUDEBUG_EVENT_DESTROY) { + clientHandleClosed = clientEvent->client_handle; + } + + PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: DRM_XE_EUDEBUG_EVENT_OPEN flags = %u len = %lu client.handle = %llu\n", + (uint16_t)event->flags, (uint32_t)event->len, (uint64_t)clientEvent->client_handle); + + } break; + + case DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE: { + drm_xe_eudebug_event_exec_queue *execQueue = reinterpret_cast(event); + + if (event->flags & DRM_XE_EUDEBUG_EVENT_CREATE) { + UNRECOVERABLE_IF(clientHandleToConnection.find(execQueue->client_handle) == clientHandleToConnection.end()); + 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++) { + clientHandleToConnection[execQueue->client_handle]->lrcHandleToVmHandle[execQueue->lrc_handle[idx]] = execQueue->vm_handle; + } + } + + if (event->flags & DRM_XE_EUDEBUG_EVENT_DESTROY) { + for (uint16_t idx = 0; idx < execQueue->width; idx++) { + clientHandleToConnection[execQueue->client_handle]->lrcHandleToVmHandle.erase(execQueue->lrc_handle[idx]); + } + clientHandleToConnection[execQueue->client_handle]->execQueues.erase(execQueue->exec_queue_handle); + } + + PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE flags = %u len = %lu client_handle = %llu\ + vm_handle = %llu exec_queue_handle = %llu engine_class = %u\n", + (uint16_t)event->flags, (uint32_t)event->len, (uint64_t)execQueue->client_handle, (uint64_t)execQueue->vm_handle, + (uint64_t)execQueue->exec_queue_handle, (uint16_t)execQueue->engine_class); + } break; + + default: + PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: UNHANDLED %u flags = %u len = %lu\n", (uint16_t)event->type, (uint16_t)event->flags, (uint32_t)event->len); + break; + } +} + } // namespace L0 \ No newline at end of file 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 aa2ff67928..2b6ba66d2c 100644 --- a/level_zero/tools/source/debug/linux/xe/debug_session.h +++ b/level_zero/tools/source/debug/linux/xe/debug_session.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Intel Corporation + * Copyright (C) 2023-2024 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -42,8 +42,54 @@ struct DebugSessionLinuxXe : DebugSessionLinux { return ZE_RESULT_SUCCESS; } - void startAsyncThread() override { - } + struct IoctlHandlerXe : DebugSessionLinux::IoctlHandler { + int ioctl(int fd, unsigned long request, void *arg) override { + int ret = 0; + int error = 0; + bool shouldRetryIoctl = false; + do { + shouldRetryIoctl = false; + ret = NEO::SysCalls::ioctl(fd, request, arg); + error = errno; + + if (ret == -1) { + shouldRetryIoctl = (error == EINTR || error == EAGAIN || error == EBUSY); + + if (request == DRM_XE_EUDEBUG_IOCTL_EU_CONTROL) { + shouldRetryIoctl = (error == EINTR || error == EAGAIN); + } + } + } while (shouldRetryIoctl); + return ret; + } + }; + + using ContextHandle = uint64_t; + using ExecQueueHandle = uint64_t; + + struct ContextParams { + ContextHandle handle = 0; + uint64_t vm = UINT64_MAX; + std::vector engines; + }; + + struct ExecQueueParams { + uint64_t vmHandle = 0; + uint16_t engineClass = UINT16_MAX; + }; + + struct BindInfo { + uint64_t gpuVa = 0; + uint64_t size = 0; + }; + + std::unique_ptr ioctlHandler; + uint32_t xeDebuggerVersion = 0; + + protected: + void startAsyncThread() override; + static void *asyncThreadFunction(void *arg); + void handleEventsAsync(); bool readModuleDebugArea() override { UNRECOVERABLE_IF(true); @@ -100,52 +146,18 @@ struct DebugSessionLinuxXe : DebugSessionLinux { UNRECOVERABLE_IF(true); } - struct IoctlHandlerXe : DebugSessionLinux::IoctlHandler { - int ioctl(int fd, unsigned long request, void *arg) override { - int ret = 0; - int error = 0; - bool shouldRetryIoctl = false; - do { - shouldRetryIoctl = false; - ret = NEO::SysCalls::ioctl(fd, request, arg); - error = errno; - - if (ret == -1) { - shouldRetryIoctl = (error == EINTR || error == EAGAIN || error == EBUSY); - - if (request == DRM_XE_EUDEBUG_IOCTL_EU_CONTROL) { - shouldRetryIoctl = (error == EINTR || error == EAGAIN); - } - } - } while (shouldRetryIoctl); - return ret; - } - }; - - using ContextHandle = uint64_t; - - struct ContextParams { - ContextHandle handle = 0; - uint64_t vm = UINT64_MAX; - std::vector engines; - }; - - struct BindInfo { - uint64_t gpuVa = 0; - uint64_t size = 0; - }; - struct ClientConnection { drm_xe_eudebug_event_client client = {}; + std::unordered_map execQueues; + std::unordered_map lrcHandleToVmHandle; std::unordered_map vmToModuleDebugAreaBindInfo; }; + std::vector> pendingVmBindEvents; bool checkAllEventsCollected(); - void handleEvent(drm_xe_eudebug_event *event); + MOCKABLE_VIRTUAL void handleEvent(drm_xe_eudebug_event *event); void readInternalEventsAsync() override; void pushApiEvent(zet_debug_event_t &debugEvent); - std::unique_ptr ioctlHandler; - uint32_t xeDebuggerVersion = 0; std::unordered_map> clientHandleToConnection; std::atomic detached{false}; diff --git a/level_zero/tools/test/unit_tests/sources/debug/linux/xe/debug_session_fixtures_linux_xe.h b/level_zero/tools/test/unit_tests/sources/debug/linux/xe/debug_session_fixtures_linux_xe.h index b0fd654465..48d994dd3f 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/linux/xe/debug_session_fixtures_linux_xe.h +++ b/level_zero/tools/test/unit_tests/sources/debug/linux/xe/debug_session_fixtures_linux_xe.h @@ -33,6 +33,7 @@ namespace L0 { namespace ult { +using typeOfLrcHandle = std::decay::type; struct DebugApiLinuxXeFixture : public DeviceFixture { void setUp() { @@ -97,8 +98,17 @@ struct MockIoctlHandlerXe : public L0::DebugSessionLinuxXe::IoctlHandlerXe { struct MockDebugSessionLinuxXe : public L0::DebugSessionLinuxXe { using L0::DebugSessionImp::apiEvents; + using L0::DebugSessionLinuxXe::asyncThread; + using L0::DebugSessionLinuxXe::asyncThreadFunction; + using L0::DebugSessionLinuxXe::clientHandleClosed; + using L0::DebugSessionLinuxXe::clientHandleToConnection; + using L0::DebugSessionLinuxXe::handleEvent; using L0::DebugSessionLinuxXe::internalEventQueue; using L0::DebugSessionLinuxXe::internalEventThread; + using L0::DebugSessionLinuxXe::invalidClientHandle; + using L0::DebugSessionLinuxXe::readEventImp; + using L0::DebugSessionLinuxXe::readInternalEventsAsync; + using L0::DebugSessionLinuxXe::startAsyncThread; MockDebugSessionLinuxXe(const zet_debug_config_t &config, L0::Device *device, int debugFd, void *params) : DebugSessionLinuxXe(config, device, debugFd, params) { clientHandleToConnection[mockClientHandle].reset(new ClientConnection); @@ -115,9 +125,35 @@ struct MockDebugSessionLinuxXe : public L0::DebugSessionLinuxXe { } return DebugSessionLinuxXe::initialize(); } + + std::unique_ptr getInternalEvent() override { + getInternalEventCounter++; + if (synchronousInternalEventRead) { + readInternalEventsAsync(); + } + return DebugSessionLinuxXe::getInternalEvent(); + } + + bool synchronousInternalEventRead = false; + std::atomic getInternalEventCounter = 0; ze_result_t initializeRetVal = ZE_RESULT_FORCE_UINT32; static constexpr uint64_t mockClientHandle = 1; }; +struct MockAsyncThreadDebugSessionLinuxXe : public MockDebugSessionLinuxXe { + using MockDebugSessionLinuxXe::MockDebugSessionLinuxXe; + static void *mockAsyncThreadFunction(void *arg) { + DebugSessionLinuxXe::asyncThreadFunction(arg); + reinterpret_cast(arg)->asyncThreadFinished = true; + return nullptr; + } + + void startAsyncThread() override { + asyncThread.thread = NEO::Thread::create(mockAsyncThreadFunction, reinterpret_cast(this)); + } + + std::atomic asyncThreadFinished{false}; +}; + } // namespace ult } // namespace L0 \ No newline at end of file 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 ed26d4ca69..ddd76e70b9 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 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Intel Corporation + * Copyright (C) 2023-2024 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -412,5 +412,255 @@ TEST_F(DebugApiLinuxTestXe, GivenMoreThan3EventsInQueueThenInternalEventsOnlyRea EXPECT_EQ(static_cast(DRM_XE_EUDEBUG_EVENT_READ), handler->debugEventInput.type); } +TEST_F(DebugApiLinuxTestXe, GivenEventInInternalEventQueueWhenAsyncThreadFunctionIsExecutedThenEventIsHandled) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto session = std::make_unique(config, device, 10); + ASSERT_NE(nullptr, session); + + session->clientHandleToConnection.clear(); + + uint8_t eventClientData[sizeof(drm_xe_eudebug_event_client)]; + auto client = reinterpret_cast(&eventClientData); + client->base.type = DRM_XE_EUDEBUG_EVENT_OPEN; + client->base.flags = DRM_XE_EUDEBUG_EVENT_CREATE; + client->base.len = sizeof(drm_xe_eudebug_event_client); + client->client_handle = 0x123456789; + + auto memory = std::make_unique(sizeof(drm_xe_eudebug_event_client) / sizeof(uint64_t)); + memcpy(memory.get(), client, sizeof(drm_xe_eudebug_event_client)); + + // Clear the event queue before using it + while (!session->internalEventQueue.empty()) { + session->internalEventQueue.pop(); + } + session->internalEventQueue.push(std::move(memory)); + + session->startAsyncThread(); + + while (session->getInternalEventCounter == 0) + ; + EXPECT_TRUE(session->asyncThread.threadActive); + EXPECT_FALSE(session->asyncThreadFinished); + + session->closeAsyncThread(); + + EXPECT_FALSE(session->asyncThread.threadActive); + EXPECT_TRUE(session->asyncThreadFinished); + EXPECT_EQ(session->clientHandleToConnection.size(), 1ul); + EXPECT_NE(session->clientHandleToConnection.find(client->client_handle), session->clientHandleToConnection.end()); + + uint64_t wrongClientHandle = 34; + EXPECT_EQ(session->clientHandleToConnection.find(wrongClientHandle), session->clientHandleToConnection.end()); +} + +TEST_F(DebugApiLinuxTestXe, GivenNoEventInInternalEventQueueWhenAsyncThreadFunctionIsExecutedThenEventsAreCheckedForAvailability) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto session = std::make_unique(config, device, 10); + ASSERT_NE(nullptr, session); + + // Clear the event queue before using it + while (!session->internalEventQueue.empty()) { + session->internalEventQueue.pop(); + } + + session->startAsyncThread(); + + while (session->getInternalEventCounter == 0) + ; + EXPECT_TRUE(session->asyncThread.threadActive); + EXPECT_FALSE(session->asyncThreadFinished); + + session->closeAsyncThread(); + + EXPECT_FALSE(session->asyncThread.threadActive); + EXPECT_TRUE(session->asyncThreadFinished); +} + +TEST_F(DebugApiLinuxTestXe, GivenOneEuDebugOpenEventAndOneIncorrectEventWhenHandleEventThenEventsAreHandled) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto session = std::make_unique(config, device, 10); + ASSERT_NE(nullptr, session); + + session->clientHandleToConnection.clear(); + 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; + + drm_xe_eudebug_event client2; + client2.type = DRM_XE_EUDEBUG_EVENT_NONE; + client2.flags = 0; + + session->handleEvent(reinterpret_cast(&client1)); + session->handleEvent(reinterpret_cast(&client2)); + EXPECT_EQ(session->clientHandleToConnection.size(), 1ul); + EXPECT_NE(session->clientHandleToConnection.find(client1.client_handle), session->clientHandleToConnection.end()); + + uint64_t wrongClientHandle = 34; + EXPECT_EQ(session->clientHandleToConnection.find(wrongClientHandle), session->clientHandleToConnection.end()); +} + +TEST_F(DebugApiLinuxTestXe, GivenEuDebugOpenEventWithEventCreateFlagWhenHandleEventThenNewClientConnectionIsCreated) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto session = std::make_unique(config, device, 10); + ASSERT_NE(nullptr, session); + + session->clientHandleToConnection.clear(); + 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; + + 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(&client1)); + session->handleEvent(reinterpret_cast(&client2)); + EXPECT_EQ(session->clientHandleToConnection.size(), 2ul); + EXPECT_NE(session->clientHandleToConnection.find(client1.client_handle), session->clientHandleToConnection.end()); + EXPECT_NE(session->clientHandleToConnection.find(client2.client_handle), session->clientHandleToConnection.end()); + + uint64_t wrongClientHandle = 34; + EXPECT_EQ(session->clientHandleToConnection.find(wrongClientHandle), session->clientHandleToConnection.end()); +} + +TEST_F(DebugApiLinuxTestXe, GivenEuDebugOpenEventWithEventDestroyFlagWhenHandleEventThenClientConnectionIsDestroyed) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto session = std::make_unique(config, device, 10); + ASSERT_NE(nullptr, session); + + session->clientHandleToConnection.clear(); + 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)); + EXPECT_EQ(session->clientHandleToConnection.size(), 1ul); + EXPECT_NE(session->clientHandleToConnection.find(client1.client_handle), session->clientHandleToConnection.end()); + + drm_xe_eudebug_event_client client2; + client2.base.type = DRM_XE_EUDEBUG_EVENT_OPEN; + client2.base.flags = DRM_XE_EUDEBUG_EVENT_DESTROY; + client2.client_handle = client1.client_handle; + EXPECT_EQ(session->clientHandleClosed, session->invalidClientHandle); + session->handleEvent(reinterpret_cast(&client2)); + EXPECT_EQ(session->clientHandleClosed, client2.client_handle); +} + +TEST_F(DebugApiLinuxTestXe, GivenEuDebugExecQueueEventWithEventCreateFlagWhenHandleEventThenExecQueueIsCreated) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto session = std::make_unique(config, device, 10); + ASSERT_NE(nullptr, session); + + session->clientHandleToConnection.clear(); + 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); + EXPECT_NE(session->clientHandleToConnection.find(execQueue->client_handle), session->clientHandleToConnection.end()); + EXPECT_EQ(session->clientHandleToConnection[execQueue->client_handle]->execQueues[execQueue->exec_queue_handle].vmHandle, + execQueue->vm_handle); + EXPECT_EQ(session->clientHandleToConnection[execQueue->client_handle]->execQueues[execQueue->exec_queue_handle].engineClass, + DRM_XE_ENGINE_CLASS_COMPUTE); + for (uint16_t idx = 0; idx < execQueue->width; idx++) { + EXPECT_EQ(session->clientHandleToConnection[execQueue->client_handle]->lrcHandleToVmHandle[execQueue->lrc_handle[idx]], + execQueue->vm_handle); + } +} + +TEST_F(DebugApiLinuxTestXe, GivenEuDebugExecQueueEventWithEventDestroyFlagWhenHandleEventThenExecQueueIsDestroyed) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto session = std::make_unique(config, device, 10); + ASSERT_NE(nullptr, session); + + session->clientHandleToConnection.clear(); + 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); + + // ExecQueue create event handle + 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); + EXPECT_NE(session->clientHandleToConnection.find(execQueue->client_handle), session->clientHandleToConnection.end()); + EXPECT_EQ(session->clientHandleToConnection[execQueue->client_handle]->execQueues[execQueue->exec_queue_handle].vmHandle, + execQueue->vm_handle); + EXPECT_EQ(session->clientHandleToConnection[execQueue->client_handle]->execQueues[execQueue->exec_queue_handle].engineClass, + DRM_XE_ENGINE_CLASS_COMPUTE); + for (uint16_t idx = 0; idx < execQueue->width; idx++) { + EXPECT_EQ(session->clientHandleToConnection[execQueue->client_handle]->lrcHandleToVmHandle[execQueue->lrc_handle[idx]], + execQueue->vm_handle); + } + + // 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); + EXPECT_TRUE(session->clientHandleToConnection[execQueue->client_handle]->execQueues.empty()); + EXPECT_TRUE(session->clientHandleToConnection[execQueue->client_handle]->lrcHandleToVmHandle.empty()); +} + } // namespace ult } // namespace L0 \ No newline at end of file