From 89144e494d3584fc3ed69b83eb07e3c0f3d853b8 Mon Sep 17 00:00:00 2001 From: Mateusz Hoppe Date: Wed, 28 Jul 2021 17:30:15 +0000 Subject: [PATCH] Add DebugSession helper methods Signed-off-by: Mateusz Hoppe --- .../tools/source/debug/debug_session.cpp | 43 +++ level_zero/tools/source/debug/debug_session.h | 29 ++ .../sources/debug/debug_session_tests.cpp | 253 ++++++++++++++++++ 3 files changed, 325 insertions(+) diff --git a/level_zero/tools/source/debug/debug_session.cpp b/level_zero/tools/source/debug/debug_session.cpp index d1cfab1c18..2c83ffc4a6 100644 --- a/level_zero/tools/source/debug/debug_session.cpp +++ b/level_zero/tools/source/debug/debug_session.cpp @@ -13,6 +13,49 @@ namespace L0 { +ze_device_thread_t DebugSession::convertToPhysical(ze_device_thread_t thread, uint32_t &deviceIndex) { + auto hwInfo = connectedDevice->getHwInfo(); + auto deviceBitfield = connectedDevice->getNEODevice()->getDeviceBitfield(); + + if (connectedDevice->getNEODevice()->isSubDevice()) { + deviceIndex = Math::log2(static_cast(deviceBitfield.to_ulong())); + } else if (thread.slice != UINT32_MAX) { + deviceIndex = thread.slice / hwInfo.gtSystemInfo.SliceCount; + thread.slice = thread.slice % hwInfo.gtSystemInfo.SliceCount; + } + + return thread; +} + +EuThread::ThreadId DebugSession::convertToThreadId(ze_device_thread_t thread) { + auto hwInfo = connectedDevice->getHwInfo(); + auto deviceBitfield = connectedDevice->getNEODevice()->getDeviceBitfield(); + + UNRECOVERABLE_IF(!DebugSession::isSingleThread(thread)); + + uint32_t deviceIndex = 0; + if (connectedDevice->getNEODevice()->isSubDevice()) { + deviceIndex = Math::log2(static_cast(deviceBitfield.to_ulong())); + } else { + deviceIndex = thread.slice / hwInfo.gtSystemInfo.SliceCount; + thread.slice = thread.slice % hwInfo.gtSystemInfo.SliceCount; + } + + EuThread::ThreadId threadId(deviceIndex, thread.slice, thread.subslice, thread.eu, thread.thread); + return threadId; +} + +ze_device_thread_t DebugSession::convertToApi(EuThread::ThreadId threadId) { + auto hwInfo = connectedDevice->getHwInfo(); + + ze_device_thread_t thread = {static_cast(threadId.slice), static_cast(threadId.subslice), static_cast(threadId.eu), static_cast(threadId.thread)}; + + if (!connectedDevice->getNEODevice()->isSubDevice()) { + thread.slice = thread.slice + static_cast(threadId.tileIndex * hwInfo.gtSystemInfo.SliceCount); + } + return thread; +} + RootDebugSession::RootDebugSession(const zet_debug_config_t &config, Device *device) : DebugSession(config, device) { if (connectedDevice) { diff --git a/level_zero/tools/source/debug/debug_session.h b/level_zero/tools/source/debug/debug_session.h index 9115786d82..a14ea1e9a3 100644 --- a/level_zero/tools/source/debug/debug_session.h +++ b/level_zero/tools/source/debug/debug_session.h @@ -43,6 +43,35 @@ struct DebugSession : _zet_debug_session_handle_t { Device *getConnectedDevice() { return connectedDevice; } + static bool isThreadAll(ze_device_thread_t thread) { + return thread.slice == UINT32_MAX && thread.subslice == UINT32_MAX && thread.eu == UINT32_MAX && thread.thread == UINT32_MAX; + } + + static bool isSingleThread(ze_device_thread_t thread) { + return thread.slice != UINT32_MAX && thread.subslice != UINT32_MAX && thread.eu != UINT32_MAX && thread.thread != UINT32_MAX; + } + + static bool areThreadsEqual(ze_device_thread_t thread, ze_device_thread_t thread2) { + return thread.slice == thread2.slice && thread.subslice == thread2.subslice && thread.eu == thread2.eu && thread.thread == thread2.thread; + } + + static bool checkSingleThreadWithinDeviceThread(ze_device_thread_t checkedThread, ze_device_thread_t thread) { + if (DebugSession::isThreadAll(thread)) { + return true; + } + + bool threadMatch = (thread.thread == checkedThread.thread) || thread.thread == UINT32_MAX; + bool euMatch = (thread.eu == checkedThread.eu) || thread.eu == UINT32_MAX; + bool subsliceMatch = (thread.subslice == checkedThread.subslice) || thread.subslice == UINT32_MAX; + bool sliceMatch = (thread.slice == checkedThread.slice) || thread.slice == UINT32_MAX; + + return threadMatch && euMatch && subsliceMatch && sliceMatch; + } + + virtual ze_device_thread_t convertToPhysical(ze_device_thread_t thread, uint32_t &deviceIndex); + virtual EuThread::ThreadId convertToThreadId(ze_device_thread_t thread); + virtual ze_device_thread_t convertToApi(EuThread::ThreadId threadId); + protected: DebugSession(const zet_debug_config_t &config, Device *device) : connectedDevice(device){}; virtual void startAsyncThread() = 0; 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 79261a9142..3153ab1c1f 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 @@ -7,10 +7,12 @@ #include "shared/test/common/helpers/default_hw_info.h" #include "shared/test/common/mocks/mock_device.h" +#include "shared/test/common/mocks/ult_device_factory.h" #include "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/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" @@ -18,6 +20,142 @@ namespace L0 { namespace ult { +TEST(DebugSession, givenThreadWhenIsThreadAllCalledThenTrueReturnedOnlyForAllValuesEqualMax) { + ze_device_thread_t thread = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX}; + EXPECT_TRUE(DebugSession::isThreadAll(thread)); + + thread = {0, UINT32_MAX, UINT32_MAX, UINT32_MAX}; + EXPECT_FALSE(DebugSession::isThreadAll(thread)); + thread = {UINT32_MAX, 0, UINT32_MAX, UINT32_MAX}; + EXPECT_FALSE(DebugSession::isThreadAll(thread)); + thread = {UINT32_MAX, UINT32_MAX, 0, UINT32_MAX}; + EXPECT_FALSE(DebugSession::isThreadAll(thread)); + thread = {UINT32_MAX, UINT32_MAX, UINT32_MAX, 0}; + EXPECT_FALSE(DebugSession::isThreadAll(thread)); +} + +TEST(DebugSession, givenThreadWhenIsSingleThreadCalledThenTrueReturnedOnlyForNonMaxValues) { + ze_device_thread_t thread = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX}; + EXPECT_FALSE(DebugSession::isSingleThread(thread)); + + thread = {0, UINT32_MAX, UINT32_MAX, UINT32_MAX}; + EXPECT_FALSE(DebugSession::isSingleThread(thread)); + + thread = {UINT32_MAX, 0, UINT32_MAX, UINT32_MAX}; + EXPECT_FALSE(DebugSession::isSingleThread(thread)); + + thread = {UINT32_MAX, UINT32_MAX, 0, UINT32_MAX}; + EXPECT_FALSE(DebugSession::isSingleThread(thread)); + + thread = {UINT32_MAX, UINT32_MAX, UINT32_MAX, 0}; + EXPECT_FALSE(DebugSession::isSingleThread(thread)); + + thread = {UINT32_MAX, UINT32_MAX, 0, 0}; + EXPECT_FALSE(DebugSession::isSingleThread(thread)); + + thread = {UINT32_MAX, 0, 0, 0}; + EXPECT_FALSE(DebugSession::isSingleThread(thread)); + + thread = {UINT32_MAX, 0, UINT32_MAX, 0}; + EXPECT_FALSE(DebugSession::isSingleThread(thread)); + + thread = {0, UINT32_MAX, 0, UINT32_MAX}; + EXPECT_FALSE(DebugSession::isSingleThread(thread)); + + thread = {UINT32_MAX, 0, 0, UINT32_MAX}; + EXPECT_FALSE(DebugSession::isSingleThread(thread)); + + thread = {0, UINT32_MAX, UINT32_MAX, 0}; + EXPECT_FALSE(DebugSession::isSingleThread(thread)); + + thread = {0, 0, UINT32_MAX, 0}; + EXPECT_FALSE(DebugSession::isSingleThread(thread)); + + thread = {0, 0, 0, UINT32_MAX}; + EXPECT_FALSE(DebugSession::isSingleThread(thread)); + + thread = {1, 2, 3, 0}; + EXPECT_TRUE(DebugSession::isSingleThread(thread)); +} + +TEST(DebugSession, givenThreadsWhenAreThreadsEqualCalledThenTrueReturnedForEqualThreads) { + ze_device_thread_t thread = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX}; + ze_device_thread_t thread2 = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX}; + + EXPECT_TRUE(DebugSession::areThreadsEqual(thread, thread2)); + + thread = {0, UINT32_MAX, UINT32_MAX, UINT32_MAX}; + EXPECT_FALSE(DebugSession::areThreadsEqual(thread, thread2)); + thread2 = {UINT32_MAX, 0, UINT32_MAX, UINT32_MAX}; + EXPECT_FALSE(DebugSession::areThreadsEqual(thread, thread2)); + + thread = {1, 0, 0, 0}; + thread2 = {1, 0, 0, UINT32_MAX}; + EXPECT_FALSE(DebugSession::areThreadsEqual(thread, thread2)); + + thread2 = {1, 0, 1, 0}; + EXPECT_FALSE(DebugSession::areThreadsEqual(thread, thread2)); + + thread2 = {1, 1, 0, 0}; + EXPECT_FALSE(DebugSession::areThreadsEqual(thread, thread2)); + + thread2 = {0, 0, 0, 0}; + EXPECT_FALSE(DebugSession::areThreadsEqual(thread, thread2)); + { + ze_device_thread_t thread = {1, 1, 1, 1}; + ze_device_thread_t thread2 = {1, 1, 1, 1}; + + EXPECT_TRUE(DebugSession::areThreadsEqual(thread, thread2)); + } +} + +TEST(DebugSession, givenThreadWhenCheckSingleThreadWithinDeviceThreadCalledThenTrueReturnedForMatchingThread) { + ze_device_thread_t thread = {0, 1, 2, 3}; + ze_device_thread_t thread2 = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX}; + + EXPECT_TRUE(DebugSession::checkSingleThreadWithinDeviceThread(thread, thread2)); + + thread = {0, 1, 2, 3}; + thread2 = {0, UINT32_MAX, UINT32_MAX, UINT32_MAX}; + + EXPECT_TRUE(DebugSession::checkSingleThreadWithinDeviceThread(thread, thread2)); + + thread = {0, 1, 2, 3}; + thread2 = {0, 1, 2, 3}; + + EXPECT_TRUE(DebugSession::checkSingleThreadWithinDeviceThread(thread, thread2)); + + thread = {0, 1, 2, 3}; + thread2 = {0, UINT32_MAX, UINT32_MAX, 4}; + + EXPECT_FALSE(DebugSession::checkSingleThreadWithinDeviceThread(thread, thread2)); + + thread = {0, 1, 2, 3}; + thread2 = {0, 1, 2, 4}; + + EXPECT_FALSE(DebugSession::checkSingleThreadWithinDeviceThread(thread, thread2)); + + thread = {0, 1, 2, 3}; + thread2 = {1, 1, 2, 3}; + + EXPECT_FALSE(DebugSession::checkSingleThreadWithinDeviceThread(thread, thread2)); + + thread = {0, 1, 2, 3}; + thread2 = {0, 2, 2, 3}; + + EXPECT_FALSE(DebugSession::checkSingleThreadWithinDeviceThread(thread, thread2)); + + thread = {0, 1, 3, 3}; + thread2 = {0, 1, 2, 3}; + + EXPECT_FALSE(DebugSession::checkSingleThreadWithinDeviceThread(thread, thread2)); + + thread = {0, 1, 3, 3}; + thread2 = {UINT32_MAX, 0, 2, 3}; + + EXPECT_FALSE(DebugSession::checkSingleThreadWithinDeviceThread(thread, thread2)); +} + TEST(RootDebugSession, givenSingleThreadWhenGettingSingleThreadsThenCorrectThreadIsReturned) { zet_debug_config_t config = {}; config.pid = 0x1234; @@ -165,5 +303,120 @@ TEST(RootDebugSession, givenBindfulSystemRoutineWhenQueryingIsBindlessThenFalseR EXPECT_FALSE(debugSession->isBindlessSystemRoutine()); } +TEST(RootDebugSession, givenApiThreadAndSingleTileWhenConvertingThenCorrectValuesReturned) { + auto hwInfo = *NEO::defaultHwInfo.get(); + NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + auto debugSession = std::make_unique(zet_debug_config_t{0x1234}, &deviceImp); + + ze_device_thread_t thread = {hwInfo.gtSystemInfo.SliceCount - 1, hwInfo.gtSystemInfo.SubSliceCount - 1, 0, 0}; + + uint32_t deviceIndex = 0; + + auto convertedThread = debugSession->convertToPhysical(thread, deviceIndex); + + EXPECT_EQ(0u, deviceIndex); + EXPECT_EQ(convertedThread.slice, thread.slice); + EXPECT_EQ(convertedThread.subslice, thread.subslice); + EXPECT_EQ(convertedThread.eu, thread.eu); + EXPECT_EQ(convertedThread.thread, thread.thread); + + thread.slice = UINT32_MAX; + convertedThread = debugSession->convertToPhysical(thread, deviceIndex); + + EXPECT_EQ(0u, deviceIndex); + EXPECT_EQ(convertedThread.slice, thread.slice); +} + +using DebugSessionMultiTile = Test; + +TEST_F(DebugSessionMultiTile, givenApiThreadAndMultipleTilesWhenConvertingToPhysicalThenCorrectValueReturned) { + L0::Device *device = driverHandle->devices[0]; + + auto debugSession = std::make_unique(zet_debug_config_t{0x1234}, device); + + ze_device_thread_t thread = {sliceCount * 2 - 1, 0, 0, 0}; + + uint32_t deviceIndex = 0; + + auto convertedThread = debugSession->convertToPhysical(thread, deviceIndex); + + EXPECT_EQ(1u, deviceIndex); + EXPECT_EQ(sliceCount - 1, convertedThread.slice); + EXPECT_EQ(thread.subslice, convertedThread.subslice); + EXPECT_EQ(thread.eu, convertedThread.eu); + EXPECT_EQ(thread.thread, convertedThread.thread); + + thread = {sliceCount - 1, 0, 0, 0}; + convertedThread = debugSession->convertToPhysical(thread, deviceIndex); + + EXPECT_EQ(0u, deviceIndex); + EXPECT_EQ(sliceCount - 1, convertedThread.slice); + EXPECT_EQ(thread.subslice, convertedThread.subslice); + EXPECT_EQ(thread.eu, convertedThread.eu); + EXPECT_EQ(thread.thread, convertedThread.thread); + + thread.slice = UINT32_MAX; + convertedThread = debugSession->convertToPhysical(thread, deviceIndex); + + EXPECT_EQ(0u, deviceIndex); + EXPECT_EQ(convertedThread.slice, thread.slice); + + L0::DeviceImp *deviceImp = static_cast(device); + debugSession = std::make_unique(zet_debug_config_t{0x1234}, deviceImp->subDevices[1]); + + thread = {sliceCount - 1, 0, 0, 0}; + deviceIndex = 10; + convertedThread = debugSession->convertToPhysical(thread, deviceIndex); + EXPECT_EQ(1u, deviceIndex); + EXPECT_EQ(sliceCount - 1, convertedThread.slice); + EXPECT_EQ(thread.subslice, convertedThread.subslice); + EXPECT_EQ(thread.eu, convertedThread.eu); + EXPECT_EQ(thread.thread, convertedThread.thread); +} + +TEST_F(DebugSessionMultiTile, WhenConvertingToThreadIdAndBackThenCorrectThreadIdsAreReturned) { + L0::Device *device = driverHandle->devices[0]; + + auto debugSession = std::make_unique(zet_debug_config_t{0x1234}, device); + + ze_device_thread_t thread = {sliceCount * 2 - 1, 0, 0, 0}; + + auto threadID = debugSession->convertToThreadId(thread); + + EXPECT_EQ(1u, threadID.tileIndex); + EXPECT_EQ(sliceCount - 1, threadID.slice); + EXPECT_EQ(thread.subslice, threadID.subslice); + EXPECT_EQ(thread.eu, threadID.eu); + EXPECT_EQ(thread.thread, threadID.thread); + + auto apiThread = debugSession->convertToApi(threadID); + + EXPECT_EQ(thread.slice, apiThread.slice); + EXPECT_EQ(thread.subslice, apiThread.subslice); + EXPECT_EQ(thread.eu, apiThread.eu); + EXPECT_EQ(thread.thread, apiThread.thread); + + L0::DeviceImp *deviceImp = static_cast(device); + debugSession = std::make_unique(zet_debug_config_t{0x1234}, deviceImp->subDevices[1]); + + thread = {sliceCount - 1, 0, 0, 0}; + + threadID = debugSession->convertToThreadId(thread); + + EXPECT_EQ(1u, threadID.tileIndex); + EXPECT_EQ(sliceCount - 1, threadID.slice); + EXPECT_EQ(thread.subslice, threadID.subslice); + EXPECT_EQ(thread.eu, threadID.eu); + EXPECT_EQ(thread.thread, threadID.thread); + + apiThread = debugSession->convertToApi(threadID); + + EXPECT_EQ(thread.slice, apiThread.slice); + EXPECT_EQ(thread.subslice, apiThread.subslice); + EXPECT_EQ(thread.eu, apiThread.eu); + EXPECT_EQ(thread.thread, apiThread.thread); +} + } // namespace ult } // namespace L0