758 lines
18 KiB
Bash
Executable file
758 lines
18 KiB
Bash
Executable file
#!/bin/sh
|
|
#
|
|
# This is an utility script to manage Intel GPU frequencies.
|
|
# It can be used for debugging performance problems or trying to obtain a stable
|
|
# frequency while benchmarking.
|
|
#
|
|
# Note the Intel i915 GPU driver allows to change the minimum, maximum and boost
|
|
# frequencies in steps of 50 MHz via:
|
|
#
|
|
# /sys/class/drm/card<n>/<freq_info>
|
|
#
|
|
# Where <n> is the DRM card index and <freq_info> one of the following:
|
|
#
|
|
# - gt_max_freq_mhz (enforced maximum freq)
|
|
# - gt_min_freq_mhz (enforced minimum freq)
|
|
# - gt_boost_freq_mhz (enforced boost freq)
|
|
#
|
|
# The hardware capabilities can be accessed via:
|
|
#
|
|
# - gt_RP0_freq_mhz (supported maximum freq)
|
|
# - gt_RPn_freq_mhz (supported minimum freq)
|
|
# - gt_RP1_freq_mhz (most efficient freq)
|
|
#
|
|
# The current frequency can be read from:
|
|
# - gt_act_freq_mhz (the actual GPU freq)
|
|
# - gt_cur_freq_mhz (the last requested freq)
|
|
#
|
|
# Also note that in addition to GPU management, the script offers the
|
|
# possibility to adjust CPU operating frequencies. However, this is currently
|
|
# limited to just setting the maximum scaling frequency as percentage of the
|
|
# maximum frequency allowed by the hardware.
|
|
#
|
|
# Copyright (C) 2022 Collabora Ltd.
|
|
# Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
|
#
|
|
# SPDX-License-Identifier: MIT
|
|
#
|
|
|
|
#
|
|
# Constants
|
|
#
|
|
|
|
# GPU
|
|
DRM_FREQ_SYSFS_PATTERN="/sys/class/drm/card%d/gt_%s_freq_mhz"
|
|
ENF_FREQ_INFO="max min boost"
|
|
CAP_FREQ_INFO="RP0 RPn RP1"
|
|
ACT_FREQ_INFO="act cur"
|
|
THROTT_DETECT_SLEEP_SEC=2
|
|
THROTT_DETECT_PID_FILE_PATH=/tmp/thrott-detect.pid
|
|
|
|
# CPU
|
|
CPU_SYSFS_PREFIX=/sys/devices/system/cpu
|
|
CPU_PSTATE_SYSFS_PATTERN="${CPU_SYSFS_PREFIX}/intel_pstate/%s"
|
|
CPU_FREQ_SYSFS_PATTERN="${CPU_SYSFS_PREFIX}/cpu%s/cpufreq/%s_freq"
|
|
CAP_CPU_FREQ_INFO="cpuinfo_max cpuinfo_min"
|
|
ENF_CPU_FREQ_INFO="scaling_max scaling_min"
|
|
ACT_CPU_FREQ_INFO="scaling_cur"
|
|
|
|
#
|
|
# Global variables.
|
|
#
|
|
unset INTEL_DRM_CARD_INDEX
|
|
unset GET_ACT_FREQ GET_ENF_FREQ GET_CAP_FREQ
|
|
unset SET_MIN_FREQ SET_MAX_FREQ
|
|
unset MONITOR_FREQ
|
|
unset CPU_SET_MAX_FREQ
|
|
unset DETECT_THROTT
|
|
unset DRY_RUN
|
|
|
|
#
|
|
# Simple printf based stderr logger.
|
|
#
|
|
log() {
|
|
local msg_type=$1
|
|
|
|
shift
|
|
printf "%s: %s: " "${msg_type}" "${0##*/}" >&2
|
|
printf "$@" >&2
|
|
printf "\n" >&2
|
|
}
|
|
|
|
#
|
|
# Helper to print sysfs path for the given card index and freq info.
|
|
#
|
|
# arg1: Frequency info sysfs name, one of *_FREQ_INFO constants above
|
|
# arg2: Video card index, defaults to INTEL_DRM_CARD_INDEX
|
|
#
|
|
print_freq_sysfs_path() {
|
|
printf ${DRM_FREQ_SYSFS_PATTERN} "${2:-${INTEL_DRM_CARD_INDEX}}" "$1"
|
|
}
|
|
|
|
#
|
|
# Helper to set INTEL_DRM_CARD_INDEX for the first identified Intel video card.
|
|
#
|
|
identify_intel_gpu() {
|
|
local i=0 vendor path
|
|
|
|
while [ ${i} -lt 16 ]; do
|
|
[ -c "/dev/dri/card$i" ] || {
|
|
i=$((i + 1))
|
|
continue
|
|
}
|
|
|
|
path=$(print_freq_sysfs_path "" ${i})
|
|
path=${path%/*}/device/vendor
|
|
|
|
[ -r "${path}" ] && read vendor < "${path}" && \
|
|
[ "${vendor}" = "0x8086" ] && INTEL_DRM_CARD_INDEX=$i && return 0
|
|
|
|
i=$((i + 1))
|
|
done
|
|
|
|
return 1
|
|
}
|
|
|
|
#
|
|
# Read the specified freq info from sysfs.
|
|
#
|
|
# arg1: Flag (y/n) to also enable printing the freq info.
|
|
# arg2...: Frequency info sysfs name(s), see *_FREQ_INFO constants above
|
|
# return: Global variable(s) FREQ_${arg} containing the requested information
|
|
#
|
|
read_freq_info() {
|
|
local var val info path print=0 ret=0
|
|
|
|
[ "$1" = "y" ] && print=1
|
|
shift
|
|
|
|
while [ $# -gt 0 ]; do
|
|
info=$1
|
|
shift
|
|
var=FREQ_${info}
|
|
path=$(print_freq_sysfs_path "${info}")
|
|
|
|
[ -r ${path} ] && read ${var} < ${path} || {
|
|
log ERROR "Failed to read freq info from: %s" "${path}"
|
|
ret=1
|
|
continue
|
|
}
|
|
|
|
[ -n "${var}" ] || {
|
|
log ERROR "Got empty freq info from: %s" "${path}"
|
|
ret=1
|
|
continue
|
|
}
|
|
|
|
[ ${print} -eq 1 ] && {
|
|
eval val=\$${var}
|
|
printf "%6s: %4s MHz\n" "${info}" "${val}"
|
|
}
|
|
done
|
|
|
|
return ${ret}
|
|
}
|
|
|
|
#
|
|
# Display requested info.
|
|
#
|
|
print_freq_info() {
|
|
local req_freq
|
|
|
|
[ -n "${GET_CAP_FREQ}" ] && {
|
|
printf "* Hardware capabilities\n"
|
|
read_freq_info y ${CAP_FREQ_INFO}
|
|
printf "\n"
|
|
}
|
|
|
|
[ -n "${GET_ENF_FREQ}" ] && {
|
|
printf "* Enforcements\n"
|
|
read_freq_info y ${ENF_FREQ_INFO}
|
|
printf "\n"
|
|
}
|
|
|
|
[ -n "${GET_ACT_FREQ}" ] && {
|
|
printf "* Actual\n"
|
|
read_freq_info y ${ACT_FREQ_INFO}
|
|
printf "\n"
|
|
}
|
|
}
|
|
|
|
#
|
|
# Helper to print frequency value as requested by user via '-s, --set' option.
|
|
# arg1: user requested freq value
|
|
#
|
|
compute_freq_set() {
|
|
local val
|
|
|
|
case "$1" in
|
|
+)
|
|
val=${FREQ_RP0}
|
|
;;
|
|
-)
|
|
val=${FREQ_RPn}
|
|
;;
|
|
*%)
|
|
val=$((${1%?} * ${FREQ_RP0} / 100))
|
|
# Adjust freq to comply with 50 MHz increments
|
|
val=$((val / 50 * 50))
|
|
;;
|
|
*[!0-9]*)
|
|
log ERROR "Cannot set freq to invalid value: %s" "$1"
|
|
return 1
|
|
;;
|
|
"")
|
|
log ERROR "Cannot set freq to unspecified value"
|
|
return 1
|
|
;;
|
|
*)
|
|
# Adjust freq to comply with 50 MHz increments
|
|
val=$(($1 / 50 * 50))
|
|
;;
|
|
esac
|
|
|
|
printf "%s" "${val}"
|
|
}
|
|
|
|
#
|
|
# Helper for set_freq().
|
|
#
|
|
set_freq_max() {
|
|
log INFO "Setting GPU max freq to %s MHz" "${SET_MAX_FREQ}"
|
|
|
|
read_freq_info n min || return $?
|
|
|
|
[ ${SET_MAX_FREQ} -gt ${FREQ_RP0} ] && {
|
|
log ERROR "Cannot set GPU max freq (%s) to be greater than hw max freq (%s)" \
|
|
"${SET_MAX_FREQ}" "${FREQ_RP0}"
|
|
return 1
|
|
}
|
|
|
|
[ ${SET_MAX_FREQ} -lt ${FREQ_RPn} ] && {
|
|
log ERROR "Cannot set GPU max freq (%s) to be less than hw min freq (%s)" \
|
|
"${SET_MIN_FREQ}" "${FREQ_RPn}"
|
|
return 1
|
|
}
|
|
|
|
[ ${SET_MAX_FREQ} -lt ${FREQ_min} ] && {
|
|
log ERROR "Cannot set GPU max freq (%s) to be less than min freq (%s)" \
|
|
"${SET_MAX_FREQ}" "${FREQ_min}"
|
|
return 1
|
|
}
|
|
|
|
[ -z "${DRY_RUN}" ] || return 0
|
|
|
|
printf "%s" ${SET_MAX_FREQ} | tee $(print_freq_sysfs_path max) \
|
|
$(print_freq_sysfs_path boost) > /dev/null
|
|
[ $? -eq 0 ] || {
|
|
log ERROR "Failed to set GPU max frequency"
|
|
return 1
|
|
}
|
|
}
|
|
|
|
#
|
|
# Helper for set_freq().
|
|
#
|
|
set_freq_min() {
|
|
log INFO "Setting GPU min freq to %s MHz" "${SET_MIN_FREQ}"
|
|
|
|
read_freq_info n max || return $?
|
|
|
|
[ ${SET_MIN_FREQ} -gt ${FREQ_max} ] && {
|
|
log ERROR "Cannot set GPU min freq (%s) to be greater than max freq (%s)" \
|
|
"${SET_MIN_FREQ}" "${FREQ_max}"
|
|
return 1
|
|
}
|
|
|
|
[ ${SET_MIN_FREQ} -lt ${FREQ_RPn} ] && {
|
|
log ERROR "Cannot set GPU min freq (%s) to be less than hw min freq (%s)" \
|
|
"${SET_MIN_FREQ}" "${FREQ_RPn}"
|
|
return 1
|
|
}
|
|
|
|
[ -z "${DRY_RUN}" ] || return 0
|
|
|
|
printf "%s" ${SET_MIN_FREQ} > $(print_freq_sysfs_path min)
|
|
[ $? -eq 0 ] || {
|
|
log ERROR "Failed to set GPU min frequency"
|
|
return 1
|
|
}
|
|
}
|
|
|
|
#
|
|
# Set min or max or both GPU frequencies to the user indicated values.
|
|
#
|
|
set_freq() {
|
|
# Get hw max & min frequencies
|
|
read_freq_info n RP0 RPn || return $?
|
|
|
|
[ -z "${SET_MAX_FREQ}" ] || {
|
|
SET_MAX_FREQ=$(compute_freq_set "${SET_MAX_FREQ}")
|
|
[ -z "${SET_MAX_FREQ}" ] && return 1
|
|
}
|
|
|
|
[ -z "${SET_MIN_FREQ}" ] || {
|
|
SET_MIN_FREQ=$(compute_freq_set "${SET_MIN_FREQ}")
|
|
[ -z "${SET_MIN_FREQ}" ] && return 1
|
|
}
|
|
|
|
#
|
|
# Ensure correct operation order, to avoid setting min freq
|
|
# to a value which is larger than max freq.
|
|
#
|
|
# E.g.:
|
|
# crt_min=crt_max=600; new_min=new_max=700
|
|
# > operation order: max=700; min=700
|
|
#
|
|
# crt_min=crt_max=600; new_min=new_max=500
|
|
# > operation order: min=500; max=500
|
|
#
|
|
if [ -n "${SET_MAX_FREQ}" ] && [ -n "${SET_MIN_FREQ}" ]; then
|
|
[ ${SET_MAX_FREQ} -lt ${SET_MIN_FREQ} ] && {
|
|
log ERROR "Cannot set GPU max freq to be less than min freq"
|
|
return 1
|
|
}
|
|
|
|
read_freq_info n min || return $?
|
|
|
|
if [ ${SET_MAX_FREQ} -lt ${FREQ_min} ]; then
|
|
set_freq_min || return $?
|
|
set_freq_max
|
|
else
|
|
set_freq_max || return $?
|
|
set_freq_min
|
|
fi
|
|
elif [ -n "${SET_MAX_FREQ}" ]; then
|
|
set_freq_max
|
|
elif [ -n "${SET_MIN_FREQ}" ]; then
|
|
set_freq_min
|
|
else
|
|
log "Unexpected call to set_freq()"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
#
|
|
# Helper for detect_throttling().
|
|
#
|
|
get_thrott_detect_pid() {
|
|
[ -e ${THROTT_DETECT_PID_FILE_PATH} ] || return 0
|
|
|
|
local pid
|
|
read pid < ${THROTT_DETECT_PID_FILE_PATH} || {
|
|
log ERROR "Failed to read pid from: %s" "${THROTT_DETECT_PID_FILE_PATH}"
|
|
return 1
|
|
}
|
|
|
|
local proc_path=/proc/${pid:-invalid}/cmdline
|
|
[ -r ${proc_path} ] && grep -qs "${0##*/}" ${proc_path} && {
|
|
printf "%s" "${pid}"
|
|
return 0
|
|
}
|
|
|
|
# Remove orphaned PID file
|
|
rm -rf ${THROTT_DETECT_PID_FILE_PATH}
|
|
return 1
|
|
}
|
|
|
|
#
|
|
# Control detection and reporting of GPU throttling events.
|
|
# arg1: start - run throttle detector in background
|
|
# stop - stop throttle detector process, if any
|
|
# status - verify if throttle detector is running
|
|
#
|
|
detect_throttling() {
|
|
local pid
|
|
pid=$(get_thrott_detect_pid)
|
|
|
|
case "$1" in
|
|
status)
|
|
printf "Throttling detector is "
|
|
[ -z "${pid}" ] && printf "not running\n" && return 0
|
|
printf "running (pid=%s)\n" ${pid}
|
|
;;
|
|
|
|
stop)
|
|
[ -z "${pid}" ] && return 0
|
|
|
|
log INFO "Stopping throttling detector (pid=%s)" "${pid}"
|
|
kill ${pid}; sleep 1; kill -0 ${pid} 2>/dev/null && kill -9 ${pid}
|
|
rm -rf ${THROTT_DETECT_PID_FILE_PATH}
|
|
;;
|
|
|
|
start)
|
|
[ -n "${pid}" ] && {
|
|
log WARN "Throttling detector is already running (pid=%s)" ${pid}
|
|
return 0
|
|
}
|
|
|
|
(
|
|
read_freq_info n RPn || exit $?
|
|
|
|
while true; do
|
|
sleep ${THROTT_DETECT_SLEEP_SEC}
|
|
read_freq_info n act min cur || exit $?
|
|
|
|
#
|
|
# The throttling seems to occur when act freq goes below min.
|
|
# However, it's necessary to exclude the idle states, where
|
|
# act freq normally reaches RPn and cur goes below min.
|
|
#
|
|
[ ${FREQ_act} -lt ${FREQ_min} ] && \
|
|
[ ${FREQ_act} -gt ${FREQ_RPn} ] && \
|
|
[ ${FREQ_cur} -ge ${FREQ_min} ] && \
|
|
printf "GPU throttling detected: act=%s min=%s cur=%s RPn=%s\n" \
|
|
${FREQ_act} ${FREQ_min} ${FREQ_cur} ${FREQ_RPn}
|
|
done
|
|
) &
|
|
|
|
pid=$!
|
|
log INFO "Started GPU throttling detector (pid=%s)" ${pid}
|
|
|
|
printf "%s\n" ${pid} > ${THROTT_DETECT_PID_FILE_PATH} || \
|
|
log WARN "Failed to write throttle detector PID file"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
#
|
|
# Retrieve the list of online CPUs.
|
|
#
|
|
get_online_cpus() {
|
|
local path cpu_index
|
|
|
|
printf "0"
|
|
for path in $(grep 1 ${CPU_SYSFS_PREFIX}/cpu*/online); do
|
|
cpu_index=${path##*/cpu}
|
|
printf " %s" ${cpu_index%%/*}
|
|
done
|
|
}
|
|
|
|
#
|
|
# Helper to print sysfs path for the given CPU index and freq info.
|
|
#
|
|
# arg1: Frequency info sysfs name, one of *_CPU_FREQ_INFO constants above
|
|
# arg2: CPU index
|
|
#
|
|
print_cpu_freq_sysfs_path() {
|
|
printf ${CPU_FREQ_SYSFS_PATTERN} "$2" "$1"
|
|
}
|
|
|
|
#
|
|
# Read the specified CPU freq info from sysfs.
|
|
#
|
|
# arg1: CPU index
|
|
# arg2: Flag (y/n) to also enable printing the freq info.
|
|
# arg3...: Frequency info sysfs name(s), see *_CPU_FREQ_INFO constants above
|
|
# return: Global variable(s) CPU_FREQ_${arg} containing the requested information
|
|
#
|
|
read_cpu_freq_info() {
|
|
local var val info path cpu_index print=0 ret=0
|
|
|
|
cpu_index=$1
|
|
[ "$2" = "y" ] && print=1
|
|
shift 2
|
|
|
|
while [ $# -gt 0 ]; do
|
|
info=$1
|
|
shift
|
|
var=CPU_FREQ_${info}
|
|
path=$(print_cpu_freq_sysfs_path "${info}" ${cpu_index})
|
|
|
|
[ -r ${path} ] && read ${var} < ${path} || {
|
|
log ERROR "Failed to read CPU freq info from: %s" "${path}"
|
|
ret=1
|
|
continue
|
|
}
|
|
|
|
[ -n "${var}" ] || {
|
|
log ERROR "Got empty CPU freq info from: %s" "${path}"
|
|
ret=1
|
|
continue
|
|
}
|
|
|
|
[ ${print} -eq 1 ] && {
|
|
eval val=\$${var}
|
|
printf "%6s: %4s Hz\n" "${info}" "${val}"
|
|
}
|
|
done
|
|
|
|
return ${ret}
|
|
}
|
|
|
|
#
|
|
# Helper to print freq. value as requested by user via '--cpu-set-max' option.
|
|
# arg1: user requested freq value
|
|
#
|
|
compute_cpu_freq_set() {
|
|
local val
|
|
|
|
case "$1" in
|
|
+)
|
|
val=${CPU_FREQ_cpuinfo_max}
|
|
;;
|
|
-)
|
|
val=${CPU_FREQ_cpuinfo_min}
|
|
;;
|
|
*%)
|
|
val=$((${1%?} * ${CPU_FREQ_cpuinfo_max} / 100))
|
|
;;
|
|
*[!0-9]*)
|
|
log ERROR "Cannot set CPU freq to invalid value: %s" "$1"
|
|
return 1
|
|
;;
|
|
"")
|
|
log ERROR "Cannot set CPU freq to unspecified value"
|
|
return 1
|
|
;;
|
|
*)
|
|
log ERROR "Cannot set CPU freq to custom value; use +, -, or % instead"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
printf "%s" "${val}"
|
|
}
|
|
|
|
#
|
|
# Adjust CPU max scaling frequency.
|
|
#
|
|
set_cpu_freq_max() {
|
|
local target_freq res=0
|
|
case "${CPU_SET_MAX_FREQ}" in
|
|
+)
|
|
target_freq=100
|
|
;;
|
|
-)
|
|
target_freq=1
|
|
;;
|
|
*%)
|
|
target_freq=${CPU_SET_MAX_FREQ%?}
|
|
;;
|
|
*)
|
|
log ERROR "Invalid CPU freq"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
local pstate_info=$(printf "${CPU_PSTATE_SYSFS_PATTERN}" max_perf_pct)
|
|
[ -e "${pstate_info}" ] && {
|
|
log INFO "Setting intel_pstate max perf to %s" "${target_freq}%"
|
|
printf "%s" "${target_freq}" > "${pstate_info}"
|
|
[ $? -eq 0 ] || {
|
|
log ERROR "Failed to set intel_pstate max perf"
|
|
res=1
|
|
}
|
|
}
|
|
|
|
local cpu_index
|
|
for cpu_index in $(get_online_cpus); do
|
|
read_cpu_freq_info ${cpu_index} n ${CAP_CPU_FREQ_INFO} || { res=$?; continue; }
|
|
|
|
target_freq=$(compute_cpu_freq_set "${CPU_SET_MAX_FREQ}")
|
|
[ -z "${target_freq}" ] && { res=$?; continue; }
|
|
|
|
log INFO "Setting CPU%s max scaling freq to %s Hz" ${cpu_index} "${target_freq}"
|
|
[ -n "${DRY_RUN}" ] && continue
|
|
|
|
printf "%s" ${target_freq} > $(print_cpu_freq_sysfs_path scaling_max ${cpu_index})
|
|
[ $? -eq 0 ] || {
|
|
res=1
|
|
log ERROR "Failed to set CPU%s max scaling frequency" ${cpu_index}
|
|
}
|
|
done
|
|
|
|
return ${res}
|
|
}
|
|
|
|
#
|
|
# Show help message.
|
|
#
|
|
print_usage() {
|
|
cat <<EOF
|
|
Usage: ${0##*/} [OPTION]...
|
|
|
|
A script to manage Intel GPU frequencies. Can be used for debugging performance
|
|
problems or trying to obtain a stable frequency while benchmarking.
|
|
|
|
Note Intel GPUs only accept specific frequencies, usually multiples of 50 MHz.
|
|
|
|
Options:
|
|
-g, --get [act|enf|cap|all]
|
|
Get frequency information: active (default), enforced,
|
|
hardware capabilities or all of them.
|
|
|
|
-s, --set [{min|max}=]{FREQUENCY[%]|+|-}
|
|
Set min or max frequency to the given value (MHz).
|
|
Append '%' to interpret FREQUENCY as % of hw max.
|
|
Use '+' or '-' to set frequency to hardware max or min.
|
|
Omit min/max prefix to set both frequencies.
|
|
|
|
-r, --reset Reset frequencies to hardware defaults.
|
|
|
|
-m, --monitor [act|enf|cap|all]
|
|
Monitor the indicated frequencies via 'watch' utility.
|
|
See '-g, --get' option for more details.
|
|
|
|
-d|--detect-thrott [start|stop|status]
|
|
Start (default operation) the throttling detector
|
|
as a background process. Use 'stop' or 'status' to
|
|
terminate the detector process or verify its status.
|
|
|
|
--cpu-set-max [FREQUENCY%|+|-}
|
|
Set CPU max scaling frequency as % of hw max.
|
|
Use '+' or '-' to set frequency to hardware max or min.
|
|
|
|
-r, --reset Reset frequencies to hardware defaults.
|
|
|
|
--dry-run See what the script will do without applying any
|
|
frequency changes.
|
|
|
|
-h, --help Display this help text and exit.
|
|
EOF
|
|
}
|
|
|
|
#
|
|
# Parse user input for '-g, --get' option.
|
|
# Returns 0 if a value has been provided, otherwise 1.
|
|
#
|
|
parse_option_get() {
|
|
local ret=0
|
|
|
|
case "$1" in
|
|
act) GET_ACT_FREQ=1;;
|
|
enf) GET_ENF_FREQ=1;;
|
|
cap) GET_CAP_FREQ=1;;
|
|
all) GET_ACT_FREQ=1; GET_ENF_FREQ=1; GET_CAP_FREQ=1;;
|
|
-*|"")
|
|
# No value provided, using default.
|
|
GET_ACT_FREQ=1
|
|
ret=1
|
|
;;
|
|
*)
|
|
print_usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
return ${ret}
|
|
}
|
|
|
|
#
|
|
# Validate user input for '-s, --set' option.
|
|
# arg1: input value to be validated
|
|
# arg2: optional flag indicating input is restricted to %
|
|
#
|
|
validate_option_set() {
|
|
case "$1" in
|
|
+|-|[0-9]%|[0-9][0-9]%)
|
|
return 0
|
|
;;
|
|
*[!0-9]*|"")
|
|
print_usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
[ -z "$2" ] || { print_usage; exit 1; }
|
|
}
|
|
|
|
#
|
|
# Parse script arguments.
|
|
#
|
|
[ $# -eq 0 ] && { print_usage; exit 1; }
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
-g|--get)
|
|
parse_option_get "$2" && shift
|
|
;;
|
|
|
|
-s|--set)
|
|
shift
|
|
case "$1" in
|
|
min=*)
|
|
SET_MIN_FREQ=${1#min=}
|
|
validate_option_set "${SET_MIN_FREQ}"
|
|
;;
|
|
max=*)
|
|
SET_MAX_FREQ=${1#max=}
|
|
validate_option_set "${SET_MAX_FREQ}"
|
|
;;
|
|
*)
|
|
SET_MIN_FREQ=$1
|
|
validate_option_set "${SET_MIN_FREQ}"
|
|
SET_MAX_FREQ=${SET_MIN_FREQ}
|
|
;;
|
|
esac
|
|
;;
|
|
|
|
-r|--reset)
|
|
RESET_FREQ=1
|
|
SET_MIN_FREQ="-"
|
|
SET_MAX_FREQ="+"
|
|
;;
|
|
|
|
-m|--monitor)
|
|
MONITOR_FREQ=act
|
|
parse_option_get "$2" && MONITOR_FREQ=$2 && shift
|
|
;;
|
|
|
|
-d|--detect-thrott)
|
|
DETECT_THROTT=start
|
|
case "$2" in
|
|
start|stop|status)
|
|
DETECT_THROTT=$2
|
|
shift
|
|
;;
|
|
esac
|
|
;;
|
|
|
|
--cpu-set-max)
|
|
shift
|
|
CPU_SET_MAX_FREQ=$1
|
|
validate_option_set "${CPU_SET_MAX_FREQ}" restricted
|
|
;;
|
|
|
|
--dry-run)
|
|
DRY_RUN=1
|
|
;;
|
|
|
|
-h|--help)
|
|
print_usage
|
|
exit 0
|
|
;;
|
|
|
|
*)
|
|
print_usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
shift
|
|
done
|
|
|
|
#
|
|
# Main
|
|
#
|
|
RET=0
|
|
|
|
identify_intel_gpu || {
|
|
log INFO "No Intel GPU detected"
|
|
exit 0
|
|
}
|
|
|
|
[ -n "${SET_MIN_FREQ}${SET_MAX_FREQ}" ] && { set_freq || RET=$?; }
|
|
print_freq_info
|
|
|
|
[ -n "${DETECT_THROTT}" ] && detect_throttling ${DETECT_THROTT}
|
|
|
|
[ -n "${CPU_SET_MAX_FREQ}" ] && { set_cpu_freq_max || RET=$?; }
|
|
|
|
[ -n "${MONITOR_FREQ}" ] && {
|
|
log INFO "Entering frequency monitoring mode"
|
|
sleep 2
|
|
exec watch -d -n 1 "$0" -g "${MONITOR_FREQ}"
|
|
}
|
|
|
|
exit ${RET}
|