shtools/zgoc/zgoc
Mateo FERON 0950379829 Init
2020-04-06 16:01:00 +02:00

337 lines
7.7 KiB
Bash
Executable file

#!/bin/sh
#
# This script does not support multiple GPUs
# Only radeon GPUs supported
#
config_file="/usr/share/z/config/zgoc.conf"
if [ ! -f "$config_file" ]
then
echo'# zgoc config file
GPU_PROFILE_PATH=/usr/share/z/zgoc/profiles/gpu
GPU_MEM_PATH=/usr/share/z/zgoc/profiles/mem
GPU_POWER_PATH=/usr/share/z/zgoc/profiles/power
GPU_NAME=
GPU_PCI_ID=
GPU_AUTOMEMFIX=true
GPU_MIN_POWER=30
FANC_PROFILE_PATH=/usr/share/z/zgoc/profiles/fan
FANC_DEFAULT_PROFILE=default
FANC_TIME_INTERVAL=2' > "$config_file"
fi
profile_path=$(grep "GPU_PROFILE_PATH=" "$config_file" | cut -d '=' -f2-)
mem_path=$(grep "GPU_MEM_PATH=" "$config_file" | cut -d '=' -f2-)
power_path=$(grep "GPU_POWER_PATH=" "$config_file" | cut -d '=' -f2-)
card_name=$( grep "GPU_NAME=" "$config_file" | cut -d '=' -f2-)
pci_id=$(grep "GPU_PCI_ID=" "$config_file" | cut -d '=' -f2-)
automemfix=$(grep "GPU_AUTOMEMFIX=" "$config_file" | cut -d '=' -f2-)
min_power=$(grep "GPU_MIN_POWER=" "$config_file" | cut -d '=' -f2-)
if [ ! "$automemfix" = "true" ]
then
automemfix=""
fi
usage() {
echo "Usage: zgoc <arguments>"
echo "Arguments:"
echo " print : show current state"
echo " gpu : GPU overclocking"
echo " mem : memory overclocking"
echo " apply : apply GPU and memory profiles"
echo " reset : reset GPU and memory to stock values"
echo " memfix : fix screen artifacting caused by low memory state"
echo " power : power cap"
echo ""
echo "Config file: $config_file"
}
error () {
printf "\033[1;31m%s\033[0m\n" "$1" >&2
}
root_check () {
if [ "$(id | cut -d'=' -f2 | cut -d'(' -f1)" -ne 0 ]
then
echo "Root privileges required" > /dev/stderr
exit 10
fi
}
_stop() {
echo ""
exit
}
trap '_stop' INT
# val_convert <reduction factor n> <precision>
# convert an integer to a lower decimal
# output = input*10^-n
# reads from input
val_convert () {
read -r in
size=${#in}
n2=$((size - $1))
integer=$(echo "$in" | cut -c-$n2)
if [ "$2" != 0 ] ; then
decimal=$(echo "$in" | cut -c$((n2+1))-"$size" | cut -c1-"$2")
fi
if [ -z "$integer" ] ; then
integer=0
fi
printf "%s" "$integer"
if [ -n "$decimal" ] ; then
printf ".%s" "$decimal"
fi
echo ""
}
kernel_req ()
{
MAIN_KERNELVER=$(uname -r | cut -d'.' -f1) # Get kernel version.
SEC_KERNELVER=$(uname -r | cut -d'.' -f2) # Get kernel version.
if [ "$MAIN_KERNELVER" -le "$1" ]; then
if [ "$SEC_KERNELVER" -lt "$2" ]; then
error "Kernel $1.$2 or higher is required for this feature"
exit 13
fi
fi
}
# kernel version check
kernel_req 4 15
file_report () {
if [ -f "$(pwd)/$1" ]
then
printf "%s = " "$(pwd)/$1"
cat "$(pwd)/$1"
elif [ -f "$1" ]
then
printf "%s = " "$1"
cat "$1"
else
error "File $1 from $(pwd) unaccessible"
fi
}
file_write () {
if ! echo "$1" > "$2" ;
then
error "Error writing to $2 from $(pwd)"
exit 14
fi
file_report "$2"
}
high_mem_state () {
if [ -z "$HIGH_MEM_STATE" ]
then
_t=$(grep OD_MCLK "$path/device/pp_od_clk_voltage" -A6)
I=0
while echo "$_t" | grep -q "$I:" ; do
I=$((I + 1))
done
HIGH_MEM_STATE=$((I - 1))
fi
echo $HIGH_MEM_STATE
}
set_core_state () {
root_check
echo "s$1: $2 MHz $3 mV"
echo "s$1 $2 $3" > "$path/device/pp_od_clk_voltage"
}
set_mem_state () {
root_check
echo "m$1: $2 MHz $3 mV"
echo "m $1 $2 $3" > "$path/device/pp_od_clk_voltage"
}
force_mem_state_high () {
root_check
echo "manual" > "$path/device/power_dpm_force_performance_level"
high_mem_state > "$path/device/pp_dpm_mclk"
echo "Forcing memory state to $(high_mem_state) (fix artifacting)"
}
apply () {
root_check
echo "c" > "$path/device/pp_od_clk_voltage"
echo "Profile applied"
if [ -n "$automemfix" ] ; then
force_mem_state_high
fi
}
reset_stock () {
root_check
if echo "0 1 2 3 4 5 6 7" > "$path/device/pp_dpm_sclk" && echo "r" > "$path/device/pp_od_clk_voltage" ; then
echo "Reset to default"
fi
}
apply_power () {
root_check
if ! echo "$1" | grep -Eq '^[0-9]+$' ; then
echo "Invalid power value" >&2
exit 2
elif [ "$1" -lt "$min_power" ] ; then
echo "Power value too low" >&2
exit 2
elif [ -z "$1" ] ; then
echo "No power value given" >&2
exit 2
else
if echo "$1""000000" > $hwmon/power1_cap ; then
echo "Power cap set to $1 W"
fi
fi
}
set_profile () {
read -r _states
read -r _frequencies
read -r _voltages
I=1
for T in $_states
do
if [ "$1" = "gpu" ] ; then
set_core_state "$(echo "$_states" | awk -v I=$I '{print $I}')" "$(echo "$_frequencies" | awk -v I=$I '{print $I}')" "$(echo "$_voltages" | awk -v I=$I '{print $I}')"
elif [ "$1" = "mem" ] ; then
set_mem_state "$(echo "$_states" | awk -v I=$I '{print $I}')" "$(echo "$_frequencies" | awk -v I=$I '{print $I}')" "$(echo "$_voltages" | awk -v I=$I '{print $I}')"
fi
I=$((I + 1))
done
}
## locate device path
if [ "$(lspci | grep -c VGA)" -gt 1 ]
then
if [ -z "$card_name" ] && [ -z "$pci_id" ] ; then
error "Several GPUs are present and no GPU is specified"
error "Edit GPU_NAME or GPU_PCI_ID in '$config_file'"
exit 20
fi
if [ -z "$pci_id" ] ; then
pci_id=$(lspci | grep VGA | grep "$card_name" | cut -d ' ' -f1)
if [ "$(echo "$pci_id" | wc -l)" -gt 1 ] ; then
error "More than one name match for GPU"
exit 21
elif [ "$(echo "$pci_id" | wc -l)" -lt 1 ] ; then
error "No name match for GPU"
exit 22
fi
fi
if ! path=$(ls -l /sys/class/drm/card? | grep "$pci_id" | tr -s ' ' | cut -d ' ' -f9) ; then
error "Error finding pci device"
echo 23
fi
else
path=/sys/class/drm/card0
fi
hwmon=$path/device/hwmon/$(ls $path/device/hwmon)
if [ "$( printf "0x%08x\n" "$(cat /sys/module/amdgpu/parameters/ppfeaturemask)" )" != "0xffffffff" ] ; then
error "PP feature not enabled"
echo "Append 'amdgpu.ppfeaturemask=0xffffffff' to boot parameters to enable it" >&2
exit 11
fi
if [ ! -f "$path/device/pp_od_clk_voltage" ]
then
error "FATAL: overclocking file not found"
error "Either feature is not properly enabled or this isn't a Radeon GPU"
exit 12
fi
# read arguments
shift $((OPTIND-1))
if [ "$#" -gt 0 ]
then
if [ "$1" = "reset" ]; then
reset_stock
elif [ "$1" = "gpu" ]; then
if [ "$2" = "profile" ]; then
if [ -f "$profile_path/$3" ] ; then
set_profile gpu < "$profile_path/$3"
else
if ! cd "$profile_path" 2>/dev/null ; then
exit
fi
ls -p | grep -v /
fi
elif [ "$2" = "file" ]; then
set_profile gpu < "$3"
apply
else
echo "zgoc gpu <profile/file>"
fi
elif [ "$1" = "mem" ]; then
if [ "$2" = "profile" ]; then
if [ -f "$mem_path/$3" ] ; then
set_profile mem < "$mem_path/$3"
else
if ! cd "$mem_path" 2>/dev/null ; then
exit
fi
ls -p | grep -v /
fi
elif [ "$2" = "file" ]; then
set_profile mem < "$3"
apply
else
echo "zgoc mem <profile/file>"
fi
elif [ "$1" = "power" ] ; then
kernel_req 4 20
if [ "$2" = "profile" ]; then
if [ -f "$power_path/$3" ] ; then
apply_power "$(cat "$power_path/$3")"
else
if ! cd "$power_path" 2>/dev/null ; then
exit
fi
ls -p | grep -v /
fi
elif [ "$2" = "max" ]; then
apply_power "$(val_convert 6 0 < $hwmon/power1_cap_max)"
elif [ "$2" = "set" ]; then
apply_power "$3"
elif [ "$2" = "print" ]; then
echo $(val_convert 6 0 < $hwmon/power1_cap) W
else
echo "zgoc power <max/profile/set/print>"
fi
elif [ "$1" = "apply" ]; then
apply
elif [ "$1" = "memfix" ]; then
force_mem_state_high
elif [ "$1" = "print" ]; then
cat $path/device/pp_od_clk_voltage
else
usage
fi
else
usage
fi
exit 0