# 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 . # # 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 __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 }