Add EuThread class

- add thread map to RootDebugSession


Signed-off-by: Mateusz Hoppe <mateusz.hoppe@intel.com>
This commit is contained in:
Mateusz Hoppe
2021-07-22 22:32:05 +00:00
committed by Compute-Runtime-Automation
parent e87056fb4d
commit ad5735c60b
8 changed files with 455 additions and 1 deletions

View File

@@ -5,8 +5,10 @@
# #
set(L0_SRCS_TOOLS_DEBUG set(L0_SRCS_TOOLS_DEBUG
${CMAKE_CURRENT_SOURCE_DIR}/debug_session.cpp
${CMAKE_CURRENT_SOURCE_DIR}/debug_session.h ${CMAKE_CURRENT_SOURCE_DIR}/debug_session.h
${CMAKE_CURRENT_SOURCE_DIR}/debug_handlers.h ${CMAKE_CURRENT_SOURCE_DIR}/debug_handlers.h
${CMAKE_CURRENT_SOURCE_DIR}/eu_thread.h
${CMAKE_CURRENT_SOURCE_DIR}${BRANCH_DIR_SUFFIX}/debug_handlers.cpp ${CMAKE_CURRENT_SOURCE_DIR}${BRANCH_DIR_SUFFIX}/debug_handlers.cpp
) )

View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "level_zero/tools/source/debug/debug_session.h"
#include "shared/source/helpers/hw_info.h"
#include "level_zero/core/source/device/device_imp.h"
namespace L0 {
RootDebugSession::RootDebugSession(const zet_debug_config_t &config, Device *device) : DebugSession(config, device) {
if (connectedDevice) {
auto hwInfo = connectedDevice->getHwInfo();
const uint32_t numSubslicesPerSlice = hwInfo.gtSystemInfo.MaxSubSlicesSupported / hwInfo.gtSystemInfo.MaxSlicesSupported;
const uint32_t numEuPerSubslice = hwInfo.gtSystemInfo.MaxEuPerSubSlice;
const uint32_t numThreadsPerEu = (hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount);
uint32_t subDeviceCount = 1;
for (uint32_t tileIndex = 0; tileIndex < subDeviceCount; tileIndex++) {
for (uint32_t sliceID = 0; sliceID < hwInfo.gtSystemInfo.MaxSlicesSupported; sliceID++) {
for (uint32_t subsliceID = 0; subsliceID < numSubslicesPerSlice; subsliceID++) {
for (uint32_t euID = 0; euID < numEuPerSubslice; euID++) {
for (uint32_t threadID = 0; threadID < numThreadsPerEu; threadID++) {
EuThread::ThreadId thread = {tileIndex, sliceID, subsliceID, euID, threadID};
allThreads[uint64_t(thread)] = std::make_unique<EuThread>(thread);
}
}
}
}
}
}
}
std::vector<ze_device_thread_t> RootDebugSession::getSingleThreads(ze_device_thread_t physicalThread, const NEO::HardwareInfo &hwInfo) {
const uint32_t numSubslicesPerSlice = hwInfo.gtSystemInfo.MaxSubSlicesSupported / hwInfo.gtSystemInfo.MaxSlicesSupported;
const uint32_t numEuPerSubslice = hwInfo.gtSystemInfo.MaxEuPerSubSlice;
const uint32_t numThreadsPerEu = (hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount);
UNRECOVERABLE_IF(numThreadsPerEu > 8);
std::vector<ze_device_thread_t> threads;
const uint32_t slice = physicalThread.slice;
const uint32_t subslice = physicalThread.subslice;
const uint32_t eu = physicalThread.eu;
const uint32_t thread = physicalThread.thread;
for (uint32_t sliceID = 0; sliceID < hwInfo.gtSystemInfo.MaxSlicesSupported; sliceID++) {
if (slice != UINT32_MAX) {
sliceID = slice;
}
for (uint32_t subsliceID = 0; subsliceID < numSubslicesPerSlice; subsliceID++) {
if (subslice != UINT32_MAX) {
subsliceID = subslice;
}
for (uint32_t euID = 0; euID < numEuPerSubslice; euID++) {
if (eu != UINT32_MAX) {
euID = eu;
}
for (uint32_t threadID = 0; threadID < numThreadsPerEu; threadID++) {
if (thread != UINT32_MAX) {
threadID = thread;
}
threads.push_back({sliceID, subsliceID, euID, threadID});
if (thread != UINT32_MAX) {
break;
}
}
if (eu != UINT32_MAX) {
break;
}
}
if (subslice != UINT32_MAX) {
break;
}
}
if (slice != UINT32_MAX) {
break;
}
}
return threads;
}
} // namespace L0

