Skip to content

Instantly share code, notes, and snippets.

@jbedo
Created July 1, 2011 10:37
Show Gist options
  • Save jbedo/1058282 to your computer and use it in GitHub Desktop.
Save jbedo/1058282 to your computer and use it in GitHub Desktop.
ATI temperature controller
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<math.h>
#include<string.h>
#include<limits.h>
#define NADAPTERS 4
static const int MAXCLOCK = 950;
static const int MINCLOCK = 500;
static const int STARTCLOCK = 800;
static const float TARGET = 95;
static const float TOL = 2;
static const float P = 5;
static const int LOADTHRESH = 95;
static const int SLEEPTIME = 5;
typedef struct adapt adapt;
struct adapt{
float temp;
int clock;
int load;
};
adapt adapters[NADAPTERS];
int
parse_int(char *str, char *buf)
{
char *num, *end;
int n;
n = strlen(str);
if(strncmp(buf, str, n)){
fprintf(stderr, "Error parsing string: %s\n", buf);
return INT_MIN;
}
num = buf + n;
for(end = num; *end <= '9' && *end >= '0' && end != '\0'; end++);
*end = '\0';
return atoi(num);
}
int
fetch(void)
{
FILE *ati;
char buf[1024];
int tiktok;
char *num, *end;
int id = -1;
/* Read in the temperatures */
if((ati = popen("aticonfig --adapter=all --odgt", "r")) == NULL){
fprintf(stderr, "Error executing aticonfig to fetch temperatures\n");
return -1;
}
tiktok = 0;
while(fgets(buf, sizeof(buf) - 1, ati) != NULL){
switch(tiktok){
case 0:
break;
case 1:
if((id = parse_int("Adapter ", buf)) == INT_MIN){
pclose(ati);
return -1;
}
break;
case 2:
if(id < 0 || id >= NADAPTERS)
abort();
if(strncmp(buf, " Sensor 0: Temperature - ", 36)){
fprintf(stderr, "Error parsing temperature string: %s\n", buf);
pclose(ati);
return -1;
}
num = buf + 36;
for(end = num; *end != ' ' && end != '\0'; end++);
*end = '\0';
adapters[id].temp = atof(num);
break;
default:
abort();
}
tiktok = (1 + tiktok) % 3;
}
pclose(ati);
/* Now the clock speeds and workloads */
if((ati = popen("aticonfig --adapter=all --odgc", "r")) == NULL){
fprintf(stderr, "Error executing aticonfig to fetch clocks\n");
return -1;
}
tiktok = 0;
while(fgets(buf, sizeof(buf) - 1, ati) != NULL){
switch(tiktok){
case 1:
if((id = parse_int("Adapter ", buf)) == INT_MIN){
pclose(ati);
return -1;
}
break;
case 3:
if(id < 0 || id >= NADAPTERS)
abort();
adapters[id].clock = parse_int(" Current Clocks : ", buf);
break;
case 6:
if(id < 0 || id >= NADAPTERS)
abort();
if((adapters[id].load = parse_int(" GPU load : ", buf)) == INT_MIN){
pclose(ati);
return -1;
}
break;
default:
break;
}
tiktok = (1 + tiktok) % 7;
}
pclose(ati);
}
int
setclock(int i)
{
char buf[512];
sprintf(buf, "aticonfig --adapter=%d --odsc=%d,%d > /dev/null", i, adapters[i].clock, adapters[i].clock - 100);
if(system(buf) != 0){
fprintf(stderr, "Error setting adapter %d to %d: \n", i, adapters[i].clock, buf);
return -1;
}
return 0;
}
int
main(int argc, char **argv)
{
int i;
float error;
for(;;){
if(!fetch()){
for(i = 0; i < NADAPTERS; i++){
error = TARGET - adapters[i].temp;
if(fabs(error) > TOL && (error < 0 || adapters[i].load > LOADTHRESH)){
if(error > 0 && adapters[i].clock >= MAXCLOCK)
continue;
adapters[i].clock += P * error;
if(adapters[i].clock > MAXCLOCK)
adapters[i].clock = MAXCLOCK;
if(adapters[i].clock < MINCLOCK)
adapters[i].clock = MINCLOCK;
printf("%d,%d: %g %d\n", i, adapters[i].clock, adapters[i].temp, adapters[i].load);
setclock(i);
}
}
}else
fprintf(stderr, "Fetch error. Skipping.\n");
sleep(SLEEPTIME);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment