Skip to content

Instantly share code, notes, and snippets.

@syldrathecat
Created June 24, 2017 07:41
Show Gist options
  • Save syldrathecat/355f4ebfcbe001eaebf7ded36666b53c to your computer and use it in GitHub Desktop.
Save syldrathecat/355f4ebfcbe001eaebf7ded36666b53c to your computer and use it in GitHub Desktop.
#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