Created
October 19, 2018 12:55
-
-
Save tuxzz/59d1d3b02e3754b5dfed0243a384473e to your computer and use it in GitHub Desktop.
Control fan speed of Nvidia GPU based on control point
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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