Skip to content

Instantly share code, notes, and snippets.

@ihaque
Created November 29, 2011 10:43
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ihaque/1404373 to your computer and use it in GitHub Desktop.
Save ihaque/1404373 to your computer and use it in GitHub Desktop.
Automatic temperature-based fan-speed control for AMD GPUs in Linux
from bisect import bisect_left
from subprocess import Popen, PIPE
from time import sleep
import numpy as np
def get_temperature(gpu=0):
lines = Popen(["aticonfig", "--adapter=%d" % gpu, "--od-gettemperature"],
stdout=PIPE).communicate()[0].split("\n")
lines = [xx.strip() for xx in lines if len(xx.strip()) > 0]
# Adapter 0 - AMD Radeon HD 6800 Series
# Sensor 0: Temperature - 63.00 C
#
templine = lines[1].strip()
fields = templine.split()
assert(fields[2] == "Temperature")
return float(fields[4])
def set_fan_speed(fanspeed_pct, gpu=0):
output = Popen(["aticonfig", "--pplib-cmd",
"set fanspeed %d %d" % (gpu, fanspeed_pct)],
stdout=PIPE).communicate()[0]
assert(output.strip() == "PPLIB command execution is Successful!")
return
def get_fan_speed(gpu=0):
lines = Popen(["aticonfig", "--pplib-cmd", "get fanspeed %d" % gpu],
stdout=PIPE).communicate()[0].split("\n")
# Fan speed query:
# Query Index: 0, Speed in percent
# Result: Fan Speed: 20%
linefields = [xx.strip().split() for xx in lines if len(xx.strip()) > 0]
assert(" ".join(linefields[-1][1:3]) == "Fan Speed:")
# Strip the %
return int(linefields[-1][-1][:-1])
class LinearInterpolatingFanCurve:
def __init__(self, curve):
curve.sort()
assert(curve[0][1] >= 20)
assert(curve[-1][1] == 100)
self.temps, self.fans = zip(*curve)
self.temps = map(float, self.temps)
self.fans = map(float, self.fans)
def temp2fan(self, temp):
if temp < self.temps[0]:
return self.fans[0]
elif temp > self.temps[-1]:
return self.fans[-1]
else:
idx = bisect_left(self.temps, temp)
tleft = self.temps[idx-1]
tright = self.temps[idx]
fleft = self.fans[idx-1]
fright = self.fans[idx]
fanspeed = (temp-tleft)/(tright-tleft) * fright +\
(tright-temp)/(tright-tleft) * fleft
fanspeed = int(round(fanspeed))
print "Tl =",tleft,"Tr =",tright,"Fl =",fleft,"Fr =",fright,"T =",temp,"Fs =",fanspeed
return fanspeed
def main():
print "Manual fan speed control is dangerous and can fry your hardware!"
print "Use this program at your own risk! I take no responsibility!"
poll_period = 1
buffer_size = 4
hysteresis = 1
# Temperature curve has control points specified by pairs of
# (temperature in degC, fan speed in %)
curve = [( 0, 20), (65, 20),
(70, 40),
(80, 70), (90, 100)]
fanmap = LinearInterpolatingFanCurve(curve)
fanspeed = get_fan_speed()
fantemp = get_temperature()
temps_buffer = np.empty((buffer_size,))
temps_buffer[:] = fantemp
idx = 0
while True:
temps_buffer[idx] = get_temperature()
idx = (idx + 1) % buffer_size
temp = np.mean(temps_buffer)
fan = fanmap.temp2fan(temp)
if fan != fanspeed and abs(temp-fantemp) > hysteresis:
set_fan_speed(fan)
fanspeed = fan
fantemp = temp
print "\tSet fan speed to",get_fan_speed()
sleep(poll_period)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment