|  | # Copyright (C) 2019-2025 Free Software Foundation, Inc. | 
|  | # | 
|  | # This program is free software; you can redistribute it and/or modify | 
|  | # it under the terms of the GNU General Public License as published by | 
|  | # the Free Software Foundation; either version 3 of the License, or | 
|  | # (at your option) any later version. | 
|  | # | 
|  | # This program is distributed in the hope that it will be useful, | 
|  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | # GNU General Public License for more details. | 
|  | # | 
|  | # You should have received a copy of the GNU General Public License | 
|  | # along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
|  | # | 
|  | # Support library for testing ROCm (AMD GPU) GDB features. | 
|  |  | 
|  | # ROCM_PATH is used by hipcc as well. | 
|  | if {[info exists ::env(ROCM_PATH)]} { | 
|  | set rocm_path $::env(ROCM_PATH) | 
|  | } else { | 
|  | set rocm_path "/opt/rocm" | 
|  | } | 
|  |  | 
|  | # Act as a drop-in replacement for "remote_exec host" | 
|  | # that logs the failures. | 
|  |  | 
|  | proc log_host_exec { cmd } { | 
|  | set result [remote_exec host "$cmd"] | 
|  | set exit_status [lindex $result 0] | 
|  | if {$exit_status != 0} { | 
|  | # -1 indicates that $cmd could not be executed at all. | 
|  | if {$exit_status == -1} { | 
|  | verbose -log "Cannot execute $cmd." | 
|  | } else { | 
|  | verbose -log "$cmd returned an error." | 
|  | } | 
|  | } | 
|  |  | 
|  | return $result | 
|  | } | 
|  |  | 
|  | # Detect available AMDGPU devices. | 
|  | # | 
|  | # Return a list of GPU devices that do exist on the system. | 
|  | # The list will be empty when there's no GPU or the execution | 
|  | # of rocm_agent_enumerator does not succeed.  It is up to the | 
|  | # caller of this procedure that what should happen when an empty | 
|  | # list is returned. | 
|  |  | 
|  | gdb_caching_proc find_amdgpu_devices {} { | 
|  | global rocm_path | 
|  | set hip_gpu_devices [list] | 
|  | set enumerator "rocm_agent_enumerator" | 
|  | set targets "" | 
|  |  | 
|  | # Try the PATH first | 
|  | set result [log_host_exec "$enumerator"] | 
|  | if {[lindex $result 0] == 0} { | 
|  | set targets [lindex $result 1] | 
|  | } else { | 
|  | # Now try the ROCM_PATH | 
|  | set result [log_host_exec "$rocm_path/bin/$enumerator"] | 
|  | if {[lindex $result 0] == 0} { | 
|  | set targets [lindex $result 1] | 
|  | } | 
|  | } | 
|  |  | 
|  | if {$targets != ""} { | 
|  | foreach dev $targets { | 
|  | # Ignore the 'gfx000' device which identifies the host. | 
|  | if {$dev != "gfx000"} { | 
|  | lappend hip_gpu_devices $dev | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return $hip_gpu_devices | 
|  | } | 
|  |  | 
|  | # Get the list of GPU targets to compile for. | 
|  | # | 
|  | # If HCC_AMDGPU_TARGET is set in the environment, use it. | 
|  | # Otherwise, consider the devices available on the system. | 
|  |  | 
|  | proc hcc_amdgpu_targets {} { | 
|  | # First, look for HCC_AMDGPU_TARGET (same env var hipcc uses). | 
|  | if {[info exists ::env(HCC_AMDGPU_TARGET)]} { | 
|  | # We don't verify the contents of HCC_AMDGPU_TARGET. | 
|  | # That's the toolchain's job. | 
|  | return [split $::env(HCC_AMDGPU_TARGET) ","] | 
|  | } | 
|  |  | 
|  | return [find_amdgpu_devices] | 
|  | } | 
|  |  | 
|  | gdb_caching_proc allow_hipcc_tests {} { | 
|  | # Only the native target supports ROCm debugging.  E.g., when | 
|  | # testing against GDBserver, there's no point in running the ROCm | 
|  | # tests. | 
|  | if {[target_info gdb_protocol] != ""} { | 
|  | return {0 "remote debugging"} | 
|  | } | 
|  |  | 
|  | if {![istarget "*-linux*"]} { | 
|  | return {0 "target platform is not Linux"} | 
|  | } | 
|  |  | 
|  | # Ensure that GDB is built with amd-dbgapi support. | 
|  | set output [remote_exec host $::GDB "$::INTERNAL_GDBFLAGS --configuration"] | 
|  | if { [string first "--with-amd-dbgapi" $output] == -1 } { | 
|  | return {0 "amd-dbgapi not supported"} | 
|  | } | 
|  |  | 
|  | # Check if there's any GPU device to run the tests on. | 
|  | set devices [find_amdgpu_devices] | 
|  | if {[llength $devices] == 0} { | 
|  | return {0 "no suitable amdgpu targets found"} | 
|  | } | 
|  |  | 
|  | # Check if we have a working hipcc compiler available. | 
|  | # TARGETS won't be empty, because there's at least one GPU device. | 
|  | set targets [hcc_amdgpu_targets] | 
|  | set flags [list hip additional_flags=--offload-arch=[join $targets ","]] | 
|  | if {![gdb_simple_compile hipprobe { | 
|  | #include <hip/hip_runtime.h> | 
|  | __global__ void | 
|  | kern () {} | 
|  |  | 
|  | int | 
|  | main () | 
|  | { | 
|  | kern<<<1, 1>>> (); | 
|  | if (hipDeviceSynchronize () != hipSuccess) | 
|  | return -1; | 
|  | return 0; | 
|  | } | 
|  | } executable $flags]} { | 
|  | return {0 "failed to compile hip program"} | 
|  | } | 
|  |  | 
|  | return 1 | 
|  | } | 
|  |  | 
|  | # The lock file used to ensure that only one GDB has access to the GPU | 
|  | # at a time. | 
|  | set gpu_lock_filename gpu-parallel.lock | 
|  |  | 
|  | # Run body under the GPU lock.  Also calls gdb_exit before releasing | 
|  | # the GPU lock. | 
|  |  | 
|  | proc with_rocm_gpu_lock { body } { | 
|  | with_lock $::gpu_lock_filename {uplevel 1 $body} | 
|  |  | 
|  | # In case BODY returned early due to some testcase failing, and | 
|  | # left GDB running, debugging the GPU. | 
|  | gdb_exit | 
|  | } | 
|  |  | 
|  | # Return true if all the devices support debugging multiple processes | 
|  | # using the GPU. | 
|  |  | 
|  | proc hip_devices_support_debug_multi_process {} { | 
|  | set unsupported_targets \ | 
|  | {gfx900 gfx906 gfx908 gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032} | 
|  |  | 
|  | set targets [find_amdgpu_devices] | 
|  | if { [llength $targets] == 0 } { | 
|  | return 0 | 
|  | } | 
|  |  | 
|  | foreach target $targets { | 
|  | if { [lsearch -exact $unsupported_targets $target] != -1 } { | 
|  | return 0 | 
|  | } | 
|  | } | 
|  | return 1 | 
|  | } |