From 7e58789c02ae7e5b9f087c77b83b766751f75ad7 Mon Sep 17 00:00:00 2001 From: Mateusz Hoppe Date: Thu, 2 Jun 2022 09:09:31 +0000 Subject: [PATCH] L0Debug - move i915 KMD event reading to a dedicated thread - reading events must not be blocked, for example by other ioctls - by moving event reading to another thread, handling events is not blocking event reading Related-To: NEO-7019 Signed-off-by: Mateusz Hoppe --- .../debug/linux/prelim/debug_session.cpp | 99 +++++++--- .../source/debug/linux/prelim/debug_session.h | 18 +- .../debug/linux/test_debug_api_linux.cpp | 187 +++++++++++++----- 3 files changed, 220 insertions(+), 84 deletions(-) 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 d544c78bf9..9ed684a973 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session.cpp +++ b/level_zero/tools/source/debug/linux/prelim/debug_session.cpp @@ -41,6 +41,7 @@ DebugSessionLinux::DebugSessionLinux(const zet_debug_config_t &config, Device *d }; DebugSessionLinux::~DebugSessionLinux() { closeAsyncThread(); + closeInternalEventsThread(); } DebugSession *DebugSession::create(const zet_debug_config_t &config, Device *device, ze_result_t &result) { @@ -238,25 +239,22 @@ ze_result_t DebugSessionLinux::initialize() { return ZE_RESULT_NOT_READY; } - ze_result_t result = ZE_RESULT_NOT_READY; - - uint8_t maxEventBuffer[sizeof(prelim_drm_i915_debug_event) + maxEventSize]; - auto event = reinterpret_cast(maxEventBuffer); - - event->size = maxEventSize; + startInternalEventsThread(); bool allEventsCollected = false; - + bool eventAvailable = false; do { - event->type = PRELIM_DRM_I915_DEBUG_EVENT_READ; - event->flags = 0; - event->size = maxEventSize; - - result = readEventImp(event); + auto eventMemory = getInternalEvent(); + if (eventMemory != nullptr) { + handleEvent(reinterpret_cast(eventMemory.get())); + eventAvailable = true; + } else { + eventAvailable = false; + } allEventsCollected = checkAllEventsCollected(); - } while (result == ZE_RESULT_SUCCESS && !allEventsCollected); + } while (eventAvailable && !allEventsCollected); if (clientHandleClosed == clientHandle && clientHandle != invalidClientHandle) { return ZE_RESULT_ERROR_DEVICE_LOST; @@ -269,9 +267,6 @@ ze_result_t DebugSessionLinux::initialize() { return ZE_RESULT_SUCCESS; } - if (result != ZE_RESULT_SUCCESS) { - return result; - } return ZE_RESULT_NOT_READY; } @@ -279,15 +274,8 @@ void *DebugSessionLinux::asyncThreadFunction(void *arg) { DebugSessionLinux *self = reinterpret_cast(arg); PRINT_DEBUGGER_INFO_LOG("Debugger async thread start\n", ""); - uint8_t maxEventBuffer[sizeof(prelim_drm_i915_debug_event) + maxEventSize]; - auto event = reinterpret_cast(maxEventBuffer); - - event->size = maxEventSize; - event->type = PRELIM_DRM_I915_DEBUG_EVENT_READ; - event->flags = 0; - while (self->asyncThread.threadActive) { - self->handleEventsAsync(event); + self->handleEventsAsync(); self->sendInterrupts(); self->generateEventsAndResumeStoppedThreads(); @@ -299,15 +287,56 @@ void *DebugSessionLinux::asyncThreadFunction(void *arg) { return nullptr; } +void *DebugSessionLinux::readInternalEventsThreadFunction(void *arg) { + DebugSessionLinux *self = reinterpret_cast(arg); + PRINT_DEBUGGER_INFO_LOG("Debugger internal event thread started\n", ""); + + while (self->internalEventThread.threadActive) { + self->readInternalEventsAsync(); + } + + PRINT_DEBUGGER_INFO_LOG("Debugger internal event thread closing\n", ""); + + self->internalEventThread.threadFinished.store(true); + return nullptr; +} + void DebugSessionLinux::startAsyncThread() { asyncThread.thread = NEO::Thread::create(asyncThreadFunction, reinterpret_cast(this)); } void DebugSessionLinux::closeAsyncThread() { asyncThread.close(); + internalEventThread.close(); } -void DebugSessionLinux::handleEventsAsync(prelim_drm_i915_debug_event *event) { +std::unique_ptr DebugSessionLinux::getInternalEvent() { + std::unique_ptr eventMemory; + + { + std::unique_lock lock(internalEventThreadMutex); + + if (internalEventQueue.empty()) { + apiEventCondition.wait_for(lock, std::chrono::milliseconds(100)); + } + + if (!internalEventQueue.empty()) { + eventMemory = std::move(internalEventQueue.front()); + internalEventQueue.pop(); + } + } + return eventMemory; +} + +void DebugSessionLinux::handleEventsAsync() { + auto eventMemory = getInternalEvent(); + if (eventMemory != nullptr) { + handleEvent(reinterpret_cast(eventMemory.get())); + } +} + +void DebugSessionLinux::readInternalEventsAsync() { + struct pollfd pollFd = { .fd = fd, .events = POLLIN, @@ -319,7 +348,7 @@ void DebugSessionLinux::handleEventsAsync(prelim_drm_i915_debug_event *event) { PRINT_DEBUGGER_INFO_LOG("Debugger async thread readEvent poll() retCode: %d\n", numberOfFds); - if (numberOfFds < 0 && errno == EINVAL) { + if (!detached && numberOfFds < 0 && errno == EINVAL) { zet_debug_event_t debugEvent = {}; debugEvent.type = ZET_DEBUG_EVENT_TYPE_DETACHED; debugEvent.info.detached.reason = ZET_DEBUG_DETACH_REASON_INVALID; @@ -334,19 +363,32 @@ void DebugSessionLinux::handleEventsAsync(prelim_drm_i915_debug_event *event) { int maxLoopCount = 3; do { + + uint8_t maxEventBuffer[sizeof(prelim_drm_i915_debug_event) + maxEventSize]; + auto event = reinterpret_cast(maxEventBuffer); + event->size = maxEventSize; event->type = PRELIM_DRM_I915_DEBUG_EVENT_READ; event->flags = 0; - event->size = maxEventSize; result = readEventImp(event); maxLoopCount--; + + if (result == ZE_RESULT_SUCCESS) { + std::unique_lock lock(internalEventThreadMutex); + + auto memory = std::make_unique(maxEventSize / sizeof(uint64_t)); + memcpy(memory.get(), event, maxEventSize); + + internalEventQueue.push(std::move(memory)); + internalEventCondition.notify_one(); + } } while (result == ZE_RESULT_SUCCESS && maxLoopCount > 0); } } bool DebugSessionLinux::closeConnection() { closeAsyncThread(); - + internalEventThread.close(); if (fd == 0) { return false; } @@ -660,7 +702,6 @@ ze_result_t DebugSessionLinux::readEventImp(prelim_drm_i915_debug_event *drmDebu PRINT_DEBUGGER_ERROR_LOG("PRELIM_I915_DEBUG_IOCTL_READ_EVENT unsupported flag = %d\n", (int)drmDebugEvent->flags); return ZE_RESULT_ERROR_UNKNOWN; } - handleEvent(drmDebugEvent); return ZE_RESULT_SUCCESS; } return ZE_RESULT_NOT_READY; 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 ba44b164fc..071ea51664 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session.h +++ b/level_zero/tools/source/debug/linux/prelim/debug_session.h @@ -195,9 +195,20 @@ struct DebugSessionLinux : DebugSessionImp { } static void *asyncThreadFunction(void *arg); + static void *readInternalEventsThreadFunction(void *arg); void startAsyncThread() override; void closeAsyncThread(); - void handleEventsAsync(prelim_drm_i915_debug_event *event); + + void startInternalEventsThread() { + internalEventThread.thread = NEO::Thread::create(readInternalEventsThreadFunction, reinterpret_cast(this)); + } + void closeInternalEventsThread() { + internalEventThread.close(); + } + + void handleEventsAsync(); + void readInternalEventsAsync(); + MOCKABLE_VIRTUAL std::unique_ptr getInternalEvent(); void handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *vmBind); void handleContextParamEvent(prelim_drm_i915_debug_event_context_param *contextParam); @@ -232,6 +243,11 @@ struct DebugSessionLinux : DebugSessionImp { std::mutex asyncThreadMutex; std::condition_variable apiEventCondition; + ThreadHelper internalEventThread; + std::mutex internalEventThreadMutex; + std::condition_variable internalEventCondition; + std::queue> internalEventQueue; + int fd = 0; int ioctl(unsigned long request, void *arg); std::unique_ptr ioctlHandler; 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 7223a5516e..193e4d5ddb 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 @@ -122,6 +122,10 @@ struct MockIoctlHandler : public L0::DebugSessionLinux::IoctlHandler { int poll(pollfd *pollFd, unsigned long int numberOfFds, int timeout) override { passedTimeout = timeout; pollCounter++; + + if (eventQueue.empty() && pollRetVal >= 0) { + return 0; + } return pollRetVal; } @@ -274,6 +278,7 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux { using L0::DebugSessionLinux::handleEvent; using L0::DebugSessionLinux::handleEventsAsync; using L0::DebugSessionLinux::handleVmBindEvent; + using L0::DebugSessionLinux::internalEventQueue; using L0::DebugSessionLinux::interruptImp; using L0::DebugSessionLinux::ioctl; using L0::DebugSessionLinux::ioctlHandler; @@ -283,6 +288,7 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux { using L0::DebugSessionLinux::pushApiEvent; using L0::DebugSessionLinux::readEventImp; using L0::DebugSessionLinux::readGpuMemory; + using L0::DebugSessionLinux::readInternalEventsAsync; using L0::DebugSessionLinux::readModuleDebugArea; using L0::DebugSessionLinux::readSbaBuffer; using L0::DebugSessionLinux::readStateSaveAreaHeader; @@ -380,6 +386,14 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux { return L0::DebugSessionLinux::checkThreadIsResumed(threadID); } + std::unique_ptr getInternalEvent() override { + getInternalEventCounter++; + if (synchronousInternalEventRead) { + readInternalEventsAsync(); + } + return DebugSessionLinux::getInternalEvent(); + } + bool allThreadsStopped = false; int64_t returnTimeDiff = -1; static constexpr uint64_t mockClientHandle = 1; @@ -398,6 +412,9 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux { std::vector> resumedThreads; std::unordered_map stoppedThreads; + + std::atomic getInternalEventCounter = 0; + bool synchronousInternalEventRead = false; }; size_t threadSlotOffset(SIP::StateSaveAreaHeader *pStateSaveAreaHeader, int slice, int subslice, int eu, int thread) { @@ -2492,14 +2509,13 @@ TEST_F(DebugApiLinuxTest, GivenDebugSessionWhenClientHandleIsInvalidDuringInitia ASSERT_NE(nullptr, session); auto handler = new MockIoctlHandler; - handler->pollRetVal = 1; handler->debugEventRetVal = -1; session->ioctlHandler.reset(handler); session->clientHandle = MockDebugSessionLinux::invalidClientHandle; ze_result_t result = session->initialize(); EXPECT_EQ(ZE_RESULT_NOT_READY, result); - EXPECT_EQ(1, handler->ioctlCalled); + EXPECT_EQ(0, session->getInternalEventCounter); } TEST_F(DebugApiLinuxTest, GivenDebuggerLogsWhenReadEventFailsDuringInitializationThenErrorIsPrintedAndReturned) { @@ -2519,9 +2535,17 @@ TEST_F(DebugApiLinuxTest, GivenDebuggerLogsWhenReadEventFailsDuringInitializatio handler->debugEventRetVal = -1; session->ioctlHandler.reset(handler); + prelim_drm_i915_debug_event_client client = {}; + + client.base.type = PRELIM_DRM_I915_DEBUG_EVENT_CLIENT; + client.base.flags = PRELIM_DRM_I915_DEBUG_EVENT_CREATE; + client.base.size = sizeof(prelim_drm_i915_debug_event_client); + client.handle = 1; + handler->eventQueue.push({reinterpret_cast(&client), static_cast(client.base.size)}); + ze_result_t result = session->initialize(); EXPECT_EQ(ZE_RESULT_NOT_READY, result); - EXPECT_EQ(1, handler->ioctlCalled); + EXPECT_EQ(2, session->getInternalEventCounter); auto errorMessage = ::testing::internal::GetCapturedStderr(); auto pos = errorMessage.find("PRELIM_I915_DEBUG_IOCTL_READ_EVENT failed: retCode: -1 errno ="); @@ -2739,7 +2763,7 @@ TEST_F(DebugApiLinuxTest, GivenClientContextAndModuleDebugAreaEventsWhenInitiali vmBindDebugArea->client_handle = MockDebugSessionLinux::mockClientHandle; vmBindDebugArea->va_start = moduleDebugAddress; vmBindDebugArea->va_length = 0x1000; - vmBindDebugArea->vm_handle = 0; + vmBindDebugArea->vm_handle = 50; vmBindDebugArea->num_uuids = 1; auto uuids = reinterpret_cast(ptrOffset(vmBindDebugAreaData, sizeof(prelim_drm_i915_debug_event_vm_bind))); typeOfUUID uuidTemp = 3; @@ -2770,10 +2794,10 @@ TEST_F(DebugApiLinuxTest, GivenClientContextAndModuleDebugAreaEventsWhenInitiali ze_result_t result = session->initialize(); EXPECT_EQ(ZE_RESULT_SUCCESS, result); - constexpr size_t readUuidCount = 1; - constexpr size_t dummyReadEventCount = 0; - constexpr size_t vmOpenDebugAreaCount = 1; - EXPECT_EQ(eventsCount + readUuidCount + dummyReadEventCount + vmOpenDebugAreaCount, static_cast(handler->ioctlCalled)); + EXPECT_EQ(eventsCount, static_cast(session->getInternalEventCounter.load())); + + // Expect VM OPEN called + EXPECT_EQ(50u, handler->vmOpen.handle); } TEST_F(DebugApiLinuxTest, GivenClientContextAndModuleDebugAreaEventsWhenIncorrectModuleDebugAreaReadThenErrorIsReturned) { @@ -2937,17 +2961,17 @@ TEST_F(DebugApiLinuxTest, GivenDebugSessionWhenClientCreateAndDestroyEventsReadO handler->eventQueue.push({reinterpret_cast(&clientCreate), static_cast(clientCreate.base.size)}); handler->eventQueue.push({reinterpret_cast(&clientDestroy), static_cast(clientDestroy.base.size)}); handler->pollRetVal = 1; - auto eventsCount = handler->eventQueue.size(); + auto eventsCount = handler->eventQueue.size() + 1; session->ioctlHandler.reset(handler); session->clientHandle = 1; ze_result_t result = session->initialize(); EXPECT_EQ(ZE_RESULT_ERROR_DEVICE_LOST, result); - EXPECT_EQ(eventsCount + 1, static_cast(handler->ioctlCalled)); + EXPECT_EQ(eventsCount, static_cast(session->getInternalEventCounter.load())); } -TEST_F(DebugApiLinuxTest, GivenDebugSessionInitializationWhenReadEventHasInvalidFlagsThenUnknownErrorIsReturned) { +TEST_F(DebugApiLinuxTest, GivenEventWithInvalidFlagsWhenReadingEventThenUnknownErrorIsReturned) { zet_debug_config_t config = {}; config.pid = 0x1234; @@ -2967,11 +2991,40 @@ TEST_F(DebugApiLinuxTest, GivenDebugSessionInitializationWhenReadEventHasInvalid session->ioctlHandler.reset(handler); - ze_result_t result = session->initialize(); + auto memory = std::make_unique(MockDebugSessionLinux::maxEventSize / sizeof(uint64_t)); + prelim_drm_i915_debug_event *event = reinterpret_cast(memory.get()); + event->type = PRELIM_DRM_I915_DEBUG_EVENT_READ; + event->flags = 0; + event->size = MockDebugSessionLinux::maxEventSize; + + ze_result_t result = session->readEventImp(event); EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, result); EXPECT_EQ(eventsCount, static_cast(handler->ioctlCalled)); } +TEST_F(DebugApiLinuxTest, GivenDebugSessionInitializationWhenNoValidEventsAreReadThenResultNotReadyIsReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto session = std::make_unique(config, device, 10); + ASSERT_NE(nullptr, session); + + prelim_drm_i915_debug_event_client clientInvalidFlag = {}; + clientInvalidFlag.base.type = PRELIM_DRM_I915_DEBUG_EVENT_CLIENT; + clientInvalidFlag.base.flags = 0x8000; + clientInvalidFlag.base.size = sizeof(prelim_drm_i915_debug_event_client); + clientInvalidFlag.handle = 1; + + auto handler = new MockIoctlHandler; + handler->eventQueue.push({reinterpret_cast(&clientInvalidFlag), static_cast(clientInvalidFlag.base.size)}); + handler->pollRetVal = 1; + + session->ioctlHandler.reset(handler); + + ze_result_t result = session->initialize(); + EXPECT_EQ(ZE_RESULT_NOT_READY, result); +} + TEST_F(DebugApiLinuxTest, GivenInvalidFlagsWhenReadingEventThenUnknownErrorIsReturned) { zet_debug_config_t config = {}; config.pid = 0x1234; @@ -2999,7 +3052,7 @@ TEST_F(DebugApiLinuxTest, GivenInvalidFlagsWhenReadingEventThenUnknownErrorIsRet EXPECT_EQ(1u, static_cast(handler->ioctlCalled)); } -TEST_F(DebugApiLinuxTest, GivenValidFlagsWhenReadingEventThenEventIsProcessed) { +TEST_F(DebugApiLinuxTest, GivenValidFlagsWhenReadingEventThenEventIsNotProcessed) { zet_debug_config_t config = {}; config.pid = 0x1234; @@ -3032,7 +3085,7 @@ TEST_F(DebugApiLinuxTest, GivenValidFlagsWhenReadingEventThenEventIsProcessed) { auto drmDebugEvent = reinterpret_cast(data); ze_result_t result = session->readEventImp(drmDebugEvent); EXPECT_EQ(ZE_RESULT_SUCCESS, result); - EXPECT_EQ(1u, session->handleEventCalledCount); + EXPECT_EQ(0u, session->handleEventCalledCount); } TEST_F(DebugApiLinuxTest, GivenDebuggerLogsAndUnhandledEventTypeWhenHandlingEventThenMessageIsPrinted) { @@ -3111,13 +3164,13 @@ TEST_F(DebugApiLinuxTest, GivenContextCreateAndDestroyEventsWhenInitializingThen handler->eventQueue.push({reinterpret_cast(&context2), static_cast(context2.base.size)}); handler->eventQueue.push({reinterpret_cast(&contextDestroy), static_cast(contextDestroy.base.size)}); - auto eventsCount = handler->eventQueue.size(); + auto eventsCount = handler->eventQueue.size() + 1; handler->pollRetVal = 1; session->ioctlHandler.reset(handler); session->initialize(); - EXPECT_EQ(eventsCount + 1, static_cast(handler->ioctlCalled)); + EXPECT_EQ(eventsCount, static_cast(session->getInternalEventCounter.load())); EXPECT_EQ(1u, session->clientHandleToConnection[clientHandle]->contextsCreated.size()); EXPECT_EQ(session->clientHandleToConnection[clientHandle]->contextsCreated.end(), session->clientHandleToConnection[clientHandle]->contextsCreated.find(context.handle)); @@ -5325,7 +5378,7 @@ TEST_F(DebugApiLinuxAttentionTest, GivenInvalidVmHandleWhenHandlingAttentionEven } using DebugApiLinuxAsyncThreadTest = Test; -TEST_F(DebugApiLinuxAsyncThreadTest, GivenPollReturnsErrorAndEinvalWhenHandlingEventsAsyncThenDetachEventIsGenerated) { +TEST_F(DebugApiLinuxAsyncThreadTest, GivenPollReturnsErrorAndEinvalWhenReadingInternalEventsAsyncThenDetachEventIsGenerated) { zet_debug_config_t config = {}; config.pid = 0x1234; @@ -5337,25 +5390,38 @@ TEST_F(DebugApiLinuxAsyncThreadTest, GivenPollReturnsErrorAndEinvalWhenHandlingE session->ioctlHandler.reset(handler); session->clientHandle = MockDebugSessionLinux::mockClientHandle; - std::unique_ptr> event( - reinterpret_cast(malloc(sizeof(prelim_drm_i915_debug_event) + DebugSessionLinux::maxEventSize)), [](prelim_drm_i915_debug_event *ptr) { free(ptr); }); - event->size = DebugSessionLinux::maxEventSize; - event->type = PRELIM_DRM_I915_DEBUG_EVENT_READ; - event->flags = 0; errno = EINVAL; - - session->handleEventsAsync(event.get()); + session->readInternalEventsAsync(); EXPECT_EQ(1u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->apiEvents.size()); EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_DETACHED, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->apiEvents.front().type); session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->apiEvents.pop(); errno = 0; - session->handleEventsAsync(event.get()); + session->readInternalEventsAsync(); EXPECT_EQ(0u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->apiEvents.size()); } -TEST_F(DebugApiLinuxAsyncThreadTest, GivenPollReturnsZeroWhenHandlingEventsAsyncThenNoEventIsReadAndGenerated) { +TEST_F(DebugApiLinuxAsyncThreadTest, GivenPollReturnsErrorAndEBusyWhenReadingInternalEventsAsyncThenDetachEventIsNotGenerated) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto session = std::make_unique(config, device, 10); + ASSERT_NE(nullptr, session); + + auto handler = new MockIoctlHandler; + handler->pollRetVal = -1; + session->ioctlHandler.reset(handler); + session->clientHandle = MockDebugSessionLinux::mockClientHandle; + + errno = EBUSY; + session->readInternalEventsAsync(); + + EXPECT_EQ(0u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->apiEvents.size()); + errno = 0; +} + +TEST_F(DebugApiLinuxAsyncThreadTest, GivenPollReturnsZeroWhenReadingInternalEventsAsyncThenNoEventIsReadAndGenerated) { zet_debug_config_t config = {}; config.pid = 0x1234; @@ -5367,20 +5433,14 @@ TEST_F(DebugApiLinuxAsyncThreadTest, GivenPollReturnsZeroWhenHandlingEventsAsync session->ioctlHandler.reset(handler); session->clientHandle = MockDebugSessionLinux::mockClientHandle; - std::unique_ptr> event( - reinterpret_cast(malloc(sizeof(prelim_drm_i915_debug_event) + DebugSessionLinux::maxEventSize)), [](prelim_drm_i915_debug_event *ptr) { free(ptr); }); - event->size = DebugSessionLinux::maxEventSize; - event->type = PRELIM_DRM_I915_DEBUG_EVENT_READ; - event->flags = 0; - - session->handleEventsAsync(event.get()); + session->readInternalEventsAsync(); EXPECT_EQ(0, handler->ioctlCalled); EXPECT_EQ(0u, handler->debugEventInput.type); EXPECT_EQ(0u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->apiEvents.size()); } -TEST_F(DebugApiLinuxAsyncThreadTest, GivenPollReturnsNonZeroWhenHandlingEventsAsyncThenEventReadIsCalled) { +TEST_F(DebugApiLinuxAsyncThreadTest, GivenPollReturnsNonZeroWhenReadingInternalEventsAsyncThenEventReadIsCalled) { zet_debug_config_t config = {}; config.pid = 0x1234; @@ -5391,6 +5451,7 @@ TEST_F(DebugApiLinuxAsyncThreadTest, GivenPollReturnsNonZeroWhenHandlingEventsAs handler->pollRetVal = 1; session->ioctlHandler.reset(handler); session->clientHandle = MockDebugSessionLinux::mockClientHandle; + session->synchronousInternalEventRead = true; uint64_t clientHandle = 2; prelim_drm_i915_debug_event_client client = {}; @@ -5401,13 +5462,7 @@ TEST_F(DebugApiLinuxAsyncThreadTest, GivenPollReturnsNonZeroWhenHandlingEventsAs handler->eventQueue.push({reinterpret_cast(&client), static_cast(client.base.size)}); - std::unique_ptr> event( - reinterpret_cast(malloc(sizeof(prelim_drm_i915_debug_event) + DebugSessionLinux::maxEventSize)), [](prelim_drm_i915_debug_event *ptr) { free(ptr); }); - event->size = DebugSessionLinux::maxEventSize; - event->type = PRELIM_DRM_I915_DEBUG_EVENT_READ; - event->flags = 0; - - session->handleEventsAsync(event.get()); + session->readInternalEventsAsync(); constexpr int clientEventCount = 1; constexpr int dummyReadEventCount = 1; @@ -5417,7 +5472,37 @@ TEST_F(DebugApiLinuxAsyncThreadTest, GivenPollReturnsNonZeroWhenHandlingEventsAs EXPECT_EQ(static_cast(PRELIM_DRM_I915_DEBUG_EVENT_READ), handler->debugEventInput.type); } -TEST_F(DebugApiLinuxAsyncThreadTest, GivenPollReturnsNonZeroWhenHandlingEventsAsyncThenEventReadIsCalledForAtMost3Times) { +TEST_F(DebugApiLinuxAsyncThreadTest, GivenEventsAvailableWhenHandlingEventsAsyncThenEventIsProcessed) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto session = std::make_unique(config, device, 10); + ASSERT_NE(nullptr, session); + + auto handler = new MockIoctlHandler; + handler->pollRetVal = 1; + session->ioctlHandler.reset(handler); + session->clientHandle = MockDebugSessionLinux::mockClientHandle; + session->synchronousInternalEventRead = true; + + uint64_t clientHandle = 2; + prelim_drm_i915_debug_event_client client = {}; + client.base.type = PRELIM_DRM_I915_DEBUG_EVENT_CLIENT; + client.base.flags = PRELIM_DRM_I915_DEBUG_EVENT_CREATE; + client.base.size = sizeof(prelim_drm_i915_debug_event_client); + client.handle = clientHandle; + + handler->eventQueue.push({reinterpret_cast(&client), static_cast(client.base.size)}); + + EXPECT_EQ(nullptr, session->clientHandleToConnection[clientHandle]); + + session->handleEventsAsync(); + + EXPECT_EQ(1u, session->handleEventCalledCount); + EXPECT_NE(nullptr, session->clientHandleToConnection[clientHandle]); +} + +TEST_F(DebugApiLinuxAsyncThreadTest, GivenPollReturnsNonZeroWhenReadingEventsAsyncThenEventReadIsCalledForAtMost3Times) { zet_debug_config_t config = {}; config.pid = 0x1234; @@ -5441,18 +5526,12 @@ TEST_F(DebugApiLinuxAsyncThreadTest, GivenPollReturnsNonZeroWhenHandlingEventsAs handler->eventQueue.push({reinterpret_cast(&client), static_cast(client.base.size)}); handler->eventQueue.push({reinterpret_cast(&client), static_cast(client.base.size)}); - std::unique_ptr> event( - reinterpret_cast(malloc(sizeof(prelim_drm_i915_debug_event) + DebugSessionLinux::maxEventSize)), [](prelim_drm_i915_debug_event *ptr) { free(ptr); }); - event->size = DebugSessionLinux::maxEventSize; - event->type = PRELIM_DRM_I915_DEBUG_EVENT_READ; - event->flags = 0; - - session->handleEventsAsync(event.get()); + session->readInternalEventsAsync(); EXPECT_EQ(3, handler->ioctlCalled); EXPECT_EQ(DebugSessionLinux::maxEventSize, handler->debugEventInput.size); EXPECT_EQ(static_cast(PRELIM_DRM_I915_DEBUG_EVENT_READ), handler->debugEventInput.type); - EXPECT_EQ(clientHandle, session->clientHandleToConnection[clientHandle]->client.handle); + EXPECT_EQ(3u, session->internalEventQueue.size()); } TEST_F(DebugApiLinuxAsyncThreadTest, GivenDebugSessionWhenStartingAndClosingAsyncThreadThenThreadIsStartedAndFinishes) { @@ -5469,7 +5548,7 @@ TEST_F(DebugApiLinuxAsyncThreadTest, GivenDebugSessionWhenStartingAndClosingAsyn session->startAsyncThread(); - while (handler->pollCounter == 0) + while (session->getInternalEventCounter == 0) ; EXPECT_TRUE(session->asyncThread.threadActive); @@ -5495,7 +5574,7 @@ TEST_F(DebugApiLinuxAsyncThreadTest, GivenDebugSessionWithAsyncThreadWhenClosing session->startAsyncThread(); - while (handler->pollCounter == 0) + while (session->getInternalEventCounter == 0) ; EXPECT_TRUE(session->asyncThread.threadActive); @@ -5544,7 +5623,7 @@ TEST_F(DebugApiLinuxAsyncThreadTest, GivenInterruptedThreadsWhenNoAttentionEvent auto result = session->interrupt(thread); EXPECT_EQ(ZE_RESULT_SUCCESS, result); - while (handler->pollCounter == 0) + while (session->getInternalEventCounter == 0) ; session->closeAsyncThread(); @@ -5578,7 +5657,7 @@ TEST_F(DebugApiLinuxAsyncThreadTest, GivenInterruptedThreadsWhenNoAttentionEvent auto result = session->interrupt(thread); EXPECT_EQ(ZE_RESULT_SUCCESS, result); - while (handler->pollCounter == 0) + while (session->getInternalEventCounter == 0) ; session->closeAsyncThread();