diff --git a/level_zero/core/source/device/device_imp.cpp b/level_zero/core/source/device/device_imp.cpp index 8cc70b477f..74d14c2f08 100644 --- a/level_zero/core/source/device/device_imp.cpp +++ b/level_zero/core/source/device/device_imp.cpp @@ -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(); + + 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); diff --git a/level_zero/core/source/device/device_imp.h b/level_zero/core/source/device/device_imp.h index d11680b51b..e348ae4771 100644 --- a/level_zero/core/source/device/device_imp.h +++ b/level_zero/core/source/device/device_imp.h @@ -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, diff --git a/level_zero/tools/source/debug/debug_handlers.cpp b/level_zero/tools/source/debug/debug_handlers.cpp index 4cfca0d871..48f05c2a91 100644 --- a/level_zero/tools/source/debug/debug_handlers.cpp +++ b/level_zero/tools/source/debug/debug_handlers.cpp @@ -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 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 lock(debugSessionMutex); + auto rootL0Device = device->getNEODevice()->getRootDevice()->getSpecializedDevice(); + zet_debug_config_t dummy = {}; + auto rootSession = rootL0Device->getDebugSession(dummy); + rootSession->detachTileDebugSession(session); + + if (rootSession->areAllTileDebugSessionDetached()) { + + rootL0Device->removeDebugSession(); + delete rootSession; + } + } } return ZE_RESULT_SUCCESS; } diff --git a/level_zero/tools/source/debug/debug_session.h b/level_zero/tools/source/debug/debug_session.h index cdf1c4a2cc..91e5a26b1f 100644 --- a/level_zero/tools/source/debug/debug_session.h +++ b/level_zero/tools/source/debug/debug_session.h @@ -30,6 +30,7 @@ struct DebugSession : _zet_debug_session_handle_t { static DebugSession *fromHandle(zet_debug_session_handle_t handle) { return static_cast(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); diff --git a/level_zero/tools/source/debug/debug_session_imp.cpp b/level_zero/tools/source/debug/debug_session_imp.cpp index 74cfe4c067..a2f2b9ef41 100644 --- a/level_zero/tools/source/debug/debug_session_imp.cpp +++ b/level_zero/tools/source/debug/debug_session_imp.cpp @@ -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(thread); + for (uint32_t threadID = 0; threadID < numThreadsPerEu; threadID++) { + + EuThread::ThreadId thread = {tileIndex, sliceID, subsliceID, euID, threadID}; + + allThreads[uint64_t(thread)] = std::make_unique(thread); + } } } } @@ -261,6 +271,36 @@ void DebugSession::printBitmask(uint8_t *bitmask, size_t bitmaskSize) { } } +DebugSession *DebugSessionImp::attachTileDebugSession(Device *device) { + std::unique_lock lock(asyncThreadMutex); + + uint32_t subDeviceIndex = Math::log2(static_cast(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 lock(asyncThreadMutex); + + uint32_t subDeviceIndex = Math::log2(static_cast(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; diff --git a/level_zero/tools/source/debug/debug_session_imp.h b/level_zero/tools/source/debug/debug_session_imp.h index 0b800520cd..527cbb7f84 100644 --- a/level_zero/tools/source/debug/debug_session_imp.h +++ b/level_zero/tools/source/debug/debug_session_imp.h @@ -13,6 +13,7 @@ #include #include #include +#include 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 newlyStoppedThreads; std::vector stateSaveAreaHeader; + std::vector> tileSessions; // DebugSession, attached + bool tileAttachEnabled = false; + ThreadHelper asyncThread; std::mutex asyncThreadMutex; diff --git a/level_zero/tools/source/debug/linux/prelim/debug_session.cpp b/level_zero/tools/source/debug/linux/prelim/debug_session.cpp index e4226f1b86..8be2229c02 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session.cpp +++ b/level_zero/tools/source/debug/linux/prelim/debug_session.cpp @@ -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(); + tileSessions[i] = std::pair{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 diff --git a/level_zero/tools/source/debug/linux/prelim/debug_session.h b/level_zero/tools/source/debug/linux/prelim/debug_session.h index 548c198b51..37f773f225 100644 --- a/level_zero/tools/source/debug/linux/prelim/debug_session.h +++ b/level_zero/tools/source/debug/linux/prelim/debug_session.h @@ -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::max(); constexpr static uint64_t invalidHandle = std::numeric_limits::max(); @@ -261,4 +266,46 @@ struct DebugSessionLinux : DebugSessionImp { std::unordered_map> clientHandleToConnection; }; +struct TileDebugSessionLinux : DebugSessionLinux { + TileDebugSessionLinux(zet_debug_config_t config, Device *device, DebugSessionImp *rootDebugSession) : DebugSessionLinux(config, device, 0), + rootDebugSession(reinterpret_cast(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 diff --git a/level_zero/tools/test/unit_tests/sources/debug/debug_session_tests.cpp b/level_zero/tools/test/unit_tests/sources/debug/debug_session_tests.cpp index 1a22c2192e..faadca7313 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/debug_session_tests.cpp +++ b/level_zero/tools/test/unit_tests/sources/debug/debug_session_tests.cpp @@ -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(); + tileSessions[i] = std::pair{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(&hwInfo, 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + + auto sessionMock = std::make_unique(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(&hwInfo, 0)); + neoDevice->incRefInternal(); + + auto subDevice = NEO::Device::create(neoDevice->getExecutionEnvironment(), 0, *neoDevice); + subDevice->incRefInternal(); + { + auto deviceImp = std::make_unique>(subDevice, subDevice->getExecutionEnvironment()); + + auto sessionMock = std::make_unique(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(); + + 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(); + auto subDevice1 = neoDevice->getSubDevice(1)->getSpecializedDevice(); + + 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(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(); + auto subDevice1 = neoDevice->getSubDevice(1)->getSpecializedDevice(); + + 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(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(); + 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 diff --git a/level_zero/tools/test/unit_tests/sources/debug/linux/CMakeLists.txt b/level_zero/tools/test/unit_tests/sources/debug/linux/CMakeLists.txt index 0509646f82..71ddbfe32d 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/linux/CMakeLists.txt +++ b/level_zero/tools/test/unit_tests/sources/debug/linux/CMakeLists.txt @@ -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() diff --git a/level_zero/tools/test/unit_tests/sources/debug/linux/test_debug_api_linux.cpp b/level_zero/tools/test/unit_tests/sources/debug/linux/test_debug_api_linux.cpp index 1520075697..0c2b7e1738 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/linux/test_debug_api_linux.cpp +++ b/level_zero/tools/test/unit_tests/sources/debug/linux/test_debug_api_linux.cpp @@ -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(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(&clientCreate), static_cast(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(), session->tileSessions[0].first->getConnectedDevice()); + EXPECT_EQ(neoDevice->getSubDevice(1)->getSpecializedDevice(), session->tileSessions[1].first->getConnectedDevice()); + + EXPECT_FALSE(session->tileSessions[0].second); + EXPECT_FALSE(session->tileSessions[1].second); +} + } // namespace ult } // namespace L0 diff --git a/level_zero/tools/test/unit_tests/sources/debug/linux/tile_debug_session_linux_tests.cpp b/level_zero/tools/test/unit_tests/sources/debug/linux/tile_debug_session_linux_tests.cpp new file mode 100644 index 0000000000..7934c85836 --- /dev/null +++ b/level_zero/tools/test/unit_tests/sources/debug/linux/tile_debug_session_linux_tests.cpp @@ -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(&hwInfo, 0)); + + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface); + + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + + auto session = std::make_unique(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 diff --git a/level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h b/level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h index ba49566400..24f177f10f 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h +++ b/level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h @@ -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; }; diff --git a/level_zero/tools/test/unit_tests/sources/debug/windows/test_debug_api_windows.cpp b/level_zero/tools/test/unit_tests/sources/debug/windows/test_debug_api_windows.cpp index 69cd550b16..ce3e73380a 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/windows/test_debug_api_windows.cpp +++ b/level_zero/tools/test/unit_tests/sources/debug/windows/test_debug_api_windows.cpp @@ -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; HWTEST2_F(DebugApiWindowsTest, givenDebugAttachAvailableWhenGetDebugPropertiesCalledThenCorrectFlagIsReturned, isDebugSupportedProduct) { zet_device_debug_properties_t debugProperties = {}; diff --git a/shared/source/debug_settings/debug_variables_base.inl b/shared/source/debug_settings/debug_variables_base.inl index 0ef102fb59..a72b9f293d 100644 --- a/shared/source/debug_settings/debug_variables_base.inl +++ b/shared/source/debug_settings/debug_variables_base.inl @@ -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*/ diff --git a/shared/test/common/test_files/igdrcl.config b/shared/test/common/test_files/igdrcl.config index e0e48fbc12..f8268f7872 100644 --- a/shared/test/common/test_files/igdrcl.config +++ b/shared/test/common/test_files/igdrcl.config @@ -446,3 +446,4 @@ ExperimentalEnableL0DebuggerForOpenCL = 0 DebuggerDisableSingleAddressSbaTracking = 0 ForceImagesSupport = -1 ForceCsrLockInBcsEnqueueOnlyForGpgpuSubmission = -1 +ExperimentalEnableTileAttach = 0 \ No newline at end of file