aboutsummaryrefslogtreecommitdiffstats
path: root/linux/nvidia-fan-control.sh
diff options
context:
space:
mode:
authorAaron LI <aly@aaronly.me>2017-06-14 22:58:26 +0800
committerAaron LI <aly@aaronly.me>2017-06-14 22:58:26 +0800
commitdf4319684282b4eeb2c5d3ee0a2ac9bb14fcd29c (patch)
treefc63ff311698f981714a7a49d6a07a9d24b73b5e /linux/nvidia-fan-control.sh
parentb2473586a3017af791e089deaeaab5683449613b (diff)
downloadatoolbox-df4319684282b4eeb2c5d3ee0a2ac9bb14fcd29c.tar.bz2
Add linux/nvidia-fan-control.sh
Start Xorg and manually control NVIDIA GPU fan using `nvidia-settings`. WARNING: * After enabled manual fan control, and GPU performance level is restricted to the lowest `P8`, for unknown reason! * Disabled manual fan control by setting `GPUFanControlState=0` cannot make the GPU fan automatically controlled, for unknown reason!
Diffstat (limited to 'linux/nvidia-fan-control.sh')
-rwxr-xr-xlinux/nvidia-fan-control.sh200
1 files changed, 200 insertions, 0 deletions
diff --git a/linux/nvidia-fan-control.sh b/linux/nvidia-fan-control.sh
new file mode 100755
index 0000000..60df143
--- /dev/null
+++ b/linux/nvidia-fan-control.sh
@@ -0,0 +1,200 @@
+#!/bin/sh
+#
+# Copyright (c) 2017 Aaron LI <aly@aaronly.me>
+# MIT License
+#
+# Manually control NVIDIA GPU fan speed using `nvidia-settings` tool.
+#
+# NOTE:
+# Make sure the NVIDIA persistence daemon `nvidia-persistenced` is
+# running to keep the GPU context. Otherwise, the applied settings
+# will be reverted after X exited.
+#
+# NOTE:
+# This script should work on Debian Linux (testing; amd64)
+#
+# Credits:
+# [1] NVIDIA GPU Coolness
+# https://sites.google.com/site/akohlmey/random-hacks/nvidia-gpu-coolness
+# [2] http://klein-group.icms.temple.edu/akohlmey/files/set-gpu-fans.tar.gz
+#
+#
+# 2017-06-14
+#
+
+set -e
+
+DEBUG=
+
+error() {
+ echo "ERROR: $@" >&2
+}
+
+debug() {
+ if [ -n "${DEBUG}" ]; then
+ echo "DEBUG: $@" >&2
+ fi
+}
+
+
+make_edid() {
+ # Generate this with: base64 <file>
+ base64 -d > "$1" <<_EOF_
+AP///////wAQrBXwTFRBNS4TAQOANCB47h7Frk80sSYOUFSlSwCBgKlA0QBxTwEBAQEBAQEBKDyA
+oHCwI0AwIDYABkQhAAAaAAAA/wBDNTkyTTlCOTVBVEwKAAAA/ABERUxMIFUyNDEwCiAgAAAA/QA4
+TB5REQAKICAgICAgAB0=
+_EOF_
+}
+
+
+make_xorgconf() {
+ local xcfg busid edidfile
+ xcfg="$1"
+ busid="$2"
+ edidfile="$3"
+ cat > "${xcfg}" <<_EOF_
+# Simple single screen X server config with fake CRT attached
+
+Section "ServerLayout"
+ Identifier "Layout0"
+ Screen 0 "Screen0" 0 0
+EndSection
+
+Section "Screen"
+ Identifier "Screen0"
+ Device "VideoCard0"
+ Monitor "Monitor0"
+ DefaultDepth 24
+ Option "UseDisplayDevice" "DFP-0"
+ Option "ConnectedMonitor" "DFP-0"
+ Option "CustomEDID" "DFP-0:${edidfile}"
+ Option "Coolbits" "5"
+ SubSection "Display"
+ Depth 24
+ Modes "1024x768"
+ EndSubSection
+EndSection
+
+Section "Files"
+ ModulePath "/usr/lib/xorg/modules/extensions/nvidia"
+ ModulePath "/usr/lib/xorg/modules"
+EndSection
+
+Section "ServerFlags"
+ Option "AllowEmptyInput" "on"
+ Option "Xinerama" "off"
+ Option "SELinux" "off"
+EndSection
+
+Section "Device"
+ Identifier "VideoCard0"
+ Driver "nvidia"
+ Screen 0
+ Option "UseDisplayDevice" "DFP-0"
+ Option "ConnectedMonitor" "DFP-0"
+ Option "CustomEDID" "DFP-0:${edidfile}"
+ Option "Coolbits" "4"
+ BusID "${busid}"
+EndSection
+
+Section "Monitor"
+ Identifier "Monitor0"
+ Vendorname "Dummy Display"
+ Modelname "1024x768"
+EndSection
+_EOF_
+}
+
+
+# Convert the PCI ID from format "<bus>:<device>.<func>" to
+# "PCI:<bus>:<device>:<func>" for Xorg usage.
+make_busid() {
+ local busid cmd
+ busid=$(echo "$1" | \
+ sed -e 's/\([0-f]\+\):\([0-f]\+\)\.\([0-f]\+\)/0x\1 0x\2 0x\3/')
+ debug make_busid:busid: ${busid}
+ cmd="printf 'PCI:%d:%d:%d' ${busid}"
+ debug make_busid:cmd: ${cmd}
+ busid=$(eval ${cmd})
+ debug make_busid:busid: ${busid}
+ echo ${busid}
+}
+
+
+get_gpu_busid() {
+ local busid=""
+ for id in $(lspci | grep "VGA compatible controller: NVIDIA" | \
+ cut -d' ' -f1); do
+ debug get_gpu_busid:id: ${id}
+ busid="${busid} $(make_busid ${id})"
+ done
+ debug get_gpu_busid:busid: ${busid}
+ echo "${busid}"
+}
+
+
+# Default display number for Xorg
+XD=:0
+# Default fan speed (70%)
+FANSPEED=70
+
+usage() {
+ local progname
+ progname="${0##*/}"
+ cat <<_EOF_
+usage:
+ ${progname} start [ speed_percent ]
+ Set the GPU fan speed to given percent (default: ${FANSPEED})
+ ${progname} stop
+ Go back to automatic fan control
+_EOF_
+}
+
+case "$1" in
+ start)
+ shift
+ FANSPEED=${1:-${FANSPEED}}
+ CMD="nvidia-settings -a [gpu:0]/GPUFanControlState=1 \
+ -a [fan:0]/GPUTargetFanSpeed=${FANSPEED}"
+ ;;
+ stop)
+ CMD="nvidia-settings -a [gpu:0]/GPUFanControlState=0"
+ ;;
+ *)
+ usage
+ exit 1
+ ;;
+esac
+
+EDIDFILE=$(mktemp /tmp/edid-XXXXXXXX.bin)
+make_edid ${EDIDFILE}
+
+BUSID=$(get_gpu_busid)
+if [ -z "${BUSID}" ]; then
+ error "no NVIDIA GPU found!" >&2
+ exit 2
+fi
+
+if [ $(id -u) -ne 0 ]; then
+ error "root privileges required!" >&2
+ exit 3
+fi
+
+for busid in ${BUSID}; do
+ echo "Set fan speed for NVIDIA GPU: ${busid} ..."
+ XCFG=$(mktemp /tmp/xorg-XXXXXXXX.conf)
+ make_xorgconf ${XCFG} ${busid} ${EDIDFILE}
+ Xorg ${XD} -config ${XCFG} -keeptty >/dev/null &
+ XPID=$!
+ sleep 3
+ echo "Started Xorg at display ${XD} with PID=${XPID}."
+ env DISPLAY=${XD} ${CMD}
+ sleep 1
+ kill -9 ${XPID}
+ echo "Killed Xorg PID=${XPID}."
+ rm -f ${XCFG}
+done
+
+rm -f ${EDIDFILE}
+
+exit 0