Added Makefile-type instalation of with pip3 and systemd daemon

This commit is contained in:
Domen Tabernik 2020-07-27 14:56:37 +00:00
parent 3c8b435e32
commit dd8789ab53
7 changed files with 91 additions and 49 deletions

27
Makefile Normal file
View File

@ -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

View File

@ -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

11
setup.py Normal file
View File

@ -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',
],
},
)

View File

@ -0,0 +1,8 @@
{
"fan_settings" : {"0": 20,
"60": 25,
"70": 30,
"80": 35,
"87": 40,
"90": 43}
}

View File

@ -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

View File

@ -184,10 +184,10 @@ def ipmi_raw_cmd(raw_cmd, hostname = 'localhost', username=None, password=None,
try:
s = subprocess.check_output(cmd + " 2>&1", shell=True)
except subprocess.CalledProcessError, ex:
except subprocess.CalledProcessError as ex:
print("Error: Problem running ipmitool")
print("Command: %s" % cmd)
print("Return code: %d" % ex)
print("Return code: %s" % ex)
return False
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)
try:
s = subprocess.check_output(cmd + " 2>&1", shell=True)
except subprocess.CalledProcessError, ex:
except subprocess.CalledProcessError as ex:
print("Error: Problem running ipmitool")
print("Command: %s" % cmd)
print("Return code: %d" % ex)
print("Return code: %s" % ex)
return False
fan_status_return = {}

View File

@ -3,7 +3,7 @@
# author: Domen Tabernik
# 2019
import time, superfans, subprocess, signal, sys
import time, superfans, subprocess, signal, sys, json
class GracefulKiller:
kill_now = False
@ -24,6 +24,7 @@ def retrieve_nvidia_gpu_temperature():
s = subprocess.check_output(cmd + " 2>&1", shell=True)
if len(s) <= 0:
return False
s = s.decode('ascii')
out = [int(x.strip()) for x in s.split("\n") if len(x.strip()) > 0]
if out:
@ -45,6 +46,9 @@ def superfans_gpu_controller(fan_settings, FAN_INCREASED_MIN_TIME=120, sleep_sec
"""
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
default_preset = superfans.get_preset(superfan_config)
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
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])
if update_sys1_fan:
superfans.set_fan(superfan_config, target_fan, superfans.FAN_ZONE_SYS1)
#if update_sys1_fan:
# superfans.set_fan(superfan_config, target_fan, superfans.FAN_ZONE_SYS1)
if update_sys2_fan:
superfans.set_fan(superfan_config, target_fan, superfans.FAN_ZONE_SYS2)
#if update_sys2_fan:
# superfans.set_fan(superfan_config, target_fan, superfans.FAN_ZONE_SYS2)
if update_sys1_fan or update_sys2_fan:
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('\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')
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)
print('Reverted back to system default.')
if __name__ == "__main__":
# fan settings = {[in deg C]: [% fan], ...}
fan_settings = {0: 20,
60: 25,
70: 30,
80: 35,
87: 40,
90: 43}
def main():
if len(sys.argv) != 2:
print('Invalid number of arguments: missing configuration file!!')
print('')
print(' Usage: %s [PATH_TO_JSON_CONFIG]' % sys.argv[0])
print('')
print(' Configuration file in JSON format should include "fan_settings" = {[in deg C]: [% fan], ...} ')
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()