refactor: Move common attention handling EuDebug code out of prelim

Move common attention handling code from prelim in common linux
debug_session(.h/.cpp) files.
This common code could be shared to handle attention events for
prelim and xe driver based Eu Debug

Related-To: NEO-9673
Signed-off-by: Jitendra Sharma <jitendra.sharma@intel.com>
This commit is contained in:
Jitendra Sharma 2024-02-19 06:31:12 +00:00 committed by Compute-Runtime-Automation
parent f404f3ceb1
commit f56babb2a9
11 changed files with 236 additions and 80 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2023 Intel Corporation
* Copyright (C) 2021-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@ -127,7 +127,7 @@ struct DebugSessionImp : DebugSession {
size_t calculateThreadSlotOffset(EuThread::ThreadId threadId);
size_t calculateRegisterOffsetInThreadSlot(const SIP::regset_desc *const regdesc, uint32_t start);
void newAttentionRaised(uint32_t deviceIndex) {
void newAttentionRaised() {
if (expectedAttentionEvents > 0) {
expectedAttentionEvents--;
}

View File

@ -649,4 +649,77 @@ ze_result_t DebugSessionLinux::getElfOffset(const zet_debug_memory_space_desc_t
return status;
}
void DebugSessionLinux::updateStoppedThreadsAndCheckTriggerEvents(AttentionEventFields &attention, uint32_t tileIndex) {
auto vmHandle = getVmHandleFromClientAndlrcHandle(attention.clientHandle, attention.lrcHandle);
if (vmHandle == invalidHandle) {
return;
}
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);
}
PRINT_DEBUGGER_THREAD_LOG("ATTENTION for tile = %d thread count = %d\n", tileIndex, (int)threadsWithAttention.size());
if (threadsWithAttention.size() > 0) {
auto gpuVa = getContextStateSaveAreaGpuVa(vmHandle);
auto stateSaveAreaSize = getContextStateSaveAreaSize(vmHandle);
auto stateSaveReadResult = ZE_RESULT_ERROR_UNKNOWN;
std::unique_lock<std::mutex> lock;
if (tileSessionsEnabled) {
lock = getThreadStateMutexForTileSession(tileIndex);
} else {
lock = std::unique_lock<std::mutex>(threadStateMutex);
}
if (gpuVa != 0 && stateSaveAreaSize != 0) {
std::vector<EuThread::ThreadId> newThreads;
getNotStoppedThreads(threadsWithAttention, newThreads);
if (newThreads.size() > 0) {
allocateStateSaveAreaMemory(stateSaveAreaSize);
stateSaveReadResult = readGpuMemory(vmHandle, stateSaveAreaMemory.data(), stateSaveAreaSize, gpuVa);
}
} else {
PRINT_DEBUGGER_ERROR_LOG("Context state save area bind info invalid\n", "");
DEBUG_BREAK_IF(true);
}
if (stateSaveReadResult == ZE_RESULT_SUCCESS) {
for (auto &threadId : threadsWithAttention) {
PRINT_DEBUGGER_THREAD_LOG("ATTENTION event for thread: %s\n", EuThread::toString(threadId).c_str());
if (tileSessionsEnabled) {
addThreadToNewlyStoppedFromRaisedAttentionForTileSession(threadId, vmHandle, stateSaveAreaMemory.data(), tileIndex);
} else {
addThreadToNewlyStoppedFromRaisedAttention(threadId, vmHandle, stateSaveAreaMemory.data());
}
}
}
}
if (tileSessionsEnabled) {
checkTriggerEventsForAttentionForTileSession(tileIndex);
} else {
checkTriggerEventsForAttention();
}
}
} // namespace L0

View File

