[PATCH 3/6] umr: Complete umr completion

Luben Tuikov luben.tuikov at amd.com
Wed Mar 23 11:48:39 UTC 2022


Complete all commands. Complete all commands' arguments which can be
completed. Data is gathered from files in the UMR_DATABASE_PATH, from the
PCI system and from the /sys filesystem in order to complete the arguments
of commands which require non-open-value argument, i.e. an argument from a
closed set.

Cc: Alex Deucher <Alexander.Deucher at amd.com>
Cc: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer at amd.com>
Cc: Tom StDenis <tom.stdenis at amd.com>
Cc: Christian König <christian.koenig at amd.com>
Signed-off-by: Luben Tuikov <luben.tuikov at amd.com>
---
 scripts/umr-completion.bash | 374 ++++++++++++++++++++++++++++++++++--
 1 file changed, 362 insertions(+), 12 deletions(-)

diff --git a/scripts/umr-completion.bash b/scripts/umr-completion.bash
index 79972949b9861e..7029264ca5f725 100644
--- a/scripts/umr-completion.bash
+++ b/scripts/umr-completion.bash
@@ -1,6 +1,22 @@
 # bash completion for umr
+# Copyright (C) Advanced Micro Devices 2022
+#
+# You should set UMR_DATABASE_PATH before sourcing this file in your
+# .bashrc. To source it, do "source <location of this file>"--to see a
+# usual location of this file, see the FILES section in umr(1).
+#
+# I recommend you "set show-all-if-ambiguous On" in your .inputrc, for
+# matches to be listed immediately (on a first TAB key press) as
+# opposed to ring the bell the first time and seeing matches on the
+# second TAB key press. To load the keymap, do "bind -f ~/.inputrc" in
+# your .bashrc, assuming your .inputrc is in your home directory.
 
-_setup()
+if [[ ! -d $UMR_DATABASE_PATH ]]; then
+    echo -n "UMR_DATABASE_PATH must be set for correct operation of umr bash completion."
+    echo " See the FILES section in umr(1)."
+fi
+
+_umr_setup_ips()
 {
     select_gpu=""
     if [ $COMP_CWORD -ge 4 ]; then
@@ -25,9 +41,9 @@ _setup()
     done
 }
 
-_comp_blocks()
+_umr_comp_blocks()
 {
-    _setup
+    _umr_setup_ips
 
     if [ -z "$cur" ]; then
         COMPREPLY=( $(compgen -W "${ips[*]}" -- "$cur") )
@@ -39,9 +55,9 @@ _comp_blocks()
     fi
 }
 
-_comp_regs()
+_umr_comp_regs()
 {
-    _setup
+    _umr_setup_ips
 
     if [[ "$cur" =~ ^[^.]*'.'[^.]*'.'[^.]*$ ]]; then
         cur_asic="${cur%%.*}"
@@ -60,24 +76,358 @@ _comp_regs()
     fi
 }
 
