Skip to content

Instantly share code, notes, and snippets.

@AlexKordic
Created March 22, 2024 17:36
Show Gist options
  • Save AlexKordic/65f031b708177a01a002cc19f0d7298c to your computer and use it in GitHub Desktop.
Save AlexKordic/65f031b708177a01a002cc19f0d7298c to your computer and use it in GitHub Desktop.
Script to control nvidia GPU fan speed.
import pynvml, time
from pynvml import *
TEMP_MIN_VALUE = 30.0 # fan is around 30%
TEMP_MAX_VALUE = 65.0 # fan is at 100% onwards
TEMP_RANGE = TEMP_MAX_VALUE - TEMP_MIN_VALUE
def fanspeed_from_t(t):
if t <= TEMP_MIN_VALUE: return 0.0
if t >= TEMP_MAX_VALUE: return 1.0
return (t - TEMP_MIN_VALUE) / TEMP_RANGE
try:
_nvmlGetFunctionPointer = pynvml._nvmlGetFunctionPointer
_nvmlCheckReturn = pynvml._nvmlCheckReturn
except AttributeError as err:
_nvmlGetFunctionPointer = pynvml.nvml._nvmlGetFunctionPointer
_nvmlCheckReturn = pynvml.nvml._nvmlCheckReturn
nvmlInit()
def alex_nvmlDeviceGetMinMaxFanSpeed(handle):
c_minSpeed = c_uint()
c_maxSpeed = c_uint()
fn = _nvmlGetFunctionPointer("nvmlDeviceGetMinMaxFanSpeed")
ret = fn(handle, byref(c_minSpeed), byref(c_maxSpeed))
_nvmlCheckReturn(ret)
return c_minSpeed.value, c_maxSpeed.value
class Device:
def __init__(self, index):
self.index = index
self.handle = nvmlDeviceGetHandleByIndex(index)
self.name = nvmlDeviceGetName(self.handle)
self.fan_count = nvmlDeviceGetNumFans(self.handle)
self.fan_min, self.fan_max = alex_nvmlDeviceGetMinMaxFanSpeed(self.handle)
self._fan_range = self.fan_max - self.fan_min
def temp(self):
return nvmlDeviceGetTemperature(self.handle, NVML_TEMPERATURE_GPU)
def fan_percentages(self):
return [nvmlDeviceGetFanSpeed_v2(self.handle, i) for i in range(self.fan_count)]
def set_fan_speed(self, percentage):
""" WARNING: This function changes the fan control policy to manual. It means that YOU have to monitor the temperature and adjust the fan speed accordingly. If you set the fan speed too low you can burn your GPU! Use nvmlDeviceSetDefaultFanSpeed_v2 to restore default control policy.
"""
for i in range(self.fan_count):
nvmlDeviceSetFanSpeed_v2(self.handle, i, percentage)
def query(self):
return f"{self.index}:{self.name} {self.temp()}@{self.fan_percentages()}"
def control(self):
t = self.temp()
fans = self.fan_percentages()
current = round(sum(fans) / len(fans))
shouldbe = round(fanspeed_from_t(t) * self._fan_range + self.fan_min)
if(shouldbe != current):
print(f"{self.index}:{self.name} t={t} {current} >> {shouldbe}")
# change fan speed
self.set_fan_speed(shouldbe)
def __str__(self):
return f"{self.index}:{self.name} fans={self.fan_count} {self.fan_min}-{self.fan_max}"
__repr__ = __str__
print(f"Driver Version: {nvmlSystemGetDriverVersion()}")
device_count = nvmlDeviceGetCount()
devices = [Device(i) for i in range(device_count)]
for device in devices:
print(device)
def main():
try:
while True:
for device in devices:
# print(device.query())
device.control()
time.sleep(1)
finally:
# reset to auto fan control
for device in devices:
for i in range(device.fan_count):
nvmlDeviceSetDefaultFanSpeed_v2(device.handle, i)
nvmlShutdown()
if __name__ == "__main__":
main()
@RoversX
Copy link

RoversX commented Jun 27, 2024

Tested on 2080Ti, works perfectly, thank you so much!

:~$ ./fan.sh
Driver Version: 535.183.01
0:NVIDIA GeForce RTX 2080 Ti fans=1 27-100
0:NVIDIA GeForce RTX 2080 Ti t=36 27 >> 40
0:NVIDIA GeForce RTX 2080 Ti t=36 43 >> 40
0:NVIDIA GeForce RTX 2080 Ti t=36 41 >> 40
0:NVIDIA GeForce RTX 2080 Ti t=36 39 >> 40
0:NVIDIA GeForce RTX 2080 Ti t=35 40 >> 37
0:NVIDIA GeForce RTX 2080 Ti t=35 36 >> 37
0:NVIDIA GeForce RTX 2080 Ti t=34 37 >> 35

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment