diff --git a/.gitignore b/.gitignore index a359539..eed27d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ bin/* +*.tar.gz !*.gitkeep diff --git a/Makefile b/Makefile index 85981ae..bea687c 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ CFLAGS = -Wall -Wpedantic -Wextra -O2 -march=native\ SRC = src BINDIR = bin BIN = homemade_speedstep +RELEASE_TAG = $(shell git describe) all: $(BIN) @@ -15,8 +16,11 @@ $(BIN): debug: $(CC) $(CFLAGS) -g $(SRC)/$(BIN).c -o $(BINDIR)/$(BIN) -install: $(BIN) - cp $(BINDIR)/$(BIN) /usr/bin/$(BIN) +release: clean + tar czf homemade_speedstep-$(RELEASE_TAG).tar.gz $(shell ls -A | grep -v "*.tar.gz") + +install: + mv $(BINDIR)/$(BIN) /usr/bin/$(BIN) install-openrc: install cp init.d/$(BIN) /etc/init.d/$(BIN) @@ -25,3 +29,4 @@ install-openrc: install clean: $(RM) -r $(BINDIR)/* + $(RM) ./*.tar.gz diff --git a/src/homemade_speedstep.c b/src/homemade_speedstep.c index acf324e..0a0e71f 100644 --- a/src/homemade_speedstep.c +++ b/src/homemade_speedstep.c @@ -1,117 +1,7 @@ #include #include #include - -#define VERSION "1.1" -#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); - if ((file = fopen(filename, "w")) != 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++; - } -} +#include "homemade_speedstep.h" int main(int argc, char** argv){ /* check for no arguments or help */ @@ -123,6 +13,7 @@ int main(int argc, char** argv){ fprintf(stderr, " -v | --version prints out version number\n"); return 0; } + /* print version number if asked to and exit */ if (comparestrings(argv[1], "-v") == 0 || comparestrings(argv[1], "--version") == 0){ fprintf(stderr, VERSION"\n"); @@ -141,20 +32,21 @@ int main(int argc, char** argv){ and that max is higher than min */ if (maxtemp <= mintemp){ fprintf(stderr, "error: maxtemp must be higher than mintemp\n"); + fprintf(stderr, " see homemade_speedstep --help\n"); return 2; } /* try to open scaling_available_frequencies, exit on fail */ FILE *freqsfile; if ((freqsfile = fopen(FREQS, "r")) == 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"); + FILEERROR("read", "scaling_available_frequencies"); return 5; } /* assign content of freqsfile to a temporary char array */ char* freqsfilec = malloc(sizeof(char) * 200); getfilec(freqsfile, freqsfilec); + /* close file since we no loger use it */ + fclose(freqsfile); + /* count the number of steps (should probably figure out a better way of doing this */ int stepc = countblanks(freqsfilec); /* create a char ** array with pointers to freq steps */ char ** steps = malloc(sizeof(char*) * stepc); @@ -164,22 +56,20 @@ int main(int argc, char** argv){ for(i = 0; i < stepc; i++){ *index = splitstr(steps, freqsfilec, *index, i); } - /* free memory and close file */ + /* free memory */ free(index); free(freqsfilec); - fclose(freqsfile); /* try to open scaling_maximum_frequency, exit on fail */ FILE* curmaxfile; if ((curmaxfile = fopen(MAXSPDPREFIX"0"MAXSPDSUFFIX, "r")) == 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"); + FILEERROR("read", "scaling_maximum_frequency"); return 6; } /* assign content of curmaxfile to a temporary char array */ char *curmaxfreq = malloc(sizeof(char) * 20); getfilec(curmaxfile, curmaxfreq); + /* close file since we're done using it */ + fclose(curmaxfile); newlinetonullbyte(curmaxfreq); /* figure out what step we're on */ int curstep = -1; @@ -189,9 +79,8 @@ int main(int argc, char** argv){ break; } } - /* free memory and close file */ + /* free memory */ 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"); @@ -200,42 +89,58 @@ int main(int argc, char** argv){ fprintf(stderr, " running as root\n"); return 7; } + /* these two go on the stack because we're going to need it throughout + the program's lifetime and also because they're small */ int timepassed = 0; int temperature; FILE* curtempfile; - /* from here onwards an infinite while loop should start */ + /* setup is ready, time to run the main loop */ while((curtempfile = fopen(CURTEMPPATH, "r")) != NULL){ + /* we don't want timepassed to grow infinitely */ if (timepassed < 61){ timepassed++; } + /* 7 chars should be enough to store temp, but I put two more just in case + if temperature is above 9999999ÂșC there's bigger problems than memory */ char* char_temperature = malloc(sizeof(char) * 8); getfilec(curtempfile, char_temperature); + /* close file since we're done using it */ + fclose(curtempfile); newlinetonullbyte(char_temperature); temperature = stringtoint(char_temperature, stringlength(char_temperature)); + /* free memory */ 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]); + if (changefreq(THREADS, steps[curstep]) != 0){ + FILEERROR("write to", "scaling_max_freq"); + return 8; + } timepassed = 0; } /* check if current temp is lower than min and step up */ if (temperature <= mintemp && curstep > 0){ curstep--; - changespeed(THREADS, steps[curstep]); + if (changefreq(THREADS, steps[curstep]) != 0){ + FILEERROR("write to", "scaling_max_freq"); + return 8; + } 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]); + if (changefreq(THREADS, steps[curstep]) != 0){ + FILEERROR("write to", "scaling_max_freq"); + return 8; + } timepassed = 0; } - fclose(curtempfile); sleep(POLLING_TIME); } - /* cleanup for graceful exit */ + /* something went wrong if we're here, make sure to free last dynamic memory */ free(steps); - fclose(curtempfile); - return 0; + FILEERROR("read", "temp"); + return 9; } diff --git a/src/homemade_speedstep.h b/src/homemade_speedstep.h new file mode 100644 index 0000000..cc21863 --- /dev/null +++ b/src/homemade_speedstep.h @@ -0,0 +1,140 @@ +#ifndef STDIO_H +#define STDIO_H +#include +#endif +#ifndef STDLIB_H +#define STDLIB_H +#include +#endif +#ifndef UNISTD_H +#define UNISTD_H +#include +#endif + +#ifndef HOMEMADE_SPEEDSTEP_H +#define HOMEMADE_SPEEDSTEP_H + +#define VERSION "1.2" +#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" +#define FILEERROR(operation, filename) fprintf(stderr, "error: couldn't %s %s\n check that you have support for cpufreq\n in your kernel and that the program is\n running as root\n", operation, filename) + +int changefreq(int threads, char* step); /* change max frequency of 'threads' to 'step', returns 0 on success */ +int comparestrings(char *a, char *b); /* no security checks, make sure at least one of the char arrays is null terminated, returns 0 on success */ +int getfilec(FILE *file, char arr[]); /* fills 'arr[]' with every character on '*file', returns the number of characters written to 'arr[]' as an int */ +int powerof(int base, int exponent); /* returns power of base to the exponent */ +int stringtoint(char number[], int length); /* returns an int of 'length' length from the string 'number', make sure string only has numbers in it or results will not be as expected */ +int stringlength(char string[]); /* no security checks, make sure string is null terminated */ +int splitstr(char** dest, char line[], int index1, int index2); /* add a substring from 'line' to 'dest'. index1 is offset of characters read from 'line' and index2 is the place in 'dest' to store the new char, returns int with new offset of characters read from 'line' + 1 **/ +int countblanks(char line[]); /* */ +void newlinetonullbyte(char string[]); /* */ + +int changefreq(int threads, char* step){ + int i; + char filename[100]; + FILE* file; + for (i=0; i < threads; i++){ + sprintf(filename, MAXSPDPREFIX"%d"MAXSPDSUFFIX, i); + if ((file = fopen(filename, "w")) == NULL){ + return 1; + } + fprintf(file, "%s\n", step); + fclose(file); + } + return 0; +} + +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++; + } +} +#endif