Added Makefile-type instalation of with pip3 and systemd daemon
This commit is contained in:
parent
3c8b435e32
commit
dd8789ab53
|
@ -0,0 +1,27 @@
|
||||||
|
all: superfans-gpu-controller superfans-gpu-controller.service
|
||||||
|
.PHONY: all superfans-gpu-controller-daemon install uninstall clean
|
||||||
|
|
||||||
|
service_dir=/etc/systemd/system
|
||||||
|
conf_dir=/etc
|
||||||
|
awk_script='BEGIN {FS="="; OFS="="}{if ($$1=="ExecStart") {$$2=exec_path} if (substr($$1,1,1) != "\#") {print $$0}}'
|
||||||
|
|
||||||
|
superfans-gpu-controller: superfans_gpu_controller.py setup.py
|
||||||
|
pip3 install .
|
||||||
|
|
||||||
|
superfans-gpu-controller.service: superfans_gpu_controller.py
|
||||||
|
# awk is needed to replace the absolute path of mydaemon executable in the .service file
|
||||||
|
awk -v exec_path='$(shell which superfans-gpu-controller) $(conf_dir)/superfans-gpu-controller.json' $(awk_script) superfans-gpu-controller.service.template > superfans-gpu-controller.service
|
||||||
|
|
||||||
|
install: $(service_dir) $(conf_dir) superfans-gpu-controller.service
|
||||||
|
cp superfans-gpu-controller.json $(conf_dir)
|
||||||
|
cp superfans-gpu-controller.service $(service_dir)
|
||||||
|
-systemctl enable superfans-gpu-controller.service
|
||||||
|
-systemctl enable superfans-gpu-controller
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
-systemctl stop superfans-gpu-controller
|
||||||
|
-rm -r $(service_dir)/superfans-gpu-controller.service
|
||||||
|
-rm -r $(conf_dir)/superfans-gpu-controller.json
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm superfans-gpu-controller.service
|
|
@ -1,30 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
echo "Created '/etc/systemd/system/superfans-gpu-controller.service' service file"
|
|
||||||
echo "[Unit]
|
|
||||||
Description=GPU-based controller of SUPERMICRO server FANs
|
|
||||||
After=syslog.target nvidia-persistenced.service
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
User=root
|
|
||||||
Group=root
|
|
||||||
WorkingDirectory=`pwd`
|
|
||||||
Environment=PYTHONUNBUFFERED=true
|
|
||||||
ExecStart=/usr/bin/python -u `pwd`/superfans_gpu_controller.py
|
|
||||||
StandardOutput=syslog
|
|
||||||
StandardError=syslog
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target" > /etc/systemd/system/superfans-gpu-controller.service
|
|
||||||
echo "\n"
|
|
||||||
|
|
||||||
echo "Registering superfans-gpu-controller.service"
|
|
||||||
systemctl enable superfans-gpu-controller.service
|
|
||||||
systemctl daemon-reload
|
|
||||||
|
|
||||||
echo "Enabled start at system startup"
|
|
||||||
systemctl enable superfans-gpu-controller
|
|
||||||
|
|
||||||
echo "Starting the service"
|
|
||||||
systemctl start superfans-gpu-controller
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
from setuptools import setup
|
||||||
|
setup(name='superfans-gpu-controller',
|
||||||
|
version='0.1',
|
||||||
|
description='Supermicro FAN controller based on NVIDIA GPU temperature',
|
||||||
|
py_modules=['superfans_gpu_controller','superfans' ],
|
||||||
|
entry_points={
|
||||||
|
'console_scripts': [
|
||||||
|
'superfans-gpu-controller = superfans_gpu_controller:main',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
)
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"fan_settings" : {"0": 20,
|
||||||
|
"60": 25,
|
||||||
|
"70": 30,
|
||||||
|
"80": 35,
|
||||||
|
"87": 40,
|
||||||
|
"90": 43}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
[Unit]
|
||||||
|
Description=GPU-based controller of SUPERMICRO server FANs
|
||||||
|
After=syslog.target nvidia-persistenced.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
|
Environment="PYTHONUNBUFFERED=true"
|
||||||
|
ExecStart=/placeholder/path/to/superfans-gpu-controller "/etc/superfans-gpu-controller.json"
|
||||||
|
StandardOutput=syslog
|
||||||
|
StandardError=syslog
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
|
@ -184,10 +184,10 @@ def ipmi_raw_cmd(raw_cmd, hostname = 'localhost', username=None, password=None,
|
||||||
|
|
||||||
try:
|
try:
|
||||||
s = subprocess.check_output(cmd + " 2>&1", shell=True)
|
s = subprocess.check_output(cmd + " 2>&1", shell=True)
|
||||||
except subprocess.CalledProcessError, ex:
|
except subprocess.CalledProcessError as ex:
|
||||||
print("Error: Problem running ipmitool")
|
print("Error: Problem running ipmitool")
|
||||||
print("Command: %s" % cmd)
|
print("Command: %s" % cmd)
|
||||||
print("Return code: %d" % ex)
|
print("Return code: %s" % ex)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
out = s.strip()
|
out = s.strip()
|
||||||
|
@ -212,10 +212,10 @@ def ipmi_fan_status(hostname = 'localhost', username=None, password=None, use_en
|
||||||
cmd = 'ipmitool -I lanplus -U %s %s -H %s sensor | grep FAN' % (shlex.quote(username), cmd_pass, hostname)
|
cmd = 'ipmitool -I lanplus -U %s %s -H %s sensor | grep FAN' % (shlex.quote(username), cmd_pass, hostname)
|
||||||
try:
|
try:
|
||||||
s = subprocess.check_output(cmd + " 2>&1", shell=True)
|
s = subprocess.check_output(cmd + " 2>&1", shell=True)
|
||||||
except subprocess.CalledProcessError, ex:
|
except subprocess.CalledProcessError as ex:
|
||||||
print("Error: Problem running ipmitool")
|
print("Error: Problem running ipmitool")
|
||||||
print("Command: %s" % cmd)
|
print("Command: %s" % cmd)
|
||||||
print("Return code: %d" % ex)
|
print("Return code: %s" % ex)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
fan_status_return = {}
|
fan_status_return = {}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# author: Domen Tabernik
|
# author: Domen Tabernik
|
||||||
# 2019
|
# 2019
|
||||||
|
|
||||||
import time, superfans, subprocess, signal, sys
|
import time, superfans, subprocess, signal, sys, json
|
||||||
|
|
||||||
class GracefulKiller:
|
class GracefulKiller:
|
||||||
kill_now = False
|
kill_now = False
|
||||||
|
@ -24,6 +24,7 @@ def retrieve_nvidia_gpu_temperature():
|
||||||
s = subprocess.check_output(cmd + " 2>&1", shell=True)
|
s = subprocess.check_output(cmd + " 2>&1", shell=True)
|
||||||
if len(s) <= 0:
|
if len(s) <= 0:
|
||||||
return False
|
return False
|
||||||
|
s = s.decode('ascii')
|
||||||
|
|
||||||
out = [int(x.strip()) for x in s.split("\n") if len(x.strip()) > 0]
|
out = [int(x.strip()) for x in s.split("\n") if len(x.strip()) > 0]
|
||||||
if out:
|
if out:
|
||||||
|
@ -45,6 +46,9 @@ def superfans_gpu_controller(fan_settings, FAN_INCREASED_MIN_TIME=120, sleep_sec
|
||||||
"""
|
"""
|
||||||
superfan_config = dict(hostname= 'localhost')
|
superfan_config = dict(hostname= 'localhost')
|
||||||
|
|
||||||
|
# convert fan_settings keys from string to int
|
||||||
|
fan_settings = { int(k): fan_settings[k] for k in sorted(fan_settings.keys()) }
|
||||||
|
|
||||||
# save default present before changing anything
|
# save default present before changing anything
|
||||||
default_preset = superfans.get_preset(superfan_config)
|
default_preset = superfans.get_preset(superfan_config)
|
||||||
print('Started fan control using GPU temperature.')
|
print('Started fan control using GPU temperature.')
|
||||||
|
@ -113,16 +117,16 @@ def superfans_gpu_controller(fan_settings, FAN_INCREASED_MIN_TIME=120, sleep_sec
|
||||||
# Allow for 1% difference in target
|
# Allow for 1% difference in target
|
||||||
update_sys1_fan = any([d > fan_target_eps for d in diff_sys1_fan])
|
update_sys1_fan = any([d > fan_target_eps for d in diff_sys1_fan])
|
||||||
update_sys2_fan = any([d > fan_target_eps for d in diff_sys2_fan])
|
update_sys2_fan = any([d > fan_target_eps for d in diff_sys2_fan])
|
||||||
if update_sys1_fan:
|
#if update_sys1_fan:
|
||||||
superfans.set_fan(superfan_config, target_fan, superfans.FAN_ZONE_SYS1)
|
# superfans.set_fan(superfan_config, target_fan, superfans.FAN_ZONE_SYS1)
|
||||||
|
|
||||||
if update_sys2_fan:
|
#if update_sys2_fan:
|
||||||
superfans.set_fan(superfan_config, target_fan, superfans.FAN_ZONE_SYS2)
|
# superfans.set_fan(superfan_config, target_fan, superfans.FAN_ZONE_SYS2)
|
||||||
|
|
||||||
if update_sys1_fan or update_sys2_fan:
|
if update_sys1_fan or update_sys2_fan:
|
||||||
print('\tCurrent GPU measurements (in C): %s' % ','.join(map(str,GPU_temp)))
|
print('\tCurrent GPU measurements (in C): %s' % ','.join(map(str,GPU_temp)))
|
||||||
print('\tMoving average GPU measurements (in C): %s (max=%d)' % (','.join(map(str,mean_GPU_temp)),max_gpu_temp))
|
print('\tMoving average GPU measurements (in C): %s (max=%d)' % (','.join(map(str,mean_GPU_temp)),max_gpu_temp))
|
||||||
print('\tTarget FAN speed: %d C => FAN %d %% (difference: SYS1 fan = %.2f; SYS2 fan = %.2f)' % (max_gpu_temp, target_fan, max(diff_sys1_fan), max(diff_sys2_fan)))
|
print('\tTarget FAN speed: %d C => FAN %d %% (difference: SYS1 fan = %.2f; SYS2 fan = %.2f)' % (max_gpu_temp, target_fan, max(diff_sys1_fan), max(diff_sys2_fan)))
|
||||||
print('\n\n')
|
print('\n\n')
|
||||||
|
|
||||||
previous_target_fan = target_fan
|
previous_target_fan = target_fan
|
||||||
|
@ -134,13 +138,20 @@ def superfans_gpu_controller(fan_settings, FAN_INCREASED_MIN_TIME=120, sleep_sec
|
||||||
superfans.set_preset(superfan_config, default_preset)
|
superfans.set_preset(superfan_config, default_preset)
|
||||||
print('Reverted back to system default.')
|
print('Reverted back to system default.')
|
||||||
|
|
||||||
if __name__ == "__main__":
|
def main():
|
||||||
# fan settings = {[in deg C]: [% fan], ...}
|
if len(sys.argv) != 2:
|
||||||
fan_settings = {0: 20,
|
print('Invalid number of arguments: missing configuration file!!')
|
||||||
60: 25,
|
print('')
|
||||||
70: 30,
|
print(' Usage: %s [PATH_TO_JSON_CONFIG]' % sys.argv[0])
|
||||||
80: 35,
|
print('')
|
||||||
87: 40,
|
print(' Configuration file in JSON format should include "fan_settings" = {[in deg C]: [% fan], ...} ')
|
||||||
90: 43}
|
print
|
||||||
|
exit(0)
|
||||||
|
|
||||||
superfans_gpu_controller(fan_settings)
|
with open(sys.argv[1]) as cfg_file:
|
||||||
|
cfg = json.load(cfg_file)
|
||||||
|
|
||||||
|
superfans_gpu_controller(cfg['fan_settings'])
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
Loading…
Reference in New Issue