├── .gitignore ├── .readthedocs.yaml ├── Buildinfo.properties.in ├── CMakeLists.txt ├── License.txt ├── README.md ├── RGD_NOTICES.txt ├── RGD_RELEASE_NOTES.txt ├── _clang-format ├── build ├── dependency_map.py ├── fetch_dependencies.py ├── pre_build.py └── utils │ └── get_version.py ├── documentation ├── Makefile ├── make.bat ├── requirements.txt └── source │ ├── _static │ ├── style.css │ └── theme_overrides.css │ ├── _templates │ └── layout.html │ ├── conf.py │ ├── help_manual.rst │ ├── images │ ├── driver-experiments-select-api.png │ ├── driver-experiments-select-experiment.png │ ├── enable-crash-analysis.png │ ├── enable-driver-experiments.png │ ├── open-text-summary.png │ ├── rgd-advanced-options.png │ └── select-text-output-format.png │ └── index.rst ├── external ├── .gitattributes ├── amd_gpu_dis │ ├── Include │ │ └── CodeObjectDisassemblerApi.h │ └── Lib │ │ ├── Linux │ │ └── x64 │ │ │ └── libamdgpu_dis.so │ │ └── VS2022 │ │ └── x64 │ │ ├── amdgpu_dis.dll │ │ └── amdgpu_dis.lib └── dev_driver │ └── include │ └── rgdevents.h ├── samples └── sample_crash_dump.rgd ├── source ├── radeon_gpu_detective_backend │ ├── CMakeLists.txt │ ├── rgd_amd_gpu_dis_loader.cpp │ ├── rgd_amd_gpu_dis_loader.h │ ├── rgd_asic_info.cpp │ ├── rgd_asic_info.h │ ├── rgd_code_object_comgr_handle.h │ ├── rgd_code_object_database.cpp │ ├── rgd_code_object_database.h │ ├── rgd_crash_info_registers_parser.h │ ├── rgd_crash_info_registers_parser_context.cpp │ ├── rgd_crash_info_registers_parser_context.h │ ├── rgd_crash_info_registers_parser_rdna2.cpp │ ├── rgd_crash_info_registers_parser_rdna2.h │ ├── rgd_crash_info_registers_parser_rdna3.cpp │ ├── rgd_crash_info_registers_parser_rdna3.h │ ├── rgd_crash_info_registers_parser_rdna4.cpp │ ├── rgd_crash_info_registers_parser_rdna4.h │ ├── rgd_data_types.h │ ├── rgd_enhanced_crash_info_serializer.cpp │ ├── rgd_enhanced_crash_info_serializer.h │ ├── rgd_exec_marker_tree_serializer.cpp │ ├── rgd_exec_marker_tree_serializer.h │ ├── rgd_hash.h │ ├── rgd_marker_data_serializer.cpp │ ├── rgd_marker_data_serializer.h │ ├── rgd_parsing_utils.cpp │ ├── rgd_parsing_utils.h │ ├── rgd_register_parsing_utils.cpp │ ├── rgd_register_parsing_utils.h │ ├── rgd_resource_info_serializer.cpp │ ├── rgd_resource_info_serializer.h │ ├── rgd_serializer.cpp │ ├── rgd_serializer.h │ ├── rgd_serializer_json.cpp │ ├── rgd_serializer_json.h │ ├── rgd_utils.cpp │ ├── rgd_utils.h │ └── rgd_version_info.h.in └── radeon_gpu_detective_cli │ ├── CMakeLists.txt │ ├── main.cpp │ └── windows │ ├── resource.h │ └── rgd.rc └── test ├── RGD_TEST_README.md ├── scripts ├── TestRunner.py └── input_description_files │ ├── RgdAllTests.json │ └── RgdDriverSanity.json └── source └── rgd_test ├── CMakeLists.txt ├── main.cpp ├── test_rgd_file.cpp └── test_rgd_file.h /.gitignore: -------------------------------------------------------------------------------- 1 | build/CMake 2 | build/win 3 | build/linux 4 | .vscode 5 | *.vs 6 | *.csproj.user 7 | obj 8 | build/__pycache__ 9 | external/rmv 10 | external/update_check_api 11 | external/system_info_utils 12 | external/rdf 13 | external/third_party 14 | external/comgr_package 15 | Buildinfo.properties 16 | rgd_version_info.h 17 | documentation/build 18 | *~ 19 | *.aps -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the version of Python and other tools you might need 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3.11" 13 | 14 | # Build documentation in the docs/source directory with Sphinx 15 | sphinx: 16 | configuration: documentation/source/conf.py 17 | 18 | # We recommend specifying your dependencies to enable reproducible builds: 19 | # https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 20 | python: 21 | install: 22 | - requirements: documentation/requirements.txt -------------------------------------------------------------------------------- /Buildinfo.properties.in: -------------------------------------------------------------------------------- 1 | BUILD_NUMBER=@RGD_BUILD_NUMBER@ 2 | VERSION_NUMBER=@RGD_MAJOR_VERSION@.@RGD_MINOR_VERSION@ -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #============================================================================= 2 | # Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | # @author AMD Developer Tools Team 4 | # @file 5 | # @brief Top level CMakeLists file. 6 | #============================================================================= 7 | 8 | cmake_minimum_required (VERSION 3.10) 9 | project (RGD) 10 | 11 | # Define version information 12 | set(RGD_MAJOR_VERSION 1) 13 | set(RGD_MINOR_VERSION 4) 14 | set(RGD_PATCH_NUMBER 0) 15 | if (NOT RGD_BUILD_NUMBER) 16 | set(RGD_BUILD_NUMBER 0) 17 | endif () 18 | 19 | string(TIMESTAMP DATE "\"%m/%d/%Y\"") 20 | string(TIMESTAMP YEAR "\"%Y\"") 21 | 22 | configure_file("${CMAKE_SOURCE_DIR}/Buildinfo.properties.in" "${CMAKE_SOURCE_DIR}/Buildinfo.properties") 23 | configure_file("${CMAKE_SOURCE_DIR}/source/radeon_gpu_detective_backend/rgd_version_info.h.in" "${CMAKE_SOURCE_DIR}/source/radeon_gpu_detective_backend/rgd_version_info.h") 24 | 25 | # Add cmake utilities 26 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/external/rmv/cmake") 27 | include(dev_tools) 28 | 29 | add_definitions(-DCOMGR_DYNAMIC_LINKING) 30 | 31 | # Include directories for all projects. 32 | set(AMDGPU_DIS_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/external/amd_gpu_dis/Include/) 33 | set(AMD_COMGR_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/external/comgr_package/comgr/include/) 34 | include_directories("${PROJECT_SOURCE_DIR}/external/") 35 | include_directories("${PROJECT_SOURCE_DIR}/external/rdf/rdf/inc/") 36 | include_directories("${PROJECT_SOURCE_DIR}/external/third_party/") 37 | include_directories("${PROJECT_SOURCE_DIR}/external/comgr_package/comgr/include/") 38 | include_directories("${PROJECT_SOURCE_DIR}/external/comgr_package/comgr_utils/") 39 | 40 | # rgd command line tool. 41 | add_subdirectory (source/radeon_gpu_detective_cli) 42 | 43 | add_subdirectory (source/radeon_gpu_detective_backend) 44 | 45 | # RDF. 46 | add_definitions(-DRDF_CXX_BINDINGS) 47 | option(RDF_STATIC "Build RDF as a static library" ON) 48 | add_subdirectory(external/rdf/imported/zstd) 49 | add_subdirectory(external/rdf/rdf) 50 | 51 | # RMV. 52 | add_subdirectory(external/rmv/source/parser parser) 53 | add_subdirectory(external/rmv/source/backend backend) 54 | 55 | # System info. 56 | set(SYSTEM_INFO_BUILD_RDF_INTERFACES ON) 57 | add_subdirectory(external/system_info_utils) 58 | 59 | # Test rgd app. 60 | add_subdirectory(test/source/rgd_test) 61 | 62 | # COMGR. 63 | add_subdirectory(external/comgr_package/comgr_utils ComgrUtils) 64 | 65 | # Define the location of dependent libraries 66 | IF(WIN32) 67 | set(AMD_COMGR_LIBS_DIR ${PROJECT_SOURCE_DIR}/external/comgr_package/comgr/lib/VS2022/x64) 68 | set(AMDGPU_DIS_LIBS_DIR ${PROJECT_SOURCE_DIR}/external/amd_gpu_dis/Lib/VS2022/x64) 69 | ELSEIF(UNIX) 70 | set(AMD_COMGR_LIBS_DIR ${PROJECT_SOURCE_DIR}/external/comgr_package/comgr/lib/x64) 71 | set(AMDGPU_DIS_LIBS_DIR ${PROJECT_SOURCE_DIR}/external/amd_gpu_dis/Lib/Linux/x64) 72 | ENDIF() 73 | 74 | # Locate shared library components referenced by multiple targets 75 | IF(WIN32) 76 | set (AMD_COMGR_LIB_FILENAME amd_comgr_2) 77 | ELSEIF(UNIX) 78 | set (AMD_COMGR_SHARED ${CMAKE_SHARED_LIBRARY_PREFIX}amd_comgr${CMAKE_SHARED_LIBRARY_SUFFIX}) 79 | set (AMD_COMGR_LIB_FILENAME amd_comgr) 80 | ENDIF() 81 | set (AMD_COMGR_SHARED ${CMAKE_SHARED_LIBRARY_PREFIX}${AMD_COMGR_LIB_FILENAME}${CMAKE_SHARED_LIBRARY_SUFFIX}) 82 | set (AMDGPU_DIS_SHARED ${CMAKE_SHARED_LIBRARY_PREFIX}amdgpu_dis${CMAKE_SHARED_LIBRARY_SUFFIX}) 83 | 84 | find_library(AMD_COMGR_LIB ${AMD_COMGR_LIB_FILENAME} PATHS ${AMD_COMGR_LIBS_DIR} NO_DEFAULT_PATH) 85 | find_file(AMD_COMGR_SHAREDLIB ${AMD_COMGR_SHARED} PATHS ${AMD_COMGR_LIBS_DIR} NO_DEFAULT_PATH) 86 | find_library(AMDGPU_DIS_LIB amdgpu_dis PATHS ${AMDGPU_DIS_LIBS_DIR} NO_DEFAULT_PATH) 87 | find_file(AMDGPU_DIS_SHAREDLIB ${AMDGPU_DIS_SHARED} PATHS ${AMDGPU_DIS_LIBS_DIR} NO_DEFAULT_PATH) 88 | 89 | message ("Comgr found at ${AMD_COMGR_LIB}") 90 | message ("Comgr shared at ${AMD_COMGR_SHAREDLIB}") 91 | message ("AMDGPU_Dis found at ${AMDGPU_DIS_LIB}") 92 | message ("AMDGPU_Dis shared at ${AMDGPU_DIS_SHAREDLIB}") 93 | message ("AMDGPU_Dis include at ${AMDGPU_DIS_INCLUDE_DIR}") 94 | 95 | set(CPACK_ARCHIVE_COMPONENT_INSTALL ON) 96 | set(CPACK_COMPONENTS_GROUPING IGNORE) 97 | 98 | set(CPACK_PACKAGE_VERSION "${RGD_MAJOR_VERSION}.${RGD_MINOR_VERSION}.${RGD_PATCH_NUMBER}.${RGD_BUILD_NUMBER}") 99 | 100 | if (${CMAKE_BUILD_TYPE} MATCHES "Debug") 101 | set(CPACK_RGD_CLI_PACKAGE_NAME "radeon_gpu_detective_debug") 102 | set(CPACK_RGD_TEST_PACKAGE_NAME "rgd_test_debug") 103 | else () 104 | set(CPACK_RGD_CLI_PACKAGE_NAME "radeon_gpu_detective") 105 | set(CPACK_RGD_TEST_PACKAGE_NAME "rgd_test") 106 | endif () 107 | 108 | set(CPACK_RGD_CLI_FULL_PACKAGE_NAME "${CPACK_RGD_CLI_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") 109 | set(CPACK_RGD_TEST_FULL_PACKAGE_NAME "${CPACK_RGD_TEST_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") 110 | set(CPACK_ARCHIVE_RGD_CLI_COMPONENT_FILE_NAME "${CPACK_RGD_CLI_FULL_PACKAGE_NAME}") 111 | set(CPACK_ARCHIVE_RGD_TEST_COMPONENT_FILE_NAME "${CPACK_RGD_TEST_FULL_PACKAGE_NAME}") 112 | 113 | # Archive RGD CLI configuration 114 | install(TARGETS radeon_gpu_detective_cli 115 | RUNTIME 116 | DESTINATION ./${CPACK_RGD_CLI_FULL_PACKAGE_NAME} 117 | COMPONENT rgd_cli_component) 118 | 119 | install(FILES RGD_NOTICES.txt 120 | DESTINATION ./${CPACK_RGD_CLI_FULL_PACKAGE_NAME} 121 | COMPONENT rgd_cli_component) 122 | install(FILES README.md 123 | DESTINATION ./${CPACK_RGD_CLI_FULL_PACKAGE_NAME} 124 | COMPONENT rgd_cli_component) 125 | install(FILES RGD_RELEASE_NOTES.txt 126 | DESTINATION ./${CPACK_RGD_CLI_FULL_PACKAGE_NAME} 127 | COMPONENT rgd_cli_component) 128 | install(DIRECTORY documentation/build/rgd 129 | DESTINATION ./${CPACK_RGD_CLI_FULL_PACKAGE_NAME}/help/ 130 | COMPONENT rgd_cli_component) 131 | install(DIRECTORY samples 132 | DESTINATION ./${CPACK_RGD_CLI_FULL_PACKAGE_NAME} 133 | COMPONENT rgd_cli_component) 134 | 135 | # Define the location of dependent libraries for RGD CLI. 136 | IF(WIN32) 137 | install(FILES external/amd_gpu_dis/Lib/VS2022/x64/amdgpu_dis.dll 138 | DESTINATION ./${CPACK_RGD_CLI_FULL_PACKAGE_NAME} 139 | COMPONENT rgd_cli_component) 140 | install(FILES external/comgr_package/comgr/lib/VS2022/x64/amd_comgr_2.dll 141 | DESTINATION ./${CPACK_RGD_CLI_FULL_PACKAGE_NAME} 142 | COMPONENT rgd_cli_component) 143 | ELSEIF(UNIX) 144 | install(FILES ${AMDGPU_DIS_SHAREDLIB} 145 | DESTINATION ./${CPACK_RGD_CLI_FULL_PACKAGE_NAME}/lib/ 146 | COMPONENT rgd_cli_component) 147 | install(FILES ${AMD_COMGR_SHAREDLIB} 148 | DESTINATION ./${CPACK_RGD_CLI_FULL_PACKAGE_NAME}/lib/ 149 | COMPONENT rgd_cli_component) 150 | ENDIF() 151 | 152 | # Archive RGD TEST configuration 153 | install(TARGETS rgd_test 154 | RUNTIME 155 | DESTINATION ./${CPACK_ARCHIVE_RGD_TEST_COMPONENT_FILE_NAME}/${CPACK_RGD_CLI_FULL_PACKAGE_NAME}/ 156 | COMPONENT rgd_test_component) 157 | 158 | install(TARGETS radeon_gpu_detective_cli 159 | RUNTIME 160 | DESTINATION ./${CPACK_ARCHIVE_RGD_TEST_COMPONENT_FILE_NAME}/${CPACK_RGD_CLI_FULL_PACKAGE_NAME}/ 161 | COMPONENT rgd_test_component) 162 | 163 | install(FILES test/RGD_TEST_README.md 164 | DESTINATION ./${CPACK_RGD_TEST_FULL_PACKAGE_NAME}/ 165 | COMPONENT rgd_test_component) 166 | 167 | install(DIRECTORY test/scripts/input_description_files 168 | DESTINATION ./${CPACK_RGD_TEST_FULL_PACKAGE_NAME}/ 169 | COMPONENT rgd_test_component) 170 | 171 | install(FILES test/scripts/TestRunner.py 172 | DESTINATION ./${CPACK_RGD_TEST_FULL_PACKAGE_NAME}/ 173 | COMPONENT rgd_test_component) 174 | 175 | # Define the location of dependent libraries for RGD TEST. 176 | IF(WIN32) 177 | install(FILES external/amd_gpu_dis/Lib/VS2022/x64/amdgpu_dis.dll 178 | DESTINATION ./${CPACK_ARCHIVE_RGD_TEST_COMPONENT_FILE_NAME}/${CPACK_RGD_CLI_FULL_PACKAGE_NAME}/ 179 | COMPONENT rgd_test_component) 180 | install(FILES external/comgr_package/comgr/lib/VS2022/x64/amd_comgr_2.dll 181 | DESTINATION ./${CPACK_ARCHIVE_RGD_TEST_COMPONENT_FILE_NAME}/${CPACK_RGD_CLI_FULL_PACKAGE_NAME}/ 182 | COMPONENT rgd_test_component) 183 | ENDIF() 184 | 185 | include(CPack) 186 | 187 | cpack_add_component(rgd_cli_component 188 | DISPLAY_NAME "Radeon GPU Detective ${CPACK_PACKAGE_VERSION} ${RGD_BUILD_SUFFIX}" 189 | DESCRIPTION "RGD application") 190 | 191 | cpack_add_component(rgd_test_component 192 | DISPLAY_NAME "RGD Tests ${CPACK_PACKAGE_VERSION} ${RGD_BUILD_SUFFIX}" 193 | DESCRIPTION "RGD backend tests and driver sanity tests") 194 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # radeon_gpu_detective 2 | RGD is a tool for post-mortem analysis of GPU crashes. 3 | 4 | The tool performs offline processing of AMD GPU crash dump files and generates crash analysis reports in text and JSON formats. 5 | 6 | To generate AMD GPU crash dumps for your application, use Radeon Developer Panel (RDP) and follow the Crash Analysis help manual. 7 | 8 | ## Build Instructions ## 9 | It is recommended to build the tool using the "pre_build.py" script which can be found under the "build" subdirectory. 10 | 11 | **Steps:** 12 | 13 | `` 14 | cd build 15 | `` 16 | 17 | 18 | `` 19 | python pre_build.py 20 | `` 21 | 22 | The script supports different options such as using different MSVC toolsets versions. For the list of options run the script with `-h`. 23 | 24 | By default, a solution is generated for VS 2022. To generate a solution for a different VS version or to use a different MSVC toolchain use the `--vs` argument. 25 | For example, to generate the solution for VS 2019 with the VS 2019 toolchain (MSVC 16), run: 26 | 27 | `` 28 | python pre_build.py --vs 2019 29 | `` 30 | 31 | ## Running ## 32 | Basic usage (text output): 33 | 34 | `` 35 | rgd --parse -o 36 | `` 37 | 38 | Basic usage (JSON output): 39 | 40 | `` 41 | rgd --parse --json 42 | `` 43 | 44 | For more options, run `rgd -h` to print the help manual. 45 | 46 | 47 | ## Usage ## 48 | The rgd command line tool accepts AMD driver GPU crash dump files as an input (.rgd files) and generates crash analysis report files with summarized information that can assist in debugging GPU crashes. 49 | 50 | The basic usage is: 51 | 52 | `` 53 | rgd --parse -o 54 | `` 55 | 56 | The rgd command line tool's crash analysis output files include the following information by default: 57 | * System information (CPUs, GPUs, driver, OS etc.) 58 | * Execution marker tree for each command buffer which was in flight during the crash. 59 | * Summary of the markers that were in progress during the crash (similar to the marker tree, just without the hierarchy and only including markers that were in progress). 60 | * Page fault summary (for crashes that were determined to be caused by a page fault) 61 | 62 | Both text and JSON output files include the same information, in different representation. For simplicity, we will refer here to the human-readable textual output. Here are some more details about the crash analysis file's contents: 63 | 64 | ### Crash Analysis File Information ### 65 | * Input crash dump file name: the full path to the .rgd file that was used to generate this file. 66 | * Input crash dump file creation time 67 | * RGD CLI version used 68 | 69 | ### System Information ### 70 | This section is titled `SYSTEM INFO` and includes information about: 71 | * Driver 72 | * OS 73 | * CPUs 74 | * GPUs 75 | 76 | ### Markers in Progress ### 77 | 78 | This section is titled `MARKERS IN PROGRESS` and contains information *only* about the execution markers that were in progress during the crash for each command buffer which was determined to be in flight during the crash. Here is the matching output for the tree below (see [EXECUTION MARKER TREE](#execution-marker-tree)): 79 | 80 | ``` 81 | Command Buffer ID: 0x2e 82 | ======================= 83 | Frame 268 CL0/DownSamplePS/CmdDraw 84 | Frame 268 CL0/DownSamplePS/CmdDraw 85 | Frame 268 CL0/DownSamplePS/CmdDraw 86 | Frame 268 CL0/DownSamplePS/CmdDraw 87 | Frame 268 CL0/DownSamplePS/CmdDraw 88 | Frame 268 CL0/Bloom/BlurPS/CmdDraw 89 | ``` 90 | 91 | Note that marker hierarchy is denoted by "/". 92 | 93 | ### Execution Marker Tree ### 94 | This section is titled `EXECUTION MARKER TREE` and contains a tree describing the marker status for each command buffer that was determined to be in flight during the crash. 95 | 96 | User-provided marker strings will be wrapped in "double quotes". Here is an example marker tree: 97 | 98 | ``` 99 | Command Buffer ID: 0x2e 100 | ======================= 101 | [>] "Frame 268 CL0" 102 | ├─[X] "Depth + Normal + Motion Vector PrePass" 103 | ├─[X] "Shadow Cascade Pass" 104 | ├─[X] "TLAS Build" 105 | ├─[X] "Classify tiles" 106 | ├─[X] "Trace shadows" 107 | ├─[X] "Denoise shadows" 108 | ├─[X] CmdDispatch 109 | ├─[X] CmdDispatch 110 | ├─[X] "GltfPbrPass::DrawBatchList" 111 | ├─[X] "Skydome Proc" 112 | ├─[X] "GltfPbrPass::DrawBatchList" 113 | ├─[>] "DownSamplePS" 114 | └─[>] "Bloom" 115 | ├─[>] "BlurPS" 116 | │ ├─[>] CmdDraw 117 | │ └─[ ] CmdDraw 118 | ├─[ ] CmdDraw 119 | ├─[ ] "BlurPS" 120 | ├─[ ] CmdDraw 121 | ├─[ ] "BlurPS" 122 | ├─[ ] CmdDraw 123 | ├─[ ] "BlurPS" 124 | ├─[ ] CmdDraw 125 | ├─[ ] "BlurPS" 126 | └─[ ] CmdDraw 127 | ``` 128 | 129 | 130 | #### Configuring the Execution Marker Output with RGD CLI #### 131 | 132 | RGD CLI exposes a few options that impact how the marker tree is generated: 133 | 134 | * ``--marker-src`` include a suffix tag for each node in the tree indicating its origin (the component that submitted the marker). The supported components are: 135 | * [APP] for application marker. 136 | * [Driver-PAL] for markers originating from PAL. 137 | * [Driver-DX12] for markers originating from DXCP non-PAL code. 138 | 139 | * ``--expand-markers``: expand all parent nodes in the tree (RGD will collapse all nodes which do not have any sub-nodes in progress as these would generally be considered "noise" when trying to find the culprit marker). 140 | 141 | #### Configuring the Page Fault Summary with RGD CLI #### 142 | 143 | * ``--va-timeline``: print a table with all events that impacted the offending VA, sorted chronologically (note that this is only applicable for crashes that are caused by a page fault). Since this table can be extremely verbose, and since in most cases this table is not required for analyzing the crash, it is not included by default in the output file. 144 | 145 | * ``--all-resources``: If specified, the tool's output will include all the resources regardless of their virtual address from the input crash dump file. 146 | 147 | 148 | #### Page Fault Summary #### 149 | If the crash was determined to be caused by a page fault, a section titled `PAGE FAULT SUMMARY` will include useful details about the page fault such as: 150 | 151 | * `Offending VA`: the virtual address which triggered the page fault. 152 | * `Resource timeline`: a timeline of the associated resources (all resources that resided in the offending VA) with relevant events such as Create, Bind and Destroy. These events will be sorted chronologically. Each line includes: 153 | * Time of event 154 | * Event type 155 | * Type of resource 156 | * Resource ID 157 | * Resource size 158 | * Resource name (if named, otherwise NULL) 159 | * `Associated resources`: a list of all associated resources with their details, including: 160 | * Resource ID 161 | * Name (if named by the user) 162 | * Type and creation flags 163 | * Size 164 | * Virtual address and parent allocation base address 165 | * Commit type 166 | * Resource timeline that shows all events that are relevant to this specific resource in chronological order 167 | 168 | 169 | *A note about time tracking:* 170 | 171 | The general time format used by RGD is `` which stands for ``. Beginning of time (`00:00:00.00`) is when the crash analysis session started (note that there is an expected lag between the start of the crashing process and the beginning of the crash analysis session, due to the time that takes to initialize crash analysis in the driver). 172 | 173 | ## Capturing AMD GPU Crash Dump Files ## 174 | 175 | * To learn how to get started with RGD, see the [RGD quickstart guide](documentation/source/index.rst). More information can be found on the [RGD help manual](documentation/source/help_manual.rst). 176 | * The complete documentation can be found in the [Radeon Developer Tool Suite archive](https://gpuopen.com/rdts-windows/) under ``help/rgd/index.html``. 177 | 178 | -------------------------------------------------------------------------------- /RGD_NOTICES.txt: -------------------------------------------------------------------------------- 1 | Third-party licenses, acknowledgements 2 | ====================================== 3 | 4 | Radeon™ GPU Detective (RGD) uses the following third-party software: 5 | 6 | **cxxopts** 7 | 8 | Copyright (c) 2014 Jarryd Beck 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | 28 | **nlohmann/json** 29 | 30 | Copyright © 2013-2018 Niels Lohmann 31 | 32 | **Catch2** 33 | 34 | Boost Software License - Version 1.0 - August 17th, 2003 35 | -------------------------------------------------------------------------------- /RGD_RELEASE_NOTES.txt: -------------------------------------------------------------------------------- 1 | Radeon™ GPU Detective v1.4 Release Notes 2 | ======================================== 3 | Radeon GPU Detective (RGD) is a tool for post-mortem analysis of GPU crashes (TDRs). 4 | Using the tool you can capture and analyze AMD GPU crash dumps and produce information that can help narrow down the search for the crash's root cause. 5 | Such information includes page fault details, resource details and execution markers reflecting the GPU work that was in progress at the moments leading to the crash 6 | 7 | Highlights 8 | ========== 9 | 1. Added support for RDNA™ 4 GPUs (AMD Radeon™ RX 9070 series). 10 | 2. Introducing Hardware Crash Analysis: RGD collects low-level information about the GPU hardware state upon crash. If the crash was caused by a shader, RGD will now present relevant information in the output file including: 11 | a. New execution marker to identify in-flight shaders during the crash. 12 | b. New `SHADER INFO` section with details about the crashing shaders: disassembly, offending instructions, wavefront counts and more. 13 | 14 | Explicit exclusions 15 | =================== 16 | - RGD targets GPU crashes (TDRs) on Windows®. RGD will not detect pure CPU crashes (for example, CPU null pointer dereference or integer division by zero). You will need to use a CPU debugger for that. Please use CPU debugging mechanisms to investigate such cases. 17 | - Hardware Crash Analysis in RGD v1.4 focuses on offending shaders. For this mode to be applicable to you crash case, the GPU crash needs to be triggered by a shader-executing hardware block. If the GPU crash happened somewhere else, no shader will be associated with the execution tree markers, and you will not have the benefits of the new Hardware Crash Analysis mode. 18 | - Hardware Crash Analysis is only supported on discrete RDNA™ GPUs (requires RDNA™ 2 and above). APU support will be added in a future release. 19 | 20 | Known Issues 21 | ============ 22 | * Crash Analysis is not support on RX 6750 XT. 23 | * In certain cases, trying to capture a GPU crash dump of an app that has Microsoft® DRED enabled can lead to a system crash. 24 | * Attempting to capture GPU crash dumps on a system with a Ryzen CPU that includes integrated graphics (with no connected discrete Radeon GPU) may result in a BSOD. 25 | * In certain hang cases (where the GPU crash was not caused by a page fault), Hardware Crash Analysis may not detect the offending shader. However, as long as your crash case is supported by RGD, you can count on the "standard" (RGD v1.3) information to be included, whether or not the Hardware Crash Analysis feature was applicable to your crash case. 26 | 27 | System Requirements 28 | =================== 29 | * Operating system: Windows 10 or 11. 30 | 31 | * Latest Adrenalin Software driver. A system reboot is recommended after the driver installation. 32 | 33 | * GPU: Radeon™ RX 6000 series (RDNA™ 2), RX 7000 series (RDNA™ 3) or RX 9000 series (RDNA™ 4) card. 34 | 35 | * Latest RDP (Radeon Developer Panel) version, which is available as part of the Radeon Developer Tool Suite and can be downloaded from GPUOpen.com. Make sure you are using RDP v3.3 or later. 36 | 37 | Note that this version of RGD supports DirectX® 12 and Vulkan® applications, so you will need either DX12 or vulkan application that crashes. For the best experience, it is recommended to: 38 | * Use string markers around render passes using the AMD GPU Services (AGS) library, as these will appear in the command line tool's output and will help identifying the code that was executing during the crash. 39 | * Name resources such as heaps, buffers and textures using ID3D12Object::SetName() (for DX12 resources) and vkSetDebugUtilsObjectNameEXT() (for vulkan objects), as these names will appear in the Page Fault Summary section of the command line tool's output file, and are critical for identifying the offending resource when applicable. 40 | -------------------------------------------------------------------------------- /_clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | IndentWidth: 4 3 | UseTab: Never 4 | ColumnLimit: 160 5 | 6 | Language: Cpp 7 | AccessModifierOffset: -4 8 | BreakBeforeBraces: Custom 9 | BraceWrapping: 10 | AfterCaseLabel: true 11 | AfterClass: true 12 | AfterControlStatement: true 13 | AfterEnum: true 14 | AfterFunction: true 15 | AfterNamespace: true 16 | AfterObjCDeclaration: true 17 | AfterStruct: true 18 | AfterUnion: true 19 | AfterExternBlock: false 20 | BeforeCatch: true 21 | BeforeElse: true 22 | IndentBraces: false 23 | SplitEmptyFunction: true 24 | SplitEmptyRecord: true 25 | SplitEmptyNamespace: true 26 | ConstructorInitializerAllOnOneLineOrOnePerLine : false 27 | BreakConstructorInitializers: BeforeComma 28 | DerivePointerAlignment: false 29 | IndentCaseLabels: false 30 | NamespaceIndentation: All 31 | AlignConsecutiveAssignments: true 32 | AlignConsecutiveDeclarations: true 33 | AlignEscapedNewlines: Left 34 | AlignTrailingComments: true 35 | AlignOperands: true 36 | AllowShortFunctionsOnASingleLine: false 37 | AllowShortIfStatementsOnASingleLine: false 38 | AllowShortLoopsOnASingleLine: false 39 | AllowShortBlocksOnASingleLine: false 40 | ReflowComments: false 41 | SortIncludes: false 42 | SortUsingDeclarations: false 43 | BinPackArguments: false 44 | BinPackParameters: false 45 | ExperimentalAutoDetectBinPacking: false 46 | AllowAllParametersOfDeclarationOnNextLine: false -------------------------------------------------------------------------------- /build/dependency_map.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | # Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | # 4 | # Definitions for project external dependencies to be fetched or updated before build. 5 | # 6 | 7 | 8 | import sys 9 | 10 | # prevent generation of .pyc file 11 | sys.dont_write_bytecode = True 12 | 13 | ####### Git Dependencies ####### 14 | 15 | # To allow for future updates where we may have cloned the project, store the root of 16 | # the repo in a variable. In future, we can automatically calculate this based on the git config 17 | github_root = "https://github.com/" 18 | 19 | # Define a set of dependencies that exist as separate git projects. 20 | # each git dependency has a desired directory where it will be cloned - along with a commit to checkout 21 | git_mapping = { 22 | github_root + "nlohmann/json" : ["../external/third_party/json", "v3.9.1"], 23 | github_root + "jarro2783/cxxopts" : ["../external/third_party/cxxopts", "v3.0.0"], 24 | github_root + "GPUOpen-Drivers/libamdrdf" : ["../external/rdf", "v1.1.2"], 25 | github_root + "GPUOpen-Tools/radeon_memory_visualizer" : ["../external/rmv", "9ff1cd0491ec4b040557f3e844c04018db6c3368"], 26 | github_root + "GPUOpen-Tools/system_info_utils" : ["../external/system_info_utils", "88a338a01949f8d8bad60a30b78b65300fd13a9f"], 27 | github_root + "catchorg/Catch2" : ["../external/third_party/catch2", "v2.13.6"] 28 | } 29 | 30 | ####### URL Dependencies ####### 31 | 32 | if sys.platform == "win32": 33 | comgr_package = "https://github.com/GPUOpen-Tools/comgr_utils/releases/download/rdts-2025-03-11/COMGR-Package-Windows-197.zip" 34 | elif sys.platform.startswith('linux') == True: 35 | comgr_package = "https://github.com/GPUOpen-Tools/comgr_utils/releases/download/rdts-2025-03-11/COMGR-Package-Linux-197.tgz" 36 | else: 37 | log_print("Unsupported Platform") 38 | sys.exit(-1) 39 | 40 | # Downloads required for Windows builds. 41 | url_mapping_win = { 42 | comgr_package : "../external/comgr_package", 43 | } 44 | 45 | # Downloads required for Linux builds. 46 | url_mapping_linux = { 47 | comgr_package : "../external/comgr_package", 48 | } 49 | -------------------------------------------------------------------------------- /build/fetch_dependencies.py: -------------------------------------------------------------------------------- 1 | #! python3 2 | # Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. 3 | # 4 | # Script to fetch all external git and/or downloadable dependencies needed to build the project 5 | # 6 | # fetch_dependencies.py 7 | # 8 | # Each git repo will be updated to the commit specified in the "gitMapping" table. 9 | 10 | import os 11 | import subprocess 12 | import sys 13 | import zipfile 14 | import tarfile 15 | import platform 16 | import argparse 17 | import stat 18 | 19 | 20 | # Check for the python 3.x name and import it as the 2.x name 21 | try: 22 | import urllib.request as urllib 23 | # if that failed, then try the 2.x name 24 | except ImportError: 25 | import urllib 26 | 27 | # to allow the script to be run from anywhere - not just the cwd - store the absolute path to the script file 28 | script_root = os.path.dirname(os.path.realpath(__file__)) 29 | 30 | # also store the basename of the file 31 | script_name = os.path.basename(__file__) 32 | 33 | # Print a message to the console with appropriate pre-amble 34 | def log_print(message): 35 | print ("\n" + script_name + ": " + message) 36 | sys.stdout.flush() 37 | 38 | # add script root to support import of URL and git maps 39 | sys.path.append(script_root) 40 | from dependency_map import git_mapping 41 | from dependency_map import url_mapping_win 42 | from dependency_map import url_mapping_linux 43 | 44 | # Download a zip or tgz file from the specified URL and unzip into the directory defined by destination. 45 | # The destination directory will be created if it doesn't exist 46 | # if the 'update' parameter is true then the existing file and output directory will be deleted and re-created 47 | # TODO - this function needs to handle errors gracefully when URL is incorrect or inaccessible 48 | def download_url_dependencies(url_mapping, update, retry_count = 10): 49 | for url in url_mapping: 50 | # convert targetPath to OS specific format 51 | tmp_path = os.path.join(script_root, url_mapping[url]) 52 | # clean up path, collapsing any ../ and converting / to \ for Windows 53 | target_path = os.path.normpath(tmp_path) 54 | # TODO if update is defined - delete file and directory if they exist 55 | # make target directory if it doesn't exist 56 | if not os.path.isdir(target_path): 57 | os.makedirs(target_path) 58 | # generate the target zip file name from the source URL filename and the target path 59 | # note - this rule currently handles URLs that contain # and ? characters at the end 60 | # those currently used by Jenkins don't have this style 61 | zip_file_name = url.split('/')[-1].split('#')[0].split('?')[0] 62 | zip_path = os.path.join(target_path, zip_file_name) 63 | if os.path.isfile(zip_path): 64 | # File exists - print message and continue 65 | log_print("URL Dependency %s found and not updated" % zip_path) 66 | else: 67 | # File doesn't exist - download and unpack it 68 | log_print("Downloading " + url + " into " + zip_path) 69 | try: 70 | urllib.urlretrieve(url, zip_path) 71 | except urllib.ContentTooShortError: 72 | os.remove(zip_path) 73 | if retry_count > 0: 74 | log_print("URL content too short. Retrying. Retries remaining: %d" % retry_count) 75 | download_url_dependencies(url_mapping, update, retry_count - 1) 76 | return; 77 | # Unpack the downloaded file into the target directory 78 | if os.path.splitext(zip_path)[1] == ".zip": 79 | # if file extension is .zip then unzip it 80 | log_print("Extracting in " + target_path) 81 | zipfile.ZipFile(zip_path).extractall(target_path) 82 | elif os.path.splitext(zip_path)[1] == ".tgz": 83 | # if file extension is .tgz then untar it 84 | log_print("Extracting in " + target_path) 85 | tarfile.open(zip_path).extractall(target_path) 86 | 87 | # Clone or update a git repo 88 | def update_git_dependencies(git_mapping, update): 89 | for git_repo in git_mapping: 90 | # add script directory to path 91 | tmp_path = os.path.join(script_root, git_mapping[git_repo][0]) 92 | 93 | # clean up path, collapsing any ../ and converting / to \ for Windows 94 | path = os.path.normpath(tmp_path) 95 | 96 | # required commit 97 | reqd_commit = git_mapping[git_repo][1] 98 | 99 | do_checkout = False 100 | if not os.path.isdir(path): 101 | # directory doesn't exist - clone from git 102 | log_print("Directory %s does not exist, using 'git clone' to get latest from %s" % (path, git_repo)) 103 | p = subprocess.Popen((["git", "clone", git_repo ,path]), stderr=subprocess.STDOUT) 104 | p.wait() 105 | if(p.returncode == 0): 106 | do_checkout = True 107 | else: 108 | log_print("git clone failed with return code: %d" % p.returncode) 109 | return False 110 | elif update == True: 111 | # directory exists and update requested - get latest from git 112 | log_print("Directory %s exists, using 'git fetch --tags -f' to get latest from %s" % (path, git_repo)) 113 | p = subprocess.Popen((["git", "fetch", "--tags", "-f"]), cwd=path, stderr=subprocess.STDOUT) 114 | p.wait() 115 | if(p.returncode == 0): 116 | do_checkout = True 117 | else: 118 | log_print("git fetch failed with return code: %d" % p.returncode) 119 | return False 120 | else: 121 | # Directory exists and update not requested 122 | log_print("Git Dependency %s found and not updated" % git_repo) 123 | 124 | if do_checkout == True: 125 | log_print("Checking out required commit: %s" % reqd_commit) 126 | p = subprocess.Popen((["git", "checkout", reqd_commit]), cwd=path, stderr=subprocess.STDOUT) 127 | p.wait() 128 | if(p.returncode != 0): 129 | log_print("git checkout failed with return code: %d" % p.returncode) 130 | return False 131 | log_print("Ensuring any branch is on the head using git pull --ff-only origin %s" % reqd_commit) 132 | p = subprocess.Popen((["git", "pull", "--ff-only", "origin", reqd_commit]), cwd=path, stderr=subprocess.STDOUT) 133 | p.wait() 134 | if(p.returncode != 0): 135 | log_print("git merge failed with return code: %d" % p.returncode) 136 | return False 137 | 138 | return True 139 | 140 | # Main body of update functionality 141 | def do_fetch_dependencies(update, internal): 142 | # Print git version being used 143 | git_cmd = ["git", "--version"] 144 | git_output = subprocess.check_output(git_cmd, stderr=subprocess.STDOUT) 145 | log_print("%s" % git_output) 146 | 147 | # Update all git dependencies 148 | if update_git_dependencies(git_mapping, update): 149 | if sys.platform == "win32": 150 | download_url_dependencies(url_mapping_win, update) 151 | elif sys.platform.startswith('linux') == True: 152 | download_url_dependencies(url_mapping_linux, update) 153 | return True 154 | else: 155 | return False 156 | 157 | if __name__ == '__main__': 158 | # fetch_dependencies.py executed as a script 159 | 160 | # parse the command line arguments 161 | parser = argparse.ArgumentParser(description="A script that fetches all the necessary build dependencies for the project") 162 | args = parser.parse_args() 163 | 164 | do_fetch_dependencies(True, args.internal) 165 | -------------------------------------------------------------------------------- /build/utils/get_version.py: -------------------------------------------------------------------------------- 1 | #!python 2 | # Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. 3 | # Get RGD version from RGD/source/common/rgd_version_info.h. 4 | # 5 | # Usage: 6 | # python radeon_gpu_detective/build/utils/get_version.py [--major] [--minor] [--update] [--versionfile ] 7 | # --major Return major version number 8 | # --minor Return minor version number 9 | # --update Return update version number 10 | # --versionfile Use as the full path name of for rgd_version_info.h 11 | # 12 | import os 13 | import argparse 14 | 15 | # Get full path to script to support run from anywhere. 16 | SCRIPTROOT = os.path.dirname(os.path.realpath(__file__)) 17 | 18 | # Handle command line arguments. 19 | PARSER = argparse.ArgumentParser(description='Get RGD version information') 20 | PARSER.add_argument('--major', action='store_true', default=False, help='Return value of MAJOR version string') 21 | PARSER.add_argument('--minor', action='store_true', default=False, help='Return value of MINOR version string') 22 | PARSER.add_argument('--update', action='store_true', default=False, help='Return the value of UPDATE version string') 23 | PARSER.add_argument('--versionfile', action='store', default=None, help='Use alternate path for file path') 24 | VERSIONARGS = PARSER.parse_args() 25 | 26 | # Initialize file for search. 27 | RGDVERSIONFILE = os.path.normpath(os.path.join(SCRIPTROOT, '../..', 'source/radeon_gpu_detective_cli/rgd_version_info.h')) 28 | RGDVERSIONDATA = None 29 | if not VERSIONARGS.versionfile == None: 30 | RGDVERSIONFILE = os.path.normpath(VERSIONARGS.versionfile) 31 | if os.path.exists(RGDVERSIONFILE): 32 | RGDVERSIONDATA = open(RGDVERSIONFILE) 33 | else: 34 | print("ERROR: Unable to open file: %s"%RGDVERSIONFILE) 35 | sys.exit(1) 36 | 37 | # Get major, minor, and update version strings. 38 | MAJOR = None 39 | MINOR = None 40 | UPDATE = None 41 | for line in RGDVERSIONDATA: 42 | if 'define RGD_VERSION_MAJOR ' in line: 43 | MAJOR = (line.split()[2]) 44 | if 'define RGD_VERSION_MINOR ' in line: 45 | MINOR = (line.split()[2]) 46 | if 'define RGD_VERSION_UPDATE ' in line: 47 | UPDATE = (line.split()[2]) 48 | 49 | if VERSIONARGS.major == True: 50 | print(MAJOR) 51 | if VERSIONARGS.minor == True: 52 | print(MINOR) 53 | if VERSIONARGS.update == True: 54 | print(UPDATE) 55 | -------------------------------------------------------------------------------- /documentation/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright © Advanced Micro Devices, Inc. All rights reserved. 2 | # 3 | # Minimal makefile for Sphinx documentation 4 | # 5 | 6 | # You can set these variables from the command line. 7 | SPHINXOPTS = 8 | SPHINXBUILD = sphinx-build 9 | SPHINXPROJ = RadeonGPUDetective 10 | SOURCEDIR = source 11 | BUILDDIR = build 12 | 13 | # Put it first so that "make" without argument is like "make help". 14 | help: 15 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 16 | 17 | .PHONY: help Makefile 18 | 19 | # Catch-all target: route all unknown targets to Sphinx using the new 20 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 21 | %: Makefile 22 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /documentation/make.bat: -------------------------------------------------------------------------------- 1 | REM Copyright © Advanced Micro Devices, Inc. All rights reserved. 2 | 3 | @ECHO OFF 4 | 5 | pushd %~dp0 6 | 7 | REM Command file for Sphinx documentation 8 | 9 | if "%SPHINXBUILD%" == "" ( 10 | set SPHINXBUILD=sphinx-build 11 | ) 12 | set SOURCEDIR=source 13 | set BUILDDIR=build 14 | set SPHINXPROJ=RadeonGPUDetective 15 | 16 | if "%1" == "" goto help 17 | 18 | REM The sphinx-rtd-theme dependency was depreciated in newer versions of Sphinx 19 | REM and is no longer included by default 20 | python -m pip install -q --disable-pip-version-check --user sphinx-rtd-theme 21 | 22 | %SPHINXBUILD% >NUL 2>NUL 23 | if errorlevel 9009 ( 24 | echo. 25 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 26 | echo.installed, then set the SPHINXBUILD environment variable to point 27 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 28 | echo.may add the Sphinx directory to PATH. 29 | echo. 30 | echo.If you don't have Sphinx installed, grab it from 31 | echo.http://sphinx-doc.org/ 32 | exit /b 1 33 | ) 34 | 35 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 36 | goto end 37 | 38 | :help 39 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 40 | 41 | :end 42 | popd 43 | -------------------------------------------------------------------------------- /documentation/requirements.txt: -------------------------------------------------------------------------------- 1 | # Defining requirements for docs 2 | sphinx==5.3.0 3 | sphinx_rtd_theme==1.1.1 4 | readthedocs-sphinx-search==0.1.1 -------------------------------------------------------------------------------- /documentation/source/_static/style.css: -------------------------------------------------------------------------------- 1 | .wy-nav-content { 2 | max-width: none; 3 | } -------------------------------------------------------------------------------- /documentation/source/_static/theme_overrides.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | img { 4 | max-width: 100%; 5 | max-height: auto; 6 | box-shadow: 6px 6px #eee; 7 | -ms-interpolation-mode: bicubic; 8 | border: 1px solid #ccc; 9 | } 10 | 11 | table { 12 | font-size: 12px; 13 | } -------------------------------------------------------------------------------- /documentation/source/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "!layout.html" %} 2 | {% block extrahead %} 3 | 4 | {% endblock %} -------------------------------------------------------------------------------- /documentation/source/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Radeon GPU Detective documentation build configuration file, created by 5 | # sphinx-quickstart on Wed Jan 17 18:10:06 2018. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | # sys.path.insert(0, os.path.abspath('.')) 20 | #import os 21 | #import sys 22 | 23 | 24 | 25 | # -- General configuration ------------------------------------------------ 26 | 27 | # If your documentation needs a minimal Sphinx version, state it here. 28 | # 29 | # needs_sphinx = '1.0' 30 | 31 | # Add any Sphinx extension module names here, as strings. They can be 32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 33 | # ones. 34 | extensions = [] 35 | 36 | # Add any paths that contain templates here, relative to this directory. 37 | templates_path = ['_templates'] 38 | 39 | # The suffix(es) of source filenames. 40 | # You can specify multiple suffix as a list of string: 41 | # 42 | # source_suffix = ['.rst', '.md'] 43 | source_suffix = '.rst' 44 | 45 | # The master toctree document. 46 | master_doc = 'index' 47 | 48 | # General information about the project. 49 | project = u'Radeon GPU Detective' 50 | copyright = u'2025, Advanced Micro Devices, Inc. All rights reserved.' 51 | author = u'AMD Developer Tools' 52 | 53 | # The version info for the project you're documenting, acts as replacement for 54 | # |version| and |release|, also used in various other places throughout the 55 | # built documents. 56 | # 57 | # The short X.Y version. 58 | version = u'1.4' 59 | # The full version, including alpha/beta/rc tags. 60 | release = u'1.4' 61 | 62 | # The language for content autogenerated by Sphinx. Refer to documentation 63 | # for a list of supported languages. 64 | # 65 | # This is also used if you do content translation via gettext catalogs. 66 | # Usually you set "language" from the command line for these cases. 67 | language = 'en' 68 | 69 | # List of patterns, relative to source directory, that match files and 70 | # directories to ignore when looking for source files. 71 | # This patterns also effect to html_static_path and html_extra_path 72 | exclude_patterns = ["[A-Z]*.rst"] 73 | 74 | # The name of the Pygments (syntax highlighting) style to use. 75 | pygments_style = 'sphinx' 76 | 77 | # If true, `todo` and `todoList` produce output, else they produce nothing. 78 | todo_include_todos = False 79 | 80 | 81 | # -- Options for HTML output ---------------------------------------------- 82 | 83 | # The theme to use for HTML and HTML Help pages. See the documentation for 84 | # a list of builtin themes. 85 | # 86 | html_theme = 'sphinx_rtd_theme' 87 | 88 | # Theme options are theme-specific and customize the look and feel of a theme 89 | # further. For a list of options available for each theme, see the 90 | # documentation. 91 | # 92 | # html_theme_options = {} 93 | 94 | # Add any paths that contain custom static files (such as style sheets) here, 95 | # relative to this directory. They are copied after the builtin static files, 96 | # so a file named "default.css" will overwrite the builtin "default.css". 97 | html_static_path = ['_static'] 98 | 99 | # If a function setup(app) exists, Sphinx will call this function as a normal 100 | # extension during application startup. This method of using the overrides css 101 | # file works better with read the docs (more so than specifying it via the 102 | # html_context tag) 103 | #def setup(app): 104 | # app.add_css_file('theme_overrides.css') 105 | 106 | #html_show_sourcelink = False 107 | #html_show_sphinx = False 108 | 109 | 110 | # -- Options for HTMLHelp output ------------------------------------------ 111 | 112 | # Output file base name for HTML help builder. 113 | htmlhelp_basename = 'RadeonGPUDetectivedoc' 114 | 115 | 116 | # -- Options for LaTeX output --------------------------------------------- 117 | 118 | latex_elements = { 119 | # The paper size ('letterpaper' or 'a4paper'). 120 | # 121 | # 'papersize': 'letterpaper', 122 | 123 | # The font size ('10pt', '11pt' or '12pt'). 124 | # 125 | # 'pointsize': '10pt', 126 | 127 | # Additional stuff for the LaTeX preamble. 128 | # 129 | # 'preamble': '', 130 | 131 | # Latex figure (float) alignment 132 | # 133 | # 'figure_align': 'htbp', 134 | } 135 | 136 | # Grouping the document tree into LaTeX files. List of tuples 137 | # (source start file, target name, title, 138 | # author, documentclass [howto, manual, or own class]). 139 | #latex_documents = [ 140 | # (master_doc, 'RadeonGPUDetective.tex', u'Radeon GPU Detective Documentation', 141 | # u'AMD Developer Tools', 'manual'), 142 | #] 143 | 144 | 145 | # -- Options for manual page output --------------------------------------- 146 | 147 | # One entry per manual page. List of tuples 148 | # (source start file, name, description, authors, manual section). 149 | man_pages = [ 150 | (master_doc, 'radeongpudetective', u'Radeon GPU Detective Documentation', 151 | [author], 1) 152 | ] 153 | 154 | 155 | # -- Options for Texinfo output ------------------------------------------- 156 | 157 | # Grouping the document tree into Texinfo files. List of tuples 158 | # (source start file, target name, title, author, 159 | # dir menu entry, description, category) 160 | texinfo_documents = [ 161 | (master_doc, 'RadeonGPUDetective', u'Radeon GPU Detective Documentation', 162 | author, 'RadeonGPUDetective', 'One line description of project.', 163 | 'Miscellaneous'), 164 | ] 165 | 166 | 167 | 168 | # -- Options for Epub output ---------------------------------------------- 169 | 170 | # Bibliographic Dublin Core info. 171 | epub_title = project 172 | epub_author = author 173 | epub_publisher = author 174 | epub_copyright = copyright 175 | 176 | # The unique identifier of the text. This can be a ISBN number 177 | # or the project homepage. 178 | # 179 | # epub_identifier = '' 180 | 181 | # A unique identification for the text. 182 | # 183 | # epub_uid = '' 184 | 185 | # A list of files that should not be packed into the epub file. 186 | epub_exclude_files = ['search.html'] 187 | -------------------------------------------------------------------------------- /documentation/source/images/driver-experiments-select-api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GPUOpen-Tools/radeon_gpu_detective/21c2589081650e0d1cfdc356b4c3ed931e2a132e/documentation/source/images/driver-experiments-select-api.png -------------------------------------------------------------------------------- /documentation/source/images/driver-experiments-select-experiment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GPUOpen-Tools/radeon_gpu_detective/21c2589081650e0d1cfdc356b4c3ed931e2a132e/documentation/source/images/driver-experiments-select-experiment.png -------------------------------------------------------------------------------- /documentation/source/images/enable-crash-analysis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GPUOpen-Tools/radeon_gpu_detective/21c2589081650e0d1cfdc356b4c3ed931e2a132e/documentation/source/images/enable-crash-analysis.png -------------------------------------------------------------------------------- /documentation/source/images/enable-driver-experiments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GPUOpen-Tools/radeon_gpu_detective/21c2589081650e0d1cfdc356b4c3ed931e2a132e/documentation/source/images/enable-driver-experiments.png -------------------------------------------------------------------------------- /documentation/source/images/open-text-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GPUOpen-Tools/radeon_gpu_detective/21c2589081650e0d1cfdc356b4c3ed931e2a132e/documentation/source/images/open-text-summary.png -------------------------------------------------------------------------------- /documentation/source/images/rgd-advanced-options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GPUOpen-Tools/radeon_gpu_detective/21c2589081650e0d1cfdc356b4c3ed931e2a132e/documentation/source/images/rgd-advanced-options.png -------------------------------------------------------------------------------- /documentation/source/images/select-text-output-format.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GPUOpen-Tools/radeon_gpu_detective/21c2589081650e0d1cfdc356b4c3ed931e2a132e/documentation/source/images/select-text-output-format.png -------------------------------------------------------------------------------- /documentation/source/index.rst: -------------------------------------------------------------------------------- 1 | Radeon™ GPU Detective (RGD) 2 | =========================== 3 | Radeon GPU Detective (RGD) is a tool for post-mortem analysis of GPU crashes. 4 | 5 | .. toctree:: 6 | :maxdepth: 2 7 | :caption: Contents: 8 | 9 | help_manual.rst 10 | 11 | .. _quickstart-guide: 12 | 13 | Quickstart Guide 14 | ---------------- 15 | 16 | This guide will get you up and running with RGD, a tool for post-mortem GPU crash analysis. You will learn how to generate AMD GPU crash dumps and crash analysis reports. 17 | 18 | .. note:: 19 | Review these requirements to make sure that this tool is relevant for your use case: 20 | 21 | * RGD v1.4 supports **DirectX12** and **Vulkan**. 22 | * **Windows 10 or 11**. 23 | * **RDNA™2** (RX 6000 series), **RDNA™3** (RX 7000 series) or **RDNA™ 4** (RX 9000 series) card. 24 | * Must **TDR** (we don't catch it if there is no TDR). 25 | * **Reproducible crashes** (you will have to reproduce the crash to capture a GPU crash dump). 26 | 27 | Preparation 28 | ^^^^^^^^^^^ 29 | * Download the latest Windows version of `Radeon Developer Tools Suite (RDTS) `_ and extract the .zip archive. 30 | 31 | Capture GPU crash dump 32 | ^^^^^^^^^^^^^^^^^^^^^^ 33 | 34 | 1. Before you start, if you ever changed the TdrLevel registry setting, make sure it is set to TdrLevelRecover(3). 35 | 2. Run RDP GUI app (RadeonDeveloperPanel.exe). 36 | 3. Under CAPTURE -> "Available features", enable "Crash Analysis". 37 | 38 | .. image:: images/enable-crash-analysis.png 39 | 40 | 4. Under the "Crash Analysis" tab, make sure that the Text checkbox is checked for the automatic crash summary generation. Please note, Hardware Crash Analysis feature is enabled by default. For more information about the Hardware Crash Analysis feature, please see the RGD :doc:`help_manual`. 41 | 42 | .. image:: images/select-text-output-format.png 43 | 44 | 5. Run the crashing app and reproduce the TDR. 45 | 46 | .. note:: 47 | You can always generate the text or JSON summary files from an .rgd file after has been captured. This can be done either by right-clicking the .rgd file entry in RDP and using the context menu or by invoking the rgd command line tool directly (run ``rgd -h`` to see the help manual). 48 | 49 | Capture GPU crash dump with Driver Experiments enabled 50 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 51 | 52 | 1. Under CAPTURE -> "Available features", enable "Driver Experiments" 53 | 54 | .. image:: images/enable-driver-experiments.png 55 | 56 | 2. Under the "Driver Experiments" tab, select the API you want to enable the experiments for (DirectX12 or Vulkan). 57 | 58 | .. image:: images/driver-experiments-select-api.png 59 | 60 | 3. Under the "Driver Experiments" tab, enable/select the experiments you want to activate. 61 | 62 | .. image:: images/driver-experiments-select-experiment.png 63 | 64 | 4. Follow the steps in the previous section to capture the GPU crash dump. 65 | 66 | Crash analysis 67 | ^^^^^^^^^^^^^^ 68 | 69 | After system recovery, if the crash was detected, you should see a new .rgd file under “Recently collected dumps”. 70 | The .rgd file is a binary file that stores information about the crash. 71 | RGD doesn't offer a GUI tool to open these files. 72 | Instead, you can convert them to a report in text or JSON format directly from RDP. 73 | To do it, right-click and select “Open text summary”: 74 | 75 | .. image:: images/open-text-summary.png 76 | 77 | 78 | This will open the .txt crash analysis file which includes information that can help narrow down the search for the crash's root cause:: 79 | 80 | Command Buffer ID: 0x617 (Queue type: Direct) 81 | ============================================= 82 | [>] "Frame 362 CL0" 83 | ├─[X] "Depth + Normal + Motion Vector PrePass" 84 | ├─[X] "Shadow Cascade Pass" 85 | ├─[X] "TLAS Build" 86 | ├─[X] "Classify tiles" 87 | ├─[X] "Trace shadows" 88 | ├─[X] ----------Barrier---------- 89 | ├─[X] "Denoise shadows" 90 | ├─[X] "GltfPbrPass::DrawBatchList" 91 | ├─[X] "Skydome Proc" 92 | ├─[X] "GltfPbrPass::DrawBatchList" 93 | ├─[>] "DownSamplePS" 94 | │ ├─[X] ----------Barrier---------- 95 | │ ├─[#] Draw(VertexCount=3, InstanceCount=1) <-- has a correlated running wave 96 | │ ├─[#] Draw(VertexCount=3, InstanceCount=1) <-- has a correlated running wave 97 | │ ├─[#] Draw(VertexCount=3, InstanceCount=1) <-- has a correlated running wave 98 | │ ├─[#] Draw(VertexCount=3, InstanceCount=1) <-- has a correlated running wave 99 | │ ├─[#] Draw(VertexCount=3, InstanceCount=1) <-- has a correlated running wave 100 | │ └─[>] ----------Barrier---------- 101 | ├─[>] "Bloom" 102 | │ ├─[>] "BlurPS" 103 | │ │ ├─[>] ----------Barrier---------- 104 | │ │ ├─[#] Draw(VertexCount=3, InstanceCount=1) <-- has a correlated running wave 105 | │ │ ├─[#] Draw(VertexCount=3, InstanceCount=1) <-- has a correlated running wave 106 | │ │ └─[ ] ----------Barrier---------- 107 | │ ├─[ ] ----------Barrier---------- 108 | │ ├─[ ] Draw(VertexCount=3, InstanceCount=1) 109 | │ ├─[ ] Draw(VertexCount=3, InstanceCount=1) 110 | │ ├─[ ] "BlurPS" 111 | │ ├─[ ] Draw(VertexCount=3, InstanceCount=1) 112 | │ └─[ ] ----------Barrier---------- 113 | └─[ ] "Indirect draw simple" 114 | 115 | 116 | To learn about the contents of the crash analysis summary .txt file, please refer to the :doc:`help_manual`. 117 | 118 | DISCLAIMER 119 | ---------- 120 | The information contained herein is for informational purposes only, and is subject to change without notice. While every 121 | precaution has been taken in the preparation of this document, it may contain technical inaccuracies, omissions and typographical 122 | errors, and AMD is under no obligation to update or otherwise correct this information. Advanced Micro Devices, Inc. makes no 123 | representations or warranties with respect to the accuracy or completeness of the contents of this document, and assumes no 124 | liability of any kind, including the implied warranties of noninfringement, merchantability or fitness for particular purposes, with 125 | respect to the operation or use of AMD hardware, software or other products described herein. No license, including implied or 126 | arising by estoppel, to any intellectual property rights is granted by this document. Terms and limitations applicable to the purchase 127 | or use of AMD’s products are as set forth in a signed agreement between the parties or in AMD's Standard Terms and Conditions 128 | of Sale. 129 | 130 | AMD, the AMD Arrow logo, Radeon, Ryzen, CrossFire, RDNA and combinations thereof are trademarks of Advanced Micro Devices, Inc. Other product names used in 131 | this publication are for identification purposes only and may be trademarks of their respective companies. 132 | © 2025 Advanced Micro Devices, Inc. All rights reserved. 133 | -------------------------------------------------------------------------------- /external/.gitattributes: -------------------------------------------------------------------------------- 1 | amd_gpu_dis/Lib/VS2022/x64/amdgpu_dis.dll filter=lfs diff=lfs merge=lfs -text 2 | amd_gpu_dis/Lib/Linux/x64/libamdgpu_dis.so filter=lfs diff=lfs merge=lfs -text 3 | -------------------------------------------------------------------------------- /external/amd_gpu_dis/Include/CodeObjectDisassemblerApi.h: -------------------------------------------------------------------------------- 1 | /*=-- CodeObjectDisassemblerApi.hpp - Disassembler for AMD GPU Code Object ----------- C++ --=// 2 | // 3 | // The LLVM Compiler Infrastructure 4 | // 5 | // This file is distributed under the University of Illinois Open Source 6 | // License. See LICENSE.TXT for details. 7 | // 8 | //===--------------------------------------------------------------------------------------===// 9 | // 10 | /// \file 11 | /// 12 | /// This file contains declaration for AMD GPU Code Object Dissassembler API 13 | // 14 | //===--------------------------------------------------------------------------------------===*/ 15 | #ifndef CODE_OBJECT_DISASSEMBLER_API_H_ 16 | #define CODE_OBJECT_DISASSEMBLER_API_H_ 17 | 18 | #include /* for uintXX_t type */ 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | #if defined(_WIN32) || defined(__CYGWIN__) 25 | #if AMD_GPU_DIS_NO_EXPORTS 26 | #define AMD_GPU_DIS_API_ENTRY /* empty */ 27 | #elif defined(AMD_GPU_DIS_EXPORTS) 28 | /* Export symbols when building the library on Windows. */ 29 | #define AMD_GPU_DIS_API_ENTRY __declspec(dllexport) 30 | #else 31 | /* No symbol export when used by the library user on Windows. */ 32 | #define AMD_GPU_DIS_API_ENTRY __declspec(dllimport) 33 | #endif 34 | /* The API calling convention on Windows. */ 35 | #define AMD_GPU_DIS_API_CALL __cdecl 36 | #else 37 | #if __GNUC__ >= 4 38 | /* Use symbol visibility control supported by GCC 4.x and newer. */ 39 | #define AMD_GPU_DIS_API_ENTRY __attribute__((visibility("default"))) 40 | #else 41 | /* No symbol visibility control for GCC older than 4.0. */ 42 | #define AMD_GPU_DIS_API_ENTRY 43 | #endif 44 | /* The API calling convention on Linux. */ 45 | #define AMD_GPU_DIS_API_CALL 46 | #endif 47 | 48 | #define AMD_GPU_DIS_MAJOR_VERSION_NUMBER 1 49 | #define AMD_GPU_DIS_MINOR_VERSION_NUMBER (sizeof(AmdGpuDisApiTable)) 50 | 51 | #define AMD_GPU_DIS_INVALID_ADDRESS UINT64_MAX 52 | 53 | typedef enum { 54 | AMD_GPU_DIS_STATUS_SUCCESS = 0, 55 | AMD_GPU_DIS_STATUS_FAILED = -1, 56 | AMD_GPU_DIS_STATUS_NULL_POINTER = -2, 57 | AMD_GPU_DIS_STATUS_MEMORY_ALLOCATION_FAILURE = -3, 58 | AMD_GPU_DIS_STATUS_INVALID_INPUT = -4, 59 | AMD_GPU_DIS_STATUS_INVALID_CONTEXT_HANDLE = -5, 60 | AMD_GPU_DIS_STATUS_INVALID_CALLBACK = -6, 61 | AMD_GPU_DIS_STATUS_INVALID_CFG_BLOCK = -7, 62 | AMD_GPU_DIS_STATUS_INVALID_PC = -8, 63 | AMD_GPU_DIS_STATUS_OUT_OF_RANGE = -9 64 | } AmdGpuDisStatus; 65 | 66 | typedef struct { 67 | uint64_t handle; 68 | } AmdGpuDisContext; 69 | 70 | /* 71 | /// @brief This will be the entry API to get all the function pointers to be 72 | /// called 73 | */ 74 | extern AMD_GPU_DIS_API_ENTRY AmdGpuDisStatus AMD_GPU_DIS_API_CALL 75 | AmdGpuDisGetApiTable(void *ApiTableOut); 76 | 77 | /* 78 | /// @brief Create context handle 79 | */ 80 | typedef AmdGpuDisStatus(AMD_GPU_DIS_API_CALL *AmdGpuDisCreateContext_fn)( 81 | AmdGpuDisContext *Context); 82 | 83 | /* 84 | /// @brief Destroy context handle 85 | */ 86 | typedef AmdGpuDisStatus(AMD_GPU_DIS_API_CALL *AmdGpuDisDestroyContext_fn)( 87 | AmdGpuDisContext Context); 88 | 89 | /* 90 | /// @brief Load code object from buffer 91 | */ 92 | typedef AmdGpuDisStatus(AMD_GPU_DIS_API_CALL *AmdGpuDisLoadCodeObjectBuffer_fn)( 93 | AmdGpuDisContext Context, const char *CodeObjectBuffer, 94 | size_t CodeObjectBufferSize, bool EmitCFG); 95 | 96 | /* 97 | /// @brief Query disassembly string size 98 | */ 99 | typedef AmdGpuDisStatus( 100 | AMD_GPU_DIS_API_CALL *AmdGpuDisGetDisassemblyStringSize_fn)( 101 | AmdGpuDisContext Context, size_t *DisassemblyStringSize); 102 | 103 | /* 104 | /// @brief Query disassembly string 105 | */ 106 | typedef AmdGpuDisStatus(AMD_GPU_DIS_API_CALL *AmdGpuDisGetDisassemblyString_fn)( 107 | AmdGpuDisContext Context, char *DisassemblyString); 108 | 109 | /* 110 | /// @brief Query CFG head labels 111 | */ 112 | typedef AmdGpuDisStatus(AMD_GPU_DIS_API_CALL *AmdGpuDisIterateCfgHeads_fn)( 113 | AmdGpuDisContext Context, 114 | AmdGpuDisStatus (*Callback)(const char *head, void *UserData), 115 | void *UserData); 116 | 117 | /* 118 | /// @brief Query the destination block labels for a given block of CFG 119 | */ 120 | typedef AmdGpuDisStatus( 121 | AMD_GPU_DIS_API_CALL *AmdGpuDisIterateCfgBasicBlockDestinations_fn)( 122 | AmdGpuDisContext Context, const char *Block, 123 | AmdGpuDisStatus (*Callback)(const char *DstBlock, bool IsBranchTarget, 124 | void *UserData), 125 | void *UserData); 126 | 127 | /* 128 | /// @brief Query all instructions for a given block of CFG 129 | */ 130 | typedef AmdGpuDisStatus( 131 | AMD_GPU_DIS_API_CALL *AmdGpuDisIterateCfgBasicBlockInstructions_fn)( 132 | AmdGpuDisContext Context, const char *Block, 133 | AmdGpuDisStatus (*Callback)(const char *Inst, const char *Comment, 134 | void *UserData), 135 | void *UserData); 136 | 137 | /* 138 | /// @brief Query flattened block labels for a given head block of CFG 139 | */ 140 | typedef AmdGpuDisStatus( 141 | AMD_GPU_DIS_API_CALL *AmdGpuDisIterateCfgFlatBasicBlocks_fn)( 142 | AmdGpuDisContext Context, const char *HeadBlock, 143 | AmdGpuDisStatus (*Callback)(const char *Block, void *UserData), 144 | void *UserData); 145 | 146 | /* 147 | /// @brief Query an instruction for a given block of CFG with the index relative 148 | /// to the start of the block 149 | */ 150 | typedef AmdGpuDisStatus( 151 | AMD_GPU_DIS_API_CALL *AmdGpuDisGetCfgBasicBlockInstructionByIndex_fn)( 152 | AmdGpuDisContext Context, const char *Block, size_t Index, 153 | AmdGpuDisStatus (*Callback)(const char *Inst, const char *Comment, 154 | void *UserData), 155 | void *UserData); 156 | 157 | /* 158 | /// @brief Query the program counter for a given block of CFG with the index relative 159 | /// to the start of the block 160 | */ 161 | typedef AmdGpuDisStatus( 162 | AMD_GPU_DIS_API_CALL *AmdGpuDisGetProgramCounterByIndex_fn)( 163 | AmdGpuDisContext Context, const char *Block, size_t Index, 164 | uint64_t *ProgramCounter); 165 | 166 | /* 167 | /// @brief Query the address of an instruction by the address of its 168 | /// block and index within that block. 169 | */ 170 | typedef AmdGpuDisStatus( 171 | AMD_GPU_DIS_API_CALL 172 | *AmdGpuDisGetInstructionAddressByBlockAddressAndIndex_fn)( 173 | AmdGpuDisContext Context, uint64_t BlockAddr, uint64_t Index, 174 | uint64_t *InstrAddr); 175 | 176 | /* 177 | /// @brief Query the location of the instruction with the program counter 178 | */ 179 | typedef AmdGpuDisStatus( 180 | AMD_GPU_DIS_API_CALL 181 | *AmdGpuDisGetCfgInstructionLocationByProgramCounter_fn)( 182 | AmdGpuDisContext Context, uint64_t ProgramCounter, 183 | uint64_t *BasicBlockAddress, uint64_t *Offset); 184 | 185 | /* 186 | /// @brief Query the max program counter value 187 | */ 188 | typedef AmdGpuDisStatus( 189 | AMD_GPU_DIS_API_CALL *AmdGpuDisGetMaxProgramCounter_fn)( 190 | AmdGpuDisContext Context, uint64_t *ProgramCounter); 191 | 192 | /* 193 | /// @brief Query the starting program counter value of the first instruction 194 | */ 195 | typedef AmdGpuDisStatus( 196 | AMD_GPU_DIS_API_CALL *AmdGpuDisGetInstructionStartingProgramCounter_fn)( 197 | AmdGpuDisContext Context, uint64_t *ProgramCounter); 198 | 199 | /* 200 | /// @brief Query the number of instructions for a given block of CFG 201 | */ 202 | typedef AmdGpuDisStatus(AMD_GPU_DIS_API_CALL *AmdGpuDisGetCfgBasicBlockSize_fn)( 203 | AmdGpuDisContext Context, const char *Block, size_t *BlockSize); 204 | 205 | /* 206 | /// @brief Query the result if unknown instructions were seen for current CFG 207 | */ 208 | typedef AmdGpuDisStatus(AMD_GPU_DIS_API_CALL *AmdGpuDisIfSeenCfgUnknownInstructions_fn)( 209 | AmdGpuDisContext Context, const char *HeadBlock, bool *SeenUnknownInst); 210 | 211 | /* 212 | /// @brief Query the basic block name string by address 213 | */ 214 | typedef AmdGpuDisStatus( 215 | AMD_GPU_DIS_API_CALL *AmdGpuDisGetBasicBlockNameByAddress_fn)( 216 | AmdGpuDisContext Context, uint64_t BasicBlockAddress, 217 | AmdGpuDisStatus (*Callback)(const char *BasicBlockName, void *UserData), 218 | void *UserData); 219 | 220 | /* 221 | /// @brief Query the basic block address by name string 222 | */ 223 | typedef AmdGpuDisStatus( 224 | AMD_GPU_DIS_API_CALL *AmdGpuDisGetBasicBlockAddressByName_fn)( 225 | AmdGpuDisContext Context, const char *BasicBlockName, 226 | uint64_t *BasicBlockAddress); 227 | 228 | /* 229 | /// @brief Query the destination block addresses for a given block address of CFG 230 | */ 231 | typedef AmdGpuDisStatus( 232 | AMD_GPU_DIS_API_CALL *AmdGpuDisIterateCfgBasicBlockDestinationsByAddress_fn)( 233 | AmdGpuDisContext Context, uint64_t BasicBlockAddress, 234 | AmdGpuDisStatus (*Callback)(uint64_t DstBasicBlockAddress, 235 | bool IsBranchTarget, void *UserData), 236 | void *UserData); 237 | 238 | /* 239 | /// @brief Query an instruction for a given block address of CFG with the offset of the block 240 | */ 241 | typedef AmdGpuDisStatus( 242 | AMD_GPU_DIS_API_CALL *AmdGpuDisGetCfgBasicBlockInstructionLine_fn)( 243 | AmdGpuDisContext Context, uint64_t BasicBlockAddress, uint64_t Offset, 244 | AmdGpuDisStatus (*Callback)(const char *InstStr, const char *CommentStr, 245 | void *UserData), 246 | void *UserData); 247 | 248 | /* 249 | /// @brief Query the number of instructions for a given block of CFG by address 250 | */ 251 | typedef AmdGpuDisStatus( 252 | AMD_GPU_DIS_API_CALL *AmdGpuDisGetCfgBasicBlockSizeByAddress_fn)( 253 | AmdGpuDisContext Context, uint64_t BasicBlockAddress, 254 | uint64_t *BasicBlockSize); 255 | 256 | /* 257 | /// @brief Query the location address of the instruction with the program counter 258 | */ 259 | typedef AmdGpuDisStatus( 260 | AMD_GPU_DIS_API_CALL *AmdGpuDisGetCfgInstructionAddressByProgramCounter_fn)( 261 | AmdGpuDisContext Context, uint64_t ProgramCounter, 262 | uint64_t *BasicBlockAddress, uint64_t *Offset); 263 | 264 | /* 265 | /// @brief Query flattened block addresses for a given head block address of CFG 266 | */ 267 | typedef AmdGpuDisStatus( 268 | AMD_GPU_DIS_API_CALL *AmdGpuDisIterateCfgFlatBasicBlockAddresses_fn)( 269 | AmdGpuDisContext Context, uint64_t HeadBlockAddress, 270 | AmdGpuDisStatus (*Callback)(uint64_t Address, void *UserData), 271 | void *UserData); 272 | 273 | /* 274 | /// @brief Query CFG head addresses 275 | */ 276 | typedef AmdGpuDisStatus( 277 | AMD_GPU_DIS_API_CALL *AmdGpuDisIterateCfgHeadAddresses_fn)( 278 | AmdGpuDisContext Context, 279 | AmdGpuDisStatus (*Callback)(uint64_t Address, void *UserData), 280 | void *UserData); 281 | 282 | /* 283 | /// @brief Query all instructions for a given block address of CFG 284 | */ 285 | typedef AmdGpuDisStatus( 286 | AMD_GPU_DIS_API_CALL 287 | *AmdGpuDisIterateCfgBasicBlockInstructionsByAddress_fn)( 288 | AmdGpuDisContext Context, uint64_t BasicBlockAddress, 289 | AmdGpuDisStatus (*Callback)(const char *InstStr, const char *CommentStr, 290 | void *UserData), 291 | void *UserData); 292 | 293 | /* 294 | /// @brief Query a block by its address. 295 | */ 296 | typedef struct AmdGpuDisBlock AmdGpuDisBlock; 297 | typedef AmdGpuDisStatus(AMD_GPU_DIS_API_CALL *AmdGpuDisGetBlockByAddress_fn)( 298 | AmdGpuDisContext Context, uint64_t BlockAddr, const AmdGpuDisBlock **Block); 299 | 300 | /* 301 | /// @brief Query the address of a given block. 302 | */ 303 | typedef AmdGpuDisStatus(AMD_GPU_DIS_API_CALL *AmdGpuDisGetBlockAddress_fn)( 304 | const AmdGpuDisBlock *Block, uint64_t *BlockAddr); 305 | 306 | typedef struct { 307 | uint32_t MajorVersion; 308 | uint32_t MinorVersion; 309 | 310 | AmdGpuDisCreateContext_fn AmdGpuDisCreateContext; 311 | AmdGpuDisDestroyContext_fn AmdGpuDisDestroyContext; 312 | AmdGpuDisLoadCodeObjectBuffer_fn AmdGpuDisLoadCodeObjectBuffer; 313 | AmdGpuDisGetDisassemblyStringSize_fn AmdGpuDisGetDisassemblyStringSize; 314 | AmdGpuDisGetDisassemblyString_fn AmdGpuDisGetDisassemblyString; 315 | AmdGpuDisIterateCfgHeads_fn AmdGpuDisIterateCfgHeads; 316 | AmdGpuDisIterateCfgBasicBlockDestinations_fn 317 | AmdGpuDisIterateCfgBasicBlockDestinations; 318 | AmdGpuDisIterateCfgBasicBlockInstructions_fn 319 | AmdGpuDisIterateCfgBasicBlockInstructions; 320 | AmdGpuDisIterateCfgFlatBasicBlocks_fn AmdGpuDisIterateCfgFlatBasicBlocks; 321 | AmdGpuDisGetCfgBasicBlockInstructionByIndex_fn 322 | AmdGpuDisGetCfgBasicBlockInstructionByIndex; 323 | AmdGpuDisGetProgramCounterByIndex_fn AmdGpuDisGetProgramCounterByIndex; 324 | AmdGpuDisGetCfgInstructionLocationByProgramCounter_fn 325 | AmdGpuDisGetCfgInstructionLocationByProgramCounter; 326 | AmdGpuDisGetCfgBasicBlockSize_fn AmdGpuDisGetCfgBasicBlockSize; 327 | AmdGpuDisIfSeenCfgUnknownInstructions_fn 328 | AmdGpuDisIfSeenCfgUnknownInstructions; 329 | AmdGpuDisGetMaxProgramCounter_fn AmdGpuDisGetMaxProgramCounter; 330 | AmdGpuDisGetInstructionStartingProgramCounter_fn 331 | AmdGpuDisGetInstructionStartingProgramCounter; 332 | AmdGpuDisGetBasicBlockNameByAddress_fn AmdGpuDisGetBasicBlockNameByAddress; 333 | AmdGpuDisGetBasicBlockAddressByName_fn AmdGpuDisGetBasicBlockAddressByName; 334 | AmdGpuDisIterateCfgBasicBlockDestinationsByAddress_fn 335 | AmdGpuDisIterateCfgBasicBlockDestinationsByAddress; 336 | AmdGpuDisGetCfgBasicBlockInstructionLine_fn 337 | AmdGpuDisGetCfgBasicBlockInstructionLine; 338 | AmdGpuDisGetCfgBasicBlockSizeByAddress_fn 339 | AmdGpuDisGetCfgBasicBlockSizeByAddress; 340 | AmdGpuDisGetCfgInstructionAddressByProgramCounter_fn 341 | AmdGpuDisGetCfgInstructionAddressByProgramCounter; 342 | AmdGpuDisIterateCfgFlatBasicBlockAddresses_fn 343 | AmdGpuDisIterateCfgFlatBasicBlockAddresses; 344 | AmdGpuDisIterateCfgHeadAddresses_fn AmdGpuDisIterateCfgHeadAddresses; 345 | AmdGpuDisIterateCfgBasicBlockInstructionsByAddress_fn 346 | AmdGpuDisIterateCfgBasicBlockInstructionsByAddress; 347 | AmdGpuDisGetInstructionAddressByBlockAddressAndIndex_fn 348 | AmdGpuDisGetInstructionAddressByBlockAddressAndIndex; 349 | AmdGpuDisGetBlockByAddress_fn GetBlockByAddress; 350 | AmdGpuDisGetBlockAddress_fn GetBlockAddress; 351 | } AmdGpuDisApiTable; 352 | 353 | #ifdef __cplusplus 354 | } 355 | #endif 356 | 357 | #endif /* CODE_OBJECT_DISASSEMBLER_API_H_ */ 358 | -------------------------------------------------------------------------------- /external/amd_gpu_dis/Lib/Linux/x64/libamdgpu_dis.so: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:c7387cecc1bb5359da5ff28d1826ce5b1c9174677439ce62e340aa167829105a 3 | size 22776640 4 | -------------------------------------------------------------------------------- /external/amd_gpu_dis/Lib/VS2022/x64/amdgpu_dis.dll: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:793fd138366d178bedaa99268668393eeab72bd8c615afa0e792479e8e890dc4 3 | size 15464960 4 | -------------------------------------------------------------------------------- /external/amd_gpu_dis/Lib/VS2022/x64/amdgpu_dis.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GPUOpen-Tools/radeon_gpu_detective/21c2589081650e0d1cfdc356b4c3ed931e2a132e/external/amd_gpu_dis/Lib/VS2022/x64/amdgpu_dis.lib -------------------------------------------------------------------------------- /samples/sample_crash_dump.rgd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GPUOpen-Tools/radeon_gpu_detective/21c2589081650e0d1cfdc356b4c3ed931e2a132e/samples/sample_crash_dump.rgd -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #============================================================================= 2 | # Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | # @author AMD Developer Tools Team 4 | # @file 5 | # @brief RGD Backend CMakeLists file. 6 | #============================================================================= 7 | 8 | cmake_minimum_required (VERSION 3.10) 9 | project (rgd_backend) 10 | 11 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 12 | 13 | # Include cxxopts for command line parsing. 14 | include_directories("${PROJECT_SOURCE_DIR}/../../external/") 15 | include_directories("${PROJECT_SOURCE_DIR}/../../external/rmv/source/parser/") 16 | include_directories("${PROJECT_SOURCE_DIR}/../../external/rmv/source/backend/") 17 | include_directories("${PROJECT_SOURCE_DIR}/../../external/third_party/") 18 | include_directories("${PROJECT_SOURCE_DIR}/../../external/rdf/rdf/inc/") 19 | include_directories("${PROJECT_SOURCE_DIR}/../../external/comgr_package/comgr_utils/") 20 | include_directories("${PROJECT_SOURCE_DIR}/../../external/comgr_package/comgr/include/") 21 | include_directories(AFTER ${AMDGPU_DIS_INCLUDE_DIR} ) 22 | include_directories(AFTER ${AMD_COMGR_INCLUDE_DIR} ) 23 | 24 | set(CMAKE_CXX_STANDARD 17) 25 | 26 | # RDF. 27 | add_definitions(-DSYSTEM_INFO_ENABLE_RDF) 28 | add_definitions(-DRDF_CXX_BINDINGS) 29 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 30 | 31 | IF (WIN32) 32 | add_definitions(-DRDF_PLATFORM_WINDOWS) 33 | add_link_options(/STACK:16777216) 34 | ELSEIF(UNIX) 35 | add_definitions(-DRDF_PLATFORM_UNIX) 36 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,stack-size=16777216") 37 | ENDIF(WIN32) 38 | 39 | # RGD backend source files that are common for Windows and Linux 40 | file (GLOB RGD_BACKEND_SOURCE 41 | "*.h" 42 | "*.cpp" 43 | "../../external/nlohmann/*.hpp" 44 | ) 45 | 46 | add_library(${PROJECT_NAME} STATIC ${RGD_BACKEND_SOURCE}) 47 | 48 | set_property(TARGET ${PROJECT_NAME} PROPERTY POSITION_INDEPENDENT_CODE ON) 49 | -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_amd_gpu_dis_loader.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================================ 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools 4 | /// @file 5 | /// @brief This is a dynamic loader module of AMDGPUDis library. 6 | //============================================================================================ 7 | 8 | #include "rgd_amd_gpu_dis_loader.h" 9 | 10 | AmdGpuDisEntryPoints* AmdGpuDisEntryPoints::instance_ = nullptr; 11 | std::once_flag AmdGpuDisEntryPoints::init_instance_flag_; -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_amd_gpu_dis_loader.h: -------------------------------------------------------------------------------- 1 | //============================================================================================ 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools 4 | /// @file 5 | /// @brief This is a dynamic loader module of AMDGPUDis library. 6 | //============================================================================================ 7 | 8 | #ifndef RGD_BACKEND_RGD_AMD_GPU_DIS_LOADER_H_ 9 | #define RGD_BACKEND_RGD_AMD_GPU_DIS_LOADER_H_ 10 | 11 | #ifdef _WIN32 12 | #ifndef NOMINMAX 13 | #define NOMINMAX 14 | #endif 15 | #include 16 | #include 17 | #else 18 | #include 19 | #endif 20 | 21 | #include 22 | #include 23 | 24 | #include "CodeObjectDisassemblerApi.h" 25 | 26 | /// @brief Singleton class to manage the disassembler entry points. 27 | class AmdGpuDisEntryPoints 28 | { 29 | public: 30 | decltype(AmdGpuDisGetApiTable)* AmdGpuDisGetApiTable_fn; ///< Type for function pointer to get entry point table. 31 | 32 | /// @brief Get singleton instance. 33 | /// 34 | /// @return The singleton instance of AmdGpuDisEntryPoints. 35 | static AmdGpuDisEntryPoints* Instance() 36 | { 37 | std::call_once(init_instance_flag_, InitInstance); 38 | 39 | return instance_; 40 | } 41 | 42 | /// @brief Delete singleton instance. 43 | static void DeleteInstance() 44 | { 45 | if (nullptr != instance_) 46 | { 47 | AmdGpuDisEntryPoints* copy_of_instance = instance_; 48 | instance_ = nullptr; 49 | delete copy_of_instance; 50 | } 51 | } 52 | 53 | /// @brief Check whether the entry points are valid. 54 | /// 55 | /// @return true if all entry points were initialized. 56 | bool EntryPointsValid() 57 | { 58 | return entry_points_valid_; 59 | } 60 | 61 | private: 62 | bool entry_points_valid_ = true; ///< Flag indicating if the AMDGPUDis library entry points are valid. 63 | 64 | #ifdef _WIN32 65 | HMODULE module_; ///< The AMDGPUDis library module handle. 66 | #else 67 | void* module_; ///< The AMDGPUDis library module handle. 68 | #endif 69 | 70 | /// @brief Attempts to initialize the specified AMDGPUDis library entry point. 71 | /// 72 | /// @param [in] entry_point_name The name of the entry point to initialize. 73 | /// 74 | /// @return The address of the entry point or nullptr if the entry point could not be initialized. 75 | void* InitEntryPoint(const char* entry_point_name) 76 | { 77 | if (nullptr != module_) 78 | { 79 | #ifdef _WIN32 80 | return GetProcAddress(module_, entry_point_name); 81 | #else 82 | return dlsym(module_, entry_point_name); 83 | #endif 84 | } 85 | 86 | return nullptr; 87 | } 88 | 89 | /// @brief Private constructor. 90 | AmdGpuDisEntryPoints() 91 | { 92 | #ifdef _WIN32 93 | module_ = LoadLibrary(_T("amdgpu_dis.dll")); 94 | #else 95 | module_ = dlopen("libamdgpu_dis.so", RTLD_LAZY | RTLD_DEEPBIND); 96 | #endif 97 | #define INIT_AMDGPUDIS_ENTRY_POINT(func) \ 98 | reinterpret_cast(InitEntryPoint(#func)); \ 99 | entry_points_valid_ &= nullptr != func##_fn 100 | 101 | AmdGpuDisGetApiTable_fn = INIT_AMDGPUDIS_ENTRY_POINT(AmdGpuDisGetApiTable); 102 | #undef INIT_AMDGPUDIS_ENTRY_POINT 103 | } 104 | 105 | /// @brief Destructor. 106 | virtual ~AmdGpuDisEntryPoints() 107 | { 108 | if (nullptr != module_) 109 | { 110 | #ifdef _WIN32 111 | FreeLibrary(module_); 112 | #else 113 | dlclose(module_); 114 | #endif 115 | } 116 | DeleteInstance(); 117 | } 118 | 119 | static AmdGpuDisEntryPoints* instance_; ///< Static singleton instance. 120 | static std::once_flag init_instance_flag_; ///< Static instance init flag for multithreading. 121 | 122 | /// @brief Create the singleton instance. 123 | static void InitInstance() 124 | { 125 | instance_ = new (std::nothrow) AmdGpuDisEntryPoints; 126 | } 127 | }; 128 | 129 | #endif // RGD_BACKEND_RGD_AMD_GPU_DIS_LOADER_H_ -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_asic_info.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2022-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief Implementation for ASIC info utilities. 6 | //============================================================================= 7 | 8 | #include "rgd_asic_info.h" 9 | 10 | namespace ecitrace 11 | { 12 | // See amdgpu_asic.h and Device::DetermineGpuIpLevels() in PAL 13 | static constexpr uint32_t kFamilyNavi = 0x8F; 14 | static constexpr uint32_t kNavi2XMinimumRevision = 0x28; 15 | 16 | static constexpr uint32_t kFamilyNavi3 = 0x91; 17 | 18 | static constexpr uint32_t kFamilyNavi4 = 0x98; 19 | 20 | GpuSeries ecitrace::AsicInfo::GetGpuSeries(const uint32_t asic_family, const uint32_t asic_e_rev) 21 | { 22 | if (asic_family == kFamilyNavi) 23 | { 24 | return asic_e_rev < kNavi2XMinimumRevision ? GpuSeries::kNavi1 : GpuSeries::kNavi2; 25 | } 26 | 27 | // This is derived from Gfx9::DetermineIpLevel() in PAL 28 | switch (asic_family) 29 | { 30 | case kFamilyNavi3: 31 | return GpuSeries::kNavi3; 32 | case kFamilyNavi4: 33 | return GpuSeries::kNavi4; 34 | 35 | default: 36 | return GpuSeries::kUnknown; 37 | } 38 | } 39 | }; // namespace ecitrace -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_asic_info.h: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2022-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief Declaration for ASIC info utilities. 6 | //============================================================================= 7 | 8 | #ifndef RGD_SOURCE_TRACE_INC_ASIC_INFO_H_ 9 | #define RGD_SOURCE_TRACE_INC_ASIC_INFO_H_ 10 | 11 | #include 12 | 13 | namespace ecitrace 14 | { 15 | /// @brief The different releases of GPUs. 16 | enum class GpuSeries : uint8_t 17 | { 18 | kUnknown = 0, 19 | kNavi1, ///< The Navi1 series of cards. 20 | kNavi2, ///< The Navi2 series of cards. 21 | kNavi3, ///< The Navi3 series of cards. 22 | kNavi4 ///< The Navi4 series of cards. 23 | }; 24 | 25 | /// @brief An utility function that help with determining info about the ASIC. 26 | struct AsicInfo 27 | { 28 | /// @brief Provides the GPU series for an ASIC. 29 | /// @param [in] asic_family The family of the ASIC. 30 | /// @param [in] asic_e_rev The eRevision of the ASIC. 31 | /// @return The series for the ASIC. 32 | static GpuSeries GetGpuSeries(uint32_t asic_family, uint32_t asic_e_rev); 33 | 34 | private: 35 | /// @brief Constructor. 36 | AsicInfo() = default; 37 | }; 38 | } // namespace ecitrace 39 | #endif //RGD_SOURCE_TRACE_INC_ASIC_INFO_H_ -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_code_object_comgr_handle.h: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief Code object manager handles. 6 | //============================================================================= 7 | 8 | #ifndef RGD_BACKEND_RGD_CODE_OBJECT_COMGR_HANDLE_H_ 9 | #define RGD_BACKEND_RGD_CODE_OBJECT_COMGR_HANDLE_H_ 10 | 11 | #include 12 | #include "amd_comgr.h" 13 | 14 | /// RGD style Handle to access comgr. 15 | typedef std::unique_ptr RgdComgrHandle; 16 | 17 | #endif // RGD_BACKEND_RGD_CODE_OBJECT_COMGR_HANDLE_H_ -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_code_object_database.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================================ 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools 4 | /// @file 5 | /// @brief 6 | //============================================================================================ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "rgd_amd_gpu_dis_loader.h" 13 | #include "rgd_code_object_database.h" 14 | #include "rgd_utils.h" 15 | 16 | // Global disassembler function table. 17 | AmdGpuDisApiTable rgd_disassembler_api_table = {}; 18 | 19 | // *** INTERNALLY-LINKED AUXILIARY FUNCTIONS - BEGIN *** 20 | static uint64_t crashing_shader_count = 0; 21 | 22 | // Initialize the comgr handles for the code object entries. 23 | static bool RgdCodeObjDbInitializeComgrHandles(RgdCodeObjectDatabase* code_object_db) 24 | { 25 | assert(code_object_db != nullptr); 26 | 27 | bool ret = true; 28 | if (code_object_db != nullptr || code_object_db->entries_.size() == 0) 29 | { 30 | ret = false; 31 | } 32 | 33 | for (RgdCodeObjectEntry& entry : code_object_db->entries_) 34 | { 35 | const char* code_object_payload = (const char*)entry.code_object_payload_.data(); 36 | entry.comgr_handle_ = amdt::CodeObj::OpenBufferRaw(code_object_payload, entry.code_obj_size_in_bytes_); 37 | if (entry.comgr_handle_ != nullptr) 38 | { 39 | // Extract the Pal PipelineData. 40 | const bool [[maybe_unused]] is_contains_pal_metadata = 41 | (amdt::kComgrUtilsStatusSuccess == entry.comgr_handle_->ExtractPalPipelineData(entry.pipeline_data_)); 42 | 43 | // Now try to extract symbols. 44 | if (!entry.comgr_handle_->ExtractSymbolData(entry.symbol_info_)) 45 | { 46 | RgdUtils::PrintMessage("failed to extract symbol data for the code object", RgdMessageType::kError, true); 47 | ret = false; 48 | } 49 | 50 | // Really should have at least 1 symbol. 51 | assert(is_contains_pal_metadata && entry.symbol_info_.num_symbols > 0); 52 | } 53 | else 54 | { 55 | // Failed to open the buffer. 56 | RgdUtils::PrintMessage("failed to open code object buffer.", RgdMessageType::kError, true); 57 | ret = false; 58 | } 59 | } 60 | 61 | return ret; 62 | } 63 | 64 | // Get the hardware stage for the shader. 65 | static amdt::HwStageType GetHwStageForShader(uint16_t hardware_mapping_bit_field) 66 | { 67 | int ret = log2(hardware_mapping_bit_field); 68 | amdt::HwStageType hw_stage = (amdt::HwStageType)ret; 69 | return hw_stage; 70 | } 71 | 72 | // Get the shader type string. 73 | static std::string GetShaderTypeString(amdt::ShaderInfoType shader_type) 74 | { 75 | std::stringstream ret; 76 | switch (shader_type) 77 | { 78 | case amdt::kVertexShader: 79 | ret << "Vertex"; 80 | break; 81 | case amdt::kHullShader: 82 | ret << "Hull"; 83 | break; 84 | case amdt::kDomainShader: 85 | ret << "Domain"; 86 | break; 87 | case amdt::kGeometryShader: 88 | ret << "Geometry"; 89 | break; 90 | case amdt::kPixelShader: 91 | ret << "Pixel"; 92 | break; 93 | case amdt::kComputeShader: 94 | ret << "Compute"; 95 | break; 96 | case amdt::kMeshShader: 97 | ret << "Mesh"; 98 | break; 99 | case amdt::kTaskShader: 100 | ret << "Task"; 101 | break; 102 | default: 103 | ret << kStrUnknown; 104 | break; 105 | } 106 | 107 | return ret.str(); 108 | } 109 | 110 | // Get the hardware stage string. 111 | static std::string GetHwStageString(amdt::HwStageType hw_stage) 112 | { 113 | std::stringstream ret; 114 | switch (hw_stage) 115 | { 116 | case amdt::kHwStageEs: 117 | ret << "ES"; 118 | break; 119 | case amdt::kHwStageGs: 120 | ret << "GS"; 121 | break; 122 | case amdt::kHwStageVs: 123 | ret << "VS"; 124 | break; 125 | case amdt::kHwStageHs: 126 | ret << "HS"; 127 | break; 128 | case amdt::kHwStageLs: 129 | ret << "LS"; 130 | break; 131 | case amdt::kHwStageSs: 132 | ret << "SS"; 133 | break; 134 | case amdt::kHwStagePrimS: 135 | ret << "PrimS"; 136 | break; 137 | case amdt::kHwStagePs: 138 | ret << "PS"; 139 | break; 140 | case amdt::kHwStageCs: 141 | ret << "CS"; 142 | break; 143 | default: 144 | ret << kStrUnknown; 145 | break; 146 | } 147 | 148 | return ret.str(); 149 | } 150 | 151 | // Build the instructions vector for the shader. 152 | static void BuildInstructionsVectorForShader(const std::string& disassembly_text, 153 | const std::string entry_point_symbol_name, 154 | uint64_t symbol_size, 155 | std::vector>& out_instructions_vector) 156 | { 157 | std::istringstream disassembly_stream(disassembly_text); 158 | std::string line; 159 | 160 | // Regular expression to match lines with instructions. 161 | std::regex symbol_entry_point_regex(R"((_amdgpu_.._main):)"); 162 | std::regex instruction_regex(R"((^\s*)(.+)(//\s)([0-9a-fA-F]+):(\s[0-9a-fA-F]+){1,3})"); 163 | std::regex branch_label_regex(R"(^_L[\d]+:)"); 164 | std::regex padding_instruction_s_code_end_regex(R"((^\s*)(s_code_end)(.+))"); 165 | 166 | bool is_entry_point_found = false; 167 | uint64_t start_offset = UINT64_MAX; 168 | uint64_t end_offset = 0; 169 | 170 | // Parse the disassembly text to extract instructions and their offsets. 171 | while (std::getline(disassembly_stream, line)) 172 | { 173 | // Check if the line starts with a tab character 174 | if (!line.empty() && line[0] == '\t') 175 | { 176 | // Replace the tab character with spaces (e.g., 4 spaces) 177 | line.replace(0, 1, " "); 178 | } 179 | 180 | std::smatch match; 181 | if (std::regex_match(line, match, symbol_entry_point_regex)) 182 | { 183 | if (match[1].str() == entry_point_symbol_name) 184 | { 185 | is_entry_point_found = true; 186 | } 187 | } 188 | 189 | if (is_entry_point_found) 190 | { 191 | if (std::regex_match(line, match, padding_instruction_s_code_end_regex)) 192 | { 193 | break; 194 | } 195 | 196 | if (std::regex_match(line, match, instruction_regex)) 197 | { 198 | // Extract the offset from the matched line. 199 | uint64_t offset = std::stoull(match[4].str(), nullptr, 16); 200 | if (start_offset == UINT64_MAX) 201 | { 202 | // Extract the offset from the matched line. 203 | start_offset = offset; 204 | end_offset = start_offset + symbol_size; 205 | } 206 | 207 | if (offset < end_offset) 208 | { 209 | out_instructions_vector.emplace_back(offset, line); 210 | } 211 | else 212 | { 213 | break; 214 | } 215 | } 216 | else if (std::regex_match(line, match, branch_label_regex)) 217 | { 218 | uint64_t offset = 0; 219 | out_instructions_vector.emplace_back(offset, line); 220 | } 221 | } 222 | } 223 | } 224 | 225 | // Check if the shader was in-flight at the time of the crash. 226 | static bool IsInFlightShader(const std::map& pc_offset_to_hung_wave_count_map_, RgdShaderInfo shader_info) 227 | { 228 | bool is_in_flight_shader = false; 229 | assert(shader_info.instructions.size() != 0); 230 | if (shader_info.instructions.size() != 0) 231 | { 232 | uint64_t start_offset = shader_info.instructions[0].first; 233 | uint64_t end_offset = shader_info.instructions[shader_info.instructions.size() - 1].first; 234 | 235 | for (const std::pair& pc_offset_to_hung_wave_count : pc_offset_to_hung_wave_count_map_) 236 | { 237 | // Check if the PC offset falls within the range of the shader instructions. 238 | // PC always points to the next instruction to execute. So it not expected to be equal to the offset for the first instruction in the shader 239 | if (pc_offset_to_hung_wave_count.first > start_offset && pc_offset_to_hung_wave_count.first <= end_offset) 240 | { 241 | is_in_flight_shader = true; 242 | break; 243 | } 244 | } 245 | } 246 | return is_in_flight_shader; 247 | } 248 | 249 | // Get the symbol size from the symbol name metadata. 250 | static uint64_t RgdGetSymbolSizeFromSymbolName(const std::string symbol_name, RgdCodeObjectEntry* entry) 251 | { 252 | uint64_t symbol_size = 0; 253 | for (uint32_t j = 0; j < entry->symbol_info_.num_symbols; ++j) 254 | { 255 | const amdt::CodeObjSymbol* symbol = &(entry->symbol_info_.symbols[j]); 256 | if (symbol_name == symbol->symbol_function.name) 257 | { 258 | symbol_size = symbol->symbol_function.symbol_size; 259 | break; 260 | } 261 | } 262 | 263 | return symbol_size; 264 | } 265 | 266 | // Initialize the code object entry. 267 | static void RgdCodeObjDbInitCodeObjEntry(RgdCodeObjectEntry* entry) 268 | { 269 | assert(entry != nullptr); 270 | if (entry != nullptr) 271 | { 272 | if (RgdCodeObjDbCreateIsaContextAmdGpuDis(entry)) 273 | { 274 | AmdGpuDisStatus status = AMD_GPU_DIS_STATUS_FAILED; 275 | 276 | // Get the full AMDGPU disassembly for the code object entry. 277 | size_t disassembly_string_size = 0; 278 | status = rgd_disassembler_api_table.AmdGpuDisGetDisassemblyStringSize(entry->amd_gpu_dis_context_, &disassembly_string_size); 279 | if (status == AMD_GPU_DIS_STATUS_SUCCESS) 280 | { 281 | std::vector disassembly_string(disassembly_string_size); 282 | status = rgd_disassembler_api_table.AmdGpuDisGetDisassemblyString(entry->amd_gpu_dis_context_, disassembly_string.data()); 283 | if (status == AMD_GPU_DIS_STATUS_SUCCESS) 284 | { 285 | entry->disassembly_ = std::string(disassembly_string.data()); 286 | } 287 | else 288 | { 289 | entry->disassembly_ = kStrNotAvailable; 290 | } 291 | } 292 | 293 | const amdt::PalPipelineData* pipeline_data = &(entry->pipeline_data_); 294 | 295 | assert(pipeline_data->num_pipelines != 0); 296 | assert(pipeline_data->pipelines != nullptr); 297 | 298 | if (pipeline_data->pipelines != nullptr && pipeline_data->num_pipelines != 0) 299 | { 300 | // For each shader in the pipeline metadata, build the shader info. 301 | for (size_t j = 0; j < pipeline_data->pipelines[0].num_shaders; ++j) 302 | { 303 | amdt::HwStageType stage = GetHwStageForShader(pipeline_data->pipelines[0].shader_list[j].hardware_mapping_bit_field); 304 | RgdShaderInfo shader_info; 305 | assert(entry->hw_stage_to_shader_info_map_.find(stage) == entry->hw_stage_to_shader_info_map_.end()); 306 | shader_info.api_shader_hash_lo = pipeline_data->pipelines[0].shader_list[j].api_shader_hash_lo; 307 | shader_info.api_shader_hash_hi = pipeline_data->pipelines[0].shader_list[j].api_shader_hash_hi; 308 | shader_info.api_stage = GetShaderTypeString(pipeline_data->pipelines[0].shader_list[j].shader_type); 309 | shader_info.hw_stage = GetHwStageString(stage); 310 | entry->hw_stage_to_shader_info_map_[stage] = shader_info; 311 | } 312 | 313 | // For each stage in the pipeline metadata, update the respective shader info. 314 | for (size_t j = 0; j < pipeline_data->pipelines[0].num_stages; ++j) 315 | { 316 | amdt::HwStageType stage = pipeline_data->pipelines[0].stage_list[j].stage_type; 317 | 318 | assert(entry->hw_stage_to_shader_info_map_.find(stage) != entry->hw_stage_to_shader_info_map_.end()); 319 | if (entry->hw_stage_to_shader_info_map_.find(stage) != entry->hw_stage_to_shader_info_map_.end()) 320 | { 321 | RgdShaderInfo& shader_info = entry->hw_stage_to_shader_info_map_[stage]; 322 | assert(pipeline_data->pipelines[0].stage_list[j].entry_point_symbol_name != nullptr); 323 | if (pipeline_data->pipelines[0].stage_list[j].entry_point_symbol_name != nullptr) 324 | { 325 | shader_info.entry_point_symbol_name = pipeline_data->pipelines[0].stage_list[j].entry_point_symbol_name; 326 | } 327 | else 328 | { 329 | shader_info.entry_point_symbol_name = ""; 330 | RgdUtils::PrintMessage("failed to find entry point symbol name for the hardware stage.", RgdMessageType::kError, true); 331 | } 332 | shader_info.symbol_size = RgdGetSymbolSizeFromSymbolName(shader_info.entry_point_symbol_name, entry); 333 | 334 | // Build the instructions vector for the shader. 335 | assert(shader_info.symbol_size != 0); 336 | assert(!entry->disassembly_.empty()); 337 | BuildInstructionsVectorForShader( 338 | entry->disassembly_, shader_info.entry_point_symbol_name, shader_info.symbol_size, shader_info.instructions); 339 | 340 | // Make a copy of instructions for json output. 341 | shader_info.instructions_json_output = shader_info.instructions; 342 | 343 | // Check if this shader is the crashing shader. 344 | assert(shader_info.instructions.size() != 0); 345 | if (shader_info.instructions.size() != 0) 346 | { 347 | // Update the crashing shader flag and assign the seq number/id to the crashing shader. 348 | if (IsInFlightShader(entry->pc_offset_to_hung_wave_count_map_, shader_info)) 349 | { 350 | shader_info.is_in_flight_shader = true; 351 | shader_info.crashing_shader_id = ++crashing_shader_count; 352 | shader_info.str_shader_info_id = RgdUtils::GetAlphaNumericId(kStrPrefixShaderInfoId, shader_info.crashing_shader_id); 353 | } 354 | } 355 | } 356 | else 357 | { 358 | RgdUtils::PrintMessage("failed to find shader info for the hardware stage.", RgdMessageType::kError, true); 359 | } 360 | } 361 | } 362 | else 363 | { 364 | RgdUtils::PrintMessage("failed to find pipeline data for the code object.", RgdMessageType::kError, true); 365 | } 366 | } 367 | } 368 | } 369 | 370 | // *** INTERNALLY-LINKED AUXILIARY FUNCTIONS - END *** 371 | 372 | bool RgdCodeObjectDatabase::AddCodeObject(uint64_t pc_instruction_offset, 373 | uint64_t api_pso_hash, 374 | size_t pc_wave_count, 375 | Rgd128bitHash internal_pipeline_hash, 376 | std::vector&& code_object_payload) 377 | { 378 | bool ret = true; 379 | if (!is_code_obj_db_built_) 380 | { 381 | if (internal_pipeline_hash_to_entry_map_.find(internal_pipeline_hash) == internal_pipeline_hash_to_entry_map_.end()) 382 | { 383 | // Code object entry does not exist. Create a new one. 384 | entries_.emplace_back(); 385 | RgdCodeObjectEntry& entry = entries_.back(); 386 | entry.internal_pipeline_hash_ = internal_pipeline_hash; 387 | entry.api_pso_hash_ = api_pso_hash; 388 | entry.code_object_payload_ = std::move(code_object_payload); 389 | entry.code_obj_size_in_bytes_ = entry.code_object_payload_.size(); 390 | assert(entry.code_obj_size_in_bytes_ != 0); 391 | internal_pipeline_hash_to_entry_map_[internal_pipeline_hash] = &entry; 392 | 393 | assert(entry.pc_offset_to_hung_wave_count_map_.find(pc_instruction_offset) == entry.pc_offset_to_hung_wave_count_map_.end()); 394 | entry.pc_offset_to_hung_wave_count_map_[pc_instruction_offset] = pc_wave_count; 395 | } 396 | else 397 | { 398 | // Code object entry already exists. Update the additional pc instruction offset information. 399 | RgdCodeObjectEntry& entry = *internal_pipeline_hash_to_entry_map_[internal_pipeline_hash]; 400 | 401 | if (entry.pc_offset_to_hung_wave_count_map_.find(pc_instruction_offset) != entry.pc_offset_to_hung_wave_count_map_.end()) 402 | { 403 | // This pc instruction offset already exists. Update the wave count. 404 | entry.pc_offset_to_hung_wave_count_map_[pc_instruction_offset] += pc_wave_count; 405 | } 406 | else 407 | { 408 | // This pc instruction offset does not exist. Add it. 409 | entry.pc_offset_to_hung_wave_count_map_[pc_instruction_offset] = pc_wave_count; 410 | } 411 | } 412 | } 413 | else 414 | { 415 | // AddCodeObject should be called before Populate. 416 | assert(false); 417 | ret = false; 418 | } 419 | 420 | return ret; 421 | } 422 | 423 | bool RgdCodeObjectDatabase::Populate() 424 | { 425 | bool ret = true; 426 | if (entries_.size() == 0) 427 | { 428 | ret = false; 429 | } 430 | else 431 | { 432 | rgd_disassembler_api_table.MajorVersion = AMD_GPU_DIS_MAJOR_VERSION_NUMBER; 433 | rgd_disassembler_api_table.MinorVersion = AMD_GPU_DIS_MINOR_VERSION_NUMBER; 434 | 435 | AmdGpuDisStatus status = AMD_GPU_DIS_STATUS_FAILED; 436 | 437 | if (nullptr == AmdGpuDisEntryPoints::Instance()->AmdGpuDisGetApiTable_fn) 438 | { 439 | RgdUtils::PrintMessage("unable to load and initialize disassembler.", RgdMessageType::kError, true); 440 | ret = false; 441 | } 442 | else 443 | { 444 | status = AmdGpuDisEntryPoints::Instance()->AmdGpuDisGetApiTable_fn(&rgd_disassembler_api_table); 445 | if (status == AMD_GPU_DIS_STATUS_FAILED) 446 | { 447 | RgdUtils::PrintMessage("failed to get disassembler API table.", RgdMessageType::kError, true); 448 | ret = false; 449 | } 450 | } 451 | 452 | if (ret) 453 | { 454 | ret = RgdCodeObjDbInitializeComgrHandles(this); 455 | 456 | for (RgdCodeObjectEntry& entry : entries_) 457 | { 458 | RgdCodeObjDbInitCodeObjEntry(&entry); 459 | } 460 | } 461 | is_code_obj_db_built_ = ret; 462 | } 463 | 464 | return ret; 465 | } 466 | 467 | bool RgdCodeObjDbCreateIsaContextAmdGpuDis(RgdCodeObjectEntry* code_obj_entry) 468 | { 469 | bool ret = false; 470 | assert(code_obj_entry != nullptr); 471 | if (code_obj_entry != nullptr) 472 | { 473 | AmdGpuDisContext context; 474 | AmdGpuDisStatus status = AMD_GPU_DIS_STATUS_FAILED; 475 | 476 | if (nullptr != rgd_disassembler_api_table.AmdGpuDisCreateContext) 477 | { 478 | status = rgd_disassembler_api_table.AmdGpuDisCreateContext(&context); 479 | if (status == AMD_GPU_DIS_STATUS_SUCCESS) 480 | { 481 | status = rgd_disassembler_api_table.AmdGpuDisLoadCodeObjectBuffer( 482 | context, (const char*)code_obj_entry->code_object_payload_.data(), code_obj_entry->code_obj_size_in_bytes_, false); 483 | if (status == AMD_GPU_DIS_STATUS_SUCCESS) 484 | { 485 | code_obj_entry->amd_gpu_dis_context_ = context; 486 | ret = true; 487 | } 488 | else 489 | { 490 | RgdUtils::PrintMessage("failed to load code object buffer.", RgdMessageType::kError, true); 491 | } 492 | } 493 | else 494 | { 495 | RgdUtils::PrintMessage("failed to create disassembler context.", RgdMessageType::kError, true); 496 | } 497 | } 498 | else 499 | { 500 | RgdUtils::PrintMessage("disassembler API table is not initialized.", RgdMessageType::kError, true); 501 | } 502 | } 503 | return ret; 504 | } 505 | -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_code_object_database.h: -------------------------------------------------------------------------------- 1 | //============================================================================================ 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools 4 | /// @file 5 | /// @brief 6 | //============================================================================================ 7 | 8 | #ifndef RGD_CODE_OBJECT_DATABASE_H_ 9 | #define RGD_CODE_OBJECT_DATABASE_H_ 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include "rgd_hash.h" 18 | #include "rgd_data_types.h" 19 | #include "rgd_code_object_comgr_handle.h" 20 | 21 | // Holds information about individual shader in a code object disassembly. 22 | struct RgdShaderInfo 23 | { 24 | // Crashing shader sequence number. 25 | uint64_t crashing_shader_id = 0; 26 | 27 | // 128 bit hash lower bits. 28 | uint64_t api_shader_hash_lo = 0; 29 | 30 | // 128 bit hash higher bits. 31 | uint64_t api_shader_hash_hi = 0; 32 | 33 | // Start offset address for the shader. 34 | uint64_t symbol_size = 0; 35 | 36 | // API Stage - Shader type from amdt::ShaderInfoType. 37 | std::string api_stage; 38 | 39 | // Hardware stage from amdt::HwStageType. 40 | std::string hw_stage; 41 | 42 | // Symbol name. 43 | std::string entry_point_symbol_name; 44 | 45 | // Alphanumeric shader info id. 46 | std::string str_shader_info_id; 47 | 48 | // Disassembled instructions block for the shader (used for text output - post processed later for adding annotations for instructions pointed by the wave PCs). 49 | std::vector> instructions; 50 | 51 | // Disassembled instructions block for the shader (used for the JSON output - no post processing required). 52 | std::vector> instructions_json_output; 53 | 54 | // Is this a crashing shader. 55 | bool is_in_flight_shader = false; 56 | }; 57 | 58 | class RgdCodeObjectEntry 59 | { 60 | public: 61 | RgdCodeObjectEntry() 62 | : code_obj_size_in_bytes_(0) 63 | , api_pso_hash_(0) 64 | , code_object_payload_({}) 65 | , internal_pipeline_hash_({}) 66 | , symbol_info_({}) 67 | , pipeline_data_({}) 68 | , comgr_handle_(nullptr) 69 | , amd_gpu_dis_context_({}) 70 | { 71 | } 72 | 73 | ~RgdCodeObjectEntry() 74 | { 75 | } 76 | 77 | RgdCodeObjectEntry(RgdCodeObjectEntry&& entry) = default; 78 | 79 | RgdCodeObjectEntry& operator=(RgdCodeObjectEntry&& entry) 80 | { 81 | if (this != &entry) 82 | { 83 | code_obj_size_in_bytes_ = entry.code_obj_size_in_bytes_; 84 | api_pso_hash_ = entry.api_pso_hash_; 85 | internal_pipeline_hash_ = entry.internal_pipeline_hash_; 86 | symbol_info_ = entry.symbol_info_; 87 | pipeline_data_ = entry.pipeline_data_; 88 | comgr_handle_ = std::move(entry.comgr_handle_); 89 | amd_gpu_dis_context_ = entry.amd_gpu_dis_context_; 90 | entry.code_obj_size_in_bytes_ = 0; 91 | entry.api_pso_hash_ = 0; 92 | entry.internal_pipeline_hash_ = {}; 93 | entry.symbol_info_ = {}; 94 | entry.pipeline_data_ = {}; 95 | entry.comgr_handle_ = nullptr; 96 | entry.amd_gpu_dis_context_ = {}; 97 | } 98 | return *this; 99 | } 100 | 101 | // Size of the code object in bytes. 102 | uint64_t code_obj_size_in_bytes_ = 0; 103 | 104 | // API PSO Hash. 105 | uint64_t api_pso_hash_ = 0; 106 | 107 | // A hash of the Code object binary to correlate the loader entry with the CODE_OBJECT_DATABASE entry it refers to. 108 | Rgd128bitHash internal_pipeline_hash_; 109 | 110 | // Code object binary payload. 111 | std::vector code_object_payload_; 112 | 113 | // Symbol information. 114 | amdt::CodeObjSymbolInfo symbol_info_; 115 | 116 | // Pipeline metadata. 117 | amdt::PalPipelineData pipeline_data_; 118 | 119 | // COMGR handle. 120 | RgdComgrHandle comgr_handle_; 121 | 122 | // Current ISA context handle. 123 | AmdGpuDisContext amd_gpu_dis_context_; 124 | 125 | // Map of the program counters offset and the count of waves that have the same program counter offset. 126 | std::map pc_offset_to_hung_wave_count_map_; 127 | 128 | // Map of the hardware stage and the corresponding shader information. 129 | std::map hw_stage_to_shader_info_map_; 130 | 131 | // Disassembly string for the code object. 132 | std::string disassembly_; 133 | }; 134 | 135 | /// @brief Stores information about the crashing code objects. 136 | class RgdCodeObjectDatabase 137 | { 138 | public: 139 | /// @brief Constructor. 140 | RgdCodeObjectDatabase() = default; 141 | 142 | /// @brief Destructor. 143 | ~RgdCodeObjectDatabase() = default; 144 | 145 | /// @brief Add a code object to the database. 146 | /// This method can only be called on a code object DB before Populate is called. 147 | bool AddCodeObject(uint64_t pc_instruction_offset, uint64_t api_pso_hash, size_t pc_wave_count, Rgd128bitHash internal_pipeline_hash, std::vector&& code_object_payload); 148 | 149 | /// @brief Fill in the code object based on the buffer that is assigned to it previously. 150 | bool Populate(); 151 | 152 | // vector to hold the RGD crashing code object entries. 153 | std::vector entries_ = {}; 154 | std::map internal_pipeline_hash_to_entry_map_ = {}; 155 | bool is_code_obj_db_built_ = false; 156 | }; 157 | 158 | bool RgdCodeObjDbCreateIsaContextAmdGpuDis(RgdCodeObjectEntry* code_obj_entry); 159 | 160 | #endif // RGD_CODE_OBJECT_DATABASE_H_ -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_crash_info_registers_parser.h: -------------------------------------------------------------------------------- 1 | //============================================================================================ 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools 4 | /// @file 5 | /// @brief The interface class for parsing crash info registers data. 6 | //============================================================================================ 7 | 8 | #ifndef RGD_CRASH_INFO_REGISTERS_PARSER_H_ 9 | #define RGD_CRASH_INFO_REGISTERS_PARSER_H_ 10 | 11 | #include "rgd_data_types.h" 12 | #include "rgd_register_parsing_utils.h" 13 | 14 | class ICrashInfoRegistersParser 15 | { 16 | public: 17 | /// @brief Destructor. 18 | virtual ~ICrashInfoRegistersParser() = default; 19 | virtual bool ParseWaveInfoRegisters(const CrashData& kmd_crash_data, std::unordered_map& wave_info_registers) = 0; 20 | }; 21 | 22 | #endif // RGD_CRASH_INFO_REGISTERS_PARSER_H_ -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_crash_info_registers_parser_context.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================================ 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools 4 | /// @file 5 | /// @brief The crash info registers context class. 6 | //============================================================================================ 7 | 8 | #include "rgd_crash_info_registers_parser_context.h" 9 | 10 | CrashInfoRegistersParserContext::CrashInfoRegistersParserContext(std::unique_ptr crash_info_registers_parser) 11 | : crash_info_registers_parser_(std::move(crash_info_registers_parser)) 12 | {} 13 | 14 | bool CrashInfoRegistersParserContext::ParseWaveInfoRegisters(const CrashData& kmd_crash_data, std::unordered_map& wave_info_registers_map) 15 | { 16 | return crash_info_registers_parser_->ParseWaveInfoRegisters(kmd_crash_data, wave_info_registers_map); 17 | } -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_crash_info_registers_parser_context.h: -------------------------------------------------------------------------------- 1 | //============================================================================================ 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools 4 | /// @file 5 | /// @brief The crash info registers context class. 6 | //============================================================================================ 7 | 8 | #ifndef RGD_CRASH_INFO_REGISTERS_PARSER_CONTEXT_H_ 9 | #define RGD_CRASH_INFO_REGISTERS_PARSER_CONTEXT_H_ 10 | 11 | #include "rgd_crash_info_registers_parser.h" 12 | #include "rgd_data_types.h" 13 | #include 14 | 15 | class CrashInfoRegistersParserContext 16 | { 17 | public: 18 | explicit CrashInfoRegistersParserContext(std::unique_ptr crash_info_registers_parser); 19 | 20 | bool ParseWaveInfoRegisters(const CrashData& kmd_crash_data, std::unordered_map& wave_info_registers_map); 21 | 22 | private: 23 | std::unique_ptr crash_info_registers_parser_; 24 | }; 25 | 26 | #endif // RGD_CRASH_INFO_REGISTERS_PARSER_CONTEXT_H_ -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_crash_info_registers_parser_rdna2.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================================ 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools 4 | /// @file 5 | /// @brief The crash info registers parser for RDNA 2. 6 | //============================================================================================ 7 | 8 | #include "rgd_crash_info_registers_parser_rdna2.h" 9 | #include "rgd_register_parsing_utils.h" 10 | 11 | bool CrashInfoRegistersParserRdna2::ParseWaveInfoRegisters(const CrashData& kmd_crash_data, std::unordered_map& wave_info_registers_map) 12 | { 13 | // Parse wave info registers events. 14 | bool ret = RegisterParsingUtils::ParseWaveInfoRegisters(kmd_crash_data, wave_info_registers_map); 15 | 16 | return ret; 17 | } -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_crash_info_registers_parser_rdna2.h: -------------------------------------------------------------------------------- 1 | //============================================================================================ 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools 4 | /// @file 5 | /// @brief The crash info registers parser for RDNA 2. 6 | //============================================================================================ 7 | 8 | #ifndef RGD_CRASH_INFO_REGISTERS_PARSER_RDNA2_H_ 9 | #define RGD_CRASH_INFO_REGISTERS_PARSER_RDNA2_H_ 10 | 11 | #include "rgd_crash_info_registers_parser.h" 12 | 13 | class CrashInfoRegistersParserRdna2 : public ICrashInfoRegistersParser 14 | { 15 | public: 16 | /// @brief Destructor. 17 | virtual ~CrashInfoRegistersParserRdna2() = default; 18 | 19 | /// @brief Parse wave info registers. 20 | /// @param [in] kmd_crash_data The crash data. 21 | /// @param [out] wave_info_registers_map The wave info registers. 22 | /// @return True if the wave info registers are parsed successfully. 23 | bool ParseWaveInfoRegisters(const CrashData& kmd_crash_data, std::unordered_map& wave_info_registers_map) override; 24 | }; 25 | 26 | #endif // RGD_CRASH_INFO_REGISTER_PARSER_RDNA2_H_ -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_crash_info_registers_parser_rdna3.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================================ 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools 4 | /// @file 5 | /// @brief The crash info registers parser for RDNA 3. 6 | //============================================================================================ 7 | 8 | #include "rgd_crash_info_registers_parser_rdna3.h" 9 | #include "rgd_register_parsing_utils.h" 10 | 11 | bool CrashInfoRegistersParserRdna3::ParseWaveInfoRegisters(const CrashData& kmd_crash_data, std::unordered_map& wave_info_registers_map) 12 | { 13 | // Parse wave info registers events. 14 | return RegisterParsingUtils::ParseWaveInfoRegisters(kmd_crash_data, wave_info_registers_map); 15 | ; 16 | } -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_crash_info_registers_parser_rdna3.h: -------------------------------------------------------------------------------- 1 | //============================================================================================ 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools 4 | /// @file 5 | /// @brief The crash info registers data - navi31. 6 | //============================================================================================ 7 | 8 | #ifndef RGD_CRASH_INFO_REGISTERS_PARSER_RDNA3_H_ 9 | #define RGD_CRASH_INFO_REGISTERS_PARSER_RDNA3_H_ 10 | 11 | #include "rgd_crash_info_registers_parser.h" 12 | 13 | class CrashInfoRegistersParserRdna3 : public ICrashInfoRegistersParser 14 | { 15 | public: 16 | /// @brief Destructor. 17 | virtual ~CrashInfoRegistersParserRdna3() = default; 18 | 19 | /// @brief Parse wave info registers. 20 | /// @param [in] kmd_crash_data The crash data. 21 | /// @param [out] wave_info_registers_map The wave info registers. 22 | /// @return True if the wave info registers are parsed successfully. 23 | bool ParseWaveInfoRegisters(const CrashData& kmd_crash_data, std::unordered_map& wave_info_registers_map) override; 24 | }; 25 | 26 | #endif // RGD_CRASH_INFO_REGISTER_PARSER_RDNA3_H_ -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_crash_info_registers_parser_rdna4.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================================ 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools 4 | /// @file 5 | /// @brief The crash info registers parser for RDNA 4. 6 | //============================================================================================ 7 | 8 | #include "rgd_crash_info_registers_parser_rdna4.h" 9 | #include "rgd_register_parsing_utils.h" 10 | 11 | bool CrashInfoRegistersParserRdna4::ParseWaveInfoRegisters(const CrashData& kmd_crash_data, std::unordered_map& wave_info_registers_map) 12 | { 13 | // Parse wave info registers events for Navi4x. 14 | bool ret = !kmd_crash_data.events.empty(); 15 | wave_info_registers_map.clear(); 16 | 17 | for (uint32_t i = 0; i < kmd_crash_data.events.size(); i++) 18 | { 19 | const RgdEventOccurrence& curr_event = kmd_crash_data.events[i]; 20 | 21 | assert(curr_event.rgd_event != nullptr); 22 | if (curr_event.rgd_event != nullptr) 23 | { 24 | if (static_cast(curr_event.rgd_event->header.eventId) == KmdEventId::RgdEventWaveRegisters) 25 | { 26 | const WaveRegistersData* wave_registers = static_cast(curr_event.rgd_event); 27 | for (uint32_t j = 0; j < wave_registers->numRegisters; j++) 28 | { 29 | switch ((WaveRegistersRdna4)wave_registers->registerInfos[j].offset) 30 | { 31 | case WaveRegistersRdna4::kSqWaveActive: 32 | wave_info_registers_map[wave_registers->shaderId].sq_wave_active = wave_registers->registerInfos[j].data; 33 | break; 34 | case WaveRegistersRdna4::kSqWaveExecHi: 35 | wave_info_registers_map[wave_registers->shaderId].sq_wave_exec_hi = wave_registers->registerInfos[j].data; 36 | break; 37 | case WaveRegistersRdna4::kSqWaveExecLo: 38 | wave_info_registers_map[wave_registers->shaderId].sq_wave_exec_lo = wave_registers->registerInfos[j].data; 39 | break; 40 | case WaveRegistersRdna4::kSqWaveHwId1: 41 | wave_info_registers_map[wave_registers->shaderId].sq_wave_hw_id1 = wave_registers->registerInfos[j].data; 42 | break; 43 | case WaveRegistersRdna4::kSqWaveHwId2: 44 | wave_info_registers_map[wave_registers->shaderId].sq_wave_hw_id2 = wave_registers->registerInfos[j].data; 45 | break; 46 | case WaveRegistersRdna4::kSqWaveIbSts: 47 | wave_info_registers_map[wave_registers->shaderId].sq_wave_ib_sts = wave_registers->registerInfos[j].data; 48 | break; 49 | case WaveRegistersRdna4::kSqWaveIbSts2: 50 | wave_info_registers_map[wave_registers->shaderId].sq_wave_ib_sts2 = wave_registers->registerInfos[j].data; 51 | break; 52 | case WaveRegistersRdna4::kSqWavePcHi: 53 | wave_info_registers_map[wave_registers->shaderId].sq_wave_pc_hi = wave_registers->registerInfos[j].data; 54 | break; 55 | case WaveRegistersRdna4::kSqWavePcLo: 56 | wave_info_registers_map[wave_registers->shaderId].sq_wave_pc_lo = wave_registers->registerInfos[j].data; 57 | break; 58 | case WaveRegistersRdna4::kSqWaveStatus: 59 | wave_info_registers_map[wave_registers->shaderId].sq_wave_status = wave_registers->registerInfos[j].data; 60 | break; 61 | case WaveRegistersRdna4::kSqWaveValidAndIdle: 62 | wave_info_registers_map[wave_registers->shaderId].sq_wave_valid_and_idle = wave_registers->registerInfos[j].data; 63 | break; 64 | case WaveRegistersRdna4::kSqWaveStatePriv: 65 | wave_info_registers_map[wave_registers->shaderId].sq_wave_state_priv = wave_registers->registerInfos[j].data; 66 | break; 67 | case WaveRegistersRdna4::kSqWaveExcpFlagPriv: 68 | wave_info_registers_map[wave_registers->shaderId].sq_wave_excp_flag_priv = wave_registers->registerInfos[j].data; 69 | break; 70 | case WaveRegistersRdna4::kSqWaveExcpFlagUser: 71 | wave_info_registers_map[wave_registers->shaderId].sq_wave_excp_flag_user = wave_registers->registerInfos[j].data; 72 | break; 73 | 74 | default: 75 | // Should not reach here. 76 | assert(false); 77 | } 78 | } 79 | } 80 | } 81 | } 82 | 83 | if (ret) 84 | { 85 | ret = !wave_info_registers_map.empty(); 86 | } 87 | 88 | return ret; 89 | } -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_crash_info_registers_parser_rdna4.h: -------------------------------------------------------------------------------- 1 | //============================================================================================ 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools 4 | /// @file 5 | /// @brief The crash info registers data - navi4x. 6 | //============================================================================================ 7 | 8 | #ifndef RGD_CRASH_INFO_REGISTERS_PARSER_RDNA4_H_ 9 | #define RGD_CRASH_INFO_REGISTERS_PARSER_RDNA4_H_ 10 | 11 | #include "rgd_crash_info_registers_parser.h" 12 | 13 | class CrashInfoRegistersParserRdna4 : public ICrashInfoRegistersParser 14 | { 15 | public: 16 | /// @brief Destructor. 17 | virtual ~CrashInfoRegistersParserRdna4() = default; 18 | 19 | /// @brief Parse wave info registers. 20 | /// @param [in] kmd_crash_data The crash data. 21 | /// @param [out] wave_info_registers_map The wave info registers. 22 | /// @return True if the wave info registers are parsed successfully. 23 | bool ParseWaveInfoRegisters(const CrashData& kmd_crash_data, std::unordered_map& wave_info_registers_map) override; 24 | }; 25 | 26 | #endif // RGD_CRASH_INFO_REGISTERS_PARSER_RDNA4_H_ -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_data_types.h: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief global data types. 6 | //============================================================================= 7 | #ifndef RADEON_GPU_DETECTIVE_SOURCE_RGD_DATA_TYPES_H_ 8 | #define RADEON_GPU_DETECTIVE_SOURCE_RGD_DATA_TYPES_H_ 9 | 10 | // C++. 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | // JSON. 18 | #include "json/single_include/nlohmann/json.hpp" 19 | 20 | // RDF. 21 | #include "rdf/rdf/inc/amdrdf.h" 22 | 23 | // Dev driver. 24 | #include "dev_driver/include/rgdevents.h" 25 | 26 | // System info. 27 | #include "system_info_utils/source/system_info_reader.h" 28 | 29 | // Local. 30 | #include "rgd_asic_info.h" 31 | 32 | // Marker value is in bits [0:27] while marker source is in bits [28:31]. 33 | static const uint32_t kMarkerValueMask = 0x0FFFFFFF; 34 | static const uint32_t kMarkerSrcMask = 0xF0000000; 35 | static const uint32_t kMarkerSrcBitLen = 4; 36 | static const uint32_t kUint32Bits = 32; 37 | 38 | // Reserved virtual address. Used when option 'all-resources' is specified. 39 | static const uint64_t kVaReserved = 0x0; 40 | 41 | // Special virtual address constants. 42 | static const uint64_t kVaDeadBeef = 0xbeefde000000; 43 | 44 | // Output json element string name for offending va information. 45 | static const char* kJsonElemPageFaultSummary = "page_fault_summary"; 46 | 47 | // String not available. 48 | static const char* kStrNotAvailable = "N/A"; 49 | static const char* kStrUnknown = "Unknown"; 50 | 51 | // Heap type strings. 52 | static const char* kStrHeapTypeLocal = "Local (GPU memory, CPU-visible)"; 53 | static const char* kStrHeapTypeInvisible = "Invisible (GPU memory, invisible to CPU)"; 54 | static const char* kStrHeapTypeHost = "Host (CPU memory)"; 55 | 56 | // Driver Marker strings. 57 | static const char* kStrDraw = "Draw"; 58 | static const char* kStrDispatch = "Dispatch"; 59 | 60 | // Marker strings for Barriers. 61 | static const char* kBarrierStandard = "Barrier"; 62 | static const char* kBarrierRelease = "Release"; 63 | static const char* kBarrierAcquire = "Acquire"; 64 | static const char* kBarrierReleaseEvent = "ReleaseEvent"; 65 | static const char* kBarrierAcquireEvent = "AcquireEvent"; 66 | static const char* kBarrierReleaseThenAcquire = "ReleaseThenAcquire"; 67 | static const std::unordered_set kBarrierMarkerStrings = { kBarrierStandard, kBarrierRelease, kBarrierAcquire, kBarrierReleaseEvent,kBarrierAcquireEvent, kBarrierReleaseThenAcquire}; 68 | 69 | static const char* kChunkIdTraceProcessInfo = "TraceProcessInfo"; 70 | static const uint32_t kChunkMaxSupportedVersionTraceProcessInfo = 1; 71 | 72 | static const char* kChunkIdDriverOverrides = "DriverOverrides"; 73 | 74 | // DriverOverrides chunk version constants. 75 | static const uint32_t kChunkMaxSupportedVersionDriverOverrides = 3; 76 | 77 | static const char* kChunkIdCodeObject = "CodeObject"; 78 | static const uint32_t kChunkMaxSupportedVersionCodeObject = 2; 79 | 80 | static const char* kChunkIdCOLoadEvent = "COLoadEvent"; 81 | static const uint32_t kChunkMaxSupportedVersionCOLoadEvent = 3; 82 | 83 | static const char* kChunkIdPsoCorrelation = "PsoCorrelation"; 84 | static const uint32_t kChunkMaxSupportedVersionPsoCorrelation = 3; 85 | 86 | // DriverOverrides chunk JSON element name constants. 87 | static const char* kJsonElemComponentsDriverOverridesChunk = "Components"; 88 | static const char* kJsonElemComponentDriverOverridesChunk = "Component"; 89 | static const char* kJsonElemStructuresDriverOverridesChunk = "Structures"; 90 | static const char* kJsonElemExperimentsDriverOverridesChunk = "Experiments"; 91 | static const char* kJsonElemSettingNameDriverOverridesChunk = "SettingName"; 92 | static const char* kJsonElemUserOverrideDriverOverridesChunk = "UserOverride"; 93 | static const char* kJsonElemWasSupportedDriverOverridesChunk = "Supported"; 94 | static const char* kJsonElemCurrentDriverOverridesChunk = "Current"; 95 | static const char* kJsonElemIsDriverExperimentsDriverOverridesChunk = "IsDriverExperiments"; 96 | static const char* kErrorMsgInvalidDriverOverridesJson = "invalid DriverOverrides JSON"; 97 | static const char* kErrorMsgFailedToParseDriverExperimentsInfo = "failed to parse Driver Experiments info"; 98 | 99 | // Enhanced Crash Info JSON element name constants. 100 | static const char* kJsonElemShaders = "shaders"; 101 | static const char* kJsonElemShaderInfo = "shader_info"; 102 | static const char* kJsonElemShaderInfoId = "shader_info_id"; 103 | static const char* kJsonElemApiPsoHash = "api_pso_hash"; 104 | static const char* kJsonElemApiShaderHashHi = "api_shader_hash_hi"; 105 | static const char* kJsonElemApiShaderHashLo = "api_shader_hash_lo"; 106 | static const char* kJsonElemApiStage = "api_stage"; 107 | static const char* kJsonElemDisassembly = "disassembly"; 108 | static const char* kJsonElemInstructionOffset = "instruction_offset"; 109 | static const char* kJsonElemInstr = "instr"; 110 | static const char* kJsonElemInstructionsDisassembly = "instructions_disassembly"; 111 | static const char* kJsonElemWaveCount = "wave_count"; 112 | static const char* kJsonElemInstructionsHidden = "instructions_hidden"; 113 | 114 | // ID prefixes 115 | static const char* kStrPrefixShaderInfoId = "ShaderInfoID"; 116 | static const char* kStrPrefixCodeObjectId = "CodeObjectID"; 117 | 118 | // Represents the execution status of an execution marker. 119 | // A marker can be in a one of 3 states: 120 | // 1. Hasn't started executing 121 | // 2. In progress 122 | // 3. Finished 123 | enum class MarkerExecutionStatus 124 | { 125 | kNotStarted, 126 | kInProgress, 127 | kFinished 128 | }; 129 | 130 | // Configuration dictated by the user's command line arguments. 131 | struct Config 132 | { 133 | // Full path to the crash dump input file. 134 | std::string crash_dump_file; 135 | 136 | // Full path to the analysis output text file. 137 | std::string output_file_txt; 138 | 139 | // Full path to the analysis output json file. 140 | std::string output_file_json; 141 | 142 | // True for higher level of details for console output. 143 | bool is_verbose = false; 144 | 145 | // Serialize all the resources from the input crash dump file. 146 | bool is_all_resources = false; 147 | 148 | // Include timeline of the memory event for the virtual address. 149 | bool is_va_timeline = false; 150 | 151 | // Include raw Umd and Kmd crash data in the output. 152 | bool is_raw_event_data = false; 153 | 154 | // Include marker source information in execution marker tree visualization. 155 | bool is_marker_src = false; 156 | 157 | // Expand all marker nodes in the execution marker tree visualization. 158 | bool is_expand_markers = false; 159 | 160 | // Print raw timestamp in the text output. 161 | bool is_raw_time = false; 162 | 163 | // Output compact JSON. 164 | bool is_compact_json = false; 165 | 166 | // Print additional system information. 167 | bool is_extended_sysinfo = false; 168 | 169 | // Include implicit resources in summary output. 170 | bool is_include_implicit_resources = false; 171 | 172 | // Include internal barriers in Execution Marker Tree. Internal barriers are filtered out by default. 173 | bool is_include_internal_barriers = false; 174 | 175 | // Include full code object disassembly. 176 | bool is_all_disassembly = false; 177 | }; 178 | 179 | // Stores time information about the crash analysis session. 180 | struct CrashAnalysisTimeInfo 181 | { 182 | // Base time: initial timestamp where analysis started. 183 | uint64_t start_time = 0; 184 | 185 | // Frequency of timestamps in chunk. 186 | uint64_t frequency = 0; 187 | }; 188 | 189 | // An occurrence of an RGD event. 190 | struct RgdEventOccurrence 191 | { 192 | RgdEventOccurrence(RgdEvent* event, uint64_t event_timing) : 193 | rgd_event(event), event_time(event_timing){} 194 | 195 | // The event itself. 196 | RgdEvent* rgd_event = nullptr; 197 | 198 | // The time when the event happened. 199 | uint64_t event_time = 0; 200 | }; 201 | 202 | // Stores the crash data which was read from the crash dump file's UmdCrashData chunk. 203 | struct CrashData 204 | { 205 | // The header of the first chunk that was used to encode the crash data. 206 | // This header can be used to retrieve the base time information for the crash data events. 207 | DDEventProviderHeader chunk_header; 208 | 209 | // Crash data events. 210 | // We store all events by value and access them during execution using their 211 | // indices in order to optimize runtime performance. Indices are used instead 212 | // of pointers, to avoid invalidated pointers in case that the underlying 213 | // std::vector storage is relocated by the runtime. 214 | std::vector events; 215 | 216 | // The payload where the raw event data is stored. 217 | std::vector chunk_payload; 218 | 219 | // Time information about the crash analysis session. 220 | CrashAnalysisTimeInfo time_info; 221 | }; 222 | 223 | // Holds the execution status of a marker: information on if the marker started and finished execution. 224 | struct MarkerExecutionStatusFlags 225 | { 226 | // True if the marker started execution. 227 | bool is_started = false; 228 | 229 | // True if the marker finished execution. 230 | bool is_finished = false; 231 | }; 232 | 233 | // Holds the code object chunk info. 234 | struct CodeObject 235 | { 236 | RgdCodeObjectHeader chunk_header; 237 | 238 | // The payload where the code object binary blob data is stored. 239 | std::vector chunk_payload; 240 | }; 241 | 242 | // Holds the parsed contents of a crash dump RDF file. 243 | // For now RMT is not included as it is being parsed separately through a dedicated API. 244 | struct RgdCrashDumpContents 245 | { 246 | system_info_utils::SystemInfo system_info; 247 | ecitrace::GpuSeries gpu_series{0}; 248 | TraceChunkApiInfo api_info; 249 | CrashData umd_crash_data; 250 | CrashData kmd_crash_data; 251 | TraceProcessInfo crashing_app_process_info; 252 | // Mapping between command buffer ID and the indices for umd_crash_data.events array of its relevant execution marker events. 253 | std::unordered_map> cmd_buffer_mapping; 254 | 255 | // Driver Experiments JSON 256 | nlohmann::json driver_experiments_json; 257 | 258 | // CodeObject Database. 259 | std::map code_objects_map; 260 | 261 | // CodeObject Loader Events. 262 | std::vector code_object_load_events; 263 | 264 | // PSO Correlations. 265 | std::vector pso_correlations; 266 | }; 267 | 268 | // Holds the information about the crashing shader for correlation with the execution markers nodes. 269 | struct RgdCrashingShaderInfo 270 | { 271 | std::vector crashing_shader_ids; 272 | std::vector api_stages; 273 | }; 274 | 275 | struct WaveInfoRegisters 276 | { 277 | uint32_t sq_wave_status{0}; 278 | uint32_t sq_wave_pc_hi{0}; 279 | uint32_t sq_wave_pc_lo{0}; 280 | 281 | //sq_wave_trapsts is available only for RDNA2 and RDNA3. 282 | uint32_t sq_wave_trapsts{0}; 283 | uint32_t sq_wave_ib_sts{0}; 284 | uint32_t sq_wave_ib_sts2{0}; 285 | uint32_t sq_wave_active{0}; 286 | uint32_t sq_wave_exec_hi{0}; 287 | uint32_t sq_wave_exec_lo{0}; 288 | uint32_t sq_wave_hw_id1{0}; 289 | uint32_t sq_wave_hw_id2{0}; 290 | uint32_t sq_wave_valid_and_idle{0}; 291 | 292 | // RDNA4 specific registers. 293 | uint32_t sq_wave_state_priv{0}; 294 | uint32_t sq_wave_excp_flag_priv{0}; 295 | uint32_t sq_wave_excp_flag_user{0}; 296 | }; 297 | 298 | #endif // RADEON_GPU_DETECTIVE_SOURCE_RGD_DATA_TYPES_H_ 299 | -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_enhanced_crash_info_serializer.h: -------------------------------------------------------------------------------- 1 | //============================================================================================ 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools 4 | /// @file 5 | /// @brief serializer for enhanced crash information. 6 | //============================================================================================ 7 | 8 | #ifndef RGD_ENHANCED_CRASH_INFO_SERIALIZER_H_ 9 | #define RGD_ENHANCED_CRASH_INFO_SERIALIZER_H_ 10 | 11 | // C++. 12 | #include 13 | 14 | // Local. 15 | #include "rgd_data_types.h" 16 | 17 | static constexpr uint64_t kAddressHighWordOne = 0x0000000100000000; 18 | 19 | class RgdEnhancedCrashInfoSerializer 20 | { 21 | public: 22 | /// @brief Constructor. 23 | RgdEnhancedCrashInfoSerializer(); 24 | 25 | /// @brief Destructor. 26 | ~RgdEnhancedCrashInfoSerializer(); 27 | 28 | /// @brief Initialize the enhanced crash info serializer. 29 | bool Initialize(RgdCrashDumpContents& rgd_crash_dump_contents, bool is_page_fault); 30 | 31 | /// @brief Serialize the code object information and get in-flight shader info. 32 | bool GetInFlightShaderInfo(const Config& user_config, std::string& out_text); 33 | 34 | /// @brief Serialize the enhanced crash information in JSON format. 35 | bool GetInFlightShaderInfoJson(const Config& user_config, nlohmann::json& out_json); 36 | 37 | /// @brief Get the set of API PSO hashes for the shaders that were in flight at the time of the crash. 38 | bool GetInFlightShaderApiPsoHashes(std::unordered_map& in_flight_shader_api_pso_hashes_to_shader_info_); 39 | 40 | /// @brief Get the complete disassembly of the shaders that were in flight at the time of the crash. 41 | bool GetCompleteDisassembly(const Config& user_config, std::string& out_text); 42 | 43 | private: 44 | class Impl; 45 | std::unique_ptr enhanced_crash_info_serializer_impl_; 46 | }; 47 | 48 | #endif // RGD_ENHANCED_CRASH_INFO_SERIALIZER_H_ -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_exec_marker_tree_serializer.h: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief execution marker tree serialization. 6 | //============================================================================= 7 | #ifndef RADEON_GPU_DETECTIVE_EXEC_MARKER_TREE_SERIALIZER_H_ 8 | #define RADEON_GPU_DETECTIVE_EXEC_MARKER_TREE_SERIALIZER_H_ 9 | 10 | // C++. 11 | #include 12 | #include 13 | 14 | // Dev driver. 15 | #include "dev_driver/include/rgdevents.h" 16 | 17 | // Local. 18 | #include "rgd_data_types.h" 19 | 20 | // JSON. 21 | #include "json/single_include/nlohmann/json.hpp" 22 | 23 | // Node in the execution marker tree. 24 | struct MarkerNode 25 | { 26 | MarkerNode(uint64_t begin_timestamp, uint32_t value, uint64_t api_pso_hash, bool is_shader_in_flight, const std::string& str) 27 | : timestamp_begin_(begin_timestamp) 28 | , marker_str(str) 29 | , marker_value(value) 30 | , api_pso_hash(api_pso_hash) 31 | , is_shader_in_flight(is_shader_in_flight) 32 | , marker_info{} 33 | { 34 | } 35 | uint64_t timestamp_begin_ = 0; 36 | uint64_t timestamp_end_ = 0; 37 | 38 | // Pipeline bind API PSO hash. 39 | uint64_t api_pso_hash = 0; 40 | 41 | // User string. 42 | std::string marker_str; 43 | 44 | // Marker value. 45 | uint32_t marker_value = 0; 46 | 47 | // Execution status. 48 | MarkerExecutionStatus exec_status = MarkerExecutionStatus::kNotStarted; 49 | 50 | /// Used as a buffer to host additional structural data for DrawInfo, DispatchInfo, BarrierBeginInfo and BarrierEndInfo. It should start with ExecutionMarkerInfoHeader followed 51 | /// by a data structure that ExecutionMarkerInfoHeader.infoType dictates. All the structures are tightly packed 52 | /// (no paddings). 53 | uint8_t marker_info[MarkerInfoBufferSize] = { 0 }; 54 | 55 | // Child markers (markers that started after this marker began and before it ended). 56 | std::vector child_markers; 57 | 58 | // Counter to store no of consecutive nodes with same status on its level. 59 | uint64_t repeating_same_status_count = 0; 60 | 61 | // The count of consecutive identical nodes. Nodes are considered identical if they have the same status, same parent node and their marker string value is same. 62 | uint64_t consecutive_identical_nodes_count = 0; 63 | 64 | // For more than one consecutive identical nodes, Marker Summary List in text output includes path once for this node appended with repeat count. 65 | // This will be set to false for all identical occurrences of the nodes after the first node (nodes 2 to n) and the nodes 2 to n are excluded from the marker summary list in text output. 66 | bool is_include_node_in_text_summary_list = true; 67 | 68 | // Set to true if this marker is associated with a crashing shader. 69 | bool is_shader_in_flight = false; 70 | 71 | // Crashing shader information for this marker. Updated only when the marker is associated with a crashing shader. 72 | RgdCrashingShaderInfo crashing_shader_info; 73 | }; 74 | 75 | // Builds a tree representation of the execution markers for a single command buffer. 76 | class ExecMarkerTreeSerializer 77 | { 78 | public: 79 | ExecMarkerTreeSerializer(const Config& user_config, const std::unordered_map& cmd_buffer_exec_buffer, 80 | uint64_t kmd_crash_value_begin, uint64_t kmd_crash_value_end) : 81 | cmd_buffer_exec_status_{ cmd_buffer_exec_buffer }, 82 | kmd_crash_value_begin_{ kmd_crash_value_begin }, 83 | kmd_crash_value_end_{ kmd_crash_value_end }, 84 | is_file_visualization_(!user_config.output_file_txt.empty()) {} 85 | 86 | // Insert a Begin marker into the tree. 87 | void PushMarkerBegin(uint64_t timestamp, 88 | uint32_t marker_value, 89 | uint64_t pipeline_api_pso_hash, 90 | bool is_shader_in_flight, 91 | const std::string& str, 92 | RgdCrashingShaderInfo& rgd_crashing_shader_info); 93 | 94 | // Update Begin marker info. 95 | void UpdateMarkerInfo(uint32_t marker_value, const uint8_t info[]); 96 | 97 | // Insert an End marker into the tree. 98 | void PushMarkerEnd(uint64_t timestamp, uint32_t marker_value); 99 | 100 | // Serialize the summary list into a string. 101 | std::string SummaryListToString() const; 102 | 103 | // Serialize the summary list into a json representation. 104 | void SummaryListToJson(nlohmann::json& summary_list_json) const; 105 | 106 | // Serialize the tree into a string. 107 | std::string TreeToString(const Config& user_config) const; 108 | 109 | // Serialize the tree into a json. 110 | void TreeToJson(const Config& user_config, nlohmann::json& marker_tree_json) const; 111 | 112 | // Build the look ahead counter of consecutive same status marker nodes. 113 | void UpdateSameStatusMarkerNodesCount(); 114 | 115 | // Validate the 'begin' execution markers for matching 'end' marker and report the missing 'end' markers. 116 | void ValidateExecutionMarkers(); 117 | 118 | private: 119 | const uint64_t kmd_crash_value_begin_ = 0; 120 | const uint64_t kmd_crash_value_end_ = 0; 121 | std::vector marker_nodes_; 122 | std::vector current_stack_; 123 | std::unordered_map cmd_buffer_exec_status_; 124 | std::string missing_markers_info_txt_; 125 | 126 | // True if the text visualization is for a file - we use special characters that 127 | // render more nicely in files, but are not rendered nicely on Windows console. 128 | bool is_file_visualization_ = false; 129 | 130 | #ifdef _DEBUG 131 | // Tracking the most recent timestamp for input validation. 132 | uint64_t last_timestamp_ = 0; 133 | void UpdateAndValidateTimestamp(uint64_t timestamp); 134 | #endif 135 | 136 | // Return the status of the given marker node. 137 | MarkerExecutionStatus GetItemStatus(const MarkerNode& node) const; 138 | 139 | // Generates a string representation of the execution marker tree. 140 | std::string TreeNodeToString(std::vector is_last_on_level, const MarkerNode& node, const Config& user_config) const; 141 | 142 | // Generates a json object for the execution marker tree node. 143 | void TreeNodeToJson(const MarkerNode& node, nlohmann::json& marker_node_json, const Config& user_config) const; 144 | 145 | // Generates a summary for markers that are in progress. 146 | std::string GenerateSummaryString(std::vector& node_stack, bool& is_atleast_one_child_in_progress) const; 147 | 148 | // Generates a json representation of a summary for markers that are in progress. 149 | void GenerateSummaryJson(std::vector& node_stack, 150 | nlohmann::json& marker_summary_json, bool& is_atleast_one_child_in_progress) const; 151 | 152 | // Build the look ahead counter of consecutive same status child marker nodes. 153 | void UpdateSameStatusMarkerNodesCountForThisNode(MarkerNode& current_node); 154 | }; 155 | 156 | #endif // RADEON_GPU_DETECTIVE_EXEC_MARKER_TREE_SERIALIZER_H_ -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_hash.h: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2018-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief A 128-bit uint used for hashes. 6 | //============================================================================= 7 | 8 | #ifndef RADEON_GPU_DETECTIVE_SOURCE_RGD_HASH_H_ 9 | #define RADEON_GPU_DETECTIVE_SOURCE_RGD_HASH_H_ 10 | 11 | #include 12 | 13 | /// @brief Struct to hold a 128 bit hash. 14 | typedef struct Rgd128bitHash 15 | { 16 | /// @brief Default constructor 17 | Rgd128bitHash() 18 | : low(0) 19 | , high(0) 20 | { 21 | } 22 | 23 | /// @brief Constructor that takes the hash. 24 | /// 25 | /// @param [in] input_low The low 64 bits of the hash. 26 | /// @param [in] input_high The high 64 bits of the hash. 27 | Rgd128bitHash(const uint64_t input_low, const uint64_t input_high) 28 | { 29 | low = input_low; 30 | high = input_high; 31 | } 32 | 33 | // The low 64 bits of the hash. 34 | uint64_t low; 35 | 36 | // The high 64 bits of the hash. 37 | uint64_t high; 38 | } Rgd128bitHash; 39 | 40 | /// @brief Compare two 128-bit hashes for equality. 41 | /// @param [in] a The first hash to compare. 42 | /// @param [in] b The second hash to compare. 43 | /// @return true if the hashes are equal. 44 | static bool Rgd128bitHashCompare(const Rgd128bitHash& a, const Rgd128bitHash& b) 45 | { 46 | return (a.low == b.low) && (a.high == b.high); 47 | } 48 | 49 | /// @brief Check if a 128-bit hash is zero. 50 | /// @param [in] a The hash to check. 51 | /// @return true if the hash is zero. 52 | static bool Rgd128bitHashIsZero(const Rgd128bitHash& a) 53 | { 54 | return (a.low == 0) && (a.high == 0); 55 | } 56 | 57 | /// @brief Copy one 128-bit hash to another. 58 | /// @param [out] dest The destination hash. 59 | /// @param [in] src The source hash. 60 | static void Rgd128bitHashCopy(Rgd128bitHash& dest, const Rgd128bitHash& src) 61 | { 62 | dest.low = src.low; 63 | dest.high = src.high; 64 | } 65 | 66 | /// @brief Overloaded operator to check if one hash is less than another hash. 67 | /// 68 | /// @param [in] a The first hash to compare. 69 | /// @param [in] b The second to compare. 70 | /// 71 | /// @return true if the first hash is less than the second hash. 72 | inline bool operator<(const Rgd128bitHash& a, const Rgd128bitHash& b) 73 | { 74 | if (a.high < b.high) 75 | { 76 | return true; 77 | } 78 | 79 | if (a.high > b.high) 80 | { 81 | return false; 82 | } 83 | 84 | // The hi bits of the hash are equal, use the low bits as a tiebreaker. 85 | return (a.low < b.low); 86 | } 87 | 88 | /// @brief Overloaded operator to check if two hashes are equal. 89 | /// 90 | /// @param [in] a The first hash to compare. 91 | /// @param [in] b The second to compare. 92 | /// 93 | /// @return true if the hashes are equal. 94 | inline bool operator==(const Rgd128bitHash& a, const Rgd128bitHash& b) 95 | { 96 | return Rgd128bitHashCompare(a, b); 97 | } 98 | 99 | /// @brief Overloaded operator to check if two hashes are not equal. 100 | /// 101 | /// @param [in] a The first hash to compare. 102 | /// @param [in] b The second to compare. 103 | /// 104 | /// @return true if the hashes are not equal. 105 | inline bool operator!=(const Rgd128bitHash& a, const Rgd128bitHash& b) 106 | { 107 | return !Rgd128bitHashCompare(a, b); 108 | } 109 | 110 | #endif // RADEON_GPU_DETECTIVE_SOURCE_RGD_HASH_H_ -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_marker_data_serializer.h: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief execution marker serialization. 6 | //============================================================================= 7 | #ifndef RADEON_GPU_DETECTIVE_MARKER_DATA_SERIALIZER_H_ 8 | #define RADEON_GPU_DETECTIVE_MARKER_DATA_SERIALIZER_H_ 9 | 10 | // Local. 11 | #include "rgd_exec_marker_tree_serializer.h" 12 | 13 | // Dev driver. 14 | #include "dev_driver/include/rgdevents.h" 15 | 16 | static const char* kJsonElemExecutionMarkerTree = "execution_marker_tree"; 17 | static const char* kJsonElemMarkersInProgress = "markers_in_progress"; 18 | static const char* kJsonElemExecutionMarkerStatusReport = "execution_marker_status_report"; 19 | static const char* kJsonElemCmdBufferIdElement = "cmd_buffer_id"; 20 | 21 | class ExecMarkerDataSerializer 22 | { 23 | public: 24 | ExecMarkerDataSerializer(std::unordered_map in_flight_shader_api_pso_hashes_to_shader_info_) 25 | : in_flight_shader_api_pso_hashes_to_shader_info_(std::move(in_flight_shader_api_pso_hashes_to_shader_info_)) 26 | { 27 | } 28 | ~ExecMarkerDataSerializer() = default; 29 | 30 | // Generate a textual tree that represents the status of the execution markers. 31 | // cmd_buffer_events maps between each command buffer ID and the indices of its execution marker events. 32 | // cmd_buffer_marker_status maps between each command buffer ID to a mapping between [marker_value --> execution status]. 33 | bool GenerateExecutionMarkerTree(const Config& user_config, const CrashData& umd_crash_data, 34 | const std::unordered_map >& cmd_buffer_events, 35 | std::string& marker_tree); 36 | 37 | // Generate a json representation of the status of the execution markers. 38 | // cmd_buffer_events maps between each command buffer ID and the indices of its execution marker events. 39 | // cmd_buffer_marker_status maps between each command buffer ID to a mapping between [marker_value --> execution status]. 40 | bool GenerateExecutionMarkerTreeToJson(const Config& user_config, const CrashData& umd_crash_data, 41 | const std::unordered_map >& cmd_buffer_events, 42 | nlohmann::json& all_cmd_buffers_marker_tree_json); 43 | 44 | // Generate a textual summary of the execution markers. 45 | bool GenerateExecutionMarkerSummaryList(const Config& user_config, const CrashData& umd_crash_data, 46 | const std::unordered_map >& cmd_buffer_events, 47 | std::string& marker_summary_list_txt); 48 | 49 | // Generate a json representation of the summary of the execution markers. 50 | bool GenerateExecutionMarkerSummaryListJson(const Config& user_config, const CrashData& umd_crash_data, 51 | const std::unordered_map >& cmd_buffer_events, 52 | nlohmann::json& all_cmd_buffers_marker_summary_json); 53 | 54 | // Returns true if any of the shaders that are associated with the pipeline that is represented by the given API PSO hash is in flight. 55 | bool IsShaderInFlight(uint64_t api_pso_hash); 56 | 57 | private: 58 | 59 | // Build command buffer marker status map. 60 | bool BuildCmdBufferMarkerStatus(const CrashData& umd_crash_data, 61 | const std::unordered_map >& cmd_buffer_events); 62 | 63 | // Build execution marker tree nodes. 64 | bool BuildCmdBufferExecutionMarkerTreeNodes(const Config& user_config, const CrashData& umd_crash_data, 65 | const std::unordered_map >& cmd_buffer_events); 66 | 67 | // Map to store command buffer id -> marker value -> marker execution status. 68 | std::unordered_map > command_buffer_marker_status_; 69 | 70 | // Map to store command buffer id -> ExecMarkerTreeSerializer mapping. 71 | std::unordered_map > command_buffer_exec_tree_; 72 | 73 | // Map to store command buffer info. 74 | std::unordered_map cmd_buffer_info_map_; 75 | 76 | // For each in-flight shader, this is a mapping between the shader's pipeline's PSO hash to the pipeline's shader information. 77 | std::unordered_map in_flight_shader_api_pso_hashes_to_shader_info_; 78 | }; 79 | 80 | #endif // RADEON_GPU_DETECTIVE_MARKER_DATA_SERIALIZER_H_ 81 | -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_parsing_utils.h: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief utilities for parsing raw data. 6 | //============================================================================= 7 | #ifndef RADEON_GPU_DETECTIVE_SOURCE_RGD_PARSING_UTILS_H_ 8 | #define RADEON_GPU_DETECTIVE_SOURCE_RGD_PARSING_UTILS_H_ 9 | 10 | // C++. 11 | #include 12 | #include 13 | #include 14 | 15 | // JSON. 16 | #include "json/single_include/nlohmann/json.hpp" 17 | 18 | // RDF. 19 | #include "rdf/rdf/inc/amdrdf.h" 20 | 21 | // Local. 22 | #include "rgd_data_types.h" 23 | 24 | class RgdParsingUtils 25 | { 26 | public: 27 | // Parses a CrashData chunk (either UMD or KMD) from the given chunk file. chunk_identifier is used to identify the chunk. 28 | static bool ParseCrashDataChunks(rdf::ChunkFile& chunk_file, const char* chunk_identifier, CrashData& umd_crash_data, CrashData& kmd_crash_data, std::string& error_msg); 29 | 30 | // Builds a mapping between the command buffer ID and the list of execution markers (begin and end) for that 31 | // command buffer ID. Execution markers will be sorted chronologically. 32 | static bool BuildCommandBufferMapping(const Config& user_config, const CrashData& umd_crash_data, 33 | std::unordered_map>& cmd_buffer_mapping); 34 | 35 | // Returns a formatted size string for the number of bytes (KB, MB etc.). 36 | static std::string GetFormattedSizeString(uint64_t size_in_bytes, const char* unit = "B"); 37 | 38 | // Returns the string representation of the Umd event type based on its ID. 39 | static std::string UmdRgdEventIdToString(uint8_t event_id); 40 | 41 | // Returns the string representation of the Kmd event type based on its ID. 42 | static std::string KmdRgdEventIdToString(uint8_t event_id); 43 | 44 | // Extracts the name of the marker's source which is packed into the upper 4 bits of the marker value. 45 | static std::string ExtractMarkerSource(uint32_t marker_value); 46 | 47 | // Parses a TraceProcessInfo chunk. 48 | static bool ParseTraceProcessInfoChunk(rdf::ChunkFile& chunk_file, const char* chunk_identifier, TraceProcessInfo& process_info); 49 | 50 | // Parse a 'DriverOverrides' chunk from the given chunk file. 51 | static bool ParseDriverOverridesChunk(rdf::ChunkFile& chunk_file, const char* chunk_identifier, nlohmann::json& driver_experiments_json); 52 | 53 | // Parse a 'CodeObject' chunk from the given chunk file. 54 | static bool ParseCodeObjectChunk(rdf::ChunkFile& chunk_file, const char* chunk_identifier, std::map& code_objects_map); 55 | 56 | // Parse a 'COLoadEvent' chunk from the given chunk file. 57 | static bool ParseCodeObjectLoadEventChunk(rdf::ChunkFile& chunk_file, 58 | const char* chunk_identifier, 59 | std::vector& code_object_loader_events); 60 | 61 | // Parse a 'PsoCorrelation' chunk from the given chunk file. 62 | static bool PsoCorrelationChunk(rdf::ChunkFile& chunk_file, const char* chunk_identifier, std::vector& pso_correlations); 63 | 64 | // Get the crash type - page fault or hang. 65 | static bool GetIsPageFault(); 66 | 67 | private: 68 | RgdParsingUtils() = delete; 69 | ~RgdParsingUtils() = delete; 70 | 71 | // Set the crash type - page fault or hang. 72 | static void SetIsPageFault(bool is_page_fault); 73 | 74 | // Is the crash type a page fault or a hang? 75 | static bool is_page_fault_; 76 | }; 77 | 78 | #endif // RADEON_GPU_DETECTIVE_SOURCE_RGD_PARSING_UTILS_H_ 79 | -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_register_parsing_utils.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================================ 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools 4 | /// @file 5 | /// @brief The crash info registers parsing utilities. 6 | //============================================================================================ 7 | 8 | #include "rgd_register_parsing_utils.h" 9 | 10 | bool RegisterParsingUtils::ParseWaveInfoRegisters(const CrashData& kmd_crash_data, std::unordered_map& wave_info_registers_map) 11 | { 12 | // Parse wave info registers events for RDNA2 and RDNA3. 13 | bool ret = !kmd_crash_data.events.empty(); 14 | wave_info_registers_map.clear(); 15 | 16 | for (uint32_t i = 0; i < kmd_crash_data.events.size(); i++) 17 | { 18 | const RgdEventOccurrence& curr_event = kmd_crash_data.events[i]; 19 | 20 | assert(curr_event.rgd_event != nullptr); 21 | if (curr_event.rgd_event != nullptr) 22 | { 23 | if (static_cast(curr_event.rgd_event->header.eventId) == KmdEventId::RgdEventWaveRegisters) 24 | { 25 | const WaveRegistersData* wave_registers = static_cast(curr_event.rgd_event); 26 | for (uint32_t j = 0; j < wave_registers->numRegisters; j++) 27 | { 28 | switch ((WaveRegistersRdna2AndRdna3)wave_registers->registerInfos[j].offset) 29 | { 30 | case WaveRegistersRdna2AndRdna3::kSqWaveActive: 31 | wave_info_registers_map[wave_registers->shaderId].sq_wave_active = wave_registers->registerInfos[j].data; 32 | break; 33 | case WaveRegistersRdna2AndRdna3::kSqWaveExecHi: 34 | wave_info_registers_map[wave_registers->shaderId].sq_wave_exec_hi = wave_registers->registerInfos[j].data; 35 | break; 36 | case WaveRegistersRdna2AndRdna3::kSqWaveExecLo: 37 | wave_info_registers_map[wave_registers->shaderId].sq_wave_exec_lo = wave_registers->registerInfos[j].data; 38 | break; 39 | case WaveRegistersRdna2AndRdna3::kSqWaveHwId1: 40 | wave_info_registers_map[wave_registers->shaderId].sq_wave_hw_id1 = wave_registers->registerInfos[j].data; 41 | break; 42 | case WaveRegistersRdna2AndRdna3::kSqWaveHwId2: 43 | wave_info_registers_map[wave_registers->shaderId].sq_wave_hw_id2 = wave_registers->registerInfos[j].data; 44 | break; 45 | case WaveRegistersRdna2AndRdna3::kSqWaveIbSts: 46 | wave_info_registers_map[wave_registers->shaderId].sq_wave_ib_sts = wave_registers->registerInfos[j].data; 47 | break; 48 | case WaveRegistersRdna2AndRdna3::kSqWaveIbSts2: 49 | wave_info_registers_map[wave_registers->shaderId].sq_wave_ib_sts2 = wave_registers->registerInfos[j].data; 50 | break; 51 | case WaveRegistersRdna2AndRdna3::kSqWavePcHi: 52 | wave_info_registers_map[wave_registers->shaderId].sq_wave_pc_hi = wave_registers->registerInfos[j].data; 53 | break; 54 | case WaveRegistersRdna2AndRdna3::kSqWavePcLo: 55 | wave_info_registers_map[wave_registers->shaderId].sq_wave_pc_lo = wave_registers->registerInfos[j].data; 56 | break; 57 | case WaveRegistersRdna2AndRdna3::kSqWaveStatus: 58 | wave_info_registers_map[wave_registers->shaderId].sq_wave_status = wave_registers->registerInfos[j].data; 59 | break; 60 | case WaveRegistersRdna2AndRdna3::kSqWaveTrapsts: 61 | wave_info_registers_map[wave_registers->shaderId].sq_wave_trapsts = wave_registers->registerInfos[j].data; 62 | break; 63 | case WaveRegistersRdna2AndRdna3::kSqWaveValidAndIdle: 64 | wave_info_registers_map[wave_registers->shaderId].sq_wave_valid_and_idle = wave_registers->registerInfos[j].data; 65 | break; 66 | default: 67 | // Should not reach here. 68 | assert(false); 69 | } 70 | } 71 | } 72 | } 73 | } 74 | 75 | if (ret) 76 | { 77 | ret = !wave_info_registers_map.empty(); 78 | } 79 | 80 | return ret; 81 | } -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_register_parsing_utils.h: -------------------------------------------------------------------------------- 1 | //============================================================================================ 2 | // Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools 4 | /// @file 5 | /// @brief The crash info registers parsing utilities. 6 | //============================================================================================ 7 | 8 | #ifndef RGD_REGISTER_PARSING_UTILS_H_ 9 | #define RGD_REGISTER_PARSING_UTILS_H_ 10 | 11 | // Local. 12 | #include "rgd_data_types.h" 13 | 14 | // Wave registers offsets for RDNA3 and RDNA2. 15 | enum class WaveRegistersRdna2AndRdna3 : uint32_t 16 | { 17 | kSqWaveStatus = 0x0102, 18 | kSqWavePcHi = 0x0109, 19 | kSqWavePcLo = 0x0108, 20 | kSqWaveTrapsts = 0x0103, 21 | kSqWaveIbSts = 0x0107, 22 | kSqWaveIbSts2 = 0x011c, 23 | kSqWaveActive = 0x000a, 24 | kSqWaveExecHi = 0x027f, 25 | kSqWaveExecLo = 0x027e, 26 | kSqWaveHwId1 = 0x0117, 27 | kSqWaveHwId2 = 0x0118, 28 | kSqWaveValidAndIdle = 0x000b 29 | }; 30 | 31 | // Wave registers offsets for RDNA4. 32 | enum class WaveRegistersRdna4 : uint32_t 33 | { 34 | kSqWaveStatus = 0x0102, 35 | kSqWaveStatePriv = 0x0104, 36 | kSqWavePcHi = 0x0141, 37 | kSqWavePcLo = 0x0140, 38 | kSqWaveIbSts = 0x0107, 39 | kSqWaveExcpFlagPriv = 0x0111, 40 | kSqWaveExcpFlagUser = 0x0112, 41 | kSqWaveIbSts2 = 0x011c, 42 | kSqWaveActive = 0x000a, 43 | kSqWaveExecHi = 0x027f, 44 | kSqWaveExecLo = 0x027e, 45 | kSqWaveHwId1 = 0x0117, 46 | kSqWaveHwId2 = 0x0118, 47 | kSqWaveValidAndIdle = 0x000b 48 | }; 49 | 50 | class RegisterParsingUtils 51 | { 52 | public: 53 | /// @brief Parse wave info registers for Navi2x and Navi3x. 54 | /// @param [in] kmd_crash_data The crash data. 55 | /// @param [out] wave_info_registers_map The wave info registers. 56 | /// @return True if the wave info registers are parsed successfully. 57 | static bool ParseWaveInfoRegisters(const CrashData& kmd_crash_data, std::unordered_map& wave_info_registers_map); 58 | 59 | private: 60 | RegisterParsingUtils() = delete; 61 | ~RegisterParsingUtils() = delete; 62 | }; 63 | 64 | #endif // RGD_REGISTER_PARSING_UTILS_H_ -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_resource_info_serializer.h: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief serializer for memory resource information. 6 | //============================================================================= 7 | #ifndef RGD_RESOURCE_INFO_H_ 8 | #define RGD_RESOURCE_INFO_H_ 9 | 10 | #include 11 | #include "rgd_data_types.h" 12 | 13 | // JSON. 14 | #include "json/single_include/nlohmann/json.hpp" 15 | 16 | class RgdResourceInfoSerializer 17 | { 18 | public: 19 | /// @brief Constructor. 20 | RgdResourceInfoSerializer(); 21 | 22 | /// @brief Destructor. 23 | ~RgdResourceInfoSerializer(); 24 | 25 | /// @brief Serialize resource information for the virtual address. 26 | /// 27 | /// When virtual address provided is zero, information for all the resources 28 | /// from the input crash dump file is serialized. 29 | /// 30 | /// @param [in] user_config The user configuration. 31 | /// @param [in] virtual_address The GPU Address. 32 | /// @param [out] out_text The resource information string. 33 | /// 34 | /// @return true if resource history is built successfully; false otherwise. 35 | bool GetVirtualAddressHistoryInfo(const Config& user_config, const uint64_t virtual_address, std::string& out_text); 36 | 37 | /// @brief Serialize resource information for the virtual address. 38 | /// 39 | /// When virtual address provided is zero, information for all the resources 40 | /// from the input crash dump file is serialized. 41 | /// 42 | /// @param [in] user_config The user configuration. 43 | /// @param [in] virtual_address The GPU Address. 44 | /// @param [out] out_json The resource information json object. 45 | /// 46 | /// @return true if resource history is built successfully; false otherwise. 47 | bool GetVirtualAddressHistoryInfo(const Config& user_config, const uint64_t virtual_address, nlohmann::json& out_json); 48 | 49 | /// @brief Initialize resource info serializer handle with the Rmt dataset handle for the input trace file. 50 | /// 51 | /// @param [in] trace_file_path The path of the crash dump file. 52 | /// 53 | /// @return true if Rmt dataset handle initialization is successful; false otherwise. 54 | bool InitializeWithTraceFile(const std::string& trace_file_path); 55 | 56 | private: 57 | 58 | class Impl; 59 | std::unique_ptr resource_info_serializer_impl_; 60 | 61 | }; 62 | 63 | #endif // RGD_RESOURCE_INFO_H_ -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_serializer.h: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief serializer different data elements. 6 | //============================================================================= 7 | #ifndef RADEON_GPU_DETECTIVE_SOURCE_RGD_SERIALIZER_H_ 8 | #define RADEON_GPU_DETECTIVE_SOURCE_RGD_SERIALIZER_H_ 9 | 10 | // C++. 11 | #include 12 | #include 13 | 14 | // System Info. 15 | #include "system_info_utils/source/system_info_reader.h" 16 | #include "dev_driver/include/rgdevents.h" 17 | 18 | // Local. 19 | #include "rgd_data_types.h" 20 | 21 | class RgdSerializer 22 | { 23 | public: 24 | // Serializes the given SystemInfo structure into a string. 25 | // Returns true if the file exists and false otherwise. 26 | static bool ToString(const Config& user_config, const system_info_utils::SystemInfo& system_info, const nlohmann::json& driver_experiments_json, std::string& system_info_txt); 27 | 28 | // Serialize the input parameters information into a string. 29 | static void InputInfoToString(const Config& user_config, 30 | const TraceProcessInfo& process_info, 31 | const system_info_utils::SystemInfo& system_info, 32 | const TraceChunkApiInfo& api_info, 33 | std::string& input_info_str); 34 | 35 | // Generates a string representing the RgdEvent's header for Umd event, with each line being pushed with the offset tabs. 36 | static std::string RgdEventHeaderToStringUmd(const RgdEvent& rgd_event, const std::string& offset_tabs); 37 | 38 | // Generates a string representing the RgdEvent's header for Kmd event, with each line being pushed with the offset tabs. 39 | static std::string RgdEventHeaderToStringKmd(const RgdEvent& rgd_event, const std::string& offset_tabs); 40 | 41 | // Serializes the given RGD event into a string with offset being 42 | static std::string EventTimestampToString(const TimestampEvent& timestamp_event, const std::string& offset_tabs); 43 | static std::string EventExecMarkerBeginToString(const CrashAnalysisExecutionMarkerBegin& exec_marker_event, const std::string& offset_tabs); 44 | static std::string EventExecMarkerInfoToString(const CrashAnalysisExecutionMarkerInfo& exec_marker_event, const std::string& offset_tabs); 45 | static std::string EventExecMarkerEndToString(const CrashAnalysisExecutionMarkerEnd& exec_marker_event, const std::string& offset_tabs); 46 | static std::string EventDebugNopToString(const CrashDebugNopData& debug_nop_event, const std::string& offset_tabs); 47 | static std::string EventVmPageFaultToString(const VmPageFaultEvent& page_fault_event, const std::string& offset_tabs); 48 | static std::string EventShaderWaveToString(const ShaderWaves& shader_wave_event, const std::string& offset_tabs); 49 | static std::string EventMmrRegisterDataToString(const MmrRegistersData& mmr_register_data_event, const std::string& offset_tabs); 50 | static std::string EventWaveRegisterDataToString(const WaveRegistersData& wave_register_data_event, const std::string& offset_tabs); 51 | static std::string EventSeInfoToString(const SeInfo& se_info_event, const std::string& offset_tabs); 52 | 53 | // Serialize RGD Umd events in the given container into a string. 54 | static std::string SerializeUmdCrashEvents(const std::vector& umd_events); 55 | 56 | // Serialize RGD Kmd events in the given container into a string. 57 | static std::string SerializeKmdCrashEvents(const std::vector& kmd_events); 58 | 59 | // Serialize the crash analysis time info structure into a string. 60 | static std::string CrashAnalysisTimeInfoToString(const CrashAnalysisTimeInfo& time_info); 61 | 62 | // Serialize the Code Object Load Events info. 63 | static std::string CodeObjectLoadEventsToString(const std::vector& code_object_load_events); 64 | 65 | // Serialize the Code Object Database info. 66 | static std::string CodeObjectsToString(const std::map& code_objects_map); 67 | 68 | // Serialize the PSO Correlations info. 69 | static std::string PsoCorrelationsToString(const std::vector& pso_correlations); 70 | 71 | private: 72 | RgdSerializer() = delete; 73 | ~RgdSerializer() = delete; 74 | }; 75 | 76 | #endif // RADEON_GPU_DETECTIVE_SOURCE_RGD_SERIALIZER_H_ 77 | -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_serializer_json.h: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief serializer to JSON format. 6 | //============================================================================= 7 | #ifndef RADEON_GPU_DETECTIVE_SOURCE_RGD_SERIALIZER_JSON_H_ 8 | #define RADEON_GPU_DETECTIVE_SOURCE_RGD_SERIALIZER_JSON_H_ 9 | 10 | // C++. 11 | #include 12 | 13 | // JSON. 14 | #include "json/single_include/nlohmann/json.hpp" 15 | 16 | // System Info. 17 | #include "system_info_utils/source/system_info_reader.h" 18 | 19 | // Local. 20 | #include "rgd_data_types.h" 21 | #include "rgd_resource_info_serializer.h" 22 | #include "rgd_marker_data_serializer.h" 23 | #include "rgd_enhanced_crash_info_serializer.h" 24 | 25 | // JSON Schema version 26 | #define STRINGIFY_JSON_SCHEMA_VERSION(major, minor) STRINGIFY_MACRO(major) "." STRINGIFY_MACRO(minor) 27 | #define RGD_JSON_SCHEMA_VERSION_MAJOR 1 28 | #define RGD_JSON_SCHEMA_VERSION_MINOR 1 29 | #define RGD_JSON_SCHEMA_VERSION STRINGIFY_JSON_SCHEMA_VERSION(RGD_JSON_SCHEMA_VERSION_MAJOR, RGD_JSON_SCHEMA_VERSION_MINOR) 30 | 31 | // *** INTERNALLY-LINKED AUXILIARY CONSTANTS - BEGIN *** 32 | 33 | static const char* kStrInfoNoCmdBuffersInFlight = "no command buffers were in flight during crash."; 34 | static const char* kStrNoInFlightShaderInfo = "in flight shader info not available."; 35 | 36 | // *** INTERNALLY-LINKED AUXILIARY CONSTANTS - END *** 37 | 38 | class RgdSerializerJson 39 | { 40 | public: 41 | RgdSerializerJson() = default; 42 | ~RgdSerializerJson() = default; 43 | 44 | // Set input information. 45 | void SetInputInfo(const Config& user_config, 46 | const TraceProcessInfo& process_info, 47 | const system_info_utils::SystemInfo& system_info, 48 | const TraceChunkApiInfo& api_info); 49 | 50 | // Serializes and sets relevant system info. 51 | void SetSystemInfoData(const Config& user_config, const system_info_utils::SystemInfo& system_info); 52 | 53 | // Serializes and sets the execution marker events and other relevant UMD crash data. 54 | void SetUmdCrashData(const CrashData& umd_crash_data); 55 | 56 | // Serializes and sets relevant KMD events, such as page fault and debug nop. 57 | void SetKmdCrashData(const CrashData& kmd_crash_data); 58 | 59 | // Set virtual address memory residency timeline and relevent resource memory event history. 60 | void SetVaResourceData(RgdResourceInfoSerializer& resource_serializer, 61 | const Config& user_config, 62 | const uint64_t virtual_address); 63 | 64 | // Set command buffer execution markers status tree. 65 | void SetExecutionMarkerTree(const Config& user_config, const CrashData& kmd_crash_data, 66 | const std::unordered_map >& cmd_buffer_events, 67 | ExecMarkerDataSerializer& exec_marker_serializer); 68 | 69 | // Set command buffer executiona marker summary list. 70 | void SetExecutionMarkerSummaryList(const Config& user_config, const CrashData& kmd_crash_data, 71 | const std::unordered_map >& cmd_buffer_events, 72 | ExecMarkerDataSerializer& exec_marker_serializer); 73 | 74 | // Set Driver Experiments info. 75 | void SetDriverExperimentsInfoData(const nlohmann::json& driver_experiments_json); 76 | 77 | // Set shader info. 78 | void SetShaderInfo(const Config& user_config, RgdEnhancedCrashInfoSerializer& enhanced_crash_info_serializer); 79 | 80 | // Saves the JSON contents to a file. 81 | bool SaveToFile(const Config& user_config) const; 82 | 83 | private: 84 | nlohmann::json json_; 85 | }; 86 | 87 | #endif // RADEON_GPU_DETECTIVE_SOURCE_RGD_SERIALIZER_JSON_H_ 88 | -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_utils.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief general utilities. 6 | //============================================================================= 7 | #include "rgd_utils.h" 8 | #include "rgd_data_types.h" 9 | 10 | // C++. 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | bool RgdUtils::IsFileExists(const std::string& file_name) 22 | { 23 | std::ifstream fs(file_name.c_str()); 24 | return fs.good(); 25 | } 26 | 27 | bool RgdUtils::IsValidFilePath(const std::string& file_name) 28 | { 29 | std::ofstream file_path(file_name); 30 | bool is_invalid = !file_path; 31 | return !is_invalid; 32 | } 33 | 34 | bool RgdUtils::WriteTextFile(const std::string& file_name, const std::string& contents) 35 | { 36 | bool ret = false; 37 | std::ofstream output; 38 | output.open(file_name.c_str()); 39 | if (output.is_open()) 40 | { 41 | output << contents << std::endl; 42 | output.close(); 43 | ret = true; 44 | } 45 | return ret; 46 | } 47 | 48 | std::string RgdUtils::GetFileCreationTime(const std::string& file_name) 49 | { 50 | struct stat fileInfo; 51 | std::stringstream return_txt; 52 | if (stat(file_name.c_str(), &fileInfo) == 0) 53 | { 54 | char time_string[100] = ""; 55 | if (std::strftime(time_string, sizeof(time_string), "%c", std::localtime(&fileInfo.st_mtime)) != 0) 56 | { 57 | return_txt << time_string; 58 | } 59 | } 60 | 61 | return (return_txt.str().empty() ? kStrNotAvailable : return_txt.str()); 62 | } 63 | 64 | void RgdUtils::PrintMessage(const char* msg, RgdMessageType msg_type, bool is_verbose) 65 | { 66 | if(is_verbose || !is_verbose && msg_type == RgdMessageType::kError) 67 | { 68 | switch (msg_type) 69 | { 70 | case RgdMessageType::kInfo: 71 | std::cout << "INFO: " << msg << std::endl; 72 | break; 73 | case RgdMessageType::kWarning: 74 | std::cout << "WARNING: " << msg << std::endl; 75 | break; 76 | case RgdMessageType::kError: 77 | std::cerr << "ERROR: " << msg << std::endl; 78 | break; 79 | } 80 | } 81 | } 82 | 83 | void RgdUtils::LeftTrim(const std::string& text, std::string& trimmed_text) 84 | { 85 | trimmed_text = text; 86 | auto space_iter = std::find_if(trimmed_text.begin(), trimmed_text.end(), [](char ch) { return !std::isspace(ch, std::locale::classic()); }); 87 | trimmed_text.erase(trimmed_text.begin(), space_iter); 88 | } 89 | 90 | void RgdUtils::RightTrim(const std::string& text, std::string& trimmed_text) 91 | { 92 | trimmed_text = text; 93 | auto space_iter = std::find_if(trimmed_text.rbegin(), trimmed_text.rend(), [](char ch) { return !std::isspace(ch, std::locale::classic()); }); 94 | trimmed_text.erase(space_iter.base(), trimmed_text.end()); 95 | } 96 | 97 | void RgdUtils::TrimLeadingAndTrailingWhitespace(const std::string& text, std::string& trimmed_text) 98 | { 99 | // Trim the whitespace off the left and right sides of the incoming text. 100 | std::string left_trimmed; 101 | LeftTrim(text, left_trimmed); 102 | RightTrim(left_trimmed, trimmed_text); 103 | } 104 | 105 | // Append and return the heap type string with developer friendly type name. 106 | std::string RgdUtils::ToHeapTypeString(const std::string& heap_type_str) 107 | { 108 | assert(!heap_type_str.empty()); 109 | std::string extended_heap_type_string = heap_type_str; 110 | 111 | if (heap_type_str == "local") 112 | { 113 | extended_heap_type_string = kStrHeapTypeLocal; 114 | } 115 | else if (heap_type_str == "invisible") 116 | { 117 | extended_heap_type_string = kStrHeapTypeInvisible; 118 | } 119 | 120 | return extended_heap_type_string; 121 | } 122 | 123 | std::string RgdUtils::ToFormattedNumericString(size_t number) 124 | { 125 | std::stringstream ss; 126 | ss.imbue(std::locale("")); 127 | ss << std::fixed << number; 128 | return ss.str(); 129 | } 130 | 131 | // Returns the command buffer queue type string. 132 | std::string RgdUtils::GetCmdBufferQueueTypeString(CmdBufferQueueType queue_type) 133 | { 134 | std::stringstream ret; 135 | switch (queue_type) 136 | { 137 | case CMD_BUFFER_QUEUE_TYPE_DIRECT: 138 | ret << "Direct"; 139 | break; 140 | case CMD_BUFFER_QUEUE_TYPE_COMPUTE: 141 | ret << "Compute"; 142 | break; 143 | case CMD_BUFFER_QUEUE_TYPE_COPY: 144 | ret << "Copy"; 145 | break; 146 | default: 147 | ret << "Unknown"; 148 | break; 149 | } 150 | 151 | return ret.str(); 152 | } 153 | 154 | // Returns the Execution Marker API type string. 155 | std::string RgdUtils::GetExecMarkerApiTypeString(CrashAnalysisExecutionMarkerApiType api_type) 156 | { 157 | std::stringstream ret; 158 | 159 | switch (api_type) 160 | { 161 | case CrashAnalysisExecutionMarkerApiType::CRASH_ANALYSIS_EXECUTION_MARKER_API_DRAW_INSTANCED: 162 | ret << "Draw"; 163 | break; 164 | case CrashAnalysisExecutionMarkerApiType::CRASH_ANALYSIS_EXECUTION_MARKER_API_DRAW_INDEXED_INSTANCED: 165 | ret << "DrawIndexed"; 166 | break; 167 | case CrashAnalysisExecutionMarkerApiType::CRASH_ANALYSIS_EXECUTION_MARKER_API_DISPATCH: 168 | ret << "Dispatch"; 169 | break; 170 | case CrashAnalysisExecutionMarkerApiType::CRASH_ANALYSIS_EXECUTION_MARKER_API_COPY_RESOURCE: 171 | ret << "CopyResource"; 172 | break; 173 | case CrashAnalysisExecutionMarkerApiType::CRASH_ANALYSIS_EXECUTION_MARKER_API_COPY_TEXTURE_REGION: 174 | ret << "CopyTextureRegion"; 175 | break; 176 | case CrashAnalysisExecutionMarkerApiType::CRASH_ANALYSIS_EXECUTION_MARKER_API_COPY_BUFFER_REGION: 177 | ret << "CopyBufferRegion"; 178 | break; 179 | case CrashAnalysisExecutionMarkerApiType::CRASH_ANALYSIS_EXECUTION_MARKER_API_COPY_TILES: 180 | ret << "CopyTiles"; 181 | break; 182 | case CrashAnalysisExecutionMarkerApiType::CRASH_ANALYSIS_EXECUTION_MARKER_API_ATOMIC_COPY_BUFFER_REGION: 183 | ret << "AtomicCopyBufferRegion"; 184 | break; 185 | case CrashAnalysisExecutionMarkerApiType::CRASH_ANALYSIS_EXECUTION_MARKER_API_BARRIER: 186 | ret << "Barrier"; 187 | break; 188 | case CrashAnalysisExecutionMarkerApiType::CRASH_ANALYSIS_EXECUTION_MARKER_API_EXECUTE_INDIRECT: 189 | ret << "ExecuteIndirect"; 190 | break; 191 | case CrashAnalysisExecutionMarkerApiType::CRASH_ANALYSIS_EXECUTION_MARKER_API_DISPATCH_RAYS_INDIRECT: 192 | ret << "DispatchRaysIndirect"; 193 | break; 194 | case CrashAnalysisExecutionMarkerApiType::CRASH_ANALYSIS_EXECUTION_MARKER_API_DISPATCH_RAYS_UNIFIED: 195 | ret << "DispatchRaysUnified"; 196 | break; 197 | case CrashAnalysisExecutionMarkerApiType::CRASH_ANALYSIS_EXECUTION_MARKER_API_EXECUTE_INDIRECT_RAYS_UNSPECIFIED: 198 | ret << "ExecuteIndirectRaysUnspecified"; 199 | break; 200 | case CrashAnalysisExecutionMarkerApiType::CRASH_ANALYSIS_EXECUTION_MARKER_API_INTERNAL_DISPATCH_BUILD_BVH: 201 | ret << "InternalDispatchBuildBvh"; 202 | break; 203 | case CrashAnalysisExecutionMarkerApiType::CRASH_ANALYSIS_EXECUTION_MARKER_API_DISPATCH_MESH: 204 | ret << "DispatchMesh"; 205 | break; 206 | default: 207 | ret << "Unknown"; 208 | break; 209 | } 210 | 211 | return ret.str(); 212 | } 213 | 214 | // Returns the API string. 215 | std::string RgdUtils::GetApiString(TraceApiType api_type) 216 | { 217 | std::stringstream ret_txt; 218 | 219 | switch (api_type) 220 | { 221 | case TraceApiType::GENERIC: 222 | ret_txt << kStrNotAvailable; 223 | break; 224 | case TraceApiType::DIRECTX_12: 225 | ret_txt << "DirectX 12"; 226 | break; 227 | case TraceApiType::VULKAN: 228 | ret_txt << "Vulkan"; 229 | break; 230 | case TraceApiType::DIRECTX_9: 231 | case TraceApiType::DIRECTX_11: 232 | case TraceApiType::OPENGL: 233 | case TraceApiType::OPENCL: 234 | case TraceApiType::MANTLE: 235 | case TraceApiType::HIP: 236 | case TraceApiType::METAL: 237 | default: 238 | // Should not reach here. 239 | assert(false); 240 | ret_txt << "Invalid"; 241 | break; 242 | } 243 | 244 | return ret_txt.str(); 245 | } 246 | 247 | std::string RgdUtils::GetHangTypeString(HangType hang_type) 248 | { 249 | std::stringstream ret_txt; 250 | switch (hang_type) 251 | { 252 | case pageFault: 253 | ret_txt << "Page fault"; 254 | break; 255 | case nonPageFault: 256 | ret_txt << "Non-page fault"; 257 | break; 258 | case unknown: 259 | ret_txt << "Unknown"; 260 | break; 261 | default: 262 | // Should not reach here. 263 | assert(false); 264 | ret_txt << "Invalid"; 265 | break; 266 | } 267 | 268 | return ret_txt.str(); 269 | } 270 | 271 | std::string RgdUtils::GetAlphaNumericId(std::string id_prefix, uint64_t id) 272 | { 273 | std::stringstream ret_txt; 274 | assert(!id_prefix.empty()); 275 | ret_txt << id_prefix << id; 276 | return ret_txt.str(); 277 | } 278 | -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_utils.h: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief general utilities. 6 | //============================================================================= 7 | #ifndef RADEON_GPU_DETECTIVE_SOURCE_RGD_UTILS_H_ 8 | #define RADEON_GPU_DETECTIVE_SOURCE_RGD_UTILS_H_ 9 | 10 | // C++. 11 | #include 12 | 13 | // System Info. 14 | #include "system_info_utils/source/system_info_reader.h" 15 | 16 | // Dev driver. 17 | #include "dev_driver/include/rgdevents.h" 18 | 19 | // Types of messages that are printed by the tool. 20 | enum class RgdMessageType 21 | { 22 | kInfo, 23 | kWarning, 24 | kError 25 | }; 26 | 27 | class RgdUtils 28 | { 29 | public: 30 | 31 | // *** FILESYSTEM - START *** 32 | 33 | // Returns true if the file exists and false otherwise. 34 | static bool IsFileExists(const std::string& file_name); 35 | 36 | // Returns true if the given full path is valid and false otherwise. 37 | static bool IsValidFilePath(const std::string& file_name); 38 | 39 | // Returns creation time of the input crash dump file. 40 | static std::string GetFileCreationTime(const std::string& file_name); 41 | 42 | // Writes the contents into the given full text file path. Returns true on success and false otherwise. 43 | static bool WriteTextFile(const std::string& file_name, const std::string& contents); 44 | 45 | // *** FILESYSTEM - END *** 46 | 47 | // Prints a message to the console based on the the message type and the verbosity level. 48 | // Error messages are always printed to std::cerr. 49 | // Warning and INFO messages are only printed in verbose mode. 50 | static void PrintMessage(const char* msg, RgdMessageType msg_type, bool is_verbose); 51 | 52 | // Trim the whitespace off the left side of the incoming string. 53 | static void LeftTrim(const std::string& text, std::string& trimmed_text); 54 | 55 | // Trim the whitespace off the right side of the incoming string. 56 | static void RightTrim(const std::string& text, std::string& trimmed_text); 57 | 58 | // Trim the leading or trailing whitespaces if any. 59 | static void TrimLeadingAndTrailingWhitespace(const std::string& text, std::string& trimmed_text); 60 | 61 | // Append and return the heap type string with developer friendly type name. 62 | static std::string ToHeapTypeString(const std::string& heap_type_str); 63 | 64 | // Format the input number to a comma separated string. 65 | static std::string ToFormattedNumericString(size_t number); 66 | 67 | // Returns the command buffer queue type string. 68 | static std::string GetCmdBufferQueueTypeString(CmdBufferQueueType queue_type); 69 | 70 | // Returns the Execution Marker API type string. 71 | static std::string GetExecMarkerApiTypeString(CrashAnalysisExecutionMarkerApiType api_type); 72 | 73 | // Returns the API string. 74 | static std::string GetApiString(TraceApiType api_type); 75 | 76 | // Returns the hang type string. 77 | static std::string GetHangTypeString(HangType hang_type); 78 | 79 | // Returns the alphanumeric string id bu appending the input string prefix and id. 80 | static std::string GetAlphaNumericId(std::string id_prefix, uint64_t id); 81 | 82 | private: 83 | RgdUtils() = delete; 84 | ~RgdUtils() = delete; 85 | }; 86 | 87 | #endif // RADEON_GPU_DETECTIVE_SOURCE_RGD_UTILS_H_ 88 | -------------------------------------------------------------------------------- /source/radeon_gpu_detective_backend/rgd_version_info.h.in: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief Radeon GPU Detective version header 6 | //============================================================================= 7 | 8 | #ifndef RGD_FRONTEND_VERSION_H_ 9 | #define RGD_FRONTEND_VERSION_H_ 10 | 11 | #define STRINGIFY_MACRO_(a) #a 12 | #define STRINGIFY_MACRO(a) STRINGIFY_MACRO_(a) 13 | #define STRINGIFY_VERSION(major, minor, patch, build) STRINGIFY_MACRO(major) "." STRINGIFY_MACRO(minor) "." STRINGIFY_MACRO(patch) "." STRINGIFY_MACRO(build) 14 | 15 | #define RGD_MAJOR_VERSION @RGD_MAJOR_VERSION@ ///< Major version number. 16 | #define RGD_MINOR_VERSION @RGD_MINOR_VERSION@ ///< Minor version number. 17 | #define RGD_PATCH_NUMBER @RGD_PATCH_NUMBER@ ///< Patch number. 18 | #define RGD_BUILD_NUMBER @RGD_BUILD_NUMBER@ ///< Build number. 19 | #define RGD_BUILD_SUFFIX "@RGD_BUILD_SUFFIX@" ///< Build suffix 20 | #define RGD_BUILD_DATE_STRING @DATE@ 21 | #define RGD_BUILD_YEAR @YEAR@ 22 | #define RGD_VERSION STRINGIFY_VERSION(RGD_MAJOR_VERSION, RGD_MINOR_VERSION, RGD_PATCH_NUMBER, RGD_BUILD_NUMBER) 23 | #define RGD_APP_NAME "Radeon GPU Detective" 24 | #define RGD_TITLE RGD_APP_NAME " " RGD_VERSION " " RGD_BUILD_SUFFIX ///< Title 25 | #define RGD_COPYRIGHT_STRING "Copyright (C) "RGD_BUILD_YEAR" Advanced Micro Devices, Inc. All rights reserved." 26 | 27 | #endif -------------------------------------------------------------------------------- /source/radeon_gpu_detective_cli/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #============================================================================= 2 | # Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | # @author AMD Developer Tools Team 4 | # @file 5 | # @brief RGD CLI CMakeLists file. 6 | #============================================================================= 7 | 8 | cmake_minimum_required (VERSION 3.10) 9 | project (radeon_gpu_detective_cli) 10 | 11 | # Include cxxopts for command line parsing. 12 | include_directories("${PROJECT_SOURCE_DIR}/../../external/third_party/cxxopts/include/") 13 | include_directories("${PROJECT_SOURCE_DIR}/../../external/") 14 | include_directories("${PROJECT_SOURCE_DIR}/../../external/rmv/source/parser/") 15 | include_directories("${PROJECT_SOURCE_DIR}/../../external/rmv/source/backend/") 16 | include_directories("${PROJECT_SOURCE_DIR}/../../external/third_party/") 17 | include_directories("${PROJECT_SOURCE_DIR}/../radeon_gpu_detective_backend/") 18 | 19 | set(CMAKE_CXX_STANDARD 17) 20 | 21 | add_definitions(-D_USE_REAL_VA) 22 | # RDF. 23 | add_definitions(-DRDF_CXX_BINDINGS) 24 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 25 | 26 | IF (WIN32) 27 | add_definitions(-DRDF_PLATFORM_WINDOWS) 28 | add_link_options(/STACK:16777216) 29 | ELSEIF(UNIX) 30 | add_definitions(-DRDF_PLATFORM_UNIX) 31 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,stack-size=16777216") 32 | ENDIF(WIN32) 33 | 34 | # Source files that are common for Windows and Linux 35 | file(GLOB RGD_CLI_SRC 36 | "*.cpp" 37 | "*.h" 38 | "../../external/cxxopts/*.hpp" 39 | ) 40 | 41 | set( RGD_WINDOWS_SRC 42 | "windows/resource.h" 43 | "windows/rgd.rc" 44 | ) 45 | 46 | IF (WIN32) 47 | add_executable(radeon_gpu_detective_cli ${RGD_CLI_SRC} ${RGD_WINDOWS_SRC}) 48 | ELSEIF(UNIX) 49 | add_executable(radeon_gpu_detective_cli ${RGD_CLI_SRC}) 50 | ENDIF(WIN32) 51 | set_target_properties(radeon_gpu_detective_cli PROPERTIES OUTPUT_NAME rgd) 52 | 53 | # Linker. 54 | target_link_libraries(radeon_gpu_detective_cli rgd_backend rdf RmvBackend RmvParser system_info ComgrUtils ${CMAKE_DL_LIBS}) 55 | 56 | # Warning level. 57 | if(MSVC) 58 | target_compile_options(radeon_gpu_detective_cli PRIVATE /W4) 59 | endif() 60 | 61 | # Setup the post-build script. 62 | # List of all dynamically loaded libraries that need to be copied into the output 63 | set( PLUGINS 64 | ${AMD_COMGR_SHAREDLIB} 65 | ${AMDGPU_DIS_SHAREDLIB} 66 | ) 67 | 68 | # Copy all plugins (aka dynamically loaded shared libraries) into the appropriate output directory. 69 | # 70 | IF (WIN32) 71 | # For WIN32 shared libraries live in the same directory as the executable 72 | set(PLUGIN_DST $) 73 | ELSEIF (UNIX) 74 | # For Unix, shared libraries are copied into a /lib subdirectory 75 | set(PLUGIN_DST $/lib/) 76 | ENDIF() 77 | 78 | add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD 79 | COMMAND ${CMAKE_COMMAND} -E make_directory ${PLUGIN_DST} 80 | ) 81 | 82 | FOREACH (PLUGIN ${PLUGINS}) 83 | add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD 84 | COMMAND ${CMAKE_COMMAND} -E echo "copying ${PLUGIN} to ${PLUGIN_DST}" 85 | COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PLUGIN} ${PLUGIN_DST} 86 | ) 87 | ENDFOREACH() -------------------------------------------------------------------------------- /source/radeon_gpu_detective_cli/windows/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by rgd.rc 4 | // 5 | 6 | // Next default values for new objects 7 | // 8 | #ifdef APSTUDIO_INVOKED 9 | #ifndef APSTUDIO_READONLY_SYMBOLS 10 | #define _APS_NEXT_RESOURCE_VALUE 101 11 | #define _APS_NEXT_COMMAND_VALUE 40001 12 | #define _APS_NEXT_CONTROL_VALUE 1001 13 | #define _APS_NEXT_SYMED_VALUE 101 14 | #endif 15 | #endif 16 | -------------------------------------------------------------------------------- /source/radeon_gpu_detective_cli/windows/rgd.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GPUOpen-Tools/radeon_gpu_detective/21c2589081650e0d1cfdc356b4c3ed931e2a132e/source/radeon_gpu_detective_cli/windows/rgd.rc -------------------------------------------------------------------------------- /test/RGD_TEST_README.md: -------------------------------------------------------------------------------- 1 | # RGD Automated Test Kit 2 | The RGD automated test is a set of scripts and executable files that can generate AMD GPU crash dump (.rgd) files and validate the contents of the generated files. Its primary goal is to check for driver regressions. 3 | 4 | ## Usage Instructions ## 5 | * Download test kit and extract 6 | * Run: python TestRunner.py 7 | * python TestRunner.py -h should provide detailed help and more options 8 | 9 | ## Platform Support ## 10 | Supported APIs: DirectX 12 11 | 12 | Supported OS: Windows 10, Windows 11 13 | 14 | Supported hardware: Navi2 and Navi3 GPUs 15 | 16 | 17 | ## Dependencies ## 18 | * Python 3.x (tested with 3.6.5) 19 | 20 | ## More Details ## 21 | * [RGD Automated Test Kit Confluence Page](https://confluence.amd.com/display/DEVTOOLS/RGD+Automated+Test+Kit) -------------------------------------------------------------------------------- /test/scripts/input_description_files/RgdAllTests.json: -------------------------------------------------------------------------------- 1 | { 2 | "DX12": [ 3 | { 4 | "test_name": "EndlessLoopSingleVertex", 5 | "crash_test_case": 2, 6 | "verify_crash_dump": true, 7 | "verify_rgd_cli_output": false, 8 | "golden_files_positive": [], 9 | "golden_files_negative": [] 10 | }, 11 | { 12 | "test_name": "EvictReferenced", 13 | "crash_test_case": 5, 14 | "verify_crash_dump": true, 15 | "verify_rgd_cli_output": false, 16 | "golden_files_positive": [], 17 | "golden_files_negative": [] 18 | }, 19 | { 20 | "test_name": "EvictReferencedNoOveflow", 21 | "crash_test_case": 6, 22 | "verify_crash_dump": true, 23 | "verify_rgd_cli_output": false, 24 | "golden_files_positive": [], 25 | "golden_files_negative": [] 26 | }, 27 | { 28 | "test_name": "EvictReferencedNoOveflow - Multi", 29 | "crash_test_case": 6.1, 30 | "verify_crash_dump": true, 31 | "verify_rgd_cli_output": false, 32 | "golden_files_positive": [], 33 | "golden_files_negative": [] 34 | }, 35 | { 36 | "test_name": "ReleaseTextureSRV", 37 | "crash_test_case": 7, 38 | "verify_crash_dump": true, 39 | "verify_rgd_cli_output": false, 40 | "golden_files_positive": [], 41 | "golden_files_negative": [] 42 | }, 43 | { 44 | "test_name": "WrongAddressInDesc ", 45 | "crash_test_case": 8, 46 | "verify_crash_dump": true, 47 | "verify_rgd_cli_output": false, 48 | "golden_files_positive": [], 49 | "golden_files_negative": [] 50 | }, 51 | { 52 | "test_name": "SamplerOutOfRange", 53 | "crash_test_case": 9, 54 | "verify_crash_dump": true, 55 | "verify_rgd_cli_output": false, 56 | "golden_files_positive": [], 57 | "golden_files_negative": [] 58 | }, 59 | { 60 | "test_name": "WrongAcclerationStructureOffset", 61 | "crash_test_case": 10, 62 | "verify_crash_dump": true, 63 | "verify_rgd_cli_output": false, 64 | "golden_files_positive": [], 65 | "golden_files_negative": [] 66 | }, 67 | { 68 | "test_name": "OverwriteTLAS ", 69 | "crash_test_case": 11, 70 | "verify_crash_dump": true, 71 | "verify_rgd_cli_output": false, 72 | "golden_files_positive": [], 73 | "golden_files_negative": [] 74 | }, 75 | { 76 | "test_name": "IncorretTLASAddress", 77 | "crash_test_case": 12, 78 | "verify_crash_dump": true, 79 | "verify_rgd_cli_output": false, 80 | "golden_files_positive": [], 81 | "golden_files_negative": [] 82 | }, 83 | { 84 | "test_name": "IncorretTLASAddressAligned", 85 | "crash_test_case": 13, 86 | "verify_crash_dump": true, 87 | "verify_rgd_cli_output": false, 88 | "golden_files_positive": [], 89 | "golden_files_negative": [] 90 | }, 91 | { 92 | "test_name": "IncorrectInlineTraceData", 93 | "crash_test_case": 14, 94 | "verify_crash_dump": true, 95 | "verify_rgd_cli_output": false, 96 | "golden_files_positive": [], 97 | "golden_files_negative": [] 98 | }, 99 | { 100 | "test_name": "BufferOutOfBounds", 101 | "crash_test_case": 16, 102 | "verify_crash_dump": true, 103 | "verify_rgd_cli_output": false, 104 | "golden_files_positive": [], 105 | "golden_files_negative": [] 106 | }, 107 | { 108 | "test_name": "NullCBV", 109 | "crash_test_case": 17, 110 | "verify_crash_dump": true, 111 | "verify_rgd_cli_output": false, 112 | "golden_files_positive": [], 113 | "golden_files_negative": [] 114 | }, 115 | { 116 | "test_name": "DestroyCBuffer", 117 | "crash_test_case": 18, 118 | "verify_crash_dump": true, 119 | "verify_rgd_cli_output": false, 120 | "golden_files_positive": [], 121 | "golden_files_negative": [] 122 | }, 123 | { 124 | "test_name": "SamplerInfinityBias", 125 | "crash_test_case": 19, 126 | "verify_crash_dump": true, 127 | "verify_rgd_cli_output": false, 128 | "golden_files_positive": [], 129 | "golden_files_negative": [] 130 | }, 131 | { 132 | "test_name": "IncorrectStructuredBufferSRV", 133 | "crash_test_case": 20, 134 | "verify_crash_dump": true, 135 | "verify_rgd_cli_output": false, 136 | "golden_files_positive": [], 137 | "golden_files_negative": [] 138 | }, 139 | { 140 | "test_name": "DescTableNotBound", 141 | "crash_test_case": 21, 142 | "verify_crash_dump": true, 143 | "verify_rgd_cli_output": false, 144 | "golden_files_positive": [], 145 | "golden_files_negative": [] 146 | }, 147 | { 148 | "test_name": "ReleaseTextureSRV", 149 | "crash_test_case": 22, 150 | "verify_crash_dump": true, 151 | "verify_rgd_cli_output": false, 152 | "golden_files_positive": [], 153 | "golden_files_negative": [] 154 | }, 155 | { 156 | "test_name": "ReleaseTextureSRV crash on 4th", 157 | "crash_test_case": 22.1, 158 | "verify_crash_dump": true, 159 | "verify_rgd_cli_output": false, 160 | "golden_files_positive": [], 161 | "golden_files_negative": [] 162 | }, 163 | { 164 | "test_name": "ReleaseTextureSRV_Async", 165 | "crash_test_case": 22.2, 166 | "verify_crash_dump": true, 167 | "verify_rgd_cli_output": false, 168 | "golden_files_positive": [], 169 | "golden_files_negative": [] 170 | }, 171 | { 172 | "test_name": "UseNotResidentSRV", 173 | "crash_test_case": 23, 174 | "verify_crash_dump": true, 175 | "verify_rgd_cli_output": false, 176 | "golden_files_positive": [], 177 | "golden_files_negative": [] 178 | }, 179 | { 180 | "test_name": "ReleaseReservedTexture", 181 | "crash_test_case": 24, 182 | "verify_crash_dump": true, 183 | "verify_rgd_cli_output": false, 184 | "golden_files_positive": [], 185 | "golden_files_negative": [] 186 | }, 187 | { 188 | "test_name": "ReleaseReservedTextureHeap", 189 | "crash_test_case": 25, 190 | "verify_crash_dump": true, 191 | "verify_rgd_cli_output": false, 192 | "golden_files_positive": [], 193 | "golden_files_negative": [] 194 | }, 195 | { 196 | "test_name": "ReleaseTextureSRV_Placed", 197 | "crash_test_case": 27, 198 | "verify_crash_dump": true, 199 | "verify_rgd_cli_output": false, 200 | "golden_files_positive": [], 201 | "golden_files_negative": [] 202 | }, 203 | { 204 | "test_name": "NullRootSig", 205 | "crash_test_case": 28, 206 | "verify_crash_dump": true, 207 | "verify_rgd_cli_output": false, 208 | "golden_files_positive": [], 209 | "golden_files_negative": [] 210 | } 211 | ] 212 | } -------------------------------------------------------------------------------- /test/scripts/input_description_files/RgdDriverSanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "DX12": [ 3 | { 4 | "test_name": "NullCBV", 5 | "crash_test_case": 17, 6 | "page_fault_case": true, 7 | "verify_crash_dump": true, 8 | "verify_rgd_cli_output": false, 9 | "golden_files_positive": [], 10 | "golden_files_negative": [] 11 | }, 12 | { 13 | "test_name": "ReleaseTextureSRV", 14 | "crash_test_case": 22, 15 | "page_fault_case": true, 16 | "verify_crash_dump": true, 17 | "verify_rgd_cli_output": false, 18 | "golden_files_positive": [], 19 | "golden_files_negative": [] 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /test/source/rgd_test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #============================================================================= 2 | # Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | # @author AMD Developer Tools Team 4 | # @file 5 | # @brief RGD Test CMakeLists file. 6 | #============================================================================= 7 | 8 | cmake_minimum_required(VERSION 3.10) 9 | project(rgd_test) 10 | 11 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 12 | 13 | # Include cxxopts for command line parsing. 14 | include_directories("${PROJECT_SOURCE_DIR}/../../../external/third_party/catch2/single_include/catch2/") 15 | include_directories("${PROJECT_SOURCE_DIR}/../../../external/system_info_utils/source/") 16 | include_directories("${PROJECT_SOURCE_DIR}/../../../external/third_party/cxxopts/include/") 17 | include_directories("${PROJECT_SOURCE_DIR}/../../../source/radeon_gpu_detective_backend/") 18 | 19 | set(CMAKE_CXX_STANDARD 17) 20 | 21 | # RDF. 22 | add_definitions(-DRDF_CXX_BINDINGS) 23 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 24 | 25 | # Source files that are common for Windows and Linux 26 | file(GLOB RGD_TEST_SRC 27 | "*.cpp" 28 | "*.h" 29 | "../../../external/third_party/catch2/single_include/catch2/*.hpp" 30 | ) 31 | 32 | add_executable(${PROJECT_NAME} ${RGD_TEST_SRC}) 33 | 34 | # Linker. 35 | target_link_libraries(${PROJECT_NAME} rgd_backend rdf system_info) 36 | 37 | # Warning level. 38 | if(MSVC) 39 | target_compile_options(${PROJECT_NAME} PRIVATE /W4) 40 | endif() -------------------------------------------------------------------------------- /test/source/rgd_test/main.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief main entry point of RGD Test app. 6 | //============================================================================= 7 | 8 | #include 9 | #include 10 | 11 | // catch2. 12 | #define CATCH_CONFIG_RUNNER 13 | #include 14 | 15 | #include "test_rgd_file.h" 16 | #include "rgd_utils.h" 17 | 18 | struct TestConfig 19 | { 20 | bool is_page_fault = false; 21 | std::string file_path; 22 | }; 23 | 24 | static TestConfig test_config; 25 | 26 | static bool InitializeTestOptions(const char* file_name, bool is_page_fault) 27 | { 28 | assert(file_name != nullptr); 29 | test_config.file_path.assign(file_name); 30 | test_config.is_page_fault = is_page_fault; 31 | 32 | if (test_config.file_path.empty()) 33 | { 34 | std::cout << "ERROR: Missing path to .rgd file" << std::endl; 35 | return false; 36 | } 37 | 38 | if (test_config.file_path.find(".rgd") == std::string::npos) 39 | { 40 | test_config.file_path.assign(""); 41 | return false; 42 | } 43 | 44 | return true; 45 | } 46 | 47 | bool is_empty(const std::string&rgd_file_path) 48 | { 49 | std::ifstream file; 50 | file.open(rgd_file_path); 51 | bool is_empty = file.peek() == std::ifstream::traits_type::eof(); 52 | 53 | if (is_empty) 54 | { 55 | RgdUtils::PrintMessage("crash dump file is empty.", RgdMessageType::kError, true); 56 | } 57 | return is_empty; 58 | } 59 | 60 | std::shared_ptr test_rgd_file_instance = nullptr; 61 | 62 | void SetupTestRgdFileInstance() 63 | { 64 | // Parse the input .rgd file only once for all test cases. 65 | static bool is_test_rgd_file_instance = false; 66 | if (!is_test_rgd_file_instance) 67 | { 68 | test_rgd_file_instance = std::make_shared(test_config.file_path); 69 | } 70 | } 71 | 72 | int32_t main(int argc, char* argv[]) 73 | { 74 | fflush(stdout); 75 | 76 | using namespace Catch::clara; 77 | Catch::Session session; 78 | 79 | // The crash dump file to load. 80 | std::string input_file_path; 81 | bool is_page_fault = false; 82 | 83 | // Add to Catch's composite command line parser. 84 | auto cli = Opt(input_file_path, "input_file_path")["--rgd"]("The path to the trace file") 85 | | Opt(is_page_fault)["--page-fault"]("Enable page fault handling") 86 | | session.cli(); 87 | 88 | int test_result = -1; 89 | 90 | session.cli(cli); 91 | int result = session.applyCommandLine(argc, argv); 92 | if (result != 0) 93 | { 94 | return test_result; 95 | } 96 | 97 | bool initSucceeded = InitializeTestOptions(input_file_path.c_str(), is_page_fault); 98 | if (!initSucceeded) 99 | { 100 | return test_result; 101 | } 102 | else 103 | { 104 | std::cout << "Input file: " << input_file_path << std::endl; 105 | test_result = session.run(); 106 | } 107 | // Test result will contain -1 if the tests were not run (some kind of initialization problem) 108 | // or an integer containing the number of tests that failed. 109 | return test_result; 110 | } 111 | 112 | TEST_CASE("TestEmptyFile", "[TestRgdFileStructure]") 113 | { 114 | REQUIRE(is_empty(test_config.file_path) == false); 115 | } 116 | 117 | TEST_CASE("ParseRgdFile", "[TestRgdFileStructure, TestDDEventChunks]") 118 | { 119 | SetupTestRgdFileInstance(); 120 | SECTION("Valid file structure") 121 | { 122 | REQUIRE(test_rgd_file_instance->ParseRgdFile(test_config.is_page_fault)); 123 | REQUIRE(test_rgd_file_instance->IsSystemInfoParsed()); 124 | REQUIRE(!test_rgd_file_instance->IsRdfParsingError()); 125 | REQUIRE(test_rgd_file_instance->IsAppMarkersFound()); 126 | REQUIRE(test_rgd_file_instance->IsMarkerContextFound()); 127 | } 128 | } -------------------------------------------------------------------------------- /test/source/rgd_test/test_rgd_file.cpp: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief test rgd file structure. 6 | //============================================================================= 7 | 8 | #include 9 | #include 10 | 11 | #include "test_rgd_file.h" 12 | 13 | // RGD CLI. 14 | #include "rgd_parsing_utils.h" 15 | #include "rgd_data_types.h" 16 | #include "rgd_utils.h" 17 | 18 | // RDF. 19 | #include "rdf/rdf/inc/amdrdf.h" 20 | 21 | // System info. 22 | #include "system_info_utils/source/system_info_reader.h" 23 | 24 | TestRgdFile::TestRgdFile(const std::string& path) : file_path_(path) {} 25 | 26 | bool TestRgdFile::ParseRgdFile(bool is_page_fault) 27 | { 28 | bool ret = false; 29 | 30 | const char* kErrorTextCouldNotParseRgdFile = "could not parse the crash dump file"; 31 | 32 | // Read and parse the RDF file. 33 | auto file = rdf::Stream::OpenFile(file_path_.c_str()); 34 | 35 | std::string error_msg; 36 | try 37 | { 38 | rdf::ChunkFile chunk_file = rdf::ChunkFile(file); 39 | 40 | // Parse the UMD and KMD crash data chunk. 41 | const char* kChunkCrashData = "DDEvent"; 42 | ret = RgdParsingUtils::ParseCrashDataChunks(chunk_file, kChunkCrashData, rgd_file_contents_.umd_crash_data, rgd_file_contents_.kmd_crash_data, error_msg); 43 | 44 | if (!error_msg.empty()) 45 | { 46 | std::stringstream error_txt; 47 | error_txt << kErrorTextCouldNotParseRgdFile << error_msg; 48 | RgdUtils::PrintMessage(error_txt.str().c_str(), RgdMessageType::kError, true); 49 | } 50 | 51 | // Check if KMD chunk data is found. KMD chunk is optional and it is received only for the page fault crashes. 52 | is_kmd_chunk_found_ = !rgd_file_contents_.kmd_crash_data.events.empty(); 53 | 54 | if (is_page_fault && !is_kmd_chunk_found_) 55 | { 56 | ret = false; 57 | RgdUtils::PrintMessage("KMD chunk data is not found in the crash dump file.", RgdMessageType::kError, true); 58 | } 59 | 60 | // Parse System Info chunk. 61 | is_system_info_parsed_ = system_info_utils::SystemInfoReader::Parse(chunk_file, rgd_file_contents_.system_info); 62 | 63 | if (!is_system_info_parsed_) 64 | { 65 | RgdUtils::PrintMessage("failed to parse system information contents in crash dump file.", RgdMessageType::kError, true); 66 | } 67 | } 68 | catch (const std::exception& e) 69 | { 70 | is_rdf_parsing_error_ = true; 71 | std::stringstream error_txt; 72 | error_txt << kErrorTextCouldNotParseRgdFile << " (" << e.what() << ")"; 73 | RgdUtils::PrintMessage(error_txt.str().c_str(), RgdMessageType::kError, true); 74 | } 75 | 76 | return ret; 77 | } 78 | 79 | bool TestRgdFile::IsSystemInfoParsed() 80 | { 81 | return is_system_info_parsed_; 82 | } 83 | 84 | bool TestRgdFile::IsRdfParsingError() 85 | { 86 | return is_rdf_parsing_error_; 87 | } 88 | 89 | bool TestRgdFile::IsAppMarkersFound() 90 | { 91 | bool is_app_marker_found = false; 92 | for (uint32_t i = 0; i < rgd_file_contents_.umd_crash_data.events.size(); i++) 93 | { 94 | const RgdEventOccurrence& curr_marker_event = rgd_file_contents_.umd_crash_data.events[i]; 95 | UmdEventId marker_event_id = static_cast(curr_marker_event.rgd_event->header.eventId); 96 | if (marker_event_id == UmdEventId::RgdEventExecutionMarkerBegin) 97 | { 98 | const CrashAnalysisExecutionMarkerBegin& marker_begin = 99 | static_cast(*curr_marker_event.rgd_event); 100 | 101 | if ((marker_begin.markerValue & kMarkerSrcMask) >> (kUint32Bits - kMarkerSrcBitLen) == (uint32_t)CrashAnalysisExecutionMarkerSource::Application) 102 | { 103 | is_app_marker_found = true; 104 | 105 | // Break if atleast one 'APP' marker is found. 106 | break; 107 | } 108 | } 109 | } 110 | 111 | if (!is_app_marker_found) 112 | { 113 | RgdUtils::PrintMessage("no application markers found in the crash dump file.", RgdMessageType::kError, true); 114 | } 115 | 116 | return is_app_marker_found; 117 | } 118 | 119 | bool TestRgdFile::IsMarkerContextFound() 120 | { 121 | bool is_marker_context_found = false; 122 | bool is_cmd_buf_start_info_found = false; 123 | 124 | // Test for Draw info event when previous marker is Draw Begin. 125 | bool is_previous_marker_draw_begin = false; 126 | bool is_draw_info_found = true; 127 | 128 | // Test for Dispatch info event when previous marker is Dispatch Begin. 129 | bool is_previous_marker_dispatch_begin = false; 130 | bool is_dispatch_info_found = true; 131 | 132 | bool is_barrier_found = false; 133 | bool is_pipeline_bind_found = false; 134 | 135 | // Iterate through all UMD events and check if atleast one of each 'CmdBufStart', 'Pipeline Bind', 'Draw', 'Dispatch' and 'Barrier' info event is found. 136 | for (uint32_t i = 0; i < rgd_file_contents_.umd_crash_data.events.size(); i++) 137 | { 138 | const RgdEventOccurrence& curr_marker_event = rgd_file_contents_.umd_crash_data.events[i]; 139 | UmdEventId marker_event_id = static_cast(curr_marker_event.rgd_event->header.eventId); 140 | if (marker_event_id == UmdEventId::RgdEventExecutionMarkerBegin) 141 | { 142 | const CrashAnalysisExecutionMarkerBegin& marker_begin = static_cast(*curr_marker_event.rgd_event); 143 | std::string marker_name = (marker_begin.markerStringSize > 0) 144 | ? std::string(reinterpret_cast(marker_begin.markerName), marker_begin.markerStringSize) 145 | : std::string(kStrNotAvailable); 146 | if (marker_name == kStrDraw) 147 | { 148 | is_previous_marker_draw_begin = true; 149 | } 150 | else if (marker_name == kStrDispatch) 151 | { 152 | is_previous_marker_dispatch_begin = true; 153 | } 154 | } 155 | if (marker_event_id == UmdEventId::RgdEventExecutionMarkerInfo) 156 | { 157 | const CrashAnalysisExecutionMarkerInfo& exec_marker_info_event = static_cast(*curr_marker_event.rgd_event); 158 | uint32_t marker_value = exec_marker_info_event.marker; 159 | 160 | uint8_t* marker_info = const_cast(exec_marker_info_event.markerInfo); 161 | ExecutionMarkerInfoHeader* exec_marker_info_header = reinterpret_cast(marker_info); 162 | 163 | switch (exec_marker_info_header->infoType) 164 | { 165 | case ExecutionMarkerInfoType::CmdBufStart: 166 | is_cmd_buf_start_info_found = true; 167 | break; 168 | case ExecutionMarkerInfoType::BarrierBegin: 169 | is_barrier_found = true; 170 | break; 171 | case ExecutionMarkerInfoType::PipelineBind: 172 | is_pipeline_bind_found = true; 173 | break; 174 | default: 175 | break; 176 | } 177 | 178 | // Check if Draw/Dispatch info event is found when previous marker is Draw/Dispatch Begin. 179 | if (is_previous_marker_draw_begin && exec_marker_info_header->infoType != ExecutionMarkerInfoType::Draw) 180 | { 181 | is_draw_info_found = false; 182 | } 183 | else if (is_previous_marker_dispatch_begin && exec_marker_info_header->infoType != ExecutionMarkerInfoType::Dispatch) 184 | { 185 | is_dispatch_info_found = false; 186 | } 187 | 188 | // Reset the previous begin marker flags. 189 | is_previous_marker_draw_begin = false; 190 | is_previous_marker_dispatch_begin = false; 191 | 192 | if (is_cmd_buf_start_info_found 193 | && is_draw_info_found 194 | && is_dispatch_info_found 195 | && is_barrier_found 196 | && is_pipeline_bind_found) 197 | { 198 | is_marker_context_found = true; 199 | } 200 | } 201 | } 202 | 203 | if (!is_marker_context_found) 204 | { 205 | std::stringstream missing_events_txt; 206 | missing_events_txt << "marker context/info events are missing in the crash dump file. Missing info events:"; 207 | if (!is_cmd_buf_start_info_found) 208 | { 209 | missing_events_txt << " CmdBufStart"; 210 | } 211 | if (!is_draw_info_found) 212 | { 213 | missing_events_txt << " " << kStrDraw; 214 | } 215 | if (!is_dispatch_info_found) 216 | { 217 | missing_events_txt << " " << kStrDispatch; 218 | } 219 | if (!is_barrier_found) 220 | { 221 | missing_events_txt << " Barrier"; 222 | } 223 | if (!is_pipeline_bind_found) 224 | { 225 | missing_events_txt << " PipelineBind"; 226 | } 227 | 228 | RgdUtils::PrintMessage(missing_events_txt.str().c_str(), RgdMessageType::kError, true); 229 | } 230 | 231 | return is_marker_context_found; 232 | } -------------------------------------------------------------------------------- /test/source/rgd_test/test_rgd_file.h: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. 3 | /// @author AMD Developer Tools Team 4 | /// @file 5 | /// @brief Test .rgd file structure 6 | //============================================================================= 7 | #ifndef RADEON_GPU_DETECTIVE_TEST_RGD_FILE_H_ 8 | #define RADEON_GPU_DETECTIVE_TEST_RGD_FILE_H_ 9 | 10 | #include 11 | #include "rgd_data_types.h" 12 | 13 | class TestRgdFile 14 | { 15 | public: 16 | explicit TestRgdFile(const std::string& file_path); 17 | 18 | bool ParseRgdFile(bool is_page_fault); 19 | bool IsSystemInfoParsed(); 20 | bool IsRdfParsingError(); 21 | bool IsAppMarkersFound(); 22 | bool IsMarkerContextFound(); 23 | 24 | private: 25 | std::string file_path_; 26 | bool is_system_info_parsed_ = false; 27 | bool is_rdf_parsing_error_ = false; 28 | bool is_umd_chunk_found_ = false; 29 | bool is_kmd_chunk_found_ = false; 30 | RgdCrashDumpContents rgd_file_contents_; 31 | }; 32 | 33 | #endif // RADEON_GPU_DETECTIVE_TEST_RGD_FILE_H_ --------------------------------------------------------------------------------