| # Copyright (C) 2019-2024 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 |
| } |
| |
| # Return true if all the devices on the host support precise memory. |
| |
| proc hip_devices_support_precise_memory {} { |
| 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 |
| } |