fix: Implement debug area read in Xe by reusing I915 logic

Related-To: NEO-11197
Signed-off-by: Jitendra Sharma <jitendra.sharma@intel.com>
This commit is contained in:
Jitendra Sharma
2024-04-15 08:27:10 +00:00
committed by Compute-Runtime-Automation
parent 2473c38e31
commit 8a60257aac
9 changed files with 171 additions and 137 deletions

View File

@@ -92,6 +92,85 @@ bool DebugSessionLinux::closeFd() {
return true;
}
void DebugSessionLinux::handleEventsAsync() {
handleInternalEvent();
}
ze_result_t DebugSessionLinux::initialize() {
struct pollfd pollFd = {
.fd = this->fd,
.events = POLLIN,
.revents = 0,
};
auto numberOfFds = ioctlHandler->poll(&pollFd, 1, 1000);
PRINT_DEBUGGER_INFO_LOG("initialization poll() retCode: %d\n", numberOfFds);
if (numberOfFds <= 0) {
return ZE_RESULT_NOT_READY;
}
bool isRootDevice = !connectedDevice->getNEODevice()->isSubDevice();
if (isRootDevice && !tileAttachEnabled) {
createEuThreads();
}
createTileSessionsIfEnabled();
startInternalEventsThread();
bool allEventsCollected = false;
bool eventAvailable = true;
float timeDelta = 0;
float timeStart = clock();
do {
if (internalThreadHasStarted) {
eventAvailable = handleInternalEvent();
allEventsCollected = checkAllEventsCollected();
} else {
timeDelta = float(clock() - timeStart) / CLOCKS_PER_SEC;
}
} while ((eventAvailable && !allEventsCollected) && timeDelta < getThreadStartLimitTime());
internalThreadHasStarted = false;
if (clientHandleClosed == clientHandle && clientHandle != invalidClientHandle) {
return ZE_RESULT_ERROR_DEVICE_LOST;
}
if (allEventsCollected) {
if (!readModuleDebugArea()) {
return ZE_RESULT_ERROR_UNKNOWN;
}
return ZE_RESULT_SUCCESS;
}
return ZE_RESULT_NOT_READY;
}
void DebugSessionLinux::createTileSessionsIfEnabled() {
auto numTiles = connectedDevice->getNEODevice()->getNumSubDevices();
if (numTiles > 0 && tileAttachEnabled) {
tileSessions.resize(numTiles);
for (uint32_t i = 0; i < numTiles; i++) {
auto subDevice = connectedDevice->getNEODevice()->getSubDevice(i)->getSpecializedDevice<Device>();
tileSessions[i] = std::pair<DebugSessionImp *, bool>{createTileSession(config, subDevice, this), false};
}
tileSessionsEnabled = true;
}
}
bool DebugSessionLinux::checkAllEventsCollected() {
bool allEventsCollected = false;
bool clientConnected = (this->clientHandle != invalidClientHandle);
if (clientConnected) {
if (getClientConnection(clientHandle)->vmToModuleDebugAreaBindInfo.size() > 0) {
allEventsCollected = true;
}
}
PRINT_DEBUGGER_INFO_LOG("checkAllEventsCollected() returned %d, clientHandle = %ull\n", static_cast<int>(allEventsCollected), this->clientHandle);
return allEventsCollected;
}
void *DebugSessionLinux::readInternalEventsThreadFunction(void *arg) {
DebugSessionLinux *self = reinterpret_cast<DebugSessionLinux *>(arg);
PRINT_DEBUGGER_INFO_LOG("Debugger internal event thread started\n", "");

View File

@@ -25,6 +25,7 @@ struct DebugSessionLinux : DebugSessionImp {
bool closeFd();
void closeAsyncThread();
bool closeConnection() override;
ze_result_t initialize() override;
int fd = 0;
std::atomic<bool> internalThreadHasStarted{false};
@@ -240,6 +241,11 @@ struct DebugSessionLinux : DebugSessionImp {
virtual Module &getModule(uint64_t moduleHandle) = 0;
virtual std::vector<uint64_t> getAllMemoryHandles();
void handleEventsAsync();
virtual bool handleInternalEvent() = 0;
void createTileSessionsIfEnabled();
virtual DebugSessionImp *createTileSession(const zet_debug_config_t &config, Device *device, DebugSessionImp *rootDebugSession) = 0;
bool checkAllEventsCollected();
std::unique_ptr<IoctlHandler> ioctlHandler;
};

View File

@@ -100,80 +100,7 @@ int DebugSessionLinuxi915::openVmFd(uint64_t vmHandle, bool readOnly) {
return ioctl(PRELIM_I915_DEBUG_IOCTL_VM_OPEN, &vmOpen);
}
ze_result_t DebugSessionLinuxi915::initialize() {
struct pollfd pollFd = {
.fd = this->fd,
.events = POLLIN,
.revents = 0,
};
auto numberOfFds = ioctlHandler->poll(&pollFd, 1, 1000);
PRINT_DEBUGGER_INFO_LOG("initialization poll() retCode: %d\n", numberOfFds);
if (numberOfFds <= 0) {
return ZE_RESULT_NOT_READY;
}
bool isRootDevice = !connectedDevice->getNEODevice()->isSubDevice();
if (isRootDevice && !tileAttachEnabled) {
createEuThreads();
}
createTileSessionsIfEnabled();
startInternalEventsThread();
bool allEventsCollected = false;
bool eventAvailable = true;
float timeDelta = 0;
float timeStart = clock();
do {
if (internalThreadHasStarted) {
auto eventMemory = getInternalEvent();
auto debugEvent = reinterpret_cast<prelim_drm_i915_debug_event *>(eventMemory.get());
if (eventMemory != nullptr) {
handleEvent(debugEvent);
if (debugEvent->type != PRELIM_DRM_I915_DEBUG_EVENT_VM_BIND && pendingVmBindEvents.size() > 0) {
processPendingVmBindEvents();
}
eventAvailable = true;
} else {
eventAvailable = false;
}
allEventsCollected = checkAllEventsCollected();
} else {
timeDelta = float(clock() - timeStart) / CLOCKS_PER_SEC;
}
} while ((eventAvailable && !allEventsCollected) && timeDelta < getThreadStartLimitTime());
internalThreadHasStarted = false;
if (clientHandleClosed == clientHandle && clientHandle != invalidClientHandle) {
return ZE_RESULT_ERROR_DEVICE_LOST;
}
if (allEventsCollected) {
if (!readModuleDebugArea()) {
return ZE_RESULT_ERROR_UNKNOWN;
}
return ZE_RESULT_SUCCESS;
}
return ZE_RESULT_NOT_READY;
}
void DebugSessionLinuxi915::createTileSessionsIfEnabled() {
auto numTiles = connectedDevice->getNEODevice()->getNumSubDevices();
if (numTiles > 0 && tileAttachEnabled) {
tileSessions.resize(numTiles);
for (uint32_t i = 0; i < numTiles; i++) {
auto subDevice = connectedDevice->getNEODevice()->getSubDevice(i)->getSpecializedDevice<Device>();
tileSessions[i] = std::pair<DebugSessionImp *, bool>{createTileSession(config, subDevice, this), false};
}
tileSessionsEnabled = true;
}
}
TileDebugSessionLinuxi915 *DebugSessionLinuxi915::createTileSession(const zet_debug_config_t &config, Device *device, DebugSessionImp *rootDebugSession) {
DebugSessionImp *DebugSessionLinuxi915::createTileSession(const zet_debug_config_t &config, Device *device, DebugSessionImp *rootDebugSession) {
auto tileSession = new TileDebugSessionLinuxi915(config, device, rootDebugSession);
tileSession->initialize();
return tileSession;
@@ -206,16 +133,19 @@ void DebugSessionLinuxi915::startAsyncThread() {
asyncThread.thread = NEO::Thread::create(asyncThreadFunction, reinterpret_cast<void *>(this));
}
void DebugSessionLinuxi915::handleEventsAsync() {
bool DebugSessionLinuxi915::handleInternalEvent() {
auto eventMemory = getInternalEvent();
if (eventMemory != nullptr) {
auto debugEvent = reinterpret_cast<prelim_drm_i915_debug_event *>(eventMemory.get());
handleEvent(debugEvent);
if (debugEvent->type != PRELIM_DRM_I915_DEBUG_EVENT_VM_BIND && pendingVmBindEvents.size() > 0) {
processPendingVmBindEvents();
}
if (eventMemory == nullptr) {
return false;
}
auto debugEvent = reinterpret_cast<prelim_drm_i915_debug_event *>(eventMemory.get());
handleEvent(debugEvent);
if (debugEvent->type != PRELIM_DRM_I915_DEBUG_EVENT_VM_BIND && pendingVmBindEvents.size() > 0) {
processPendingVmBindEvents();
}
return true;
}
void DebugSessionLinuxi915::readInternalEventsAsync() {
@@ -541,18 +471,6 @@ void DebugSessionLinuxi915::processPendingVmBindEvents() {
}
}
bool DebugSessionLinuxi915::checkAllEventsCollected() {
bool allEventsCollected = false;
bool clientConnected = (this->clientHandle != invalidClientHandle);
if (clientConnected) {
if (clientHandleToConnection[clientHandle]->vmToModuleDebugAreaBindInfo.size() > 0) {
allEventsCollected = true;
}
}
PRINT_DEBUGGER_INFO_LOG("checkAllEventsCollected() returned %d, clientHandle = %ull\n", static_cast<int>(allEventsCollected), this->clientHandle);
return allEventsCollected;
}
ze_result_t DebugSessionLinuxi915::readEventImp(prelim_drm_i915_debug_event *drmDebugEvent) {
auto ret = ioctl(PRELIM_I915_DEBUG_IOCTL_READ_EVENT, drmDebugEvent);
if (ret != 0) {

View File

@@ -39,7 +39,6 @@ struct DebugSessionLinuxi915 : DebugSessionLinux {
DebugSessionLinuxi915(const zet_debug_config_t &config, Device *device, int debugFd, void *params);
static DebugSession *createLinuxSession(const zet_debug_config_t &config, Device *device, ze_result_t &result, bool isRootAttach);
ze_result_t initialize() override;
struct IoctlHandleri915 : DebugSessionLinux::IoctlHandler {
int ioctl(int fd, unsigned long request, void *arg) override {
@@ -102,18 +101,15 @@ struct DebugSessionLinuxi915 : DebugSessionLinux {
protected:
MOCKABLE_VIRTUAL void handleEvent(prelim_drm_i915_debug_event *event);
bool checkAllEventsCollected();
std::unordered_map<uint64_t, std::shared_ptr<ClientConnectioni915>> clientHandleToConnection;
ze_result_t readEventImp(prelim_drm_i915_debug_event *drmDebugEvent);
MOCKABLE_VIRTUAL void createTileSessionsIfEnabled();
MOCKABLE_VIRTUAL TileDebugSessionLinuxi915 *createTileSession(const zet_debug_config_t &config, Device *device, DebugSessionImp *rootDebugSession);
DebugSessionImp *createTileSession(const zet_debug_config_t &config, Device *device, DebugSessionImp *rootDebugSession) override;
static void *asyncThreadFunction(void *arg);
void startAsyncThread() override;
void handleEventsAsync();
bool handleInternalEvent() override;
void updateContextAndLrcHandlesForThreadsWithAttention(EuThread::ThreadId threadId, AttentionEventFields &attention) override {}
uint64_t getVmHandleFromClientAndlrcHandle(uint64_t clientHandle, uint64_t lrcHandle) override;

View File

@@ -62,38 +62,15 @@ DebugSession *DebugSessionLinuxXe::createLinuxSession(const zet_debug_config_t &
return nullptr;
}
ze_result_t DebugSessionLinuxXe::initialize() {
struct pollfd pollFd = {
.fd = this->fd,
.events = POLLIN,
.revents = 0,
};
auto numberOfFds = ioctlHandler->poll(&pollFd, 1, 1000);
PRINT_DEBUGGER_INFO_LOG("initialization poll() retCode: %d\n", numberOfFds);
if (numberOfFds <= 0) {
return ZE_RESULT_NOT_READY;
}
bool isRootDevice = !connectedDevice->getNEODevice()->isSubDevice();
UNRECOVERABLE_IF(!isRootDevice);
createEuThreads();
tileSessionsEnabled = false;
startInternalEventsThread();
return ZE_RESULT_SUCCESS;
}
void DebugSessionLinuxXe::handleEventsAsync() {
bool DebugSessionLinuxXe::handleInternalEvent() {
auto eventMemory = getInternalEvent();
if (eventMemory != nullptr) {
auto debugEvent = reinterpret_cast<drm_xe_eudebug_event *>(eventMemory.get());
handleEvent(debugEvent);
if (eventMemory == nullptr) {
return false;
}
auto debugEvent = reinterpret_cast<drm_xe_eudebug_event *>(eventMemory.get());
handleEvent(debugEvent);
return true;
}
void *DebugSessionLinuxXe::asyncThreadFunction(void *arg) {

View File

@@ -25,8 +25,6 @@ struct DebugSessionLinuxXe : DebugSessionLinux {
DebugSessionLinuxXe(const zet_debug_config_t &config, Device *device, int debugFd, void *params);
static DebugSession *createLinuxSession(const zet_debug_config_t &config, Device *device, ze_result_t &result, bool isRootAttach);
ze_result_t initialize() override;
struct IoctlHandlerXe : DebugSessionLinux::IoctlHandler {
int ioctl(int fd, unsigned long request, void *arg) override {
int ret = 0;
@@ -82,7 +80,10 @@ struct DebugSessionLinuxXe : DebugSessionLinux {
void startAsyncThread() override;
static void *asyncThreadFunction(void *arg);
void handleEventsAsync();
bool handleInternalEvent() override;
DebugSessionImp *createTileSession(const zet_debug_config_t &config, Device *device, DebugSessionImp *rootDebugSession) override {
return nullptr;
}
int openVmFd(uint64_t vmHandle, bool readOnly) override;
int flushVmCache(int vmfd) override;

View File

@@ -360,7 +360,7 @@ TEST(DebugSessionLinuxi915Test, GivenRootDebugSessionWhenCreateTileSessionCalled
auto session = std::make_unique<DebugSession>(zet_debug_config_t{0x1234}, &deviceImp, 10, nullptr);
ASSERT_NE(nullptr, session);
std::unique_ptr<TileDebugSessionLinuxi915> tileSession = std::unique_ptr<TileDebugSessionLinuxi915>{session->createTileSession(zet_debug_config_t{0x1234}, &deviceImp, nullptr)};
std::unique_ptr<DebugSessionImp> tileSession = std::unique_ptr<DebugSessionImp>{session->createTileSession(zet_debug_config_t{0x1234}, &deviceImp, nullptr)};
EXPECT_NE(nullptr, tileSession);
}

View File

@@ -162,6 +162,7 @@ struct MockDebugSessionLinuxXe : public L0::DebugSessionLinuxXe {
using L0::DebugSessionLinuxXe::ClientConnectionXe;
using L0::DebugSessionLinuxXe::clientHandleClosed;
using L0::DebugSessionLinuxXe::clientHandleToConnection;
using L0::DebugSessionLinuxXe::debugArea;
using L0::DebugSessionLinuxXe::euControlInterruptSeqno;
using L0::DebugSessionLinuxXe::getThreadStateMutexForTileSession;
using L0::DebugSessionLinuxXe::getVmHandleFromClientAndlrcHandle;

View File

@@ -303,7 +303,7 @@ TEST_F(DebugApiLinuxTestXe, GivenDebugSessionWhenPollReturnsZeroThenNotReadyIsRe
EXPECT_EQ(ZE_RESULT_NOT_READY, result);
}
TEST_F(DebugApiLinuxTestXe, GivenDebugSessionInitializedThenInternalEventsThreadStarted) {
TEST_F(DebugApiLinuxTestXe, GivenDebugSessionInitializationWhenNoValidEventsAreReadThenResultNotReadyIsReturned) {
zet_debug_config_t config = {};
config.pid = 0x1234;
@@ -324,8 +324,7 @@ TEST_F(DebugApiLinuxTestXe, GivenDebugSessionInitializedThenInternalEventsThread
handler->pollRetVal = 1;
ze_result_t result = session->initialize();
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
EXPECT_TRUE(session->internalEventThread.threadActive);
EXPECT_EQ(ZE_RESULT_NOT_READY, result);
}
TEST_F(DebugApiLinuxTestXe, GivenPollReturnsErrorAndEinvalWhenReadingInternalEventsAsyncThenDetachEventIsGenerated) {
@@ -2219,5 +2218,62 @@ TEST_F(DebugApiLinuxTestXe, GivenInterruptedThreadsWhenNoAttentionEventIsReadThe
}
}
TEST_F(DebugApiLinuxTestXe, GivenBindInfoForVmHandleWhenReadingModuleDebugAreaThenGpuMemoryIsRead) {
auto session = std::make_unique<MockDebugSessionLinuxXe>(zet_debug_config_t{0x1234}, device, 10);
ASSERT_NE(nullptr, session);
auto handler = new MockIoctlHandlerXe;
session->ioctlHandler.reset(handler);
session->clientHandle = MockDebugSessionLinuxXe::mockClientHandle;
uint64_t vmHandle = 6;
session->clientHandleToConnection[MockDebugSessionLinuxXe::mockClientHandle]->vmToModuleDebugAreaBindInfo[vmHandle] = {0x1234000, 0x1000};
DebugAreaHeader debugArea;
debugArea.reserved1 = 1;
debugArea.pgsize = uint8_t(4);
debugArea.version = 1;
handler->mmapRet = reinterpret_cast<char *>(&debugArea);
handler->setPreadMemory(reinterpret_cast<char *>(&debugArea), sizeof(session->debugArea), 0x1234000);
handler->preadRetVal = sizeof(session->debugArea);
auto retVal = session->readModuleDebugArea();
EXPECT_TRUE(retVal);
if (debugManager.flags.EnableDebuggerMmapMemoryAccess.get()) {
EXPECT_EQ(1, handler->mmapCalled);
EXPECT_EQ(1, handler->munmapCalled);
} else {
EXPECT_EQ(1, handler->preadCalled);
}
EXPECT_EQ(MockDebugSessionLinuxXe::mockClientHandle, handler->vmOpen.client_handle);
EXPECT_EQ(vmHandle, handler->vmOpen.vm_handle);
EXPECT_EQ(static_cast<uint64_t>(0), handler->vmOpen.flags);
EXPECT_EQ(1u, session->debugArea.reserved1);
EXPECT_EQ(1u, session->debugArea.version);
EXPECT_EQ(4u, session->debugArea.pgsize);
}
TEST(DebugSessionLinuxXeTest, GivenRootDebugSessionWhenCreateTileSessionCalledThenSessionIsNotCreated) {
auto hwInfo = *NEO::defaultHwInfo.get();
NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment<NEO::MockDevice>(&hwInfo, 0));
auto mockDrm = new DrmQueryMock(*neoDevice->executionEnvironment->rootDeviceEnvironments[0]);
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface);
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface->setDriverModel(std::unique_ptr<DriverModel>(mockDrm));
MockDeviceImp deviceImp(neoDevice, neoDevice->getExecutionEnvironment());
struct DebugSession : public DebugSessionLinuxXe {
using DebugSessionLinuxXe::createTileSession;
using DebugSessionLinuxXe::DebugSessionLinuxXe;
};
auto session = std::make_unique<DebugSession>(zet_debug_config_t{0x1234}, &deviceImp, 10, nullptr);
ASSERT_NE(nullptr, session);
std::unique_ptr<DebugSessionImp> tileSession = std::unique_ptr<DebugSessionImp>{session->createTileSession(zet_debug_config_t{0x1234}, &deviceImp, nullptr)};
EXPECT_EQ(nullptr, tileSession);
}
} // namespace ult
} // namespace L0