I am batman
This commit is contained in:
292
scripts/gpuinfo.sh
Executable file
292
scripts/gpuinfo.sh
Executable file
@@ -0,0 +1,292 @@
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2312
|
||||
# shellcheck disable=SC1090
|
||||
scrDir=`dirname "$(realpath "$0")"`
|
||||
gpuQ="/tmp/hyprdots-${UID}-gpuinfo-query"
|
||||
tired=false
|
||||
[[ " $* " =~ " tired " ]] && ! grep -q "tired" "${gpuQ}" && echo "tired=true" >>"${gpuQ}"
|
||||
[[ " $* " =~ " no_emoji " ]] && ! grep -q "NO_EMOJI" "${gpuQ}" && echo "NO_EMOJI=1" >>"${gpuQ}"
|
||||
|
||||
if [[ ! " $* " =~ " startup " ]]; then
|
||||
gpuQ="${gpuQ}$2"
|
||||
fi
|
||||
detect() { # Auto detect Gpu used by Hyprland(declared using env = WLR_DRM_DEVICES) Sophisticated?
|
||||
card=$(echo "${WLR_DRM_DEVICES}" | cut -d':' -f1 | cut -d'/' -f4)
|
||||
# shellcheck disable=SC2010
|
||||
slot_number=$(ls -l /dev/dri/by-path/ | grep "${card}" | awk -F'pci-0000:|-card' '{print $2}')
|
||||
vendor_id=$(lspci -nn -s "${slot_number}" )
|
||||
declare -A vendors=(["10de"]="nvidia" ["8086"]="intel" ["1002"]="amd")
|
||||
for vendor in "${!vendors[@]}"; do
|
||||
if [[ ${vendor_id} == *"${vendor}"* ]]; then
|
||||
initGPU="${vendors[${vendor}]}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ -n ${initGPU} ]]; then
|
||||
$0 --use "${initGPU}" startup
|
||||
fi
|
||||
}
|
||||
|
||||
query() {
|
||||
nvidia_flag=0 amd_flag=0 intel_flag=0
|
||||
touch "${gpuQ}"
|
||||
|
||||
if lsmod | grep -q 'nouveau'; then
|
||||
echo "nvidia_gpu=\"Linux\"" >>"${gpuQ}" #? Incase If nouveau is installed
|
||||
echo "nvidia_flag=1 # Using nouveau an open-source nvidia driver" >>"${gpuQ}"
|
||||
elif command -v nvidia-smi &> /dev/null; then
|
||||
nvidia_gpu=$(nvidia-smi --query-gpu=gpu_name --format=csv,noheader,nounits | head -n 1)
|
||||
if [[ -n "${nvidia_gpu}" ]] ; then # Check for NVIDIA GPU
|
||||
if [[ "${nvidia_gpu}" == *"NVIDIA-SMI has failed"* ]]; then #? Second Layer for dGPU
|
||||
echo "nvidia_flag=0 # NVIDIA-SMI has failed" >> "${gpuQ}"
|
||||
else
|
||||
nvidia_address=$(lspci | grep -Ei "VGA|3D" | grep -i "${nvidia_gpu/NVIDIA /}" | cut -d' ' -f1)
|
||||
{ echo "nvidia_address=\"${nvidia_address}\""
|
||||
echo "nvidia_gpu=\"${nvidia_gpu/NVIDIA /}\""
|
||||
echo "nvidia_flag=1"
|
||||
} >> "${gpuQ}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if lspci -nn | grep -E "(VGA|3D)" | grep -iq "1002"; then
|
||||
amd_gpu="$(lspci -nn | grep -Ei "VGA|3D" | grep -m 1 "1002" | awk -F'Advanced Micro Devices, Inc. ' '{gsub(/ *\[[^\]]*\]/,""); gsub(/ *\([^)]*\)/,""); print $2}')"
|
||||
amd_address=$(lspci | grep -Ei "VGA|3D" | grep -i "${amd_gpu}" | cut -d' ' -f1)
|
||||
{ echo "amd_address=\"${amd_address}\""
|
||||
echo "amd_flag=1" # Check for Amd GPU
|
||||
echo "amd_gpu=\"${amd_gpu}\""
|
||||
} >> "${gpuQ}";fi
|
||||
|
||||
if lspci -nn | grep -E "(VGA|3D)" | grep -iq "8086"; then
|
||||
intel_gpu="$(lspci -nn | grep -Ei "VGA|3D" | grep -m 1 "8086" | awk -F'Intel Corporation ' '{gsub(/ *\[[^\]]*\]/,""); gsub(/ *\([^)]*\)/,""); print $2}')"
|
||||
intel_address=$(lspci | grep -Ei "VGA|3D" | grep -i "${intel_gpu}" | cut -d' ' -f1)
|
||||
{ echo "intel_address=\"${intel_address}\""
|
||||
echo "intel_flag=1" # Check for Intel GPU
|
||||
echo "intel_gpu=\"${intel_gpu}\""
|
||||
} >>"${gpuQ}"; fi
|
||||
|
||||
if ! grep -q "prioGPU=" "${gpuQ}" && [[ -n "${WLR_DRM_DEVICES}" ]]; then
|
||||
trap detect EXIT
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
toggle() {
|
||||
if [[ -n "$1" ]]; then
|
||||
next_prioGPU="$1_flag"
|
||||
else
|
||||
# Initialize gpu_flags and prioGPU if they don't exist
|
||||
if ! grep -q "gpu_flags=" "${gpuQ}"; then
|
||||
gpu_flags=$(grep "flag=1" "${gpuQ}" | cut -d '=' -f 1 | tr '\n' ' ' | tr -d '#')
|
||||
echo "" >> "${gpuQ}"
|
||||
echo "gpu_flags=\"${gpu_flags[*]}\"" >> "${gpuQ}"
|
||||
fi
|
||||
|
||||
if ! grep -q "prioGPU=" "${gpuQ}"; then
|
||||
gpu_flags=$(grep "gpu_flags=" "${gpuQ}" | cut -d'=' -f 2)
|
||||
initGPU=$(echo "${gpu_flags}" | cut -d ' ' -f 1)
|
||||
echo "prioGPU=${initGPU}" >> "${gpuQ}"
|
||||
fi
|
||||
mapfile -t anchor < <(grep "flag=1" "${gpuQ}" | cut -d '=' -f 1)
|
||||
prioGPU=$(grep "prioGPU=" "${gpuQ}" | cut -d'=' -f 2) # Get the current prioGPU from the file
|
||||
# Find the index of the current prioGPU in the anchor array
|
||||
for index in "${!anchor[@]}"; do
|
||||
if [[ "${anchor[${index}]}" = "${prioGPU}" ]]; then
|
||||
current_index=${index}
|
||||
fi
|
||||
done
|
||||
next_index=$(( (current_index + 1) % ${#anchor[@]} ))
|
||||
next_prioGPU=${anchor[${next_index}]#\#}
|
||||
fi
|
||||
|
||||
# Set the next prioGPU and remove the '#' character
|
||||
sed -i 's/^\(nvidia_flag=1\|amd_flag=1\|intel_flag=1\)/#\1/' "${gpuQ}" # Comment out all the gpu flags in the file
|
||||
sed -i "s/^#${next_prioGPU}/${next_prioGPU}/" "${gpuQ}" # Uncomment the next prioGPU in the file
|
||||
sed -i "s/prioGPU=${prioGPU}/prioGPU=${next_prioGPU}/" "${gpuQ}" # Update the prioGPU in the file
|
||||
}
|
||||
|
||||
# Thee shalt find the greatest one,
|
||||
# He who not more than the chosen one
|
||||
map_floor() {
|
||||
|
||||
# From the depths of the string, words arise,
|
||||
# Keys in pairs, a treasure in disguise.
|
||||
IFS=', ' read -r -a pairs <<< "$1"
|
||||
|
||||
# If the final token stands alone and bold,
|
||||
# Declare it the default, its worth untold.
|
||||
if [[ ${pairs[-1]} != *":"* ]]; then
|
||||
def_val="${pairs[-1]}"
|
||||
unset 'pairs[${#pairs[@]}-1]'
|
||||
fi
|
||||
|
||||
# Scans the map, a peak it seeks,
|
||||
# The highest passed, the value speaks.
|
||||
for pair in "${pairs[@]}"; do
|
||||
IFS=':' read -r key value <<< "$pair"
|
||||
|
||||
# Behold! Thou holds the secrets they seek,
|
||||
# Declare it and silence the whispers unique.
|
||||
if [ ${2%%.*} -gt $key ]; then
|
||||
echo "$value"
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
# On this lonely shore, where silence dwells
|
||||
# Even the waves, echoes words unheard
|
||||
[ -n "$def_val" ] && echo $def_val || echo " "
|
||||
}
|
||||
|
||||
generate_json() {
|
||||
# Generate glyphs
|
||||
icons=$(echo "$(map_floor "$util_lv" $utilization)$(map_floor "$temp_lv" $temperature)")
|
||||
speedo=$(echo ${icons:0:1})
|
||||
thermo=$(echo ${icons:1:1})
|
||||
emoji=$(echo ${icons:2})
|
||||
|
||||
local json="{\"text\":\"${thermo} ${temperature}°C\", \"tooltip\":\"${primary_gpu}\n${thermo} Temperature: ${temperature}°C ${emoji}"
|
||||
#? Soon Add Something incase needed.
|
||||
declare -A tooltip_parts
|
||||
if [[ -n "${utilization}" ]]; then tooltip_parts["\n$speedo Utilization: "]="${utilization}%" ; fi
|
||||
if [[ -n "${current_clock_speed}" ]] && [[ -n "${max_clock_speed}" ]]; then tooltip_parts["\n Clock Speed: "]="${current_clock_speed}/${max_clock_speed} MHz" ; fi
|
||||
if [[ -n "${gpu_load}" ]]; then tooltip_parts["\n$speedo Utilization: "]="${gpu_load}%" ; fi
|
||||
if [[ -n "${core_clock}" ]]; then tooltip_parts["\n Clock Speed: "]="${core_clock} MHz" ;fi
|
||||
if [[ -n "${power_usage}" ]]; then if [[ -n "${power_limit}" ]]; then
|
||||
tooltip_parts["\n Power Usage: "]="${power_usage}/${power_limit} W"
|
||||
else
|
||||
tooltip_parts["\n Power Usage: "]="${power_usage} W"
|
||||
fi
|
||||
fi
|
||||
if [[ -n "${power_discharge}" ]] && [[ "${power_discharge}" != "0" ]]; then tooltip_parts["\n Power Discharge: "]="${power_discharge} W" ;fi
|
||||
|
||||
for key in "${!tooltip_parts[@]}"; do
|
||||
local value="${tooltip_parts[${key}]}"
|
||||
if [[ -n "${value}" && "${value}" =~ [a-zA-Z0-9] ]]; then
|
||||
json+="${key}${value}"
|
||||
fi
|
||||
done
|
||||
json="${json}\"}"
|
||||
echo "${json}"
|
||||
}
|
||||
|
||||
general_query() { # Function to get temperature from 'sensors'
|
||||
filter=''
|
||||
temperature=$(sensors | ${filter} grep -m 1 -E "(edge|Package id.*|another keyword)" | awk -F ':' '{print int($2)}') #! We can get json data from sensors too
|
||||
# gpu_load=$()
|
||||
# core_clock=$()
|
||||
for file in /sys/class/power_supply/BAT*/power_now; do
|
||||
[[ -f "${file}" ]] && power_discharge=$(awk '{print $1*10^-6 ""}' "${file}") && break
|
||||
done
|
||||
[[ -z "${power_discharge}" ]] && for file in /sys/class/power_supply/BAT*/current_now; do
|
||||
[[ -e "${file}" ]] && power_discharge=$(awk -v current="$(cat "${file}")" -v voltage="$(cat "${file/current_now/voltage_now}")" 'BEGIN {print (current * voltage) / 10^12 ""}') && break
|
||||
done
|
||||
# power_limit=$()
|
||||
utilization=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1" "}')
|
||||
current_clock_speed=$(awk '{sum += $1; n++} END {if (n > 0) print sum / n / 1000 ""}' /sys/devices/system/cpu/cpufreq/policy*/scaling_cur_freq)
|
||||
max_clock_speed=$(awk '{print $1/1000}' /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq)
|
||||
}
|
||||
|
||||
intel_GPU() { #? Function to query basic intel GPU
|
||||
primary_gpu="Intel ${intel_gpu}"
|
||||
general_query
|
||||
}
|
||||
|
||||
nvidia_GPU() { #? Function to query Nvidia GPU
|
||||
primary_gpu="NVIDIA ${nvidia_gpu}"
|
||||
if [[ "${nvidia_gpu}" == "Linux" ]]; then general_query ; return ; fi #? Open source driver
|
||||
#? Tired Flag for not using nvidia-smi if GPU is in suspend mode.
|
||||
if ${tired}; then is_suspend="$(cat /sys/bus/pci/devices/0000:"${nvidia_address}"/power/runtime_status)"
|
||||
if [[ ${is_suspend} == *"suspend"* ]]; then
|
||||
printf '{"text":"", "tooltip":"%s ⏾ Suspended mode"}' "${primary_gpu}"; exit ;fi
|
||||
fi
|
||||
gpu_info=$(nvidia-smi --query-gpu=temperature.gpu,utilization.gpu,clocks.current.graphics,clocks.max.graphics,power.draw,power.limit --format=csv,noheader,nounits)
|
||||
# Split the comma-separated values into an array
|
||||
IFS=',' read -ra gpu_data <<< "${gpu_info}"
|
||||
# Extract individual values
|
||||
temperature="${gpu_data[0]// /}"
|
||||
utilization="${gpu_data[1]// /}"
|
||||
current_clock_speed="${gpu_data[2]// /}"
|
||||
max_clock_speed="${gpu_data[3]// /}"
|
||||
power_usage="${gpu_data[4]// /}"
|
||||
power_limit="${gpu_data[5]// /}"
|
||||
}
|
||||
|
||||
amd_GPU() { #? Function to query amd GPU
|
||||
primary_gpu="AMD ${amd_gpu}"
|
||||
# Execute the AMD GPU Python script and use its output
|
||||
amd_output=$(python3 ${scrDir}/amdgpu.py)
|
||||
if [[ ! ${amd_output} == *"No AMD GPUs detected."* ]] && [[ ! ${amd_output} == *"Unknown query failure"* ]]; then
|
||||
# Extract GPU Temperature, GPU Load, GPU Core Clock, and GPU Power Usage from amd_output
|
||||
temperature=$(echo "${amd_output}" | jq -r '.["GPU Temperature"]' | sed 's/°C//')
|
||||
gpu_load=$(echo "${amd_output}" | jq -r '.["GPU Load"]' | sed 's/%//')
|
||||
core_clock=$(echo "${amd_output}" | jq -r '.["GPU Core Clock"]' | sed 's/ GHz//;s/ MHz//')
|
||||
power_usage=$(echo "${amd_output}" | jq -r '.["GPU Power Usage"]' | sed 's/ Watts//')
|
||||
|
||||
|
||||
else
|
||||
general_query
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ ! -f "${gpuQ}" ]]; then
|
||||
query ; echo -e "Initialized Variable:\n$(cat "${gpuQ}")\n\nReboot or '$0 --reset' to RESET Variables"
|
||||
fi
|
||||
source "${gpuQ}"
|
||||
case "$1" in
|
||||
"--toggle"|"-t")
|
||||
toggle
|
||||
echo -e "Sensor: ${next_prioGPU} GPU" | sed 's/_flag//g'
|
||||
exit
|
||||
;;
|
||||
"--use"|"-u")
|
||||
toggle "$2"
|
||||
;;
|
||||
"--reset"|"-rf")
|
||||
rm -fr "${gpuQ}"*
|
||||
query
|
||||
echo -e "Initialized Variable:\n$(cat "${gpuQ}" || true)\n\nReboot or '$0 --reset' to RESET Variables"
|
||||
exit
|
||||
;;
|
||||
*"-"*)
|
||||
gpu_flags=$(grep "flag=1" "${gpuQ}" | cut -d '=' -f 1 | tr '\n' ' ' | tr -d '#')
|
||||
cat << EOF
|
||||
|
||||
Available GPU: ${gpu_flags//_flag/}
|
||||
[options]
|
||||
--toggle * Toggle available GPU
|
||||
--use [GPU] * Only call the specified GPU (Useful for adding specific GPU on waybar)
|
||||
--reset * Remove & restart all query
|
||||
|
||||
[flags]
|
||||
tired * Adding this option will not query nvidia-smi if gpu is in suspend mode
|
||||
startup * Useful if you want a certain GPU to be set at startup
|
||||
no_emoji * Use glyphs instead of emoji
|
||||
|
||||
* If ${USER} declared env = WLR_DRM_DEVICES on hyprland then use this as the primary GPU
|
||||
EOF
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
|
||||
# Define glyphs
|
||||
if [[ $NO_EMOJI -eq 1 ]]; then
|
||||
temp_lv="85:, 65:, 45:☁, ❄"
|
||||
else
|
||||
temp_lv="85:🌋, 65:🔥, 45:☁️, ❄️"
|
||||
fi
|
||||
util_lv="90:, 60:, 30:, "
|
||||
|
||||
nvidia_flag=${nvidia_flag:-0} intel_flag=${intel_flag:-0} amd_flag=${amd_flag:-0}
|
||||
#? Based on the flags, call the corresponding function multi flags means multi GPU.
|
||||
if [[ "${nvidia_flag}" -eq 1 ]]; then
|
||||
nvidia_GPU
|
||||
elif [[ "${amd_flag}" -eq 1 ]]; then
|
||||
amd_GPU
|
||||
elif [[ "${intel_flag}" -eq 1 ]]; then
|
||||
intel_GPU
|
||||
else primary_gpu="Not found"
|
||||
general_query
|
||||
fi
|
||||
|
||||
generate_json #? AutoGen the Json txt for Waybar
|
||||
Reference in New Issue
Block a user