homemade_speedstep/src/homemade_speedstep.c

245 lines
6.9 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define VERSION "1.0"
#define POLLING_TIME 1
#define THREADS 4 /* TODO: automatically figure out how many threads host system has */
#define FREQS "/sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies"
#define MAXSPDPREFIX "/sys/devices/system/cpu/cpu"
#define MAXSPDSUFFIX "/cpufreq/scaling_max_freq"
#define CURTEMPPATH "/sys/devices/virtual/thermal/thermal_zone0/temp"
void changespeed(int threads, char* step){
int i;
char filename[100];
FILE* file;
for (i=0; i < threads; i++){
sprintf(filename, MAXSPDPREFIX"%d"MAXSPDSUFFIX, i);
file = fopen(filename, "w");
if (file != NULL){
fprintf(file, "%s\n", step);
fclose(file);
}
}
}
int comparestrings(char *a, char *b){
int c = 0;
while(a[c] != '\0' && b[c] != '\0'){
if(a[c] != b[c]){
return 1;
}
c++;
}
return 0;
}
int getfilec(FILE *file, char arr[]){
int c, i;
i = 0;
while((c = fgetc(file)) != EOF){
arr[i] = c;
i++;
}
arr[i] = '\0';
return i;
}
int powerof(int base, int exponent){
int i, result;
if (exponent == 0){
return result = 1;
}
result = base;
for(i = 0; i < exponent - 1; i++){
result *= base;
}
return result;
}
int stringtoint(char number[], int length){
int j, result;
result = 0;
j = 0;
while(length - 1 >= 0){
result += ((int)number[length - 1] - '0') * (powerof(10, j));
j++;
length--;
}
return result;
}
int stringlength(char string[]){
int i = 0;
while(string[i] != '\0'){
i++;
}
return i;
}
int splitstr(char** dest, char line[], int index1, int index2){
int offset = index1;
while (line[index1] != ' ' && index1 < stringlength(line)){
index1++;
}
char* p = malloc(sizeof (char)*index1);
int i;
for(i = 0; i < index1 - offset; i++){
p[i] = line[i + offset];
}
p[i] = '\0';
dest[index2] = p;
return index1 + 1;
}
int countblanks(char line[]){
int i = 0;
int j = 0;
while(line[i] != '\0'){
if (line[i] == ' '){
j++;
}
i++;
}
return j;
}
void newlinetonullbyte(char string[]){
int i = 0;
while (string[i] != '\0'){
if (string[i] == '\n'){
string[i] = '\0';
break;
}
i++;
}
}
int main(int argc, char** argv){
/* check for no arguments or help */
if (argc == 1 || comparestrings(argv[1], "-h") == 0
|| comparestrings(argv[1], "--help") == 0){
fprintf(stderr, "usage: homemade_speedstep <max temp> <min temp>\n");
fprintf(stderr, " homemade_speedstep [-h | --help | -v | --version]\n");
fprintf(stderr, " -h | --help prints out this help message\n");
fprintf(stderr, " -v | --version prints out version number\n");
return 0;
}
if (comparestrings(argv[1], "-v") == 0
|| comparestrings(argv[1], "--version") == 0){
fprintf(stderr, VERSION"\n");
return 0;
}
/* check for correct ammount of arguments */
if (argc != 3){
fprintf(stderr, "error: wrong ammount of arguments given\n");
fprintf(stderr, " see homemade_speedstep --help\n");
return 1;
}
/* set maxtemp and mintemp TODO: check for integer */
const int maxtemp = stringtoint(argv[1], stringlength(argv[1]));
const int mintemp = stringtoint(argv[2], stringlength(argv[2]));
/* check that the values are, at the very least, different
and that max is higher than min */
if (maxtemp <= mintemp){
fprintf(stderr, "error: maxtemp must be higher than mintemp\n");
return 2;
}
/* try to open scaling_available_frequencies, exit on fail */
FILE *freqsfile = fopen(FREQS, "r");
if (freqsfile == NULL){
fprintf(stderr, "error: couldn't open scaling_available_frequencies\n");
fprintf(stderr, " check that you have support for cpufreq\n");
fprintf(stderr, " in your kernel and that the program is\n");
fprintf(stderr, " running as root\n");
return 5;
}
/* assign content of freqsfile to a temporary char array */
char* freqsfilec = malloc(sizeof(char) * 200);
getfilec(freqsfile, freqsfilec);
int stepc = countblanks(freqsfilec);
/* create a char ** array with pointers to freq steps */
char ** steps = malloc(sizeof(char*) * stepc);
int* index = malloc(sizeof(int*));
*index = 0;
int i;
for(i = 0; i < stepc; i++){
*index = splitstr(steps, freqsfilec, *index, i);
}
/* free memory and close file */
free(index);
free(freqsfilec);
fclose(freqsfile);
/* try to open scaling_maximum_frequency, exit on fail */
FILE* curmaxfile = fopen(MAXSPDPREFIX"0"MAXSPDSUFFIX, "r");
if (curmaxfile == NULL){
fprintf(stderr, "error: couldn't open scaling_maximum_frequency\n");
fprintf(stderr, " check that you have support for cpufreq\n");
fprintf(stderr, " in your kernel and that the program is\n");
fprintf(stderr, " running as root\n");
return 6;
}
/* assign content of curmaxfile to a temporary char array */
char *curmaxfreq = malloc(sizeof(char) * 20);
getfilec(curmaxfile, curmaxfreq);
newlinetonullbyte(curmaxfreq);
/* figure out what step we're on */
int curstep = -1;
for(i = 0; i < stepc; i++){
if (comparestrings(steps[i], curmaxfreq) == 0){
curstep = i;
break;
}
}
/* free memory and close file */
free(curmaxfreq);
fclose(curmaxfile);
/* check if we didn't find our current step, exit on fail */
if (curstep == -1){
fprintf(stderr, "error: couldn't figure out the current frequency\n");
fprintf(stderr, " check that you have support for cpufreq\n");
fprintf(stderr, " in your kernel and that the program is\n");
fprintf(stderr, " running as root\n");
return 7;
}
int timepassed = 0;
int temperature;
FILE* curtempfile;
/* from here onwards an infinite while loop should start */
while((curtempfile = fopen(CURTEMPPATH, "r")) != NULL){
if (timepassed < 61){
timepassed++;
}
char* char_temperature = malloc(sizeof(char) * 8);
getfilec(curtempfile, char_temperature);
newlinetonullbyte(char_temperature);
temperature = stringtoint(char_temperature, stringlength(char_temperature));
free(char_temperature);
/* check if current temp is higher than max and step down */
if (temperature >= maxtemp && curstep < stepc - 1){
curstep++;
changespeed(THREADS, steps[curstep]);
timepassed = 0;
}
/* check if current temp is lower than min and step down */
if (temperature <= mintemp && curstep > 0){
curstep--;
changespeed(THREADS, steps[curstep]);
timepassed = 0;
}
/* check if a minute passed without step changes and temp is below minmax average */
if (timepassed > 60 && temperature <= (mintemp+maxtemp)/2 && curstep > 0){
curstep--;
changespeed(THREADS, steps[curstep]);
timepassed = 0;
}
fclose(curtempfile);
sleep(POLLING_TIME);
}
/* cleanup for graceful exit */
free(steps);
fclose(curtempfile);
return 0;
}