L0Debug - tile debug session - initial changes

Related-To: NEO-5784

Signed-off-by: Mateusz Hoppe <mateusz.hoppe@intel.com>
This commit is contained in:
Mateusz Hoppe 2022-07-29 11:26:12 +00:00 committed by Compute-Runtime-Automation
parent 70ef88c0bb
commit 2a5bca380d
16 changed files with 606 additions and 20 deletions

View File

@ -45,6 +45,7 @@
#include "level_zero/core/source/printf_handler/printf_handler.h"
#include "level_zero/core/source/sampler/sampler.h"
#include "level_zero/tools/source/debug/debug_session.h"
#include "level_zero/tools/source/debug/debug_session_imp.h"
#include "level_zero/tools/source/metrics/metric.h"
#include "level_zero/tools/source/sysman/sysman.h"
@ -916,7 +917,8 @@ ze_result_t DeviceImp::getDebugProperties(zet_device_debug_properties_t *pDebugP
isDebugAttachAvailable = false;
}
if (isDebugAttachAvailable && !isSubdevice) {
bool tileAttach = NEO::DebugManager.flags.ExperimentalEnableTileAttach.get();
if (isDebugAttachAvailable && (isSubdevice == tileAttach)) {
pDebugProperties->flags = zet_device_debug_property_flag_t::ZET_DEVICE_DEBUG_PROPERTY_FLAG_ATTACH;
} else {
pDebugProperties->flags = 0;
@ -1330,14 +1332,38 @@ DebugSession *DeviceImp::getDebugSession(const zet_debug_config_t &config) {
DebugSession *DeviceImp::createDebugSession(const zet_debug_config_t &config, ze_result_t &result) {
if (!this->isSubdevice) {
auto session = DebugSession::create(config, this, result);
debugSession.reset(session);
if (debugSession.get() == nullptr) {
auto session = DebugSession::create(config, this, result);
debugSession.reset(session);
} else {
result = ZE_RESULT_SUCCESS;
}
} else if (NEO::DebugManager.flags.ExperimentalEnableTileAttach.get()) {
result = ZE_RESULT_SUCCESS;
auto rootL0Device = getNEODevice()->getRootDevice()->getSpecializedDevice<DeviceImp>();
auto session = rootL0Device->getDebugSession(config);
if (!session) {
session = rootL0Device->createDebugSession(config, result);
}
if (result == ZE_RESULT_SUCCESS) {
debugSession.reset(session->attachTileDebugSession(this));
result = debugSession ? ZE_RESULT_SUCCESS : ZE_RESULT_ERROR_NOT_AVAILABLE;
}
} else {
result = ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
}
return debugSession.get();
}
void DeviceImp::removeDebugSession() {
debugSession.release();
}
void DeviceImp::setDebugSession(DebugSession *session) {
debugSession.reset(session);
}
bool DeviceImp::toPhysicalSliceId(const NEO::TopologyMap &topologyMap, uint32_t &slice, uint32_t &subslice, uint32_t &deviceIndex) {
auto hwInfo = neoDevice->getRootDeviceEnvironment().getHardwareInfo();
uint32_t subDeviceCount = NEO::HwHelper::getSubDevicesCount(hwInfo);

View File

@ -72,8 +72,9 @@ struct DeviceImp : public Device {
uint32_t getPlatformInfo() const override;
MetricDeviceContext &getMetricDeviceContext() override;
DebugSession *getDebugSession(const zet_debug_config_t &config) override;
void setDebugSession(DebugSession *session);
DebugSession *createDebugSession(const zet_debug_config_t &config, ze_result_t &result) override;
void removeDebugSession() override { debugSession.release(); }
void removeDebugSession() override;
uint32_t getMaxNumHwThreads() const override;
ze_result_t activateMetricGroupsDeferred(uint32_t count,

View File

@ -12,14 +12,22 @@
namespace L0 {
namespace DebugApiHandlers {
std::mutex debugSessionMutex;
ze_result_t debugAttach(zet_device_handle_t hDevice, const zet_debug_config_t *config, zet_debug_session_handle_t *phDebug) {
ze_result_t result = ZE_RESULT_SUCCESS;
if (!L0::Device::fromHandle(hDevice)->getNEODevice()->isSubDevice() && NEO::DebugManager.flags.ExperimentalEnableTileAttach.get()) {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
}
auto session = L0::Device::fromHandle(hDevice)->getDebugSession(*config);
std::unique_lock<std::mutex> lock(debugSessionMutex);
if (!session) {
session = L0::Device::fromHandle(hDevice)->createDebugSession(*config, result);
}
if (session) {
*phDebug = session->toHandle();
}
@ -31,8 +39,23 @@ ze_result_t debugDetach(zet_debug_session_handle_t hDebug) {
if (session) {
auto device = session->getConnectedDevice();
device->removeDebugSession();
session->closeConnection();
delete session;
if (!device->getNEODevice()->isSubDevice()) {
delete session;
} else {
std::unique_lock<std::mutex> lock(debugSessionMutex);
auto rootL0Device = device->getNEODevice()->getRootDevice()->getSpecializedDevice<DeviceImp>();
zet_debug_config_t dummy = {};
auto rootSession = rootL0Device->getDebugSession(dummy);
rootSession->detachTileDebugSession(session);
if (rootSession->areAllTileDebugSessionDetached()) {
rootL0Device->removeDebugSession();
delete rootSession;
}
}
}
return ZE_RESULT_SUCCESS;
}

View File

@ -30,6 +30,7 @@ struct DebugSession : _zet_debug_session_handle_t {
static DebugSession *fromHandle(zet_debug_session_handle_t handle) { return static_cast<DebugSession *>(handle); }
inline zet_debug_session_handle_t toHandle() { return this; }
void createEuThreads();
virtual bool closeConnection() = 0;
virtual ze_result_t initialize() = 0;
@ -80,6 +81,10 @@ struct DebugSession : _zet_debug_session_handle_t {
ze_result_t sanityMemAccessThreadCheck(ze_device_thread_t thread, const zet_debug_memory_space_desc_t *desc);
virtual DebugSession *attachTileDebugSession(Device *device) = 0;
virtual void detachTileDebugSession(DebugSession *tileSession) = 0;
virtual bool areAllTileDebugSessionDetached() = 0;
struct ThreadHelper {
void close() {
threadActive.store(false);

View File

@ -21,23 +21,33 @@
namespace L0 {
DebugSession::DebugSession(const zet_debug_config_t &config, Device *device) : connectedDevice(device) {
}
void DebugSession::createEuThreads() {
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 = std::max(1u, connectedDevice->getNEODevice()->getNumSubDevices());
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++) {
bool isRootDevice = !connectedDevice->getNEODevice()->isSubDevice();
bool isSubDevice = connectedDevice->getNEODevice()->isSubDevice();
for (uint32_t threadID = 0; threadID < numThreadsPerEu; threadID++) {
if ((isRootDevice && NEO::DebugManager.flags.ExperimentalEnableTileAttach.get() == 0) ||
(isSubDevice && NEO::DebugManager.flags.ExperimentalEnableTileAttach.get() == 1)) {
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 = std::max(1u, connectedDevice->getNEODevice()->getNumSubDevices());
EuThread::ThreadId thread = {tileIndex, sliceID, subsliceID, euID, threadID};
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++) {
allThreads[uint64_t(thread)] = std::make_unique<EuThread>(thread);
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);
}
}
}
}
@ -261,6 +271,36 @@ void DebugSession::printBitmask(uint8_t *bitmask, size_t bitmaskSize) {
}
}
DebugSession *DebugSessionImp::attachTileDebugSession(Device *device) {
std::unique_lock<std::mutex> lock(asyncThreadMutex);
uint32_t subDeviceIndex = Math::log2(static_cast<uint32_t>(device->getNEODevice()->getDeviceBitfield().to_ulong()));
auto &[tileSession, attached] = tileSessions[subDeviceIndex];
if (attached) {
return nullptr;
}
attached = true;
return tileSession;
}
void DebugSessionImp::detachTileDebugSession(DebugSession *tileSession) {
std::unique_lock<std::mutex> lock(asyncThreadMutex);
uint32_t subDeviceIndex = Math::log2(static_cast<uint32_t>(tileSession->getConnectedDevice()->getNEODevice()->getDeviceBitfield().to_ulong()));
tileSessions[subDeviceIndex].second = false;
}
bool DebugSessionImp::areAllTileDebugSessionDetached() {
for (const auto &session : tileSessions) {
if (session.second == true) {
return false;
}
}
return true;
}
ze_result_t DebugSessionImp::interrupt(ze_device_thread_t thread) {
if (areRequestedThreadsStopped(thread)) {
return ZE_RESULT_ERROR_NOT_AVAILABLE;

View File

@ -13,6 +13,7 @@
#include <condition_variable>
#include <mutex>
#include <queue>
#include <unordered_set>
namespace SIP {
struct StateSaveAreaHeader;
@ -31,7 +32,10 @@ struct DebugSessionImp : DebugSession {
Unknown
};
DebugSessionImp(const zet_debug_config_t &config, Device *device) : DebugSession(config, device) {}
DebugSessionImp(const zet_debug_config_t &config, Device *device) : DebugSession(config, device) {
tileAttachEnabled = NEO::DebugManager.flags.ExperimentalEnableTileAttach.get();
createEuThreads();
}
ze_result_t interrupt(ze_device_thread_t thread) override;
ze_result_t resume(ze_device_thread_t thread) override;
@ -40,6 +44,10 @@ struct DebugSessionImp : DebugSession {
ze_result_t writeRegisters(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) override;
ze_result_t readEvent(uint64_t timeout, zet_debug_event_t *event) override;
DebugSession *attachTileDebugSession(Device *device) override;
void detachTileDebugSession(DebugSession *tileSession) override;
bool areAllTileDebugSessionDetached() override;
static const SIP::regset_desc *getSbaRegsetDesc();
static uint32_t typeToRegsetFlags(uint32_t type);
constexpr static int64_t interruptTimeout = 2000;
@ -125,6 +133,9 @@ struct DebugSessionImp : DebugSession {
std::vector<EuThread::ThreadId> newlyStoppedThreads;
std::vector<char> stateSaveAreaHeader;
std::vector<std::pair<DebugSession *, bool>> tileSessions; // DebugSession, attached
bool tileAttachEnabled = false;
ThreadHelper asyncThread;
std::mutex asyncThreadMutex;

View File

@ -43,6 +43,10 @@ DebugSessionLinux::DebugSessionLinux(const zet_debug_config_t &config, Device *d
DebugSessionLinux::~DebugSessionLinux() {
closeAsyncThread();
closeInternalEventsThread();
for (auto &session : tileSessions) {
delete session.first;
}
tileSessions.resize(0);
}
DebugSession *DebugSession::create(const zet_debug_config_t &config, Device *device, ze_result_t &result) {
@ -240,6 +244,16 @@ ze_result_t DebugSessionLinux::initialize() {
return ZE_RESULT_NOT_READY;
}
auto numTiles = connectedDevice->getNEODevice()->getNumSubDevices();
if (numTiles > 0 && tileAttachEnabled) {
tileSessions.resize(numTiles);
zet_debug_config_t config = {};
for (uint32_t i = 0; i < numTiles; i++) {
auto subDevice = connectedDevice->getNEODevice()->getSubDevice(i)->getSpecializedDevice<Device>();
tileSessions[i] = std::pair<DebugSession *, bool>{new TileDebugSessionLinux(config, subDevice, this), false};
}
}
startInternalEventsThread();
bool allEventsCollected = false;
@ -1603,4 +1617,34 @@ ze_device_thread_t DebugSessionLinux::convertToApi(EuThread::ThreadId threadId)
return thread;
}
ze_result_t TileDebugSessionLinux::interrupt(ze_device_thread_t thread) {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
};
ze_result_t TileDebugSessionLinux::resume(ze_device_thread_t thread) {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
};
ze_result_t TileDebugSessionLinux::readMemory(ze_device_thread_t thread, const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer) {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
};
ze_result_t TileDebugSessionLinux::writeMemory(ze_device_thread_t thread, const zet_debug_memory_space_desc_t *desc, size_t size, const void *buffer) {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
};
ze_result_t TileDebugSessionLinux::acknowledgeEvent(const zet_debug_event_t *event) {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
};
ze_result_t TileDebugSessionLinux::readRegisters(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
};
ze_result_t TileDebugSessionLinux::writeRegisters(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
};
} // namespace L0

View File

@ -12,6 +12,7 @@
#include "shared/source/os_interface/linux/sys_calls.h"
#include "level_zero/core/source/device/device.h"
#include "level_zero/core/source/device/device_imp.h"
#include "level_zero/tools/source/debug/debug_session.h"
#include "level_zero/tools/source/debug/debug_session_imp.h"
@ -28,6 +29,9 @@ struct EngineClassInstance;
namespace L0 {
struct DebugSessionLinux : DebugSessionImp {
friend struct TileDebugSessionLinux;
~DebugSessionLinux() override;
DebugSessionLinux(const zet_debug_config_t &config, Device *device, int debugFd);
@ -150,6 +154,7 @@ struct DebugSessionLinux : DebugSessionImp {
};
static ze_result_t translateDebuggerOpenErrno(int error);
constexpr static uint64_t invalidClientHandle = std::numeric_limits<uint64_t>::max();
constexpr static uint64_t invalidHandle = std::numeric_limits<uint64_t>::max();
@ -261,4 +266,46 @@ struct DebugSessionLinux : DebugSessionImp {
std::unordered_map<uint64_t, std::unique_ptr<ClientConnection>> clientHandleToConnection;
};
struct TileDebugSessionLinux : DebugSessionLinux {
TileDebugSessionLinux(zet_debug_config_t config, Device *device, DebugSessionImp *rootDebugSession) : DebugSessionLinux(config, device, 0),
rootDebugSession(reinterpret_cast<DebugSessionLinux *>(rootDebugSession)){};
~TileDebugSessionLinux() override = default;
bool closeConnection() override { return true; };
ze_result_t initialize() override { return ZE_RESULT_SUCCESS; };
ze_result_t interrupt(ze_device_thread_t thread) override;
ze_result_t resume(ze_device_thread_t thread) override;
ze_result_t readMemory(ze_device_thread_t thread, const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer) override;
ze_result_t writeMemory(ze_device_thread_t thread, const zet_debug_memory_space_desc_t *desc, size_t size, const void *buffer) override;
ze_result_t acknowledgeEvent(const zet_debug_event_t *event) override;
ze_result_t readRegisters(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) override;
ze_result_t writeRegisters(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) override;
protected:
void startAsyncThread() override { UNRECOVERABLE_IF(true); };
bool readModuleDebugArea() override { return true; };
uint64_t getContextStateSaveAreaGpuVa(uint64_t memoryHandle) override {
return 0;
};
void readStateSaveAreaHeader() override{};
ze_result_t readGpuMemory(uint64_t vmHandle, char *output, size_t size, uint64_t gpuVa) override {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
};
ze_result_t writeGpuMemory(uint64_t vmHandle, const char *input, size_t size, uint64_t gpuVa) override {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
};
ze_result_t readSbaBuffer(EuThread::ThreadId threadId, NEO::SbaTrackedAddresses &sbaBuffer) override {
return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE;
};
DebugSessionLinux *rootDebugSession = nullptr;
};
} // namespace L0

View File

@ -6,6 +6,7 @@
*/
#include "shared/source/helpers/hw_helper.h"
#include "shared/test/common/libult/global_environment.h"
#include "shared/test/common/mocks/mock_device.h"
#include "shared/test/common/mocks/mock_gmm_helper.h"
#include "shared/test/common/mocks/mock_sip.h"
@ -15,9 +16,11 @@
#include "level_zero/core/source/device/device_imp.h"
#include "level_zero/core/source/hw_helpers/l0_hw_helper.h"
#include "level_zero/core/test/unit_tests/fixtures/device_fixture.h"
#include "level_zero/core/test/unit_tests/mocks/mock_built_ins.h"
#include "level_zero/core/test/unit_tests/mocks/mock_device.h"
#include "level_zero/include/zet_intel_gpu_debug.h"
#include "level_zero/tools/source/debug/debug_session_imp.h"
#include "level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h"
#include "common/StateSaveAreaHeader.h"
#include "encode_surface_state_args.h"
@ -57,12 +60,31 @@ struct MockDebugSession : public L0::DebugSessionImp {
using L0::DebugSessionImp::newlyStoppedThreads;
using L0::DebugSessionImp::pendingInterrupts;
using L0::DebugSessionImp::readStateSaveAreaHeader;
using L0::DebugSessionImp::tileSessions;
MockDebugSession(const zet_debug_config_t &config, L0::Device *device) : DebugSessionImp(config, device) {
}
~MockDebugSession() {
for (auto session : tileSessions) {
delete session.first;
}
}
bool closeConnection() override { return true; }
ze_result_t initialize() override {
auto numTiles = connectedDevice->getNEODevice()->getNumSubDevices();
if (numTiles > 0 && tileAttachEnabled) {
tileSessions.resize(numTiles);
zet_debug_config_t config = {};
for (uint32_t i = 0; i < numTiles; i++) {
auto subDevice = connectedDevice->getNEODevice()->getSubDevice(i)->getSpecializedDevice<Device>();
tileSessions[i] = std::pair<DebugSession *, bool>{new MockDebugSession(config, subDevice), false};
}
}
return ZE_RESULT_SUCCESS;
}
@ -2230,5 +2252,208 @@ TEST(DebugSessionTest, givenNoPendingInterruptsWhenSendInterruptsCalledThenNoInt
EXPECT_FALSE(sessionMock->interruptSent);
}
TEST(DebugSessionTest, GivenRootDeviceAndTileAttachWhenDebugSessionIsCreatedThenThreadsAreNotCreated) {
DebugManagerStateRestore restorer;
NEO::DebugManager.flags.ExperimentalEnableTileAttach.set(1);
zet_debug_config_t config = {};
config.pid = 0x1234;
auto hwInfo = *NEO::defaultHwInfo.get();
NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment<NEO::MockDevice>(&hwInfo, 0));
Mock<L0::DeviceImp> deviceImp(neoDevice, neoDevice->getExecutionEnvironment());
auto sessionMock = std::make_unique<MockDebugSession>(config, &deviceImp);
ASSERT_NE(nullptr, sessionMock);
EXPECT_EQ(0u, sessionMock->allThreads.size());
}
TEST(DebugSessionTest, GivenSubDeviceAndTileAttachWhenDebugSessionIsCreatedThenThreadsAreCreated) {
DebugManagerStateRestore restorer;
NEO::DebugManager.flags.ExperimentalEnableTileAttach.set(1);
zet_debug_config_t config = {};
config.pid = 0x1234;
auto hwInfo = *NEO::defaultHwInfo.get();
NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment<NEO::MockDevice>(&hwInfo, 0));
neoDevice->incRefInternal();
auto subDevice = NEO::Device::create<NEO::MockSubDevice>(neoDevice->getExecutionEnvironment(), 0, *neoDevice);
subDevice->incRefInternal();
{
auto deviceImp = std::make_unique<Mock<L0::DeviceImp>>(subDevice, subDevice->getExecutionEnvironment());
auto sessionMock = std::make_unique<MockDebugSession>(config, deviceImp.get());
ASSERT_NE(nullptr, sessionMock);
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);
auto total = hwInfo.gtSystemInfo.MaxSlicesSupported * numSubslicesPerSlice * numEuPerSubslice * numThreadsPerEu;
EXPECT_EQ(total, sessionMock->allThreads.size());
}
delete subDevice;
delete neoDevice;
}
TEST_F(MultiTileDebugSessionTest, GivenSubDeviceAndTileAttachWhenRootDeviceDebugSessionCreateFailsThenTileAttachFails) {
DebugManagerStateRestore restorer;
NEO::DebugManager.flags.ExperimentalEnableTileAttach.set(1);
if (!hwInfo.capabilityTable.l0DebuggerSupported) {
GTEST_SKIP();
}
zet_debug_config_t config = {};
config.pid = 0x1234;
L0::Device *device = driverHandle->devices[0];
auto neoDevice = device->getNEODevice();
device->getNEODevice()->getExecutionEnvironment()->releaseRootDeviceEnvironmentResources(neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0].get());
auto mockBuiltIns = new MockBuiltins();
neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0]->builtins.reset(mockBuiltIns);
auto osInterface = new OsInterfaceWithDebugAttach;
osInterface->debugAttachAvailable = false;
neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0]->osInterface.reset(osInterface);
auto subDevice0 = neoDevice->getSubDevice(0)->getSpecializedDevice<Device>();
zet_debug_session_handle_t debugSesion = nullptr;
auto retVal = zetDebugAttach(subDevice0->toHandle(), &config, &debugSesion);
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, retVal);
}
TEST_F(MultiTileDebugSessionTest, givenTileAttachEnabledWhenGettingDebugPropertiesThenDebugAttachIsSetForSubdevices) {
DebugManagerStateRestore restorer;
NEO::DebugManager.flags.ExperimentalEnableTileAttach.set(1);
if (!hwInfo.capabilityTable.l0DebuggerSupported) {
GTEST_SKIP();
}
L0::Device *device = driverHandle->devices[0];
auto neoDevice = device->getNEODevice();
device->getNEODevice()->getExecutionEnvironment()->releaseRootDeviceEnvironmentResources(neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0].get());
auto mockBuiltIns = new MockBuiltins();
neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0]->builtins.reset(mockBuiltIns);
neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0]->osInterface.reset(new OsInterfaceWithDebugAttach);
auto subDevice0 = neoDevice->getSubDevice(0)->getSpecializedDevice<Device>();
auto subDevice1 = neoDevice->getSubDevice(1)->getSpecializedDevice<Device>();
zet_device_debug_properties_t debugProperties = {};
debugProperties.flags = ZET_DEVICE_DEBUG_PROPERTY_FLAG_FORCE_UINT32;
auto result = zetDeviceGetDebugProperties(device->toHandle(), &debugProperties);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
EXPECT_EQ(0u, debugProperties.flags);
result = zetDeviceGetDebugProperties(subDevice0->toHandle(), &debugProperties);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
EXPECT_EQ(zet_device_debug_property_flag_t::ZET_DEVICE_DEBUG_PROPERTY_FLAG_ATTACH, debugProperties.flags);
result = zetDeviceGetDebugProperties(subDevice1->toHandle(), &debugProperties);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
EXPECT_EQ(zet_device_debug_property_flag_t::ZET_DEVICE_DEBUG_PROPERTY_FLAG_ATTACH, debugProperties.flags);
}
TEST_F(MultiTileDebugSessionTest, givenTileAttachEnabledWhenAttachingToRootDeviceThenErrorIsReturned) {
DebugManagerStateRestore restorer;
NEO::DebugManager.flags.ExperimentalEnableTileAttach.set(1);
zet_debug_config_t config = {};
config.pid = 0x1234;
zet_debug_session_handle_t debugSession = nullptr;
L0::Device *device = driverHandle->devices[0];
device->getNEODevice()->getExecutionEnvironment()->rootDeviceEnvironments[0]->osInterface.reset(new OsInterfaceWithDebugAttach);
auto result = zetDebugAttach(device->toHandle(), &config, &debugSession);
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result);
}
TEST_F(MultiTileDebugSessionTest, givenTileAttachEnabledWhenAttachingToTileDevicesThenDebugSessionForRootIsCreatedAndTileSessionsAreReturned) {
DebugManagerStateRestore restorer;
NEO::DebugManager.flags.ExperimentalEnableTileAttach.set(1);
zet_debug_config_t config = {};
config.pid = 0x1234;
zet_debug_session_handle_t debugSession0 = nullptr, debugSession1 = nullptr;
L0::Device *device = driverHandle->devices[0];
auto neoDevice = device->getNEODevice();
auto deviceImp = static_cast<DeviceImp *>(device);
neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0]->osInterface.reset(new OsInterfaceWithDebugAttach);
auto sessionMock = new MockDebugSession(config, device);
sessionMock->initialize();
deviceImp->setDebugSession(sessionMock);
auto subDevice0 = neoDevice->getSubDevice(0)->getSpecializedDevice<Device>();
auto subDevice1 = neoDevice->getSubDevice(1)->getSpecializedDevice<Device>();
auto result = zetDebugAttach(subDevice0->toHandle(), &config, &debugSession0);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
EXPECT_NE(nullptr, debugSession0);
EXPECT_TRUE(sessionMock->tileSessions[0].second);
EXPECT_EQ(sessionMock->tileSessions[0].first, L0::DebugSession::fromHandle(debugSession0));
EXPECT_NE(nullptr, deviceImp->getDebugSession(config));
result = zetDebugAttach(subDevice1->toHandle(), &config, &debugSession1);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
EXPECT_NE(nullptr, debugSession1);
EXPECT_TRUE(sessionMock->tileSessions[1].second);
EXPECT_EQ(sessionMock->tileSessions[1].first, L0::DebugSession::fromHandle(debugSession1));
result = zetDebugDetach(debugSession1);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
EXPECT_NE(nullptr, deviceImp->getDebugSession(config));
EXPECT_FALSE(sessionMock->tileSessions[1].second);
result = zetDebugDetach(debugSession0);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
EXPECT_EQ(nullptr, deviceImp->getDebugSession(config));
}
TEST_F(MultiTileDebugSessionTest, givenTileAttachEnabledWhenTileAttachFailsDuringDebugSessionCreateThenErrorIsReturned) {
DebugManagerStateRestore restorer;
NEO::DebugManager.flags.ExperimentalEnableTileAttach.set(1);
zet_debug_config_t config = {};
config.pid = 0x1234;
L0::Device *device = driverHandle->devices[0];
auto neoDevice = device->getNEODevice();
auto deviceImp = static_cast<DeviceImp *>(device);
neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0]->osInterface.reset(new OsInterfaceWithDebugAttach);
auto sessionMock = new MockDebugSession(config, device);
sessionMock->initialize();
deviceImp->setDebugSession(sessionMock);
sessionMock->tileSessions[0].second = true;
auto subDevice0 = neoDevice->getSubDevice(0)->getSpecializedDevice<Device>();
ze_result_t result = ZE_RESULT_SUCCESS;
auto debugSession = subDevice0->createDebugSession(config, result);
EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, result);
EXPECT_EQ(nullptr, debugSession);
}
} // namespace ult
} // namespace L0

View File

@ -9,6 +9,7 @@ if(UNIX)
target_sources(${TARGET_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt
${CMAKE_CURRENT_SOURCE_DIR}/test_debug_api_linux.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tile_debug_session_linux_tests.cpp
)
endif()
endif()

View File

@ -262,6 +262,7 @@ struct MockDebugSessionLinux : public L0::DebugSessionLinux {
using L0::DebugSessionImp::interruptSent;
using L0::DebugSessionImp::isValidGpuAddress;
using L0::DebugSessionImp::stateSaveAreaHeader;
using L0::DebugSessionImp::tileSessions;
using L0::DebugSessionImp::triggerEvents;
using L0::DebugSessionLinux::asyncThread;
@ -1011,6 +1012,21 @@ TEST_F(DebugApiLinuxTest, GivenSuccessfulInitializationWhenCreatingDebugSessionT
EXPECT_TRUE(mockSession->asyncThreadStarted);
}
TEST_F(DebugApiLinuxTest, GivenRootDeviceWhenDebugSessionIsCreatedForTheSecondTimeThenSuccessIsReturned) {
zet_debug_config_t config = {};
config.pid = 0x1234;
ze_result_t result = ZE_RESULT_SUCCESS;
auto sessionMock = device->createDebugSession(config, result);
ASSERT_NE(nullptr, sessionMock);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
auto sessionMock2 = device->createDebugSession(config, result);
EXPECT_EQ(sessionMock, sessionMock2);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
}
TEST_F(DebugApiLinuxTest, GivenClientAndMatchingUuidEventsWhenReadingEventsThenProcessEntryIsReturned) {
zet_debug_config_t config = {};
config.pid = 0x1234;
@ -6765,5 +6781,41 @@ TEST_F(DebugApiLinuxMultitileTest, GivenMultitileDeviceWhenCallingAreRequestedTh
stopped = sessionMock->areRequestedThreadsStopped(allSlices);
EXPECT_TRUE(stopped);
}
TEST_F(DebugApiLinuxMultitileTest, GivenTileAttachEnabledAndMultitileDeviceWhenInitializingDebugSessionThenTileSessionsAreCreated) {
DebugManagerStateRestore restorer;
NEO::DebugManager.flags.ExperimentalEnableTileAttach.set(1);
zet_debug_config_t config = {};
config.pid = 0x1234;
auto session = std::make_unique<MockDebugSessionLinux>(config, deviceImp, 10);
ASSERT_NE(nullptr, session);
auto handler = new MockIoctlHandler;
handler->pollRetVal = 1;
prelim_drm_i915_debug_event_client clientCreate = {};
clientCreate.base.type = PRELIM_DRM_I915_DEBUG_EVENT_CLIENT;
clientCreate.base.flags = PRELIM_DRM_I915_DEBUG_EVENT_CREATE;
clientCreate.base.size = sizeof(prelim_drm_i915_debug_event_client);
clientCreate.handle = MockDebugSessionLinux::mockClientHandle;
handler->eventQueue.push({reinterpret_cast<char *>(&clientCreate), static_cast<uint64_t>(clientCreate.base.size)});
session->ioctlHandler.reset(handler);
session->clientHandle = MockDebugSessionLinux::mockClientHandle;
session->clientHandleToConnection[session->clientHandle]->vmToContextStateSaveAreaBindInfo[1u] = {0x1000, 0x1000};
session->initialize();
ASSERT_EQ(numSubDevices, session->tileSessions.size());
EXPECT_EQ(neoDevice->getSubDevice(0)->getSpecializedDevice<L0::Device>(), session->tileSessions[0].first->getConnectedDevice());
EXPECT_EQ(neoDevice->getSubDevice(1)->getSpecializedDevice<L0::Device>(), session->tileSessions[1].first->getConnectedDevice());
EXPECT_FALSE(session->tileSessions[0].second);
EXPECT_FALSE(session->tileSessions[1].second);
}
} // namespace ult
} // namespace L0

View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 2022 Intel Corporation
*
* SPDX-License-Identifier: MIT
*
*/
#include "shared/test/common/helpers/gtest_helpers.h"
#include "shared/test/common/test_macros/test.h"
#include "level_zero/core/source/device/device_imp.h"
#include "level_zero/core/test/unit_tests/fixtures/device_fixture.h"
#include "level_zero/tools/source/debug/linux/prelim/debug_session.h"
#include "level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h"
namespace L0 {
namespace ult {
struct MockTileDebugSessionLinux : TileDebugSessionLinux {
using DebugSessionImp::stateSaveAreaHeader;
using TileDebugSessionLinux::getContextStateSaveAreaGpuVa;
using TileDebugSessionLinux::readGpuMemory;
using TileDebugSessionLinux::readModuleDebugArea;
using TileDebugSessionLinux::readSbaBuffer;
using TileDebugSessionLinux::readStateSaveAreaHeader;
using TileDebugSessionLinux::startAsyncThread;
using TileDebugSessionLinux::TileDebugSessionLinux;
using TileDebugSessionLinux::writeGpuMemory;
};
TEST(TileDebugSessionLinuxTest, GivenTileDebugSessionWhenCallingFunctionsThenUnsupportedErrorIsReturnedOrImplementationIsEmpty) {
auto hwInfo = *NEO::defaultHwInfo.get();
NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment<NEO::MockDevice>(&hwInfo, 0));
neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface);
Mock<L0::DeviceImp> deviceImp(neoDevice, neoDevice->getExecutionEnvironment());
auto session = std::make_unique<MockTileDebugSessionLinux>(zet_debug_config_t{0x1234}, &deviceImp, nullptr);
ASSERT_NE(nullptr, session);
ze_device_thread_t thread = {0, 0, 0, 0};
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, session->interrupt(thread));
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, session->resume(thread));
zet_debug_memory_space_desc_t desc = {};
size_t size = 10;
char buffer[10];
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, session->readMemory(thread, &desc, size, buffer));
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, session->writeMemory(thread, &desc, size, buffer));
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, session->readGpuMemory(0, nullptr, 0, 0));
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, session->writeGpuMemory(0, nullptr, 0, 0));
zet_debug_event_t event = {};
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, session->acknowledgeEvent(&event));
uint32_t type = 0;
uint32_t start = 0;
uint32_t count = 1;
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, session->readRegisters(thread, type, start, count, nullptr));
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, session->writeRegisters(thread, type, start, count, nullptr));
EuThread::ThreadId threadId{0, 0, 0, 0, 0};
NEO::SbaTrackedAddresses sbaBuffer = {};
EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, session->readSbaBuffer(threadId, sbaBuffer));
EXPECT_TRUE(session->closeConnection());
EXPECT_TRUE(session->readModuleDebugArea());
EXPECT_EQ(ZE_RESULT_SUCCESS, session->initialize());
EXPECT_EQ(0u, session->getContextStateSaveAreaGpuVa(0));
session->readStateSaveAreaHeader();
EXPECT_TRUE(session->stateSaveAreaHeader.empty());
EXPECT_THROW(session->startAsyncThread(), std::exception);
}
} // namespace ult
} // namespace L0

