From 16b0ea6897d69bc31aa6ba2c991848e81c180aac Mon Sep 17 00:00:00 2001 From: Brandon Yates Date: Fri, 20 Dec 2024 20:20:09 +0000 Subject: [PATCH] feature: Handle page fault events for xe debugger Related-to: NEO-10134 Signed-off-by: Brandon Yates --- .../tools/source/debug/linux/debug_session.h | 4 +- .../source/debug/linux/xe/debug_session.cpp | 14 +++- .../xe/debug_session_fixtures_linux_xe.h | 5 ++ .../linux/xe/test_debug_api_linux_xe.cpp | 76 +++++++++++-------- .../xe/eudebug/eudebug_interface_prelim.cpp | 11 ++- .../xe/eudebug/eudebug_interface_upstream.cpp | 11 ++- .../linux/xe/eudebug/eudebug_wrappers.h | 13 +++- 7 files changed, 95 insertions(+), 39 deletions(-) diff --git a/level_zero/tools/source/debug/linux/debug_session.h b/level_zero/tools/source/debug/linux/debug_session.h index d751ed9cf1..77e82f8d73 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-2024 Intel Corporation + * Copyright (C) 2023-2025 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -304,7 +304,7 @@ struct DebugSessionLinux : DebugSessionImp { uint32_t bitmaskSize; uint8_t *bitmask; }; - void handlePageFaultEvent(PageFaultEvent &pfEvent); + MOCKABLE_VIRTUAL void handlePageFaultEvent(PageFaultEvent &pfEvent); uint8_t maxRetries = 3; std::unique_ptr ioctlHandler; 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 18b3187f8f..66ebc8ceab 100644 --- a/level_zero/tools/source/debug/linux/xe/debug_session.cpp +++ b/level_zero/tools/source/debug/linux/xe/debug_session.cpp @@ -379,7 +379,19 @@ void DebugSessionLinuxXe::handleEvent(NEO::EuDebugEvent *event) { static_cast(execQueuePlacements->clientHandle), static_cast(execQueuePlacements->vmHandle), tileIndex); } } else if (type == euDebugInterface->getParamValue(NEO::EuDebugParam::eventTypePagefault)) { - PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: UNHANDLED %u flags = %u len = %lu\n", type, event->flags, event->len); + NEO::EuDebugEventPageFault *pf = reinterpret_cast(event); + + PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: DRM_XE_EUDEBUG_EVENT_PAGEFAULT flags = %d, address = %llu seqno = %d, length = %llu" + " client_handle = %llu pf_flags = %llu bitmask_size = %lu exec_queue_handle = %llu\n", + (int)pf->base.flags, (uint64_t)pf->pagefaultAddress, (uint64_t)pf->base.seqno, (uint64_t)pf->base.len, + (uint64_t)pf->clientHandle, (uint64_t)pf->flags, (uint32_t)pf->bitmaskSize, uint64_t(pf->execQueueHandle)); + auto tileIndex = 0u; + auto vmHandle = getVmHandleFromClientAndlrcHandle(pf->clientHandle, pf->lrcHandle); + if (vmHandle == invalidHandle) { + return; + } + PageFaultEvent pfEvent = {vmHandle, tileIndex, pf->pagefaultAddress, pf->bitmaskSize, pf->bitmask}; + handlePageFaultEvent(pfEvent); } else { additionalEvents(event); } 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 cd70643510..5ab053af11 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 @@ -293,6 +293,10 @@ struct MockDebugSessionLinuxXe : public L0::DebugSessionLinuxXe { return L0::DebugSessionImp::readSystemRoutineIdent(thread, vmHandle, srIdent); } + void handlePageFaultEvent(PageFaultEvent &pfEvent) override { + handlePageFaultEventCalled++; + } + uint64_t getContextStateSaveAreaGpuVa(uint64_t memoryHandle) override { return 0x1000; } @@ -314,6 +318,7 @@ struct MockDebugSessionLinuxXe : public L0::DebugSessionLinuxXe { uint32_t countToAddThreadToNewlyStoppedFromRaisedAttentionForTileSession = 0; int64_t returnTimeDiff = -1; uint32_t handleAttentionEventCalled = 0; + uint32_t handlePageFaultEventCalled = 0; }; struct MockAsyncThreadDebugSessionLinuxXe : public MockDebugSessionLinuxXe { 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 ac45809f6a..55430963c3 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 @@ -2767,39 +2767,6 @@ TEST_F(DebugApiLinuxTestXe, GivenMaxRetriesProvidedByDebugVariablesWhenAsyncThre session->closeAsyncThread(); } -TEST_F(DebugApiLinuxTestXe, GivenNotImplementedEventTypeWhenHandleEventThenDebugMessageIsPrinted) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - - auto session = std::make_unique(config, device, 10); - ASSERT_NE(nullptr, session); - DebugManagerStateRestore restore; - NEO::debugManager.flags.PrintDebugMessages.set(1); - NEO::debugManager.flags.DebuggerLogBitmask.set(NEO::DebugVariables::DEBUGGER_LOG_BITMASK::LOG_INFO); - - NEO::EuDebugEvent emptyEvent{}; - - ::testing::internal::CaptureStdout(); - - session->handleEvent(&emptyEvent); - - std::string output = testing::internal::GetCapturedStdout(); - std::string expectedOutput("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: UNHANDLED 0 flags = 0 len = 0\n"); - EXPECT_NE(std::string::npos, output.find(expectedOutput.c_str())); - - NEO::EuDebugEvent pagefaultEvent{}; - pagefaultEvent.len = 2; - pagefaultEvent.type = static_cast(NEO::EuDebugParam::eventTypePagefault); - pagefaultEvent.flags = 3; - - ::testing::internal::CaptureStdout(); - session->handleEvent(&pagefaultEvent); - - output = testing::internal::GetCapturedStdout(); - expectedOutput = std::string("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: UNHANDLED ") + std::to_string(pagefaultEvent.type) + " flags = 3 len = 2\n"; - EXPECT_NE(std::string::npos, output.find(expectedOutput.c_str())); -} - TEST(DebugSessionLinuxXeTest, GivenRootDebugSessionWhenCreateTileSessionCalledThenSessionIsNotCreated) { auto hwInfo = *NEO::defaultHwInfo.get(); NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); @@ -3113,5 +3080,48 @@ TEST_F(DebugApiLinuxMultiDeviceVmBindTestXe, GivenVmBindForProgramModuleWhenHand EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_MODULE_UNLOAD, event.type); } +TEST_F(DebugApiLinuxTestXe, GivenPageFaultEventThenPageFaultHandledCalled) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto sessionMock = std::make_unique(config, device, 10); + ASSERT_NE(nullptr, sessionMock); + sessionMock->clientHandle = MockDebugSessionLinuxXe::mockClientHandle; + + uint64_t execQueueHandle = 2; + uint64_t vmHandle = 7; + uint64_t lrcHandle = 8; + + sessionMock->clientHandleToConnection[MockDebugSessionLinuxXe::mockClientHandle]->lrcHandleToVmHandle[lrcHandle] = vmHandle; + + uint8_t data[sizeof(NEO::EuDebugEventPageFault) + 128]; + ze_device_thread_t thread{0, 0, 0, 0}; + + sessionMock->stoppedThreads[EuThread::ThreadId(0, thread).packed] = 1; + sessionMock->pendingInterrupts.push_back(std::pair(thread, false)); + + sessionMock->interruptSent = true; + sessionMock->euControlInterruptSeqno = 1; + + NEO::EuDebugEventPageFault pf = {}; + pf.base.type = static_cast(NEO::EuDebugParam::eventTypePagefault); + pf.base.flags = static_cast(NEO::EuDebugParam::eventBitStateChange); + pf.base.len = sizeof(data); + pf.base.seqno = 2; + pf.clientHandle = MockDebugSessionLinuxXe::mockClientHandle; + pf.lrcHandle = lrcHandle; + pf.flags = 0; + pf.execQueueHandle = execQueueHandle; + pf.bitmaskSize = 0; + memcpy(data, &pf, sizeof(NEO::EuDebugEventPageFault)); + sessionMock->handleEvent(reinterpret_cast(data)); + EXPECT_EQ(sessionMock->handlePageFaultEventCalled, 1u); + + pf.lrcHandle = 0x1234; + memcpy(data, &pf, sizeof(NEO::EuDebugEventPageFault)); + sessionMock->handleEvent(reinterpret_cast(data)); + EXPECT_EQ(sessionMock->handlePageFaultEventCalled, 1u); +} + } // namespace ult } // namespace L0 diff --git a/shared/source/os_interface/linux/xe/eudebug/eudebug_interface_prelim.cpp b/shared/source/os_interface/linux/xe/eudebug/eudebug_interface_prelim.cpp index 3974dc3867..c28eea2c66 100644 --- a/shared/source/os_interface/linux/xe/eudebug/eudebug_interface_prelim.cpp +++ b/shared/source/os_interface/linux/xe/eudebug/eudebug_interface_prelim.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Intel Corporation + * Copyright (C) 2024-2025 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -157,6 +157,15 @@ static_assert(sizeof(EuDebugEventVmBindUfence) == sizeof(prelim_drm_xe_eudebug_e static_assert(offsetof(EuDebugEventVmBindUfence, base) == offsetof(prelim_drm_xe_eudebug_event_vm_bind_ufence, base)); static_assert(offsetof(EuDebugEventVmBindUfence, vmBindRefSeqno) == offsetof(prelim_drm_xe_eudebug_event_vm_bind_ufence, vm_bind_ref_seqno)); +static_assert(sizeof(EuDebugEventPageFault) == sizeof(prelim_drm_xe_eudebug_event_pagefault)); +static_assert(offsetof(EuDebugEventPageFault, clientHandle) == offsetof(prelim_drm_xe_eudebug_event_pagefault, client_handle)); +static_assert(offsetof(EuDebugEventPageFault, execQueueHandle) == offsetof(prelim_drm_xe_eudebug_event_pagefault, exec_queue_handle)); +static_assert(offsetof(EuDebugEventPageFault, lrcHandle) == offsetof(prelim_drm_xe_eudebug_event_pagefault, lrc_handle)); +static_assert(offsetof(EuDebugEventPageFault, flags) == offsetof(prelim_drm_xe_eudebug_event_pagefault, flags)); +static_assert(offsetof(EuDebugEventPageFault, bitmaskSize) == offsetof(prelim_drm_xe_eudebug_event_pagefault, bitmask_size)); +static_assert(offsetof(EuDebugEventPageFault, pagefaultAddress) == offsetof(prelim_drm_xe_eudebug_event_pagefault, pagefault_address)); +static_assert(offsetof(EuDebugEventPageFault, bitmask) == offsetof(prelim_drm_xe_eudebug_event_pagefault, bitmask)); + static_assert(sizeof(EuDebugReadMetadata) == sizeof(prelim_drm_xe_eudebug_read_metadata)); static_assert(offsetof(EuDebugReadMetadata, clientHandle) == offsetof(prelim_drm_xe_eudebug_read_metadata, client_handle)); static_assert(offsetof(EuDebugReadMetadata, metadataHandle) == offsetof(prelim_drm_xe_eudebug_read_metadata, metadata_handle)); diff --git a/shared/source/os_interface/linux/xe/eudebug/eudebug_interface_upstream.cpp b/shared/source/os_interface/linux/xe/eudebug/eudebug_interface_upstream.cpp index 081ebdd0e5..c46ebb3730 100644 --- a/shared/source/os_interface/linux/xe/eudebug/eudebug_interface_upstream.cpp +++ b/shared/source/os_interface/linux/xe/eudebug/eudebug_interface_upstream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Intel Corporation + * Copyright (C) 2024-2025 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -156,6 +156,15 @@ static_assert(sizeof(EuDebugEventVmBindUfence) == sizeof(drm_xe_eudebug_event_vm static_assert(offsetof(EuDebugEventVmBindUfence, base) == offsetof(drm_xe_eudebug_event_vm_bind_ufence, base)); static_assert(offsetof(EuDebugEventVmBindUfence, vmBindRefSeqno) == offsetof(drm_xe_eudebug_event_vm_bind_ufence, vm_bind_ref_seqno)); +static_assert(sizeof(EuDebugEventPageFault) == sizeof(drm_xe_eudebug_event_pagefault)); +static_assert(offsetof(EuDebugEventPageFault, clientHandle) == offsetof(drm_xe_eudebug_event_pagefault, client_handle)); +static_assert(offsetof(EuDebugEventPageFault, execQueueHandle) == offsetof(drm_xe_eudebug_event_pagefault, exec_queue_handle)); +static_assert(offsetof(EuDebugEventPageFault, lrcHandle) == offsetof(drm_xe_eudebug_event_pagefault, lrc_handle)); +static_assert(offsetof(EuDebugEventPageFault, flags) == offsetof(drm_xe_eudebug_event_pagefault, flags)); +static_assert(offsetof(EuDebugEventPageFault, bitmaskSize) == offsetof(drm_xe_eudebug_event_pagefault, bitmask_size)); +static_assert(offsetof(EuDebugEventPageFault, pagefaultAddress) == offsetof(drm_xe_eudebug_event_pagefault, pagefault_address)); +static_assert(offsetof(EuDebugEventPageFault, bitmask) == offsetof(drm_xe_eudebug_event_pagefault, bitmask)); + static_assert(sizeof(EuDebugReadMetadata) == sizeof(drm_xe_eudebug_read_metadata)); static_assert(offsetof(EuDebugReadMetadata, clientHandle) == offsetof(drm_xe_eudebug_read_metadata, client_handle)); static_assert(offsetof(EuDebugReadMetadata, metadataHandle) == offsetof(drm_xe_eudebug_read_metadata, metadata_handle)); diff --git a/shared/source/os_interface/linux/xe/eudebug/eudebug_wrappers.h b/shared/source/os_interface/linux/xe/eudebug/eudebug_wrappers.h index 82a79dbb6a..a25437c1f1 100644 --- a/shared/source/os_interface/linux/xe/eudebug/eudebug_wrappers.h +++ b/shared/source/os_interface/linux/xe/eudebug/eudebug_wrappers.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Intel Corporation + * Copyright (C) 2024-2025 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -101,6 +101,17 @@ struct EuDebugEventVmBindUfence { uint64_t vmBindRefSeqno; }; +struct EuDebugEventPageFault { + struct EuDebugEvent base; + uint64_t clientHandle; + uint64_t execQueueHandle; + uint64_t lrcHandle; + uint32_t flags; + uint32_t bitmaskSize; + uint64_t pagefaultAddress; + uint8_t bitmask[]; +}; + struct EuDebugReadMetadata { uint64_t clientHandle; uint64_t metadataHandle;