feature: Implement thread control and att event handling for xe

Related-To: NEO-9673
Signed-off-by: Jitendra Sharma <jitendra.sharma@intel.com>
This commit is contained in:
Jitendra Sharma
2024-02-19 16:37:23 +00:00
committed by Compute-Runtime-Automation
parent a4ed483238
commit fb73fad6d7
10 changed files with 557 additions and 158 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2023 Intel Corporation
* Copyright (C) 2021-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@@ -168,7 +168,20 @@ class EuThread {
}
bool getPageFault() {
return hasPageFault;
;
}
void setContextHandle(uint64_t contextHandleParam) {
contextHandle = contextHandleParam;
}
void getContextHandle(uint64_t &contextHandleParam) const {
DEBUG_BREAK_IF(state != State::stopped);
contextHandleParam = contextHandle;
}
void setLrcHandle(uint64_t lrcHandleParam) {
lrcHandle = lrcHandleParam;
}
void getLrcHandle(uint64_t &lrcHandleParam) const {
DEBUG_BREAK_IF(state != State::stopped);
lrcHandleParam = lrcHandle;
}
public:
@@ -181,6 +194,8 @@ class EuThread {
std::atomic<uint64_t> memoryHandle = invalidHandle;
std::atomic<bool> reportedAsStopped = false;
bool hasPageFault = false;
uint64_t contextHandle = 0;
uint64_t lrcHandle = 0;
};
static_assert(sizeof(EuThread::ThreadId) == sizeof(uint64_t));

View File

