From f4182e37ee121a062c73289400bde39a29052e42 Mon Sep 17 00:00:00 2001 From: Igor Venevtsev Date: Tue, 29 Mar 2022 15:39:27 +0000 Subject: [PATCH] Add debugger support - debug session implementation Resolves: NEO-6813 Signed-off-by: Igor Venevtsev --- .../core/source/dll/linux/CMakeLists.txt | 4 +- level_zero/include/zet_intel_gpu_debug.h | 55 + level_zero/tools/source/debug/CMakeLists.txt | 23 +- .../tools/source/debug/debug_handlers.cpp | 55 +- .../tools/source/debug/debug_session.cpp | 238 -- level_zero/tools/source/debug/debug_session.h | 2 +- .../tools/source/debug/debug_session_imp.cpp | 1001 +++++++ .../tools/source/debug/debug_session_imp.h | 121 + .../tools/source/debug/linux/CMakeLists.txt | 15 + .../source/debug/linux/debug_session.cpp | 18 + .../linux/debug_session_linux_helper.cpp | 2 +- .../tools/source/debug/windows/CMakeLists.txt | 13 + .../source/debug/windows/debug_session.cpp | 18 + .../unit_tests/sources/debug/CMakeLists.txt | 5 +- .../sources/debug/debug_session_tests.cpp | 2581 +++++++++++++---- .../debug/debug_session_thread_tests.cpp | 603 ++++ .../sources/debug/test_debug_api.cpp | 314 +- .../sources/debug/test_debug_api.inl | 200 -- .../sources/debug/windows/CMakeLists.txt | 12 + .../debug/windows/test_debug_api_windows.cpp | 51 + 20 files changed, 4296 insertions(+), 1035 deletions(-) create mode 100644 level_zero/include/zet_intel_gpu_debug.h delete mode 100644 level_zero/tools/source/debug/debug_session.cpp create mode 100644 level_zero/tools/source/debug/debug_session_imp.cpp create mode 100644 level_zero/tools/source/debug/debug_session_imp.h create mode 100644 level_zero/tools/source/debug/linux/CMakeLists.txt create mode 100644 level_zero/tools/source/debug/linux/debug_session.cpp create mode 100644 level_zero/tools/source/debug/windows/CMakeLists.txt create mode 100644 level_zero/tools/source/debug/windows/debug_session.cpp create mode 100644 level_zero/tools/test/unit_tests/sources/debug/debug_session_thread_tests.cpp delete mode 100644 level_zero/tools/test/unit_tests/sources/debug/test_debug_api.inl create mode 100644 level_zero/tools/test/unit_tests/sources/debug/windows/CMakeLists.txt create mode 100644 level_zero/tools/test/unit_tests/sources/debug/windows/test_debug_api_windows.cpp diff --git a/level_zero/core/source/dll/linux/CMakeLists.txt b/level_zero/core/source/dll/linux/CMakeLists.txt index 03c6cf6e97..527de7e5d2 100644 --- a/level_zero/core/source/dll/linux/CMakeLists.txt +++ b/level_zero/core/source/dll/linux/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2020-2021 Intel Corporation +# Copyright (C) 2020-2022 Intel Corporation # # SPDX-License-Identifier: MIT # @@ -7,7 +7,7 @@ set(L0_SRCS_DLL_LINUX ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt ${CMAKE_CURRENT_SOURCE_DIR}/debugger_l0_linux.cpp - ${NEO_SOURCE_DIR}/level_zero/tools/source/debug${BRANCH_DIR_SUFFIX}linux/debug_session_linux_helper.cpp + ${NEO_SOURCE_DIR}/level_zero/tools/source/debug/linux/${BRANCH_DIR_SUFFIX}debug_session_linux_helper.cpp ) set_property(GLOBAL PROPERTY L0_SRCS_DLL_LINUX ${L0_SRCS_DLL_LINUX}) diff --git a/level_zero/include/zet_intel_gpu_debug.h b/level_zero/include/zet_intel_gpu_debug.h new file mode 100644 index 0000000000..489f739291 --- /dev/null +++ b/level_zero/include/zet_intel_gpu_debug.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021-2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#ifndef _ZET_INTEL_GPU_DEBUG_H +#define _ZET_INTEL_GPU_DEBUG_H +#if defined(__cplusplus) +#pragma once +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/////////////////////////////////////////////////////////////////////////////// +/// @brief Supported device-specific register set types. +typedef enum _zet_debug_regset_type_intel_gpu_t { + ZET_DEBUG_REGSET_TYPE_INVALID_INTEL_GPU = 0, ///< An invalid register set + ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU = 1, ///< The general purpose register set + ZET_DEBUG_REGSET_TYPE_ADDR_INTEL_GPU = 2, ///< The address register set + ZET_DEBUG_REGSET_TYPE_FLAG_INTEL_GPU = 3, ///< The flag register set + ZET_DEBUG_REGSET_TYPE_CE_INTEL_GPU = 4, ///< The channel enable register set + ZET_DEBUG_REGSET_TYPE_SR_INTEL_GPU = 5, ///< The status register set + ZET_DEBUG_REGSET_TYPE_CR_INTEL_GPU = 6, ///< The control register set + ZET_DEBUG_REGSET_TYPE_TDR_INTEL_GPU = 7, ///< The thread dependency register set + ZET_DEBUG_REGSET_TYPE_ACC_INTEL_GPU = 8, ///< The accumulator register set + ZET_DEBUG_REGSET_TYPE_MME_INTEL_GPU = 9, ///< The mme register set + ZET_DEBUG_REGSET_TYPE_SP_INTEL_GPU = 10, ///< The stack pointer register set + ZET_DEBUG_REGSET_TYPE_SBA_INTEL_GPU = 11, ///< The state base address register set + ZET_DEBUG_REGSET_TYPE_FORCE_UINT32 = 0x7fffffff +} zet_debug_regset_type_intel_gpu_t; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief SBA register set layout +typedef enum _zet_debug_sba_intel_gpu_t { + ZET_DEBUG_SBA_GENERAL_STATE_INTEL_GPU = 0, ///< GeneralStateBaseAddress + ZET_DEBUG_SBA_SURFACE_STATE_INTEL_GPU = 1, ///< SurfaceStateBaseAddress + ZET_DEBUG_SBA_DYNAMIC_STATE_INTEL_GPU = 2, ///< DynamicStateBaseAddress + ZET_DEBUG_SBA_INDIRECT_OBJECT_INTEL_GPU = 3, ///< IndirectObjectBaseAddress + ZET_DEBUG_SBA_INSTRUCTION_INTEL_GPU = 4, ///< InstructionBaseAddress + ZET_DEBUG_SBA_BINDLESS_SURFACE_INTEL_GPU = 5, ///< BindlessSurfaceStateBaseAddress + ZET_DEBUG_SBA_BINDLESS_SAMPLER_INTEL_GPU = 6, ///< BindlessSamplerStateBaseAddress + ZET_DEBUG_SBA_BINDING_TABLE_INTEL_GPU = 7, ///< BindingTableStateBaseAddress + ZET_DEBUG_SBA_SCRATCH_SPACE_INTEL_GPU = 8, ///< ScratchSpaceBaseAddress + ZET_DEBUG_SBA_COUNT_INTEL_GPU = 9 ///< Number of registers in SBA regster set +} zet_debug_sba_intel_gpu_t; + +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif // _ZET_INTEL_GPU_DEBUG_H diff --git a/level_zero/tools/source/debug/CMakeLists.txt b/level_zero/tools/source/debug/CMakeLists.txt index c495001d38..6614d0d211 100644 --- a/level_zero/tools/source/debug/CMakeLists.txt +++ b/level_zero/tools/source/debug/CMakeLists.txt @@ -1,21 +1,18 @@ # -# Copyright (C) 2021 Intel Corporation +# Copyright (C) 2021-2022 Intel Corporation # # SPDX-License-Identifier: MIT # -set(L0_SRCS_TOOLS_DEBUG - ${CMAKE_CURRENT_SOURCE_DIR}/debug_session.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/debug_session.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 +target_sources(${L0_STATIC_LIB_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/debug_session.h + ${CMAKE_CURRENT_SOURCE_DIR}/debug_session_imp.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/debug_session_imp.h + ${CMAKE_CURRENT_SOURCE_DIR}/debug_handlers.h + ${CMAKE_CURRENT_SOURCE_DIR}/debug_handlers.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/eu_thread.h + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt ) add_subdirectories() - -target_sources(${L0_STATIC_LIB_NAME} - PRIVATE - ${L0_SRCS_TOOLS_DEBUG} - ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt -) diff --git a/level_zero/tools/source/debug/debug_handlers.cpp b/level_zero/tools/source/debug/debug_handlers.cpp index 6438f787c2..4cfca0d871 100644 --- a/level_zero/tools/source/debug/debug_handlers.cpp +++ b/level_zero/tools/source/debug/debug_handlers.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Intel Corporation + * Copyright (C) 2021-2022 Intel Corporation * * SPDX-License-Identifier: MIT * @@ -7,48 +7,65 @@ #include "level_zero/tools/source/debug/debug_handlers.h" +#include "level_zero/core/source/device/device_imp.h" #include "level_zero/tools/source/debug/debug_session.h" namespace L0 { - -DebugSession *DebugSession::create(const zet_debug_config_t &config, Device *device, ze_result_t &result) { - result = ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; - return nullptr; -} - namespace DebugApiHandlers { ze_result_t debugAttach(zet_device_handle_t hDevice, const zet_debug_config_t *config, zet_debug_session_handle_t *phDebug) { - return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + ze_result_t result = ZE_RESULT_SUCCESS; + auto session = L0::Device::fromHandle(hDevice)->getDebugSession(*config); + + if (!session) { + session = L0::Device::fromHandle(hDevice)->createDebugSession(*config, result); + } + + if (session) { + *phDebug = session->toHandle(); + } + return result; } -ze_result_t debugDetach(zet_debug_session_handle_t hDebug) { return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; } +ze_result_t debugDetach(zet_debug_session_handle_t hDebug) { + auto session = L0::DebugSession::fromHandle(hDebug); + if (session) { + auto device = session->getConnectedDevice(); + device->removeDebugSession(); + session->closeConnection(); + delete session; + } + return ZE_RESULT_SUCCESS; +} -ze_result_t debugReadEvent(zet_debug_session_handle_t hDebug, uint64_t timeout, zet_debug_event_t *event) { return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; } +ze_result_t debugReadEvent(zet_debug_session_handle_t hDebug, uint64_t timeout, zet_debug_event_t *event) { return L0::DebugSession::fromHandle(hDebug)->readEvent(timeout, event); } -ze_result_t debugInterrupt(zet_debug_session_handle_t hDebug, ze_device_thread_t thread) { return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; } +ze_result_t debugInterrupt(zet_debug_session_handle_t hDebug, ze_device_thread_t thread) { return L0::DebugSession::fromHandle(hDebug)->interrupt(thread); } -ze_result_t debugResume(zet_debug_session_handle_t hDebug, ze_device_thread_t thread) { return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; } +ze_result_t debugResume(zet_debug_session_handle_t hDebug, ze_device_thread_t thread) { return L0::DebugSession::fromHandle(hDebug)->resume(thread); } ze_result_t debugReadMemory(zet_debug_session_handle_t hDebug, ze_device_thread_t thread, const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer) { - return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + return L0::DebugSession::fromHandle(hDebug)->readMemory(thread, desc, size, buffer); } ze_result_t debugWriteMemory(zet_debug_session_handle_t hDebug, 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; + return L0::DebugSession::fromHandle(hDebug)->writeMemory(thread, desc, size, buffer); } -ze_result_t debugAcknowledgeEvent(zet_debug_session_handle_t hDebug, const zet_debug_event_t *event) { return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; } +ze_result_t debugAcknowledgeEvent(zet_debug_session_handle_t hDebug, const zet_debug_event_t *event) { + return L0::DebugSession::fromHandle(hDebug)->acknowledgeEvent(event); +} ze_result_t debugGetRegisterSetProperties(zet_device_handle_t hDevice, uint32_t *pCount, zet_debug_regset_properties_t *pRegisterSetProperties) { - return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + return L0::DebugSession::getRegisterSetProperties(L0::Device::fromHandle(hDevice), pCount, pRegisterSetProperties); } ze_result_t debugReadRegisters(zet_debug_session_handle_t hDebug, ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) { - return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + return L0::DebugSession::fromHandle(hDebug)->readRegisters(thread, type, start, count, pRegisterValues); } ze_result_t debugWriteRegisters(zet_debug_session_handle_t hDebug, ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) { - return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + return L0::DebugSession::fromHandle(hDebug)->writeRegisters(thread, type, start, count, pRegisterValues); } + } // namespace DebugApiHandlers -} // namespace L0 \ No newline at end of file +} // namespace L0 diff --git a/level_zero/tools/source/debug/debug_session.cpp b/level_zero/tools/source/debug/debug_session.cpp deleted file mode 100644 index 54727d6a17..0000000000 --- a/level_zero/tools/source/debug/debug_session.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (C) 2021-2022 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 { - -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; -} - -DebugSession::DebugSession(const zet_debug_config_t &config, Device *device) : connectedDevice(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 = 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++) { - - for (uint32_t threadID = 0; threadID < numThreadsPerEu; threadID++) { - - EuThread::ThreadId thread = {tileIndex, sliceID, subsliceID, euID, threadID}; - - allThreads[uint64_t(thread)] = std::make_unique(thread); - } - } - } - } - } - } -} - -std::vector DebugSession::getSingleThreadsForDevice(uint32_t deviceIndex, 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 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({deviceIndex, 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; -} - -bool DebugSession::areRequestedThreadsStopped(ze_device_thread_t thread) { - auto &hwInfo = connectedDevice->getHwInfo(); - uint32_t deviceIndex = 0; - auto physicalThread = convertToPhysical(thread, deviceIndex); - auto singleThreads = getSingleThreadsForDevice(deviceIndex, physicalThread, hwInfo); - bool requestedThreadsStopped = true; - - for (auto &threadId : singleThreads) { - - if (allThreads[threadId]->isStopped()) { - continue; - } - requestedThreadsStopped = false; - } - - return requestedThreadsStopped; -} - -ze_result_t DebugSession::sanityMemAccessThreadCheck(ze_device_thread_t thread, const zet_debug_memory_space_desc_t *desc) { - if (DebugSession::isThreadAll(thread)) { - if (desc->type != ZET_DEBUG_MEMORY_SPACE_TYPE_DEFAULT) { - return ZE_RESULT_ERROR_INVALID_ARGUMENT; - } else { - return ZE_RESULT_SUCCESS; - } - } else if (DebugSession::isSingleThread(thread)) { - if (desc->type != ZET_DEBUG_MEMORY_SPACE_TYPE_DEFAULT) { - return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; - } - - if (!areRequestedThreadsStopped(thread)) { - return ZE_RESULT_ERROR_NOT_AVAILABLE; - } else { - return ZE_RESULT_SUCCESS; - } - } - - return ZE_RESULT_ERROR_INVALID_ARGUMENT; -} - -void DebugSession::fillDevicesFromThread(ze_device_thread_t thread, std::vector &devices) { - auto deviceCount = std::max(1u, connectedDevice->getNEODevice()->getNumSubDevices()); - UNRECOVERABLE_IF(devices.size() < deviceCount); - - uint32_t deviceIndex = 0; - convertToPhysical(thread, deviceIndex); - bool singleDevice = (thread.slice != UINT32_MAX && deviceCount > 1) || deviceCount == 1; - - if (singleDevice) { - devices[deviceIndex] = 1; - } else { - for (uint32_t i = 0; i < deviceCount; i++) { - devices[i] = 1; - } - } -} - -bool DebugSession::isBindlessSystemRoutine() { - if (debugArea.reserved1 &= 1) { - return true; - } - return false; -} - -size_t DebugSession::getPerThreadScratchOffset(size_t ptss, EuThread::ThreadId threadId) { - 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); - - const auto &hwInfoConfig = *NEO::HwInfoConfig::get(hwInfo.platform.eProductFamily); - uint32_t threadEuRatio = hwInfoConfig.getThreadEuRatioForScratch(hwInfo); - - if (threadEuRatio / numThreadsPerEu > 1) { - ptss *= threadEuRatio / numThreadsPerEu; - } - - auto threadOffset = (((threadId.slice * numSubslicesPerSlice + threadId.subslice) * numEuPerSubslice + threadId.eu) * numThreadsPerEu + threadId.thread) * ptss; - return threadOffset; -} - -void DebugSession::printBitmask(uint8_t *bitmask, size_t bitmaskSize) { - if (NEO::DebugManager.flags.DebuggerLogBitmask.get() & NEO::DebugVariables::DEBUGGER_LOG_BITMASK::LOG_INFO) { - - DEBUG_BREAK_IF(bitmaskSize % sizeof(uint64_t) != 0); - - PRINT_DEBUGGER_LOG(stdout, "\nINFO: Bitmask: ", ""); - - for (size_t i = 0; i < bitmaskSize / sizeof(uint64_t); i++) { - uint64_t bitmask64 = 0; - memcpy_s(&bitmask64, sizeof(uint64_t), &bitmask[i * sizeof(uint64_t)], sizeof(uint64_t)); - PRINT_DEBUGGER_LOG(stdout, "\n [%lu] = %#018" PRIx64, static_cast(i), bitmask64); - } - } -} - -} // namespace L0 diff --git a/level_zero/tools/source/debug/debug_session.h b/level_zero/tools/source/debug/debug_session.h index 7a76f8e297..8ae8135d80 100644 --- a/level_zero/tools/source/debug/debug_session.h +++ b/level_zero/tools/source/debug/debug_session.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Intel Corporation + * Copyright (C) 2021-2022 Intel Corporation * * SPDX-License-Identifier: MIT * diff --git a/level_zero/tools/source/debug/debug_session_imp.cpp b/level_zero/tools/source/debug/debug_session_imp.cpp new file mode 100644 index 0000000000..0a7c300d75 --- /dev/null +++ b/level_zero/tools/source/debug/debug_session_imp.cpp @@ -0,0 +1,1001 @@ +/* + * Copyright (C) 2021-2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/tools/source/debug/debug_session_imp.h" + +#include "shared/source/helpers/hw_helper.h" + +#include "level_zero/core/source/device/device_imp.h" +#include "level_zero/core/source/hw_helpers/l0_hw_helper.h" +#include "level_zero/include/zet_intel_gpu_debug.h" + +#include "common/StateSaveAreaHeader.h" + +namespace L0 { + +DebugSession::DebugSession(const zet_debug_config_t &config, Device *device) : connectedDevice(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 = 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++) { + + for (uint32_t threadID = 0; threadID < numThreadsPerEu; threadID++) { + + EuThread::ThreadId thread = {tileIndex, sliceID, subsliceID, euID, threadID}; + + allThreads[uint64_t(thread)] = std::make_unique(thread); + } + } + } + } + } + } +} + +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(!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; +} + +std::vector DebugSession::getSingleThreadsForDevice(uint32_t deviceIndex, 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 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({deviceIndex, 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; +} + +bool DebugSession::areRequestedThreadsStopped(ze_device_thread_t thread) { + auto &hwInfo = connectedDevice->getHwInfo(); + uint32_t deviceIndex = 0; + auto physicalThread = DebugSession::convertToPhysical(thread, deviceIndex); + auto singleThreads = getSingleThreadsForDevice(deviceIndex, physicalThread, hwInfo); + bool requestedThreadsStopped = true; + + for (auto &threadId : singleThreads) { + + if (allThreads[threadId]->isStopped()) { + continue; + } + requestedThreadsStopped = false; + } + + return requestedThreadsStopped; +} + +ze_result_t DebugSession::sanityMemAccessThreadCheck(ze_device_thread_t thread, const zet_debug_memory_space_desc_t *desc) { + if (DebugSession::isThreadAll(thread)) { + if (desc->type != ZET_DEBUG_MEMORY_SPACE_TYPE_DEFAULT) { + return ZE_RESULT_ERROR_INVALID_ARGUMENT; + } else { + return ZE_RESULT_SUCCESS; + } + } else if (DebugSession::isSingleThread(thread)) { + if (desc->type != ZET_DEBUG_MEMORY_SPACE_TYPE_DEFAULT) { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + + if (!areRequestedThreadsStopped(thread)) { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } else { + return ZE_RESULT_SUCCESS; + } + } + + return ZE_RESULT_ERROR_INVALID_ARGUMENT; +} + +void DebugSession::fillDevicesFromThread(ze_device_thread_t thread, std::vector &devices) { + auto deviceCount = std::max(1u, connectedDevice->getNEODevice()->getNumSubDevices()); + UNRECOVERABLE_IF(devices.size() < deviceCount); + + uint32_t deviceIndex = 0; + convertToPhysical(thread, deviceIndex); + bool singleDevice = (thread.slice != UINT32_MAX && deviceCount > 1) || deviceCount == 1; + + if (singleDevice) { + devices[deviceIndex] = 1; + } else { + for (uint32_t i = 0; i < deviceCount; i++) { + devices[i] = 1; + } + } +} + +bool DebugSession::isBindlessSystemRoutine() { + if (debugArea.reserved1 &= 1) { + return true; + } + return false; +} + +size_t DebugSession::getPerThreadScratchOffset(size_t ptss, EuThread::ThreadId threadId) { + 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); + + const auto &hwInfoConfig = *NEO::HwInfoConfig::get(hwInfo.platform.eProductFamily); + uint32_t threadEuRatio = hwInfoConfig.getThreadEuRatioForScratch(hwInfo); + + if (threadEuRatio / numThreadsPerEu > 1) { + ptss *= threadEuRatio / numThreadsPerEu; + } + + auto threadOffset = (((threadId.slice * numSubslicesPerSlice + threadId.subslice) * numEuPerSubslice + threadId.eu) * numThreadsPerEu + threadId.thread) * ptss; + return threadOffset; +} + +void DebugSession::printBitmask(uint8_t *bitmask, size_t bitmaskSize) { + if (NEO::DebugManager.flags.DebuggerLogBitmask.get() & NEO::DebugVariables::DEBUGGER_LOG_BITMASK::LOG_INFO) { + + DEBUG_BREAK_IF(bitmaskSize % sizeof(uint64_t) != 0); + + PRINT_DEBUGGER_LOG(stdout, "\nINFO: Bitmask: ", ""); + + for (size_t i = 0; i < bitmaskSize / sizeof(uint64_t); i++) { + uint64_t bitmask64 = 0; + memcpy_s(&bitmask64, sizeof(uint64_t), &bitmask[i * sizeof(uint64_t)], sizeof(uint64_t)); + PRINT_DEBUGGER_LOG(stdout, "\n [%lu] = %#018" PRIx64, static_cast(i), bitmask64); + } + } +} + +ze_result_t DebugSessionImp::interrupt(ze_device_thread_t thread) { + if (areRequestedThreadsStopped(thread)) { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + + { + std::unique_lock lock(interruptMutex); + + for (auto &previousThread : pendingInterrupts) { + if (areThreadsEqual(thread, previousThread.first)) { + return ZE_RESULT_NOT_READY; + } + } + + interruptRequests.push(thread); + } + + return ZE_RESULT_SUCCESS; +} + +DebugSessionImp::Error DebugSessionImp::resumeThreadsWithinDevice(uint32_t deviceIndex, ze_device_thread_t physicalThread) { + auto &hwInfo = connectedDevice->getHwInfo(); + bool allThreadsRunning = true; + auto singleThreads = getSingleThreadsForDevice(deviceIndex, physicalThread, hwInfo); + Error retVal = Error::Unknown; + + std::vector resumeThreads; + std::vector resumeThreadIds; + + for (auto &threadId : singleThreads) { + if (allThreads[threadId]->isRunning()) { + continue; + } + allThreadsRunning = false; + resumeThreads.emplace_back(ze_device_thread_t{static_cast(threadId.slice), static_cast(threadId.subslice), static_cast(threadId.eu), static_cast(threadId.thread)}); + resumeThreadIds.push_back(threadId); + } + + if (allThreadsRunning) { + return Error::ThreadsRunning; + } + + std::unique_lock lock(threadStateMutex); + + [[maybe_unused]] auto sipCommandResult = writeResumeCommand(resumeThreadIds); + DEBUG_BREAK_IF(sipCommandResult != true); + + auto result = resumeImp(resumeThreads, deviceIndex); + + for (auto &threadID : resumeThreadIds) { + while (checkThreadIsResumed(threadID) == false) + ; + + allThreads[threadID]->resumeThread(); + } + + if (sipCommandResult && result == ZE_RESULT_SUCCESS) { + retVal = Error::Success; + } + + return retVal; +} + +bool DebugSessionImp::writeResumeCommand(const std::vector &threadIds) { + auto stateSaveAreaHeader = getStateSaveAreaHeader(); + bool success = true; + + if (stateSaveAreaHeader->versionHeader.version.major < 2u) { + auto &hwInfo = connectedDevice->getHwInfo(); + auto &l0HwHelper = L0HwHelper::get(hwInfo.platform.eRenderCoreFamily); + + if (l0HwHelper.isResumeWARequired()) { + constexpr uint32_t sipResumeValue = 0x40000000; + + bool isBindlessSip = (debugArea.reserved1 == 1); + auto registerType = ZET_DEBUG_REGSET_TYPE_CR_INTEL_GPU; + uint32_t dword = 1; + + if (!isBindlessSip) { + registerType = ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU; + dword = 4; + } + + for (auto &threadID : threadIds) { + uint32_t reg[8] = {}; + auto apiThread = convertToApi(threadID); + if (readRegistersImp(apiThread, registerType, 0, 1, reg) != ZE_RESULT_SUCCESS) { + success = false; + } else { + reg[dword] |= sipResumeValue; + if (writeRegistersImp(apiThread, registerType, 0, 1, reg) != ZE_RESULT_SUCCESS) { + success = false; + } + } + } + } + } else // >= 2u + { + auto *regdesc = &stateSaveAreaHeader->regHeader.cmd; + SIP::sip_command resumeCommand = {0}; + resumeCommand.command = static_cast(NEO::SipKernel::COMMAND::RESUME); + + for (auto &threadID : threadIds) { + PRINT_DEBUGGER_INFO_LOG("Write RESUME for %s\n", EuThread::toString(threadID).c_str()); + auto result = registersAccessHelper(allThreads[threadID].get(), regdesc, 0, 1, &resumeCommand, true); + if (result != ZE_RESULT_SUCCESS) { + success = false; + PRINT_DEBUGGER_ERROR_LOG("Failed to write RESUME command for thread %s\n", EuThread::toString(threadID).c_str()); + } + } + } + return success; +} + +bool DebugSessionImp::checkThreadIsResumed(const EuThread::ThreadId &threadID) { + auto stateSaveAreaHeader = getStateSaveAreaHeader(); + bool resumed = true; + + if (stateSaveAreaHeader->versionHeader.version.major >= 2u) { + const auto thread = allThreads[threadID].get(); + auto gpuVa = getContextStateSaveAreaGpuVa(thread->getMemoryHandle()); + if (gpuVa == 0) { + PRINT_DEBUGGER_ERROR_LOG("Failed to get Context State Save Area GPU Virtual Address\n", ""); + return resumed; + } + + auto threadSlotOffset = calculateThreadSlotOffset(thread->getThreadId()); + auto srMagicOffset = threadSlotOffset + getStateSaveAreaHeader()->regHeader.sr_magic_offset; + SIP::sr_ident srMagic; + memset(srMagic.magic, 0, sizeof(SIP::sr_ident::magic)); + readGpuMemory(thread->getMemoryHandle(), reinterpret_cast(&srMagic), sizeof(srMagic), gpuVa + srMagicOffset); + + if (0 != strcmp(srMagic.magic, "srmagic")) { + PRINT_DEBUGGER_ERROR_LOG("checkThreadIsResumed - Failed to read srMagic for thread %s\n", EuThread::toString(threadID).c_str()); + return resumed; + } + + PRINT_DEBUGGER_THREAD_LOG("checkThreadIsResumed - Read counter for thread %s, counter == %d\n", EuThread::toString(threadID).c_str(), (int)srMagic.count); + + // Counter greater than last one means thread was resumed + if (srMagic.count == thread->getLastCounter()) { + resumed = false; + } + } + return resumed; +} + +ze_result_t DebugSessionImp::resume(ze_device_thread_t thread) { + uint32_t deviceIndex = 0; + auto physicalThread = convertToPhysical(thread, deviceIndex); + + auto deviceCount = std::max(1u, connectedDevice->getNEODevice()->getNumSubDevices()); + bool singleDevice = (thread.slice != UINT32_MAX && deviceCount > 1) || deviceCount == 1; + ze_result_t retVal = ZE_RESULT_SUCCESS; + + if (singleDevice) { + auto result = resumeThreadsWithinDevice(deviceIndex, physicalThread); + if (result == Error::ThreadsRunning) { + retVal = ZE_RESULT_ERROR_NOT_AVAILABLE; + } else if (result != Error::Success) { + return ZE_RESULT_ERROR_UNKNOWN; + } + } else { + bool allThreadsRunning = true; + + for (uint32_t deviceId = 0; deviceId < deviceCount; deviceId++) { + auto result = resumeThreadsWithinDevice(deviceId, physicalThread); + + if (result == Error::ThreadsRunning) { + continue; + } else if (result != Error::Success) { + retVal = ZE_RESULT_ERROR_UNKNOWN; + } + allThreadsRunning = false; + } + + if (allThreadsRunning) { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + } + + return retVal; +} + +void DebugSessionImp::sendInterrupts() { + + if (interruptSent) { + return; + } + + { + std::unique_lock lock(interruptMutex); + + while (interruptRequests.size() > 0) { + auto thread = interruptRequests.front(); + pendingInterrupts.push_back(std::pair(thread, false)); + interruptRequests.pop(); + } + } + + if (pendingInterrupts.size() == 0) { + return; + } + + expectedAttentionEvents = 0; + auto deviceCount = std::max(1u, connectedDevice->getNEODevice()->getNumSubDevices()); + + if (deviceCount == 1) { + uint32_t deviceIndex = 0; + ze_result_t result; + { + std::unique_lock lock(threadStateMutex); + result = interruptImp(deviceIndex); + } + + if (result == ZE_RESULT_SUCCESS) { + interruptTime = std::chrono::high_resolution_clock::now(); + interruptSent = true; + } else { + zet_debug_event_t debugEvent = {}; + debugEvent.type = ZET_DEBUG_EVENT_TYPE_THREAD_UNAVAILABLE; + + for (auto &request : pendingInterrupts) { + debugEvent.info.thread.thread = request.first; + enqueueApiEvent(debugEvent); + } + + { + std::unique_lock lock(interruptMutex); + pendingInterrupts.clear(); + } + } + } else { + std::vector devices(deviceCount); + + for (auto &request : pendingInterrupts) { + auto thread = request.first; + fillDevicesFromThread(thread, devices); + } + + std::vector results(deviceCount); + + for (uint32_t i = 0; i < deviceCount; i++) { + if (devices[i]) { + std::unique_lock lock(threadStateMutex); + results[i] = interruptImp(i); + if (results[i] == ZE_RESULT_SUCCESS) { + expectedAttentionEvents++; + } + } else { + results[i] = ZE_RESULT_SUCCESS; + } + } + + const bool allFailed = std::all_of(results.begin(), results.end(), + [](const auto &result) { return result != ZE_RESULT_SUCCESS; }); + + PRINT_DEBUGGER_INFO_LOG("Successful interrupt requests = %u \n", expectedAttentionEvents); + + if (allFailed) { + zet_debug_event_t debugEvent = {}; + debugEvent.type = ZET_DEBUG_EVENT_TYPE_THREAD_UNAVAILABLE; + + for (auto &request : pendingInterrupts) { + debugEvent.info.thread.thread = request.first; + enqueueApiEvent(debugEvent); + } + + expectedAttentionEvents = 0; + + { + std::unique_lock lock(interruptMutex); + pendingInterrupts.clear(); + } + } else { + interruptTime = std::chrono::high_resolution_clock::now(); + interruptSent = true; + } + } +} + +void DebugSessionImp::markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(EuThread::ThreadId threadId, uint64_t memoryHandle) { + + SIP::sr_ident srMagic = {}; + srMagic.count = 0; + + bool wasStopped = false; + { + std::unique_lock lock(threadStateMutex); + + if (!readSystemRoutineIdent(allThreads[threadId].get(), memoryHandle, srMagic)) { + PRINT_DEBUGGER_ERROR_LOG("Failed to read SR IDENT\n", ""); + return; + } else { + PRINT_DEBUGGER_INFO_LOG("SIP version == %d.%d.%d\n", (int)srMagic.version.major, (int)srMagic.version.minor, (int)srMagic.version.patch); + } + + wasStopped = allThreads[threadId]->isStopped(); + + if (!allThreads[threadId]->verifyStopped(srMagic.count)) { + return; + } + + allThreads[threadId]->stopThread(memoryHandle); + } + + bool threadWasInterrupted = false; + + for (auto &request : pendingInterrupts) { + ze_device_thread_t apiThread = convertToApi(threadId); + + auto isInterrupted = checkSingleThreadWithinDeviceThread(apiThread, request.first); + + if (isInterrupted) { + request.second = true; + threadWasInterrupted = true; + } + } + + if (!threadWasInterrupted && !wasStopped) { + newlyStoppedThreads.push_back(threadId); + } +} + +void DebugSessionImp::generateEventsAndResumeStoppedThreads() { + + if (interruptSent && !triggerEvents) { + auto timeDiff = getTimeDifferenceMilliseconds(interruptTime); + if (timeDiff > interruptTimeout) { + triggerEvents = true; + interruptTime = std::chrono::high_resolution_clock::now(); + } + } + + if (triggerEvents) { + generateEventsForPendingInterrupts(); + + std::vector resumeThreads; + std::vector stoppedThreadsToReport; + + fillResumeAndStoppedThreadsFromNewlyStopped(resumeThreads, stoppedThreadsToReport); + + resumeAccidentallyStoppedThreads(resumeThreads); + generateEventsForStoppedThreads(stoppedThreadsToReport); + + interruptSent = false; + triggerEvents = false; + } +} + +bool DebugSessionImp::isForceExceptionOrForceExternalHaltOnlyExceptionReason(uint32_t *cr0) { + const uint32_t cr0ExceptionBitmask = 0xFC000000; + const uint32_t cr0ForcedExcpetionBitmask = 0x44000000; + + return (((cr0[1] & cr0ExceptionBitmask) & (~cr0ForcedExcpetionBitmask)) == 0); +} + +void DebugSessionImp::fillResumeAndStoppedThreadsFromNewlyStopped(std::vector &resumeThreads, std::vector &stoppedThreadsToReport) { + + for (auto &newlyStopped : newlyStoppedThreads) { + if (allThreads[newlyStopped]->isStopped()) { + uint32_t reg[8] = {}; + + ze_device_thread_t apiThread = convertToApi(newlyStopped); + readRegistersImp(apiThread, ZET_DEBUG_REGSET_TYPE_CR_INTEL_GPU, 0, 1, reg); + + if (isForceExceptionOrForceExternalHaltOnlyExceptionReason(reg)) { + PRINT_DEBUGGER_THREAD_LOG("RESUME accidentally stopped thread = %s\n", allThreads[newlyStopped]->toString().c_str()); + resumeThreads.push_back(newlyStopped); + } else { + PRINT_DEBUGGER_THREAD_LOG("Newly stopped thread = %s, exception bits = %#010" PRIx32 "\n", allThreads[newlyStopped]->toString().c_str(), reg[1]); + stoppedThreadsToReport.push_back(newlyStopped); + } + } + } + + newlyStoppedThreads.clear(); +} + +void DebugSessionImp::generateEventsForPendingInterrupts() { + zet_debug_event_t debugEvent = {}; + + for (auto &request : pendingInterrupts) { + if (request.second == true) { + debugEvent.type = ZET_DEBUG_EVENT_TYPE_THREAD_STOPPED; + debugEvent.info.thread.thread = request.first; + enqueueApiEvent(debugEvent); + } else { + debugEvent.type = ZET_DEBUG_EVENT_TYPE_THREAD_UNAVAILABLE; + debugEvent.info.thread.thread = request.first; + enqueueApiEvent(debugEvent); + } + } + + { + std::unique_lock lock(interruptMutex); + pendingInterrupts.clear(); + } +} + +void DebugSessionImp::resumeAccidentallyStoppedThreads(const std::vector &threadIds) { + std::vector threads[4]; + std::vector threadIdsPerDevice[4]; + + for (auto &threadID : threadIds) { + ze_device_thread_t thread = {static_cast(threadID.slice), static_cast(threadID.subslice), static_cast(threadID.eu), static_cast(threadID.thread)}; + uint32_t deviceIndex = static_cast(threadID.tileIndex); + + UNRECOVERABLE_IF((connectedDevice->getNEODevice()->getNumSubDevices() > 0) && + (deviceIndex >= connectedDevice->getNEODevice()->getNumSubDevices())); + + threads[deviceIndex].push_back(thread); + threadIdsPerDevice[deviceIndex].push_back(threadID); + } + + for (uint32_t i = 0; i < 4; i++) { + std::unique_lock lock(threadStateMutex); + + if (threads[i].size() > 0) { + [[maybe_unused]] auto writeSipCommandResult = writeResumeCommand(threadIdsPerDevice[i]); + DEBUG_BREAK_IF(writeSipCommandResult != true); + resumeImp(threads[i], i); + } + + for (auto &threadID : threadIdsPerDevice[i]) { + while (checkThreadIsResumed(threadID) == false) + ; + + allThreads[threadID]->resumeThread(); + } + } +} + +void DebugSessionImp::generateEventsForStoppedThreads(const std::vector &threadIds) { + zet_debug_event_t debugEvent = {}; + for (auto &threadID : threadIds) { + ze_device_thread_t thread = convertToApi(threadID); + + debugEvent.type = ZET_DEBUG_EVENT_TYPE_THREAD_STOPPED; + debugEvent.info.thread.thread = thread; + enqueueApiEvent(debugEvent); + } +} + +const SIP::StateSaveAreaHeader *DebugSessionImp::getStateSaveAreaHeader() { + if (stateSaveAreaHeader.empty()) { + readStateSaveAreaHeader(); + } + return reinterpret_cast(stateSaveAreaHeader.data()); +} + +const SIP::regset_desc *DebugSessionImp::getSbaRegsetDesc() { + // SBA virtual register set is always present + static const SIP::regset_desc sba = {0, ZET_DEBUG_SBA_COUNT_INTEL_GPU, 64, 8}; + return &sba; +} + +const SIP::regset_desc *DebugSessionImp::typeToRegsetDesc(uint32_t type) { + auto pStateSaveAreaHeader = getStateSaveAreaHeader(); + + UNRECOVERABLE_IF(pStateSaveAreaHeader == nullptr); + + switch (type) { + case ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU: + return &pStateSaveAreaHeader->regHeader.grf; + case ZET_DEBUG_REGSET_TYPE_ADDR_INTEL_GPU: + return &pStateSaveAreaHeader->regHeader.addr; + case ZET_DEBUG_REGSET_TYPE_FLAG_INTEL_GPU: + return &pStateSaveAreaHeader->regHeader.flag; + case ZET_DEBUG_REGSET_TYPE_CE_INTEL_GPU: + return &pStateSaveAreaHeader->regHeader.emask; + case ZET_DEBUG_REGSET_TYPE_SR_INTEL_GPU: + return &pStateSaveAreaHeader->regHeader.sr; + case ZET_DEBUG_REGSET_TYPE_CR_INTEL_GPU: + return &pStateSaveAreaHeader->regHeader.cr; + case ZET_DEBUG_REGSET_TYPE_TDR_INTEL_GPU: + return &pStateSaveAreaHeader->regHeader.tdr; + case ZET_DEBUG_REGSET_TYPE_ACC_INTEL_GPU: + return &pStateSaveAreaHeader->regHeader.acc; + case ZET_DEBUG_REGSET_TYPE_MME_INTEL_GPU: + return &pStateSaveAreaHeader->regHeader.mme; + case ZET_DEBUG_REGSET_TYPE_SP_INTEL_GPU: + return &pStateSaveAreaHeader->regHeader.sp; + case ZET_DEBUG_REGSET_TYPE_SBA_INTEL_GPU: + return DebugSessionImp::getSbaRegsetDesc(); + default: + return nullptr; + } +} + +uint32_t DebugSessionImp::typeToRegsetFlags(uint32_t type) { + switch (type) { + case ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU: + case ZET_DEBUG_REGSET_TYPE_ADDR_INTEL_GPU: + case ZET_DEBUG_REGSET_TYPE_FLAG_INTEL_GPU: + case ZET_DEBUG_REGSET_TYPE_SR_INTEL_GPU: + case ZET_DEBUG_REGSET_TYPE_CR_INTEL_GPU: + case ZET_DEBUG_REGSET_TYPE_ACC_INTEL_GPU: + case ZET_DEBUG_REGSET_TYPE_SP_INTEL_GPU: + return ZET_DEBUG_REGSET_FLAG_READABLE | ZET_DEBUG_REGSET_FLAG_WRITEABLE; + + case ZET_DEBUG_REGSET_TYPE_CE_INTEL_GPU: + case ZET_DEBUG_REGSET_TYPE_TDR_INTEL_GPU: + case ZET_DEBUG_REGSET_TYPE_SBA_INTEL_GPU: + return ZET_DEBUG_REGSET_FLAG_READABLE; + + default: + return 0; + } +} + +size_t DebugSessionImp::calculateThreadSlotOffset(EuThread::ThreadId threadId) { + auto pStateSaveAreaHeader = getStateSaveAreaHeader(); + return pStateSaveAreaHeader->versionHeader.size * 8 + pStateSaveAreaHeader->regHeader.state_area_offset + ((((threadId.slice * pStateSaveAreaHeader->regHeader.num_subslices_per_slice + threadId.subslice) * pStateSaveAreaHeader->regHeader.num_eus_per_subslice + threadId.eu) * pStateSaveAreaHeader->regHeader.num_threads_per_eu + threadId.thread) * pStateSaveAreaHeader->regHeader.state_save_size); +} + +size_t DebugSessionImp::calculateRegisterOffsetInThreadSlot(const SIP::regset_desc *regdesc, uint32_t start) { + return regdesc->offset + regdesc->bytes * start; +} + +ze_result_t DebugSessionImp::readSbaRegisters(ze_device_thread_t thread, uint32_t start, uint32_t count, void *pRegisterValues) { + auto sbaRegDesc = DebugSessionImp::getSbaRegsetDesc(); + + if (start >= sbaRegDesc->num) { + return ZE_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (start + count > sbaRegDesc->num) { + return ZE_RESULT_ERROR_INVALID_ARGUMENT; + } + + ze_result_t ret = ZE_RESULT_SUCCESS; + + SbaTrackedAddresses sbaBuffer; + ret = readSbaBuffer(convertToThreadId(thread), sbaBuffer); + if (ret != ZE_RESULT_SUCCESS) { + return ret; + } + + uint32_t r0[8]; + ret = readRegistersImp(thread, ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU, 0, 1, r0); + if (ret != ZE_RESULT_SUCCESS) { + return ret; + } + + uint64_t BindingTableBaseAddress = ((r0[4] >> 5) << 5) + sbaBuffer.SurfaceStateBaseAddress; + uint64_t ScratchSpaceBaseAddress = 0; + + auto &hwHelper = NEO::HwHelper::get(connectedDevice->getNEODevice()->getHardwareInfo().platform.eRenderCoreFamily); + if (hwHelper.isScratchSpaceSurfaceStateAccessible()) { + auto surfaceStateForScratch = ((r0[5] >> 10) << 6); + + if (surfaceStateForScratch > 0) { + uint64_t renderSurfaceStateGpuVa = surfaceStateForScratch + sbaBuffer.SurfaceStateBaseAddress; + constexpr size_t renderSurfaceStateSize = 64; + std::vector renderSurfaceState(renderSurfaceStateSize, 0); + + ret = readGpuMemory(allThreads[convertToThreadId(thread)]->getMemoryHandle(), renderSurfaceState.data(), renderSurfaceStateSize, renderSurfaceStateGpuVa); + + if (ret != ZE_RESULT_SUCCESS) { + return ret; + } + + auto scratchSpacePTSize = hwHelper.getRenderSurfaceStatePitch(renderSurfaceState.data()); + auto threadOffset = getPerThreadScratchOffset(scratchSpacePTSize, convertToThreadId(thread)); + auto scratchAllocationBase = NEO::GmmHelper::decanonize(hwHelper.getRenderSurfaceStateBaseAddress(renderSurfaceState.data())); + if (scratchAllocationBase != 0) { + ScratchSpaceBaseAddress = threadOffset + scratchAllocationBase; + } + } + } else { + auto scratchPointer = ((r0[5] >> 10) << 10); + if (scratchPointer != 0) { + ScratchSpaceBaseAddress = scratchPointer + sbaBuffer.GeneralStateBaseAddress; + } + } + + std::vector packed; + packed.push_back(sbaBuffer.GeneralStateBaseAddress); + packed.push_back(sbaBuffer.SurfaceStateBaseAddress); + packed.push_back(sbaBuffer.DynamicStateBaseAddress); + packed.push_back(sbaBuffer.IndirectObjectBaseAddress); + packed.push_back(sbaBuffer.InstructionBaseAddress); + packed.push_back(sbaBuffer.BindlessSurfaceStateBaseAddress); + packed.push_back(sbaBuffer.BindlessSamplerStateBaseAddress); + packed.push_back(BindingTableBaseAddress); + packed.push_back(ScratchSpaceBaseAddress); + + size_t size = count * sbaRegDesc->bytes; + memcpy_s(pRegisterValues, size, &packed[start], size); + + return ZE_RESULT_SUCCESS; +} + +ze_result_t DebugSession::getRegisterSetProperties(Device *device, uint32_t *pCount, zet_debug_regset_properties_t *pRegisterSetProperties) { + if (nullptr == pCount) { + return ZE_RESULT_ERROR_INVALID_NULL_POINTER; + } + + if (*pCount && !pRegisterSetProperties) { + return ZE_RESULT_ERROR_INVALID_NULL_POINTER; + } + + auto &stateSaveAreaHeader = NEO::SipKernel::getBindlessDebugSipKernel(*device->getNEODevice()).getStateSaveAreaHeader(); + + if (stateSaveAreaHeader.size() == 0) { + *pCount = 0; + return ZE_RESULT_SUCCESS; + } + + uint32_t totalRegsetNum = 0; + auto parseRegsetDesc = [&](const SIP::regset_desc ®setDesc, zet_debug_regset_type_intel_gpu_t regsetType) { + if (regsetDesc.num) { + if (totalRegsetNum < *pCount) { + zet_debug_regset_properties_t regsetProps = { + ZET_STRUCTURE_TYPE_DEBUG_REGSET_PROPERTIES, + nullptr, + static_cast(regsetType), + 0, + DebugSessionImp::typeToRegsetFlags(regsetType), + 0, + regsetDesc.num, + regsetDesc.bits, + regsetDesc.bytes, + }; + pRegisterSetProperties[totalRegsetNum] = regsetProps; + } + ++totalRegsetNum; + } + }; + + auto pStateSaveArea = reinterpret_cast(stateSaveAreaHeader.data()); + + parseRegsetDesc(pStateSaveArea->regHeader.grf, ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU); + parseRegsetDesc(pStateSaveArea->regHeader.addr, ZET_DEBUG_REGSET_TYPE_ADDR_INTEL_GPU); + parseRegsetDesc(pStateSaveArea->regHeader.flag, ZET_DEBUG_REGSET_TYPE_FLAG_INTEL_GPU); + parseRegsetDesc(pStateSaveArea->regHeader.emask, ZET_DEBUG_REGSET_TYPE_CE_INTEL_GPU); + parseRegsetDesc(pStateSaveArea->regHeader.sr, ZET_DEBUG_REGSET_TYPE_SR_INTEL_GPU); + parseRegsetDesc(pStateSaveArea->regHeader.cr, ZET_DEBUG_REGSET_TYPE_CR_INTEL_GPU); + parseRegsetDesc(pStateSaveArea->regHeader.tdr, ZET_DEBUG_REGSET_TYPE_TDR_INTEL_GPU); + parseRegsetDesc(pStateSaveArea->regHeader.acc, ZET_DEBUG_REGSET_TYPE_ACC_INTEL_GPU); + parseRegsetDesc(pStateSaveArea->regHeader.mme, ZET_DEBUG_REGSET_TYPE_MME_INTEL_GPU); + parseRegsetDesc(pStateSaveArea->regHeader.sp, ZET_DEBUG_REGSET_TYPE_SP_INTEL_GPU); + + parseRegsetDesc(*DebugSessionImp::getSbaRegsetDesc(), ZET_DEBUG_REGSET_TYPE_SBA_INTEL_GPU); + + if (!*pCount || (*pCount > totalRegsetNum)) { + *pCount = totalRegsetNum; + } + + return ZE_RESULT_SUCCESS; +} + +ze_result_t DebugSessionImp::registersAccessHelper(const EuThread *thread, const SIP::regset_desc *regdesc, + uint32_t start, uint32_t count, void *pRegisterValues, bool write) { + if (start >= regdesc->num) { + return ZE_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (start + count > regdesc->num) { + return ZE_RESULT_ERROR_INVALID_ARGUMENT; + } + + auto gpuVa = getContextStateSaveAreaGpuVa(thread->getMemoryHandle()); + if (gpuVa == 0) { + return ZE_RESULT_ERROR_UNKNOWN; + } + + char tssMagic[8] = {0}; + readGpuMemory(thread->getMemoryHandle(), tssMagic, sizeof(tssMagic), gpuVa); + if (0 != strcmp(tssMagic, "tssarea")) { + return ZE_RESULT_ERROR_UNKNOWN; + } + + auto threadSlotOffset = calculateThreadSlotOffset(thread->getThreadId()); + + auto srMagicOffset = threadSlotOffset + getStateSaveAreaHeader()->regHeader.sr_magic_offset; + SIP::sr_ident srMagic; + memset(srMagic.magic, 0, sizeof(SIP::sr_ident::magic)); + + readGpuMemory(thread->getMemoryHandle(), reinterpret_cast(&srMagic), sizeof(srMagic), gpuVa + srMagicOffset); + if (0 != strcmp(srMagic.magic, "srmagic")) { + return ZE_RESULT_ERROR_UNKNOWN; + } + + auto startRegOffset = threadSlotOffset + calculateRegisterOffsetInThreadSlot(regdesc, start); + + int ret = 0; + if (write) { + ret = writeGpuMemory(thread->getMemoryHandle(), static_cast(pRegisterValues), count * regdesc->bytes, gpuVa + startRegOffset); + } else { + ret = readGpuMemory(thread->getMemoryHandle(), static_cast(pRegisterValues), count * regdesc->bytes, gpuVa + startRegOffset); + } + + return ret == 0 ? ZE_RESULT_SUCCESS : ZE_RESULT_ERROR_UNKNOWN; +} + +ze_result_t DebugSessionImp::readRegisters(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) { + if (!areRequestedThreadsStopped(thread)) { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + + auto stateSaveAreaHeader = getStateSaveAreaHeader(); + if (stateSaveAreaHeader == nullptr) { + return ZE_RESULT_ERROR_UNKNOWN; + } + + if (type == ZET_DEBUG_REGSET_TYPE_SBA_INTEL_GPU) { + return readSbaRegisters(thread, start, count, pRegisterValues); + } + + return readRegistersImp(thread, type, start, count, pRegisterValues); +} + +ze_result_t DebugSessionImp::readRegistersImp(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) { + auto regdesc = typeToRegsetDesc(type); + if (nullptr == regdesc) { + return ZE_RESULT_ERROR_INVALID_ARGUMENT; + } + + return registersAccessHelper(allThreads[convertToThreadId(thread)].get(), regdesc, start, count, pRegisterValues, false); +} + +ze_result_t DebugSessionImp::writeRegisters(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) { + if (!areRequestedThreadsStopped(thread)) { + return ZE_RESULT_ERROR_NOT_AVAILABLE; + } + + auto stateSaveAreaHeader = getStateSaveAreaHeader(); + if (stateSaveAreaHeader == nullptr) { + return ZE_RESULT_ERROR_UNKNOWN; + } + + return writeRegistersImp(thread, type, start, count, pRegisterValues); +} + +ze_result_t DebugSessionImp::writeRegistersImp(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) { + auto regdesc = typeToRegsetDesc(type); + if (nullptr == regdesc) { + return ZE_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (ZET_DEBUG_REGSET_FLAG_WRITEABLE != ((DebugSessionImp::typeToRegsetFlags(type) & ZET_DEBUG_REGSET_FLAG_WRITEABLE))) { + return ZE_RESULT_ERROR_INVALID_ARGUMENT; + } + + return registersAccessHelper(allThreads[convertToThreadId(thread)].get(), regdesc, start, count, pRegisterValues, true); +} + +bool DebugSessionImp::isValidGpuAddress(uint64_t address) { + auto decanonizedAddress = NEO::GmmHelper::decanonize(address); + auto gmm = connectedDevice->getNEODevice()->getGmmHelper(); + bool validAddress = gmm->isValidCanonicalGpuAddress(address); + + if (address == decanonizedAddress || validAddress) { + return true; + } + return false; +} + +} // namespace L0 diff --git a/level_zero/tools/source/debug/debug_session_imp.h b/level_zero/tools/source/debug/debug_session_imp.h new file mode 100644 index 0000000000..9c4ac1e475 --- /dev/null +++ b/level_zero/tools/source/debug/debug_session_imp.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2021-2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#pragma once + +#include "level_zero/tools/source/debug/debug_session.h" + +#include +#include +#include + +namespace SIP { +struct StateSaveAreaHeader; +struct regset_desc; +struct sr_ident; +struct sip_command; +} // namespace SIP + +namespace L0 { + +struct DebugSessionImp : DebugSession { + + enum class Error { + Success, + ThreadsRunning, + Unknown + }; + + DebugSessionImp(const zet_debug_config_t &config, Device *device) : DebugSession(config, device) {} + + ze_result_t interrupt(ze_device_thread_t thread) override; + ze_result_t resume(ze_device_thread_t thread) 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; + + static const SIP::regset_desc *getSbaRegsetDesc(); + static uint32_t typeToRegsetFlags(uint32_t type); + constexpr static int64_t interruptTimeout = 2000; + + protected: + MOCKABLE_VIRTUAL ze_result_t readRegistersImp(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues); + MOCKABLE_VIRTUAL ze_result_t writeRegistersImp(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues); + Error resumeThreadsWithinDevice(uint32_t deviceIndex, ze_device_thread_t physicalThread); + MOCKABLE_VIRTUAL bool writeResumeCommand(const std::vector &threadIds); + MOCKABLE_VIRTUAL bool checkThreadIsResumed(const EuThread::ThreadId &threadID); + + virtual ze_result_t resumeImp(std::vector threads, uint32_t deviceIndex) = 0; + virtual ze_result_t interruptImp(uint32_t deviceIndex) = 0; + + virtual ze_result_t readGpuMemory(uint64_t memoryHandle, char *output, size_t size, uint64_t gpuVa) = 0; + virtual ze_result_t writeGpuMemory(uint64_t memoryHandle, const char *input, size_t size, uint64_t gpuVa) = 0; + + virtual void enqueueApiEvent(zet_debug_event_t &debugEvent) = 0; + virtual bool readSystemRoutineIdent(EuThread *thread, uint64_t vmHandle, SIP::sr_ident &srMagic) = 0; + + ze_result_t readSbaRegisters(ze_device_thread_t thread, uint32_t start, uint32_t count, void *pRegisterValues); + MOCKABLE_VIRTUAL bool isForceExceptionOrForceExternalHaltOnlyExceptionReason(uint32_t *cr0); + void sendInterrupts(); + MOCKABLE_VIRTUAL void markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(EuThread::ThreadId threadId, uint64_t memoryHandle); + MOCKABLE_VIRTUAL void fillResumeAndStoppedThreadsFromNewlyStopped(std::vector &resumeThreads, std::vector &stoppedThreadsToReport); + MOCKABLE_VIRTUAL void generateEventsAndResumeStoppedThreads(); + MOCKABLE_VIRTUAL void resumeAccidentallyStoppedThreads(const std::vector &threadIds); + MOCKABLE_VIRTUAL void generateEventsForStoppedThreads(const std::vector &threadIds); + MOCKABLE_VIRTUAL void generateEventsForPendingInterrupts(); + + const SIP::StateSaveAreaHeader *getStateSaveAreaHeader(); + virtual void readStateSaveAreaHeader(){}; + + virtual uint64_t getContextStateSaveAreaGpuVa(uint64_t memoryHandle) { + return 0; + }; + + ze_result_t registersAccessHelper(const EuThread *thread, const SIP::regset_desc *regdesc, + uint32_t start, uint32_t count, void *pRegisterValues, bool write); + + const SIP::regset_desc *typeToRegsetDesc(uint32_t type); + size_t calculateThreadSlotOffset(EuThread::ThreadId threadId); + size_t calculateRegisterOffsetInThreadSlot(const SIP::regset_desc *const regdesc, uint32_t start); + + void newAttentionRaised(uint32_t deviceIndex) { + if (expectedAttentionEvents > 0) { + expectedAttentionEvents--; + } + } + + void checkTriggerEventsForAttention() { + if (pendingInterrupts.size() > 0 || newlyStoppedThreads.size()) { + if (expectedAttentionEvents == 0) { + triggerEvents = true; + } + } + } + + bool isValidGpuAddress(uint64_t address); + + MOCKABLE_VIRTUAL int64_t getTimeDifferenceMilliseconds(std::chrono::high_resolution_clock::time_point time) { + auto now = std::chrono::high_resolution_clock::now(); + auto timeDifferenceMs = std::chrono::duration_cast(now - time).count(); + return timeDifferenceMs; + } + + std::chrono::high_resolution_clock::time_point interruptTime; + std::atomic interruptSent = false; + std::atomic triggerEvents = false; + + uint32_t expectedAttentionEvents = 0; + + std::mutex interruptMutex; + std::mutex threadStateMutex; + std::queue interruptRequests; + std::vector> pendingInterrupts; + std::vector newlyStoppedThreads; + std::vector stateSaveAreaHeader; +}; + +} // namespace L0 diff --git a/level_zero/tools/source/debug/linux/CMakeLists.txt b/level_zero/tools/source/debug/linux/CMakeLists.txt new file mode 100644 index 0000000000..8015df8715 --- /dev/null +++ b/level_zero/tools/source/debug/linux/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# Copyright (C) 2021-2022 Intel Corporation +# +# SPDX-License-Identifier: MIT +# + +if(UNIX) + target_sources(${L0_STATIC_LIB_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/${BRANCH_DIR_SUFFIX}/debug_session.cpp + ) + + add_subdirectories() +endif() diff --git a/level_zero/tools/source/debug/linux/debug_session.cpp b/level_zero/tools/source/debug/linux/debug_session.cpp new file mode 100644 index 0000000000..1b61258f46 --- /dev/null +++ b/level_zero/tools/source/debug/linux/debug_session.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021-2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/tools/source/debug/debug_session.h" + +#include "level_zero/core/source/device/device.h" + +namespace L0 { + +DebugSession *DebugSession::create(const zet_debug_config_t &config, Device *device, ze_result_t &result) { + result = ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + return nullptr; +} +} // namespace L0 diff --git a/level_zero/tools/source/debug/linux/debug_session_linux_helper.cpp b/level_zero/tools/source/debug/linux/debug_session_linux_helper.cpp index b1f3aac3ec..921806f30d 100644 --- a/level_zero/tools/source/debug/linux/debug_session_linux_helper.cpp +++ b/level_zero/tools/source/debug/linux/debug_session_linux_helper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Intel Corporation + * Copyright (C) 2021-2022 Intel Corporation * * SPDX-License-Identifier: MIT * diff --git a/level_zero/tools/source/debug/windows/CMakeLists.txt b/level_zero/tools/source/debug/windows/CMakeLists.txt new file mode 100644 index 0000000000..2a081ff192 --- /dev/null +++ b/level_zero/tools/source/debug/windows/CMakeLists.txt @@ -0,0 +1,13 @@ +# +# Copyright (C) 2021-2022 Intel Corporation +# +# SPDX-License-Identifier: MIT +# + +if(WIN32) + target_sources(${L0_STATIC_LIB_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/debug_session.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ) +endif() diff --git a/level_zero/tools/source/debug/windows/debug_session.cpp b/level_zero/tools/source/debug/windows/debug_session.cpp new file mode 100644 index 0000000000..1b61258f46 --- /dev/null +++ b/level_zero/tools/source/debug/windows/debug_session.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021-2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "level_zero/tools/source/debug/debug_session.h" + +#include "level_zero/core/source/device/device.h" + +namespace L0 { + +DebugSession *DebugSession::create(const zet_debug_config_t &config, Device *device, ze_result_t &result) { + result = ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + return nullptr; +} +} // namespace L0 diff --git a/level_zero/tools/test/unit_tests/sources/debug/CMakeLists.txt b/level_zero/tools/test/unit_tests/sources/debug/CMakeLists.txt index 5497842b44..ca17f5c2d7 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/CMakeLists.txt +++ b/level_zero/tools/test/unit_tests/sources/debug/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (C) 2021 Intel Corporation +# Copyright (C) 2021-2022 Intel Corporation # # SPDX-License-Identifier: MIT # @@ -7,9 +7,10 @@ target_sources(${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt ${CMAKE_CURRENT_SOURCE_DIR}/debug_session_tests.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/debug_session_thread_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/eu_thread_tests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mock_debug_session.h - ${CMAKE_CURRENT_SOURCE_DIR}${BRANCH_DIR_SUFFIX}test_debug_api.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test_debug_api.cpp ) add_subdirectories() 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 74bf4a227d..acc9283ecf 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 @@ -1,391 +1,262 @@ /* - * Copyright (C) 2021 Intel Corporation + * Copyright (C) 2021-2022 Intel Corporation * * SPDX-License-Identifier: MIT * */ -#include "shared/test/common/helpers/default_hw_info.h" +#include "shared/source/helpers/hw_helper.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" #include "shared/test/common/mocks/ult_device_factory.h" #include "shared/test/common/test_macros/test.h" #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/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" +#include "level_zero/include/zet_intel_gpu_debug.h" +#include "level_zero/tools/source/debug/debug_session_imp.h" + +#include "common/StateSaveAreaHeader.h" +#include "encode_surface_state_args.h" 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(DebugSession, givenSingleThreadWhenGettingSingleThreadsThenCorrectThreadIsReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - - auto hwInfo = *NEO::defaultHwInfo.get(); - NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - auto debugSession = std::make_unique(config, &deviceImp); - - auto subslice = hwInfo.gtSystemInfo.MaxSubSlicesSupported / hwInfo.gtSystemInfo.MaxSlicesSupported - 1; - ze_device_thread_t physicalThread = {0, subslice, 2, 3}; - - auto threads = debugSession->getSingleThreadsForDevice(0, physicalThread, hwInfo); - - EXPECT_EQ(1u, threads.size()); - - EXPECT_EQ(0u, threads[0].tileIndex); - 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(DebugSession, givenAllThreadsWhenGettingSingleThreadsThenCorrectThreadsAreReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - - auto hwInfo = *NEO::defaultHwInfo.get(); - NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - auto debugSession = std::make_unique(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->getSingleThreadsForDevice(0, physicalThread, hwInfo); - - EXPECT_EQ(numThreadsPerEu, threads.size()); - - for (uint32_t i = 0; i < numThreadsPerEu; i++) { - EXPECT_EQ(0u, threads[i].tileIndex); - 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(DebugSession, givenAllEUsWhenGettingSingleThreadsThenCorrectThreadsAreReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - - auto hwInfo = *NEO::defaultHwInfo.get(); - NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - auto debugSession = std::make_unique(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->getSingleThreadsForDevice(0, 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(DebugSession, givenAllSubslicesWhenGettingSingleThreadsThenCorrectThreadsAreReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - - auto hwInfo = *NEO::defaultHwInfo.get(); - NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - auto debugSession = std::make_unique(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->getSingleThreadsForDevice(0, 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(DebugSession, givenAllSlicesWhenGettingSingleThreadsThenCorrectThreadsAreReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - - auto hwInfo = *NEO::defaultHwInfo.get(); - NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - auto debugSession = std::make_unique(config, &deviceImp); - - ze_device_thread_t physicalThread = {UINT32_MAX, 0, 0, 0}; - const uint32_t numSlices = hwInfo.gtSystemInfo.MaxSlicesSupported; - - auto threads = debugSession->getSingleThreadsForDevice(0, physicalThread, hwInfo); - - EXPECT_EQ(numSlices, threads.size()); - - for (uint32_t i = 0; i < numSlices; i++) { - EXPECT_EQ(0u, threads[i].tileIndex); - EXPECT_EQ(i, threads[i].slice); - EXPECT_EQ(0u, threads[i].subslice); - EXPECT_EQ(0u, threads[i].eu); - EXPECT_EQ(0u, threads[i].thread); - } -} - -TEST(DebugSession, givenBindlessSystemRoutineWhenQueryingIsBindlessThenTrueReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - - auto hwInfo = *NEO::defaultHwInfo.get(); - NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - auto debugSession = std::make_unique(config, &deviceImp); - - debugSession->debugArea.reserved1 = 1u; - - EXPECT_TRUE(debugSession->isBindlessSystemRoutine()); -} - -TEST(DebugSession, givenBindfulSystemRoutineWhenQueryingIsBindlessThenFalseReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - - auto hwInfo = *NEO::defaultHwInfo.get(); - NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - auto debugSession = std::make_unique(config, &deviceImp); - - debugSession->debugArea.reserved1 = 0u; - - EXPECT_FALSE(debugSession->isBindlessSystemRoutine()); -} - -TEST(DebugSession, 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); -} - -TEST(DebugSession, givenAllStoppedThreadsWhenAreRequestedThreadsStoppedCalledThenTrueReturned) { - 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); - - for (uint32_t i = 0; i < hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount; i++) { - EuThread::ThreadId thread(0, 0, 0, 0, i); - sessionMock->allThreads[thread]->stopThread(1u); +struct MockDebugSession : public L0::DebugSessionImp { + + using L0::DebugSession::allThreads; + using L0::DebugSession::debugArea; + + using L0::DebugSessionImp::calculateThreadSlotOffset; + using L0::DebugSessionImp::checkTriggerEventsForAttention; + using L0::DebugSessionImp::fillResumeAndStoppedThreadsFromNewlyStopped; + using L0::DebugSessionImp::generateEventsAndResumeStoppedThreads; + using L0::DebugSessionImp::generateEventsForPendingInterrupts; + using L0::DebugSessionImp::generateEventsForStoppedThreads; + using L0::DebugSessionImp::getStateSaveAreaHeader; + using L0::DebugSessionImp::markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention; + using L0::DebugSessionImp::newAttentionRaised; + using L0::DebugSessionImp::readSbaRegisters; + using L0::DebugSessionImp::registersAccessHelper; + using L0::DebugSessionImp::resumeAccidentallyStoppedThreads; + using L0::DebugSessionImp::sendInterrupts; + using L0::DebugSessionImp::typeToRegsetDesc; + + using L0::DebugSessionImp::interruptSent; + using L0::DebugSessionImp::stateSaveAreaHeader; + using L0::DebugSessionImp::triggerEvents; + + using L0::DebugSessionImp::expectedAttentionEvents; + using L0::DebugSessionImp::interruptMutex; + using L0::DebugSessionImp::interruptRequests; + using L0::DebugSessionImp::isValidGpuAddress; + using L0::DebugSessionImp::newlyStoppedThreads; + using L0::DebugSessionImp::pendingInterrupts; + using L0::DebugSessionImp::readStateSaveAreaHeader; + + MockDebugSession(const zet_debug_config_t &config, L0::Device *device) : DebugSessionImp(config, device) { } - ze_device_thread_t apiThread = {0, 0, 0, UINT32_MAX}; - EXPECT_TRUE(sessionMock->areRequestedThreadsStopped(apiThread)); -} + bool closeConnection() override { return true; } + ze_result_t initialize() override { + return ZE_RESULT_SUCCESS; + } -TEST(DebugSession, givenSomeStoppedThreadsWhenAreRequestedThreadsStoppedCalledThenFalseReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - auto hwInfo = *NEO::defaultHwInfo.get(); + ze_result_t readEvent(uint64_t timeout, zet_debug_event_t *event) override { + return ZE_RESULT_SUCCESS; + } - NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + ze_result_t readMemory(ze_device_thread_t thread, const zet_debug_memory_space_desc_t *desc, size_t size, void *buffer) override { + return readMemoryResult; + } + ze_result_t writeMemory(ze_device_thread_t thread, const zet_debug_memory_space_desc_t *desc, size_t size, const void *buffer) override { + return ZE_RESULT_SUCCESS; + } + ze_result_t acknowledgeEvent(const zet_debug_event_t *event) override { + return ZE_RESULT_SUCCESS; + } + ze_result_t readRegistersImp(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) override { + readRegistersCallCount++; + readRegistersReg = type; - auto sessionMock = std::make_unique(config, &deviceImp); - - for (uint32_t i = 0; i < hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount; i++) { - EuThread::ThreadId thread(0, 0, 0, 0, i); - if (i % 2) { - sessionMock->allThreads[thread]->stopThread(1u); + if (readRegistersSizeToFill > 0 && readRegistersSizeToFill <= sizeof(regs)) { + memcpy_s(pRegisterValues, readRegistersSizeToFill, regs, readRegistersSizeToFill); } + if (readRegistersResult != ZE_RESULT_FORCE_UINT32) { + return readRegistersResult; + } + return DebugSessionImp::readRegistersImp(thread, type, start, count, pRegisterValues); } - ze_device_thread_t apiThread = {0, 0, 0, UINT32_MAX}; - EXPECT_FALSE(sessionMock->areRequestedThreadsStopped(apiThread)); + ze_result_t writeRegistersImp(ze_device_thread_t thread, uint32_t type, uint32_t start, uint32_t count, void *pRegisterValues) override { + writeRegistersCallCount++; + writeRegistersReg = type; + + if (writeRegistersResult != ZE_RESULT_FORCE_UINT32) { + return writeRegistersResult; + } + + return DebugSessionImp::writeRegistersImp(thread, type, start, count, pRegisterValues); + } + + ze_result_t readSbaBuffer(EuThread::ThreadId threadId, SbaTrackedAddresses &sbaBuffer) override { + sbaBuffer = sba; + return readSbaBufferResult; + } + + void readStateSaveAreaHeader() override { + readStateSaveAreaHeaderCalled++; + DebugSessionImp::readStateSaveAreaHeader(); + } + ze_result_t resumeImp(std::vector threads, uint32_t deviceIndex) override { + resumeImpCalled++; + resumeThreadCount = threads.size(); + return resumeImpResult; + } + + ze_result_t interruptImp(uint32_t deviceIndex) override { + interruptImpCalled++; + interruptedDevices.push_back(deviceIndex); + return interruptImpResult; + } + + ze_result_t readGpuMemory(uint64_t memoryHandle, char *output, size_t size, uint64_t gpuVa) override { + if (gpuVa != 0 && gpuVa >= reinterpret_cast(stateSaveAreaHeader.data()) && + gpuVa <= reinterpret_cast(stateSaveAreaHeader.data() + stateSaveAreaHeader.size())) { + [[maybe_unused]] auto offset = ptrDiff(gpuVa, reinterpret_cast(stateSaveAreaHeader.data())); + memcpy_s(output, size, reinterpret_cast(gpuVa), size); + } + + else if (gpuVa != 0 && gpuVa >= reinterpret_cast(readMemoryBuffer) && + gpuVa <= reinterpret_cast(ptrOffset(readMemoryBuffer, sizeof(readMemoryBuffer)))) { + memcpy_s(output, size, reinterpret_cast(gpuVa), std::min(size, sizeof(readMemoryBuffer))); + } + return readMemoryResult; + } + ze_result_t writeGpuMemory(uint64_t memoryHandle, const char *input, size_t size, uint64_t gpuVa) override { + + if (gpuVa != 0 && gpuVa >= reinterpret_cast(stateSaveAreaHeader.data()) && + gpuVa <= reinterpret_cast(stateSaveAreaHeader.data() + stateSaveAreaHeader.size())) { + [[maybe_unused]] auto offset = ptrDiff(gpuVa, reinterpret_cast(stateSaveAreaHeader.data())); + memcpy_s(reinterpret_cast(gpuVa), size, input, size); + } + + return writeMemoryResult; + } + + void resumeAccidentallyStoppedThreads(const std::vector &threadIds) override { + resumeAccidentallyStoppedCalled++; + return DebugSessionImp::resumeAccidentallyStoppedThreads(threadIds); + } + + void startAsyncThread() override {} + bool readModuleDebugArea() override { return true; } + + void enqueueApiEvent(zet_debug_event_t &debugEvent) override { + events.push_back(debugEvent); + } + + bool isForceExceptionOrForceExternalHaltOnlyExceptionReason(uint32_t *cr0) override { + return onlyForceException; + } + + bool isForceExceptionOrForceExternalHaltOnlyExceptionReasonBase(uint32_t *cr0) { + return DebugSessionImp::isForceExceptionOrForceExternalHaltOnlyExceptionReason(cr0); + } + + bool readSystemRoutineIdent(EuThread *thread, uint64_t vmHandle, SIP::sr_ident &srMagic) override { + srMagic.count = threadStopped ? 1 : 0; + return readSystemRoutineIdentRetVal; + } + + bool areRequestedThreadsStopped(ze_device_thread_t thread) override { + if (areRequestedThreadsStoppedReturnValue != -1) { + return areRequestedThreadsStoppedReturnValue != 0; + } + return DebugSessionImp::areRequestedThreadsStopped(thread); + } + + bool writeResumeCommand(const std::vector &threadIds) override { + writeResumeCommandCalled++; + if (skipWriteResumeCommand) { + return true; + } + return L0::DebugSessionImp::writeResumeCommand(threadIds); + } + + bool checkThreadIsResumed(const EuThread::ThreadId &threadID) override { + checkThreadIsResumedCalled++; + if (skipCheckThreadIsResumed) { + return true; + } + return L0::DebugSessionImp::checkThreadIsResumed(threadID); + } + + uint64_t getContextStateSaveAreaGpuVa(uint64_t memoryHandle) override { + if (returnStateSaveAreaGpuVa) { + return reinterpret_cast(this->stateSaveAreaHeader.data()); + } + return DebugSessionImp::getContextStateSaveAreaGpuVa(memoryHandle); + }; + + int64_t getTimeDifferenceMilliseconds(std::chrono::high_resolution_clock::time_point time) override { + if (returnTimeDiff != -1) { + return returnTimeDiff; + } + return L0::DebugSessionImp::getTimeDifferenceMilliseconds(time); + } + + uint32_t interruptImpCalled = 0; + uint32_t resumeImpCalled = 0; + uint32_t resumeAccidentallyStoppedCalled = 0; + size_t resumeThreadCount = 0; + ze_result_t interruptImpResult = ZE_RESULT_SUCCESS; + ze_result_t resumeImpResult = ZE_RESULT_SUCCESS; + bool onlyForceException = true; + bool threadStopped = true; + int areRequestedThreadsStoppedReturnValue = -1; + bool readSystemRoutineIdentRetVal = true; + size_t readRegistersSizeToFill = 0; + ze_result_t readSbaBufferResult = ZE_RESULT_SUCCESS; + ze_result_t readRegistersResult = ZE_RESULT_FORCE_UINT32; + ze_result_t readMemoryResult = ZE_RESULT_SUCCESS; + ze_result_t writeMemoryResult = ZE_RESULT_SUCCESS; + ze_result_t writeRegistersResult = ZE_RESULT_FORCE_UINT32; + + uint32_t readStateSaveAreaHeaderCalled = 0; + uint32_t readRegistersCallCount = 0; + uint32_t readRegistersReg = 0; + uint32_t writeRegistersCallCount = 0; + uint32_t writeRegistersReg = 0; + + bool skipWriteResumeCommand = true; + uint32_t writeResumeCommandCalled = 0; + + bool skipCheckThreadIsResumed = true; + uint32_t checkThreadIsResumedCalled = 0; + + std::vector events; + std::vector interruptedDevices; + + SbaTrackedAddresses sba; + uint64_t readMemoryBuffer[64]; + uint64_t regs[16]; + + int returnTimeDiff = -1; + bool returnStateSaveAreaGpuVa = true; +}; + +using DebugSessionTest = ::testing::Test; + +TEST(DebugSessionTest, givenNullDeviceWhenDebugSessionCreatedThenAllThreadsAreEmpty) { + auto sessionMock = std::make_unique(zet_debug_config_t{0x1234}, nullptr); + EXPECT_TRUE(sessionMock->allThreads.empty()); } -TEST(DebugSession, givenApiThreadAndSingleTileWhenFillingDevicesThenVectorEntryIsSet) { - 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}; - - std::vector devices(1); - debugSession->fillDevicesFromThread(thread, devices); - - EXPECT_EQ(1u, devices[0]); -} - -TEST(DebugSession, givenDifferentCombinationsOfThreadsAndMemoryTypeCheckExpectedMemoryAccess) { +TEST(DebugSessionTest, givenAllStoppedThreadsWhenInterruptCalledThenErrorNotAvailableReturned) { zet_debug_config_t config = {}; config.pid = 0x1234; auto hwInfo = *NEO::defaultHwInfo.get(); @@ -393,211 +264,1873 @@ TEST(DebugSession, givenDifferentCombinationsOfThreadsAndMemoryTypeCheckExpected NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - auto sessionMock = std::make_unique(config, &deviceImp); - ze_device_thread_t thread = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX}; - zet_debug_memory_space_desc_t desc; - desc.address = 0x1000; - desc.type = ZET_DEBUG_MEMORY_SPACE_TYPE_DEFAULT; - - ze_result_t retVal = sessionMock->sanityMemAccessThreadCheck(thread, &desc); - EXPECT_EQ(ZE_RESULT_SUCCESS, retVal); - - desc.type = ZET_DEBUG_MEMORY_SPACE_TYPE_SLM; - - retVal = sessionMock->sanityMemAccessThreadCheck(thread, &desc); - EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, retVal); - - thread = {1, 1, UINT32_MAX, UINT32_MAX}; - retVal = sessionMock->sanityMemAccessThreadCheck(thread, &desc); - EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, retVal); - - thread = {0, 0, 0, 1}; - retVal = sessionMock->sanityMemAccessThreadCheck(thread, &desc); - EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, retVal); - - desc.type = ZET_DEBUG_MEMORY_SPACE_TYPE_DEFAULT; - - retVal = sessionMock->sanityMemAccessThreadCheck(thread, &desc); - EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, retVal); + auto sessionMock = std::make_unique(config, &deviceImp); for (uint32_t i = 0; i < hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount; i++) { EuThread::ThreadId thread(0, 0, 0, 0, i); sessionMock->allThreads[thread]->stopThread(1u); } - retVal = sessionMock->sanityMemAccessThreadCheck(thread, &desc); - EXPECT_EQ(ZE_RESULT_SUCCESS, retVal); + ze_device_thread_t apiThread = {0, 0, 0, UINT32_MAX}; + auto result = sessionMock->interrupt(apiThread); + + EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, result); } -TEST(DebugSession, givenDifferentThreadsWhenGettingPerThreadScratchOffsetThenCorrectOffsetReturned) { +TEST(DebugSessionTest, givenNoPendingInterruptWhenSendInterruptCalledThenInterruptImpNotCalled) { + zet_debug_config_t config = {}; + config.pid = 0x1234; auto hwInfo = *NEO::defaultHwInfo.get(); - NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + + NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - auto debugSession = std::make_unique(zet_debug_config_t{0x1234}, &deviceImp); - const uint32_t numThreadsPerEu = (hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount); - EuThread::ThreadId thread0Eu0 = {0, 0, 0, 0, 0}; - EuThread::ThreadId thread0Eu1 = {0, 0, 0, 1, 0}; - EuThread::ThreadId thread2Subslice1 = {0, 0, 1, 0, 2}; + auto sessionMock = std::make_unique(config, &deviceImp); + sessionMock->interruptSent = true; - const uint32_t ptss = 128; - - auto size = debugSession->getPerThreadScratchOffset(ptss, thread0Eu0); - EXPECT_EQ(0u, size); - - size = debugSession->getPerThreadScratchOffset(ptss, thread0Eu1); - EXPECT_EQ(ptss * numThreadsPerEu, size); - - size = debugSession->getPerThreadScratchOffset(ptss, thread2Subslice1); - EXPECT_EQ(2 * ptss + ptss * hwInfo.gtSystemInfo.MaxEuPerSubSlice * numThreadsPerEu, size); + sessionMock->sendInterrupts(); + EXPECT_EQ(0u, sessionMock->interruptImpCalled); } -TEST(DebugSession, GivenLogsEnabledWhenPrintBitmaskCalledThenBitmaskIsPrinted) { - DebugManagerStateRestore restorer; - NEO::DebugManager.flags.DebuggerLogBitmask.set(255); +TEST(DebugSessionTest, givenPendingInterruptWhenNewInterruptForThreadCalledThenErrorNotReadyReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + auto hwInfo = *NEO::defaultHwInfo.get(); - ::testing::internal::CaptureStdout(); + NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - uint64_t bitmask[2] = {0x404080808080, 0x1111ffff1111ffff}; - DebugSession::printBitmask(reinterpret_cast(bitmask), sizeof(bitmask)); + auto sessionMock = std::make_unique(config, &deviceImp); - auto output = ::testing::internal::GetCapturedStdout(); + ze_device_thread_t apiThread = {0, 0, 0, 1}; - EXPECT_THAT(output, testing::HasSubstr(std::string("\nINFO: Bitmask: "))); - EXPECT_THAT(output, testing::HasSubstr(std::string("[0] = 0x0000404080808080"))); - EXPECT_THAT(output, testing::HasSubstr(std::string("[1] = 0x1111ffff1111ffff"))); + sessionMock->pendingInterrupts.push_back({apiThread, false}); + auto result = sessionMock->interrupt(apiThread); + + EXPECT_EQ(ZE_RESULT_NOT_READY, result); } -TEST(DebugSession, GivenLogsDisabledWhenPrintBitmaskCalledThenBitmaskIsNotPrinted) { - DebugManagerStateRestore restorer; - NEO::DebugManager.flags.DebuggerLogBitmask.set(0); +TEST(DebugSessionTest, givenInterruptAlreadySentWhenSendInterruptCalledSecondTimeThenEarlyReturns) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + auto hwInfo = *NEO::defaultHwInfo.get(); - ::testing::internal::CaptureStdout(); + NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - uint64_t bitmask[2] = {0x404080808080, 0x1111ffff1111ffff}; - DebugSession::printBitmask(reinterpret_cast(bitmask), sizeof(bitmask)); + auto sessionMock = std::make_unique(config, &deviceImp); - auto output = ::testing::internal::GetCapturedStdout(); + sessionMock->threadStopped = 0; - EXPECT_EQ(0u, output.size()); + ze_device_thread_t apiThread = {0, 0, 0, 1}; + auto result = sessionMock->interrupt(apiThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + sessionMock->sendInterrupts(); + EXPECT_EQ(1u, sessionMock->interruptImpCalled); + EXPECT_EQ(0u, sessionMock->expectedAttentionEvents); + + ze_device_thread_t apiThread2 = {0, 0, 0, 2}; + result = sessionMock->interrupt(apiThread2); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + sessionMock->sendInterrupts(); + EXPECT_EQ(1u, sessionMock->interruptImpCalled); } -using DebugSessionMultiTile = Test; +TEST(DebugSessionTest, givenInterruptRequestWhenInterruptImpFailsInSendInterruptThenApiEventsArePushed) { + 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); + + sessionMock->readRegistersResult = ZE_RESULT_SUCCESS; + sessionMock->interruptImpResult = ZE_RESULT_ERROR_UNKNOWN; + ze_device_thread_t apiThread = {0, 0, 0, 1}; + auto result = sessionMock->interrupt(apiThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + sessionMock->sendInterrupts(); + EXPECT_EQ(1u, sessionMock->interruptImpCalled); + + EXPECT_EQ(1u, sessionMock->events.size()); + + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_THREAD_UNAVAILABLE, sessionMock->events[0].type); + EXPECT_TRUE(DebugSession::areThreadsEqual(apiThread, sessionMock->events[0].info.thread.thread)); + + EXPECT_EQ(0u, sessionMock->pendingInterrupts.size()); +} + +TEST(DebugSessionTest, givenPendingInteruptWhenHadnlingThreadWithAttentionThenPendingInterruptIsMarkedComplete) { + 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); + + ze_device_thread_t apiThread = {0, 0, 0, 0}; + EuThread::ThreadId thread(0, 0, 0, 0, 0); + + auto result = sessionMock->interrupt(apiThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + sessionMock->sendInterrupts(); + sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(thread, 1u); + + EXPECT_TRUE(sessionMock->allThreads[thread]->isStopped()); + + EXPECT_TRUE(sessionMock->pendingInterrupts[0].second); + EXPECT_EQ(0u, sessionMock->newlyStoppedThreads.size()); +} + +TEST(DebugSessionTest, givenStoppedThreadWhenAddingNewlyStoppedThenThreadIsNotAdded) { + 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); + + EuThread::ThreadId thread(0, 0, 0, 0, 0); + sessionMock->allThreads[thread]->stopThread(1u); + + sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(thread, 1u); + + EXPECT_EQ(0u, sessionMock->newlyStoppedThreads.size()); +} + +TEST(DebugSessionTest, givenNoStoppedThreadWhenAddingNewlyStoppedThenThreadIsNotAdded) { + 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); + sessionMock->threadStopped = 0; + + EuThread::ThreadId thread(0, 0, 0, 0, 0); + sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(thread, 1u); + + EXPECT_EQ(0u, sessionMock->newlyStoppedThreads.size()); +} + +TEST(DebugSessionTest, givenNoInterruptsSentWhenGenerateEventsAndResumeCalledThenTriggerEventsNotChanged) { + 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); + + sessionMock->interruptSent = false; + sessionMock->triggerEvents = false; + + sessionMock->generateEventsAndResumeStoppedThreads(); + EXPECT_FALSE(sessionMock->triggerEvents); +} + +TEST(DebugSessionTest, givenTriggerEventsWhenGenerateEventsAndResumeCalledThenEventsGeneratedAndThreadsResumed) { + 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); + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + ze_device_thread_t apiThread = {0, 0, 0, 1}; + ze_device_thread_t apiThread2 = {0, 0, 1, 1}; + sessionMock->pendingInterrupts.push_back({apiThread, true}); + + sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(EuThread::ThreadId(0, apiThread2), 1u); + + sessionMock->triggerEvents = true; + sessionMock->interruptSent = true; + + sessionMock->onlyForceException = false; + + sessionMock->generateEventsAndResumeStoppedThreads(); + + EXPECT_EQ(2u, sessionMock->events.size()); + + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_THREAD_STOPPED, sessionMock->events[0].type); + EXPECT_TRUE(DebugSession::areThreadsEqual(apiThread, sessionMock->events[0].info.thread.thread)); + + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_THREAD_STOPPED, sessionMock->events[1].type); + EXPECT_TRUE(DebugSession::areThreadsEqual(apiThread2, sessionMock->events[1].info.thread.thread)); + + EXPECT_EQ(1u, sessionMock->resumeAccidentallyStoppedCalled); + EXPECT_EQ(0u, sessionMock->pendingInterrupts.size()); + EXPECT_EQ(0u, sessionMock->newlyStoppedThreads.size()); +} + +TEST(DebugSessionTest, givenPendingInterruptAfterTimeoutWhenGenerateEventsAndResumeStoppedThreadsIsCalledThenEventsUnavailableAreSentAndFlagsSetFalse) { + 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); + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + ze_device_thread_t apiThread = {0, 0, 0, 1}; + sessionMock->pendingInterrupts.push_back({apiThread, false}); + + sessionMock->triggerEvents = false; + sessionMock->interruptSent = true; + sessionMock->returnTimeDiff = 5 * DebugSessionImp::interruptTimeout; + + sessionMock->generateEventsAndResumeStoppedThreads(); + + EXPECT_EQ(1u, sessionMock->events.size()); + + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_THREAD_UNAVAILABLE, sessionMock->events[0].type); + EXPECT_TRUE(DebugSession::areThreadsEqual(apiThread, sessionMock->events[0].info.thread.thread)); + + EXPECT_EQ(0u, sessionMock->pendingInterrupts.size()); + EXPECT_EQ(0u, sessionMock->newlyStoppedThreads.size()); + EXPECT_FALSE(sessionMock->triggerEvents); + EXPECT_FALSE(sessionMock->interruptSent); +} + +TEST(DebugSessionTest, givenPendingInterruptBeforeTimeoutWhenGenerateEventsAndResumeStoppedThreadsIsCalledThenEventsNotTriggered) { + 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); + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + ze_device_thread_t apiThread = {0, 0, 0, 1}; + sessionMock->pendingInterrupts.push_back({apiThread, false}); + + sessionMock->triggerEvents = false; + sessionMock->interruptSent = true; + sessionMock->returnTimeDiff = DebugSessionImp::interruptTimeout / 2; + + sessionMock->generateEventsAndResumeStoppedThreads(); + + EXPECT_EQ(0u, sessionMock->events.size()); + EXPECT_EQ(1u, sessionMock->pendingInterrupts.size()); + EXPECT_FALSE(sessionMock->triggerEvents); + EXPECT_TRUE(sessionMock->interruptSent); +} + +TEST(DebugSessionTest, givenErrorFromReadSystemRoutineIdentWhenCheckingThreadStateThenThreadIsNotStopped) { + 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); + sessionMock->readSystemRoutineIdentRetVal = false; + EuThread::ThreadId thread(0, 0, 0, 0, 0); + + sessionMock->markPendingInterruptsOrAddToNewlyStoppedFromRaisedAttention(thread, 1u); + + EXPECT_FALSE(sessionMock->allThreads[thread]->isStopped()); + EXPECT_EQ(0u, sessionMock->newlyStoppedThreads.size()); +} + +TEST(DebugSessionTest, givenPendingInterruptsWhenGeneratingEventsThenStoppedEventIsGeneratedForCompletedInterrupt) { + 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); + + ze_device_thread_t apiThread = {0, 0, 0, 1}; + ze_device_thread_t apiThread2 = {0, 0, 1, 1}; + sessionMock->pendingInterrupts.push_back({apiThread, false}); + sessionMock->pendingInterrupts.push_back({apiThread2, true}); + + sessionMock->generateEventsForPendingInterrupts(); + + EXPECT_EQ(2u, sessionMock->events.size()); + + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_THREAD_UNAVAILABLE, sessionMock->events[0].type); + EXPECT_TRUE(DebugSession::areThreadsEqual(apiThread, sessionMock->events[0].info.thread.thread)); + + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_THREAD_STOPPED, sessionMock->events[1].type); + EXPECT_TRUE(DebugSession::areThreadsEqual(apiThread2, sessionMock->events[1].info.thread.thread)); + + EXPECT_EQ(0u, sessionMock->pendingInterrupts.size()); +} + +TEST(DebugSessionTest, givenEmptyStateSaveAreaWhenGetStateSaveAreaCalledThenReadStateSaveAreaCalled) { + 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); + auto stateSaveArea = sessionMock->getStateSaveAreaHeader(); + EXPECT_EQ(nullptr, stateSaveArea); + EXPECT_EQ(1u, sessionMock->readStateSaveAreaHeaderCalled); +} + +TEST(DebugSessionTest, givenStoppedThreadsWhenFillingResumeAndStoppedThreadsFromNewlyStoppedThenContainerFilledBasedOnExceptionReason) { + 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); + + EuThread::ThreadId thread = {0, 0, 0, 0, 1}; + EuThread::ThreadId thread2 = {0, 0, 0, 1, 1}; + EuThread::ThreadId thread3 = {0, 0, 0, 1, 2}; + + sessionMock->newlyStoppedThreads.push_back(thread); + sessionMock->newlyStoppedThreads.push_back(thread2); + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + sessionMock->onlyForceException = true; + + { + std::vector resumeThreads; + std::vector stoppedThreads; + + sessionMock->allThreads[thread]->stopThread(1u); + sessionMock->allThreads[thread2]->stopThread(1u); + + sessionMock->fillResumeAndStoppedThreadsFromNewlyStopped(resumeThreads, stoppedThreads); + EXPECT_EQ(2u, resumeThreads.size()); + EXPECT_EQ(0u, stoppedThreads.size()); + } + + sessionMock->newlyStoppedThreads.push_back(thread); + sessionMock->newlyStoppedThreads.push_back(thread2); + sessionMock->newlyStoppedThreads.push_back(thread3); + + sessionMock->onlyForceException = false; + { + std::vector resumeThreads; + std::vector stoppedThreads; + + sessionMock->allThreads[thread]->stopThread(1u); + sessionMock->allThreads[thread2]->stopThread(1u); + + sessionMock->fillResumeAndStoppedThreadsFromNewlyStopped(resumeThreads, stoppedThreads); + EXPECT_EQ(0u, resumeThreads.size()); + EXPECT_EQ(2u, stoppedThreads.size()); + } +} + +TEST(DebugSessionTest, givenThreadsToResumeWhenResumeAccidentallyStoppedThreadsCalledThenThreadsResumed) { + class InternalMockDebugSession : public MockDebugSession { + public: + InternalMockDebugSession(const zet_debug_config_t &config, L0::Device *device) : MockDebugSession(config, device) {} + ze_result_t readGpuMemory(uint64_t memoryHandle, char *output, size_t size, uint64_t gpuVa) override { + SIP::sr_ident srMagic; + srMagic.count = counter++; + memcpy_s(output, size, reinterpret_cast(&srMagic), sizeof(srMagic)); + return readMemoryResult; + } + + int counter = 0; + }; + 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); + sessionMock->skipCheckThreadIsResumed = false; + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + EuThread::ThreadId thread = {0, 0, 0, 0, 1}; + EuThread::ThreadId thread2 = {0, 0, 0, 1, 1}; + + std::vector threadIds; + sessionMock->allThreads[thread]->verifyStopped(1u); + sessionMock->allThreads[thread2]->verifyStopped(1u); + + threadIds.push_back(thread); + threadIds.push_back(thread2); + + sessionMock->resumeAccidentallyStoppedThreads(threadIds); + + EXPECT_EQ(2u, sessionMock->resumeThreadCount); + EXPECT_EQ(1u, sessionMock->resumeImpCalled); + EXPECT_EQ(3u, sessionMock->checkThreadIsResumedCalled); + + EXPECT_TRUE(sessionMock->allThreads[thread]->isRunning()); + EXPECT_TRUE(sessionMock->allThreads[thread2]->isRunning()); +} + +TEST(DebugSessionTest, givenCr0RegisterWhenIsFEOrFEHOnlyExceptionReasonThenTrueReturnedForFEorFEHBitsOnly) { + 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); + + uint32_t cr0[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + cr0[1] = 1 << 26; + EXPECT_TRUE(sessionMock->isForceExceptionOrForceExternalHaltOnlyExceptionReasonBase(cr0)); + cr0[1] = 1 << 30; + EXPECT_TRUE(sessionMock->isForceExceptionOrForceExternalHaltOnlyExceptionReasonBase(cr0)); + cr0[1] = (1 << 26) | (1 << 30); + EXPECT_TRUE(sessionMock->isForceExceptionOrForceExternalHaltOnlyExceptionReasonBase(cr0)); + + cr0[1] = (1 << 27) | (1 << 30); + EXPECT_FALSE(sessionMock->isForceExceptionOrForceExternalHaltOnlyExceptionReasonBase(cr0)); + cr0[1] = (1 << 27) | (1 << 26); + EXPECT_FALSE(sessionMock->isForceExceptionOrForceExternalHaltOnlyExceptionReasonBase(cr0)); + cr0[1] = (1 << 28); + EXPECT_FALSE(sessionMock->isForceExceptionOrForceExternalHaltOnlyExceptionReasonBase(cr0)); +} + +TEST(DebugSessionTest, givenSomeThreadsRunningWhenResumeCalledThenOnlyStoppedThreadsResumed) { + 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); + + ze_device_thread_t thread = {0, 0, 0, UINT32_MAX}; + + for (uint32_t i = 0; i < hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount; i++) { + EuThread::ThreadId thread(0, 0, 0, 0, i); + sessionMock->allThreads[thread]->stopThread(1u); + } + + EuThread::ThreadId euthread(0, 0, 0, 0, 3); + sessionMock->allThreads[euthread]->resumeThread(); + + auto result = sessionMock->resume(thread); + + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount - 1u, sessionMock->resumeThreadCount); + + for (uint32_t i = 0; i < hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount; i++) { + EuThread::ThreadId thread(0, 0, 0, 0, i); + EXPECT_TRUE(sessionMock->allThreads[thread]->isRunning()); + } +} + +TEST(DebugSessionTest, givenAllThreadsRunningWhenResumeCalledThenErrorUnavailableReturned) { + 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); + + ze_device_thread_t thread = {0, 0, 0, 1}; + auto result = sessionMock->resume(thread); + EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, result); +} + +TEST(DebugSessionTest, givenErrorFromResumeImpWhenResumeCalledThenErrorReturned) { + 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); + sessionMock->resumeImpResult = ZE_RESULT_ERROR_UNKNOWN; + + ze_device_thread_t thread = {0, 0, 0, 1}; + sessionMock->allThreads[EuThread::ThreadId(0, thread)]->stopThread(1u); + + auto result = sessionMock->resume(thread); + EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, result); +} + +TEST(DebugSessionTest, givenErrorFromReadSbaBufferWhenReadSbaRegistersCalledThenErrorReturned) { + 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); + sessionMock->readSbaBufferResult = ZE_RESULT_ERROR_UNKNOWN; + + ze_device_thread_t thread = {0, 0, 0, 0}; + uint64_t sba[9]; + auto result = sessionMock->readSbaRegisters(thread, 0, 9, sba); + EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, result); +} + +TEST(DebugSessionTest, givenErrorFromReadRegistersWhenReadSbaRegistersCalledThenErrorReturned) { + 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); + sessionMock->readRegistersResult = ZE_RESULT_ERROR_UNKNOWN; + + ze_device_thread_t thread = {0, 0, 0, 0}; + uint64_t sba[9]; + auto result = sessionMock->readSbaRegisters(thread, 0, 9, sba); + EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, result); +} + +HWTEST2_F(DebugSessionTest, givenErrorFromReadMemoryWhenReadSbaRegistersCalledThenErrorReturned, IsAtLeastXeHpCore) { + 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); + sessionMock->readRegistersResult = ZE_RESULT_SUCCESS; + sessionMock->readMemoryResult = ZE_RESULT_ERROR_UNKNOWN; + sessionMock->readRegistersSizeToFill = 6 * sizeof(uint32_t); + + uint32_t *scratchIndex = reinterpret_cast(ptrOffset(sessionMock->regs, 5 * sizeof(uint32_t))); + *scratchIndex = 1u << 10u; + + ze_device_thread_t thread = {0, 0, 0, 0}; + uint64_t sba[9]; + + auto result = sessionMock->readSbaRegisters(thread, 0, 9, sba); + + auto &hwHelper = HwHelper::get(neoDevice->getHardwareInfo().platform.eRenderCoreFamily); + EXPECT_TRUE(hwHelper.isScratchSpaceSurfaceStateAccessible()); + EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, result); +} + +TEST(DebugSessionTest, givenUnknownRegsetTypeWhenTypeToRegsetFlagsCalledThenZeroIsReturned) { + EXPECT_EQ(0u, DebugSessionImp::typeToRegsetFlags(0)); + EXPECT_EQ(0u, DebugSessionImp::typeToRegsetFlags(UINT32_MAX)); +} + +TEST(DebugSessionTest, givenNullptrStateSaveAreaGpuVaWhenCallingCheckIsThreadResumedThenReportThreadHasBeenResumed) { + class InternalMockDebugSession : public MockDebugSession { + public: + InternalMockDebugSession(const zet_debug_config_t &config, L0::Device *device) : MockDebugSession(config, device) {} + uint64_t getContextStateSaveAreaGpuVa(uint64_t memoryHandle) override { + return 0; + }; + }; + 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); + sessionMock->skipCheckThreadIsResumed = false; + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + ze_device_thread_t thread = {0, 0, 0, 0}; + EuThread::ThreadId threadId(0, thread); + bool resumed = sessionMock->checkThreadIsResumed(threadId); + + EXPECT_TRUE(resumed); + EXPECT_EQ(1u, sessionMock->checkThreadIsResumedCalled); +} + +TEST(DebugSessionTest, whenCallingCheckThreadIsResumedWithoutSrMagicThenThreadIsAssumedRunning) { + 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); + sessionMock->skipCheckThreadIsResumed = false; + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + ze_device_thread_t thread = {0, 0, 0, 0}; + EuThread::ThreadId threadId(0, thread); + bool resumed = sessionMock->checkThreadIsResumed(threadId); + + EXPECT_TRUE(resumed); + EXPECT_EQ(1u, sessionMock->checkThreadIsResumedCalled); +} + +TEST(DebugSessionTest, givenSrMagicWithCounterLessThanlLastThreadCounterThenThreadHasBeenResumed) { + class InternalMockDebugSession : public MockDebugSession { + public: + InternalMockDebugSession(const zet_debug_config_t &config, L0::Device *device) : MockDebugSession(config, device) {} + ze_result_t readGpuMemory(uint64_t memoryHandle, char *output, size_t size, uint64_t gpuVa) override { + SIP::sr_ident srMagic; + srMagic.count = 0; + memcpy_s(output, size, reinterpret_cast(&srMagic), sizeof(srMagic)); + return readMemoryResult; + } + }; + 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); + sessionMock->skipCheckThreadIsResumed = false; + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + ze_device_thread_t thread = {0, 0, 0, 0}; + EuThread::ThreadId threadId(0, thread); + sessionMock->allThreads[threadId]->verifyStopped(1u); + sessionMock->allThreads[threadId]->stopThread(1u); + bool resumed = sessionMock->checkThreadIsResumed(threadId); + + EXPECT_TRUE(resumed); + EXPECT_EQ(1u, sessionMock->checkThreadIsResumedCalled); +} + +TEST(DebugSessionTest, givenSrMagicWithCounterEqualToPrevousThenThreadHasNotBeenResumed) { + class InternalMockDebugSession : public MockDebugSession { + public: + InternalMockDebugSession(const zet_debug_config_t &config, L0::Device *device) : MockDebugSession(config, device) {} + ze_result_t readGpuMemory(uint64_t memoryHandle, char *output, size_t size, uint64_t gpuVa) override { + SIP::sr_ident srMagic; + srMagic.count = 1; + memcpy_s(output, size, reinterpret_cast(&srMagic), sizeof(srMagic)); + return readMemoryResult; + } + }; + 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); + sessionMock->skipCheckThreadIsResumed = false; + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + ze_device_thread_t thread = {0, 0, 0, 0}; + EuThread::ThreadId threadId(0, thread); + sessionMock->allThreads[threadId]->verifyStopped(1u); + sessionMock->allThreads[threadId]->stopThread(1u); + + EXPECT_EQ(1u, sessionMock->allThreads[threadId]->getLastCounter()); + + bool resumed = sessionMock->checkThreadIsResumed(threadId); + + EXPECT_FALSE(resumed); +} + +TEST(DebugSessionTest, givenSrMagicWithCounterBiggerThanPreviousThenThreadIsResumed) { + class InternalMockDebugSession : public MockDebugSession { + public: + InternalMockDebugSession(const zet_debug_config_t &config, L0::Device *device) : MockDebugSession(config, device) {} + ze_result_t readGpuMemory(uint64_t memoryHandle, char *output, size_t size, uint64_t gpuVa) override { + SIP::sr_ident srMagic; + srMagic.count = 3; + memcpy_s(output, size, reinterpret_cast(&srMagic), sizeof(srMagic)); + return readMemoryResult; + } + }; + 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); + sessionMock->skipCheckThreadIsResumed = false; + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + ze_device_thread_t thread = {0, 0, 0, 0}; + EuThread::ThreadId threadId(0, thread); + sessionMock->allThreads[threadId]->verifyStopped(1u); + sessionMock->allThreads[threadId]->stopThread(1u); + + EXPECT_EQ(1u, sessionMock->allThreads[threadId]->getLastCounter()); + + bool resumed = sessionMock->checkThreadIsResumed(threadId); + + EXPECT_TRUE(resumed); +} + +TEST(DebugSessionTest, givenSrMagicWithCounterOverflowingZeroThenThreadIsResumed) { + class InternalMockDebugSession : public MockDebugSession { + public: + InternalMockDebugSession(const zet_debug_config_t &config, L0::Device *device) : MockDebugSession(config, device) {} + ze_result_t readGpuMemory(uint64_t memoryHandle, char *output, size_t size, uint64_t gpuVa) override { + SIP::sr_ident srMagic; + srMagic.count = 0; + memcpy_s(output, size, reinterpret_cast(&srMagic), sizeof(srMagic)); + return readMemoryResult; + } + }; + 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); + sessionMock->skipCheckThreadIsResumed = false; + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + ze_device_thread_t thread = {0, 0, 0, 0}; + EuThread::ThreadId threadId(0, thread); + sessionMock->allThreads[threadId]->verifyStopped(255u); + sessionMock->allThreads[threadId]->stopThread(1u); + + EXPECT_EQ(255u, sessionMock->allThreads[threadId]->getLastCounter()); + + bool resumed = sessionMock->checkThreadIsResumed(threadId); + EXPECT_TRUE(resumed); +} + +TEST(DebugSessionTest, GivenBindlessSipVersion1AndResumeWARequiredWhenCallingResumeThenBitInRegisterIsWritten) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + auto hwInfo = *NEO::defaultHwInfo.get(); + auto &l0HwHelper = L0HwHelper::get(hwInfo.platform.eRenderCoreFamily); + + NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + + auto sessionMock = std::make_unique(config, &deviceImp); + ASSERT_NE(nullptr, sessionMock); + sessionMock->readRegistersResult = ZE_RESULT_SUCCESS; + sessionMock->writeRegistersResult = ZE_RESULT_SUCCESS; + sessionMock->readMemoryResult = ZE_RESULT_SUCCESS; + sessionMock->debugArea.reserved1 = 1u; + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(1); + sessionMock->skipWriteResumeCommand = false; + sessionMock->skipCheckThreadIsResumed = false; + + ze_device_thread_t thread = {0, 0, 0, 0}; + EuThread::ThreadId threadId(0, thread); + sessionMock->allThreads[threadId]->stopThread(1u); + + auto result = sessionMock->resume(thread); + EXPECT_EQ(result, ZE_RESULT_SUCCESS); + + if (l0HwHelper.isResumeWARequired()) { + EXPECT_EQ(1u, sessionMock->readRegistersCallCount); + EXPECT_EQ(1u, sessionMock->writeRegistersCallCount); + EXPECT_EQ(1u, sessionMock->writeResumeCommandCalled); + EXPECT_EQ(1u, sessionMock->checkThreadIsResumedCalled); + EXPECT_EQ(uint32_t(ZET_DEBUG_REGSET_TYPE_CR_INTEL_GPU), sessionMock->readRegistersReg); + EXPECT_EQ(uint32_t(ZET_DEBUG_REGSET_TYPE_CR_INTEL_GPU), sessionMock->writeRegistersReg); + } else { + EXPECT_EQ(0u, sessionMock->readRegistersCallCount); + EXPECT_EQ(0u, sessionMock->writeRegistersCallCount); + EXPECT_EQ(1u, sessionMock->writeResumeCommandCalled); + EXPECT_EQ(1u, sessionMock->checkThreadIsResumedCalled); + } + + EXPECT_FALSE(sessionMock->allThreads[threadId]->isStopped()); +} + +TEST(DebugSessionTest, GivenErrorFromReadRegisterWhenResumingThreadThenRegisterIsNotWrittenWithResumeBitAndErrorReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + auto hwInfo = *NEO::defaultHwInfo.get(); + auto &l0HwHelper = L0HwHelper::get(hwInfo.platform.eRenderCoreFamily); + + NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + + auto sessionMock = std::make_unique(config, &deviceImp); + ASSERT_NE(nullptr, sessionMock); + sessionMock->readRegistersResult = ZE_RESULT_ERROR_UNKNOWN; + sessionMock->writeRegistersResult = ZE_RESULT_SUCCESS; + sessionMock->readMemoryResult = ZE_RESULT_SUCCESS; + sessionMock->debugArea.reserved1 = 1u; + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(1); + sessionMock->skipWriteResumeCommand = false; + sessionMock->skipCheckThreadIsResumed = false; + + ze_device_thread_t thread = {0, 0, 0, 0}; + EuThread::ThreadId threadId(0, thread); + sessionMock->allThreads[threadId]->stopThread(1u); + + auto result = sessionMock->resume(thread); + + if (l0HwHelper.isResumeWARequired()) { + EXPECT_EQ(1u, sessionMock->readRegistersCallCount); + EXPECT_EQ(0u, sessionMock->writeRegistersCallCount); + EXPECT_EQ(1u, sessionMock->writeResumeCommandCalled); + EXPECT_EQ(1u, sessionMock->checkThreadIsResumedCalled); + EXPECT_EQ(uint32_t(ZET_DEBUG_REGSET_TYPE_CR_INTEL_GPU), sessionMock->readRegistersReg); + EXPECT_EQ(0u, sessionMock->writeRegistersReg); + EXPECT_EQ(result, ZE_RESULT_ERROR_UNKNOWN); + } else { + EXPECT_EQ(0u, sessionMock->readRegistersCallCount); + EXPECT_EQ(0u, sessionMock->writeRegistersCallCount); + EXPECT_EQ(1u, sessionMock->writeResumeCommandCalled); + EXPECT_EQ(1u, sessionMock->checkThreadIsResumedCalled); + + EXPECT_EQ(result, ZE_RESULT_SUCCESS); + } + + EXPECT_FALSE(sessionMock->allThreads[threadId]->isStopped()); +} + +TEST(DebugSessionTest, GivenErrorFromWriteRegisterWhenResumingThreadThenRegisterIsNotWrittenWithResumeBitAndErrorReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + auto hwInfo = *NEO::defaultHwInfo.get(); + auto &l0HwHelper = L0HwHelper::get(hwInfo.platform.eRenderCoreFamily); + + NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + + auto sessionMock = std::make_unique(config, &deviceImp); + ASSERT_NE(nullptr, sessionMock); + sessionMock->readRegistersResult = ZE_RESULT_SUCCESS; + sessionMock->writeRegistersResult = ZE_RESULT_ERROR_UNKNOWN; + sessionMock->readMemoryResult = ZE_RESULT_SUCCESS; + sessionMock->debugArea.reserved1 = 1u; + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(1); + sessionMock->skipWriteResumeCommand = false; + sessionMock->skipCheckThreadIsResumed = false; + + ze_device_thread_t thread = {0, 0, 0, 0}; + EuThread::ThreadId threadId(0, thread); + sessionMock->allThreads[threadId]->stopThread(1u); + + auto result = sessionMock->resume(thread); + + if (l0HwHelper.isResumeWARequired()) { + EXPECT_EQ(1u, sessionMock->readRegistersCallCount); + EXPECT_EQ(1u, sessionMock->writeRegistersCallCount); + EXPECT_EQ(1u, sessionMock->writeResumeCommandCalled); + EXPECT_EQ(1u, sessionMock->checkThreadIsResumedCalled); + EXPECT_EQ(uint32_t(ZET_DEBUG_REGSET_TYPE_CR_INTEL_GPU), sessionMock->readRegistersReg); + EXPECT_EQ(result, ZE_RESULT_ERROR_UNKNOWN); + } else { + EXPECT_EQ(0u, sessionMock->readRegistersCallCount); + EXPECT_EQ(0u, sessionMock->writeRegistersCallCount); + EXPECT_EQ(1u, sessionMock->writeResumeCommandCalled); + EXPECT_EQ(1u, sessionMock->checkThreadIsResumedCalled); + + EXPECT_EQ(result, ZE_RESULT_SUCCESS); + } + + EXPECT_FALSE(sessionMock->allThreads[threadId]->isStopped()); +} + +TEST(DebugSessionTest, GivenNonBindlessSipVersion1AndResumeWARequiredWhenCallingResumeThenBitInRegisterIsWritten) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + auto hwInfo = *NEO::defaultHwInfo.get(); + auto &l0HwHelper = L0HwHelper::get(hwInfo.platform.eRenderCoreFamily); + + NEO::MockDevice *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + + auto sessionMock = std::make_unique(config, &deviceImp); + ASSERT_NE(nullptr, sessionMock); + sessionMock->readRegistersResult = ZE_RESULT_SUCCESS; + sessionMock->writeRegistersResult = ZE_RESULT_SUCCESS; + sessionMock->readMemoryResult = ZE_RESULT_SUCCESS; + sessionMock->debugArea.reserved1 = 0u; + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(1); + sessionMock->skipWriteResumeCommand = false; + sessionMock->skipCheckThreadIsResumed = false; + + ze_device_thread_t thread = {0, 0, 0, 0}; + EuThread::ThreadId threadId(0, thread); + sessionMock->allThreads[threadId]->stopThread(1u); + + auto result = sessionMock->resume(thread); + EXPECT_EQ(result, ZE_RESULT_SUCCESS); + + if (l0HwHelper.isResumeWARequired()) { + EXPECT_EQ(1u, sessionMock->readRegistersCallCount); + EXPECT_EQ(1u, sessionMock->writeRegistersCallCount); + EXPECT_EQ(1u, sessionMock->writeResumeCommandCalled); + EXPECT_EQ(1u, sessionMock->checkThreadIsResumedCalled); + EXPECT_EQ(uint32_t(ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU), sessionMock->writeRegistersReg); + } else { + EXPECT_EQ(0u, sessionMock->readRegistersCallCount); + EXPECT_EQ(0u, sessionMock->writeRegistersCallCount); + EXPECT_EQ(1u, sessionMock->writeResumeCommandCalled); + EXPECT_EQ(1u, sessionMock->checkThreadIsResumedCalled); + } + + EXPECT_FALSE(sessionMock->allThreads[threadId]->isStopped()); +} + +TEST(DebugSessionTest, GivenBindlessSipVersion2WhenWritingResumeFailsThenErrorIsReturned) { + class InternalMockDebugSession : public MockDebugSession { + public: + InternalMockDebugSession(const zet_debug_config_t &config, L0::Device *device) : MockDebugSession(config, device) {} + ze_result_t readGpuMemory(uint64_t memoryHandle, char *output, size_t size, uint64_t gpuVa) override { + switch (counter) { + case 0: + case 1: + MockDebugSession::readGpuMemory(memoryHandle, output, size, gpuVa); + counter++; + break; + default: + SIP::sr_ident srMagic; + if (firstEntry) { + srMagic.count = 1; + firstEntry = false; + } else { + srMagic.count = 2; + } + memcpy_s(output, size, reinterpret_cast(&srMagic), sizeof(srMagic)); + break; + } + + return readMemoryResult; + } + + private: + int counter = 0; + bool firstEntry = true; + }; + 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); + sessionMock->readRegistersResult = ZE_RESULT_ERROR_UNKNOWN; + sessionMock->writeRegistersResult = ZE_RESULT_ERROR_UNKNOWN; + sessionMock->debugArea.reserved1 = 1u; + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + sessionMock->skipWriteResumeCommand = false; + sessionMock->skipCheckThreadIsResumed = false; + + ze_device_thread_t thread = {0, 0, 0, 0}; + EuThread::ThreadId threadId(0, thread); + sessionMock->allThreads[threadId]->verifyStopped(1); + sessionMock->allThreads[threadId]->stopThread(1u); + + auto result = sessionMock->resume(thread); + EXPECT_EQ(result, ZE_RESULT_ERROR_UNKNOWN); + + EXPECT_EQ(1u, sessionMock->writeResumeCommandCalled); + EXPECT_EQ(2u, sessionMock->checkThreadIsResumedCalled); +} + +TEST(DebugSessionTest, GivenBindlessSipVersion2WhenResumingThreadThenCheckIfThreadIsResumedIsCalledUntilSipCounterIsIncremented) { + class InternalMockDebugSession : public MockDebugSession { + public: + InternalMockDebugSession(const zet_debug_config_t &config, L0::Device *device) : MockDebugSession(config, device) {} + ze_result_t readGpuMemory(uint64_t memoryHandle, char *output, size_t size, uint64_t gpuVa) override { + + SIP::sr_ident srMagic{}; + if (counter > 5) { + srMagic.count = 4; + } else { + srMagic.count = 1; + } + memcpy_s(output, size, reinterpret_cast(&srMagic), sizeof(srMagic)); + + counter++; + return readMemoryResult; + } + int counter = 0; + }; + + 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); + sessionMock->debugArea.reserved1 = 1u; + sessionMock->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + sessionMock->skipCheckThreadIsResumed = false; + + ze_device_thread_t thread = {0, 0, 0, 0}; + EuThread::ThreadId threadId(0, thread); + sessionMock->allThreads[threadId]->verifyStopped(1); + sessionMock->allThreads[threadId]->stopThread(1u); + + auto result = sessionMock->resume(thread); + EXPECT_EQ(result, ZE_RESULT_SUCCESS); + + EXPECT_EQ(1u, sessionMock->writeResumeCommandCalled); + EXPECT_EQ(7u, sessionMock->checkThreadIsResumedCalled); + + sessionMock->allThreads[threadId]->verifyStopped(3); + sessionMock->allThreads[threadId]->stopThread(1u); + + sessionMock->checkThreadIsResumedCalled = 0; + result = sessionMock->resume(thread); + EXPECT_EQ(result, ZE_RESULT_SUCCESS); + + EXPECT_EQ(1u, sessionMock->checkThreadIsResumedCalled); +} + +using MultiTileDebugSessionTest = Test; + +TEST_F(MultiTileDebugSessionTest, givenThreadsFromMultipleTilesWhenResumeCalledThenThreadsResumedInAllTiles) { + zet_debug_config_t config = {}; + config.pid = 0x1234; -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); -} + auto sessionMock = std::make_unique(config, deviceImp); -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); -} - -TEST_F(DebugSessionMultiTile, givenApiThreadAndMultiTileWhenFillingDevicesThenVectorEntriesAreSet) { - L0::Device *device = driverHandle->devices[0]; - - auto debugSession = std::make_unique(zet_debug_config_t{0x1234}, device); + EuThread::ThreadId threadTile0(0, 0, 0, 0, 0); + EuThread::ThreadId threadTile1(1, 0, 0, 0, 0); + sessionMock->allThreads[threadTile0]->stopThread(1u); + sessionMock->allThreads[threadTile1]->stopThread(1u); ze_device_thread_t thread = {UINT32_MAX, 0, 0, 0}; - std::vector devices(numSubDevices); - debugSession->fillDevicesFromThread(thread, devices); + auto result = sessionMock->resume(thread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); - EXPECT_EQ(1u, devices[0]); - EXPECT_EQ(1u, devices[1]); + EXPECT_TRUE(sessionMock->allThreads[threadTile0]->isRunning()); + EXPECT_TRUE(sessionMock->allThreads[threadTile1]->isRunning()); + + EXPECT_EQ(2u, sessionMock->resumeImpCalled); + + sessionMock->allThreads[threadTile1]->stopThread(1u); + + result = sessionMock->resume(thread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + EXPECT_EQ(3u, sessionMock->resumeImpCalled); } -TEST_F(DebugSessionMultiTile, givenApiThreadAndSingleTileWhenFillingDevicesThenVectorEntryIsSet) { +TEST_F(MultiTileDebugSessionTest, givenThreadFromSingleTileWhenResumeCalledThenThreadIsResumed) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + L0::Device *device = driverHandle->devices[0]; + L0::DeviceImp *deviceImp = static_cast(device); - auto debugSession = std::make_unique(zet_debug_config_t{0x1234}, device); + auto sessionMock = std::make_unique(config, deviceImp); - ze_device_thread_t thread = {sliceCount * numSubDevices - 1, 0, 0, 0}; + EuThread::ThreadId threadTile1(1, 0, 0, 0, 0); + sessionMock->allThreads[threadTile1]->stopThread(1u); - std::vector devices(numSubDevices); - debugSession->fillDevicesFromThread(thread, devices); + ze_device_thread_t thread = {sliceCount, 0, 0, 0}; - EXPECT_EQ(0u, devices[0]); - EXPECT_EQ(1u, devices[1]); + auto result = sessionMock->resume(thread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + EXPECT_TRUE(sessionMock->allThreads[threadTile1]->isRunning()); + + EXPECT_EQ(1u, sessionMock->resumeImpCalled); } + +TEST_F(MultiTileDebugSessionTest, givenRunningThreadsWhenResumeCalledThenThreadsNotResumedAndErrorNotAvailableReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + L0::Device *device = driverHandle->devices[0]; + L0::DeviceImp *deviceImp = static_cast(device); + + auto sessionMock = std::make_unique(config, deviceImp); + + EuThread::ThreadId threadTile0(0, 0, 0, 0, 0); + EuThread::ThreadId threadTile1(1, 0, 0, 0, 0); + + ze_device_thread_t thread = {UINT32_MAX, 0, 0, 0}; + auto result = sessionMock->resume(thread); + EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, result); + + EXPECT_EQ(0u, sessionMock->resumeImpCalled); + + EXPECT_TRUE(sessionMock->allThreads[threadTile0]->isRunning()); + EXPECT_TRUE(sessionMock->allThreads[threadTile1]->isRunning()); +} + +TEST_F(MultiTileDebugSessionTest, givenErrorFromResumeWithinDeviceWhenResumeCalledThenThreadsAreResumedAndErrorUnkwnownReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + L0::Device *device = driverHandle->devices[0]; + L0::DeviceImp *deviceImp = static_cast(device); + + auto sessionMock = std::make_unique(config, deviceImp); + + EuThread::ThreadId threadTile0(0, 0, 0, 0, 0); + EuThread::ThreadId threadTile1(1, 0, 0, 0, 0); + sessionMock->allThreads[threadTile0]->stopThread(1u); + sessionMock->allThreads[threadTile1]->stopThread(1u); + + ze_device_thread_t thread = {UINT32_MAX, 0, 0, 0}; + + sessionMock->resumeImpResult = ZE_RESULT_ERROR_NOT_AVAILABLE; + + auto result = sessionMock->resume(thread); + EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, result); + + EXPECT_EQ(2u, sessionMock->resumeImpCalled); + + EXPECT_TRUE(sessionMock->allThreads[threadTile0]->isRunning()); + EXPECT_TRUE(sessionMock->allThreads[threadTile1]->isRunning()); +} + +TEST_F(MultiTileDebugSessionTest, givenOneDeviceRequestWhenSendingInterruptsThenOnlyOneInterruptCalled) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + L0::Device *device = driverHandle->devices[0]; + L0::DeviceImp *deviceImp = static_cast(device); + + auto sessionMock = std::make_unique(config, deviceImp); + + sessionMock->interruptImpResult = ZE_RESULT_SUCCESS; + // Second subdevice's slice + ze_device_thread_t apiThread = {sliceCount, 0, 0, 0}; + + auto result = sessionMock->interrupt(apiThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + sessionMock->sendInterrupts(); + + EXPECT_EQ(1u, sessionMock->interruptImpCalled); + EXPECT_TRUE(sessionMock->interruptSent); + EXPECT_EQ(1u, sessionMock->interruptedDevices[0]); + EXPECT_EQ(1u, sessionMock->expectedAttentionEvents); +} + +TEST_F(MultiTileDebugSessionTest, givenTwoDevicesInRequestsWhenSendingInterruptsThenTwoInterruptsCalled) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + L0::Device *device = driverHandle->devices[0]; + L0::DeviceImp *deviceImp = static_cast(device); + + auto sessionMock = std::make_unique(config, deviceImp); + + sessionMock->interruptImpResult = ZE_RESULT_SUCCESS; + + ze_device_thread_t apiThread = {0, 0, 0, 0}; + ze_device_thread_t apiThread2 = {sliceCount, 0, 0, 0}; + + auto result = sessionMock->interrupt(apiThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + result = sessionMock->interrupt(apiThread2); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + sessionMock->sendInterrupts(); + + EXPECT_EQ(2u, sessionMock->interruptImpCalled); + EXPECT_TRUE(sessionMock->interruptSent); + EXPECT_EQ(0u, sessionMock->interruptedDevices[0]); + EXPECT_EQ(1u, sessionMock->interruptedDevices[1]); + EXPECT_EQ(2u, sessionMock->expectedAttentionEvents); +} + +TEST_F(MultiTileDebugSessionTest, givenAllSlicesInRequestWhenSendingInterruptsThenTwoInterruptsCalled) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + L0::Device *device = driverHandle->devices[0]; + L0::DeviceImp *deviceImp = static_cast(device); + + auto sessionMock = std::make_unique(config, deviceImp); + + sessionMock->interruptImpResult = ZE_RESULT_SUCCESS; + + ze_device_thread_t apiThread = {UINT32_MAX, 0, 0, 0}; + + auto result = sessionMock->interrupt(apiThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + sessionMock->sendInterrupts(); + + EXPECT_EQ(2u, sessionMock->interruptImpCalled); + EXPECT_TRUE(sessionMock->interruptSent); + EXPECT_EQ(0u, sessionMock->interruptedDevices[0]); + EXPECT_EQ(1u, sessionMock->interruptedDevices[1]); + EXPECT_EQ(2u, sessionMock->expectedAttentionEvents); +} + +TEST_F(MultiTileDebugSessionTest, givenTwoInterruptsSentWhenCheckingTriggerEventsThenTriggerEventsWhenAllAttEventsReceived) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + L0::Device *device = driverHandle->devices[0]; + L0::DeviceImp *deviceImp = static_cast(device); + + auto sessionMock = std::make_unique(config, deviceImp); + + sessionMock->interruptImpResult = ZE_RESULT_SUCCESS; + ze_device_thread_t apiThread = {UINT32_MAX, 0, 0, 0}; + + auto result = sessionMock->interrupt(apiThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + sessionMock->sendInterrupts(); + EXPECT_EQ(2u, sessionMock->expectedAttentionEvents); + + sessionMock->newAttentionRaised(0); + EXPECT_EQ(1u, sessionMock->expectedAttentionEvents); + sessionMock->checkTriggerEventsForAttention(); + + EXPECT_FALSE(sessionMock->triggerEvents); + + sessionMock->newAttentionRaised(1); + EXPECT_EQ(0u, sessionMock->expectedAttentionEvents); + sessionMock->checkTriggerEventsForAttention(); + + EXPECT_TRUE(sessionMock->triggerEvents); +} + +TEST_F(MultiTileDebugSessionTest, givenTwoDevicesInRequestsWhenAllInterruptsReturnErrorThenAllInterruptRequestsGenerateUnavailableEvents) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + L0::Device *device = driverHandle->devices[0]; + L0::DeviceImp *deviceImp = static_cast(device); + + auto sessionMock = std::make_unique(config, deviceImp); + + sessionMock->readRegistersResult = ZE_RESULT_SUCCESS; + sessionMock->interruptImpResult = ZE_RESULT_ERROR_UNKNOWN; + + ze_device_thread_t apiThread = {0, 0, 0, 0}; + ze_device_thread_t apiThread2 = {sliceCount, 0, 0, 0}; + + auto result = sessionMock->interrupt(apiThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + result = sessionMock->interrupt(apiThread2); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + EXPECT_EQ(2u, sessionMock->interruptRequests.size()); + + sessionMock->sendInterrupts(); + + EXPECT_EQ(2u, sessionMock->interruptImpCalled); + EXPECT_FALSE(sessionMock->interruptSent); + EXPECT_EQ(0u, sessionMock->interruptedDevices[0]); + EXPECT_EQ(1u, sessionMock->interruptedDevices[1]); + + EXPECT_EQ(0u, sessionMock->expectedAttentionEvents); + EXPECT_EQ(0u, sessionMock->pendingInterrupts.size()); + + EXPECT_EQ(2u, sessionMock->events.size()); + + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_THREAD_UNAVAILABLE, sessionMock->events[0].type); + EXPECT_TRUE(DebugSession::areThreadsEqual(apiThread, sessionMock->events[0].info.thread.thread)); + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_THREAD_UNAVAILABLE, sessionMock->events[1].type); + EXPECT_TRUE(DebugSession::areThreadsEqual(apiThread2, sessionMock->events[1].info.thread.thread)); +} + +TEST_F(MultiTileDebugSessionTest, givenAllSlicesInRequestWhenAllInterruptsReturnErrorThenAllInterruptRequestsGenerateUnavailableEvents) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + L0::Device *device = driverHandle->devices[0]; + L0::DeviceImp *deviceImp = static_cast(device); + + auto sessionMock = std::make_unique(config, deviceImp); + + sessionMock->interruptImpResult = ZE_RESULT_ERROR_UNKNOWN; + + ze_device_thread_t apiThread = {UINT32_MAX, 0, 0, 0}; + + auto result = sessionMock->interrupt(apiThread); + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + + EXPECT_EQ(1u, sessionMock->interruptRequests.size()); + + sessionMock->sendInterrupts(); + + EXPECT_EQ(2u, sessionMock->interruptImpCalled); + EXPECT_FALSE(sessionMock->interruptSent); + EXPECT_EQ(0u, sessionMock->interruptedDevices[0]); + EXPECT_EQ(1u, sessionMock->interruptedDevices[1]); + + EXPECT_EQ(0u, sessionMock->expectedAttentionEvents); + EXPECT_EQ(0u, sessionMock->pendingInterrupts.size()); + + EXPECT_EQ(1u, sessionMock->events.size()); + + EXPECT_EQ(ZET_DEBUG_EVENT_TYPE_THREAD_UNAVAILABLE, sessionMock->events[0].type); + EXPECT_TRUE(DebugSession::areThreadsEqual(apiThread, sessionMock->events[0].info.thread.thread)); +} + +struct DebugSessionRegistersAccess { + void SetUp() { + zet_debug_config_t config = {}; + config.pid = 0x1234; + auto hwInfo = *NEO::defaultHwInfo.get(); + + neoDevice = NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0); + deviceImp = std::make_unique>(neoDevice, neoDevice->getExecutionEnvironment()); + + session = std::make_unique(config, deviceImp.get()); + } + + void TearDown() { + } + + void dumpRegisterState() { + if (session->stateSaveAreaHeader.size() == 0) { + return; + } + auto pStateSaveAreaHeader = reinterpret_cast(session->stateSaveAreaHeader.data()); + + for (uint32_t thread = 0; thread < pStateSaveAreaHeader->regHeader.num_threads_per_eu; thread++) { + EuThread::ThreadId threadId(0, 0, 0, 0, thread); + auto threadSlotOffset = session->calculateThreadSlotOffset(threadId); + + auto srMagicOffset = threadSlotOffset + pStateSaveAreaHeader->regHeader.sr_magic_offset; + SIP::sr_ident srMagic; + srMagic.count = 1; + srMagic.version.major = pStateSaveAreaHeader->versionHeader.version.major; + + session->writeGpuMemory(0, reinterpret_cast(&srMagic), sizeof(srMagic), reinterpret_cast(pStateSaveAreaHeader) + srMagicOffset); + } + } + std::unique_ptr session; + std::unique_ptr> deviceImp; + NEO::MockDevice *neoDevice = nullptr; +}; + +using DebugSessionRegistersAccessTest = Test; + +TEST_F(DebugSessionRegistersAccessTest, givenTypeToRegsetDescCalledThenCorrectRegdescIsReturned) { + session->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + auto pStateSaveAreaHeader = session->getStateSaveAreaHeader(); + + EXPECT_EQ(session->typeToRegsetDesc(ZET_DEBUG_REGSET_TYPE_INVALID_INTEL_GPU), nullptr); + EXPECT_EQ(session->typeToRegsetDesc(ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU), &pStateSaveAreaHeader->regHeader.grf); + EXPECT_EQ(session->typeToRegsetDesc(ZET_DEBUG_REGSET_TYPE_ADDR_INTEL_GPU), &pStateSaveAreaHeader->regHeader.addr); + EXPECT_EQ(session->typeToRegsetDesc(ZET_DEBUG_REGSET_TYPE_FLAG_INTEL_GPU), &pStateSaveAreaHeader->regHeader.flag); + EXPECT_EQ(session->typeToRegsetDesc(ZET_DEBUG_REGSET_TYPE_CE_INTEL_GPU), &pStateSaveAreaHeader->regHeader.emask); + EXPECT_EQ(session->typeToRegsetDesc(ZET_DEBUG_REGSET_TYPE_SR_INTEL_GPU), &pStateSaveAreaHeader->regHeader.sr); + EXPECT_EQ(session->typeToRegsetDesc(ZET_DEBUG_REGSET_TYPE_CR_INTEL_GPU), &pStateSaveAreaHeader->regHeader.cr); + EXPECT_EQ(session->typeToRegsetDesc(ZET_DEBUG_REGSET_TYPE_TDR_INTEL_GPU), &pStateSaveAreaHeader->regHeader.tdr); + EXPECT_EQ(session->typeToRegsetDesc(ZET_DEBUG_REGSET_TYPE_ACC_INTEL_GPU), &pStateSaveAreaHeader->regHeader.acc); + EXPECT_EQ(session->typeToRegsetDesc(ZET_DEBUG_REGSET_TYPE_MME_INTEL_GPU), &pStateSaveAreaHeader->regHeader.mme); + EXPECT_EQ(session->typeToRegsetDesc(ZET_DEBUG_REGSET_TYPE_SP_INTEL_GPU), &pStateSaveAreaHeader->regHeader.sp); + EXPECT_NE(session->typeToRegsetDesc(ZET_DEBUG_REGSET_TYPE_SBA_INTEL_GPU), nullptr); +} + +TEST_F(DebugSessionRegistersAccessTest, givenUnsupportedRegisterTypeWhenReadRegistersCalledThenErrorInvalidArgumentIsReturned) { + session->areRequestedThreadsStoppedReturnValue = 1; + session->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, zetDebugReadRegisters(session->toHandle(), {0, 0, 0, 0}, 0x12345, 0, 1, nullptr)); +} + +TEST_F(DebugSessionRegistersAccessTest, givenUnsupportedRegisterTypeWhenWriteRegistersCalledThenErrorInvalidArgumentIsReturned) { + session->areRequestedThreadsStoppedReturnValue = 1; + session->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, zetDebugWriteRegisters(session->toHandle(), {0, 0, 0, 0}, 0x12345, 0, 1, nullptr)); +} + +TEST_F(DebugSessionRegistersAccessTest, givenInvalidRegistersIndicesWhenReadRegistersCalledThenErrorInvalidArgumentIsReturned) { + session->areRequestedThreadsStoppedReturnValue = 1; + session->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, zetDebugReadRegisters(session->toHandle(), {0, 0, 0, 0}, ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU, 128, 1, nullptr)); + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, zetDebugReadRegisters(session->toHandle(), {0, 0, 0, 0}, ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU, 127, 2, nullptr)); +} + +TEST_F(DebugSessionRegistersAccessTest, givenInvalidRegistersIndicesWheniWriteRegistersCalledThenErrorInvalidArgumentIsReturned) { + session->areRequestedThreadsStoppedReturnValue = 1; + session->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, zetDebugWriteRegisters(session->toHandle(), {0, 0, 0, 0}, ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU, 128, 1, nullptr)); + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, zetDebugWriteRegisters(session->toHandle(), {0, 0, 0, 0}, ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU, 127, 2, nullptr)); +} + +TEST_F(DebugSessionRegistersAccessTest, givenInvalidSbaRegistersIndicesWhenReadSbaRegistersCalledThenErrorInvalidArgumentIsReturned) { + session->areRequestedThreadsStoppedReturnValue = 1; + session->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, zetDebugReadRegisters(session->toHandle(), {0, 0, 0, 0}, ZET_DEBUG_REGSET_TYPE_SBA_INTEL_GPU, 9, 1, nullptr)); + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, zetDebugReadRegisters(session->toHandle(), {0, 0, 0, 0}, ZET_DEBUG_REGSET_TYPE_SBA_INTEL_GPU, 8, 2, nullptr)); +} + +TEST_F(DebugSessionRegistersAccessTest, givenWriteSbaRegistersCalledThenErrorInvalidArgumentIsReturned) { + session->areRequestedThreadsStoppedReturnValue = 1; + session->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, zetDebugWriteRegisters(session->toHandle(), {0, 0, 0, 0}, ZET_DEBUG_REGSET_TYPE_SBA_INTEL_GPU, 0, 1, nullptr)); +} + +TEST_F(DebugSessionRegistersAccessTest, givenNoneThreadsStoppedWhenReadRegistersCalledThenErrorNotAvailableReturned) { + session->areRequestedThreadsStoppedReturnValue = 0; + + char grf[32] = {0}; + EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, zetDebugReadRegisters(session->toHandle(), {0, 0, 0, 0}, ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU, 0, 1, grf)); +} + +TEST_F(DebugSessionRegistersAccessTest, givenNoneThreadsStoppedWhenWriteRegistersCalledThenErrorNotAvailableReturned) { + session->areRequestedThreadsStoppedReturnValue = 0; + + char grf[32] = {0}; + EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, zetDebugWriteRegisters(session->toHandle(), {0, 0, 0, 0}, ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU, 0, 1, grf)); +} + +TEST_F(DebugSessionRegistersAccessTest, givenNoStateSaveAreaWhenReadRegistersCalledThenErrorUnknownReturned) { + session->areRequestedThreadsStoppedReturnValue = 1; + char grf[32] = {0}; + EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, zetDebugReadRegisters(session->toHandle(), {0, 0, 0, 0}, ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU, 0, 1, grf)); +} + +TEST_F(DebugSessionRegistersAccessTest, givenNoStateSaveAreaWhenWriteRegistersCalledThenErrorUnknownReturned) { + session->areRequestedThreadsStoppedReturnValue = 1; + char grf[32] = {0}; + EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, zetDebugWriteRegisters(session->toHandle(), {0, 0, 0, 0}, ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU, 0, 1, grf)); +} + +TEST_F(DebugSessionRegistersAccessTest, givenNoStateSaveAreaGpuVaWhenRegistersAccessHelperCalledThenErrorUnknownReturned) { + session->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + { + auto pStateSaveAreaHeader = reinterpret_cast(session->stateSaveAreaHeader.data()); + auto size = pStateSaveAreaHeader->versionHeader.size * 8 + + pStateSaveAreaHeader->regHeader.state_area_offset + + pStateSaveAreaHeader->regHeader.state_save_size * 16; + session->stateSaveAreaHeader.resize(size); + } + + session->returnStateSaveAreaGpuVa = false; + auto *regdesc = &(reinterpret_cast(session->stateSaveAreaHeader.data()))->regHeader.grf; + uint8_t r0[32]; + EuThread::ThreadId thread0(0, 0, 0, 0, 0); + auto ret = session->registersAccessHelper(session->allThreads[thread0].get(), regdesc, 0, 1, r0, false); + EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, ret); +} + +TEST_F(DebugSessionRegistersAccessTest, givenTssMagicCorruptedWhenRegistersAccessHelperCalledThenErrorUnknownReturned) { + session->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + { + auto pStateSaveAreaHeader = reinterpret_cast(session->stateSaveAreaHeader.data()); + auto size = pStateSaveAreaHeader->versionHeader.size * 8 + + pStateSaveAreaHeader->regHeader.state_area_offset + + pStateSaveAreaHeader->regHeader.state_save_size * 16; + session->stateSaveAreaHeader.resize(size); + } + + session->stateSaveAreaHeader[0] = '!'; + auto *regdesc = &(reinterpret_cast(session->stateSaveAreaHeader.data()))->regHeader.grf; + uint8_t r0[32]; + EuThread::ThreadId thread0(0, 0, 0, 0, 0); + auto ret = session->registersAccessHelper(session->allThreads[thread0].get(), regdesc, 0, 1, r0, false); + EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, ret); +} + +TEST_F(DebugSessionRegistersAccessTest, givenWriteGpuMemoryErrorWhenRegistersAccessHelperCalledThenErrorUnknownReturned) { + session->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + { + auto pStateSaveAreaHeader = reinterpret_cast(session->stateSaveAreaHeader.data()); + auto size = pStateSaveAreaHeader->versionHeader.size * 8 + + pStateSaveAreaHeader->regHeader.state_area_offset + + pStateSaveAreaHeader->regHeader.state_save_size * 16; + session->stateSaveAreaHeader.resize(size); + } + + session->writeMemoryResult = ZE_RESULT_ERROR_UNKNOWN; + auto *regdesc = &(reinterpret_cast(session->stateSaveAreaHeader.data()))->regHeader.grf; + uint8_t r0[32]; + EuThread::ThreadId thread0(0, 0, 0, 0, 0); + auto ret = session->registersAccessHelper(session->allThreads[thread0].get(), regdesc, 0, 1, r0, true); + EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, ret); +} + +TEST_F(DebugSessionRegistersAccessTest, givenReadGpuMemoryErrorWhenRegistersAccessHelperCalledThenErrorUnknownReturned) { + session->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + { + auto pStateSaveAreaHeader = reinterpret_cast(session->stateSaveAreaHeader.data()); + auto size = pStateSaveAreaHeader->versionHeader.size * 8 + + pStateSaveAreaHeader->regHeader.state_area_offset + + pStateSaveAreaHeader->regHeader.state_save_size * 16; + session->stateSaveAreaHeader.resize(size); + } + + session->readMemoryResult = ZE_RESULT_ERROR_UNKNOWN; + auto *regdesc = &(reinterpret_cast(session->stateSaveAreaHeader.data()))->regHeader.grf; + uint8_t r0[32]; + EuThread::ThreadId thread0(0, 0, 0, 0, 0); + auto ret = session->registersAccessHelper(session->allThreads[thread0].get(), regdesc, 0, 1, r0, true); + EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, ret); +} + +TEST_F(DebugSessionRegistersAccessTest, givenNoStateSaveAreaWhenReadRegisterCalledThenErrorUnknownReturned) { + session->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + { + auto pStateSaveAreaHeader = reinterpret_cast(session->stateSaveAreaHeader.data()); + auto size = pStateSaveAreaHeader->versionHeader.size * 8 + + pStateSaveAreaHeader->regHeader.state_area_offset + + pStateSaveAreaHeader->regHeader.state_save_size * 16; + session->stateSaveAreaHeader.resize(size); + } + + session->readMemoryResult = ZE_RESULT_ERROR_UNKNOWN; + auto *regdesc = &(reinterpret_cast(session->stateSaveAreaHeader.data()))->regHeader.grf; + uint8_t r0[32]; + EuThread::ThreadId thread0(0, 0, 0, 0, 0); + auto ret = session->registersAccessHelper(session->allThreads[thread0].get(), regdesc, 0, 1, r0, true); + EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, ret); +} + +TEST_F(DebugSessionRegistersAccessTest, GivenSipVersion2WhenWritingResumeCommandThenCmdRegIsWritten) { + const uint32_t resumeValue = 0; + session->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + { + auto pStateSaveAreaHeader = reinterpret_cast(session->stateSaveAreaHeader.data()); + auto size = pStateSaveAreaHeader->versionHeader.size * 8 + + pStateSaveAreaHeader->regHeader.state_area_offset + + pStateSaveAreaHeader->regHeader.state_save_size * 16; + session->stateSaveAreaHeader.resize(size); + } + + EuThread::ThreadId thread0(0, 0, 0, 0, 0); + EuThread::ThreadId thread3(0, 0, 0, 0, 3); + + std::vector threads; + threads.push_back(thread0); + threads.push_back(thread3); + + dumpRegisterState(); + + session->skipWriteResumeCommand = false; + session->writeResumeCommand(threads); + + auto *regdesc = &(reinterpret_cast(session->stateSaveAreaHeader.data()))->regHeader.cmd; + SIP::sip_command resumeCommand = {0}; + resumeCommand.command = 11; + + session->registersAccessHelper(session->allThreads[thread0].get(), regdesc, 0, 1, &resumeCommand, false); + EXPECT_EQ(resumeValue, resumeCommand.command); + + resumeCommand.command = 11; + session->registersAccessHelper(session->allThreads[thread3].get(), regdesc, 0, 1, &resumeCommand, false); + EXPECT_EQ(resumeValue, resumeCommand.command); +} + +TEST_F(DebugSessionRegistersAccessTest, GivenBindlessSipVersion2WhenCallingResumeThenResumeInCmdRegisterIsWritten) { + session->debugArea.reserved1 = 1u; + session->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + { + auto pStateSaveAreaHeader = reinterpret_cast(session->stateSaveAreaHeader.data()); + auto size = pStateSaveAreaHeader->versionHeader.size * 8 + + pStateSaveAreaHeader->regHeader.state_area_offset + + pStateSaveAreaHeader->regHeader.state_save_size * 16; + session->stateSaveAreaHeader.resize(size); + } + session->skipWriteResumeCommand = false; + + ze_device_thread_t thread = {0, 0, 0, 0}; + EuThread::ThreadId threadId(0, thread); + session->allThreads[threadId]->stopThread(1u); + + dumpRegisterState(); + + auto result = session->resume(thread); + EXPECT_EQ(result, ZE_RESULT_SUCCESS); + + EXPECT_EQ(0u, session->readRegistersCallCount); + EXPECT_EQ(0u, session->writeRegistersCallCount); + EXPECT_EQ(1u, session->writeResumeCommandCalled); +} + +TEST_F(DebugSessionRegistersAccessTest, WhenReadingSbaRegistersThenCorrectAddressesAreReturned) { + session->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + + { + auto pStateSaveAreaHeader = reinterpret_cast(session->stateSaveAreaHeader.data()); + auto size = pStateSaveAreaHeader->versionHeader.size * 8 + + pStateSaveAreaHeader->regHeader.state_area_offset + + pStateSaveAreaHeader->regHeader.state_save_size * 16; + session->stateSaveAreaHeader.resize(size); + } + + auto &hwHelper = HwHelper::get(neoDevice->getHardwareInfo().platform.eRenderCoreFamily); + ze_device_thread_t thread = {0, 0, 0, 0}; + ze_device_thread_t thread1 = {0, 0, 0, 1}; + EuThread::ThreadId threadId(0, thread); + EuThread::ThreadId threadId1(0, thread1); + session->allThreads[threadId]->stopThread(1u); + session->allThreads[threadId1]->stopThread(1u); + + dumpRegisterState(); + + auto threadSlotOffset = session->calculateThreadSlotOffset(threadId); + auto stateSaveAreaHeader = reinterpret_cast(session->stateSaveAreaHeader.data()); + auto grfOffset = threadSlotOffset + stateSaveAreaHeader->regHeader.grf.offset; + uint32_t *r0Thread0 = reinterpret_cast(ptrOffset(session->stateSaveAreaHeader.data(), grfOffset)); + r0Thread0[4] = 0x20 << 5; + + threadSlotOffset = session->calculateThreadSlotOffset(threadId1); + grfOffset = threadSlotOffset + stateSaveAreaHeader->regHeader.grf.offset; + uint32_t *r0Thread1 = reinterpret_cast(ptrOffset(session->stateSaveAreaHeader.data(), grfOffset)); + r0Thread1[4] = 0x24 << 5; + + uint64_t sba[ZET_DEBUG_SBA_COUNT_INTEL_GPU]; + uint64_t sbaExpected[ZET_DEBUG_SBA_COUNT_INTEL_GPU]; + + for (uint32_t i = 0; i < ZET_DEBUG_SBA_COUNT_INTEL_GPU; i++) { + sbaExpected[i] = i * 0x1000; + } + + sbaExpected[ZET_DEBUG_SBA_SURFACE_STATE_INTEL_GPU] = reinterpret_cast(session->readMemoryBuffer); + + session->sba.InstructionBaseAddress = sbaExpected[ZET_DEBUG_SBA_INSTRUCTION_INTEL_GPU]; + session->sba.IndirectObjectBaseAddress = sbaExpected[ZET_DEBUG_SBA_INDIRECT_OBJECT_INTEL_GPU]; + session->sba.GeneralStateBaseAddress = sbaExpected[ZET_DEBUG_SBA_GENERAL_STATE_INTEL_GPU]; + session->sba.DynamicStateBaseAddress = sbaExpected[ZET_DEBUG_SBA_DYNAMIC_STATE_INTEL_GPU]; + session->sba.BindlessSurfaceStateBaseAddress = sbaExpected[ZET_DEBUG_SBA_BINDLESS_SURFACE_INTEL_GPU]; + session->sba.BindlessSamplerStateBaseAddress = sbaExpected[ZET_DEBUG_SBA_BINDLESS_SAMPLER_INTEL_GPU]; + session->sba.SurfaceStateBaseAddress = sbaExpected[ZET_DEBUG_SBA_SURFACE_STATE_INTEL_GPU]; + + auto scratchAllocationBase = 0ULL; + if (hwHelper.isScratchSpaceSurfaceStateAccessible()) { + const uint32_t ptss = 128; + hwHelper.setRenderSurfaceStateForBuffer(neoDevice->getRootDeviceEnvironment(), + &session->readMemoryBuffer[1 * (hwHelper.getRenderSurfaceStateSize() / sizeof(std::decay::type))], 1, scratchAllocationBase, 0, + ptss, nullptr, false, 6, false, true); + + r0Thread0[5] = 1 << 10; // first surface state + } else { + r0Thread0[5] = 0; + } + + EXPECT_EQ(ZE_RESULT_SUCCESS, session->readSbaRegisters(thread, 0, ZET_DEBUG_SBA_COUNT_INTEL_GPU, sba)); + EXPECT_EQ(0ULL, sba[ZET_DEBUG_SBA_SCRATCH_SPACE_INTEL_GPU]); + + scratchAllocationBase = sbaExpected[ZET_DEBUG_SBA_SCRATCH_SPACE_INTEL_GPU]; + uint64_t scratchAllocationBase2 = (1ULL << 47) + 0x12000u; + auto scratchAllocationBase2Canonized = NEO::GmmHelper::canonize(scratchAllocationBase2); + + if (hwHelper.isScratchSpaceSurfaceStateAccessible()) { + const uint32_t ptss = 128; + hwHelper.setRenderSurfaceStateForBuffer(neoDevice->getRootDeviceEnvironment(), + &session->readMemoryBuffer[1 * (hwHelper.getRenderSurfaceStateSize() / sizeof(std::decay::type))], 1, scratchAllocationBase, 0, + ptss, nullptr, false, 6, false, true); + + r0Thread0[5] = 1 << 10; // first surface state + + sbaExpected[ZET_DEBUG_SBA_SCRATCH_SPACE_INTEL_GPU] = scratchAllocationBase; + } else { + r0Thread0[3] = 1; // (2) ^ 1 + r0Thread0[5] = 2 << 10; + sbaExpected[ZET_DEBUG_SBA_SCRATCH_SPACE_INTEL_GPU] = ((r0Thread0[5] >> 10) << 10) + sbaExpected[ZET_DEBUG_SBA_GENERAL_STATE_INTEL_GPU]; + } + + sbaExpected[ZET_DEBUG_SBA_BINDING_TABLE_INTEL_GPU] = ((r0Thread0[4] >> 5) << 5) + sbaExpected[ZET_DEBUG_SBA_SURFACE_STATE_INTEL_GPU]; + + EXPECT_EQ(ZE_RESULT_SUCCESS, session->readSbaRegisters(thread, 0, ZET_DEBUG_SBA_COUNT_INTEL_GPU, sba)); + + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_GENERAL_STATE_INTEL_GPU], sba[ZET_DEBUG_SBA_GENERAL_STATE_INTEL_GPU]); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_SURFACE_STATE_INTEL_GPU], sba[ZET_DEBUG_SBA_SURFACE_STATE_INTEL_GPU]); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_DYNAMIC_STATE_INTEL_GPU], sba[ZET_DEBUG_SBA_DYNAMIC_STATE_INTEL_GPU]); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_INDIRECT_OBJECT_INTEL_GPU], sba[ZET_DEBUG_SBA_INDIRECT_OBJECT_INTEL_GPU]); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_INSTRUCTION_INTEL_GPU], sba[ZET_DEBUG_SBA_INSTRUCTION_INTEL_GPU]); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_BINDLESS_SURFACE_INTEL_GPU], sba[ZET_DEBUG_SBA_BINDLESS_SURFACE_INTEL_GPU]); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_BINDLESS_SAMPLER_INTEL_GPU], sba[ZET_DEBUG_SBA_BINDLESS_SAMPLER_INTEL_GPU]); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_BINDING_TABLE_INTEL_GPU], sba[ZET_DEBUG_SBA_BINDING_TABLE_INTEL_GPU]); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_SCRATCH_SPACE_INTEL_GPU], sba[ZET_DEBUG_SBA_SCRATCH_SPACE_INTEL_GPU]); + + if (hwHelper.isScratchSpaceSurfaceStateAccessible()) { + const uint32_t ptss = 128; + hwHelper.setRenderSurfaceStateForBuffer(neoDevice->getRootDeviceEnvironment(), + &session->readMemoryBuffer[2 * (hwHelper.getRenderSurfaceStateSize() / sizeof(std::decay::type))], 1, scratchAllocationBase2Canonized, 0, + ptss, nullptr, false, 6, false, true); + + r0Thread1[5] = 2 << 10; // second surface state + + sbaExpected[ZET_DEBUG_SBA_SCRATCH_SPACE_INTEL_GPU] = scratchAllocationBase2 + ptss; + } else { + r0Thread1[3] = 2; // (2) ^ 2 + r0Thread1[5] = 2 << 10; + sbaExpected[ZET_DEBUG_SBA_SCRATCH_SPACE_INTEL_GPU] = ((r0Thread1[5] >> 10) << 10) + sbaExpected[ZET_DEBUG_SBA_GENERAL_STATE_INTEL_GPU]; + } + + sbaExpected[ZET_DEBUG_SBA_BINDING_TABLE_INTEL_GPU] = ((r0Thread1[4] >> 5) << 5) + sbaExpected[ZET_DEBUG_SBA_SURFACE_STATE_INTEL_GPU]; + + EXPECT_EQ(ZE_RESULT_SUCCESS, session->readSbaRegisters(thread1, 0, ZET_DEBUG_SBA_COUNT_INTEL_GPU, sba)); + + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_GENERAL_STATE_INTEL_GPU], sba[ZET_DEBUG_SBA_GENERAL_STATE_INTEL_GPU]); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_SURFACE_STATE_INTEL_GPU], sba[ZET_DEBUG_SBA_SURFACE_STATE_INTEL_GPU]); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_DYNAMIC_STATE_INTEL_GPU], sba[ZET_DEBUG_SBA_DYNAMIC_STATE_INTEL_GPU]); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_INDIRECT_OBJECT_INTEL_GPU], sba[ZET_DEBUG_SBA_INDIRECT_OBJECT_INTEL_GPU]); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_INSTRUCTION_INTEL_GPU], sba[ZET_DEBUG_SBA_INSTRUCTION_INTEL_GPU]); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_BINDLESS_SURFACE_INTEL_GPU], sba[ZET_DEBUG_SBA_BINDLESS_SURFACE_INTEL_GPU]); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_BINDLESS_SAMPLER_INTEL_GPU], sba[ZET_DEBUG_SBA_BINDLESS_SAMPLER_INTEL_GPU]); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_BINDING_TABLE_INTEL_GPU], sba[ZET_DEBUG_SBA_BINDING_TABLE_INTEL_GPU]); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_SCRATCH_SPACE_INTEL_GPU], sba[ZET_DEBUG_SBA_SCRATCH_SPACE_INTEL_GPU]); + + if (hwHelper.isScratchSpaceSurfaceStateAccessible()) { + const uint32_t ptss = 0; + hwHelper.setRenderSurfaceStateForBuffer(neoDevice->getRootDeviceEnvironment(), + &session->readMemoryBuffer[0], 1, 0xdeadbeef, 0, + ptss, nullptr, false, 6, false, true); + + r0Thread1[5] = 0; // Surface state at index 0 + } else { + r0Thread1[3] = 0; + r0Thread1[5] = 0; + } + sbaExpected[ZET_DEBUG_SBA_SCRATCH_SPACE_INTEL_GPU] = 0; + + EXPECT_EQ(ZE_RESULT_SUCCESS, session->readSbaRegisters(thread1, 0, ZET_DEBUG_SBA_COUNT_INTEL_GPU, sba)); + EXPECT_EQ(sbaExpected[ZET_DEBUG_SBA_SCRATCH_SPACE_INTEL_GPU], sba[ZET_DEBUG_SBA_SCRATCH_SPACE_INTEL_GPU]); +} + +TEST(DebugSessionTest, givenCanonicalOrDecanonizedAddressWhenCheckingValidAddressThenTrueReturned) { + 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); + + uint64_t address = 0xffffffff12345678; + + EXPECT_TRUE(sessionMock->isValidGpuAddress(address)); + + auto decanonized = NEO::GmmHelper::decanonize(address); + EXPECT_TRUE(sessionMock->isValidGpuAddress(decanonized)); +} + +TEST(DebugSessionTest, givenInvalidAddressWhenCheckingValidAddressThenFalseIsReturned) { + 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); + + uint64_t address = maxNBitValue(NEO::MockGmmHelper::addressWidth) << 1 | 0x4000; + + EXPECT_FALSE(sessionMock->isValidGpuAddress(address)); +} + +TEST(DebugSessionTest, givenDebugSessionWhenGettingTimeDiffThenDiffReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto sessionMock = std::make_unique(config, nullptr); + + auto now = std::chrono::high_resolution_clock::now(); + auto diff = sessionMock->getTimeDifferenceMilliseconds(now); + + EXPECT_LE(0, diff); +} + +TEST(DebugSessionTest, givenDebugSessionWhenGetContextSaveAreaGpuVaCalledThenZeroIsReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto sessionMock = std::make_unique(config, nullptr); + sessionMock->returnStateSaveAreaGpuVa = false; + + EXPECT_EQ(0ULL, sessionMock->getContextStateSaveAreaGpuVa(1ULL)); +} + +TEST(DebugSessionTest, givenNewAttentionRaisedWithNoExpectedAttentionThenExpectedAttentionNotChanged) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto sessionMock = std::make_unique(config, nullptr); + EXPECT_EQ(0UL, sessionMock->expectedAttentionEvents); + sessionMock->newAttentionRaised(0); + EXPECT_EQ(0UL, sessionMock->expectedAttentionEvents); +} + +TEST(DebugSessionTest, givenNoPendingInterruptsOrNoNewlyStoppedThreadsAndCheckTriggerEventsForAttentionThenDoNotTriggerEvents) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto sessionMock = std::make_unique(config, nullptr); + + sessionMock->triggerEvents = false; + sessionMock->expectedAttentionEvents = 0; + sessionMock->pendingInterrupts.clear(); + sessionMock->newlyStoppedThreads.clear(); + + sessionMock->checkTriggerEventsForAttention(); + EXPECT_FALSE(sessionMock->triggerEvents); + + ze_device_thread_t apiThread = {0, 0, 0, 1}; + sessionMock->pendingInterrupts.push_back({apiThread, false}); + + sessionMock->checkTriggerEventsForAttention(); + EXPECT_TRUE(sessionMock->triggerEvents); + + EuThread::ThreadId thread = {0, 0, 0, 0, 1}; + sessionMock->pendingInterrupts.clear(); + sessionMock->newlyStoppedThreads.push_back(thread); + + EXPECT_TRUE(sessionMock->triggerEvents); +} + +TEST(DebugSessionTest, givenNoPendingInterruptsWhenSendInterruptsCalledThenNoInterruptsSent) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto sessionMock = std::make_unique(config, nullptr); + sessionMock->interruptSent = false; + sessionMock->pendingInterrupts.clear(); + sessionMock->sendInterrupts(); + EXPECT_FALSE(sessionMock->interruptSent); +} + } // namespace ult } // namespace L0 diff --git a/level_zero/tools/test/unit_tests/sources/debug/debug_session_thread_tests.cpp b/level_zero/tools/test/unit_tests/sources/debug/debug_session_thread_tests.cpp new file mode 100644 index 0000000000..d1a05151ce --- /dev/null +++ b/level_zero/tools/test/unit_tests/sources/debug/debug_session_thread_tests.cpp @@ -0,0 +1,603 @@ +/* + * Copyright (C) 2021-2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#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 "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/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(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(DebugSession, givenSingleThreadWhenGettingSingleThreadsThenCorrectThreadIsReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto hwInfo = *NEO::defaultHwInfo.get(); + NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + auto debugSession = std::make_unique(config, &deviceImp); + + auto subslice = hwInfo.gtSystemInfo.MaxSubSlicesSupported / hwInfo.gtSystemInfo.MaxSlicesSupported - 1; + ze_device_thread_t physicalThread = {0, subslice, 2, 3}; + + auto threads = debugSession->getSingleThreadsForDevice(0, physicalThread, hwInfo); + + EXPECT_EQ(1u, threads.size()); + + EXPECT_EQ(0u, threads[0].tileIndex); + 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(DebugSession, givenAllThreadsWhenGettingSingleThreadsThenCorrectThreadsAreReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto hwInfo = *NEO::defaultHwInfo.get(); + NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + auto debugSession = std::make_unique(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->getSingleThreadsForDevice(0, physicalThread, hwInfo); + + EXPECT_EQ(numThreadsPerEu, threads.size()); + + for (uint32_t i = 0; i < numThreadsPerEu; i++) { + EXPECT_EQ(0u, threads[i].tileIndex); + 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(DebugSession, givenAllEUsWhenGettingSingleThreadsThenCorrectThreadsAreReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto hwInfo = *NEO::defaultHwInfo.get(); + NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + auto debugSession = std::make_unique(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->getSingleThreadsForDevice(0, 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(DebugSession, givenAllSubslicesWhenGettingSingleThreadsThenCorrectThreadsAreReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto hwInfo = *NEO::defaultHwInfo.get(); + NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + auto debugSession = std::make_unique(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->getSingleThreadsForDevice(0, 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(DebugSession, givenAllSlicesWhenGettingSingleThreadsThenCorrectThreadsAreReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto hwInfo = *NEO::defaultHwInfo.get(); + NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + auto debugSession = std::make_unique(config, &deviceImp); + + ze_device_thread_t physicalThread = {UINT32_MAX, 0, 0, 0}; + const uint32_t numSlices = hwInfo.gtSystemInfo.MaxSlicesSupported; + + auto threads = debugSession->getSingleThreadsForDevice(0, physicalThread, hwInfo); + + EXPECT_EQ(numSlices, threads.size()); + + for (uint32_t i = 0; i < numSlices; i++) { + EXPECT_EQ(0u, threads[i].tileIndex); + EXPECT_EQ(i, threads[i].slice); + EXPECT_EQ(0u, threads[i].subslice); + EXPECT_EQ(0u, threads[i].eu); + EXPECT_EQ(0u, threads[i].thread); + } +} + +TEST(DebugSession, givenBindlessSystemRoutineWhenQueryingIsBindlessThenTrueReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto hwInfo = *NEO::defaultHwInfo.get(); + NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + auto debugSession = std::make_unique(config, &deviceImp); + + debugSession->debugArea.reserved1 = 1u; + + EXPECT_TRUE(debugSession->isBindlessSystemRoutine()); +} + +TEST(DebugSession, givenBindfulSystemRoutineWhenQueryingIsBindlessThenFalseReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + auto hwInfo = *NEO::defaultHwInfo.get(); + NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(&hwInfo, 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + auto debugSession = std::make_unique(config, &deviceImp); + + debugSession->debugArea.reserved1 = 0u; + + EXPECT_FALSE(debugSession->isBindlessSystemRoutine()); +} + +TEST(DebugSession, 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); +} + +TEST(DebugSession, givenAllStoppedThreadsWhenAreRequestedThreadsStoppedCalledThenTrueReturned) { + 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); + + for (uint32_t i = 0; i < hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount; i++) { + EuThread::ThreadId thread(0, 0, 0, 0, i); + sessionMock->allThreads[thread]->stopThread(1u); + } + + ze_device_thread_t apiThread = {0, 0, 0, UINT32_MAX}; + EXPECT_TRUE(sessionMock->areRequestedThreadsStopped(apiThread)); +} + +TEST(DebugSession, givenSomeStoppedThreadsWhenAreRequestedThreadsStoppedCalledThenFalseReturned) { + 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); + + for (uint32_t i = 0; i < hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount; i++) { + EuThread::ThreadId thread(0, 0, 0, 0, i); + if (i % 2) { + sessionMock->allThreads[thread]->stopThread(1u); + } + } + + ze_device_thread_t apiThread = {0, 0, 0, UINT32_MAX}; + EXPECT_FALSE(sessionMock->areRequestedThreadsStopped(apiThread)); +} + +TEST(DebugSession, givenApiThreadAndSingleTileWhenFillingDevicesThenVectorEntryIsSet) { + 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}; + + std::vector devices(1); + debugSession->fillDevicesFromThread(thread, devices); + + EXPECT_EQ(1u, devices[0]); +} + +TEST(DebugSession, givenDifferentCombinationsOfThreadsAndMemoryTypeCheckExpectedMemoryAccess) { + 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); + ze_device_thread_t thread = {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX}; + zet_debug_memory_space_desc_t desc; + desc.address = 0x1000; + desc.type = ZET_DEBUG_MEMORY_SPACE_TYPE_DEFAULT; + + ze_result_t retVal = sessionMock->sanityMemAccessThreadCheck(thread, &desc); + EXPECT_EQ(ZE_RESULT_SUCCESS, retVal); + + desc.type = ZET_DEBUG_MEMORY_SPACE_TYPE_SLM; + + retVal = sessionMock->sanityMemAccessThreadCheck(thread, &desc); + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, retVal); + + thread = {1, 1, UINT32_MAX, UINT32_MAX}; + retVal = sessionMock->sanityMemAccessThreadCheck(thread, &desc); + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_ARGUMENT, retVal); + + thread = {0, 0, 0, 1}; + retVal = sessionMock->sanityMemAccessThreadCheck(thread, &desc); + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, retVal); + + desc.type = ZET_DEBUG_MEMORY_SPACE_TYPE_DEFAULT; + + retVal = sessionMock->sanityMemAccessThreadCheck(thread, &desc); + EXPECT_EQ(ZE_RESULT_ERROR_NOT_AVAILABLE, retVal); + + for (uint32_t i = 0; i < hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount; i++) { + EuThread::ThreadId thread(0, 0, 0, 0, i); + sessionMock->allThreads[thread]->stopThread(1u); + } + + retVal = sessionMock->sanityMemAccessThreadCheck(thread, &desc); + EXPECT_EQ(ZE_RESULT_SUCCESS, retVal); +} + +TEST(DebugSession, givenDifferentThreadsWhenGettingPerThreadScratchOffsetThenCorrectOffsetReturned) { + 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); + + const uint32_t numThreadsPerEu = (hwInfo.gtSystemInfo.ThreadCount / hwInfo.gtSystemInfo.EUCount); + EuThread::ThreadId thread0Eu0 = {0, 0, 0, 0, 0}; + EuThread::ThreadId thread0Eu1 = {0, 0, 0, 1, 0}; + EuThread::ThreadId thread2Subslice1 = {0, 0, 1, 0, 2}; + + const uint32_t ptss = 128; + + auto size = debugSession->getPerThreadScratchOffset(ptss, thread0Eu0); + EXPECT_EQ(0u, size); + + size = debugSession->getPerThreadScratchOffset(ptss, thread0Eu1); + EXPECT_EQ(ptss * numThreadsPerEu, size); + + size = debugSession->getPerThreadScratchOffset(ptss, thread2Subslice1); + EXPECT_EQ(2 * ptss + ptss * hwInfo.gtSystemInfo.MaxEuPerSubSlice * numThreadsPerEu, size); +} + +TEST(DebugSession, GivenLogsEnabledWhenPrintBitmaskCalledThenBitmaskIsPrinted) { + DebugManagerStateRestore restorer; + NEO::DebugManager.flags.DebuggerLogBitmask.set(255); + + ::testing::internal::CaptureStdout(); + + uint64_t bitmask[2] = {0x404080808080, 0x1111ffff1111ffff}; + DebugSession::printBitmask(reinterpret_cast(bitmask), sizeof(bitmask)); + + auto output = ::testing::internal::GetCapturedStdout(); + + EXPECT_THAT(output, testing::HasSubstr(std::string("\nINFO: Bitmask: "))); + EXPECT_THAT(output, testing::HasSubstr(std::string("[0] = 0x0000404080808080"))); + EXPECT_THAT(output, testing::HasSubstr(std::string("[1] = 0x1111ffff1111ffff"))); +} + +TEST(DebugSession, GivenLogsDisabledWhenPrintBitmaskCalledThenBitmaskIsNotPrinted) { + DebugManagerStateRestore restorer; + NEO::DebugManager.flags.DebuggerLogBitmask.set(0); + + ::testing::internal::CaptureStdout(); + + uint64_t bitmask[2] = {0x404080808080, 0x1111ffff1111ffff}; + DebugSession::printBitmask(reinterpret_cast(bitmask), sizeof(bitmask)); + + auto output = ::testing::internal::GetCapturedStdout(); + + EXPECT_EQ(0u, output.size()); +} + +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); +} + +TEST_F(DebugSessionMultiTile, givenApiThreadAndMultiTileWhenFillingDevicesThenVectorEntriesAreSet) { + L0::Device *device = driverHandle->devices[0]; + + auto debugSession = std::make_unique(zet_debug_config_t{0x1234}, device); + + ze_device_thread_t thread = {UINT32_MAX, 0, 0, 0}; + + std::vector devices(numSubDevices); + debugSession->fillDevicesFromThread(thread, devices); + + EXPECT_EQ(1u, devices[0]); + EXPECT_EQ(1u, devices[1]); +} + +TEST_F(DebugSessionMultiTile, givenApiThreadAndSingleTileWhenFillingDevicesThenVectorEntryIsSet) { + L0::Device *device = driverHandle->devices[0]; + + auto debugSession = std::make_unique(zet_debug_config_t{0x1234}, device); + + ze_device_thread_t thread = {sliceCount * numSubDevices - 1, 0, 0, 0}; + + std::vector devices(numSubDevices); + debugSession->fillDevicesFromThread(thread, devices); + + EXPECT_EQ(0u, devices[0]); + EXPECT_EQ(1u, devices[1]); +} +} // namespace ult +} // namespace L0 diff --git a/level_zero/tools/test/unit_tests/sources/debug/test_debug_api.cpp b/level_zero/tools/test/unit_tests/sources/debug/test_debug_api.cpp index bd433a87aa..95d5464b40 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/test_debug_api.cpp +++ b/level_zero/tools/test/unit_tests/sources/debug/test_debug_api.cpp @@ -1,77 +1,178 @@ /* - * Copyright (C) 2021 Intel Corporation + * Copyright (C) 2021-2022 Intel Corporation * * SPDX-License-Identifier: MIT * */ -#include "level_zero/tools/test/unit_tests/sources/debug/test_debug_api.inl" - +#include "shared/test/common/mocks/mock_device.h" +#include "shared/test/common/mocks/mock_sip.h" #include "shared/test/common/test_macros/test.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/include/zet_intel_gpu_debug.h" #include "level_zero/tools/source/debug/debug_handlers.h" +#include "level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h" namespace L0 { namespace ult { -TEST_F(DebugApiTest, givenDeviceWhenDebugAttachIsCalledThenNullptrSessionHandleAndErrorAreReturned) { +struct DebugApiFixture : public DeviceFixture { + void SetUp() { + DeviceFixture::SetUp(); + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface); + mockBuiltins = new MockBuiltins(); + mockBuiltins->stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->builtins.reset(mockBuiltins); + } + + void TearDown() { + DeviceFixture::TearDown(); + } + + MockBuiltins *mockBuiltins = nullptr; +}; + +using DebugApiTest = Test; + +TEST_F(DebugApiTest, givenDeviceWhenGettingDebugPropertiesThenNoFlagIsSet) { + 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); +} + +TEST_F(DebugApiTest, givenDeviceWhenCallingDebugAttachThenErrorIsReturned) { zet_debug_config_t config = {}; config.pid = 0x1234; + zet_debug_session_handle_t debugSession = nullptr; + + auto result = zetDebugAttach(device->toHandle(), &config, &debugSession); + + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result); + EXPECT_EQ(nullptr, debugSession); +} + +TEST_F(DebugApiTest, givenSubDeviceWhenCallingDebugAttachThenErrorIsReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + zet_debug_session_handle_t debugSession = nullptr; Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + deviceImp.isSubdevice = true; - zet_debug_session_handle_t debugSession = nullptr; auto result = zetDebugAttach(deviceImp.toHandle(), &config, &debugSession); EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result); EXPECT_EQ(nullptr, debugSession); } -TEST_F(DebugApiTest, givenDebugSessionSetWhenGettingDebugSessionThenCorrectObjectIsReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; +using isDebugSupportedProduct = IsWithinProducts; +HWTEST2_F(DebugApiTest, givenDeviceWhenDebugAttachIsAvaialbleThenGetPropertiesReturnsCorrectFlag, isDebugSupportedProduct) { + zet_device_debug_properties_t debugProperties = {}; + debugProperties.flags = ZET_DEVICE_DEBUG_PROPERTY_FLAG_FORCE_UINT32; - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - deviceImp.debugSession = std::make_unique(config, &deviceImp); + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new OsInterfaceWithDebugAttach); - EXPECT_NE(nullptr, deviceImp.getDebugSession(config)); + auto result = zetDeviceGetDebugProperties(device->toHandle(), &debugProperties); + + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(ZET_DEVICE_DEBUG_PROPERTY_FLAG_ATTACH, debugProperties.flags); } -TEST_F(DebugApiTest, givenNoDebugSessionWhenGettingDebugSessionThenNullptrIsReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; +using isDebugNotSupportedProduct = IsNotWithinProducts; +HWTEST2_F(DebugApiTest, givenDeviceWhenDebugIsNotSupportedThenGetPropertiesReturnsCorrectFlag, isDebugNotSupportedProduct) { + zet_device_debug_properties_t debugProperties = {}; + debugProperties.flags = ZET_DEVICE_DEBUG_PROPERTY_FLAG_FORCE_UINT32; - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - deviceImp.debugSession.release(); - EXPECT_EQ(nullptr, deviceImp.getDebugSession(config)); + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new OsInterfaceWithDebugAttach); + + auto result = zetDeviceGetDebugProperties(device->toHandle(), &debugProperties); + + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(0u, debugProperties.flags); } -TEST_F(DebugApiTest, givenSubdeviceWhenGettingDebugSessionThenNullptrIsReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; +TEST_F(DebugApiTest, givenStateSaveAreaHeaderUnavailableWhenGettingDebugPropertiesThenAttachFlagIsNotReturned) { + zet_device_debug_properties_t debugProperties = {}; + debugProperties.flags = ZET_DEVICE_DEBUG_PROPERTY_FLAG_FORCE_UINT32; + + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new OsInterfaceWithDebugAttach); + mockBuiltins->stateSaveAreaHeader.clear(); + + auto result = zetDeviceGetDebugProperties(device->toHandle(), &debugProperties); + + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(0u, debugProperties.flags); +} + +TEST_F(DebugApiTest, givenSubDeviceWhenDebugAttachIsAvaialbleThenGetPropertiesReturnsNoFlag) { + zet_device_debug_properties_t debugProperties = {}; + debugProperties.flags = ZET_DEVICE_DEBUG_PROPERTY_FLAG_FORCE_UINT32; + + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new OsInterfaceWithDebugAttach); Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); deviceImp.isSubdevice = true; - EXPECT_EQ(nullptr, deviceImp.getDebugSession(config)); + + auto result = zetDeviceGetDebugProperties(deviceImp.toHandle(), &debugProperties); + + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(0u, debugProperties.flags); } -TEST(DebugSessionTest, WhenDebugSessionCreateIsCalledThenNullptrReturned) { - ze_result_t result; +TEST_F(DebugApiTest, givenDeviceWithDebugSessionWhenDebugAttachIsCalledThenSessionHandleIsReturned) { zet_debug_config_t config = {}; config.pid = 0x1234; - L0::DebugSession *session = L0::DebugSession::create(config, nullptr, result); - EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result); - EXPECT_EQ(nullptr, session); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + deviceImp.debugSession.reset(new DebugSessionMock(config, &deviceImp)); + + zet_debug_session_handle_t debugSession = nullptr; + auto result = zetDebugAttach(deviceImp.toHandle(), &config, &debugSession); + + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(deviceImp.debugSession->toHandle(), debugSession); } -TEST(DebugSessionTest, WhenUnsupportedFunctionCalledThenErrorIsReturned) { - zet_debug_session_handle_t session = {}; +TEST_F(DebugApiTest, givenDeviceWithDebugSessionWhenDebugDetachIsCalledThenSuccessIsReturnedAndSessionDeleted) { + zet_debug_config_t config = {}; + config.pid = 0x1234; - auto result = L0::DebugApiHandlers::debugDetach(session); - EXPECT_EQ(result, ZE_RESULT_ERROR_UNSUPPORTED_FEATURE); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + deviceImp.debugSession.reset(new DebugSessionMock(config, &deviceImp)); - result = L0::DebugApiHandlers::debugReadEvent(session, 0, nullptr); + zet_debug_session_handle_t debugSession = deviceImp.debugSession->toHandle(); + auto result = zetDebugDetach(debugSession); + + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(nullptr, deviceImp.debugSession); +} + +TEST_F(DebugApiTest, givenDeviceWithoutSessionWhenDebugDetachIsCalledThenSuccessIsReturned) { + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + + zet_debug_session_handle_t debugSession = 0; + auto result = zetDebugDetach(debugSession); + + EXPECT_EQ(ZE_RESULT_SUCCESS, result); + EXPECT_EQ(nullptr, deviceImp.debugSession); +} + +TEST_F(DebugApiTest, WhenUnsupportedFunctionCalledThenErrorIsReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + deviceImp.debugSession.reset(new DebugSessionMock(config, &deviceImp)); + + zet_debug_session_handle_t session = deviceImp.debugSession->toHandle(); + + auto result = L0::DebugApiHandlers::debugReadEvent(session, 0, nullptr); EXPECT_EQ(result, ZE_RESULT_ERROR_UNSUPPORTED_FEATURE); ze_device_thread_t thread = {}; @@ -90,10 +191,6 @@ TEST(DebugSessionTest, WhenUnsupportedFunctionCalledThenErrorIsReturned) { result = L0::DebugApiHandlers::debugAcknowledgeEvent(session, nullptr); EXPECT_EQ(result, ZE_RESULT_ERROR_UNSUPPORTED_FEATURE); - zet_device_handle_t hDevice = {}; - result = L0::DebugApiHandlers::debugGetRegisterSetProperties(hDevice, nullptr, nullptr); - EXPECT_EQ(result, ZE_RESULT_ERROR_UNSUPPORTED_FEATURE); - uint32_t type = {0}; result = L0::DebugApiHandlers::debugReadRegisters(session, thread, type, 0, 0, nullptr); EXPECT_EQ(result, ZE_RESULT_ERROR_UNSUPPORTED_FEATURE); @@ -102,5 +199,152 @@ TEST(DebugSessionTest, WhenUnsupportedFunctionCalledThenErrorIsReturned) { EXPECT_EQ(result, ZE_RESULT_ERROR_UNSUPPORTED_FEATURE); } +TEST_F(DebugApiTest, givenNullCountPointerWhenGetRegisterSetPropertiesCalledThenInvalidNullPointerIsReturned) { + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_NULL_POINTER, zetDebugGetRegisterSetProperties(device->toHandle(), nullptr, nullptr)); +} + +TEST_F(DebugApiTest, givenZeroCountWhenGetRegisterSetPropertiesCalledThenCorrectCountIsSet) { + uint32_t count = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, zetDebugGetRegisterSetProperties(device->toHandle(), &count, nullptr)); + EXPECT_EQ(10u, count); +} + +TEST_F(DebugApiTest, givenGetRegisterSetPropertiesCalledAndExtraSpaceIsProvidedThenCorrectPropertiesReturned) { + uint32_t count = 100; + std::vector regsetProps(count); + EXPECT_EQ(ZE_RESULT_SUCCESS, zetDebugGetRegisterSetProperties(device->toHandle(), &count, regsetProps.data())); + EXPECT_EQ(10u, count); +} + +TEST_F(DebugApiTest, givenNoStateSaveHeaderWhenGettingRegSetPropertiesThenZeroCountIsReturned) { + uint32_t count = 10; + std::vector regsetProps(count); + + mockBuiltins->stateSaveAreaHeader.clear(); + + EXPECT_EQ(ZE_RESULT_SUCCESS, zetDebugGetRegisterSetProperties(device->toHandle(), &count, regsetProps.data())); + EXPECT_EQ(0u, count); +} + +TEST_F(DebugApiTest, givenNonZeroCountAndNullRegsetPointerWhenGetRegisterSetPropertiesCalledTheniInvalidNullPointerIsReturned) { + uint32_t count = 12; + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_NULL_POINTER, zetDebugGetRegisterSetProperties(device->toHandle(), &count, nullptr)); +} + +TEST_F(DebugApiTest, givenGetRegisterSetPropertiesCalledCorrectPropertiesReturned) { + uint32_t count = 0; + EXPECT_EQ(ZE_RESULT_SUCCESS, zetDebugGetRegisterSetProperties(device->toHandle(), &count, nullptr)); + EXPECT_EQ(10u, count); + + std::vector regsetProps(count); + EXPECT_EQ(ZE_RESULT_SUCCESS, zetDebugGetRegisterSetProperties(device->toHandle(), &count, regsetProps.data())); + + EXPECT_EQ(10u, count); + + auto validateRegsetProps = [](const zet_debug_regset_properties_t ®setProps, + zet_debug_regset_type_intel_gpu_t type, zet_debug_regset_flags_t flags, + uint32_t num, uint32_t bits, uint32_t bytes) { + EXPECT_EQ(regsetProps.stype, ZET_STRUCTURE_TYPE_DEBUG_REGSET_PROPERTIES); + EXPECT_EQ(regsetProps.pNext, nullptr); + EXPECT_EQ(regsetProps.type, type); + EXPECT_EQ(regsetProps.version, 0u); + EXPECT_EQ(regsetProps.generalFlags, flags); + EXPECT_EQ(regsetProps.count, num); + EXPECT_EQ(regsetProps.bitSize, bits); + EXPECT_EQ(regsetProps.byteSize, bytes); + }; + + validateRegsetProps(regsetProps[0], ZET_DEBUG_REGSET_TYPE_GRF_INTEL_GPU, ZET_DEBUG_REGSET_FLAG_READABLE | ZET_DEBUG_REGSET_FLAG_WRITEABLE, 128, 256, 32); + validateRegsetProps(regsetProps[1], ZET_DEBUG_REGSET_TYPE_ADDR_INTEL_GPU, ZET_DEBUG_REGSET_FLAG_READABLE | ZET_DEBUG_REGSET_FLAG_WRITEABLE, 1, 256, 32); + validateRegsetProps(regsetProps[2], ZET_DEBUG_REGSET_TYPE_FLAG_INTEL_GPU, ZET_DEBUG_REGSET_FLAG_READABLE | ZET_DEBUG_REGSET_FLAG_WRITEABLE, 2, 32, 4); + validateRegsetProps(regsetProps[3], ZET_DEBUG_REGSET_TYPE_CE_INTEL_GPU, ZET_DEBUG_REGSET_FLAG_READABLE, 1, 32, 4); + validateRegsetProps(regsetProps[4], ZET_DEBUG_REGSET_TYPE_SR_INTEL_GPU, ZET_DEBUG_REGSET_FLAG_READABLE | ZET_DEBUG_REGSET_FLAG_WRITEABLE, 2, 128, 16); + validateRegsetProps(regsetProps[5], ZET_DEBUG_REGSET_TYPE_CR_INTEL_GPU, ZET_DEBUG_REGSET_FLAG_READABLE | ZET_DEBUG_REGSET_FLAG_WRITEABLE, 1, 128, 16); + validateRegsetProps(regsetProps[6], ZET_DEBUG_REGSET_TYPE_TDR_INTEL_GPU, ZET_DEBUG_REGSET_FLAG_READABLE, 1, 128, 16); + validateRegsetProps(regsetProps[7], ZET_DEBUG_REGSET_TYPE_ACC_INTEL_GPU, ZET_DEBUG_REGSET_FLAG_READABLE | ZET_DEBUG_REGSET_FLAG_WRITEABLE, 10, 256, 32); + // MME is not present + validateRegsetProps(regsetProps[8], ZET_DEBUG_REGSET_TYPE_SP_INTEL_GPU, ZET_DEBUG_REGSET_FLAG_READABLE | ZET_DEBUG_REGSET_FLAG_WRITEABLE, 1, 128, 16); + validateRegsetProps(regsetProps[9], ZET_DEBUG_REGSET_TYPE_SBA_INTEL_GPU, ZET_DEBUG_REGSET_FLAG_READABLE, ZET_DEBUG_SBA_COUNT_INTEL_GPU, 64, 8); +} + +TEST(DebugSessionTest, givenDebugSessionWhenConvertingToAndFromHandleCorrectHandleAndPointerIsReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(NEO::defaultHwInfo.get(), 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + auto debugSession = std::make_unique(config, &deviceImp); + L0::DebugSession *session = debugSession.get(); + + zet_debug_session_handle_t debugSessionHandle = debugSession->toHandle(); + auto sessionFromHandle = L0::DebugSession::fromHandle(session); + + EXPECT_NE(nullptr, debugSessionHandle); + EXPECT_EQ(session, sessionFromHandle); +} + +TEST(DebugSessionTest, givenDebugSessionWhenGettingConnectedDeviceThenCorrectDeviceIsReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(NEO::defaultHwInfo.get(), 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + auto debugSession = std::make_unique(config, &deviceImp); + L0::DebugSession *session = debugSession.get(); + + auto device = session->getConnectedDevice(); + + EXPECT_EQ(&deviceImp, device); +} + +TEST(DebugSessionTest, givenDeviceWithDebugSessionWhenRemoveCalledThenSessionIsNotDeleted) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(NEO::defaultHwInfo.get(), 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + auto debugSession = std::make_unique(config, &deviceImp); + L0::DebugSession *session = debugSession.get(); + deviceImp.debugSession.reset(session); + deviceImp.removeDebugSession(); + + EXPECT_EQ(nullptr, deviceImp.debugSession.get()); +} + +TEST(DebugSessionTest, givenSubDeviceWhenCreateingSessionThenNullptrReturned) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(NEO::defaultHwInfo.get(), 0)); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + deviceImp.isSubdevice = true; + + ze_result_t result = ZE_RESULT_ERROR_DEVICE_LOST; + auto session = deviceImp.createDebugSession(config, result); + + EXPECT_EQ(nullptr, session); + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result); +} + +TEST(DebugSessionTest, givenRootDeviceWhenCreateingSessionThenResultReturnedIsCorrect) { + zet_debug_config_t config = {}; + config.pid = 0x1234; + + NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(NEO::defaultHwInfo.get(), 0)); + + auto osInterface = new OsInterfaceWithDebugAttach; + osInterface->debugAttachAvailable = false; + + neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0]->osInterface.reset(osInterface); + Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); + deviceImp.isSubdevice = false; + + ze_result_t result = ZE_RESULT_ERROR_DEVICE_LOST; + auto session = deviceImp.createDebugSession(config, result); + + EXPECT_EQ(nullptr, session); + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result); +} + } // namespace ult } // namespace L0 diff --git a/level_zero/tools/test/unit_tests/sources/debug/test_debug_api.inl b/level_zero/tools/test/unit_tests/sources/debug/test_debug_api.inl deleted file mode 100644 index e747d5000d..0000000000 --- a/level_zero/tools/test/unit_tests/sources/debug/test_debug_api.inl +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2021-2022 Intel Corporation - * - * SPDX-License-Identifier: MIT - * - */ - -#include "shared/test/common/mocks/mock_device.h" -#include "shared/test/common/test_macros/test.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/tools/test/unit_tests/sources/debug/mock_debug_session.h" - -namespace L0 { -namespace ult { - -struct DebugApiFixture : public DeviceFixture { - void SetUp() { - DeviceFixture::SetUp(); - neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface); - } - - void TearDown() { - DeviceFixture::TearDown(); - } -}; - -using DebugApiTest = Test; - -TEST_F(DebugApiTest, givenDeviceWhenGettingDebugPropertiesThenNoFlagIsSet) { - 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); -} - -TEST_F(DebugApiTest, givenDeviceWhenCallingDebugAttachThenErrorIsReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - zet_debug_session_handle_t debugSession = nullptr; - - auto result = zetDebugAttach(device->toHandle(), &config, &debugSession); - - EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result); - EXPECT_EQ(nullptr, debugSession); -} - -TEST_F(DebugApiTest, givenSubDeviceWhenCallingDebugAttachThenErrorIsReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - zet_debug_session_handle_t debugSession = nullptr; - - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - deviceImp.isSubdevice = true; - - auto result = zetDebugAttach(deviceImp.toHandle(), &config, &debugSession); - - EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result); - EXPECT_EQ(nullptr, debugSession); -} - -using isDebugSupportedProduct = IsWithinProducts; -HWTEST2_F(DebugApiTest, givenDeviceWhenDebugAttachIsAvaialbleThenGetPropertiesReturnsCorrectFlag, isDebugSupportedProduct) { - zet_device_debug_properties_t debugProperties = {}; - debugProperties.flags = ZET_DEVICE_DEBUG_PROPERTY_FLAG_FORCE_UINT32; - - neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new OsInterfaceWithDebugAttach); - - auto result = zetDeviceGetDebugProperties(device->toHandle(), &debugProperties); - - EXPECT_EQ(ZE_RESULT_SUCCESS, result); - EXPECT_EQ(ZET_DEVICE_DEBUG_PROPERTY_FLAG_ATTACH, debugProperties.flags); -} - -using isDebugNotSupportedProduct = IsNotWithinProducts; -HWTEST2_F(DebugApiTest, givenDeviceWhenDebugIsNotSupportedThenGetPropertiesReturnsCorrectFlag, isDebugNotSupportedProduct) { - zet_device_debug_properties_t debugProperties = {}; - debugProperties.flags = ZET_DEVICE_DEBUG_PROPERTY_FLAG_FORCE_UINT32; - - neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new OsInterfaceWithDebugAttach); - - auto result = zetDeviceGetDebugProperties(device->toHandle(), &debugProperties); - - EXPECT_EQ(ZE_RESULT_SUCCESS, result); - EXPECT_EQ(0u, debugProperties.flags); -} - -TEST_F(DebugApiTest, givenStateSaveAreaHeaderUnavailableWhenGettingDebugPropertiesThenAttachFlagIsNotReturned) { - zet_device_debug_properties_t debugProperties = {}; - debugProperties.flags = ZET_DEVICE_DEBUG_PROPERTY_FLAG_FORCE_UINT32; - - neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new OsInterfaceWithDebugAttach); - mockBuiltIns->stateSaveAreaHeader.clear(); - - auto result = zetDeviceGetDebugProperties(device->toHandle(), &debugProperties); - - EXPECT_EQ(ZE_RESULT_SUCCESS, result); - EXPECT_EQ(0u, debugProperties.flags); -} - -TEST_F(DebugApiTest, givenSubDeviceWhenDebugAttachIsAvaialbleThenGetPropertiesReturnsNoFlag) { - zet_device_debug_properties_t debugProperties = {}; - debugProperties.flags = ZET_DEVICE_DEBUG_PROPERTY_FLAG_FORCE_UINT32; - - neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new OsInterfaceWithDebugAttach); - - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - deviceImp.isSubdevice = true; - - auto result = zetDeviceGetDebugProperties(deviceImp.toHandle(), &debugProperties); - - EXPECT_EQ(ZE_RESULT_SUCCESS, result); - EXPECT_EQ(0u, debugProperties.flags); -} - -TEST(DebugSessionTest, givenDebugSessionWhenConvertingToAndFromHandleCorrectHandleAndPointerIsReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - - NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(NEO::defaultHwInfo.get(), 0)); - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - auto debugSession = std::make_unique(config, &deviceImp); - L0::DebugSession *session = debugSession.get(); - - zet_debug_session_handle_t debugSessionHandle = debugSession->toHandle(); - auto sessionFromHandle = L0::DebugSession::fromHandle(session); - - EXPECT_NE(nullptr, debugSessionHandle); - EXPECT_EQ(session, sessionFromHandle); -} - -TEST(DebugSessionTest, givenDebugSessionWhenGettingConnectedDeviceThenCorrectDeviceIsReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - - NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(NEO::defaultHwInfo.get(), 0)); - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - auto debugSession = std::make_unique(config, &deviceImp); - L0::DebugSession *session = debugSession.get(); - - auto device = session->getConnectedDevice(); - - EXPECT_EQ(&deviceImp, device); -} - -TEST(DebugSessionTest, givenDeviceWithDebugSessionWhenRemoveCalledThenSessionIsNotDeleted) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - - NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(NEO::defaultHwInfo.get(), 0)); - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - auto debugSession = std::make_unique(config, &deviceImp); - L0::DebugSession *session = debugSession.get(); - deviceImp.debugSession.reset(session); - deviceImp.removeDebugSession(); - - EXPECT_EQ(nullptr, deviceImp.debugSession.get()); -} - -TEST(DebugSessionTest, givenSubDeviceWhenCreateingSessionThenNullptrReturned) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - - NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(NEO::defaultHwInfo.get(), 0)); - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - deviceImp.isSubdevice = true; - - ze_result_t result = ZE_RESULT_ERROR_DEVICE_LOST; - auto session = deviceImp.createDebugSession(config, result); - - EXPECT_EQ(nullptr, session); - EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result); -} - -TEST(DebugSessionTest, givenRootDeviceWhenCreateingSessionThenResultReturnedIsCorrect) { - zet_debug_config_t config = {}; - config.pid = 0x1234; - - NEO::Device *neoDevice(NEO::MockDevice::createWithNewExecutionEnvironment(NEO::defaultHwInfo.get(), 0)); - - auto osInterface = new OsInterfaceWithDebugAttach; - osInterface->debugAttachAvailable = false; - - neoDevice->getExecutionEnvironment()->rootDeviceEnvironments[0]->osInterface.reset(osInterface); - Mock deviceImp(neoDevice, neoDevice->getExecutionEnvironment()); - deviceImp.isSubdevice = false; - - ze_result_t result = ZE_RESULT_ERROR_DEVICE_LOST; - auto session = deviceImp.createDebugSession(config, result); - - EXPECT_EQ(nullptr, session); - EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result); -} - -} // namespace ult -} // namespace L0 diff --git a/level_zero/tools/test/unit_tests/sources/debug/windows/CMakeLists.txt b/level_zero/tools/test/unit_tests/sources/debug/windows/CMakeLists.txt new file mode 100644 index 0000000000..e51666e18f --- /dev/null +++ b/level_zero/tools/test/unit_tests/sources/debug/windows/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright (C) 2021-2022 Intel Corporation +# +# SPDX-License-Identifier: MIT +# + +if(WIN32) + target_sources(${TARGET_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/test_debug_api_windows.cpp + ) +endif() 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 new file mode 100644 index 0000000000..bb5a674fec --- /dev/null +++ b/level_zero/tools/test/unit_tests/sources/debug/windows/test_debug_api_windows.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021-2022 Intel Corporation + * + * SPDX-License-Identifier: MIT + * + */ + +#include "shared/test/common/test_macros/test.h" + +#include "level_zero/core/test/unit_tests/fixtures/device_fixture.h" + +namespace L0 { +namespace ult { + +struct DebugApiWindowsFixture : public DeviceFixture { + void SetUp() { + DeviceFixture::SetUp(); + neoDevice->executionEnvironment->rootDeviceEnvironments[0]->osInterface.reset(new NEO::OSInterface); + } + + void TearDown() { + DeviceFixture::TearDown(); + } +}; + +using DebugApiWinTest = Test; + +TEST_F(DebugApiWinTest, givenDeviceWhenGettingDebugPropertiesThanNoFlagIsSet) { + 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); +} + +TEST_F(DebugApiWinTest, givenDeviceWhenCallingDebugAttachThenErrorIsReturned) { + + zet_debug_config_t config = {}; + config.pid = 0x1234; + zet_debug_session_handle_t debugSession = nullptr; + + auto result = zetDebugAttach(device->toHandle(), &config, &debugSession); + + EXPECT_EQ(ZE_RESULT_ERROR_UNSUPPORTED_FEATURE, result); + EXPECT_EQ(nullptr, debugSession); +} + +} // namespace ult +} // namespace L0