diff --git a/level_zero/tools/source/debug/debug_session_imp.cpp b/level_zero/tools/source/debug/debug_session_imp.cpp index 10ed0b1dfe..c5056e1870 100644 --- a/level_zero/tools/source/debug/debug_session_imp.cpp +++ b/level_zero/tools/source/debug/debug_session_imp.cpp @@ -11,6 +11,7 @@ #include "shared/source/execution_environment/root_device_environment.h" #include "shared/source/gmm_helper/gmm_helper.h" #include "shared/source/helpers/basic_math.h" +#include "shared/source/helpers/file_io.h" #include "shared/source/helpers/gfx_core_helper.h" #include "shared/source/helpers/hw_info.h" #include "shared/source/helpers/sleep.h" @@ -985,7 +986,23 @@ ze_result_t DebugSessionImp::readEvent(uint64_t timeout, zet_debug_event_t *outp return ZE_RESULT_NOT_READY; } +void DebugSessionImp::dumpDebugSurfaceToFile(uint64_t vmHandle, uint64_t gpuVa, const std::string &path) { + auto stateSaveAreaSize = getContextStateSaveAreaSize(vmHandle); + std::vector data(stateSaveAreaSize); + auto retVal = readGpuMemory(vmHandle, data.data(), data.size(), gpuVa); + if (retVal != ZE_RESULT_SUCCESS) { + PRINT_DEBUGGER_ERROR_LOG("Reading context state save area failed, error = %d\n", retVal); + return; + } + writeDataToFile(path.c_str(), std::string_view(data.data(), data.size())); +} + void DebugSessionImp::validateAndSetStateSaveAreaHeader(uint64_t vmHandle, uint64_t gpuVa) { + const std::string dumpDebugSurfacePath = NEO::debugManager.flags.DumpDebugSurfaceFile.get(); + if (dumpDebugSurfacePath != "unk") { + dumpDebugSurfaceToFile(vmHandle, gpuVa, dumpDebugSurfacePath); + } + auto headerSize = sizeof(NEO::StateSaveAreaHeader); std::vector data(headerSize); auto retVal = readGpuMemory(vmHandle, data.data(), sizeof(SIP::StateSaveArea), gpuVa); diff --git a/level_zero/tools/source/debug/debug_session_imp.h b/level_zero/tools/source/debug/debug_session_imp.h index 81480fa257..6d217f595b 100644 --- a/level_zero/tools/source/debug/debug_session_imp.h +++ b/level_zero/tools/source/debug/debug_session_imp.h @@ -118,6 +118,7 @@ struct DebugSessionImp : DebugSession { MOCKABLE_VIRTUAL void generateEventsForPendingInterrupts(); const NEO::StateSaveAreaHeader *getStateSaveAreaHeader(); + void dumpDebugSurfaceToFile(uint64_t vmHandle, uint64_t gpuVa, const std::string &path); void validateAndSetStateSaveAreaHeader(uint64_t vmHandle, uint64_t gpuVa); virtual void readStateSaveAreaHeader(){}; MOCKABLE_VIRTUAL ze_result_t readFifo(uint64_t vmHandle, std::vector &threadsWithAttention); 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 b7c2ebb5b4..037dcead90 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 @@ -26,6 +26,10 @@ #include "common/StateSaveAreaHeader.h" #include "encode_surface_state_args.h" +namespace NEO { +extern std::map virtualFileList; +} + namespace L0 { namespace ult { @@ -1183,7 +1187,7 @@ TEST(DebugSessionTest, givenMultipleStoppedThreadsAndInvalidStateSaveAreaWhenRes MockDeviceImp deviceImp(neoDevice); auto sessionMock = std::make_unique(config, &deviceImp); - sessionMock->forceZeroStateSaveAreaSize = true; + sessionMock->forceStateSaveAreaSize = 0; auto threadCount = hwInfo.gtSystemInfo.NumThreadsPerEu; for (uint32_t i = 0; i < threadCount; i++) { @@ -2122,6 +2126,54 @@ TEST_F(DebugSessionTest, GivenInvalidSwFifoNodeWhenCheckingIsValidNodeAndOnReadi EXPECT_EQ(ZE_RESULT_ERROR_UNKNOWN, session->isValidNode(0, reinterpret_cast(session->readMemoryBuffer.data()), invalidNode)); } +TEST_F(DebugSessionTest, givenDumpDebugSurfaceFileWhenStateSaveAreaIsReadThenDebugSurfaceFileIsDumped) { + static constexpr const char *filePath = "test_dump_file.bin"; + DebugManagerStateRestore restorer; + NEO::debugManager.flags.DumpDebugSurfaceFile.set(filePath); + + const std::vector stateSaveAreaContent = {0xaa, 0xbb, 0xcc, 0xdd}; + + MockDeviceImp deviceImp(NEO::MockDevice::createWithNewExecutionEnvironment(NEO::defaultHwInfo.get(), 0)); + + auto session = std::make_unique(zet_debug_config_t{}, &deviceImp); + session->readMemoryBuffer.assign(stateSaveAreaContent.cbegin(), stateSaveAreaContent.cend()); + session->forceStateSaveAreaSize = session->readMemoryBuffer.size(); + session->validateAndSetStateSaveAreaHeader(0, reinterpret_cast(session->readMemoryBuffer.data())); + + EXPECT_EQ(1u, NEO::virtualFileList.size()); + EXPECT_TRUE(NEO::virtualFileList.find(filePath) != NEO::virtualFileList.end()); + auto content = NEO::virtualFileList.at(filePath).str(); + EXPECT_EQ(stateSaveAreaContent, std::vector(content.cbegin(), content.cend())); +} + +TEST_F(DebugSessionTest, givenNoDumpDebugSurfaceFileWhenStateSaveAreaIsReadThenDebugSurfaceFileIsNotDumped) { + const std::vector stateSaveAreaContent = {0xaa, 0xbb, 0xcc, 0xdd}; + + MockDeviceImp deviceImp(NEO::MockDevice::createWithNewExecutionEnvironment(NEO::defaultHwInfo.get(), 0)); + auto session = std::make_unique(zet_debug_config_t{}, &deviceImp); + + session->readMemoryBuffer.assign(stateSaveAreaContent.cbegin(), stateSaveAreaContent.cend()); + session->forceStateSaveAreaSize = session->readMemoryBuffer.size(); + + session->validateAndSetStateSaveAreaHeader(0, reinterpret_cast(session->readMemoryBuffer.data())); + + EXPECT_EQ(0u, NEO::virtualFileList.size()); +} + +TEST_F(DebugSessionTest, givenDumpDebugSurfaceFileWhenStateSaveAreaIsReadAndReadGpuMemoryFailsThenDebugSurfaceFileIsNotDumped) { + static constexpr const char *filePath = "test_dump_file.bin"; + DebugManagerStateRestore restorer; + NEO::debugManager.flags.DumpDebugSurfaceFile.set(filePath); + + MockDeviceImp deviceImp(NEO::MockDevice::createWithNewExecutionEnvironment(NEO::defaultHwInfo.get(), 0)); + + auto session = std::make_unique(zet_debug_config_t{}, &deviceImp); + session->readMemoryResult = ZE_RESULT_ERROR_UNKNOWN; + session->validateAndSetStateSaveAreaHeader(0, reinterpret_cast(session->readMemoryBuffer.data())); + + EXPECT_EQ(0u, NEO::virtualFileList.size()); +} + TEST_F(DebugSessionTest, givenTssMagicCorruptedWhenStateSaveAreIsReadThenHeaderIsNotSet) { auto stateSaveAreaHeader = MockSipData::createStateSaveAreaHeader(2); auto versionHeader = &reinterpret_cast(stateSaveAreaHeader.data())->versionHeader; diff --git a/level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h b/level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h index 7edd8d817f..4f847f1cd4 100644 --- a/level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h +++ b/level_zero/tools/test/unit_tests/sources/debug/mock_debug_session.h @@ -155,6 +155,7 @@ struct MockDebugSession : public L0::DebugSessionImp { using L0::DebugSessionImp::calculateSrMagicOffset; using L0::DebugSessionImp::calculateThreadSlotOffset; using L0::DebugSessionImp::checkTriggerEventsForAttention; + using L0::DebugSessionImp::dumpDebugSurfaceToFile; using L0::DebugSessionImp::fillResumeAndStoppedThreadsFromNewlyStopped; using L0::DebugSessionImp::generateEventsAndResumeStoppedThreads; using L0::DebugSessionImp::generateEventsForPendingInterrupts; @@ -494,8 +495,8 @@ struct MockDebugSession : public L0::DebugSessionImp { }; size_t getContextStateSaveAreaSize(uint64_t memoryHandle) override { - if (forceZeroStateSaveAreaSize) { - return 0; + if (forceStateSaveAreaSize.has_value()) { + return forceStateSaveAreaSize.value(); } if (stateSaveAreaHeader.size()) { auto header = getStateSaveAreaHeader(); @@ -589,7 +590,7 @@ struct MockDebugSession : public L0::DebugSessionImp { int64_t returnTimeDiff = -1; bool returnStateSaveAreaGpuVa = true; - bool forceZeroStateSaveAreaSize = false; + std::optional forceStateSaveAreaSize = std::nullopt; bool attachTileCalled = false; bool detachTileCalled = false; diff --git a/shared/source/debug_settings/debug_variables_base.inl b/shared/source/debug_settings/debug_variables_base.inl index 597bdfef69..655a74a33a 100644 --- a/shared/source/debug_settings/debug_variables_base.inl +++ b/shared/source/debug_settings/debug_variables_base.inl @@ -94,6 +94,7 @@ DECLARE_DEBUG_VARIABLE(std::string, FilterDeviceId, std::string("unk"), "Device DECLARE_DEBUG_VARIABLE(std::string, FilterBdfPath, std::string("unk"), "Linux-only, BDF path filter, only matching paths will be opened; ignored when unk") DECLARE_DEBUG_VARIABLE(std::string, LoadBinarySipFromFile, std::string("unk"), "Select binary file to load SIP kernel raw binary; when file named *_header.* exists, it is used as header") DECLARE_DEBUG_VARIABLE(std::string, DumpSipHeaderFile, std::string("unk"), "Dumps binary file with sip header, value is used as NAME in filename: NAME_header.bin; ignored when unk") +DECLARE_DEBUG_VARIABLE(std::string, DumpDebugSurfaceFile, std::string("unk"), "Dumps debug surface file; ignored when unk") DECLARE_DEBUG_VARIABLE(std::string, InjectInternalBuildOptions, std::string("unk"), "Append provided string to internal build options for user modules; ignored when unk") DECLARE_DEBUG_VARIABLE(std::string, InjectApiBuildOptions, std::string("unk"), "Append provided string to api build options for user modules; ignored when unk") DECLARE_DEBUG_VARIABLE(std::string, OverrideDeviceName, std::string("unk"), "Override device name to provided string; ignored when unk") diff --git a/shared/test/common/test_files/igdrcl.config b/shared/test/common/test_files/igdrcl.config index f627ff0bc9..f312ec5798 100644 --- a/shared/test/common/test_files/igdrcl.config +++ b/shared/test/common/test_files/igdrcl.config @@ -42,6 +42,7 @@ FilterDeviceId = unk FilterBdfPath = unk LoadBinarySipFromFile = unk DumpSipHeaderFile = unk +DumpDebugSurfaceFile = unk InjectInternalBuildOptions = unk InjectApiBuildOptions = unk OverrideCsrAllocationSize = -1