diff --git a/level_zero/tools/source/debug/linux/debug_session_linux_helper.cpp b/level_zero/tools/source/debug/linux/debug_session_linux_helper.cpp index 921806f30d..ebcb869509 100644 --- a/level_zero/tools/source/debug/linux/debug_session_linux_helper.cpp +++ b/level_zero/tools/source/debug/linux/debug_session_linux_helper.cpp @@ -9,7 +9,7 @@ #include namespace L0 { -DebugSession *createDebugSessionHelper(const zet_debug_config_t &config, Device *device, int debugFd) { +DebugSession *createDebugSessionHelper(const zet_debug_config_t &config, Device *device, int debugFd, void *params) { return nullptr; } 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 0b8f1e0ec0..6013ea2ab8 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session.cpp +++ b/level_zero/tools/source/debug/linux/prelim/debug_session.cpp @@ -32,11 +32,19 @@ namespace L0 { -DebugSession *createDebugSessionHelper(const zet_debug_config_t &config, Device *device, int debugFd); +DebugSession *createDebugSessionHelper(const zet_debug_config_t &config, Device *device, int debugFd, void *params); -DebugSessionLinux::DebugSessionLinux(const zet_debug_config_t &config, Device *device, int debugFd) : DebugSessionImp(config, device), fd(debugFd) { +DebugSessionLinux::DebugSessionLinux(const zet_debug_config_t &config, Device *device, int debugFd, void *params) : DebugSessionImp(config, device), fd(debugFd) { ioctlHandler.reset(new IoctlHandler); + if (params) { + this->i915DebuggerVersion = reinterpret_cast(params)->version; + } + + if (this->i915DebuggerVersion >= 3) { + this->blockOnFenceMode = true; + } + for (size_t i = 0; i < arrayCount(euControlInterruptSeqno); i++) { euControlInterruptSeqno[i] = invalidHandle; } @@ -56,13 +64,14 @@ DebugSession *DebugSession::create(const zet_debug_config_t &config, Device *dev struct prelim_drm_i915_debugger_open_param open = {}; open.pid = config.pid; open.events = 0; + open.version = 0; auto debugFd = DrmHelper::ioctl(device, NEO::DrmIoctl::DebuggerOpen, &open); if (debugFd >= 0) { PRINT_DEBUGGER_INFO_LOG("PRELIM_DRM_IOCTL_I915_DEBUGGER_OPEN: open.pid: %d, open.events: %d, debugFd: %d\n", open.pid, open.events, debugFd); - auto debugSession = createDebugSessionHelper(config, device, debugFd); + auto debugSession = createDebugSessionHelper(config, device, debugFd, &open); debugSession->setAttachMode(isRootAttach); result = debugSession->initialize(); @@ -428,11 +437,11 @@ void DebugSessionLinux::readInternalEventsAsync() { if (tileSessionsEnabled) { auto numTiles = connectedDevice->getNEODevice()->getNumSubDevices(); for (uint32_t tileIndex = 0; tileIndex < numTiles; tileIndex++) { - static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); + static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent); static_cast(tileSessions[tileIndex].first)->detached = true; } } else { - pushApiEvent(debugEvent, nullptr); + pushApiEvent(debugEvent); } detached = true; } else if (numberOfFds > 0) { @@ -538,10 +547,11 @@ void DebugSessionLinux::handleEvent(prelim_drm_i915_debug_event *event) { debugEvent.type = ZET_DEBUG_EVENT_TYPE_PROCESS_EXIT; if (tileSessionsEnabled) { - reinterpret_cast(tileSessions[deviceIndex].first)->processExit(); - static_cast(tileSessions[deviceIndex].first)->pushApiEvent(debugEvent, nullptr); + auto tileSession = reinterpret_cast(tileSessions[deviceIndex].first); + tileSession->processExit(); + tileSession->pushApiEvent(debugEvent); } else if (uuidL0CommandQueueHandleToDevice.size() == 0) { - pushApiEvent(debugEvent, nullptr); + pushApiEvent(debugEvent); } break; @@ -582,10 +592,11 @@ void DebugSessionLinux::handleEvent(prelim_drm_i915_debug_event *event) { if (tileSessionsEnabled) { UNRECOVERABLE_IF(uuidL0CommandQueueHandleToDevice.find(uuid->handle) != uuidL0CommandQueueHandleToDevice.end()); - static_cast(tileSessions[deviceIndex].first)->processEntry(); - static_cast(tileSessions[deviceIndex].first)->pushApiEvent(debugEvent, nullptr); + auto tileSession = static_cast(tileSessions[deviceIndex].first); + tileSession->processEntry(); + tileSession->pushApiEvent(debugEvent); } else if (uuidL0CommandQueueHandleToDevice.size() == 0) { - pushApiEvent(debugEvent, nullptr); + pushApiEvent(debugEvent); } uuidL0CommandQueueHandleToDevice[uuid->handle] = deviceIndex; } @@ -620,9 +631,11 @@ void DebugSessionLinux::handleEvent(prelim_drm_i915_debug_event *event) { auto &newModule = connection->uuidToModule[handle]; newModule.segmentCount = 0; + newModule.moduleUuidHandle = handle; for (uint32_t i = 0; i < NEO::EngineLimits::maxHandleCount; i++) { newModule.segmentVmBindCounter[i] = 0; newModule.loadAddresses[i].clear(); + newModule.moduleLoadEventAcked[i] = false; } } extractUuidData(uuid->client_handle, uuidData); @@ -957,7 +970,7 @@ bool DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v if (tileSessionsEnabled) { auto tileAttached = static_cast(tileSessions[tileIndex].first)->insertModule(debugEvent.info.module); if (tileAttached) { - static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); + static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent); } } else { @@ -965,7 +978,7 @@ bool DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v allInstancesEventsReceived = checkAllOtherTileIsaAllocationsPresent(tileIndex, vmBind->va_start); } if (allInstancesEventsReceived) { - pushApiEvent(debugEvent, nullptr); + pushApiEvent(debugEvent); } } } @@ -973,10 +986,16 @@ bool DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v if (createEvent) { std::lock_guard lock(asyncThreadMutex); - if (allInstancesEventsReceived && !connection->isaMap[tileIndex][vmBind->va_start]->moduleLoadEventAck && perKernelModules) { - PRINT_DEBUGGER_INFO_LOG("Add event to ack, seqno = %llu", (uint64_t)vmBind->base.seqno); - connection->isaMap[tileIndex][vmBind->va_start]->ackEvents.push_back(vmBind->base); - shouldAckEvent = false; + + if (!connection->isaMap[tileIndex][vmBind->va_start]->moduleLoadEventAck && perKernelModules) { + bool doNotAutoAckEvent = (!blockOnFenceMode && allInstancesEventsReceived); // in block on CPU mode - do not auto-ack last event for isa instance + doNotAutoAckEvent |= blockOnFenceMode; // in block on fence mode - do not auto-ack any events + + if (doNotAutoAckEvent) { + PRINT_DEBUGGER_INFO_LOG("Add event to ack, seqno = %llu", (uint64_t)vmBind->base.seqno); + connection->isaMap[tileIndex][vmBind->va_start]->ackEvents.push_back(vmBind->base); + shouldAckEvent = false; + } } connection->isaMap[tileIndex][vmBind->va_start]->vmBindCounter++; @@ -1002,14 +1021,14 @@ bool DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v if (perKernelModules) { if (tileSessionsEnabled) { static_cast(tileSessions[tileIndex].first)->removeModule(debugEvent.info.module); - static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); + static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent); } else { bool notifyEvent = true; if (isa->deviceBitfield.count() > 1) { notifyEvent = checkAllOtherTileIsaAllocationsRemoved(tileIndex, vmBind->va_start); } if (notifyEvent) { - pushApiEvent(debugEvent, nullptr); + pushApiEvent(debugEvent); } } } @@ -1032,37 +1051,93 @@ bool DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v bool canTriggerEvent = module.loadAddresses[tileIndex].size() == (module.segmentCount - 1); module.loadAddresses[tileIndex].insert(vmBind->va_start); - if (canTriggerEvent && module.loadAddresses[tileIndex].size() == module.segmentCount) { - auto gmmHelper = connectedDevice->getNEODevice()->getGmmHelper(); - loadAddress = gmmHelper->canonize(*std::min_element(module.loadAddresses[tileIndex].begin(), module.loadAddresses[tileIndex].end())); - PRINT_DEBUGGER_INFO_LOG("Zebin module loaded at: %p, with %u isa allocations", (void *)loadAddress, module.segmentCount); + if (!blockOnFenceMode) { + if (canTriggerEvent && module.loadAddresses[tileIndex].size() == module.segmentCount) { + auto gmmHelper = connectedDevice->getNEODevice()->getGmmHelper(); + loadAddress = gmmHelper->canonize(*std::min_element(module.loadAddresses[tileIndex].begin(), module.loadAddresses[tileIndex].end())); + PRINT_DEBUGGER_INFO_LOG("Zebin module loaded at: %p, with %u isa allocations", (void *)loadAddress, module.segmentCount); - zet_debug_event_t debugEvent = {}; - debugEvent.type = ZET_DEBUG_EVENT_TYPE_MODULE_LOAD; - debugEvent.info.module.format = ZET_MODULE_DEBUG_INFO_FORMAT_ELF_DWARF; - debugEvent.info.module.load = loadAddress; - debugEvent.info.module.moduleBegin = connection->uuidMap[module.elfUuidHandle].ptr; - debugEvent.info.module.moduleEnd = connection->uuidMap[module.elfUuidHandle].ptr + connection->uuidMap[module.elfUuidHandle].dataSize; + zet_debug_event_t debugEvent = {}; + debugEvent.type = ZET_DEBUG_EVENT_TYPE_MODULE_LOAD; + debugEvent.info.module.format = ZET_MODULE_DEBUG_INFO_FORMAT_ELF_DWARF; + debugEvent.info.module.load = loadAddress; + debugEvent.info.module.moduleBegin = connection->uuidMap[module.elfUuidHandle].ptr; + debugEvent.info.module.moduleEnd = connection->uuidMap[module.elfUuidHandle].ptr + connection->uuidMap[module.elfUuidHandle].dataSize; - if (!tileSessionsEnabled) { - bool allInstancesEventsReceived = true; - if (module.deviceBitfield.count() > 1) { - allInstancesEventsReceived = checkAllOtherTileModuleSegmentsPresent(tileIndex, module); + if (!tileSessionsEnabled) { + bool allInstancesEventsReceived = true; + if (module.deviceBitfield.count() > 1) { + allInstancesEventsReceived = checkAllOtherTileModuleSegmentsPresent(tileIndex, module); + } + if (allInstancesEventsReceived) { + if (vmBind->base.flags & PRELIM_DRM_I915_DEBUG_EVENT_NEED_ACK) { + debugEvent.flags = ZET_DEBUG_EVENT_FLAG_NEED_ACK; + module.ackEvents[tileIndex].push_back(vmBind->base); + } + pushApiEvent(debugEvent, vmBind->uuids[uuidIter]); + shouldAckEvent = false; + } + } else { + auto tileAttached = static_cast(tileSessions[tileIndex].first)->insertModule(debugEvent.info.module); + + if (tileAttached) { + if (vmBind->base.flags & PRELIM_DRM_I915_DEBUG_EVENT_NEED_ACK) { + debugEvent.flags = ZET_DEBUG_EVENT_FLAG_NEED_ACK; + module.ackEvents[tileIndex].push_back(vmBind->base); + } + static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, vmBind->uuids[uuidIter]); + shouldAckEvent = false; + } } - if (allInstancesEventsReceived) { - pushApiEvent(debugEvent, &vmBind->base); + } + } else { + if (canTriggerEvent && module.loadAddresses[tileIndex].size() == module.segmentCount) { + auto gmmHelper = connectedDevice->getNEODevice()->getGmmHelper(); + loadAddress = gmmHelper->canonize(*std::min_element(module.loadAddresses[tileIndex].begin(), module.loadAddresses[tileIndex].end())); + PRINT_DEBUGGER_INFO_LOG("Zebin module loaded at: %p, with %u isa allocations", (void *)loadAddress, module.segmentCount); + + zet_debug_event_t debugEvent = {}; + debugEvent.type = ZET_DEBUG_EVENT_TYPE_MODULE_LOAD; + debugEvent.info.module.format = ZET_MODULE_DEBUG_INFO_FORMAT_ELF_DWARF; + debugEvent.info.module.load = loadAddress; + debugEvent.info.module.moduleBegin = connection->uuidMap[module.elfUuidHandle].ptr; + debugEvent.info.module.moduleEnd = connection->uuidMap[module.elfUuidHandle].ptr + connection->uuidMap[module.elfUuidHandle].dataSize; + if (vmBind->base.flags & PRELIM_DRM_I915_DEBUG_EVENT_NEED_ACK) { + debugEvent.flags = ZET_DEBUG_EVENT_FLAG_NEED_ACK; + } + + if (!tileSessionsEnabled) { + bool allInstancesEventsReceived = true; + if (module.deviceBitfield.count() > 1) { + allInstancesEventsReceived = checkAllOtherTileModuleSegmentsPresent(tileIndex, module); + } + if (allInstancesEventsReceived) { + pushApiEvent(debugEvent, vmBind->uuids[uuidIter]); + shouldAckEvent = false; + } + } else { + auto tileAttached = static_cast(tileSessions[tileIndex].first)->insertModule(debugEvent.info.module); + if (tileAttached) { + static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, vmBind->uuids[uuidIter]); + shouldAckEvent = false; + } + } + } + { + std::lock_guard lock(asyncThreadMutex); + if (!module.moduleLoadEventAcked[tileIndex]) { shouldAckEvent = false; } - } else { - auto tileAttached = static_cast(tileSessions[tileIndex].first)->insertModule(debugEvent.info.module); - - if (tileAttached) { - static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, &vmBind->base); - shouldAckEvent = false; + if (tileSessionsEnabled && !static_cast(tileSessions[tileIndex].first)->isAttached) { + shouldAckEvent = true; + } + if (!shouldAckEvent && (vmBind->base.flags & PRELIM_DRM_I915_DEBUG_EVENT_NEED_ACK)) { + module.ackEvents[tileIndex].push_back(vmBind->base); } } } + } else { // destroyEvent module.segmentVmBindCounter[tileIndex]--; @@ -1084,7 +1159,7 @@ bool DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v auto tileAttached = static_cast(tileSessions[tileIndex].first)->removeModule(debugEvent.info.module); if (tileAttached) { - static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, nullptr); + static_cast(tileSessions[tileIndex].first)->pushApiEvent(debugEvent, vmBind->uuids[uuidIter]); } } else { @@ -1093,10 +1168,11 @@ bool DebugSessionLinux::handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *v notifyEvent = checkAllOtherTileModuleSegmentsRemoved(tileIndex, module); } if (notifyEvent) { - pushApiEvent(debugEvent, nullptr); + pushApiEvent(debugEvent, vmBind->uuids[uuidIter]); } } module.loadAddresses[tileIndex].clear(); + module.moduleLoadEventAcked[tileIndex] = false; } } } @@ -1745,6 +1821,32 @@ bool DebugSessionLinux::ackIsaEvents(uint32_t deviceIndex, uint64_t isaVa) { return false; } +bool DebugSessionLinux::ackModuleEvents(uint32_t deviceIndex, uint64_t moduleUuidHandle) { + std::lock_guard lock(asyncThreadMutex); + + auto connection = clientHandleToConnection[clientHandle].get(); + + if (connection->uuidToModule.find(moduleUuidHandle) != connection->uuidToModule.end()) { + auto &module = connection->uuidToModule[moduleUuidHandle]; + for (auto &event : module.ackEvents[deviceIndex]) { + + prelim_drm_i915_debug_event_ack eventToAck = {}; + eventToAck.type = event.type; + eventToAck.seqno = event.seqno; + eventToAck.flags = 0; + + auto ret = ioctl(PRELIM_I915_DEBUG_IOCTL_ACK_EVENT, &eventToAck); + PRINT_DEBUGGER_INFO_LOG("PRELIM_I915_DEBUG_IOCTL_ACK_EVENT seqno = %llu, ret = %d errno = %d\n", (uint64_t)event.seqno, ret, ret != 0 ? errno : 0); + } + module.ackEvents[deviceIndex].clear(); + module.moduleLoadEventAcked[deviceIndex] = true; + + return true; + } + DEBUG_BREAK_IF(true); + return false; +} + void DebugSessionLinux::cleanRootSessionAfterDetach(uint32_t deviceIndex) { auto connection = clientHandleToConnection[clientHandle].get(); @@ -1772,18 +1874,23 @@ ze_result_t DebugSessionLinux::acknowledgeEvent(const zet_debug_event_t *event) const zet_debug_event_t apiEventToAck = *event; { - std::lock_guard lock(asyncThreadMutex); + std::unique_lock lock(asyncThreadMutex); for (size_t i = 0; i < eventsToAck.size(); i++) { if (apiEventCompare(apiEventToAck, eventsToAck[i].first)) { - auto eventToAck = eventsToAck[i].second; - auto ret = ioctl(PRELIM_I915_DEBUG_IOCTL_ACK_EVENT, &eventToAck); - PRINT_DEBUGGER_INFO_LOG("PRELIM_I915_DEBUG_IOCTL_ACK_EVENT seqno = %llu, ret = %d errno = %d\n", (uint64_t)eventToAck.seqno, ret, ret != 0 ? errno : 0); - + auto moduleUUID = eventsToAck[i].second; auto iter = eventsToAck.begin() + i; eventsToAck.erase(iter); + lock.unlock(); + + for (uint32_t i = 0; i < NEO::EngineLimits::maxHandleCount; i++) { + if (connectedDevice->getNEODevice()->getDeviceBitfield().test(i)) { + ackModuleEvents(i, moduleUUID); + } + } + return ZE_RESULT_SUCCESS; } } @@ -1909,17 +2016,19 @@ void TileDebugSessionLinux::attachTile() { } void TileDebugSessionLinux::detachTile() { + std::vector moduleUuids; { std::lock_guard lock(asyncThreadMutex); - isAttached = false; - - for (size_t i = 0; i < eventsToAck.size(); i++) { - - auto eventToAck = eventsToAck[i].second; - auto ret = ioctl(PRELIM_I915_DEBUG_IOCTL_ACK_EVENT, &eventToAck); - PRINT_DEBUGGER_INFO_LOG("PRELIM_I915_DEBUG_IOCTL_ACK_EVENT seqno = %llu, ret = %d errno = %d\n", (uint64_t)eventToAck.seqno, ret, ret != 0 ? errno : 0); + for (const auto &eventToAck : eventsToAck) { + auto moduleUUID = eventToAck.second; + moduleUuids.push_back(moduleUUID); } eventsToAck.clear(); + isAttached = false; + } + + for (const auto &uuid : moduleUuids) { + rootDebugSession->ackModuleEvents(this->tileIndex, uuid); } } 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 eaada1168d..55bb912d5b 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session.h +++ b/level_zero/tools/source/debug/linux/prelim/debug_session.h @@ -34,7 +34,7 @@ struct DebugSessionLinux : DebugSessionImp { friend struct TileDebugSessionLinux; ~DebugSessionLinux() override; - DebugSessionLinux(const zet_debug_config_t &config, Device *device, int debugFd); + DebugSessionLinux(const zet_debug_config_t &config, Device *device, int debugFd, void *params); ze_result_t initialize() override; @@ -129,10 +129,14 @@ struct DebugSessionLinux : DebugSessionImp { struct Module { std::unordered_set loadAddresses[NEO::EngineLimits::maxHandleCount]; + uint64_t moduleUuidHandle; uint64_t elfUuidHandle; uint32_t segmentCount; NEO::DeviceBitfield deviceBitfield; int segmentVmBindCounter[NEO::EngineLimits::maxHandleCount]; + + std::vector ackEvents[NEO::EngineLimits::maxHandleCount]; + bool moduleLoadEventAcked[NEO::EngineLimits::maxHandleCount]; }; static bool apiEventCompare(const zet_debug_event_t &event1, const zet_debug_event_t &event2) { @@ -183,21 +187,19 @@ struct DebugSessionLinux : DebugSessionImp { ze_result_t interruptImp(uint32_t deviceIndex) override; void enqueueApiEvent(zet_debug_event_t &debugEvent) override { - pushApiEvent(debugEvent, nullptr); + pushApiEvent(debugEvent); } - void pushApiEvent(zet_debug_event_t &debugEvent, prelim_drm_i915_debug_event *baseEvent) { + void pushApiEvent(zet_debug_event_t &debugEvent) { + return pushApiEvent(debugEvent, invalidHandle); + } + + void pushApiEvent(zet_debug_event_t &debugEvent, uint64_t moduleUuidHandle) { std::unique_lock lock(asyncThreadMutex); - if (baseEvent && (baseEvent->flags & PRELIM_DRM_I915_DEBUG_EVENT_NEED_ACK)) { - prelim_drm_i915_debug_event_ack eventToAck = {}; - eventToAck.type = baseEvent->type; - eventToAck.seqno = baseEvent->seqno; - eventToAck.flags = 0; - debugEvent.flags = ZET_DEBUG_EVENT_FLAG_NEED_ACK; - + if (moduleUuidHandle != invalidHandle && (debugEvent.flags & ZET_DEBUG_EVENT_FLAG_NEED_ACK)) { eventsToAck.push_back( - std::pair(debugEvent, eventToAck)); + std::pair(debugEvent, moduleUuidHandle)); } apiEvents.push(debugEvent); @@ -241,6 +243,8 @@ struct DebugSessionLinux : DebugSessionImp { void handleAttentionEvent(prelim_drm_i915_debug_event_eu_attention *attention); void handleEnginesEvent(prelim_drm_i915_debug_event_engines *engines); virtual bool ackIsaEvents(uint32_t deviceIndex, uint64_t isaVa); + virtual bool ackModuleEvents(uint32_t deviceIndex, uint64_t moduleUuidHandle); + MOCKABLE_VIRTUAL void processPendingVmBindEvents(); void attachTile() override { @@ -343,10 +347,11 @@ struct DebugSessionLinux : DebugSessionImp { std::mutex internalEventThreadMutex; std::condition_variable internalEventCondition; std::queue> internalEventQueue; - std::vector> eventsToAck; + std::vector> eventsToAck; // debug event, uuid handle to module std::vector> pendingVmBindEvents; int fd = 0; + uint32_t i915DebuggerVersion = 0; virtual int ioctl(unsigned long request, void *arg); std::unique_ptr ioctlHandler; std::atomic detached{false}; @@ -358,10 +363,12 @@ struct DebugSessionLinux : DebugSessionImp { std::unordered_map> clientHandleToConnection; std::atomic internalThreadHasStarted{false}; + bool blockOnFenceMode = false; // false - blocking VM_BIND on CPU - autoack events until last blocking event + // true - blocking on fence - do not auto-ack events }; struct TileDebugSessionLinux : DebugSessionLinux { - TileDebugSessionLinux(zet_debug_config_t config, Device *device, DebugSessionImp *rootDebugSession) : DebugSessionLinux(config, device, 0), + TileDebugSessionLinux(zet_debug_config_t config, Device *device, DebugSessionImp *rootDebugSession) : DebugSessionLinux(config, device, 0, nullptr), rootDebugSession(reinterpret_cast(rootDebugSession)) { tileIndex = Math::log2(static_cast(connectedDevice->getNEODevice()->getDeviceBitfield().to_ulong())); } @@ -381,6 +388,8 @@ struct TileDebugSessionLinux : DebugSessionLinux { void attachTile() override; void detachTile() override; + bool isAttached = false; + protected: void startAsyncThread() override { UNRECOVERABLE_IF(true); }; void cleanRootSessionAfterDetach(uint32_t deviceIndex) override { UNRECOVERABLE_IF(true); }; @@ -418,6 +427,10 @@ struct TileDebugSessionLinux : DebugSessionLinux { return rootDebugSession->ackIsaEvents(this->tileIndex, isaVa); } + bool ackModuleEvents(uint32_t deviceIndex, uint64_t moduleUuidHandle) override { + return rootDebugSession->ackModuleEvents(this->tileIndex, moduleUuidHandle); + } + ze_result_t readGpuMemory(uint64_t vmHandle, char *output, size_t size, uint64_t gpuVa) override { return rootDebugSession->readGpuMemory(vmHandle, output, size, gpuVa); } @@ -436,7 +449,6 @@ struct TileDebugSessionLinux : DebugSessionLinux { DebugSessionLinux *rootDebugSession = nullptr; uint32_t tileIndex = std::numeric_limits::max(); - bool isAttached = false; bool processEntryState = false; std::unordered_map modules; diff --git a/level_zero/tools/source/debug/linux/prelim/debug_session_linux_helper.cpp b/level_zero/tools/source/debug/linux/prelim/debug_session_linux_helper.cpp index f93f8f3365..d253b857d6 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session_linux_helper.cpp +++ b/level_zero/tools/source/debug/linux/prelim/debug_session_linux_helper.cpp @@ -9,8 +9,8 @@ #include namespace L0 { -DebugSession *createDebugSessionHelper(const zet_debug_config_t &config, Device *device, int debugFd) { - return new DebugSessionLinux(config, device, debugFd); +DebugSession *createDebugSessionHelper(const zet_debug_config_t &config, Device *device, int debugFd, void *params) { + return new DebugSessionLinux(config, device, debugFd, params); } } // namespace L0 diff --git a/level_zero/tools/source/debug/windows/debug_session.cpp b/level_zero/tools/source/debug/windows/debug_session.cpp index 54d3b29d99..207a504a22 100644 --- a/level_zero/tools/source/debug/windows/debug_session.cpp +++ b/level_zero/tools/source/debug/windows/debug_session.cpp @@ -17,7 +17,7 @@ namespace L0 { -DebugSession *createDebugSessionHelper(const zet_debug_config_t &config, Device *device, int debugFd); +DebugSession *createDebugSessionHelper(const zet_debug_config_t &config, Device *device, int debugFd, void *params); DebugSessionWindows::~DebugSessionWindows() { closeAsyncThread(); @@ -29,7 +29,7 @@ DebugSession *DebugSession::create(const zet_debug_config_t &config, Device *dev return nullptr; } - auto debugSession = createDebugSessionHelper(config, device, 0); + auto debugSession = createDebugSessionHelper(config, device, 0, nullptr); debugSession->setAttachMode(isRootAttach); result = debugSession->initialize(); if (result != ZE_RESULT_SUCCESS) { diff --git a/level_zero/tools/source/debug/windows/debug_session_windows_helper.cpp b/level_zero/tools/source/debug/windows/debug_session_windows_helper.cpp index e668b43398..2f57bea743 100644 --- a/level_zero/tools/source/debug/windows/debug_session_windows_helper.cpp +++ b/level_zero/tools/source/debug/windows/debug_session_windows_helper.cpp @@ -9,7 +9,7 @@ #include namespace L0 { -DebugSession *createDebugSessionHelper(const zet_debug_config_t &config, Device *device, int debugFd) { +DebugSession *createDebugSessionHelper(const zet_debug_config_t &config, Device *device, int debugFd, void *params) { return new DebugSessionWindows(config, device); } diff --git a/level_zero/tools/test/unit_tests/sources/debug/debug_session_helper.cpp b/level_zero/tools/test/unit_tests/sources/debug/debug_session_helper.cpp index 3d73e9af5f..8f8ae70a39 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/debug_session_helper.cpp +++ b/level_zero/tools/test/unit_tests/sources/debug/debug_session_helper.cpp @@ -13,9 +13,9 @@ namespace L0 { namespace ult { CreateDebugSessionHelperFunc createDebugSessionFunc = nullptr; } -DebugSession *createDebugSessionHelper(const zet_debug_config_t &config, Device *device, int debugFd) { +DebugSession *createDebugSessionHelper(const zet_debug_config_t &config, Device *device, int debugFd, void *params) { if (L0::ult::createDebugSessionFunc) { - return L0::ult::createDebugSessionFunc(config, device, debugFd); + return L0::ult::createDebugSessionFunc(config, device, debugFd, params); } return new L0::ult::DebugSessionMock(config, device); } 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 9b49b798dc..56d43e7d93 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 @@ -250,6 +250,7 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux { using L0::DebugSessionImp::triggerEvents; using L0::DebugSessionLinux::asyncThread; + using L0::DebugSessionLinux::blockOnFenceMode; using L0::DebugSessionLinux::checkAllEventsCollected; using L0::DebugSessionLinux::clientHandle; using L0::DebugSessionLinux::clientHandleClosed; @@ -292,12 +293,14 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux { using L0::DebugSessionLinux::uuidL0CommandQueueHandleToDevice; using L0::DebugSessionLinux::writeGpuMemory; - MockDebugSessionLinux(const zet_debug_config_t &config, L0::Device *device, int debugFd) : DebugSessionLinux(config, device, debugFd) { + MockDebugSessionLinux(const zet_debug_config_t &config, L0::Device *device, int debugFd, void *params) : DebugSessionLinux(config, device, debugFd, params) { clientHandleToConnection[mockClientHandle].reset(new ClientConnection); clientHandle = mockClientHandle; createEuThreads(); } + MockDebugSessionLinux(const zet_debug_config_t &config, L0::Device *device, int debugFd) : MockDebugSessionLinux(config, device, debugFd, nullptr) {} + ze_result_t initialize() override { if (initializeRetVal != ZE_RESULT_FORCE_UINT32) { bool isRootDevice = !connectedDevice->getNEODevice()->isSubDevice(); @@ -459,6 +462,7 @@ struct MockTileDebugSessionLinux : TileDebugSessionLinux { using DebugSessionImp::stateSaveAreaHeader; using DebugSessionImp::triggerEvents; using DebugSessionLinux::detached; + using DebugSessionLinux::ioctl; using DebugSessionLinux::pushApiEvent; using TileDebugSessionLinux::cleanRootSessionAfterDetach; using TileDebugSessionLinux::getAllMemoryHandles; @@ -605,7 +609,6 @@ struct MockDebugSessionLinuxHelper { session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->classHandleToIndex[zebinModuleClassHandle] = {"L0_ZEBIN_MODULE", static_cast(NEO::DrmResourceClass::L0ZebinModule)}; session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidMap.emplace(zebinModuleUUID, std::move(zebinModuleUuidData)); session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].segmentCount = 2; - session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidMap[elfUUID].ptr = elfVa; } @@ -648,7 +651,7 @@ struct MockDebugSessionLinuxHelper { session->handleEvent(&vmBindIsa->base); } - void addZebinVmBindEvent(MockDebugSessionLinux *session, uint64_t vm, bool ack, bool create, uint64_t kernelIndex) { + void addZebinVmBindEvent(MockDebugSessionLinux *session, uint64_t vm, bool ack, bool create, uint64_t kernelIndex, uint32_t zebinModuleId) { 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); @@ -666,7 +669,21 @@ struct MockDebugSessionLinuxHelper { 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; + if (zebinModuleId == 0) { + vmBindIsa->va_start = kernelIndex == 0 ? isaGpuVa : isaGpuVa + isaSize; + } else { + vmBindIsa->va_start = kernelIndex == 0 ? isaGpuVa * 4 : isaGpuVa * 4 + isaSize; + + DebugSessionLinux::UuidData zebinModuleUuidData = { + .handle = zebinModuleUUID1, + .classHandle = zebinModuleClassHandle, + .classIndex = NEO::DrmResourceClass::L0ZebinModule, + .data = std::make_unique(sizeof(kernelCount)), + .dataSize = sizeof(kernelCount)}; + + session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidMap.emplace(zebinModuleUUID1, std::move(zebinModuleUuidData)); + session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID1].segmentCount = kernelCount; + } vmBindIsa->va_length = isaSize; vmBindIsa->vm_handle = vm; vmBindIsa->num_uuids = 4; @@ -675,12 +692,16 @@ struct MockDebugSessionLinuxHelper { uuidsTemp[0] = static_cast(isaUUID); uuidsTemp[1] = static_cast(cookieUUID); uuidsTemp[2] = static_cast(elfUUID); - uuidsTemp[3] = static_cast(zebinModuleUUID); + uuidsTemp[3] = static_cast(zebinModuleId == 0 ? zebinModuleUUID : zebinModuleUUID1); memcpy_s(uuids, 4 * sizeof(typeOfUUID), uuidsTemp, sizeof(uuidsTemp)); session->handleEvent(&vmBindIsa->base); } + void addZebinVmBindEvent(MockDebugSessionLinux *session, uint64_t vm, bool ack, bool create, uint64_t kernelIndex) { + return addZebinVmBindEvent(session, vm, ack, create, kernelIndex, 0); + } + const uint64_t sbaClassHandle = 1; const uint64_t moduleDebugClassHandle = 2; const uint64_t contextSaveClassHandle = 3; @@ -696,6 +717,7 @@ struct MockDebugSessionLinuxHelper { const uint64_t zebinModuleClassHandle = 101; const uint64_t zebinModuleUUID = 9; + const uint64_t zebinModuleUUID1 = 10; const uint32_t kernelCount = 2; const uint64_t vm0 = 1; 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 efc27fcb26..21009e8d4f 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 @@ -386,7 +386,7 @@ TEST(DebugSessionLinuxTest, GivenRootDebugSessionWhenCreateTileSessionCalledThen using DebugSessionLinux::DebugSessionLinux; }; - auto session = std::make_unique(zet_debug_config_t{0x1234}, &deviceImp, 10); + auto session = std::make_unique(zet_debug_config_t{0x1234}, &deviceImp, 10, nullptr); ASSERT_NE(nullptr, session); std::unique_ptr tileSession = std::unique_ptr{session->createTileSession(zet_debug_config_t{0x1234}, &deviceImp, nullptr)}; @@ -410,8 +410,56 @@ TEST(DebugSessionLinuxTest, GivenRootLinuxSessionWhenCallingTileSepcificFunction EXPECT_THROW(sessionMock->detachTile(), std::exception); } +using DebugSessionLinuxFenceMode = Test; + +TEST_F(DebugSessionLinuxFenceMode, GivenDebuggerOpenVersionGreaterEqual3WhenDebugSessionCreatedThanBlockingOnFenceModeIsSet) { + + zet_debug_config_t config = {}; + config.pid = 0x1234; + + VariableBackup mockCreateDebugSessionBackup(&L0::ult::createDebugSessionFunc, [](const zet_debug_config_t &config, L0::Device *device, int debugFd, void *params) -> DebugSession * { + auto session = new MockDebugSessionLinux(config, device, debugFd, params); + session->initializeRetVal = ZE_RESULT_SUCCESS; + return session; + }); + + mockDrm->context.debuggerOpenVersion = 3; + + ze_result_t result = ZE_RESULT_SUCCESS; + auto session = std::unique_ptr(DebugSession::create(config, device, result, false)); + + MockDebugSessionLinux *linuxSession = static_cast(session.get()); + + EXPECT_TRUE(linuxSession->blockOnFenceMode); +} + using DebugApiLinuxTest = Test; +TEST_F(DebugApiLinuxTest, GivenDebuggerOpenVersion1AndSuccessfulInitializationWhenCreatingDebugSessionThenBlockOnFenceModeIsFalse) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + ze_result_t result = ZE_RESULT_SUCCESS; + + VariableBackup mockCreateDebugSessionBackup(&L0::ult::createDebugSessionFunc, [](const zet_debug_config_t &config, L0::Device *device, int debugFd, void *params) -> DebugSession * { + auto session = new MockDebugSessionLinux(config, device, debugFd, params); + session->initializeRetVal = ZE_RESULT_SUCCESS; + return session; + }); + + mockDrm->context.debuggerOpenRetval = 10; + mockDrm->context.debuggerOpenVersion = 1; + mockDrm->baseErrno = false; + mockDrm->errnoRetVal = 0; + + auto session = std::unique_ptr(DebugSession::create(config, device, result, !device->getNEODevice()->isSubDevice())); + + EXPECT_NE(nullptr, session); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + MockDebugSessionLinux *linuxSession = static_cast(session.get()); + EXPECT_FALSE(linuxSession->blockOnFenceMode); +} + TEST_F(DebugApiLinuxTest, givenDeviceWhenCallingDebugAttachThenSuccessAndValidSessionHandleAreReturned) { zet_debug_config_t config = {}; config.pid = 0x1234; @@ -478,20 +526,13 @@ TEST_F(DebugApiLinuxTest, GivenUnknownEventWhenAcknowledgeEventCalledThenErrorUn auto result = L0::DebugApiHandlers::debugAcknowledgeEvent(session, &debugEvent); EXPECT_EQ(result, ZE_RESULT_ERROR_UNINITIALIZED); - // One event to acknowledge - prelim_drm_i915_debug_event eventToAck = {}; - eventToAck.type = 500; - eventToAck.seqno = 5; - eventToAck.flags = PRELIM_DRM_I915_DEBUG_EVENT_NEED_ACK; - eventToAck.size = sizeof(prelim_drm_i915_debug_event); - debugEvent.type = ZET_DEBUG_EVENT_TYPE_MODULE_LOAD; debugEvent.info.module.format = ZET_MODULE_DEBUG_INFO_FORMAT_ELF_DWARF; debugEvent.info.module.load = 0x1000; debugEvent.info.module.moduleBegin = 0x2000; debugEvent.info.module.moduleEnd = 0x3000; - sessionMock->pushApiEvent(debugEvent, &eventToAck); + sessionMock->pushApiEvent(debugEvent); // Different event acknowledged debugEvent.info.module.load = 0x2221000; @@ -514,15 +555,33 @@ TEST_F(DebugApiLinuxTest, GivenEventRequiringAckWhenAcknowledgeEventCalledThenSu zet_debug_session_handle_t session = sessionMock->toHandle(); sessionMock->clientHandle = MockDebugSessionLinux::mockClientHandle; + uint64_t isaGpuVa = 0x345000; + uint64_t isaSize = 0x2000; + zet_debug_event_t debugEvent = {}; debugEvent.flags = ZET_DEBUG_EVENT_FLAG_NEED_ACK; + debugEvent.info.module.load = isaGpuVa; + debugEvent.type = ZET_DEBUG_EVENT_TYPE_MODULE_LOAD; prelim_drm_i915_debug_event eventToAck = {}; eventToAck.type = 500; eventToAck.seqno = 10; eventToAck.flags = PRELIM_DRM_I915_DEBUG_EVENT_NEED_ACK; eventToAck.size = sizeof(prelim_drm_i915_debug_event); - sessionMock->pushApiEvent(debugEvent, &eventToAck); + + auto isa = std::make_unique(); + isa->bindInfo = {isaGpuVa, isaSize}; + isa->vmHandle = 3; + isa->elfUuidHandle = DebugSessionLinux::invalidHandle; + isa->moduleBegin = 0; + isa->moduleEnd = 0; + + auto &isaMap = sessionMock->clientHandleToConnection[sessionMock->clientHandle]->isaMap[0]; + isaMap[isaGpuVa] = std::move(isa); + isaMap[isaGpuVa]->vmBindCounter = 5; + isaMap[isaGpuVa]->ackEvents.push_back(eventToAck); + + sessionMock->pushApiEvent(debugEvent); auto result = zetDebugAcknowledgeEvent(session, &debugEvent); EXPECT_EQ(result, ZE_RESULT_SUCCESS); @@ -3727,7 +3786,6 @@ TEST_F(DebugApiLinuxVmBindTest, GivenEventForISAWhenModuleLoadEventAlreadyAckedT vmBindIsa->client_handle = MockDebugSessionLinux::mockClientHandle; vmBindIsa->va_start = isaGpuVa; vmBindIsa->va_length = isaSize; - vmBindIsa->vm_handle = vmHandleForVmBind; vmBindIsa->num_uuids = 3; auto *uuids = reinterpret_cast(ptrOffset(vmBindIsaData, sizeof(prelim_drm_i915_debug_event_vm_bind))); @@ -3739,22 +3797,33 @@ TEST_F(DebugApiLinuxVmBindTest, GivenEventForISAWhenModuleLoadEventAlreadyAckedT memcpy(uuids, uuidsTemp, sizeof(uuidsTemp)); - session->handleEvent(&vmBindIsa->base); + bool modes[] = {false, + true}; - auto isaIter = session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->isaMap[0].find(isaGpuVa); - ASSERT_NE(session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->isaMap[0].end(), isaIter); - EXPECT_EQ(1u, isaIter->second->ackEvents.size()); + for (const auto &mode : modes) { - auto event = session->apiEvents.front(); - session->apiEvents.pop(); + session->blockOnFenceMode = mode; - session->acknowledgeEvent(&event); - EXPECT_EQ(0u, isaIter->second->ackEvents.size()); + vmBindIsa->vm_handle = vmHandleForVmBind; + session->handleEvent(&vmBindIsa->base); - vmBindIsa->vm_handle = vmHandleForVmBind + 100; - session->handleEvent(&vmBindIsa->base); + auto isaIter = session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->isaMap[0].find(isaGpuVa); + ASSERT_NE(session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->isaMap[0].end(), isaIter); + EXPECT_EQ(1u, isaIter->second->ackEvents.size()); - EXPECT_EQ(0u, isaIter->second->ackEvents.size()); + auto event = session->apiEvents.front(); + session->apiEvents.pop(); + + session->acknowledgeEvent(&event); + EXPECT_EQ(0u, isaIter->second->ackEvents.size()); + + vmBindIsa->vm_handle = vmHandleForVmBind + 100; + session->handleEvent(&vmBindIsa->base); + + EXPECT_EQ(0u, isaIter->second->ackEvents.size()); + + session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->isaMap->clear(); + } } TEST_F(DebugApiLinuxVmBindTest, GivenEventForIsaWithoutAckTriggeredBeforeAttachWhenHandlingSubsequentEventsWithAckThenEventsAreAckedImmediatelyAndNotPushed) { @@ -3806,6 +3875,80 @@ TEST_F(DebugApiLinuxVmBindTest, GivenEventForIsaWithoutAckTriggeredBeforeAttachW EXPECT_EQ(vmBindIsa->base.seqno, handler->debugEventAcked.seqno); } +TEST_F(DebugApiLinuxVmBindTest, GivenTwoPendingEventsWhenAcknowledgeEventCalledThenCorrectEventIsAcked) { + setupVmToTile(session.get()); + // first module + addZebinVmBindEvent(session.get(), vm0, true, true, 0); + addZebinVmBindEvent(session.get(), vm0, true, true, 1); + + EXPECT_EQ(1u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[0].size()); + + // second module + addZebinVmBindEvent(session.get(), vm0, true, true, 0, 1); + addZebinVmBindEvent(session.get(), vm0, true, true, 1, 1); + + EXPECT_EQ(1u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID1].ackEvents[0].size()); + EXPECT_EQ(2u, session->apiEvents.size()); + + zet_debug_event_t event0 = {}; + auto result = session->readEvent(0, &event0); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + zet_debug_event_t event1 = {}; + result = session->readEvent(0, &event1); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + // 2 modules need ack + EXPECT_EQ(2u, session->eventsToAck.size()); + + handler->ackCount = 0; + session->acknowledgeEvent(&event1); + EXPECT_EQ(0u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID1].ackEvents[0].size()); + EXPECT_NE(0u, handler->ackCount); + EXPECT_EQ(1u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[0].size()); + + // 1 module needs ack + EXPECT_EQ(1u, session->eventsToAck.size()); +} + +TEST_F(DebugApiLinuxVmBindTest, GivenBlockOnFenceAndTwoPendingEventsWhenAcknowledgeEventCalledThenCorrectEventIsAcked) { + session->blockOnFenceMode = true; + setupVmToTile(session.get()); + // first module + addZebinVmBindEvent(session.get(), vm0, true, true, 0); + addZebinVmBindEvent(session.get(), vm0, true, true, 1); + + EXPECT_EQ(2u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[0].size()); + + // second module + addZebinVmBindEvent(session.get(), vm0, true, true, 0, 1); + addZebinVmBindEvent(session.get(), vm0, true, true, 1, 1); + + EXPECT_EQ(2u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID1].ackEvents[0].size()); + + EXPECT_EQ(2u, session->apiEvents.size()); + + zet_debug_event_t event0 = {}; + auto result = session->readEvent(0, &event0); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + zet_debug_event_t event1 = {}; + result = session->readEvent(0, &event1); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + // 2 modules need ack + EXPECT_EQ(2u, session->eventsToAck.size()); + + handler->ackCount = 0; + session->acknowledgeEvent(&event1); + EXPECT_EQ(0u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID1].ackEvents[0].size()); + EXPECT_EQ(2u, handler->ackCount); + EXPECT_EQ(2u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[0].size()); + + // 1 module needs ack + EXPECT_EQ(1u, session->eventsToAck.size()); +} + TEST_F(DebugApiLinuxVmBindTest, GivenIsaRemovedWhenModuleLoadEventIsAckedThenErrorReturned) { uint64_t isaGpuVa = 0x345000; uint64_t isaSize = 0x2000; @@ -6707,7 +6850,7 @@ TEST_F(DebugApiLinuxMultitileTest, GivenRootDeviceWhenDebugAttachCalledThenRootS config.pid = 0x1234; zet_debug_session_handle_t debugSession = nullptr; - VariableBackup mockCreateDebugSessionBackup(&L0::ult::createDebugSessionFunc, [](const zet_debug_config_t &config, L0::Device *device, int debugFd) -> DebugSession * { + VariableBackup mockCreateDebugSessionBackup(&L0::ult::createDebugSessionFunc, [](const zet_debug_config_t &config, L0::Device *device, int debugFd, void *params) -> DebugSession * { auto session = new MockDebugSessionLinux(config, device, debugFd); session->initializeRetVal = ZE_RESULT_SUCCESS; return session; @@ -6734,7 +6877,7 @@ TEST_F(DebugApiLinuxMultitileTest, GivenSubDeviceWhenDebugAttachCalledThenTileSe zet_debug_session_handle_t debugSession = nullptr; zet_debug_session_handle_t debugSessionRoot = nullptr; - VariableBackup mockCreateDebugSessionBackup(&L0::ult::createDebugSessionFunc, [](const zet_debug_config_t &config, L0::Device *device, int debugFd) -> DebugSession * { + VariableBackup mockCreateDebugSessionBackup(&L0::ult::createDebugSessionFunc, [](const zet_debug_config_t &config, L0::Device *device, int debugFd, void *params) -> DebugSession * { auto session = new MockDebugSessionLinux(config, device, debugFd); session->initializeRetVal = ZE_RESULT_SUCCESS; return session; @@ -6832,6 +6975,7 @@ TEST_F(DebugApiLinuxMultitileTest, givenApiThreadAndMultipleTilesWhenGettingDevi EXPECT_EQ(1u, deviceIndex); } +template struct DebugApiLinuxMultiDeviceVmBindFixture : public DebugApiLinuxMultiDeviceFixture, public MockDebugSessionLinuxHelper { void setUp() { DebugApiLinuxMultiDeviceFixture::setUp(); @@ -6846,6 +6990,7 @@ struct DebugApiLinuxMultiDeviceVmBindFixture : public DebugApiLinuxMultiDeviceFi handler = new MockIoctlHandler; session->ioctlHandler.reset(handler); + session->blockOnFenceMode = BlockOnFence; setupSessionClassHandlesAndUuidMap(session.get()); setupVmToTile(session.get()); } @@ -6854,11 +6999,67 @@ struct DebugApiLinuxMultiDeviceVmBindFixture : public DebugApiLinuxMultiDeviceFi DebugApiLinuxMultiDeviceFixture::tearDown(); } + void 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); + } + MockIoctlHandler *handler = nullptr; std::unique_ptr session; }; -using DebugApiLinuxMultiDeviceVmBindTest = Test; +using DebugApiLinuxMultiDeviceVmBindTest = Test>; TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenTileInstancedIsaWhenHandlingVmBindCreateEventsThenModuleLoadIsTriggeredAfterAllInstancesEventsReceived) { @@ -6960,28 +7161,45 @@ TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenTileInstancedIsaAndZebinModuleWh session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidMap[isaUUID] = std::move(isaUuidData); addZebinVmBindEvent(session.get(), vm0, true, true, 0); + EXPECT_EQ(1u, handler->ackCount); addZebinVmBindEvent(session.get(), vm0, true, true, 1); + EXPECT_EQ(2u, handler->ackCount); + 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); + EXPECT_EQ(3u, handler->ackCount); addZebinVmBindEvent(session.get(), vm1, true, true, 1); + // ACK not called for last segment + EXPECT_EQ(3u, handler->ackCount); EXPECT_EQ(1u, session->apiEvents.size()); + EXPECT_EQ(0u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[0].size()); + EXPECT_EQ(1u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[1].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(ZET_DEBUG_EVENT_FLAG_NEED_ACK, event.flags); EXPECT_EQ(isaGpuVa, event.info.module.load); } TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenTileInstancedIsaAndZebinModuleWhenHandlingVmBindDestroyEventsThenModuleUnloadIsTriggeredAfterAllInstancesEventsReceived) { + givenTileInstancedIsaAndZebinModuleWhenHandlingVmBindDestroyEventsThenModuleUnloadIsTriggeredAfterAllInstancesEventsReceived(); +} + +using DebugLinuxMultiDeviceVmBindBlockOnFenceTest = Test>; + +TEST_F(DebugLinuxMultiDeviceVmBindBlockOnFenceTest, givenTileInstancedIsaAndZebinModuleWhenHandlingVmBindCreateEventsThenModuleLoadIsTriggeredAfterAllInstancesEventsReceived) { + auto handler = new MockIoctlHandler; session->ioctlHandler.reset(handler); + handler->debugEventAcked.seqno = std::numeric_limits::max(); uint32_t devices = static_cast(deviceImp->getNEODevice()->getDeviceBitfield().to_ulong()); @@ -6995,43 +7213,154 @@ TEST_F(DebugApiLinuxMultiDeviceVmBindTest, givenTileInstancedIsaAndZebinModuleWh 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()); + // No ACK ioctl called + EXPECT_EQ(0u, handler->ackCount); + EXPECT_EQ(0u, session->apiEvents.size()); + + addZebinVmBindEvent(session.get(), vm1, true, true, 0); + addZebinVmBindEvent(session.get(), vm1, true, true, 1); + + // No ACK ioctl called + EXPECT_EQ(0u, handler->ackCount); + EXPECT_EQ(1u, session->apiEvents.size()); + EXPECT_EQ(kernelCount, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[0].size()); + EXPECT_EQ(kernelCount, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[1].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(ZET_DEBUG_EVENT_FLAG_NEED_ACK, event.flags); + EXPECT_EQ(isaGpuVa, event.info.module.load); +} + +TEST_F(DebugLinuxMultiDeviceVmBindBlockOnFenceTest, givenTileInstancedIsaAndZebinModuleWhenHandlingVmBindDestroyEventsThenModuleUnloadIsTriggeredAfterAllInstancesEventsReceived) { + givenTileInstancedIsaAndZebinModuleWhenHandlingVmBindDestroyEventsThenModuleUnloadIsTriggeredAfterAllInstancesEventsReceived(); +} + +TEST_F(DebugLinuxMultiDeviceVmBindBlockOnFenceTest, givenTileInstancedIsaAndZebinModuleWhenAcknowledgingEventThenModuleFromBothTilesAreAcked) { + + auto handler = new MockIoctlHandler; + session->ioctlHandler.reset(handler); + handler->debugEventAcked.seqno = std::numeric_limits::max(); + 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()); - - // 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); + // No ACK ioctl called + EXPECT_EQ(0u, handler->ackCount); + EXPECT_EQ(1u, session->apiEvents.size()); 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; - } - } + auto result = session->readEvent(0, &event); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); - EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_MODULE_UNLOAD, event.type); + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_MODULE_LOAD, event.type); + EXPECT_EQ(ZET_DEBUG_EVENT_FLAG_NEED_ACK, event.flags); + + result = zetDebugAcknowledgeEvent(session->toHandle(), &event); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + EXPECT_EQ(4u, handler->ackCount); + EXPECT_TRUE(session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].moduleLoadEventAcked[0]); + EXPECT_TRUE(session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].moduleLoadEventAcked[1]); + EXPECT_EQ(0u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[0].size()); + EXPECT_EQ(0u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[1].size()); +} + +TEST_F(DebugLinuxMultiDeviceVmBindBlockOnFenceTest, givenTileInstancedIsaAndZebinModuleWhenModuleUUIDIsNotFoundThenAcknowledgeCallsDebugBreakAndReturnsSuccess) { + + auto handler = new MockIoctlHandler; + session->ioctlHandler.reset(handler); + handler->debugEventAcked.seqno = std::numeric_limits::max(); + 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); + + addZebinVmBindEvent(session.get(), vm1, true, true, 0); + addZebinVmBindEvent(session.get(), vm1, true, true, 1); + + ASSERT_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(ZET_DEBUG_EVENT_FLAG_NEED_ACK, event.flags); + + session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule.erase(zebinModuleUUID); + + result = zetDebugAcknowledgeEvent(session->toHandle(), &event); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + EXPECT_EQ(0u, handler->ackCount); +} + +TEST_F(DebugLinuxMultiDeviceVmBindBlockOnFenceTest, givenZebinModuleForTileWithoutAckFlagWhenHandlingVmBindCreateEventsThenModuleLoadIsTriggeredAfterOneTileInstancesEventsReceived) { + + auto handler = new MockIoctlHandler; + session->ioctlHandler.reset(handler); + handler->debugEventAcked.seqno = std::numeric_limits::max(); + + uint32_t devices = static_cast(deviceImp->getNEODevice()->getSubDevice(0)->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, false, true, 0); + addZebinVmBindEvent(session.get(), vm0, false, true, 1); + EXPECT_EQ(2u, session->clientHandleToConnection[session->clientHandle]->isaMap[0].size()); + EXPECT_EQ(0u, session->clientHandleToConnection[session->clientHandle]->isaMap[1].size()); + // No ACK ioctl called + EXPECT_EQ(0u, handler->ackCount); + EXPECT_EQ(1u, session->apiEvents.size()); + EXPECT_EQ(0u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[0].size()); + EXPECT_EQ(0u, session->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[1].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(0u, event.flags); EXPECT_EQ(isaGpuVa, event.info.module.load); } diff --git a/level_zero/tools/test/unit_tests/sources/debug/linux/tile_debug_session_linux_tests.cpp b/level_zero/tools/test/unit_tests/sources/debug/linux/tile_debug_session_linux_tests.cpp index 38beb23e90..e14b5881c3 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/linux/tile_debug_session_linux_tests.cpp +++ b/level_zero/tools/test/unit_tests/sources/debug/linux/tile_debug_session_linux_tests.cpp @@ -84,6 +84,12 @@ TEST(TileDebugSessionLinuxTest, GivenTileDebugSessionWhenCallingFunctionsThenCal auto rootSbaGpuVa = rootSession->getSbaBufferGpuVa(5); EXPECT_EQ(0x567000u, sbaGpuVa); EXPECT_EQ(rootSbaGpuVa, sbaGpuVa); + + auto handler = new MockIoctlHandler; + rootSession->ioctlHandler.reset(handler); + + session->ioctl(0, nullptr); + EXPECT_EQ(1, handler->ioctlCalled); } TEST(TileDebugSessionLinuxTest, GivenTileDebugSessionWhenReadingContextStateSaveAreaHeaderThenHeaderIsCopiedFromRootSession) { @@ -111,6 +117,7 @@ TEST(TileDebugSessionLinuxTest, GivenTileDebugSessionWhenReadingContextStateSave EXPECT_STREQ(header, data); } +template struct TileAttachFixture : public DebugApiLinuxMultiDeviceFixture, public MockDebugSessionLinuxHelper { void setUp() { NEO::DebugManager.flags.ExperimentalEnableTileAttach.set(1); @@ -124,6 +131,7 @@ struct TileAttachFixture : public DebugApiLinuxMultiDeviceFixture, public MockDe session->clientHandle = MockDebugSessionLinux::mockClientHandle; session->createTileSessionsIfEnabled(); rootSession = session.get(); + rootSession->blockOnFenceMode = BlockOnFence; tileSessions[0] = static_cast(rootSession->tileSessions[0].first); tileSessions[1] = static_cast(rootSession->tileSessions[1].first); @@ -142,7 +150,7 @@ struct TileAttachFixture : public DebugApiLinuxMultiDeviceFixture, public MockDe MockTileDebugSessionLinux *tileSessions[2]; }; -using TileAttachTest = Test; +using TileAttachTest = Test>; TEST_F(TileAttachTest, GivenTileAttachEnabledAndMultitileDeviceWhenInitializingDebugSessionThenTileSessionsAreCreated) { zet_debug_config_t config = {}; @@ -773,43 +781,50 @@ TEST_F(TileAttachTest, givenStoppedThreadsWhenHandlingAttentionEventThenStoppedT EXPECT_TRUE(tileSessions[1]->triggerEvents); } -TEST_F(TileAttachTest, GivenEventsWithOsEventToAckWhenDetachingTileThenAllEventsAreAcked) { - uint64_t vmBindIsaData[sizeof(prelim_drm_i915_debug_event_vm_bind) / sizeof(uint64_t) + 3 * sizeof(typeOfUUID)]; - prelim_drm_i915_debug_event_vm_bind *vmBindIsa = reinterpret_cast(&vmBindIsaData); - vmBindIsa->base.type = PRELIM_DRM_I915_DEBUG_EVENT_VM_BIND; - vmBindIsa->base.flags = PRELIM_DRM_I915_DEBUG_EVENT_CREATE | PRELIM_DRM_I915_DEBUG_EVENT_NEED_ACK; - vmBindIsa->base.size = sizeof(prelim_drm_i915_debug_event_vm_bind) + 3 * sizeof(typeOfUUID); - vmBindIsa->base.seqno = 10; - vmBindIsa->client_handle = MockDebugSessionLinux::mockClientHandle; - vmBindIsa->va_start = isaGpuVa; - vmBindIsa->va_length = isaSize; - vmBindIsa->vm_handle = vm0; - vmBindIsa->num_uuids = 0; - +TEST_F(TileAttachTest, GivenBlockingOnCpuDetachedTileAndZebinModulesWithEventsToAckWhenDetachingTileThenNoAckIoctlIsCalled) { auto handler = new MockIoctlHandler; rootSession->ioctlHandler.reset(handler); - zet_debug_event_t debugEvent = {}; - debugEvent.type = ZET_DEBUG_EVENT_TYPE_MODULE_LOAD; - debugEvent.info.module.format = ZET_MODULE_DEBUG_INFO_FORMAT_ELF_DWARF; - debugEvent.info.module.load = isaGpuVa; - debugEvent.info.module.moduleBegin = 0; - debugEvent.info.module.moduleEnd = 0; + EXPECT_FALSE(rootSession->blockOnFenceMode); - tileSessions[0]->pushApiEvent(debugEvent, &vmBindIsa->base); + addZebinVmBindEvent(rootSession, vm0, true, true, 0); + addZebinVmBindEvent(rootSession, vm0, true, true, 1); + addZebinVmBindEvent(rootSession, vm1, true, true, 0); - debugEvent.info.module.load = 0x999000; - vmBindIsa->va_start = 0x999000; - tileSessions[0]->pushApiEvent(debugEvent, &vmBindIsa->base); - - debugEvent.info.module.load = 0x12000; - vmBindIsa->va_start = 0x12000; - tileSessions[0]->pushApiEvent(debugEvent, &vmBindIsa->base); - - tileSessions[0]->detachTile(); + EXPECT_EQ(0u, rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[0].size()); EXPECT_EQ(3u, handler->ackCount); - EXPECT_EQ(vmBindIsa->base.seqno, handler->debugEventAcked.seqno); - EXPECT_EQ(vmBindIsa->base.type, handler->debugEventAcked.type); + + handler->ackCount = 0; + tileSessions[0]->detachTile(); + // No ACK called on detach + EXPECT_EQ(0u, handler->ackCount); + EXPECT_EQ(10u, handler->debugEventAcked.seqno); + EXPECT_EQ(uint32_t(PRELIM_DRM_I915_DEBUG_EVENT_VM_BIND), handler->debugEventAcked.type); +} + +TEST_F(TileAttachTest, GivenBlockingOnCpuAttachedTileAndZebinModulesWithEventsToAckWhenDetachingTileThenLastEventIsAcked) { + auto handler = new MockIoctlHandler; + rootSession->ioctlHandler.reset(handler); + + EXPECT_FALSE(rootSession->blockOnFenceMode); + + rootSession->tileSessions[0].second = true; + tileSessions[0]->attachTile(); + + addZebinVmBindEvent(rootSession, vm0, true, true, 0); + addZebinVmBindEvent(rootSession, vm0, true, true, 1); + EXPECT_EQ(1u, tileSessions[0]->apiEvents.size()); + + addZebinVmBindEvent(rootSession, vm1, true, true, 0); + EXPECT_EQ(1u, tileSessions[0]->apiEvents.size()); + EXPECT_EQ(2u, handler->ackCount); + auto ackBeforeDetach = handler->ackCount; + + EXPECT_EQ(1u, rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[0].size()); + tileSessions[0]->detachTile(); + EXPECT_EQ(ackBeforeDetach + 1u, handler->ackCount); + EXPECT_EQ(10u, handler->debugEventAcked.seqno); + EXPECT_EQ(uint32_t(PRELIM_DRM_I915_DEBUG_EVENT_VM_BIND), handler->debugEventAcked.type); } TEST_F(TileAttachTest, GivenTileAttachedAndIsaWithOsEventToAckWhenDetachingTileThenAllEventsAreAcked) { @@ -833,7 +848,137 @@ TEST_F(TileAttachTest, GivenTileAttachedAndIsaWithOsEventToAckWhenDetachingTileT EXPECT_TRUE(isa->moduleLoadEventAck); } -using TileAttachAsyncThreadTest = Test; +TEST_F(TileAttachTest, GivenBlockingOnCpuAndZebinModuleEventWithoutAckWhenHandlingEventThenNoEventsToAckAdded) { + auto handler = new MockIoctlHandler; + rootSession->ioctlHandler.reset(handler); + + EXPECT_FALSE(rootSession->blockOnFenceMode); + + rootSession->tileSessions[0].second = true; + tileSessions[0]->attachTile(); + + addZebinVmBindEvent(rootSession, vm0, false, true, 0); + addZebinVmBindEvent(rootSession, vm0, false, true, 1); + + EXPECT_EQ(1u, tileSessions[0]->apiEvents.size()); + EXPECT_FALSE(ZET_DEBUG_EVENT_FLAG_NEED_ACK & tileSessions[0]->apiEvents.front().flags); + EXPECT_EQ(0u, rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[0].size()); + + EXPECT_EQ(0u, handler->ackCount); +} +using TileAttachBlockOnFenceTest = Test>; + +TEST_F(TileAttachBlockOnFenceTest, GivenBlockingOnFenceDetachedTileAndZebinModulesWithEventsToAckWhenDetachingTileThenNoAckIoctlIsCalled) { + auto handler = new MockIoctlHandler; + rootSession->ioctlHandler.reset(handler); + + EXPECT_TRUE(rootSession->blockOnFenceMode); + + addZebinVmBindEvent(rootSession, vm0, true, true, 0); + addZebinVmBindEvent(rootSession, vm0, true, true, 1); + addZebinVmBindEvent(rootSession, vm1, true, true, 0); + + EXPECT_EQ(0u, rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[0].size()); + EXPECT_EQ(3u, handler->ackCount); + + handler->ackCount = 0; + tileSessions[0]->detachTile(); + // No ACK called on detach + EXPECT_EQ(0u, handler->ackCount); + EXPECT_EQ(uint32_t(PRELIM_DRM_I915_DEBUG_EVENT_VM_BIND), handler->debugEventAcked.type); +} + +TEST_F(TileAttachBlockOnFenceTest, GivenBlockingOnFenceAttachedTileAndZebinModulesWithEventsToAckWhenDetachingTileThenAllEventsAreAcked) { + auto handler = new MockIoctlHandler; + rootSession->ioctlHandler.reset(handler); + + EXPECT_TRUE(rootSession->blockOnFenceMode); + + rootSession->tileSessions[0].second = true; + tileSessions[0]->attachTile(); + + addZebinVmBindEvent(rootSession, vm0, true, true, 0); + addZebinVmBindEvent(rootSession, vm0, true, true, 1); + EXPECT_EQ(1u, tileSessions[0]->apiEvents.size()); + EXPECT_EQ(0u, handler->ackCount); + + addZebinVmBindEvent(rootSession, vm1, true, true, 0); + EXPECT_EQ(1u, tileSessions[0]->apiEvents.size()); + EXPECT_EQ(ZET_DEBUG_EVENT_FLAG_NEED_ACK, tileSessions[0]->apiEvents.front().flags); + EXPECT_EQ(1u, handler->ackCount); + auto ackBeforeDetach = handler->ackCount; + + EXPECT_EQ(2u, rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[0].size()); + EXPECT_EQ(0u, rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[1].size()); + tileSessions[0]->detachTile(); + + EXPECT_EQ(ackBeforeDetach + 2u, handler->ackCount); + EXPECT_EQ(uint32_t(PRELIM_DRM_I915_DEBUG_EVENT_VM_BIND), handler->debugEventAcked.type); +} + +TEST_F(TileAttachBlockOnFenceTest, GivenBlockingOnFenceAttachedTileAndZebinModulesWithEventsToAckWhenModuleLoadEventIsAckedThenAllNewEventsAreAutoAcked) { + auto handler = new MockIoctlHandler; + rootSession->ioctlHandler.reset(handler); + + EXPECT_TRUE(rootSession->blockOnFenceMode); + + rootSession->tileSessions[0].second = true; + tileSessions[0]->attachTile(); + + addZebinVmBindEvent(rootSession, vm0, true, true, 0); + addZebinVmBindEvent(rootSession, vm0, true, true, 1); + EXPECT_EQ(1u, tileSessions[0]->apiEvents.size()); + EXPECT_EQ(0u, handler->ackCount); + + EXPECT_EQ(1u, tileSessions[0]->apiEvents.size()); + EXPECT_EQ(2u, rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[0].size()); + EXPECT_FALSE(rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].moduleLoadEventAcked[0]); + EXPECT_EQ(2, rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].segmentVmBindCounter[0]); + + zet_debug_event_t event = {}; + auto result = zetDebugReadEvent(tileSessions[0]->toHandle(), 0, &event); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(ZET_DEBUG_EVENT_FLAG_NEED_ACK, event.flags); + + result = zetDebugAcknowledgeEvent(tileSessions[0]->toHandle(), &event); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + EXPECT_EQ(2u, handler->ackCount); + EXPECT_EQ(0u, rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[0].size()); + + rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->vmToTile[vm0 + 20] = 0; + + addZebinVmBindEvent(rootSession, vm0 + 20, true, true, 0); + EXPECT_EQ(3u, handler->ackCount); + EXPECT_EQ(3, rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].segmentVmBindCounter[0]); + EXPECT_TRUE(rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].moduleLoadEventAcked[0]); + + EXPECT_EQ(0u, rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].ackEvents[0].size()); +} + +TEST_F(TileAttachBlockOnFenceTest, GivenMultipleVmBindEventsForFirstZebinSegmentWhenHandlingEventThenLoadEventIsNotTriggered) { + auto handler = new MockIoctlHandler; + rootSession->ioctlHandler.reset(handler); + + EXPECT_TRUE(rootSession->blockOnFenceMode); + + rootSession->tileSessions[0].second = true; + tileSessions[0]->attachTile(); + + rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->vmToTile[vm0 + 20] = 0; + + addZebinVmBindEvent(rootSession, vm0, true, true, 0); + addZebinVmBindEvent(rootSession, vm0 + 20, true, true, 0); + EXPECT_EQ(0u, tileSessions[0]->apiEvents.size()); + EXPECT_EQ(2, rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].segmentVmBindCounter[0]); + EXPECT_EQ(1u, rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].loadAddresses[0].size()); + + addZebinVmBindEvent(rootSession, vm0 + 20, true, true, 1); + EXPECT_EQ(1u, tileSessions[0]->apiEvents.size()); + EXPECT_EQ(2u, rootSession->clientHandleToConnection[MockDebugSessionLinux::mockClientHandle]->uuidToModule[zebinModuleUUID].loadAddresses[0].size()); +} + +using TileAttachAsyncThreadTest = Test>; TEST_F(TileAttachAsyncThreadTest, GivenInterruptedThreadsWhenNoAttentionEventIsReadThenThreadUnavailableEventIsGenerated) { rootSession->tileSessions[0].second = true; diff --git a/level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h b/level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h index 3bab7df099..4fa2eb86b3 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h +++ b/level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h @@ -13,7 +13,7 @@ #include "level_zero/tools/source/debug/debug_session_imp.h" namespace L0 { -DebugSession *createDebugSessionHelper(const zet_debug_config_t &config, Device *device, int debugFd); +DebugSession *createDebugSessionHelper(const zet_debug_config_t &config, Device *device, int debugFd, void *params); namespace ult { diff --git a/shared/test/common/libult/linux/drm_mock_prelim_context.cpp b/shared/test/common/libult/linux/drm_mock_prelim_context.cpp index bfece59710..4a9c5790d7 100644 --- a/shared/test/common/libult/linux/drm_mock_prelim_context.cpp +++ b/shared/test/common/libult/linux/drm_mock_prelim_context.cpp @@ -270,6 +270,12 @@ int DrmMockPrelimContext::handlePrelimRequest(DrmIoctl request, void *arg) { case DrmIoctl::DebuggerOpen: { auto debuggerOpen = reinterpret_cast(arg); if (debuggerOpen->pid != 0 && debuggerOpen->events == 0) { + if (debuggerOpen->version != 0) { + return -1; + } + if (debuggerOpenVersion != 0) { + debuggerOpen->version = debuggerOpenVersion; + } return debuggerOpenRetval; } } break; diff --git a/shared/test/common/libult/linux/drm_mock_prelim_context.h b/shared/test/common/libult/linux/drm_mock_prelim_context.h index b1255e745c..e03c39c442 100644 --- a/shared/test/common/libult/linux/drm_mock_prelim_context.h +++ b/shared/test/common/libult/linux/drm_mock_prelim_context.h @@ -146,6 +146,7 @@ struct DrmMockPrelimContext { // Debugger ioctls int debuggerOpenRetval = 10; // debugFd + uint32_t debuggerOpenVersion = 0; int handlePrelimRequest(DrmIoctl request, void *arg); bool handlePrelimQueryItem(void *arg);