View File

@@ -7,8 +7,12 @@
#pragma once #pragma once
#include "level_zero/core/source/debugger/debugger_l0.h" #include "level_zero/core/source/debugger/debugger_l0.h"
#include "level_zero/tools/source/debug/eu_thread.h"
#include <level_zero/ze_api.h>
#include <level_zero/zet_api.h> #include <level_zero/zet_api.h>
#include <memory>
struct _zet_debug_session_handle_t {}; struct _zet_debug_session_handle_t {};
namespace L0 { namespace L0 {
@@ -51,10 +55,14 @@ struct RootDebugSession : DebugSession {
RootDebugSession() = delete; RootDebugSession() = delete;
protected: protected:
RootDebugSession(const zet_debug_config_t &config, Device *device) : DebugSession(config, device){}; RootDebugSession(const zet_debug_config_t &config, Device *device);
virtual bool readModuleDebugArea() = 0; virtual bool readModuleDebugArea() = 0;
std::vector<ze_device_thread_t> getSingleThreads(ze_device_thread_t physicalThread, const NEO::HardwareInfo &hwInfo);
DebugAreaHeader debugArea; DebugAreaHeader debugArea;
std::map<uint64_t, std::unique_ptr<EuThread>> allThreads;
}; };
} // namespace L0 } // namespace L0

View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) 2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#pragma once
#include "shared/source/debug_settings/debug_settings_manager.h"
#include <level_zero/ze_api.h>
#include <limits>
#include <sstream>
#include <string>
namespace L0 {
class EuThread {
public:
enum class State {
Running,
Stopped,
Unavailable
};
struct ThreadId {
union {
struct {
uint64_t thread : 4;
uint64_t eu : 5;
uint64_t subslice : 10;
uint64_t slice : 10;
uint64_t tileIndex : 2;
uint64_t reserved : 33;
};
uint64_t packed;
};
ThreadId(uint32_t tile, uint32_t slice, uint32_t subslice, uint32_t eu, uint32_t thread) {
this->packed = 0;
this->tileIndex = tile;
this->slice = slice;
this->subslice = subslice;
this->eu = eu;
this->thread = thread;
}
ThreadId(uint32_t tile, ze_device_thread_t thread) {
this->packed = 0;
this->tileIndex = tile;
this->slice = thread.slice;
this->subslice = thread.subslice;
this->eu = thread.eu;
this->thread = thread.thread;
}
operator uint64_t() const {
return packed;
}
};
virtual ~EuThread() = default;
EuThread(ThreadId threadId) : threadId(threadId) {}
bool stopThread() {
if (state == State::Stopped) {
return false;
}
state = State::Stopped;
return true;
}
bool resumeThread() {
if (state != State::Stopped) {
return false;
}
state = State::Running;
return true;
}
bool isStopped() {
return state == State::Stopped;
}
bool isRunning() {
return state != State::Stopped;
}
std::string toString() {
std::stringstream threadString;
threadString << "device index = " << threadId.tileIndex << " slice = " << threadId.slice << " subslice = " << threadId.subslice << " eu = " << threadId.eu
<< " thread = " << threadId.thread;
return threadString.str();
}
ThreadId getThreadId() {
return threadId;
}
protected:
ThreadId threadId;
State state = State::Unavailable;
};
static_assert(sizeof(EuThread::ThreadId) == sizeof(uint64_t));
} // namespace L0

View File

