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 347775ac80..345b4e4591 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session.cpp +++ b/level_zero/tools/source/debug/linux/prelim/debug_session.cpp @@ -854,6 +854,7 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v DEBUG_BREAK_IF(module.elfUuidHandle != 0 && connection->uuidMap[vmBind->uuids[index]].ptr != connection->uuidMap[module.elfUuidHandle].ptr); module.elfUuidHandle = vmBind->uuids[index]; + module.deviceBitfield = devices; } } } @@ -994,8 +995,14 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v debugEvent.info.module.moduleEnd = connection->uuidMap[module.elfUuidHandle].ptr + connection->uuidMap[module.elfUuidHandle].dataSize; if (!tileSessionsEnabled) { - pushApiEvent(debugEvent, &vmBind->base); - shouldAckEvent = false; + bool allInstancesEventsReceived = true; + if (module.deviceBitfield.count() > 1) { + allInstancesEventsReceived = checkAllOtherTileModuleSegmentsPresent(tileIndex, module); + } + if (allInstancesEventsReceived) { + pushApiEvent(debugEvent, &vmBind->base); + shouldAckEvent = false; + } } else { auto tileAttached = static_cast(tileSessions[tileIndex].first)->insertModule(debugEvent.info.module); @@ -1031,7 +1038,13 @@ void DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v } } else { - pushApiEvent(debugEvent, nullptr); + bool notifyEvent = true; + if (module.deviceBitfield.count() > 1) { + notifyEvent = checkAllOtherTileModuleSegmentsRemoved(tileIndex, module); + } + if (notifyEvent) { + pushApiEvent(debugEvent, nullptr); + } } module.loadAddresses[tileIndex].clear(); } 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 f0a1a1f4c5..66edfc0b5e 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session.h +++ b/level_zero/tools/source/debug/linux/prelim/debug_session.h @@ -124,6 +124,7 @@ struct DebugSessionLinux : DebugSessionImp { std::unordered_set loadAddresses[NEO::EngineLimits::maxHandleCount]; uint64_t elfUuidHandle; uint32_t segmentCount; + NEO::DeviceBitfield deviceBitfield; int segmentVmBindCounter[NEO::EngineLimits::maxHandleCount]; }; @@ -300,6 +301,32 @@ struct DebugSessionLinux : DebugSessionImp { return allInstancesRemoved; } + bool checkAllOtherTileModuleSegmentsPresent(uint32_t tileIndex, const Module &module) { + bool allInstancesPresent = true; + for (uint32_t i = 0; i < NEO::EngineLimits::maxHandleCount; i++) { + if (i != tileIndex && connectedDevice->getNEODevice()->getDeviceBitfield().test(i)) { + if (module.loadAddresses[i].size() != module.segmentCount) { + allInstancesPresent = false; + break; + } + } + } + return allInstancesPresent; + } + + bool checkAllOtherTileModuleSegmentsRemoved(uint32_t tileIndex, const Module &module) { + bool allInstancesRemoved = true; + for (uint32_t i = 0; i < NEO::EngineLimits::maxHandleCount; i++) { + if (i != tileIndex && connectedDevice->getNEODevice()->getDeviceBitfield().test(i)) { + if (module.loadAddresses[i].size() != 0) { + allInstancesRemoved = false; + break; + } + } + } + return allInstancesRemoved; + } + ThreadHelper internalEventThread; std::mutex internalEventThreadMutex; std::condition_variable internalEventCondition; diff --git a/level_zero/tools/test/unit_tests/sources/debug/linux/debug_session_fixtures_linux.h b/level_zero/tools/test/unit_tests/sources/debug/linux/debug_session_fixtures_linux.h index d71a49a772..3d2af39362 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/linux/debug_session_fixtures_linux.h +++ b/level_zero/tools/test/unit_tests/sources/debug/linux/debug_session_fixtures_linux.h @@ -600,7 +600,7 @@ struct MockDebugSessionLinuxHelper { } void addIsaVmBindEvent(MockDebugSessionLinux *session, uint64_t vm, bool ack, bool create) { - uint64_t vmBindIsaData[sizeof(prelim_drm_i915_debug_event_vm_bind) / sizeof(uint64_t) + 3 * sizeof(typeOfUUID)]; + uint64_t vmBindIsaData[(sizeof(prelim_drm_i915_debug_event_vm_bind) + 3 * sizeof(typeOfUUID) + sizeof(uint64_t)) / sizeof(uint64_t)]; prelim_drm_i915_debug_event_vm_bind *vmBindIsa = reinterpret_cast(&vmBindIsaData); vmBindIsa->base.type = PRELIM_DRM_I915_DEBUG_EVENT_VM_BIND; @@ -633,6 +633,39 @@ struct MockDebugSessionLinuxHelper { session->handleEvent(&vmBindIsa->base); } + void addZebinVmBindEvent(MockDebugSessionLinux *session, uint64_t vm, bool ack, bool create, uint64_t kernelIndex) { + uint64_t vmBindIsaData[(sizeof(prelim_drm_i915_debug_event_vm_bind) + 4 * sizeof(typeOfUUID) + sizeof(uint64_t)) / sizeof(uint64_t)]; + prelim_drm_i915_debug_event_vm_bind *vmBindIsa = reinterpret_cast(&vmBindIsaData); + + vmBindIsa->base.type = PRELIM_DRM_I915_DEBUG_EVENT_VM_BIND; + if (create) { + vmBindIsa->base.flags = PRELIM_DRM_I915_DEBUG_EVENT_CREATE; + } else { + vmBindIsa->base.flags = PRELIM_DRM_I915_DEBUG_EVENT_DESTROY; + } + + if (ack) { + vmBindIsa->base.flags |= PRELIM_DRM_I915_DEBUG_EVENT_NEED_ACK; + } + + vmBindIsa->base.size = sizeof(prelim_drm_i915_debug_event_vm_bind) + 4 * sizeof(typeOfUUID); + vmBindIsa->base.seqno = 10; + vmBindIsa->client_handle = MockDebugSessionLinux::mockClientHandle; + vmBindIsa->va_start = kernelIndex == 0 ? isaGpuVa : isaGpuVa + isaSize; + vmBindIsa->va_length = isaSize; + vmBindIsa->vm_handle = vm; + vmBindIsa->num_uuids = 4; + auto *uuids = reinterpret_cast(ptrOffset(vmBindIsaData, sizeof(prelim_drm_i915_debug_event_vm_bind))); + typeOfUUID uuidsTemp[4]; + uuidsTemp[0] = static_cast(isaUUID); + uuidsTemp[1] = static_cast(cookieUUID); + uuidsTemp[2] = static_cast(elfUUID); + uuidsTemp[3] = static_cast(zebinModuleUUID); + + memcpy_s(uuids, 4 * sizeof(typeOfUUID), uuidsTemp, sizeof(uuidsTemp)); + session->handleEvent(&vmBindIsa->base); + } + const uint64_t sbaClassHandle = 1; const uint64_t moduleDebugClassHandle = 2; const uint64_t contextSaveClassHandle = 3; 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 acc4b36b5a..21c6e52113 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 @@ -6507,6 +6507,99 @@ TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenTileInstancedIsaWhenHandlingVmBi EXPECT_EQ(isaGpuVa, event.info.module.load); } +TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenTileInstancedIsaAndZebinModuleWhenHandlingVmBindCreateEventsThenModuleLoadIsTriggeredAfterAllInstancesEventsReceived) { + + auto handler = new MockIoctlHandler; + session->ioctlHandler.reset(handler); + + uint32_t devices = static_cast(deviceImp->getNEODevice()->getDeviceBitfield().to_ulong()); + + DebugSessionLinux::UuidData isaUuidData = { + .handle = isaUUID, + .classHandle = isaClassHandle, + .classIndex = NEO::DrmResourceClass::Isa, + .data = std::make_unique(sizeof(devices)), + .dataSize = sizeof(devices)}; + + memcpy_s(isaUuidData.data.get(), sizeof(devices), &devices, sizeof(devices)); + session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidMap[isaUUID] = std::move(isaUuidData); + + addZebinVmBindEvent(session.get(), vm0, true, true, 0); + addZebinVmBindEvent(session.get(), vm0, true, true, 1); + EXPECT_EQ(2u, session->clientHandleToConnection[session->clientHandle]->isaMap[0].size()); + EXPECT_EQ(0u, session->clientHandleToConnection[session->clientHandle]->isaMap[1].size()); + EXPECT_EQ(10u, handler->debugEventAcked.seqno); + EXPECT_EQ(0u, session->apiEvents.size()); + + addZebinVmBindEvent(session.get(), vm1, true, true, 0); + addZebinVmBindEvent(session.get(), vm1, true, true, 1); + + EXPECT_EQ(1u, session->apiEvents.size()); + + zet_debug_event_t event; + auto result = session->readEvent(0, &event); + + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_MODULE_LOAD, event.type); + EXPECT_EQ(isaGpuVa, event.info.module.load); +} + +TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenTileInstancedIsaAndZebinModuleWhenHandlingVmBindDestroyEventsThenModuleUnloadIsTriggeredAfterAllInstancesEventsReceived) { + auto handler = new MockIoctlHandler; + session->ioctlHandler.reset(handler); + + uint32_t devices = static_cast(deviceImp->getNEODevice()->getDeviceBitfield().to_ulong()); + + DebugSessionLinux::UuidData isaUuidData = { + .handle = isaUUID, + .classHandle = isaClassHandle, + .classIndex = NEO::DrmResourceClass::Isa, + .data = std::make_unique(sizeof(devices)), + .dataSize = sizeof(devices)}; + + memcpy_s(isaUuidData.data.get(), sizeof(devices), &devices, sizeof(devices)); + session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidMap[isaUUID] = std::move(isaUuidData); + + // VM BIND events for 2 kernels from zebin in vm0 - tile0 + addZebinVmBindEvent(session.get(), vm0, true, true, 0); + addZebinVmBindEvent(session.get(), vm0, true, true, 1); + + EXPECT_EQ(2u, session->clientHandleToConnection[session->clientHandle]->isaMap[0].size()); + EXPECT_EQ(0u, session->clientHandleToConnection[session->clientHandle]->isaMap[1].size()); + + // VM BIND events for 2 kernels from zebin in vm1 - tile0 + addZebinVmBindEvent(session.get(), vm1, true, true, 0); + addZebinVmBindEvent(session.get(), vm1, true, true, 1); + EXPECT_EQ(2u, session->clientHandleToConnection[session->clientHandle]->isaMap[1].size()); + + auto numberOfEvents = session->apiEvents.size(); + + // remove all VM BINDs + addZebinVmBindEvent(session.get(), vm1, false, false, 0); + EXPECT_EQ(numberOfEvents, session->apiEvents.size()); + addZebinVmBindEvent(session.get(), vm1, false, false, 1); + EXPECT_EQ(numberOfEvents, session->apiEvents.size()); + addZebinVmBindEvent(session.get(), vm0, false, false, 0); + EXPECT_EQ(numberOfEvents, session->apiEvents.size()); + addZebinVmBindEvent(session.get(), vm0, false, false, 1); + + // MODULE UNLOAD after all unbinds + auto numberOfAllEvents = session->apiEvents.size(); + EXPECT_EQ(numberOfEvents + 1, numberOfAllEvents); + + zet_debug_event_t event; + ze_result_t result = ZE_RESULT_SUCCESS; + while (numberOfAllEvents--) { + result = session->readEvent(0, &event); + if (result != ZE_RESULT_SUCCESS) { + break; + } + } + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_MODULE_UNLOAD, event.type); + EXPECT_EQ(isaGpuVa, event.info.module.load); +} + TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenTileInstancedIsaWhenWritingAndReadingIsaMemoryThenOnlyWritesAreMirrored) { auto handler = new MockIoctlHandler; session->ioctlHandler.reset(handler);