diff --git a/level_zero/tools/source/debug/linux/debug_session.h b/level_zero/tools/source/debug/linux/debug_session.h index eac0519a50..934a14e672 100644 --- a/level_zero/tools/source/debug/linux/debug_session.h +++ b/level_zero/tools/source/debug/linux/debug_session.h @@ -15,6 +15,8 @@ #include "level_zero/tools/source/debug/debug_session.h" #include "level_zero/tools/source/debug/debug_session_imp.h" +#include + namespace L0 { struct DebugSessionLinux : DebugSessionImp { @@ -116,11 +118,13 @@ struct DebugSessionLinux : DebugSessionImp { uint64_t moduleBegin; uint64_t moduleEnd; + uint64_t moduleHandle; std::unordered_set cookies; int vmBindCounter = 0; bool moduleLoadEventAck = false; std::vector ackEvents; + std::set validVMs; }; struct Module { 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 cf5e70612a..2ed2d8a6cf 100644 --- a/level_zero/tools/source/debug/linux/xe/debug_session.cpp +++ b/level_zero/tools/source/debug/linux/xe/debug_session.cpp @@ -304,7 +304,7 @@ void DebugSessionLinuxXe::handleEvent(drm_xe_eudebug_event *event) { case DRM_XE_EUDEBUG_EVENT_VM_BIND_OP: { drm_xe_eudebug_event_vm_bind_op *vmBindOp = reinterpret_cast(event); - PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: drm_xe_eudebug_event_vm_bind_op vm_bind_ref_seqno = %llu num_extensions = %llu addr = %llu range = %llu\n", + PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: drm_xe_eudebug_event_vm_bind_op vm_bind_ref_seqno = %llu num_extensions = %llu addr = 0x%llx range = %llu\n", static_cast(vmBindOp->vm_bind_ref_seqno), static_cast(vmBindOp->num_extensions), static_cast(vmBindOp->addr), static_cast(vmBindOp->range)); @@ -399,11 +399,12 @@ void DebugSessionLinuxXe::handleVmBind(VmBindData &vmBindData) { auto elfHandleInVmBind = invalidHandle; uint64_t moduleHandle = invalidHandle; + uint64_t isaAddr = 0; bool triggerModuleLoadEvent = false; for (auto &vmBindOpData : vmBindData.vmBindOpMap) { + auto &vmBindOp = vmBindOpData.second.vmBindOp; for (const auto &vmBindOpMetadata : vmBindOpData.second.vmBindOpMetadataVec) { - auto &vmBindOp = vmBindOpData.second.vmBindOp; auto &metaDataEntry = connection->metaDataMap[vmBindOpMetadata.metadata_handle]; if (vmBindOp.base.flags & DRM_XE_EUDEBUG_EVENT_CREATE) { { @@ -420,10 +421,10 @@ void DebugSessionLinuxXe::handleVmBind(VmBindData &vmBindData) { } if (metaDataEntry.metadata.type == DRM_XE_DEBUG_METADATA_ELF_BINARY) { + isaAddr = vmBindOp.addr; if (connection->isaMap[0].find(vmBindOp.addr) == connection->isaMap[0].end()) { auto &isaMap = connection->isaMap[0]; auto &elfMap = connection->elfMap; - auto isa = std::make_unique(); isa->bindInfo = {vmBindOp.addr, vmBindOp.range}; isa->vmHandle = vmBindData.vmBind.vm_handle; @@ -431,11 +432,15 @@ void DebugSessionLinuxXe::handleVmBind(VmBindData &vmBindData) { isa->moduleBegin = reinterpret_cast(metaDataEntry.data.get()); isa->moduleEnd = isa->moduleBegin + metaDataEntry.metadata.len; isa->tileInstanced = false; + isa->validVMs.insert(vmBindData.vmBind.vm_handle); isa->perKernelModule = false; elfMap[isa->moduleBegin] = isa->elfHandle; isaMap[vmBindOp.addr] = std::move(isa); isaMap[vmBindOp.addr]->moduleLoadEventAck = true; elfHandleInVmBind = vmBindOpMetadata.metadata_handle; + } else { + auto &isa = connection->isaMap[0][vmBindOp.addr]; + isa->validVMs.insert(vmBindData.vmBind.vm_handle); } } if (metaDataEntry.metadata.type == DRM_XE_DEBUG_METADATA_PROGRAM_MODULE) { @@ -445,13 +450,43 @@ void DebugSessionLinuxXe::handleVmBind(VmBindData &vmBindData) { bool canTriggerEvent = module.loadAddresses[0].size() == (module.segmentCount - 1); module.loadAddresses[0].insert(vmBindOp.addr); + moduleHandle = vmBindOpMetadata.metadata_handle; if (canTriggerEvent && module.loadAddresses[0].size() == module.segmentCount) { triggerModuleLoadEvent = true; - moduleHandle = vmBindOpMetadata.metadata_handle; } } } } + + if (vmBindOp.base.flags & DRM_XE_EUDEBUG_EVENT_DESTROY) { + if (connection->isaMap[0].count(vmBindOp.addr)) { + auto &isa = connection->isaMap[0][vmBindOp.addr]; + if (isa->validVMs.count(vmBindData.vmBind.vm_handle)) { + auto &module = connection->metaDataToModule[isa->moduleHandle]; + module.segmentVmBindCounter[0]--; + if (module.segmentVmBindCounter[0] == 0) { + zet_debug_event_t debugEvent = {}; + auto &metaDataEntry = connection->metaDataMap[isa->moduleHandle]; + auto gmmHelper = connectedDevice->getNEODevice()->getGmmHelper(); + auto loadAddress = gmmHelper->canonize(*std::min_element(module.loadAddresses[0].begin(), module.loadAddresses[0].end())); + debugEvent.type = ZET_DEBUG_EVENT_TYPE_MODULE_UNLOAD; + debugEvent.info.module.format = ZET_MODULE_DEBUG_INFO_FORMAT_ELF_DWARF; + debugEvent.info.module.load = loadAddress; + auto &elfMetadata = connection->metaDataMap[isa->elfHandle]; + debugEvent.info.module.moduleBegin = reinterpret_cast(elfMetadata.data.get()); + debugEvent.info.module.moduleEnd = reinterpret_cast(elfMetadata.data.get()) + elfMetadata.metadata.len; + pushApiEvent(debugEvent, metaDataEntry.metadata.metadata_handle); + module.loadAddresses[0].clear(); + module.moduleLoadEventAcked[0] = false; + } + isa->validVMs.erase(vmBindData.vmBind.vm_handle); + } + } + } + } + + if (isaAddr && moduleHandle != invalidHandle) { + connection->isaMap[0][isaAddr]->moduleHandle = moduleHandle; } if (triggerModuleLoadEvent) { 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 e03592d5f3..0f3e22016c 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 @@ -1394,6 +1394,178 @@ TEST_F(DebugApiLinuxTestXe, GivenVmBindOpMetadataCreateEventAndUfenceForProgramM EXPECT_EQ(reinterpret_cast(connection->metaDataMap[11].data.get()) + connection->metaDataMap[11].metadata.len, event.info.module.moduleEnd); } +TEST_F(DebugApiLinuxTestXe, GivenVmUnbindForLastIsaSegmentThenL0ModuleUnloadEventSent) { + + zet_debug_config_t config = {}; + config.pid = 0x1234; + + uint64_t seg1Va = 0xffff1234; + uint64_t seg2Va = 0xffff5678; + uint64_t seqno = 0; + + auto session = std::make_unique(config, device, 10); + ASSERT_NE(nullptr, session); + + auto handler = new MockIoctlHandlerXe; + session->ioctlHandler.reset(handler); + + 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 = MockDebugSessionLinuxXe::mockClientHandle; + session->handleEvent(reinterpret_cast(&client1)); + + auto &connection = session->clientHandleToConnection[MockDebugSessionLinuxXe::mockClientHandle]; + drm_xe_eudebug_event_metadata metadata{}; + metadata.base.type = DRM_XE_EUDEBUG_EVENT_METADATA; + metadata.base.flags = DRM_XE_EUDEBUG_EVENT_CREATE; + metadata.base.len = sizeof(drm_xe_eudebug_event_metadata); + metadata.client_handle = MockDebugSessionLinuxXe::mockClientHandle; + metadata.metadata_handle = 10; + metadata.type = DRM_XE_DEBUG_METADATA_PROGRAM_MODULE; + metadata.len = sizeof(metadata); + connection->metaDataMap[10].metadata = metadata; + connection->metaDataToModule[10].segmentCount = 2; + + metadata.metadata_handle = 11; + metadata.type = DRM_XE_DEBUG_METADATA_ELF_BINARY; + metadata.len = sizeof(metadata); + connection->metaDataMap[11].metadata = metadata; + auto ptr = std::make_unique(metadata.len); + connection->metaDataMap[11].data = std::move(ptr); + connection->metaDataMap[11].metadata.len = 10000; + + drm_xe_eudebug_event_vm_bind vmBind{}; + vmBind.base.type = DRM_XE_EUDEBUG_EVENT_VM_BIND; + vmBind.base.flags = DRM_XE_EUDEBUG_EVENT_STATE_CHANGE; + vmBind.base.len = sizeof(drm_xe_eudebug_event_vm_bind); + vmBind.base.seqno = seqno++; + vmBind.client_handle = client1.client_handle; + vmBind.vm_handle = 0x1234; + vmBind.flags = DRM_XE_EUDEBUG_EVENT_VM_BIND_FLAG_UFENCE; + vmBind.num_binds = 1; + + session->handleEvent(reinterpret_cast(&vmBind.base)); + auto &vmBindMap = session->clientHandleToConnection[client1.client_handle]->vmBindMap; + + drm_xe_eudebug_event_vm_bind_op vmBindOp{}; + vmBindOp.base.type = DRM_XE_EUDEBUG_EVENT_VM_BIND_OP; + vmBindOp.base.flags = DRM_XE_EUDEBUG_EVENT_CREATE; + vmBindOp.base.len = sizeof(drm_xe_eudebug_event_vm_bind_op); + vmBindOp.base.seqno = seqno++; + vmBindOp.num_extensions = 2; + vmBindOp.addr = seg1Va; + vmBindOp.range = 1000; + vmBindOp.vm_bind_ref_seqno = vmBind.base.seqno; + session->handleEvent(reinterpret_cast(&vmBindOp.base)); + + drm_xe_eudebug_event_vm_bind_ufence vmBindUfence{}; + vmBindUfence.base.type = DRM_XE_EUDEBUG_EVENT_VM_BIND_UFENCE; + vmBindUfence.base.flags = DRM_XE_EUDEBUG_EVENT_CREATE | DRM_XE_EUDEBUG_EVENT_NEED_ACK; + vmBindUfence.base.len = sizeof(drm_xe_eudebug_event_vm_bind_ufence); + vmBindUfence.base.seqno = seqno++; + vmBindUfence.vm_bind_ref_seqno = vmBind.base.seqno; + session->handleEvent(reinterpret_cast(&vmBindUfence.base)); + + auto &vmBindOpData = vmBindMap[vmBindOp.vm_bind_ref_seqno].vmBindOpMap[vmBindOp.base.seqno]; + drm_xe_eudebug_event_vm_bind_op_metadata vmBindOpMetadata{}; + vmBindOpMetadata.base.type = DRM_XE_EUDEBUG_EVENT_VM_BIND_OP_METADATA; + vmBindOpMetadata.base.flags = DRM_XE_EUDEBUG_EVENT_CREATE; + vmBindOpMetadata.base.len = sizeof(drm_xe_eudebug_event_vm_bind_op_metadata); + vmBindOpMetadata.base.seqno = seqno++; + vmBindOpMetadata.vm_bind_op_ref_seqno = vmBindOp.base.seqno; + vmBindOpMetadata.metadata_handle = 10; + session->handleEvent(reinterpret_cast(&vmBindOpMetadata.base)); + + vmBindOpMetadata.base.seqno = seqno++; + vmBindOpMetadata.metadata_handle = 11; + session->handleEvent(reinterpret_cast(&vmBindOpMetadata.base)); + + ASSERT_EQ(vmBindOpData.pendingNumExtensions, 0ull); + ASSERT_EQ(vmBindOpData.vmBindOpMetadataVec.size(), 2ull); + EXPECT_EQ(session->apiEvents.size(), 0u); + + // Now bind 2nd segment + vmBind.base.seqno = seqno++; + vmBind.vm_handle = 0x1234; + vmBind.flags = DRM_XE_EUDEBUG_EVENT_VM_BIND_FLAG_UFENCE; + vmBind.num_binds = 1; + session->handleEvent(reinterpret_cast(&vmBind.base)); + vmBindOp.base.flags = DRM_XE_EUDEBUG_EVENT_CREATE; + vmBindOp.base.seqno = seqno++; + vmBindOp.num_extensions = 2; + vmBindOp.vm_bind_ref_seqno = vmBind.base.seqno; + vmBindOp.addr = seg2Va; + session->handleEvent(reinterpret_cast(&vmBindOp.base)); + vmBindOpMetadata.vm_bind_op_ref_seqno = vmBindOp.base.seqno; + vmBindOpMetadata.base.seqno = seqno++; + vmBindOpMetadata.metadata_handle = 10; + session->handleEvent(reinterpret_cast(&vmBindOpMetadata.base)); + vmBindOpMetadata.base.seqno = seqno++; + vmBindOpMetadata.metadata_handle = 11; + session->handleEvent(reinterpret_cast(&vmBindOpMetadata.base)); + vmBindUfence.base.seqno = seqno++; + vmBindUfence.vm_bind_ref_seqno = vmBind.base.seqno; + session->handleEvent(reinterpret_cast(&vmBindUfence.base)); + + auto event = session->apiEvents.front(); + ASSERT_EQ(ZET_DEBUG_EVENT_TYPE_MODULE_LOAD, event.type); + session->apiEvents.pop(); + + // now do unbinds + vmBind.base.seqno = seqno++; + vmBind.vm_handle = 0x1234; + vmBind.flags = DRM_XE_EUDEBUG_EVENT_VM_BIND_FLAG_UFENCE; + vmBind.num_binds = 1; + session->handleEvent(reinterpret_cast(&vmBind.base)); + vmBindOp.base.flags = DRM_XE_EUDEBUG_EVENT_DESTROY; + vmBindOp.base.seqno = seqno++; + vmBindOp.num_extensions = 0; + vmBindOp.vm_bind_ref_seqno = vmBind.base.seqno; + vmBindOp.addr = seg2Va; + session->handleEvent(reinterpret_cast(&vmBindOp.base)); + vmBindUfence.base.seqno = seqno++; + vmBindUfence.vm_bind_ref_seqno = vmBind.base.seqno; + session->handleEvent(reinterpret_cast(&vmBindUfence.base)); + EXPECT_EQ(session->apiEvents.size(), 0u); + + vmBind.base.seqno = seqno++; + vmBind.vm_handle = 0x555; // Unbind unmatched VM + vmBind.flags = DRM_XE_EUDEBUG_EVENT_VM_BIND_FLAG_UFENCE; + vmBind.num_binds = 1; + session->handleEvent(reinterpret_cast(&vmBind.base)); + vmBindOp.base.flags = DRM_XE_EUDEBUG_EVENT_DESTROY; + vmBindOp.base.seqno = seqno++; + vmBindOp.num_extensions = 0; + vmBindOp.vm_bind_ref_seqno = vmBind.base.seqno; + session->handleEvent(reinterpret_cast(&vmBindOp.base)); + vmBindUfence.base.seqno = seqno++; + vmBindUfence.vm_bind_ref_seqno = vmBind.base.seqno; + session->handleEvent(reinterpret_cast(&vmBindUfence.base)); + // Unmatched vmHandle should not trigger any events + EXPECT_EQ(session->apiEvents.size(), 0u); + + // now unbind final segment + vmBind.base.seqno = seqno++; + vmBind.vm_handle = 0x1234; + vmBind.flags = DRM_XE_EUDEBUG_EVENT_VM_BIND_FLAG_UFENCE; + vmBind.num_binds = 1; + session->handleEvent(reinterpret_cast(&vmBind.base)); + vmBindOp.base.flags = DRM_XE_EUDEBUG_EVENT_DESTROY; + vmBindOp.base.seqno = seqno++; + vmBindOp.num_extensions = 0; + vmBindOp.vm_bind_ref_seqno = vmBind.base.seqno; + vmBindOp.addr = seg1Va; + session->handleEvent(reinterpret_cast(&vmBindOp.base)); + vmBindUfence.base.seqno = seqno++; + vmBindUfence.vm_bind_ref_seqno = vmBind.base.seqno; + session->handleEvent(reinterpret_cast(&vmBindUfence.base)); + + event = session->apiEvents.front(); + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_MODULE_UNLOAD, event.type); +} + TEST_F(DebugApiLinuxTestXe, GivenVmBindOpMetadataEventAndUfenceNotProvidedForProgramModuleWhenHandlingEventThenEventIsNotAckedButHandled) { zet_debug_config_t config = {}; config.pid = 0x1234;