@@ -6,6 +6,8 @@
target_sources(${TARGET_NAME} PRIVATE target_sources(${TARGET_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt
${CMAKE_CURRENT_SOURCE_DIR}/debug_session_tests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/eu_thread_tests.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mock_debug_session.h ${CMAKE_CURRENT_SOURCE_DIR}/mock_debug_session.h
${CMAKE_CURRENT_SOURCE_DIR}${BRANCH_DIR_SUFFIX}/test_debug_api.cpp ${CMAKE_CURRENT_SOURCE_DIR}${BRANCH_DIR_SUFFIX}/test_debug_api.cpp
) )

View File

@@ -0,0 +1,141 @@
/*
* Copyright (C) 2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/test/common/helpers/default_hw_info.h"
#include "shared/test/common/mocks/mock_device.h"
#include "test.h"
#include "level_zero/core/source/device/device_imp.h"
#include "level_zero/core/test/unit_tests/mock.h"
#include "level_zero/core/test/unit_tests/mocks/mock_device.h"
#include "level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h"
namespace L0 {
namespace ult {
TEST(RootDebugSession, givenSingleThreadWhenGettingSingleThreadsThenCorrectThreadIsReturned) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto hwInfo = *NEO::defaultHwInfo.get();
NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment<NEO::MockDevice>(&hwInfo, 0));
Mock<L0::DeviceImp> deviceImp(neoDevice, neoDevice->getExecutionEnvironment());
auto debugSession = std::make_unique<DebugSessionMock>(config, &deviceImp);
auto subslice = hwInfo.gtSystemInfo.MaxSubSlicesSupported / hwInfo.gtSystemInfo.MaxSlicesSupported - 1;
ze_device_thread_t physicalThread = {0, subslice, 2, 3};
auto threads = debugSession->getSingleThreads(physicalThread, hwInfo);
EXPECT_EQ(1u, threads.size());
EXPECT_EQ(0u, threads[0].slice);
EXPECT_EQ(subslice, threads[0].subslice);
EXPECT_EQ(2u, threads[0].eu);
EXPECT_EQ(3u, threads[0].thread);
}
TEST(RootDebugSession, givenAllThreadsWhenGettingSingleThreadsThenCorrectThreadsAreReturned) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto hwInfo = *NEO::defaultHwInfo.get();
NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment<NEO::MockDevice>(&hwInfo, 0));
Mock<L0::DeviceImp> deviceImp(neoDevice, neoDevice->getExecutionEnvironment());
auto debugSession = std::make_unique<DebugSessionMock>(config, &deviceImp);
auto subslice = hwInfo.gtSystemInfo.MaxSubSlicesSupported / hwInfo.gtSystemInfo.MaxSlicesSupported - 1;
ze_device_thread_t physicalThread = {0, subslice, 2, UINT32_MAX};
const uint32_t numThreadsPerEu = (hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount);
auto threads = debugSession->getSingleThreads(physicalThread, hwInfo);
EXPECT_EQ(numThreadsPerEu, threads.size());
for (uint32_t i = 0; i < numThreadsPerEu; i++) {
EXPECT_EQ(0u, threads[i].slice);
EXPECT_EQ(subslice, threads[i].subslice);
EXPECT_EQ(2u, threads[i].eu);
EXPECT_EQ(i, threads[i].thread);
}
}
TEST(RootDebugSession, givenAllEUsWhenGettingSingleThreadsThenCorrectThreadsAreReturned) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto hwInfo = *NEO::defaultHwInfo.get();
NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment<NEO::MockDevice>(&hwInfo, 0));
Mock<L0::DeviceImp> deviceImp(neoDevice, neoDevice->getExecutionEnvironment());
auto debugSession = std::make_unique<DebugSessionMock>(config, &deviceImp);
auto subslice = hwInfo.gtSystemInfo.MaxSubSlicesSupported / hwInfo.gtSystemInfo.MaxSlicesSupported - 1;
ze_device_thread_t physicalThread = {0, subslice, UINT32_MAX, 0};
const uint32_t numEuPerSubslice = hwInfo.gtSystemInfo.MaxEuPerSubSlice;
auto threads = debugSession->getSingleThreads(physicalThread, hwInfo);
EXPECT_EQ(numEuPerSubslice, threads.size());
for (uint32_t i = 0; i < numEuPerSubslice; i++) {
EXPECT_EQ(0u, threads[i].slice);
EXPECT_EQ(subslice, threads[i].subslice);
EXPECT_EQ(i, threads[i].eu);
EXPECT_EQ(0u, threads[i].thread);
}
}
TEST(RootDebugSession, givenAllSubslicesWhenGettingSingleThreadsThenCorrectThreadsAreReturned) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto hwInfo = *NEO::defaultHwInfo.get();
NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment<NEO::MockDevice>(&hwInfo, 0));
Mock<L0::DeviceImp> deviceImp(neoDevice, neoDevice->getExecutionEnvironment());
auto debugSession = std::make_unique<DebugSessionMock>(config, &deviceImp);
ze_device_thread_t physicalThread = {0, UINT32_MAX, 0, 0};
const uint32_t numSubslicesPerSlice = hwInfo.gtSystemInfo.MaxSubSlicesSupported / hwInfo.gtSystemInfo.MaxSlicesSupported;
auto threads = debugSession->getSingleThreads(physicalThread, hwInfo);
EXPECT_EQ(numSubslicesPerSlice, threads.size());
for (uint32_t i = 0; i < numSubslicesPerSlice; i++) {
EXPECT_EQ(0u, threads[i].slice);
EXPECT_EQ(i, threads[i].subslice);
EXPECT_EQ(0u, threads[i].eu);
EXPECT_EQ(0u, threads[i].thread);
}
}
TEST(RootDebugSession, givenAllSlicesWhenGettingSingleThreadsThenCorrectThreadsAreReturned) {
zet_debug_config_t config = {};
config.pid = 0x1234;
auto hwInfo = *NEO::defaultHwInfo.get();
NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment<NEO::MockDevice>(&hwInfo, 0));
Mock<L0::DeviceImp> deviceImp(neoDevice, neoDevice->getExecutionEnvironment());
auto debugSession = std::make_unique<DebugSessionMock>(config, &deviceImp);
ze_device_thread_t physicalThread = {UINT32_MAX, 0, 0, 0};
const uint32_t numSlices = hwInfo.gtSystemInfo.MaxSlicesSupported;
auto threads = debugSession->getSingleThreads(physicalThread, hwInfo);
EXPECT_EQ(numSlices, threads.size());
for (uint32_t i = 0; i < numSlices; i++) {
EXPECT_EQ(i, threads[i].slice);
EXPECT_EQ(0u, threads[i].subslice);
EXPECT_EQ(0u, threads[i].eu);
EXPECT_EQ(0u, threads[i].thread);
}
}
} // namespace ult
} // namespace L0

View File

@@ -0,0 +1,92 @@
/*
* Copyright (C) 2021 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "test.h"
#include "level_zero/tools/source/debug/eu_thread.h"
namespace L0 {
namespace ult {
TEST(EuThread, WhenConstructingEuThreadThenCorrectIdsAreSet) {
ze_device_thread_t devThread = {3, 4, 5, 6};
EuThread::ThreadId threadId(0, devThread);
EXPECT_EQ(0u, threadId.tileIndex);
EXPECT_EQ(3u, threadId.slice);
EXPECT_EQ(4u, threadId.subslice);
EXPECT_EQ(5u, threadId.eu);
EXPECT_EQ(6u, threadId.thread);
EuThread::ThreadId threadId2(3, 1, 2, 3, 4);
EXPECT_EQ(3u, threadId2.tileIndex);
EXPECT_EQ(1u, threadId2.slice);
EXPECT_EQ(2u, threadId2.subslice);
EXPECT_EQ(3u, threadId2.eu);
EXPECT_EQ(4u, threadId2.thread);
auto castValue = static_cast<uint64_t>(threadId2);
EXPECT_EQ(threadId2.packed, castValue);
}
TEST(EuThread, GivenEuThreadWhenGettingThreadIdThenValidIdReturned) {
ze_device_thread_t devThread = {3, 4, 5, 6};
EuThread::ThreadId threadId(0, devThread);
EuThread euThread(threadId);
auto id = euThread.getThreadId();
EXPECT_EQ(threadId.packed, id.packed);
}
TEST(EuThread, GivenEuThreadWhenChangingAndQueryingStatesThenStateIsChanged) {
ze_device_thread_t devThread = {3, 4, 5, 6};
EuThread::ThreadId threadId(0, devThread);
EuThread euThread(threadId);
EXPECT_FALSE(euThread.isStopped());
EXPECT_TRUE(euThread.isRunning());
bool result = euThread.stopThread();
EXPECT_TRUE(result);
EXPECT_TRUE(euThread.isStopped());
EXPECT_FALSE(euThread.isRunning());
result = euThread.stopThread();
EXPECT_FALSE(result);
EXPECT_TRUE(euThread.isStopped());
EXPECT_FALSE(euThread.isRunning());
result = euThread.resumeThread();
EXPECT_TRUE(result);
EXPECT_FALSE(euThread.isStopped());
EXPECT_TRUE(euThread.isRunning());
result = euThread.resumeThread();
EXPECT_FALSE(result);
EXPECT_FALSE(euThread.isStopped());
EXPECT_TRUE(euThread.isRunning());
}
TEST(EuThread, GivenEuThreadWhenToStringCalledThenCorrectStringReturned) {
ze_device_thread_t devThread = {3, 4, 5, 6};
EuThread::ThreadId threadId(0, devThread);
EuThread euThread(threadId);
auto threadString = euThread.toString();
EXPECT_EQ("device index = 0 slice = 3 subslice = 4 eu = 5 thread = 6", threadString);
}
} // namespace ult
} // namespace L0

View File

@@ -24,6 +24,8 @@ class OsInterfaceWithDebugAttach : public NEO::OSInterface {
}; };
struct DebugSessionMock : public L0::RootDebugSession { struct DebugSessionMock : public L0::RootDebugSession {
using L0::RootDebugSession::getSingleThreads;
DebugSessionMock(const zet_debug_config_t &config, L0::Device *device) : RootDebugSession(config, device), config(config){}; DebugSessionMock(const zet_debug_config_t &config, L0::Device *device) : RootDebugSession(config, device), config(config){};
bool closeConnection() override { return true; } bool closeConnection() override { return true; }
ze_result_t initialize() override { ze_result_t initialize() override {