View File

@ -31,7 +31,9 @@ struct DebugSessionMock : public L0::DebugSession {
using L0::DebugSession::getSingleThreadsForDevice;
using L0::DebugSession::isBindlessSystemRoutine;
DebugSessionMock(const zet_debug_config_t &config, L0::Device *device) : DebugSession(config, device), config(config){};
DebugSessionMock(const zet_debug_config_t &config, L0::Device *device) : DebugSession(config, device), config(config) {
createEuThreads();
};
bool closeConnection() override { return true; }
ze_result_t initialize() override {
if (config.pid == 0) {
@ -74,6 +76,13 @@ struct DebugSessionMock : public L0::DebugSession {
return true;
}
void detachTileDebugSession(DebugSession *tileSession) override {}
bool areAllTileDebugSessionDetached() override { return true; }
L0::DebugSession *attachTileDebugSession(L0::Device *device) override {
return nullptr;
}
zet_debug_config_t config;
bool asyncThreadStarted = false;
};

View File

@ -188,6 +188,21 @@ TEST_F(DebugApiWindowsTest, givenDebugAttachIsNotAvailableWhenGetDebugProperties
EXPECT_EQ(0u, debugProperties.flags);
}
TEST_F(DebugApiWindowsTest, GivenRootDeviceWhenDebugSessionIsCreatedForTheSecondTimeThenSuccessIsReturned) {
zet_debug_config_t config = {};
config.pid = 0x1234;
ze_result_t result = ZE_RESULT_SUCCESS;
auto sessionMock = device->createDebugSession(config, result);
ASSERT_NE(nullptr, sessionMock);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
auto sessionMock2 = device->createDebugSession(config, result);
EXPECT_EQ(sessionMock, sessionMock2);
EXPECT_EQ(ZE_RESULT_SUCCESS, result);
}
using isDebugSupportedProduct = IsWithinProducts<IGFX_DG1, IGFX_PVC>;
HWTEST2_F(DebugApiWindowsTest, givenDebugAttachAvailableWhenGetDebugPropertiesCalledThenCorrectFlagIsReturned, isDebugSupportedProduct) {
zet_device_debug_properties_t debugProperties = {};

View File

@ -417,6 +417,7 @@ DECLARE_DEBUG_VARIABLE(int32_t, ExperimentalSetWalkerPartitionType, -1, "Experim
DECLARE_DEBUG_VARIABLE(int32_t, ExperimentalEnableCustomLocalMemoryAlignment, 0, "Align local memory allocations to a given value. Works only with allocations at least as big as the value. 0: no effect, 2097152: 2 megabytes, 1073741824: 1 gigabyte")
DECLARE_DEBUG_VARIABLE(bool, ExperimentalEnableSourceLevelDebugger, false, "Experimentally enable source level debugger.")
DECLARE_DEBUG_VARIABLE(bool, ExperimentalEnableL0DebuggerForOpenCL, false, "Experimentally enable debugging OCL with L0 Debug API.")
DECLARE_DEBUG_VARIABLE(bool, ExperimentalEnableTileAttach, false, "Experimentally enable attaching to tiles (subdevices).")
DECLARE_DEBUG_VARIABLE(bool, ExperimentalEnableDeviceAllocationCache, false, "Experimentally enable allocation cache.")
/*DRIVER TOGGLES*/

View File

@ -446,3 +446,4 @@ ExperimentalEnableL0DebuggerForOpenCL = 0
DebuggerDisableSingleAddressSbaTracking = 0
ForceImagesSupport = -1
ForceCsrLockInBcsEnqueueOnlyForGpgpuSubmission = -1
ExperimentalEnableTileAttach = 0