@ -120,6 +120,23 @@ struct DebugSessionLinux : DebugSessionImp {
interruptAll
};
struct AttentionEventFields {
uint64_t clientHandle;
uint64_t contextHandle;
uint64_t lrcHandle;
uint32_t bitmaskSize;
uint8_t *bitmask;
};
void updateStoppedThreadsAndCheckTriggerEvents(AttentionEventFields &attention, uint32_t tileIndex);
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;
virtual void addThreadToNewlyStoppedFromRaisedAttentionForTileSession(EuThread::ThreadId threadId,
uint64_t memoryHandle,
const void *stateSaveArea,
uint32_t tileIndex) = 0;
virtual int euControlIoctl(ThreadControlCmd threadCmd,
const NEO::EngineClassInstance *classInstance,
std::unique_ptr<uint8_t[]> &bitmask,

View File

@ -1092,83 +1092,32 @@ void DebugSessionLinuxi915::handleAttentionEvent(prelim_drm_i915_debug_event_eu_
return;
}
newAttentionRaised(
tileIndex);
auto vmHandle = getVmHandleFromClientAndlrcHandle(attention->client_handle, attention->lrc_handle);
if (vmHandle == invalidHandle) {
return;
}
newAttentionRaised();
if (!connectedDevice->getNEODevice()->getDeviceBitfield().test(tileIndex)) {
return;
}
auto hwInfo = connectedDevice->getHwInfo();
auto &l0GfxCoreHelper = connectedDevice->getL0GfxCoreHelper();
AttentionEventFields attentionEventFields;
attentionEventFields.bitmask = attention->bitmask;
attentionEventFields.bitmaskSize = attention->bitmask_size;
attentionEventFields.clientHandle = attention->client_handle;
attentionEventFields.contextHandle = attention->ctx_handle;
attentionEventFields.lrcHandle = attention->lrc_handle;
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);
}
}
return updateStoppedThreadsAndCheckTriggerEvents(attentionEventFields, tileIndex);
}
if (threadsWithAttention.size() == 0) {
threadsWithAttention = l0GfxCoreHelper.getThreadsFromAttentionBitmask(hwInfo, tileIndex, attention->bitmask, attention->bitmask_size);
printBitmask(attention->bitmask, attention->bitmask_size);
}
PRINT_DEBUGGER_THREAD_LOG("ATTENTION for tile = %d thread count = %d\n", tileIndex, (int)threadsWithAttention.size());
if (threadsWithAttention.size() > 0) {
auto gpuVa = getContextStateSaveAreaGpuVa(vmHandle);
auto stateSaveAreaSize = getContextStateSaveAreaSize(vmHandle);
auto stateSaveReadResult = ZE_RESULT_ERROR_UNKNOWN;
std::unique_lock<std::mutex> lock;
if (tileSessionsEnabled) {
lock = std::unique_lock<std::mutex>(static_cast<TileDebugSessionLinuxi915 *>(tileSessions[tileIndex].first)->threadStateMutex);
} else {
lock = std::unique_lock<std::mutex>(threadStateMutex);
}
if (gpuVa != 0 && stateSaveAreaSize != 0) {
std::vector<EuThread::ThreadId> newThreads;
getNotStoppedThreads(threadsWithAttention, newThreads);
if (newThreads.size() > 0) {
allocateStateSaveAreaMemory(stateSaveAreaSize);
stateSaveReadResult = readGpuMemory(vmHandle, stateSaveAreaMemory.data(), stateSaveAreaSize, gpuVa);
}
} else {
PRINT_DEBUGGER_ERROR_LOG("Context state save area bind info invalid\n", "");
DEBUG_BREAK_IF(true);
}
if (stateSaveReadResult == ZE_RESULT_SUCCESS) {
for (auto &threadId : threadsWithAttention) {
PRINT_DEBUGGER_THREAD_LOG("ATTENTION event for thread: %s\n", EuThread::toString(threadId).c_str());
if (tileSessionsEnabled) {
static_cast<TileDebugSessionLinuxi915 *>(tileSessions[tileIndex].first)->addThreadToNewlyStoppedFromRaisedAttention(threadId, vmHandle, stateSaveAreaMemory.data());
} else {
addThreadToNewlyStoppedFromRaisedAttention(threadId, vmHandle, stateSaveAreaMemory.data());
}
}
}
}
if (tileSessionsEnabled) {
static_cast<TileDebugSessionLinuxi915 *>(tileSessions[tileIndex].first)->checkTriggerEventsForAttention();
} else {
checkTriggerEventsForAttention();
}
std::unique_lock<std::mutex> DebugSessionLinuxi915::getThreadStateMutexForTileSession(uint32_t tileIndex) {
return std::unique_lock<std::mutex>(static_cast<TileDebugSessionLinuxi915 *>(tileSessions[tileIndex].first)->threadStateMutex);
}
void DebugSessionLinuxi915::checkTriggerEventsForAttentionForTileSession(uint32_t tileIndex) {
static_cast<TileDebugSessionLinuxi915 *>(tileSessions[tileIndex].first)->checkTriggerEventsForAttention();
}
void DebugSessionLinuxi915::addThreadToNewlyStoppedFromRaisedAttentionForTileSession(EuThread::ThreadId threadId,
uint64_t memoryHandle,
const void *stateSaveArea,
uint32_t tileIndex) {
static_cast<TileDebugSessionLinuxi915 *>(tileSessions[tileIndex].first)->addThreadToNewlyStoppedFromRaisedAttention(threadId, memoryHandle, stateSaveAreaMemory.data());
}
void DebugSessionLinuxi915::handlePageFaultEvent(prelim_drm_i915_debug_event_page_fault *pf) {

View File

@ -172,7 +172,7 @@ struct DebugSessionLinuxi915 : DebugSessionLinux {
void handleEventsAsync();
uint64_t getVmHandleFromClientAndlrcHandle(uint64_t clientHandle, uint64_t lrcHandle);
uint64_t getVmHandleFromClientAndlrcHandle(uint64_t clientHandle, uint64_t lrcHandle) override;
bool handleVmBindEvent(prelim_drm_i915_debug_event_vm_bind *vmBind);
void handleContextParamEvent(prelim_drm_i915_debug_event_context_param *contextParam);
void handleAttentionEvent(prelim_drm_i915_debug_event_eu_attention *attention);
@ -183,6 +183,13 @@ struct DebugSessionLinuxi915 : DebugSessionLinux {
MOCKABLE_VIRTUAL void processPendingVmBindEvents();
std::unique_lock<std::mutex> getThreadStateMutexForTileSession(uint32_t tileIndex) override;
void checkTriggerEventsForAttentionForTileSession(uint32_t tileIndex) override;
void addThreadToNewlyStoppedFromRaisedAttentionForTileSession(EuThread::ThreadId threadId,
uint64_t memoryHandle,
const void *stateSaveArea,
uint32_t tileIndex) override;
void attachTile() override {
UNRECOVERABLE_IF(true);
}

View File

@ -303,6 +303,20 @@ int DebugSessionLinuxXe::flushVmCache(int vmfd) {
return retVal;
}
uint64_t DebugSessionLinuxXe::getVmHandleFromClientAndlrcHandle(uint64_t clientHandle, uint64_t lrcHandle) {
if (clientHandleToConnection.find(clientHandle) == clientHandleToConnection.end()) {
return invalidHandle;
}
auto &clientConnection = clientHandleToConnection[clientHandle];
if (clientConnection->lrcHandleToVmHandle.find(lrcHandle) == clientConnection->lrcHandleToVmHandle.end()) {
return invalidHandle;
}
return clientConnection->lrcHandleToVmHandle[lrcHandle];
}
int DebugSessionLinuxXe::euControlIoctl(ThreadControlCmd threadCmd,
const NEO::EngineClassInstance *classInstance,
std::unique_ptr<uint8_t[]> &bitmask,

View File

@ -162,6 +162,19 @@ struct DebugSessionLinuxXe : DebugSessionLinux {
std::atomic<bool> detached{false};
uint64_t getVmHandleFromClientAndlrcHandle(uint64_t clientHandle, uint64_t lrcHandle) override;
void checkTriggerEventsForAttentionForTileSession(uint32_t tileIndex) override {}
std::unique_lock<std::mutex> getThreadStateMutexForTileSession(uint32_t tileIndex) override {
std::mutex m;
std::unique_lock<std::mutex> lock(m);
lock.release();
return lock;
}
void addThreadToNewlyStoppedFromRaisedAttentionForTileSession(EuThread::ThreadId threadId,
uint64_t memoryHandle,
const void *stateSaveArea,
uint32_t tileIndex) override {}
ze_result_t readEventImp(drm_xe_eudebug_event *drmDebugEvent);
int ioctl(unsigned long request, void *arg);
std::atomic<bool> processEntryEventGenerated = false;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2023 Intel Corporation
* Copyright (C) 2021-2024 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
@ -2183,13 +2183,13 @@ TEST_F(MultiTileDebugSessionTest, givenTwoInterruptsSentWhenCheckingTriggerEvent
sessionMock->sendInterrupts();
EXPECT_EQ(2u, sessionMock->expectedAttentionEvents);
sessionMock->newAttentionRaised(0);
sessionMock->newAttentionRaised();
EXPECT_EQ(1u, sessionMock->expectedAttentionEvents);
sessionMock->checkTriggerEventsForAttention();
EXPECT_FALSE(sessionMock->triggerEvents);
sessionMock->newAttentionRaised(1);
sessionMock->newAttentionRaised();
EXPECT_EQ(0u, sessionMock->expectedAttentionEvents);
sessionMock->checkTriggerEventsForAttention();
@ -3294,7 +3294,7 @@ TEST(DebugSessionTest, givenNewAttentionRaisedWithNoExpectedAttentionThenExpecte
auto sessionMock = std::make_unique<MockDebugSession>(config, nullptr);
EXPECT_EQ(0UL, sessionMock->expectedAttentionEvents);
sessionMock->newAttentionRaised(0);
sessionMock->newAttentionRaised();
EXPECT_EQ(0UL, sessionMock->expectedAttentionEvents);
}

View File

@ -695,7 +695,7 @@ TEST_F(TileAttachTest, givenTwoInterruptsSentWhenCheckingTriggerEventsThenTrigge
EXPECT_EQ(0u, tileSessions[0]->expectedAttentionEvents);
EXPECT_EQ(0u, rootSession->interruptedDevice);
rootSession->newAttentionRaised(0);
rootSession->newAttentionRaised();
tileSessions[0]->checkTriggerEventsForAttention();
EXPECT_TRUE(tileSessions[0]->triggerEvents);
@ -710,7 +710,7 @@ TEST_F(TileAttachTest, givenTwoInterruptsSentWhenCheckingTriggerEventsThenTrigge
EXPECT_FALSE(tileSessions[1]->triggerEvents);
EXPECT_EQ(1u, rootSession->interruptedDevice);
rootSession->newAttentionRaised(1);
rootSession->newAttentionRaised();
EXPECT_EQ(0u, tileSessions[1]->expectedAttentionEvents);
tileSessions[1]->checkTriggerEventsForAttention();

View File

@ -126,19 +126,26 @@ struct MockIoctlHandlerXe : public L0::ult::MockIoctlHandler {
struct MockDebugSessionLinuxXe : public L0::DebugSessionLinuxXe {
using L0::DebugSessionImp::allThreads;
using L0::DebugSessionImp::apiEvents;
using L0::DebugSessionImp::expectedAttentionEvents;
using L0::DebugSessionImp::stateSaveAreaHeader;
using L0::DebugSessionImp::triggerEvents;
using L0::DebugSessionLinux::getClientConnection;
using L0::DebugSessionLinuxXe::addThreadToNewlyStoppedFromRaisedAttentionForTileSession;
using L0::DebugSessionLinuxXe::asyncThread;
using L0::DebugSessionLinuxXe::asyncThreadFunction;
using L0::DebugSessionLinuxXe::checkStoppedThreadsAndGenerateEvents;
using L0::DebugSessionLinuxXe::checkTriggerEventsForAttentionForTileSession;
using L0::DebugSessionLinuxXe::clientHandleClosed;
using L0::DebugSessionLinuxXe::clientHandleToConnection;
using L0::DebugSessionLinuxXe::euControlInterruptSeqno;
using L0::DebugSessionLinuxXe::getThreadStateMutexForTileSession;
using L0::DebugSessionLinuxXe::getVmHandleFromClientAndlrcHandle;
using L0::DebugSessionLinuxXe::handleEvent;
using L0::DebugSessionLinuxXe::internalEventQueue;
using L0::DebugSessionLinuxXe::internalEventThread;
using L0::DebugSessionLinuxXe::invalidClientHandle;
using L0::DebugSessionLinuxXe::ioctlHandler;
using L0::DebugSessionLinuxXe::newlyStoppedThreads;
using L0::DebugSessionLinuxXe::readEventImp;
using L0::DebugSessionLinuxXe::readInternalEventsAsync;
using L0::DebugSessionLinuxXe::startAsyncThread;
@ -152,6 +159,14 @@ struct MockDebugSessionLinuxXe : public L0::DebugSessionLinuxXe {
}
MockDebugSessionLinuxXe(const zet_debug_config_t &config, L0::Device *device, int debugFd) : MockDebugSessionLinuxXe(config, device, debugFd, nullptr) {}
void addThreadToNewlyStoppedFromRaisedAttentionForTileSession(EuThread::ThreadId threadId,
uint64_t memoryHandle,
const void *stateSaveArea,
uint32_t tileIndex) override {
DebugSessionLinuxXe::addThreadToNewlyStoppedFromRaisedAttentionForTileSession(threadId, 0x12345678, nullptr, 0);
countToAddThreadToNewlyStoppedFromRaisedAttentionForTileSession++;
}
ze_result_t initialize() override {
if (initializeRetVal != ZE_RESULT_FORCE_UINT32) {
createEuThreads();
@ -180,6 +195,7 @@ struct MockDebugSessionLinuxXe : public L0::DebugSessionLinuxXe {
ze_result_t initializeRetVal = ZE_RESULT_FORCE_UINT32;
static constexpr uint64_t mockClientHandle = 1;
std::unordered_map<uint64_t, uint8_t> stoppedThreads;
uint32_t countToAddThreadToNewlyStoppedFromRaisedAttentionForTileSession = 0;
};
struct MockAsyncThreadDebugSessionLinuxXe : public MockDebugSessionLinuxXe {

View File

@ -747,6 +747,73 @@ TEST_F(DebugApiLinuxTestXe, GivenEuDebugExecQueueEventWithEventDestroyFlagWhenHa
EXPECT_TRUE(session->clientHandleToConnection[execQueue->client_handle]->lrcHandleToVmHandle.empty());
}
TEST_F(DebugApiLinuxTestXe, GivenExecQueueWhenGetVmHandleFromClientAndlrcHandleThenProperVmHandleReturned) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto session = std::make_unique<MockDebugSessionLinuxXe>(config, device, 10);
ASSERT_NE(nullptr, session);
session->clientHandleToConnection.clear();
drm_xe_eudebug_event_client client1;
client1.base.type = DRM_XE_EUDEBUG_EVENT_OPEN;
client1.base.flags = DRM_XE_EUDEBUG_EVENT_CREATE;
client1.client_handle = 0x123456789;
session->handleEvent(reinterpret_cast<drm_xe_eudebug_event *>(&client1));
uint64_t execQueueData[sizeof(drm_xe_eudebug_event_exec_queue) / sizeof(uint64_t) + 3 * sizeof(typeOfLrcHandle)];
auto *lrcHandle = reinterpret_cast<typeOfLrcHandle *>(ptrOffset(execQueueData, sizeof(drm_xe_eudebug_event_exec_queue)));
typeOfLrcHandle lrcHandleTemp[3];
const uint64_t lrcHandle0 = 2;
const uint64_t lrcHandle1 = 3;
const uint64_t lrcHandle2 = 5;
lrcHandleTemp[0] = static_cast<typeOfLrcHandle>(lrcHandle0);
lrcHandleTemp[1] = static_cast<typeOfLrcHandle>(lrcHandle1);
lrcHandleTemp[2] = static_cast<typeOfLrcHandle>(lrcHandle2);
drm_xe_eudebug_event_exec_queue *execQueue = reinterpret_cast<drm_xe_eudebug_event_exec_queue *>(&execQueueData);
execQueue->base.type = DRM_XE_EUDEBUG_EVENT_EXEC_QUEUE;
execQueue->base.flags = DRM_XE_EUDEBUG_EVENT_CREATE;
execQueue->client_handle = client1.client_handle;
execQueue->vm_handle = 0x1234;
execQueue->exec_queue_handle = 0x100;
execQueue->engine_class = DRM_XE_ENGINE_CLASS_COMPUTE;
execQueue->width = 3;
memcpy(lrcHandle, lrcHandleTemp, sizeof(lrcHandleTemp));
session->handleEvent(&execQueue->base);
EXPECT_EQ(execQueue->vm_handle, session->getVmHandleFromClientAndlrcHandle(execQueue->client_handle, lrcHandleTemp[0]));
EXPECT_EQ(DebugSessionLinux::invalidHandle, session->getVmHandleFromClientAndlrcHandle(0x1234567, lrcHandleTemp[0]));
EXPECT_EQ(DebugSessionLinux::invalidHandle, session->getVmHandleFromClientAndlrcHandle(execQueue->client_handle, 7));
}
TEST_F(DebugApiLinuxTestXe, whenGetThreadStateMutexForTileSessionThenNullLockIsReceived) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto session = std::make_unique<MockDebugSessionLinuxXe>(config, device, 10);
ASSERT_NE(nullptr, session);
std::unique_lock<std::mutex> lock;
EXPECT_FALSE(session->getThreadStateMutexForTileSession(0).owns_lock());
}
TEST_F(DebugApiLinuxTestXe, GivenNewlyStoppedThreadsAndNoExpectedAttentionEventsWhenCheckTriggerEventsForTileSessionThenTriggerEventsDontChange) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto session = std::make_unique<MockDebugSessionLinuxXe>(config, device, 10);
ASSERT_NE(nullptr, session);
EuThread::ThreadId threadId{0, 0, 0, 0, 0};
session->addThreadToNewlyStoppedFromRaisedAttentionForTileSession(threadId, 0x12345678, nullptr, 0);
EXPECT_EQ(session->countToAddThreadToNewlyStoppedFromRaisedAttentionForTileSession, 1u);
session->newlyStoppedThreads.push_back(threadId);
session->expectedAttentionEvents = 0;
session->triggerEvents = false;
session->checkTriggerEventsForAttentionForTileSession(0);
EXPECT_FALSE(session->triggerEvents);
}
TEST_F(DebugApiLinuxTestXe, whenHandleExecQueueEventThenProcessEnterAndProcessExitEventTriggeredUponFirstExecQueueCreateAndLastExecQueueDestroyRespectively) {
zet_debug_config_t config = {};
config.pid = 0x1234;