+_umr_comp_option_flags()
+{
+    local FLAGS=(bits bitsfull empty_log follow no_follow_ib use_pci use_colour read_smc quiet no_kernel verbose halt_waves disasm_early_term no_disasm disasm_anyways wave64 full_shader no_fold_vm_decode no_scan_waves)
+    local F G CURR_OPTIONS
+    local ACTIVE_OPTIONS=()
+    local ACTIVE_FLAGS=()
+
+    CURR_OPTIONS="`echo ${COMP_WORDS[*]} | sed -E -e 's/^.*-O[[:space:]]+(.*)$/\1/g'`"
+    CURR_OPTIONS="`echo $CURR_OPTIONS | sed -E -e 's/,/ /g'`"
+
+    # Get rid of user-input partial option string
+    for F in $CURR_OPTIONS ; do
+	if [[ $F == $cur ]] ; then
+	   continue;
+	fi
+	ACTIVE_OPTIONS+=("$F")
+    done
+
+    # Offer only options which are not already part of --option/-O
+    for F in ${FLAGS[*]} ; do
+	for G in ${ACTIVE_OPTIONS[*]} ; do
+	    if [[ $F == $G ]]; then
+		continue 2;
+	    fi
+	done
+	ACTIVE_FLAGS+=($F)
+    done
+
+    # If the user presses TAB again after full completion, as opposed
+    # to say SPACE BAR, then give them comma and the rest of the
+    # flags.
+    COMPREPLY=( $(compgen -W "${ACTIVE_FLAGS[*]}" -- "$cur") )
+    if [[ $cur == ${COMPREPLY[0]} ]] && (( ${#COMPREPLY[*]} == 1 )) && (( ${#ACTIVE_FLAGS[*]} > 1 )) ; then
+	COMPREPLY=( $(compgen -S ',' -W "${ACTIVE_FLAGS[*]}" -- "$cur") )
+    fi
+    # Complete with a space after all options entered.
+    if [[ $cur != ${COMPREPLY[0]} ]] || (( ${#COMPREPLY[*]} != 1 )) || (( ${#ACTIVE_FLAGS[*]} > 1 )) ; then
+	compopt -o nospace
+    fi
+}
+
+_umr_comp_instance()
+{
+    local INSTANCE=(`sudo \ls -1 /sys/kernel/debug/dri/`)
+
+    COMPREPLY=( $(compgen -W "${INSTANCE[*]}" -- "$cur") )
+}
+
+_umr_comp_pci()
+{
+    local PCI_LIST=(`lspci -D | grep VGA | cut -f 1 -d \   | tr '\n' ' '`)
+
+    COMPREPLY=( $(compgen -W "${PCI_LIST[*]}" -- "$cur") )
+}
+
+_umr_comp_prof()
+{
+    local PROFS=( "pixel=" "vertex=" "compute=" )
+
+    COMPREPLY=( $(compgen -W "${PROFS[*]}" -- "$cur") )
+    compopt -o nospace
+}
+
+_umr_comp_ring()
+{
+    local INSTANCE=`echo "$COMP_LINE" | sed -E -e 's/^.*(--instance|-i)[[:space:]]+([0-9]+).*$/\2/g'`
+
+    if [[ ! $INSTANCE =~ ^[0-9]+$ ]]; then
+	# The default instance in umr is 0. See umr(1) under "--instance".
+	INSTANCE=0
+    fi
+
+    local RINGS=( `sudo $(which find) /sys/kernel/debug/dri/$INSTANCE -name amdgpu_ring_* | sed -E -e "s%/sys/kernel/debug/dri/$INSTANCE/amdgpu_ring_%%g"` )
+
+    COMPREPLY=( $(compgen -W "${RINGS[*]}" -- "$cur") )
+}
+
+_umr_comp_clock_scan()
+{
+    local CLOCKS=( `sudo $(which umr) --clock-scan | grep ".*:$" | sed -E -e 's/[: ]//g'` )
+
+    COMPREPLY=( $(compgen -W "${CLOCKS[*]}" -- "$cur") )
+}
+
+_umr_comp_force()
+{
+    local ASIC_NAMES=(`awk '{ print $2; }' $UMR_DATABASE_PATH/pci.did | sed -E -e 's/.asic//g' | sort | uniq`)
+    if [[ $cur =~ ^\..* ]] ; then
+	COMPREPLY=( $(compgen -P '.' -W "${ASIC_NAMES[*]}" -- "${cur#.}") )
+    else
+	COMPREPLY=( $(compgen -W "${ASIC_NAMES[*]}" -- "$cur") )
+    fi
+}
+
+_umr_comp_gpu()
+{
+    local INSTANCE=( `sudo \ls -1 /sys/kernel/debug/dri/` )
+    local PCI_BUS_DIR_NAMES=()
+    local PCI_BUS_IDS=()
+    local -A PCI_BUS_ASIC_NAME
+    local SUGGEST=()
+    local ASIC_NAMES=()
+    local TEMP_ASIC_NAMES=()
+    local INST_ASIC_NAME=()
+    local GPU_NAME
+    local F
+
+    # We need to do it like this, so that this works
+    # when run from non-root shell.
+    for F in ${INSTANCE[*]} ; do
+	PCI_BUS_DIR_NAMES+=("/sys/kernel/debug/dri/$F/name")
+    done
+    PCI_BUS_IDS=( `sudo cat ${PCI_BUS_DIR_NAMES[*]} | sed -E -e 's/^.* (dev=(.*)) .*$/\2/g' | sort | uniq` )
+
+    for F in ${INSTANCE[*]} ; do
+	local PCI_ID=`sudo cat  "/sys/kernel/debug/dri/$F/name" | sed -E -e 's/^.* (dev=(.*)) .*$/\2/g'`
+	local DEV_ID=`cat /sys/class/pci_bus/${PCI_ID%:??.?}/device/$PCI_ID/device`
+	local DEV_ID_NAME=`grep -i $DEV_ID ${UMR_DATABASE_PATH}/pci.did | awk '{ print $2; }' | sed -E -e 's/.asic//g'`
+	TEMP_ASIC_NAMES+=($DEV_ID_NAME)
+	PCI_BUS_ASIC_NAME["$PCI_ID"]="$DEV_ID_NAME"
+	INST_ASIC_NAME["$F"]="$DEV_ID_NAME"
+    done
+    # Remove duplicates
+    ASIC_NAMES=( `(for F in ${TEMP_ASIC_NAMES[*]} ; do echo $F; done) | sort | uniq` )
+
+    if [[ ! $cur =~ .*@.* ]] && [[ ! $cur =~ .*=.* ]]; then
+	COMPREPLY=( $(compgen -W "${ASIC_NAMES[*]}" -- "$cur") )
+	if [[ ${#COMPREPLY[*]} == 1 ]]; then
+	    GPU_NAME=${COMPREPLY[0]}
+	    COMPREPLY=( $(compgen -W "${GPU_NAME}@ ${GPU_NAME}=" -- "$cur") )
+	fi
+	compopt -o nospace
+	return
+    fi
+
+    if [[ $cur =~ .*@.* ]]; then
+	# Find all instances of the selected ASIC name and offer them
+	local INST_OFFER=()
+	GPU_NAME="${cur%%@*}"
+	for F in ${INSTANCE[*]} ; do
+	    if [[ $GPU_NAME == ${INST_ASIC_NAME["$F"]} ]] ; then
+		INST_OFFER+=("$F")
+	    fi
+	done
+	SUGGEST=( $(compgen -P "${GPU_NAME}@" -W "${INST_OFFER[*]}") )
+    elif [[ $cur =~ .*=.* ]]; then
+	# Find all PCI bus IDs of the selected ASIC name and offer them
+	local PCI_ID_OFFER=()
+	GPU_NAME="${cur%%=*}"
+	for F in ${PCI_BUS_IDS[*]} ; do
+	    if [[ $GPU_NAME == ${PCI_BUS_ASIC_NAME["$F"]} ]] ; then
+		PCI_ID_OFFER+=("$F")
+	    fi
+	done
+	SUGGEST=( $(compgen -P "${GPU_NAME}=" -W "${PCI_ID_OFFER[*]}") )
+    fi
+
+    COMPREPLY=( $(compgen -W "${SUGGEST[*]}" -- $cur) )
+}
+
+# Sets GPU_NAME with the name of the GPU given on the command line by
+# --force, --gpu or --instance, or default, and sets up IP_BLOCKS an
+# array of the names of the IP blocks of GPU_NAME.
+#
+_umr_setup_gpu_ipblocks()
+{
+    # The regex we use to match an ASIC name is "[[:alnum:]_]+".
+    local FORCE=`echo "$COMP_LINE" | sed -E -e 's/^.*(--force|-f)[[:space:]]+([[:alnum:]_]+).*$/\2/g'`
+    local GPU=`echo "$COMP_LINE" | sed -E -e  's/^.*(--gpu|-g)[[:space:]]+([[:alnum:]_]+)(@|=)*.*$/\2/g'`
+    local INSTANCE=`echo "$COMP_LINE" | sed -E -e 's/^.*(--instance|-i)[[:space:]]+([0-9]+).*$/\2/g'`
+
+    # GPU_NAME is set only when given by a parameter on the command line.
+    # GPU_NAME2 is always set, even when not specified on the command line.
+    IP_BLOCKS=
+    GPU_NAME=
+    GPU_NAME2=
+    DEFAULT_GPU_NAME=
+
+    if [[ $COMP_LINE =~ (--force|-f) ]]; then
+	GPU_NAME="$FORCE"
+	IP_BLOCKS=( `sudo umr --force $GPU_NAME --list-blocks | sed -E -e "s/^[[:space:]]*${GPU_NAME}\.(.*)[[:space:]]+\(.*$/\1/g"` )
+	GPU_NAME2="$GPU_NAME"
+    elif [[ $COMP_LINE =~ (--gpu|-g) ]]; then
+	GPU_NAME="$GPU"
+	IP_BLOCKS=( `sudo umr --force $GPU_NAME --list-blocks | sed -E -e "s/^[[:space:]]*${GPU_NAME}\.(.*)[[:space:]]+\(.*$/\1/g"` )
+	GPU_NAME2="$GPU_NAME"
+    elif [[ $COMP_LINE =~ (--instance|-i) ]]; then
+	GPU_NAME=`sudo umr --instance $INSTANCE --list-blocks | head -1 | cut -f 1 -d . | sed -E -e 's/[[:space:]]+//g'`
+	IP_BLOCKS=( `sudo umr --instance $INSTANCE --list-blocks | sed -E -e "s/^[[:space:]]*${GPU_NAME}\.(.*) \(.*$/\1/g"` )
+	GPU_NAME2="$GPU_NAME"
+    else
+	GPU_NAME2=`sudo umr --list-blocks | head -1 | cut -f 1 -d . | sed -E -e 's/[[:space:]]+//g'`
+	IP_BLOCKS=( `sudo umr --list-blocks | sed -E -e "s/^[[:space:]]*.*\.(.*) \(.*$/\1/g"` )
+    fi
+
+    DEFAULT_GPU_NAME=`sudo umr --list-blocks | head -1 | cut -f 1 -d . | sed -E -e 's/[[:space:]]+//g'`
+}
+
+_umr_comp_lookup()
+{
+    # Should specify a GPU with --force or --gpu, of even --instance.
+    # The --gpu option also specifies an IP block and is thus
+    # redundant--better use --force.
+    # Specifying a GPU is optional--a default detected
+    # will be used.
+    # The format is --lookup <IP block>.<register> <value>.
+
+    _umr_setup_gpu_ipblocks
+    local REGS
+    local FINAL
+    local F
+
+    if [[ ! $cur =~ .*\. ]]; then
+	COMPREPLY=( $(compgen -S '.' -W "${IP_BLOCKS[*]}" -- $cur) )
+	compopt -o nospace
+    else
+	# Complete a register for the given IP block.
+	# See _umr_comp_asic_ipblock_registers() below.
+	F="${cur%.*}"
+	if [[ -z $GPU_NAME ]] || [[ $GPU_NAME == $DEFAULT_GPU_NAME ]] ; then
+	    REGS=( `sudo umr --list-regs ${F} | sed -E -e "s/(.*)\.(.*)\.(.*)[[:space:]]+\(.*$/\3/g"` )
+	else
+	    REGS=( `sudo umr --force $GPU_NAME --list-regs ${F%\{*} | sed -E -e "s/${GPU_NAME}\.(.*)\.(.*)[[:space:]]+\(.*$/\2/g"` )
+	    if (( ${#REGS[*]} == 0 )); then
+		REGS=( `sudo umr --force $GPU_NAME --list-regs ${F} | sed -E -e "s/${GPU_NAME}\.(.*)\.(.*)[[:space:]]+\(.*$/\2/g"` )
+	    fi
+	fi
+	FINAL=( $(compgen -P "${F}." -W "${REGS[*]}") )
+	COMPREPLY=( $(compgen -W "${FINAL[*]}" -- "$cur") )
+    fi
+
+    unset GPU_NAME GPU_NAME2 DEFAULT_GPU_NAME IP_BLOCKS
+}
+
+_umr_comp_asic_ipblock_registers()
+{
+    # The format is --writebit asic.ipblock.regname,
+    # the same as that of --write and --read.
+
+    _umr_setup_gpu_ipblocks
+    local ips=()
+    local FINAL=()
+    local REGS=()
+    local F
+
+    ips=( $(compgen -P "${GPU_NAME2}." -W "${IP_BLOCKS[*]}") )
+
+    if [[ ! $cur =~ ${GPU_NAME2}\..*\. ]]; then
+       COMPREPLY=( $(compgen -S '.' -W "${ips[*]}" -- $cur) )
+       compopt -o nospace
+    else
+	# cur = asic.ipblock.*
+	#
+	# When using --force with the default (installed in the
+	# system) ASIC and --list-regs together, --list-regs does not
+	# take instance numbers, so to pass an instance number, we
+	# need to know if the GPU was forced on the command line.
+	# First however, get rid of user hints.
+	F="${cur%.*}"
+	if [[ -z $GPU_NAME ]] || [[ $GPU_NAME == $DEFAULT_GPU_NAME ]] ; then
+	    REGS=( `sudo umr --list-regs ${F} | sed -E -e "s/(.*)\.(.*)\.(.*)[[:space:]]+\(.*$/\3/g"` )
+	else
+	    REGS=( `sudo umr --force $GPU_NAME --list-regs ${F%\{*} | sed -E -e "s/${GPU_NAME}\.(.*)\.(.*)[[:space:]]+\(.*$/\2/g"` )
+	    if (( ${#REGS[*]} == 0 )); then
+		REGS=( `sudo umr --force $GPU_NAME --list-regs ${F} | sed -E -e "s/${GPU_NAME}\.(.*)\.(.*)[[:space:]]+\(.*$/\2/g"` )
+	    fi
+	fi
+	# Cannot combine the compgen since a match is performed
+	# _before_ the prefix is applied! And if we want to match,
+	# we need to tack the prefix prior to asking for a match.
+	FINAL=( $(compgen -P "${F}." -W "${REGS[*]}") )
+	COMPREPLY=( $(compgen -W "${FINAL[*]}" -- $cur) )
+    fi
+
+    unset GPU_NAME GPU_NAME2 DEFAULT_GPU_NAME IP_BLOCKS
+}
+
+_umr_comp_ring_stream()
+{
+    _umr_comp_ring
+    compopt -o nospace
+}
+
 _umr_completion()
 {
-    local cur prev 
+    local ALL_LONG_ARGS=(--database-path --option --gpu --instance --force --pci --gfxoff --vm_partition --bank --sbank --cbank --config --enumerate --list-blocks --list-regs --dump-discovery-table --lookup --write --writebit --read --scan --logscan --top --waves --profiler --vm-decode --vm-read --vm-write --vm-write-word --vm-disasm --ring-stream --dump-ib --dump-ib-file --header-dump --power --clock-scan --clock-manual --clock-high --clock-low --clock-auto --ppt_read --gpu_metrics --power --vbios_info --test-log --test-harness --server --gui)
+
+    local cur prev
+
+    COMP_WORDBREAKS=" ,"
 
     COMPREPLY=()
-    cur=${COMP_WORDS[COMP_CWORD]}
-    prev=${COMP_WORDS[COMP_CWORD-1]}
+    cur=$2
+    prev=$3
 
     case $prev in
+	--database-path|--dbp)
+	    compopt -o default -o dirnames
+	    ;;
+	--option|-O|bits|bitsfull|empty_log|follow|no_follow_ib|use_pci|use_colour|read_smc|quiet|no_kernel|verbose|halt_waves|disasm_early_term|no_disasm|disasm_anyways|wave64|full_shader|no_fold_vm_decode|no_scan_waves|,)
+	    _umr_comp_option_flags
+	    ;;
+	--force|-f)
+	    _umr_comp_force
+	    ;;
+	--gpu|-g)
+	    _umr_comp_gpu
+	    ;;
+	--instance|-i)
+	    _umr_comp_instance
+	    ;;
+	--pci)
+	    _umr_comp_pci
+	    ;;
+	--gfxoff|-go)
+	    COMPREPLY=( $(compgen -W "0 1" -- "$cur") )
+	    ;;
         -lr|--list-regs|-s|--scan)
-            _comp_blocks
-            return 0
+            _umr_comp_blocks
             ;;
         -r|--read|-w|--write)
-            _comp_regs
-            return 0
+            _umr_comp_regs
             ;;
+	--lookup|-lu)
+	    _umr_comp_lookup
+	    ;;
+	--writebit|-wb)
+	    _umr_comp_asic_ipblock_registers
+	    ;;
+	--waves|-wa)
+	    _umr_comp_ring
+	    ;;
+	--profiler|-prof)
+	    _umr_comp_prof
+	    ;;
+	pixel=*|vertex=*|compute=*)
+	    _umr_comp_ring
+	    ;;
+	--dump-ib-file|-df|--test-log|-tl|--test-harness|-th)
+	    compopt -o default -o filenames
+	    ;;
+	--clock-scan|-cs|--clock-manual|-cm)
+	    _umr_comp_clock_scan
+	    ;;
+	--ring-stream|-RS)
+	    _umr_comp_ring_stream
+	    ;;
+	*)
+	    COMPREPLY=( $(compgen -W "${ALL_LONG_ARGS[*]}" -- $cur) )
+	    ;;
     esac
+    return 0
 }
 
 complete -F _umr_completion umr
-- 
2.35.1.607.gf01e51a7cf



More information about the amd-gfx mailing list