Skip to content

Instantly share code, notes, and snippets.

@tuxzz
Created October 19, 2018 12:55
Show Gist options
  • Save tuxzz/59d1d3b02e3754b5dfed0243a384473e to your computer and use it in GitHub Desktop.
Save tuxzz/59d1d3b02e3754b5dfed0243a384473e to your computer and use it in GitHub Desktop.
Control fan speed of Nvidia GPU based on control point
import sys, time, subprocess
loop_interval = 0.5
control_point_list = ((54, 0), (55, 40), (60, 75), (65, 100))
max_temp_history_length = 20
get_temp_cmd = ["nvidia-settings", "-q=[gpu:0]/GPUCoreTemp", "-t"]
get_control_cmd = ["nvidia-settings", "-q=[gpu:0]/GPUFanControlState", "-t"]
get_fan_cmd = ["nvidia-settings", "-q=[fan:0]/GPUCurrentFanSpeed", "-t"]
set_control_cmd = ["nvidia-settings", "-a", "[gpu:0]/GPUFanControlState=%d"]
set_fan_cmd = ["nvidia-settings", "-a", "[fan:0]/GPUTargetFanSpeed=%d"]
def get_temp():
result = subprocess.run(get_temp_cmd, stdout = subprocess.PIPE)
if result.returncode != 0:
raise RuntimeError("Fuck! I can't get GPU tempature(Return code is %d)!" % result.returncode)
tempature = result.stdout
try:
return int(tempature)
except ValueError:
raise RuntimeError("Fuck! I can't get GPU tempature(Invalid stdout)!")
def get_control_mode():
result = subprocess.run(get_control_cmd, stdout = subprocess.PIPE)
mode = result.stdout
if result.returncode != 0:
raise RuntimeError("Fuck! I can't get GPU fan control mode(Return code is %d)!" % result.returncode)
try:
return bool(int(mode))
except ValueError:
raise RuntimeError("Fuck! I can't get GPU fan control mode(Invalid stdout)!")
def get_fan_ratio():
result = subprocess.run(get_fan_cmd, stdout = subprocess.PIPE)
ratio = result.stdout
if result.returncode != 0:
raise RuntimeError("Fuck! I can't get GPU fan speed(Return code is %d)!" % result.returncode)
try:
return int(ratio)
except ValueError:
raise RuntimeError("Fuck! I can't get GPU fan speed(Invalid stdout)!")
def set_control_mode(sw):
assert isinstance(sw, bool)
sw = int(sw)
cmd = list(set_control_cmd)
cmd[-1] = cmd[-1] % sw
result = subprocess.run(cmd, stdout = subprocess.PIPE)
if result.returncode != 0:
raise RuntimeError("Fuck! I can't set GPU fan control mode(Return code is %d)!" % result.returncode)
def set_fan_speed(ratio):
assert isinstance(ratio, int)
assert 0 <= ratio <= 100
cmd = list(set_fan_cmd)
cmd[-1] = cmd[-1] % ratio
result = subprocess.run(cmd, stdout = subprocess.PIPE)
if result.returncode != 0:
raise RuntimeError("Fuck! I can't set GPU fan speed(Return code is %d)!" % result.returncode)
def get_fan_speed_by_tempature(temp):
if temp <= control_point_list[0][0]:
return control_point_list[0][1]
elif temp >= control_point_list[-1][0]:
return control_point_list[-1][1]
n = len(control_point_list)
for i in range(1, n):
i = n - i
ct, cs = control_point_list[i]
if temp == ct:
return cs
elif temp > ct:
nt, ns = control_point_list[i + 1]
ratio = (temp - ct) / (nt - ct)
return int(round(cs + (ns - cs) * ratio))
def main():
assert len(control_point_list) > 0
pt, ps = -1, -1
for t, s in control_point_list:
assert 0 <= t <= 80
assert 0 <= s <= 100
assert t > pt
assert s > ps
pt, ps = t, s
del t, s
del pt, ps
set_control_mode(True)
curr_fan_speed = get_fan_ratio()
temp_history = [get_temp()]
while True:
try:
while len(temp_history) >= max_temp_history_length:
del temp_history[0]
temp_history.append(get_temp())
temp = max(temp_history)
s = get_fan_speed_by_tempature(temp)
if s != curr_fan_speed:
#print(temp_history[-1], temp, s)
set_fan_speed(s)
curr_fan_speed = s
time.sleep(loop_interval)
except KeyboardInterrupt:
set_control_mode(False)
return
except Exception as e:
print("Loop Failed: %s" % str(e), file = sys.stderr)
try:
set_fan_speed(s)
except Exception as ee:
print("Protection failed: %s" % str(ee), file = sys.stderr)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment