160 lines
5.5 KiB
Perl
160 lines
5.5 KiB
Perl
|
#!/usr/bin/perl
|
||
|
use strict;
|
||
|
use warnings;
|
||
|
use List::Util qw[min max];
|
||
|
|
||
|
# This script controls SuperMicro server fan speeds via IPMI in response to CPU and SYS temperatures.
|
||
|
# A fork of https://github.com/missmah/ipmi_tools by Layla Mah <layla@insightfulvr.com>
|
||
|
|
||
|
# Sensor treshold reset to allow slower fans
|
||
|
|
||
|
`ipmitool sensor thresh FANA lower 0 100 200`;
|
||
|
`ipmitool sensor thresh FANB lower 0 100 200`;
|
||
|
`ipmitool sensor thresh FAN1 lower 0 100 200`;
|
||
|
`ipmitool sensor thresh FAN2 lower 0 100 200`;
|
||
|
`ipmitool sensor thresh FAN3 lower 0 100 200`;
|
||
|
`ipmitool sensor thresh FAN4 lower 0 100 200`;
|
||
|
`ipmitool sensor thresh FAN5 lower 0 100 200`;
|
||
|
|
||
|
my $min_temp_change = 4; # *C minimum change to actually cause a fan speed update
|
||
|
my $seconds_to_sleep = 3; # Number of seconds to sleep between update loops
|
||
|
|
||
|
# CPU Temp -> Fan Speed Mappings
|
||
|
my %cpu_temp_to_fan_speed;
|
||
|
$cpu_temp_to_fan_speed{75} = 0x64;
|
||
|
$cpu_temp_to_fan_speed{70} = 0x60;
|
||
|
$cpu_temp_to_fan_speed{65} = 0x54;
|
||
|
$cpu_temp_to_fan_speed{60} = 0x52;
|
||
|
$cpu_temp_to_fan_speed{50} = 0x44;
|
||
|
$cpu_temp_to_fan_speed{40} = 0x40;
|
||
|
|
||
|
# SYS Temp -> Fan Speed Mappings
|
||
|
my %sys_temp_to_fan_speed;
|
||
|
$sys_temp_to_fan_speed{55} = 0x64;
|
||
|
$sys_temp_to_fan_speed{50} = 0x50;
|
||
|
$sys_temp_to_fan_speed{45} = 0x44;
|
||
|
$sys_temp_to_fan_speed{40} = 0x40;
|
||
|
|
||
|
# Below this line follows the actual implementation of the script
|
||
|
|
||
|
my $g_current_fan_duty_cycle = 0;
|
||
|
my $g_current_sys_temp = 0;
|
||
|
my $g_current_cpu_temp = 0;
|
||
|
my $g_last_set_cpu_temp = 0;
|
||
|
my $g_last_set_sys_temp = 0;
|
||
|
|
||
|
sub Internal_DoSetFanSpeedSys {
|
||
|
my ( $fan_speed ) = @_;
|
||
|
`ipmitool raw 0x30 0x70 0x66 0x01 0x01 $fan_speed`;
|
||
|
}
|
||
|
|
||
|
sub Internal_DoSetFanSpeedCpu {
|
||
|
my ( $fan_speed ) = @_;
|
||
|
`ipmitool raw 0x30 0x70 0x66 0x01 0x00 $fan_speed`;
|
||
|
}
|
||
|
|
||
|
sub SetFanSpeed {
|
||
|
my ( $fan_speed ) = @_;
|
||
|
|
||
|
my $cpu_temp_difference = $g_current_cpu_temp - $g_last_set_cpu_temp;
|
||
|
my $sys_temp_difference = $g_current_sys_temp - $g_last_set_sys_temp;
|
||
|
|
||
|
if( (abs $cpu_temp_difference) > $min_temp_change ) {
|
||
|
print "We last updated fan speed $cpu_temp_difference *C ago (CPU Temperature).\n";
|
||
|
print "Current CPU Temperature is $g_current_cpu_temp *C, setting CPU Fan Speed to $fan_speed\n";
|
||
|
|
||
|
$g_last_set_cpu_temp = $g_current_cpu_temp;
|
||
|
$g_current_fan_duty_cycle = $fan_speed;
|
||
|
|
||
|
Internal_DoSetFanSpeedCpu( $fan_speed );
|
||
|
}
|
||
|
|
||
|
if( (abs $sys_temp_difference) > $min_temp_change ) {
|
||
|
print "We last updated fan speed $sys_temp_difference *C ago (SYS Temperature).\n";
|
||
|
print "Current SYS Temperature is $g_current_sys_temp *C, setting SYS Fan Speed to $fan_speed\n";
|
||
|
|
||
|
$g_last_set_sys_temp = $g_current_sys_temp;
|
||
|
$g_current_fan_duty_cycle = $fan_speed;
|
||
|
|
||
|
Internal_DoSetFanSpeedSys( $fan_speed );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub UpdateFanSpeed {
|
||
|
# Gather statistics for fan speed and CPU Temp and stuch
|
||
|
my $ipmi_output = `ipmitool sdr list full`;
|
||
|
my @vals = split( "\n", $ipmi_output );
|
||
|
|
||
|
my $current_cpu_temp = 0;
|
||
|
my $current_sys_temp = 0;
|
||
|
|
||
|
foreach my $value (@vals) {
|
||
|
|
||
|
if( $value =~ /^(CPU\sTemp).*\s(\d+)\s.*degrees\sC.*/gi ) {
|
||
|
my $cpu_temp = $2;
|
||
|
$current_cpu_temp = max( $cpu_temp, $current_cpu_temp );
|
||
|
}
|
||
|
|
||
|
if( $value =~ /^(System\sTemp).*\s(\d+)\s.*degrees\sC.*/gi ) {
|
||
|
my $sys_temp = $2;
|
||
|
$current_sys_temp = max( $sys_temp, $current_sys_temp );
|
||
|
}
|
||
|
|
||
|
} # foreach my $value (@vals)
|
||
|
|
||
|
$g_current_cpu_temp = $current_cpu_temp;
|
||
|
$g_current_sys_temp = $current_sys_temp;
|
||
|
|
||
|
my $desired_fan_speed_cpu = 0x0;
|
||
|
my $desired_fan_speed_sys = 0x0;
|
||
|
|
||
|
my @cpu_temps = keys %cpu_temp_to_fan_speed;
|
||
|
for my $cpu_temp (@cpu_temps) {
|
||
|
if( $current_cpu_temp > $cpu_temp ) {
|
||
|
# If the current CPU temperature is higher than the temperature enumerated by this hash lookup,
|
||
|
# Then set the desired fan speed (if our value is larger than the existing value)
|
||
|
$desired_fan_speed_cpu = max( $cpu_temp_to_fan_speed{ $cpu_temp }, $desired_fan_speed_cpu );
|
||
|
# print "The fan speed setting for CPU Temp $cpu_temp *C is $cpu_temp_to_fan_speed{$cpu_temp} % duty cycle\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
my @sys_temps = keys %sys_temp_to_fan_speed;
|
||
|
for my $sys_temp (@sys_temps) {
|
||
|
if( $current_sys_temp > $sys_temp ) {
|
||
|
# If the current gPU temperature is higher than the temperature enumerated by this hash lookup,
|
||
|
# Then set the desired fan speed (if our value is larger than the existing value)
|
||
|
$desired_fan_speed_sys = max( $sys_temp_to_fan_speed{ $sys_temp }, $desired_fan_speed_sys );
|
||
|
# print "The fan speed setting for GPU Temp $sys_temp *C is $sys_temp_to_fan_speed{$sys_temp} % duty cycle\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( $desired_fan_speed_cpu == 0x0 ) {
|
||
|
print "\n***** ERROR: Failed to determine a desired fan speed. Forcing CPU fans to 100% duty cycle as a safety fallback measure. *****\n";
|
||
|
$desired_fan_speed_cpu = 0x64;
|
||
|
}
|
||
|
|
||
|
if( $desired_fan_speed_sys == 0x0 ) {
|
||
|
print "\n***** ERROR: Failed to determine a desired fan speed. Forcing SYS fans to 100% duty cycle as a safety fallback measure. *****\n";
|
||
|
$desired_fan_speed_sys = 0x64;
|
||
|
}
|
||
|
|
||
|
#print "Current Fan Duty Cycle: $g_current_fan_duty_cycle%\n";
|
||
|
#print "Desired CPU Fan Duty Cycle: $desired_fan_speed_cpu%\n";
|
||
|
#print "Desired SYS Fan Duty Cycle: $desired_fan_speed_sys%\n";
|
||
|
|
||
|
SetFanSpeed( $desired_fan_speed_cpu );
|
||
|
SetFanSpeed( $desired_fan_speed_sys );
|
||
|
|
||
|
}
|
||
|
|
||
|
print "Setting Fan mode to FULL SPEED.\n";
|
||
|
# Ensure Fan Mode is set to Full Speed
|
||
|
`ipmitool raw 0x30 0x45 0x01 0x01`;
|
||
|
|
||
|
while( 1 ) {
|
||
|
#print "Calling UpdateFanSpeed()...\n";
|
||
|
UpdateFanSpeed();
|
||
|
#print "Update Complete - going to sleep for $seconds_to_sleep seconds...\n";
|
||
|
sleep $seconds_to_sleep;
|
||
|
}
|