#include #include #include #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 \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; }