@@ -351,49 +351,6 @@ ze_result_t DebugSessionLinux::writeGpuMemory(uint64_t vmHandle, const char *inp
return (retVal == 0) ? ZE_RESULT_SUCCESS : ZE_RESULT_ERROR_UNKNOWN;
}
int DebugSessionLinux::threadControl(const std::vector<EuThread::ThreadId> &threads, uint32_t tile, ThreadControlCmd threadCmd, std::unique_ptr<uint8_t[]> &bitmaskOut, size_t &bitmaskSizeOut) {
auto hwInfo = connectedDevice->getHwInfo();
auto classInstance = DrmHelper::getEngineInstance(connectedDevice, tile, hwInfo.capabilityTable.defaultEngineType);
UNRECOVERABLE_IF(!classInstance);
auto &l0GfxCoreHelper = connectedDevice->getL0GfxCoreHelper();
bitmaskSizeOut = 0;
std::unique_ptr<uint8_t[]> bitmask;
size_t bitmaskSize = 0;
if (threadCmd == ThreadControlCmd::interrupt ||
threadCmd == ThreadControlCmd::resume ||
threadCmd == ThreadControlCmd::stopped) {
l0GfxCoreHelper.getAttentionBitmaskForSingleThreads(threads, hwInfo, bitmask, bitmaskSize);
}
uint64_t seqnoRet = 0;
uint64_t bitmaskSizeRet = 0;
auto euControlRetVal = euControlIoctl(threadCmd, classInstance, bitmask, bitmaskSize, seqnoRet, bitmaskSizeRet);
if (euControlRetVal != 0) {
PRINT_DEBUGGER_ERROR_LOG("euControl IOCTL failed: retCode: %d errno = %d threadCmd = %d\n", euControlRetVal, errno, threadCmd);
} else {
PRINT_DEBUGGER_INFO_LOG("euControl IOCTL: seqno = %llu threadCmd = %u\n", seqnoRet, threadCmd);
}
if (threadCmd == ThreadControlCmd::interrupt ||
threadCmd == ThreadControlCmd::interruptAll) {
if (euControlRetVal == 0) {
euControlInterruptSeqno[tile] = seqnoRet;
} else {
euControlInterruptSeqno[tile] = invalidHandle;
}
}
if (threadCmd == ThreadControlCmd::stopped) {
bitmaskOut = std::move(bitmask);
bitmaskSizeOut = bitmaskSizeRet;
}
return euControlRetVal;
}
ze_result_t DebugSessionLinux::readElfSpace(const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer,
const char *&elfData, const uint64_t offset) {
@@ -649,7 +606,7 @@ ze_result_t DebugSessionLinux::getElfOffset(const zet_debug_memory_space_desc_t
return status;
}
void DebugSessionLinux::updateStoppedThreadsAndCheckTriggerEvents(AttentionEventFields &attention, uint32_t tileIndex) {
void DebugSessionLinux::updateStoppedThreadsAndCheckTriggerEvents(AttentionEventFields &attention, uint32_t tileIndex, std::vector<EuThread::ThreadId> &threadsWithAttention) {
auto vmHandle = getVmHandleFromClientAndlrcHandle(attention.clientHandle, attention.lrcHandle);
if (vmHandle == invalidHandle) {
return;
@@ -658,16 +615,6 @@ void DebugSessionLinux::updateStoppedThreadsAndCheckTriggerEvents(AttentionEvent
auto hwInfo = connectedDevice->getHwInfo();
auto &l0GfxCoreHelper = connectedDevice->getL0GfxCoreHelper();
std::vector<EuThread::ThreadId> threadsWithAttention;
if (interruptSent) {
std::unique_ptr<uint8_t[]> bitmask;
size_t bitmaskSize;
auto attReadResult = threadControl({}, tileIndex, ThreadControlCmd::stopped, bitmask, bitmaskSize);
if (attReadResult == 0) {
threadsWithAttention = l0GfxCoreHelper.getThreadsFromAttentionBitmask(hwInfo, tileIndex, bitmask.get(), bitmaskSize);
}
}
if (threadsWithAttention.size() == 0) {
threadsWithAttention = l0GfxCoreHelper.getThreadsFromAttentionBitmask(hwInfo, tileIndex, attention.bitmask, attention.bitmaskSize);
printBitmask(attention.bitmask, attention.bitmaskSize);
@@ -705,6 +652,8 @@ void DebugSessionLinux::updateStoppedThreadsAndCheckTriggerEvents(AttentionEvent
if (stateSaveReadResult == ZE_RESULT_SUCCESS) {
for (auto &threadId : threadsWithAttention) {
PRINT_DEBUGGER_THREAD_LOG("ATTENTION event for thread: %s\n", EuThread::toString(threadId).c_str());
allThreads[threadId]->setContextHandle(attention.contextHandle);
allThreads[threadId]->setLrcHandle(attention.lrcHandle);
if (tileSessionsEnabled) {
addThreadToNewlyStoppedFromRaisedAttentionForTileSession(threadId, vmHandle, stateSaveAreaMemory.data(), tileIndex);

View File

@@ -152,7 +152,7 @@ struct DebugSessionLinux : DebugSessionImp {
uint8_t *bitmask;
};
void updateStoppedThreadsAndCheckTriggerEvents(AttentionEventFields &attention, uint32_t tileIndex);
void updateStoppedThreadsAndCheckTriggerEvents(AttentionEventFields &attention, uint32_t tileIndex, std::vector<EuThread::ThreadId> &threadsWithAttention);
virtual uint64_t getVmHandleFromClientAndlrcHandle(uint64_t clientHandle, uint64_t lrcHandle) = 0;
virtual std::unique_lock<std::mutex> getThreadStateMutexForTileSession(uint32_t tileIndex) = 0;
virtual void checkTriggerEventsForAttentionForTileSession(uint32_t tileIndex) = 0;
@@ -161,11 +161,7 @@ struct DebugSessionLinux : DebugSessionImp {
const void *stateSaveArea,
uint32_t tileIndex) = 0;
virtual int euControlIoctl(ThreadControlCmd threadCmd,
const NEO::EngineClassInstance *classInstance,
std::unique_ptr<uint8_t[]> &bitmask,
size_t bitmaskSize, uint64_t &seqnoOut, uint64_t &bitmaskSizeOut) = 0;
MOCKABLE_VIRTUAL int threadControl(const std::vector<EuThread::ThreadId> &threads, uint32_t tile, ThreadControlCmd threadCmd, std::unique_ptr<uint8_t[]> &bitmask, size_t &bitmaskSize);
virtual int threadControl(const std::vector<EuThread::ThreadId> &threads, uint32_t tile, ThreadControlCmd threadCmd, std::unique_ptr<uint8_t[]> &bitmask, size_t &bitmaskSize) = 0;
void checkStoppedThreadsAndGenerateEvents(const std::vector<EuThread::ThreadId> &threads, uint64_t memoryHandle, uint32_t deviceIndex) override;
MOCKABLE_VIRTUAL bool checkForceExceptionBit(uint64_t memoryHandle, EuThread::ThreadId threadId, uint32_t *cr0, const SIP::regset_desc *regDesc);
ze_result_t resumeImp(const std::vector<EuThread::ThreadId> &threads, uint32_t deviceIndex) override;
@@ -190,6 +186,5 @@ struct DebugSessionLinux : DebugSessionImp {
virtual std::vector<uint64_t> getAllMemoryHandles();
std::unique_ptr<IoctlHandler> ioctlHandler;
uint64_t euControlInterruptSeqno[NEO::EngineLimits::maxHandleCount];
};
} // namespace L0

View File

@@ -1101,6 +1101,18 @@ void DebugSessionLinuxi915::handleAttentionEvent(prelim_drm_i915_debug_event_eu_
return;
}
std::vector<EuThread::ThreadId> threadsWithAttention;
auto hwInfo = connectedDevice->getHwInfo();
auto &l0GfxCoreHelper = connectedDevice->getL0GfxCoreHelper();
if (interruptSent) {
std::unique_ptr<uint8_t[]> bitmask;
size_t bitmaskSize;
auto attReadResult = threadControl({}, tileIndex, ThreadControlCmd::stopped, bitmask, bitmaskSize);
if (attReadResult == 0) {
threadsWithAttention = l0GfxCoreHelper.getThreadsFromAttentionBitmask(hwInfo, tileIndex, bitmask.get(), bitmaskSize);
}
}
AttentionEventFields attentionEventFields;
attentionEventFields.bitmask = attention->bitmask;
attentionEventFields.bitmaskSize = attention->bitmask_size;
@@ -1108,7 +1120,7 @@ void DebugSessionLinuxi915::handleAttentionEvent(prelim_drm_i915_debug_event_eu_
attentionEventFields.contextHandle = attention->ctx_handle;
attentionEventFields.lrcHandle = attention->lrc_handle;
return updateStoppedThreadsAndCheckTriggerEvents(attentionEventFields, tileIndex);
return updateStoppedThreadsAndCheckTriggerEvents(attentionEventFields, tileIndex, threadsWithAttention);
}
std::unique_lock<std::mutex> DebugSessionLinuxi915::getThreadStateMutexForTileSession(uint32_t tileIndex) {
@@ -1269,17 +1281,22 @@ uint64_t DebugSessionLinuxi915::extractVaFromUuidString(std::string &uuid) {
return parts[0];
}
int DebugSessionLinuxi915::euControlIoctl(ThreadControlCmd threadCmd,
const NEO::EngineClassInstance *classInstance,
std::unique_ptr<uint8_t[]> &bitmask,
size_t bitmaskSize, uint64_t &seqnoOut, uint64_t &bitmaskSizeOut) {
int DebugSessionLinuxi915::threadControl(const std::vector<EuThread::ThreadId> &threads, uint32_t tile, ThreadControlCmd threadCmd, std::unique_ptr<uint8_t[]> &bitmaskOut, size_t &bitmaskSizeOut) {
auto hwInfo = connectedDevice->getHwInfo();
auto classInstance = DrmHelper::getEngineInstance(connectedDevice, tile, hwInfo.capabilityTable.defaultEngineType);
UNRECOVERABLE_IF(!classInstance);
auto &l0GfxCoreHelper = connectedDevice->getL0GfxCoreHelper();
bitmaskSizeOut = 0;
struct prelim_drm_i915_debug_eu_control euControl = {};
euControl.client_handle = clientHandle;
euControl.ci.engine_class = classInstance->engineClass;
euControl.ci.engine_instance = classInstance->engineInstance;
euControl.bitmask_size = 0;
euControl.bitmask_ptr = 0;
decltype(prelim_drm_i915_debug_eu_control::cmd) command = 0;
switch (threadCmd) {
case ThreadControlCmd::interruptAll:
@@ -1297,8 +1314,17 @@ int DebugSessionLinuxi915::euControlIoctl(ThreadControlCmd threadCmd,
}
euControl.cmd = command;
euControl.bitmask_size = static_cast<uint32_t>(bitmaskSize);
euControl.bitmask_ptr = reinterpret_cast<uint64_t>(bitmask.get());
std::unique_ptr<uint8_t[]> bitmask;
size_t bitmaskSize = 0;
if (command == PRELIM_I915_DEBUG_EU_THREADS_CMD_INTERRUPT ||
command == PRELIM_I915_DEBUG_EU_THREADS_CMD_RESUME ||
command == PRELIM_I915_DEBUG_EU_THREADS_CMD_STOPPED) {
l0GfxCoreHelper.getAttentionBitmaskForSingleThreads(threads, hwInfo, bitmask, bitmaskSize);
euControl.bitmask_size = static_cast<uint32_t>(bitmaskSize);
euControl.bitmask_ptr = reinterpret_cast<uint64_t>(bitmask.get());
}
if (command == PRELIM_I915_DEBUG_EU_THREADS_CMD_RESUME) {
applyResumeWa(bitmask.get(), bitmaskSize);
}
@@ -1306,8 +1332,25 @@ int DebugSessionLinuxi915::euControlIoctl(ThreadControlCmd threadCmd,
printBitmask(bitmask.get(), bitmaskSize);
auto euControlRetVal = ioctl(PRELIM_I915_DEBUG_IOCTL_EU_CONTROL, &euControl);
seqnoOut = euControl.seqno;
bitmaskSizeOut = euControl.bitmask_size;
if (euControlRetVal != 0) {
PRINT_DEBUGGER_ERROR_LOG("PRELIM_I915_DEBUG_IOCTL_EU_CONTROL failed: retCode: %d errno = %d command = %d\n", euControlRetVal, errno, command);
} else {
PRINT_DEBUGGER_INFO_LOG("PRELIM_I915_DEBUG_IOCTL_EU_CONTROL: seqno = %llu command = %u\n", (uint64_t)euControl.seqno, command);
}
if (command == PRELIM_I915_DEBUG_EU_THREADS_CMD_INTERRUPT ||
command == PRELIM_I915_DEBUG_EU_THREADS_CMD_INTERRUPT_ALL) {
if (euControlRetVal == 0) {
euControlInterruptSeqno[tile] = euControl.seqno;
} else {
euControlInterruptSeqno[tile] = invalidHandle;
}
}
if (threadCmd == ThreadControlCmd::stopped) {
bitmaskOut = std::move(bitmask);
bitmaskSizeOut = euControl.bitmask_size;
}
return euControlRetVal;
}

View File

@@ -189,10 +189,7 @@ struct DebugSessionLinuxi915 : DebugSessionLinux {
void readStateSaveAreaHeader() override;
int openVmFd(uint64_t vmHandle, bool readOnly) override;
int euControlIoctl(ThreadControlCmd threadCmd,
const NEO::EngineClassInstance *classInstance,
std::unique_ptr<uint8_t[]> &bitmask,
size_t bitmaskSize, uint64_t &seqnoOut, uint64_t &bitmaskSizeOut) override;
int threadControl(const std::vector<EuThread::ThreadId> &threads, uint32_t tile, ThreadControlCmd threadCmd, std::unique_ptr<uint8_t[]> &bitmask, size_t &bitmaskSize) override;
uint64_t getContextStateSaveAreaGpuVa(uint64_t memoryHandle) override;
size_t getContextStateSaveAreaSize(uint64_t memoryHandle) override;
virtual uint64_t getSbaBufferGpuVa(uint64_t memoryHandle);
@@ -262,6 +259,7 @@ struct DebugSessionLinuxi915 : DebugSessionLinux {
std::atomic<bool> detached{false};
std::unordered_map<uint64_t, uint32_t> uuidL0CommandQueueHandleToDevice;
uint64_t euControlInterruptSeqno[NEO::EngineLimits::maxHandleCount];
void readInternalEventsAsync() override;
bool blockOnFenceMode = false; // false - blocking VM_BIND on CPU - autoack events until last blocking event

View File

@@ -237,6 +237,7 @@ void DebugSessionLinuxXe::handleEvent(drm_xe_eudebug_event *event) {
UNRECOVERABLE_IF(clientHandleToConnection.find(execQueue->client_handle) == clientHandleToConnection.end());
if (!processEntryEventGenerated) {
clientHandle = execQueue->client_handle;
zet_debug_event_t debugEvent = {};
debugEvent.type = ZET_DEBUG_EVENT_TYPE_PROCESS_ENTRY;
pushApiEvent(debugEvent);
@@ -246,7 +247,9 @@ void DebugSessionLinuxXe::handleEvent(drm_xe_eudebug_event *event) {
clientHandleToConnection[execQueue->client_handle]->execQueues[execQueue->exec_queue_handle].vmHandle = execQueue->vm_handle;
clientHandleToConnection[execQueue->client_handle]->execQueues[execQueue->exec_queue_handle].engineClass = execQueue->engine_class;
for (uint16_t idx = 0; idx < execQueue->width; idx++) {
clientHandleToConnection[execQueue->client_handle]->lrcHandleToVmHandle[execQueue->lrc_handle[idx]] = execQueue->vm_handle;
uint64_t lrcHandle = execQueue->lrc_handle[idx];
clientHandleToConnection[execQueue->client_handle]->execQueues[execQueue->exec_queue_handle].lrcHandles.push_back(lrcHandle);
clientHandleToConnection[execQueue->client_handle]->lrcHandleToVmHandle[lrcHandle] = execQueue->vm_handle;
}
}
@@ -278,6 +281,17 @@ void DebugSessionLinuxXe::handleEvent(drm_xe_eudebug_event *event) {
(uint64_t)execQueue->exec_queue_handle, (uint16_t)execQueue->engine_class);
} break;
case DRM_XE_EUDEBUG_EVENT_EU_ATTENTION: {
drm_xe_eudebug_event_eu_attention *attention = reinterpret_cast<drm_xe_eudebug_event_eu_attention *>(event);
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: DRM_XE_EUDEBUG_EVENT_EU_ATTENTION flags = %d, seqno = %llu, len = %lu"
" client_handle = %llu flags = %llu bitmask_size = %lu exec_queue_handle = %llu lrc_handle = %llu\n",
(int)attention->base.flags, (uint64_t)attention->base.seqno, (uint32_t)attention->base.len,
(uint64_t)attention->client_handle, (uint64_t)attention->flags,
(uint32_t)attention->bitmask_size, uint64_t(attention->exec_queue_handle), uint64_t(attention->lrc_handle));
handleAttentionEvent(attention);
} break;
default:
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_READ_EVENT type: UNHANDLED %u flags = %u len = %lu\n", (uint16_t)event->type, (uint16_t)event->flags, (uint32_t)event->len);
break;
@@ -317,43 +331,111 @@ uint64_t DebugSessionLinuxXe::getVmHandleFromClientAndlrcHandle(uint64_t clientH
return clientConnection->lrcHandleToVmHandle[lrcHandle];
}
int DebugSessionLinuxXe::euControlIoctl(ThreadControlCmd threadCmd,
const NEO::EngineClassInstance *classInstance,
std::unique_ptr<uint8_t[]> &bitmask,
size_t bitmaskSize, uint64_t &seqnoOut, uint64_t &bitmaskSizeOut) {
struct drm_xe_eudebug_eu_control euControl = {};
euControl.client_handle = clientHandle;
euControl.ci.engine_class = classInstance->engineClass;
euControl.ci.engine_instance = classInstance->engineInstance;
euControl.bitmask_size = 0;
euControl.bitmask_ptr = 0;
decltype(drm_xe_eudebug_eu_control::cmd) command = 0;
switch (threadCmd) {
case ThreadControlCmd::interruptAll:
command = DRM_XE_EUDEBUG_EU_CONTROL_CMD_INTERRUPT_ALL;
break;
case ThreadControlCmd::resume:
command = DRM_XE_EUDEBUG_EU_CONTROL_CMD_RESUME;
break;
case ThreadControlCmd::stopped:
command = DRM_XE_EUDEBUG_EU_CONTROL_CMD_STOPPED;
break;
default:
command = 0xFFFFFFFF;
break;
void DebugSessionLinuxXe::handleAttentionEvent(drm_xe_eudebug_event_eu_attention *attention) {
if (interruptSent) {
if (attention->base.seqno <= euControlInterruptSeqno) {
PRINT_DEBUGGER_INFO_LOG("Discarding EU ATTENTION event for interrupt request. Event seqno == %llu <= %llu == interrupt seqno\n",
static_cast<uint64_t>(attention->base.seqno), euControlInterruptSeqno);
return;
}
}
euControl.cmd = command;
euControl.bitmask_size = static_cast<uint32_t>(bitmaskSize);
euControl.bitmask_ptr = reinterpret_cast<uint64_t>(bitmask.get());
newAttentionRaised();
std::vector<EuThread::ThreadId> threadsWithAttention;
AttentionEventFields attentionEventFields;
attentionEventFields.bitmask = attention->bitmask;
attentionEventFields.bitmaskSize = attention->bitmask_size;
attentionEventFields.clientHandle = attention->client_handle;
attentionEventFields.contextHandle = attention->exec_queue_handle;
attentionEventFields.lrcHandle = attention->lrc_handle;
printBitmask(bitmask.get(), bitmaskSize);
return updateStoppedThreadsAndCheckTriggerEvents(attentionEventFields, 0, threadsWithAttention);
}
int DebugSessionLinuxXe::threadControlInterruptAll(drm_xe_eudebug_eu_control &euControl) {
int euControlRetVal = -1;
DEBUG_BREAK_IF(clientHandleToConnection.find(clientHandle) == clientHandleToConnection.end());
for (const auto &execQueue : clientHandleToConnection[clientHandle]->execQueues) {
euControl.exec_queue_handle = execQueue.first;
for (const auto &lrcHandle : execQueue.second.lrcHandles) {
euControl.lrc_handle = lrcHandle;
euControlRetVal = ioctl(DRM_XE_EUDEBUG_IOCTL_EU_CONTROL, &euControl);
if (euControlRetVal != 0) {
PRINT_DEBUGGER_ERROR_LOG("DRM_XE_EUDEBUG_IOCTL_EU_CONTROL failed: retCode: %d errno = %d command = %d, execQueueHandle = %llu lrcHandle = %llu\n",
euControlRetVal, errno, static_cast<uint32_t>(euControl.cmd), static_cast<uint64_t>(euControl.exec_queue_handle),
static_cast<uint64_t>(euControl.lrc_handle));
} else {
DEBUG_BREAK_IF(euControlInterruptSeqno >= euControl.seqno);
euControlInterruptSeqno = euControl.seqno;
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_EU_CONTROL: seqno = %llu command = %u\n", static_cast<uint64_t>(euControl.seqno),
static_cast<uint32_t>(euControl.cmd));
}
}
}
auto euControlRetVal = ioctl(DRM_XE_EUDEBUG_IOCTL_EU_CONTROL, &euControl);
seqnoOut = euControl.seqno;
bitmaskSizeOut = euControl.bitmask_size;
return euControlRetVal;
}
int DebugSessionLinuxXe::threadControlResumeAndStopped(const std::vector<EuThread::ThreadId> &threads, drm_xe_eudebug_eu_control &euControl,
std::unique_ptr<uint8_t[]> &bitmaskOut, size_t &bitmaskSizeOut) {
int euControlRetVal = -1;
auto hwInfo = connectedDevice->getHwInfo();
auto &l0GfxCoreHelper = connectedDevice->getL0GfxCoreHelper();
std::unique_ptr<uint8_t[]> bitmask;
size_t bitmaskSize = 0;
l0GfxCoreHelper.getAttentionBitmaskForSingleThreads(threads, hwInfo, bitmask, bitmaskSize);
euControl.bitmask_size = static_cast<uint32_t>(bitmaskSize);
euControl.bitmask_ptr = reinterpret_cast<uint64_t>(bitmask.get());
printBitmask(bitmask.get(), bitmaskSize);
uint64_t execQueueHandle{0};
uint64_t lrcHandle{0};
allThreads[threads[0]]->getContextHandle(execQueueHandle);
allThreads[threads[0]]->getLrcHandle(lrcHandle);
euControl.exec_queue_handle = execQueueHandle;
euControl.lrc_handle = lrcHandle;
euControlRetVal = ioctl(DRM_XE_EUDEBUG_IOCTL_EU_CONTROL, &euControl);
if (euControlRetVal != 0) {
PRINT_DEBUGGER_ERROR_LOG("DRM_XE_EUDEBUG_IOCTL_EU_CONTROL failed: retCode: %d errno = %d command = %d, execQueueHandle = %llu lrcHandle = %llu\n",
euControlRetVal, errno, static_cast<uint32_t>(euControl.cmd), static_cast<uint64_t>(euControl.exec_queue_handle),
static_cast<uint64_t>(euControl.lrc_handle));
} else {
PRINT_DEBUGGER_INFO_LOG("DRM_XE_EUDEBUG_IOCTL_EU_CONTROL: seqno = %llu command = %u\n", static_cast<uint64_t>(euControl.seqno), static_cast<uint32_t>(euControl.cmd));
}
if (euControl.cmd == DRM_XE_EUDEBUG_EU_CONTROL_CMD_STOPPED) {
bitmaskOut = std::move(bitmask);
bitmaskSizeOut = euControl.bitmask_size;
}
return euControlRetVal;
}
int DebugSessionLinuxXe::threadControl(const std::vector<EuThread::ThreadId> &threads, uint32_t tile,
ThreadControlCmd threadCmd, std::unique_ptr<uint8_t[]> &bitmaskOut, size_t &bitmaskSizeOut) {
bitmaskSizeOut = 0;
struct drm_xe_eudebug_eu_control euControl = {};
euControl.client_handle = clientHandle;
euControl.bitmask_size = 0;
euControl.bitmask_ptr = 0;
switch (threadCmd) {
case ThreadControlCmd::interruptAll:
euControl.cmd = DRM_XE_EUDEBUG_EU_CONTROL_CMD_INTERRUPT_ALL;
return threadControlInterruptAll(euControl);
case ThreadControlCmd::resume:
euControl.cmd = DRM_XE_EUDEBUG_EU_CONTROL_CMD_RESUME;
return threadControlResumeAndStopped(threads, euControl, bitmaskOut, bitmaskSizeOut);
case ThreadControlCmd::stopped:
euControl.cmd = DRM_XE_EUDEBUG_EU_CONTROL_CMD_STOPPED;
return threadControlResumeAndStopped(threads, euControl, bitmaskOut, bitmaskSizeOut);
default:
break;
}
return -1;
}
} // namespace L0

View File

@@ -64,18 +64,13 @@ struct DebugSessionLinuxXe : DebugSessionLinux {
}
};
using ContextHandle = uint64_t;
using ExecQueueHandle = uint64_t;
struct ContextParams {
ContextHandle handle = 0;
uint64_t vm = UINT64_MAX;
std::vector<drm_xe_engine_class_instance> engines;
};
using LrcHandle = uint64_t;
struct ExecQueueParams {
uint64_t vmHandle = 0;
uint16_t engineClass = UINT16_MAX;
std::vector<LrcHandle> lrcHandles;
};
uint32_t xeDebuggerVersion = 0;
@@ -85,10 +80,10 @@ struct DebugSessionLinuxXe : DebugSessionLinux {
};
protected:
int euControlIoctl(ThreadControlCmd threadCmd,
const NEO::EngineClassInstance *classInstance,
std::unique_ptr<uint8_t[]> &bitmask,
size_t bitmaskSize, uint64_t &seqnoOut, uint64_t &bitmaskSizeOut) override;
int threadControl(const std::vector<EuThread::ThreadId> &threads, uint32_t tile, ThreadControlCmd threadCmd, std::unique_ptr<uint8_t[]> &bitmask, size_t &bitmaskSize) override;
int threadControlInterruptAll(drm_xe_eudebug_eu_control &euControl);
int threadControlResumeAndStopped(const std::vector<EuThread::ThreadId> &threads, drm_xe_eudebug_eu_control &euControl, std::unique_ptr<uint8_t[]> &bitmaskOut, size_t &bitmaskSizeOut);
void handleAttentionEvent(drm_xe_eudebug_event_eu_attention *attention);
void startAsyncThread() override;
static void *asyncThreadFunction(void *arg);
@@ -172,6 +167,8 @@ struct DebugSessionLinuxXe : DebugSessionLinux {
const void *stateSaveArea,
uint32_t tileIndex) override {}
uint64_t euControlInterruptSeqno = 0;
ze_result_t readEventImp(drm_xe_eudebug_event *drmDebugEvent);
int ioctl(unsigned long request, void *arg);
std::atomic<bool> processEntryEventGenerated = false;

View File

@@ -68,12 +68,16 @@ struct MockIoctlHandlerXe : public L0::ult::MockIoctlHandler {
debugEventRetVal = -1;
}
return debugEventRetVal;
} else if ((request == DRM_XE_EUDEBUG_IOCTL_VM_OPEN) && (arg != nullptr)) {
drm_xe_eudebug_vm_open *vmOpenIn = reinterpret_cast<drm_xe_eudebug_vm_open *>(arg);
vmOpen = *vmOpenIn;
return vmOpenRetVal;
} else if ((request == DRM_XE_EUDEBUG_IOCTL_EU_CONTROL) && (arg != nullptr)) {
drm_xe_eudebug_eu_control *euControlArg = reinterpret_cast<drm_xe_eudebug_eu_control *>(arg);
EuControlArg arg;
arg.euControl = *euControlArg;
euControlArg->seqno = euControlOutputSeqno;
euControlArg->seqno = ++euControlOutputSeqno;
if (euControlArg->bitmask_size != 0) {
arg.euControlBitmaskSize = euControlArg->bitmask_size;
@@ -110,6 +114,7 @@ struct MockIoctlHandlerXe : public L0::ult::MockIoctlHandler {
};
drm_xe_eudebug_event debugEventInput = {};
drm_xe_eudebug_vm_open vmOpen = {};
int ioctlRetVal = 0;
int debugEventRetVal = 0;
@@ -117,16 +122,18 @@ struct MockIoctlHandlerXe : public L0::ult::MockIoctlHandler {
int fsyncCalled = 0;
int fsyncRetVal = 0;
int numFsyncToSucceed = 100;
uint64_t euControlOutputSeqno = 10;
uint64_t euControlOutputSeqno = 0;
std::vector<EuControlArg> euControlArgs;
std::unique_ptr<uint8_t[]> outputBitmask;
size_t outputBitmaskSize = 0;
int vmOpenRetVal = 600;
};
struct MockDebugSessionLinuxXe : public L0::DebugSessionLinuxXe {
using L0::DebugSessionImp::allThreads;
using L0::DebugSessionImp::apiEvents;
using L0::DebugSessionImp::expectedAttentionEvents;
using L0::DebugSessionImp::interruptSent;
using L0::DebugSessionImp::stateSaveAreaHeader;
using L0::DebugSessionImp::triggerEvents;
using L0::DebugSessionLinux::getClientConnection;
@@ -135,6 +142,7 @@ struct MockDebugSessionLinuxXe : public L0::DebugSessionLinuxXe {
using L0::DebugSessionLinuxXe::asyncThreadFunction;
using L0::DebugSessionLinuxXe::checkStoppedThreadsAndGenerateEvents;
using L0::DebugSessionLinuxXe::checkTriggerEventsForAttentionForTileSession;
using L0::DebugSessionLinuxXe::ClientConnectionXe;
using L0::DebugSessionLinuxXe::clientHandleClosed;
using L0::DebugSessionLinuxXe::clientHandleToConnection;
using L0::DebugSessionLinuxXe::euControlInterruptSeqno;
@@ -146,6 +154,7 @@ struct MockDebugSessionLinuxXe : public L0::DebugSessionLinuxXe {
using L0::DebugSessionLinuxXe::invalidClientHandle;
using L0::DebugSessionLinuxXe::ioctlHandler;
using L0::DebugSessionLinuxXe::newlyStoppedThreads;
using L0::DebugSessionLinuxXe::pendingInterrupts;
using L0::DebugSessionLinuxXe::readEventImp;
using L0::DebugSessionLinuxXe::readInternalEventsAsync;
using L0::DebugSessionLinuxXe::startAsyncThread;
@@ -189,6 +198,48 @@ struct MockDebugSessionLinuxXe : public L0::DebugSessionLinuxXe {
return DebugSessionLinuxXe::getInternalEvent();
}
bool readSystemRoutineIdentFromMemory(EuThread *thread, const void *stateSaveArea, SIP::sr_ident &srIdent) override {
readSystemRoutineIdentFromMemoryCallCount++;
srIdent.count = 0;
if (stoppedThreads.size()) {
auto entry = stoppedThreads.find(thread->getThreadId());
if (entry != stoppedThreads.end()) {
srIdent.count = entry->second;
}
return true;
}
return L0::DebugSessionImp::readSystemRoutineIdentFromMemory(thread, stateSaveArea, srIdent);
}
void addThreadToNewlyStoppedFromRaisedAttention(EuThread::ThreadId threadId, uint64_t memoryHandle, const void *stateSaveArea) override {
addThreadToNewlyStoppedFromRaisedAttentionCallCount++;
return DebugSessionImp::addThreadToNewlyStoppedFromRaisedAttention(threadId, memoryHandle, stateSaveArea);
}
bool readSystemRoutineIdent(EuThread *thread, uint64_t vmHandle, SIP::sr_ident &srIdent) override {
readSystemRoutineIdentCallCount++;
srIdent.count = 0;
if (stoppedThreads.size()) {
auto entry = stoppedThreads.find(thread->getThreadId());
if (entry != stoppedThreads.end()) {
srIdent.count = entry->second;
}
return true;
}
return L0::DebugSessionImp::readSystemRoutineIdent(thread, vmHandle, srIdent);
}
uint64_t getContextStateSaveAreaGpuVa(uint64_t memoryHandle) override {
return 0x1000;
}
size_t getContextStateSaveAreaSize(uint64_t memoryHandle) override {
return 0x1000;
}
uint32_t readSystemRoutineIdentCallCount = 0;
uint32_t addThreadToNewlyStoppedFromRaisedAttentionCallCount = 0;
uint32_t readSystemRoutineIdentFromMemoryCallCount = 0;
size_t numThreadsPassedToThreadControl = 0;
bool synchronousInternalEventRead = false;
std::atomic<int> getInternalEventCounter = 0;

View File

@@ -960,7 +960,7 @@ TEST_F(DebugApiLinuxTestXe, WhenCallingReadOrWriteGpuMemoryAndFsyncFailsThenErro
EXPECT_EQ(handler->fsyncCalled, 6);
}
TEST_F(DebugApiLinuxTestXe, WhenCallingThreadControlForInterruptThenProperIoctlsIsCalled) {
TEST_F(DebugApiLinuxTestXe, WhenCallingThreadControlForInterruptOrAnyInvalidThreadControlCmdThenErrorIsReturned) {
zet_debug_config_t config = {};
config.pid = 0x1234;
@@ -975,35 +975,56 @@ TEST_F(DebugApiLinuxTestXe, WhenCallingThreadControlForInterruptThenProperIoctls
size_t bitmaskSizeOut = 0;
auto result = sessionMock->threadControl(threads, 0, MockDebugSessionLinuxXe::ThreadControlCmd::interrupt, bitmaskOut, bitmaskSizeOut);
EXPECT_EQ(result, ZE_RESULT_SUCCESS);
EXPECT_EQ(1, handler->ioctlCalled);
EXPECT_EQ(0xFFFFFFFF, handler->euControlArgs[0].euControl.cmd);
EXPECT_NE(0u, handler->euControlArgs[0].euControl.bitmask_size);
auto bitMaskPtrToCheck = handler->euControlArgs[0].euControl.bitmask_ptr;
EXPECT_NE(0u, bitMaskPtrToCheck);
EXPECT_EQ(handler->euControlOutputSeqno, sessionMock->euControlInterruptSeqno[0]);
EXPECT_EQ(0u, bitmaskSizeOut);
EXPECT_EQ(nullptr, bitmaskOut.get());
handler->euControlOutputSeqno = handler->euControlOutputSeqno + 3;
handler->ioctlCalled = 0;
result = sessionMock->threadControl(threads, 0, MockDebugSessionLinuxXe::ThreadControlCmd::interruptAll, bitmaskOut, bitmaskSizeOut);
EXPECT_EQ(result, ZE_RESULT_SUCCESS);
EXPECT_EQ(1, handler->ioctlCalled);
EXPECT_EQ(uint32_t(DRM_XE_EUDEBUG_EU_CONTROL_CMD_INTERRUPT_ALL), handler->euControlArgs[1].euControl.cmd);
EXPECT_EQ(0u, handler->euControlArgs[1].euControl.bitmask_size);
auto bitMaskPtrToCheck1 = handler->euControlArgs[1].euControl.bitmask_ptr;
EXPECT_EQ(0u, bitMaskPtrToCheck1);
EXPECT_EQ(handler->euControlOutputSeqno, sessionMock->euControlInterruptSeqno[0]);
EXPECT_EQ(0u, bitmaskSizeOut);
EXPECT_EQ(nullptr, bitmaskOut.get());
EXPECT_EQ(result, -1);
}
TEST_F(DebugApiLinuxTestXe, GivenErrorFromIoctlWhenCallingThreadControlForInterruptThenSeqnoIsNotUpdated) {
TEST_F(DebugApiLinuxTestXe, GivenErrorFromIoctlWhenCallingThreadControlThenThreadControlCallFails) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto sessionMock = std::make_unique<MockDebugSessionLinuxXe>(config, device, 10);
ASSERT_NE(nullptr, sessionMock);
auto handler = new MockIoctlHandlerXe;
sessionMock->ioctlHandler.reset(handler);
EuThread::ThreadId thread = {0, 0, 0, 0, 0};
EuThread::ThreadId thread1 = {0, 0, 0, 0, 1};
const auto memoryHandle = 1u;
sessionMock->allThreads[thread.packed]->stopThread(memoryHandle);
sessionMock->allThreads[thread.packed]->reportAsStopped();
std::vector<EuThread::ThreadId> threads;
threads.push_back(thread);
threads.push_back(thread1);
std::unique_ptr<uint8_t[]> bitmaskOut;
size_t bitmaskSizeOut = 0;
handler->ioctlRetVal = -1;
sessionMock->clientHandleToConnection[sessionMock->clientHandle].reset(new MockDebugSessionLinuxXe::ClientConnectionXe);
sessionMock->clientHandleToConnection[sessionMock->clientHandle]->execQueues[100].lrcHandles.push_back(10000);
sessionMock->clientHandleToConnection[sessionMock->clientHandle]->execQueues[100].lrcHandles.push_back(10001);
sessionMock->clientHandleToConnection[sessionMock->clientHandle]->execQueues[101].lrcHandles.push_back(11000);
sessionMock->clientHandleToConnection[sessionMock->clientHandle]->execQueues[101].lrcHandles.push_back(11001);
auto result = sessionMock->threadControl(threads, 0, MockDebugSessionLinuxXe::ThreadControlCmd::interruptAll, bitmaskOut, bitmaskSizeOut);
EXPECT_NE(0, result);
EXPECT_EQ(4, handler->ioctlCalled);
result = sessionMock->threadControl(threads, 0, MockDebugSessionLinuxXe::ThreadControlCmd::resume, bitmaskOut, bitmaskSizeOut);
EXPECT_NE(0, result);
EXPECT_EQ(5, handler->ioctlCalled);
result = sessionMock->threadControl(threads, 0, MockDebugSessionLinuxXe::ThreadControlCmd::stopped, bitmaskOut, bitmaskSizeOut);
EXPECT_NE(0, result);
EXPECT_EQ(6, handler->ioctlCalled);
}
TEST_F(DebugApiLinuxTestXe, GivenSuccessFromIoctlWhenCallingThreadControlForInterruptAllThenSequenceNumbersProperlyUpdates) {
zet_debug_config_t config = {};
config.pid = 0x1234;
@@ -1017,14 +1038,26 @@ TEST_F(DebugApiLinuxTestXe, GivenErrorFromIoctlWhenCallingThreadControlForInterr
std::unique_ptr<uint8_t[]> bitmaskOut;
size_t bitmaskSizeOut = 0;
handler->ioctlRetVal = -1;
sessionMock->clientHandleToConnection[sessionMock->clientHandle].reset(new MockDebugSessionLinuxXe::ClientConnectionXe);
sessionMock->clientHandleToConnection[sessionMock->clientHandle]->execQueues[100].lrcHandles.push_back(10000);
sessionMock->clientHandleToConnection[sessionMock->clientHandle]->execQueues[100].lrcHandles.push_back(10001);
// Invoke first threadControl IOCTL for above two lrc Handles created above.
auto result = sessionMock->threadControl(threads, 0, MockDebugSessionLinuxXe::ThreadControlCmd::interruptAll, bitmaskOut, bitmaskSizeOut);
EXPECT_NE(0, result);
EXPECT_EQ(0, result);
EXPECT_EQ(2, handler->ioctlCalled);
EXPECT_EQ(2ul, sessionMock->euControlInterruptSeqno);
EXPECT_EQ(1, handler->ioctlCalled);
EXPECT_EQ(uint32_t(DRM_XE_EUDEBUG_EU_CONTROL_CMD_INTERRUPT_ALL), handler->euControlArgs[0].euControl.cmd);
EXPECT_NE(handler->euControlOutputSeqno, sessionMock->euControlInterruptSeqno[0]);
sessionMock->clientHandleToConnection[sessionMock->clientHandle]->execQueues[101].lrcHandles.push_back(11000);
sessionMock->clientHandleToConnection[sessionMock->clientHandle]->execQueues[101].lrcHandles.push_back(11001);
// Invoke second threadControl IOCTL for total 4 lrc Handles created above.
// Total called IOCTL count would be 4 for second threadControl invoked below + 2 for above first threadControl method.
result = sessionMock->threadControl(threads, 0, MockDebugSessionLinuxXe::ThreadControlCmd::interruptAll, bitmaskOut, bitmaskSizeOut);
EXPECT_EQ(0, result);
EXPECT_EQ(6, handler->ioctlCalled);
EXPECT_EQ(handler->euControlOutputSeqno, 6u);
}
TEST_F(DebugApiLinuxTestXe, WhenCallingThreadControlForResumeThenProperIoctlsIsCalled) {
@@ -1036,7 +1069,21 @@ TEST_F(DebugApiLinuxTestXe, WhenCallingThreadControlForResumeThenProperIoctlsIsC
auto handler = new MockIoctlHandlerXe;
sessionMock->ioctlHandler.reset(handler);
std::vector<EuThread::ThreadId> threads({});
EuThread::ThreadId thread = {0, 0, 0, 0, 0};
EuThread::ThreadId thread1 = {0, 0, 0, 0, 1};
const auto memoryHandle = 1u;
sessionMock->allThreads[thread.packed]->stopThread(memoryHandle);
sessionMock->allThreads[thread.packed]->reportAsStopped();
std::vector<EuThread::ThreadId> threads;
threads.push_back(thread);
threads.push_back(thread1);
for (auto thread : threads) {
sessionMock->stoppedThreads[thread.packed] = 3;
}
std::unique_ptr<uint8_t[]> bitmaskOut;
size_t bitmaskSizeOut = 0;
@@ -1103,6 +1150,227 @@ TEST_F(DebugApiLinuxTestXe, GivenNoAttentionBitsWhenMultipleThreadsPassedToCheck
EXPECT_EQ(0u, sessionMock->apiEvents.size());
}
TEST_F(DebugApiLinuxTestXe, GivenEventSeqnoLowerEqualThanSentInterruptWhenHandlingAttentionEventThenEventIsNotProcessed) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto sessionMock = std::make_unique<MockDebugSessionLinuxXe>(config, device, 10);
ASSERT_NE(nullptr, sessionMock);
sessionMock->clientHandle = MockDebugSessionLinuxXe::mockClientHandle;
uint8_t data[sizeof(drm_xe_eudebug_event_eu_attention) + 128];
std::unique_ptr<uint8_t[]> bitmask;
size_t bitmaskSize = 0;
auto &hwInfo = neoDevice->getHardwareInfo();
auto &l0GfxCoreHelper = neoDevice->getRootDeviceEnvironment().getHelper<L0GfxCoreHelper>();
std::vector<EuThread::ThreadId> threads{
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 1},
};
constexpr uint64_t contextHandle0 = 100ul;
constexpr uint64_t lrcHandle0 = 1000ul;
sessionMock->allThreads[threads[0]]->setContextHandle(contextHandle0);
sessionMock->allThreads[threads[0]]->setLrcHandle(lrcHandle0);
constexpr uint64_t contextHandle1 = 100ul;
constexpr uint64_t lrcHandle1 = 1001ul;
sessionMock->allThreads[threads[0]]->setContextHandle(contextHandle1);
sessionMock->allThreads[threads[0]]->setLrcHandle(lrcHandle1);
l0GfxCoreHelper.getAttentionBitmaskForSingleThreads(threads, hwInfo, bitmask, bitmaskSize);
ze_device_thread_t thread = {0, 0, 0, UINT32_MAX};
sessionMock->pendingInterrupts.push_back(std::pair<ze_device_thread_t, bool>(thread, false));
sessionMock->interruptSent = true;
sessionMock->euControlInterruptSeqno = 3;
// Validate for case when event seq number is equal than euControlInterruptSeqno
drm_xe_eudebug_event_eu_attention attention = {};
attention.base.type = DRM_XE_EUDEBUG_EVENT_EU_ATTENTION;
attention.base.flags = DRM_XE_EUDEBUG_EVENT_STATE_CHANGE;
attention.base.seqno = 3;
attention.base.len = sizeof(drm_xe_eudebug_event_eu_attention) + std::min(uint32_t(128), static_cast<uint32_t>(bitmaskSize));
attention.client_handle = MockDebugSessionLinuxXe::mockClientHandle;
attention.flags = 0;
attention.exec_queue_handle = contextHandle0;
attention.lrc_handle = lrcHandle0;
attention.bitmask_size = std::min(uint32_t(128), static_cast<uint32_t>(bitmaskSize));
memcpy(data, &attention, sizeof(drm_xe_eudebug_event_eu_attention));
memcpy(ptrOffset(data, offsetof(drm_xe_eudebug_event_eu_attention, bitmask)), bitmask.get(), std::min(size_t(128), bitmaskSize));
sessionMock->handleEvent(reinterpret_cast<drm_xe_eudebug_event *>(data));
EXPECT_EQ(0u, sessionMock->newlyStoppedThreads.size());
EXPECT_EQ(1u, sessionMock->pendingInterrupts.size());
EXPECT_FALSE(sessionMock->pendingInterrupts[0].second);
EXPECT_FALSE(sessionMock->triggerEvents);
// Validate for case when event seq number is less than euControlInterruptSeqno
attention.base.seqno = 2;
memcpy(data, &attention, sizeof(drm_xe_eudebug_event_eu_attention));
memcpy(ptrOffset(data, offsetof(drm_xe_eudebug_event_eu_attention, bitmask)), bitmask.get(), std::min(size_t(128), bitmaskSize));
sessionMock->handleEvent(reinterpret_cast<drm_xe_eudebug_event *>(data));
EXPECT_EQ(0u, sessionMock->newlyStoppedThreads.size());
EXPECT_EQ(1u, sessionMock->pendingInterrupts.size());
EXPECT_FALSE(sessionMock->pendingInterrupts[0].second);
EXPECT_FALSE(sessionMock->triggerEvents);
}
TEST_F(DebugApiLinuxTestXe, GivenLrcHandleEntryNotFoundInLrcToVmHandleMapWhenHandlingAttentionEventThenEventIsNotProcessed) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto sessionMock = std::make_unique<MockDebugSessionLinuxXe>(config, device, 10);
ASSERT_NE(nullptr, sessionMock);
sessionMock->clientHandle = MockDebugSessionLinuxXe::mockClientHandle;
uint64_t execQueueHandle = 2;
uint64_t lrcHandle = 8;
sessionMock->clientHandleToConnection[MockDebugSessionLinuxXe::mockClientHandle]->lrcHandleToVmHandle[10] = 20ul;
drm_xe_eudebug_event_eu_attention attention = {};
attention.base.type = DRM_XE_EUDEBUG_EVENT_EU_ATTENTION;
attention.base.len = sizeof(drm_xe_eudebug_event_eu_attention);
attention.base.seqno = 2;
attention.client_handle = MockDebugSessionLinuxXe::mockClientHandle;
attention.lrc_handle = lrcHandle;
attention.flags = 0;
attention.lrc_handle = lrcHandle;
attention.exec_queue_handle = execQueueHandle;
attention.bitmask_size = 0;
sessionMock->handleEvent(&attention.base);
EXPECT_EQ(0u, sessionMock->newlyStoppedThreads.size());
EXPECT_EQ(0u, sessionMock->pendingInterrupts.size());
EXPECT_FALSE(sessionMock->triggerEvents);
}
TEST_F(DebugApiLinuxTestXe, GivenSentInterruptWhenHandlingAttEventThenAttBitsAreSynchronouslyScannedAgainAndAllNewThreadsChecked) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto sessionMock = std::make_unique<MockDebugSessionLinuxXe>(config, device, 10);
ASSERT_NE(nullptr, sessionMock);
sessionMock->clientHandle = MockDebugSessionLinuxXe::mockClientHandle;
auto handler = new MockIoctlHandlerXe;
sessionMock->ioctlHandler.reset(handler);
SIP::version version = {2, 0, 0};
initStateSaveArea(sessionMock->stateSaveAreaHeader, version, device);
handler->setPreadMemory(sessionMock->stateSaveAreaHeader.data(), sessionMock->stateSaveAreaHeader.size(), 0x1000);
uint64_t execQueueHandle = 2;
uint64_t vmHandle = 7;
uint64_t lrcHandle = 8;
sessionMock->clientHandleToConnection[MockDebugSessionLinuxXe::mockClientHandle]->lrcHandleToVmHandle[lrcHandle] = vmHandle;
uint8_t data[sizeof(drm_xe_eudebug_event_eu_attention) + 128];
auto &hwInfo = neoDevice->getHardwareInfo();
auto &l0GfxCoreHelper = neoDevice->getRootDeviceEnvironment().getHelper<L0GfxCoreHelper>();
std::unique_ptr<uint8_t[]> bitmask;
size_t bitmaskSize = 0;
std::vector<EuThread::ThreadId> threads{
{0, 0, 0, 0, 0}, {0, 0, 0, 0, 2}};
sessionMock->allThreads[threads[0]]->setContextHandle(execQueueHandle);
sessionMock->allThreads[threads[0]]->setLrcHandle(lrcHandle);
sessionMock->allThreads[threads[1]]->setContextHandle(execQueueHandle);
sessionMock->allThreads[threads[1]]->setLrcHandle(lrcHandle);
sessionMock->stoppedThreads[threads[0].packed] = 1;
sessionMock->stoppedThreads[threads[1].packed] = 1;
// bitmask returned from ATT scan - both threads
l0GfxCoreHelper.getAttentionBitmaskForSingleThreads(threads, hwInfo, handler->outputBitmask, handler->outputBitmaskSize);
// bitmask returned in ATT event - only one thread
l0GfxCoreHelper.getAttentionBitmaskForSingleThreads({threads[0]}, hwInfo, bitmask, bitmaskSize);
ze_device_thread_t thread = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
sessionMock->pendingInterrupts.push_back(std::pair<ze_device_thread_t, bool>(thread, false));
sessionMock->interruptSent = true;
sessionMock->euControlInterruptSeqno = 1;
drm_xe_eudebug_event_eu_attention attention = {};
attention.base.type = DRM_XE_EUDEBUG_EVENT_EU_ATTENTION;
attention.base.flags = DRM_XE_EUDEBUG_EVENT_STATE_CHANGE;
attention.base.len = sizeof(drm_xe_eudebug_event_eu_attention) + std::min(uint32_t(128), static_cast<uint32_t>(bitmaskSize));
attention.base.seqno = 2;
attention.client_handle = MockDebugSessionLinuxXe::mockClientHandle;
attention.lrc_handle = lrcHandle;
attention.flags = 0;
attention.exec_queue_handle = execQueueHandle;
attention.bitmask_size = std::min(uint32_t(128), static_cast<uint32_t>(bitmaskSize));
memcpy(data, &attention, sizeof(drm_xe_eudebug_event_eu_attention));
memcpy(ptrOffset(data, offsetof(drm_xe_eudebug_event_eu_attention, bitmask)), bitmask.get(), std::min(size_t(128), bitmaskSize));
sessionMock->handleEvent(reinterpret_cast<drm_xe_eudebug_event *>(data));
EXPECT_EQ(1u, sessionMock->newlyStoppedThreads.size());
auto expectedThreadsToCheck = (hwInfo.capabilityTable.fusedEuEnabled && hwInfo.gtSystemInfo.MaxEuPerSubSlice != 8) ? 2u : 1u;
EXPECT_EQ(expectedThreadsToCheck, sessionMock->addThreadToNewlyStoppedFromRaisedAttentionCallCount);
EXPECT_EQ(expectedThreadsToCheck, sessionMock->readSystemRoutineIdentFromMemoryCallCount);
EXPECT_EQ(0u, sessionMock->readSystemRoutineIdentCallCount);
}
TEST_F(DebugApiLinuxTestXe, GivenInterruptedThreadsWhenAttentionEventReceivedThenEventsTriggeredAfterExpectedAttentionEventCount) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto sessionMock = std::make_unique<MockDebugSessionLinuxXe>(config, device, 10);
ASSERT_NE(nullptr, sessionMock);
sessionMock->clientHandle = MockDebugSessionLinuxXe::mockClientHandle;
uint64_t execQueueHandle = 2;
uint64_t vmHandle = 7;
uint64_t lrcHandle = 8;
sessionMock->clientHandleToConnection[MockDebugSessionLinuxXe::mockClientHandle]->lrcHandleToVmHandle[lrcHandle] = vmHandle;
uint8_t data[sizeof(drm_xe_eudebug_event_eu_attention) + 128];
ze_device_thread_t thread{0, 0, 0, 0};
sessionMock->stoppedThreads[EuThread::ThreadId(0, thread).packed] = 1;
sessionMock->pendingInterrupts.push_back(std::pair<ze_device_thread_t, bool>(thread, false));
sessionMock->interruptSent = true;
sessionMock->euControlInterruptSeqno = 1;
drm_xe_eudebug_event_eu_attention attention = {};
attention.base.type = DRM_XE_EUDEBUG_EVENT_EU_ATTENTION;
attention.base.flags = DRM_XE_EUDEBUG_EVENT_STATE_CHANGE;
attention.base.len = sizeof(drm_xe_eudebug_event_eu_attention);
attention.base.seqno = 2;
attention.client_handle = MockDebugSessionLinuxXe::mockClientHandle;
attention.lrc_handle = lrcHandle;
attention.flags = 0;
attention.exec_queue_handle = execQueueHandle;
attention.bitmask_size = 0;
memcpy(data, &attention, sizeof(drm_xe_eudebug_event_eu_attention));
sessionMock->expectedAttentionEvents = 2;
sessionMock->handleEvent(reinterpret_cast<drm_xe_eudebug_event *>(data));
EXPECT_FALSE(sessionMock->triggerEvents);
attention.base.seqno = 10;
memcpy(data, &attention, sizeof(drm_xe_eudebug_event_eu_attention));
sessionMock->handleEvent(reinterpret_cast<drm_xe_eudebug_event *>(data));
EXPECT_TRUE(sessionMock->triggerEvents);
}
TEST_F(DebugApiLinuxTestXe, GivenNoElfDataImplementationThenGetElfDataReturnsNullptr) {
zet_debug_config_t config = {};
config.pid = 0x1234;

View File

@@ -149,7 +149,8 @@ struct drm_xe_eudebug_eu_control {
__u32 flags;
__u64 seqno;
struct drm_xe_engine_class_instance ci;
__u64 exec_queue_handle;
__u64 lrc_handle;
__u32 bitmask_size;
__u64 bitmask_ptr;
} __attribute__((packed));