Created
June 24, 2017 07:41
-
-
Save syldrathecat/355f4ebfcbe001eaebf7ded36666b53c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <unistd.h> | |
#define HWMON_BASE "/sys/class/hwmon" | |
#define GPU_HWMON "hwmon0" // amdgpu | |
#define GPU_TEMP_TEMP "temp1" // no name | |
#define GPU_FAN_PWM "pwm1" | |
#define CHIPSET_HWMON "hwmon1" // nct6791 | |
#define SYSTIN_TEMP_TEMP "temp1" // "SYSTIN" | |
#define CPUTIN_TEMP_TEMP "temp2" // "CPUTIN" | |
#define PECI_TEMP_TEMP "temp7" // "PECI Agent 0" | |
#define CPU_FAN_PWM "pwm2" | |
#define CHA1_FAN_PWM "pwm5" | |
#define CHA2_FAN_PWM "pwm4" | |
// Unused | |
#define CPU_HWMON "hwmon2" // coretemp | |
#define CPU_TEMP_TEMP "temp1" // "Physical id 0" | |
const char* gpu_temp_temp_filename = HWMON_BASE "/" GPU_HWMON "/" GPU_TEMP_TEMP "_input"; | |
const char* cpu_temp_temp_filename = HWMON_BASE "/" CHIPSET_HWMON "/" CPUTIN_TEMP_TEMP "_input"; | |
const char* core_temp_temp_filename = HWMON_BASE "/" CHIPSET_HWMON "/" PECI_TEMP_TEMP "_input"; | |
const char* sys_temp_temp_filename = HWMON_BASE "/" CHIPSET_HWMON "/" SYSTIN_TEMP_TEMP "_input"; | |
const char* gpu_fan_pwm_filename = HWMON_BASE "/" GPU_HWMON "/" GPU_FAN_PWM; | |
const char* cpu_fan_pwm_filename = HWMON_BASE "/" CHIPSET_HWMON "/" CPU_FAN_PWM; | |
const char* cha1_fan_pwm_filename = HWMON_BASE "/" CHIPSET_HWMON "/" CHA1_FAN_PWM; | |
const char* cha2_fan_pwm_filename = HWMON_BASE "/" CHIPSET_HWMON "/" CHA2_FAN_PWM; | |
int gpu_temp = -1; | |
int cpu_temp = -1; | |
int sys_temp = -1; | |
int gpu_state = 0; | |
int cpu_state = 0; | |
int sys_state = 0; | |
int gpu_pwm_old = -1; | |
int cpu_pwm_old = -1; | |
int cha1_pwm_old = -1; | |
int cha2_pwm_old = -1; | |
int gpu_pwm = -1; | |
int cpu_pwm = -1; | |
int cha1_pwm = -1; | |
int cha2_pwm = -1; | |
void write_number(const char* filename, int num) | |
{ | |
char buf[32]; | |
snprintf(buf, sizeof buf, "%d", num); | |
FILE* fh = fopen(filename, "wt"); | |
if (fh) | |
{ | |
fputs(buf, fh); | |
fclose(fh); | |
} | |
} | |
int read_number(const char* filename) | |
{ | |
char buf[32]; | |
FILE* hwmon = fopen(filename, "r"); | |
int num = -1; | |
if (hwmon != NULL && fgets(buf, 32, hwmon)) | |
{ | |
sscanf(buf, "%d", &num); | |
fclose(hwmon); | |
} | |
return num; | |
} | |
void enable_control() | |
{ | |
const char* gpu_fan_pwm_enable_filename = HWMON_BASE "/" GPU_HWMON "/" GPU_FAN_PWM "_enable"; | |
const char* cpu_fan_pwm_enable_filename = HWMON_BASE "/" CHIPSET_HWMON "/" CPU_FAN_PWM "_enable"; | |
const char* cha1_fan_pwm_enable_filename = HWMON_BASE "/" CHIPSET_HWMON "/" CHA1_FAN_PWM "_enable"; | |
const char* cha2_fan_pwm_enable_filename = HWMON_BASE "/" CHIPSET_HWMON "/" CHA2_FAN_PWM "_enable"; | |
write_number(gpu_fan_pwm_enable_filename, 1); | |
write_number(cpu_fan_pwm_enable_filename, 1); | |
write_number(cha1_fan_pwm_enable_filename, 1); | |
write_number(cha2_fan_pwm_enable_filename, 1); | |
} | |
void gather_inputs(int tick) | |
{ | |
(void)tick; | |
gpu_temp = read_number(gpu_temp_temp_filename); | |
cpu_temp = read_number(cpu_temp_temp_filename); | |
sys_temp = read_number(sys_temp_temp_filename); | |
} | |
void state_rule(const int* temp_in, int* state_inout, int hyst) | |
{ | |
int temp = *temp_in; | |
int state = *state_inout; | |
if (temp >= state + hyst) | |
*state_inout = temp / hyst * hyst; | |
if (temp > 0 && temp < state - hyst) | |
*state_inout = temp / hyst * hyst; | |
} | |
#define GPU_FAN_IDLE 0 | |
#define GPU_FAN_LOW 80 | |
#define GPU_FAN_MID 100 | |
#define GPU_FAN_HIGH 120 | |
#define CPU_FAN_IDLE 60 | |
#define CPU_FAN_LOW 120 | |
#define CPU_FAN_MID 155 | |
#define CPU_FAN_HIGH 220 | |
#define CHA1_FAN_IDLE 100 | |
#define CHA1_FAN_LOW 140 | |
#define CHA1_FAN_MID 180 | |
#define CHA1_FAN_HIGH 220 | |
#define CHA2_FAN_IDLE 100 | |
#define CHA2_FAN_LOW 100 | |
#define CHA2_FAN_MID 150 | |
#define CHA2_FAN_HIGH 255 | |
int x_gpu_fan_on = 0; | |
int max(int a, int b) | |
{ | |
return (a > b) ? a : b; | |
} | |
void thermal_rules(int tick) | |
{ | |
(void)tick; | |
state_rule(&gpu_temp, &gpu_state, 1000); | |
state_rule(&cpu_temp, &cpu_state, 5000); | |
state_rule(&sys_temp, &sys_state, 2000); | |
int adj_gpu_state = gpu_state - sys_state; | |
// GPU fan | |
if (adj_gpu_state >= 15000 || gpu_state >= 45000) | |
gpu_pwm = GPU_FAN_LOW + (max(adj_gpu_state - 15000, gpu_state - 44000) / 1000) * 5; | |
else if (adj_gpu_state >= 10000 || gpu_state >= 45000) | |
gpu_pwm = GPU_FAN_LOW; | |
else if (x_gpu_fan_on) | |
gpu_pwm = GPU_FAN_LOW; | |
else | |
gpu_pwm = GPU_FAN_IDLE; | |
// Extra hacky logic to disable GPU fan at 30C rather than 40C | |
if (!x_gpu_fan_on) | |
{ | |
if (gpu_pwm != GPU_FAN_IDLE) | |
x_gpu_fan_on = 1; | |
} | |
else | |
{ | |
if (adj_gpu_state <= 5000) | |
{ | |
gpu_pwm = GPU_FAN_IDLE; | |
x_gpu_fan_on = 0; | |
} | |
} | |
x_gpu_fan_on = (gpu_pwm != GPU_FAN_IDLE); | |
// CPU fan | |
if (cpu_state >= 65000) | |
cpu_pwm = 255; | |
else if (cpu_state >= 55000) | |
cpu_pwm = CPU_FAN_HIGH; | |
else if (cpu_state >= 50000) | |
cpu_pwm = CPU_FAN_MID; | |
else if (cpu_state >= 45000) | |
cpu_pwm = CPU_FAN_LOW; | |
else | |
cpu_pwm = CPU_FAN_IDLE; | |
// CHA1 fan | |
if (cpu_state >= 45000) | |
cha1_pwm = CHA1_FAN_HIGH; | |
else if (cpu_state >= 40000) | |
cha1_pwm = CHA1_FAN_MID; | |
else if (cpu_state >= 35000) | |
cha1_pwm = CHA1_FAN_LOW; | |
else | |
cha1_pwm = CHA1_FAN_IDLE; | |
// CHA2 fan | |
if (sys_state >= 44000 || cha1_pwm >= CHA1_FAN_HIGH) | |
cha2_pwm = CHA2_FAN_HIGH; | |
else if (sys_state >= 40000 || gpu_state >= 50000 || cha1_pwm >= CHA1_FAN_MID) | |
cha2_pwm = CHA2_FAN_MID; | |
else if (sys_state >= 36000 || gpu_pwm >= GPU_FAN_LOW || cpu_state >= 40000) | |
cha2_pwm = CHA2_FAN_LOW; | |
else | |
cha2_pwm = CHA2_FAN_IDLE; | |
if (cha2_pwm >= CHA2_FAN_HIGH && cha1_pwm <= CHA1_FAN_MID) | |
cha1_pwm = CHA1_FAN_MID; | |
if (cha2_pwm >= CHA2_FAN_MID && cha1_pwm <= CHA1_FAN_LOW) | |
cha1_pwm = CHA1_FAN_LOW; | |
} | |
void apply_pwm(int tick) | |
{ | |
(void)tick; | |
if (gpu_pwm != gpu_pwm_old) | |
{ | |
write_number(gpu_fan_pwm_filename, gpu_pwm); | |
gpu_pwm_old = gpu_pwm; | |
} | |
if (cpu_pwm != cpu_pwm_old) | |
{ | |
write_number(cpu_fan_pwm_filename, cpu_pwm); | |
cpu_pwm_old = cpu_pwm; | |
} | |
if (cha1_pwm != cha1_pwm_old) | |
{ | |
write_number(cha1_fan_pwm_filename, cha1_pwm); | |
cha1_pwm_old = cha1_pwm; | |
} | |
if (cha2_pwm != cha2_pwm_old) | |
{ | |
write_number(cha2_fan_pwm_filename, cha2_pwm); | |
cha2_pwm_old = cha2_pwm; | |
} | |
} | |
int main() | |
{ | |
enable_control(); | |
for (int tick = 0; ; ++tick) | |
{ | |
gather_inputs(tick); | |
thermal_rules(tick); | |
apply_pwm(tick); | |
usleep(1000000); | |
} | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment