diff --git a/fancontrol.pl b/fancontrol.pl index 0f75ccf..d61c808 100755 --- a/fancontrol.pl +++ b/fancontrol.pl @@ -16,70 +16,43 @@ use List::Util qw[min max]; `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 +my $min_temp_change = 2; # °C minimum change to actually cause a fan speed update +my $seconds_to_sleep = 2; # Number of seconds to sleep between update loops +# 0x64 = 100, 0x00 = 0. # 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; + $cpu_temp_to_fan_speed{80} = 0x64; + $cpu_temp_to_fan_speed{75} = 0x62; + $cpu_temp_to_fan_speed{70} = 0x56; + $cpu_temp_to_fan_speed{65} = 0x52; + $cpu_temp_to_fan_speed{60} = 0x48; + $cpu_temp_to_fan_speed{55} = 0x46; + $cpu_temp_to_fan_speed{50} = 0x42; + $cpu_temp_to_fan_speed{45} = 0x40; + $cpu_temp_to_fan_speed{40} = 0x36; + $cpu_temp_to_fan_speed{35} = 0x34; + $cpu_temp_to_fan_speed{30} = 0x32; # 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; + $sys_temp_to_fan_speed{66} = 0x64; + $sys_temp_to_fan_speed{60} = 0x60; + $sys_temp_to_fan_speed{57} = 0x42; + $sys_temp_to_fan_speed{55} = 0x40; + $sys_temp_to_fan_speed{52} = 0x36; + $sys_temp_to_fan_speed{50} = 0x34; + $sys_temp_to_fan_speed{47} = 0x32; + $sys_temp_to_fan_speed{45} = 0x30; + $sys_temp_to_fan_speed{30} = 0x28; -# Below this line follows the actual implementation of the script - -my $g_current_fan_duty_cycle = 0; +my $g_current_sys_fan_duty_cycle = 0; +my $g_current_cpu_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`; @@ -87,6 +60,8 @@ sub UpdateFanSpeed { my $current_cpu_temp = 0; my $current_sys_temp = 0; + my $cpu_temp_difference = 0; + my $sys_temp_difference = 0; foreach my $value (@vals) { @@ -105,50 +80,63 @@ sub UpdateFanSpeed { $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 $desired_cpu_fan_speed = 0x0; + my $desired_sys_fan_speed = 0x0; my @cpu_temps = keys %cpu_temp_to_fan_speed; for my $cpu_temp (@cpu_temps) { - if( $current_cpu_temp > $cpu_temp ) { + 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 ); + $desired_cpu_fan_speed = max( $cpu_temp_to_fan_speed{ $cpu_temp }, $desired_cpu_fan_speed ); # 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( $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 ); + $desired_sys_fan_speed = max( $sys_temp_to_fan_speed{ $sys_temp }, $desired_sys_fan_speed ); # 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 ) { + if( $desired_cpu_fan_speed == 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; + $desired_cpu_fan_speed = 0x64; } - if( $desired_fan_speed_sys == 0x0 ) { + if( $desired_sys_fan_speed == 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; + $desired_sys_fan_speed = 0x64; + } + + $cpu_temp_difference = $g_current_cpu_temp - $g_last_set_cpu_temp; + $sys_temp_difference = $g_current_sys_temp - $g_last_set_sys_temp; + + if( (abs $sys_temp_difference) > $min_temp_change ) { + print "(SYS) Temp change of $sys_temp_difference °C, current $g_current_sys_temp °C, fan speed set to $desired_sys_fan_speed %\n"; + + $g_last_set_sys_temp = $g_current_sys_temp; + $g_current_sys_fan_duty_cycle = $desired_sys_fan_speed; + + `ipmitool raw 0x30 0x70 0x66 0x01 0x01 $desired_sys_fan_speed`; } - #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"; + if( (abs $cpu_temp_difference) > $min_temp_change ) { + print "(CPU) Temp change of $cpu_temp_difference °C, current $g_current_cpu_temp °C, fan speed set to $desired_cpu_fan_speed %\n"; - SetFanSpeed( $desired_fan_speed_cpu ); - SetFanSpeed( $desired_fan_speed_sys ); + $g_last_set_cpu_temp = $g_current_cpu_temp; + $g_current_cpu_fan_duty_cycle = $desired_cpu_fan_speed; + + `ipmitool raw 0x30 0x70 0x66 0x01 0x00 $desired_cpu_fan_speed`; + } } print "Setting Fan mode to FULL SPEED.\n"; -# Ensure Fan Mode is set to Full Speed `ipmitool raw 0x30 0x45 0x01 0x01`; while( 1 ) {