diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | argparse.c | 14 | ||||
-rw-r--r-- | cpufreq.c | 47 | ||||
-rw-r--r-- | cpulist.c | 110 | ||||
-rw-r--r-- | cpulist.h | 7 | ||||
-rw-r--r-- | cputemp2maxfreq.c | 55 | ||||
-rw-r--r-- | cputemp2maxfreq.h | 3 | ||||
-rw-r--r-- | failsafe.c | 4 | ||||
-rwxr-xr-x | generate_debug_h.sh | 2 |
9 files changed, 202 insertions, 42 deletions
@@ -1,4 +1,4 @@ -cputemp2maxfreq: version.o debug.o sysfs.o cpufreq.o failsafe.o argparse.o logger.o cputemp.o +cputemp2maxfreq: version.o debug.o sysfs.o cpufreq.o failsafe.o argparse.o logger.o cputemp.o cpulist.o version.h: generate_version_h.sh .git/index ./generate_version_h.sh > version.h @@ -30,6 +30,10 @@ void printhelp() " Default: Always set CPU to lowest frequency on exit\n" "-p <time> Poll interval in seconds\n" " Default: %d\n" + "-P <CPU ID> Physical CPU number (socket number) for multi-CPU systems. Given\n" + " a number it will only change the governor/frequency for the\n" + " given CPU, or the word \"all\" to change all CPU's\n" + " Default: all\n" "-s <step> Step size in Khz when increasing/decreasing CPU speed\n" " Default: %ld\n" "-t <number> Temperature limit\n" @@ -73,7 +77,7 @@ void argparse(int argc, char **argv) memcpy(&userconfig,&config,sizeof(struct s_config)); // Parse options - while((opt=getopt(argc,argv,"c:C:d:f:g:hi:kl:mp:s:t:u"))!=-1) + while((opt=getopt(argc,argv,"c:C:d:f:g:hi:kl:mp:P:s:t:u"))!=-1) { DEBUG1_ARGPARSE("Argument: %c Value: %s\n",opt,optarg); switch(opt) @@ -118,6 +122,14 @@ void argparse(int argc, char **argv) case 'p': userconfig.interval=strtoll(optarg,NULL,10); break; + case 'P': + if (strcmp(optarg,"all")==0) + { + userconfig.cpu=-1; + } else { + userconfig.cpu=strtoll(optarg,NULL,10); + } + break; case 's': userconfig.freq_step=strtoll(optarg,NULL,10); break; @@ -7,62 +7,41 @@ #include <sys/types.h> #include "debug.h" #include "sysfs.h" +#include "cputemp2maxfreq.h" -// Validate if we found a file named cpu[0-9][0-9] -int cpufreq_is_cpu(char *name) -{ - if (strncmp(name,"cpu",3)!=0) return 0; - if ((name[3]<'0') || (name[3]>'9')) return 0; - if (name[4]==0) return 1; - - if ((name[4]<'0') || (name[4]>'9')) return 0; - if (name[5]==0) return 1; - - return 0; -} +extern struct s_cpudata cpudata; // Set a cpufreq parameter to a value int cpufreq_set_str(char *parameter,char *value,long int checkdelay) { - DIR *cpudir; - struct dirent *cpu_dirent; + int cpu; char sysfs_file[128]; int done=0; DEBUG1_CPUFREQ("Set %s to %s\n",parameter,value) -// Open the CPU directory in sysfs - cpudir=opendir("/sys/devices/system/cpu"); - if (cpudir==NULL) + if (cpudata.cpulist==NULL) { - DEBUG1_CPUFREQ("Unable to find CPU's\n"); + DEBUG1_CPUFREQ("No CPU list\n"); return -1; } - cpu_dirent=readdir(cpudir); - while(cpu_dirent!=NULL) + for(cpu=0;cpu<cpudata.cpulist_len;cpu++) { -// If it's a CPU, set our parameter - if (cpufreq_is_cpu(cpu_dirent->d_name)) + DEBUG2_CPUFREQ("Set CPU %s\n",cpudata.cpulist[cpu]); + snprintf(sysfs_file,128,"/sys/devices/system/cpu/%s/cpufreq/%s",cpudata.cpulist[cpu],parameter); + if (sysfs_write_str(sysfs_file,value,checkdelay)!=0) { - DEBUG2_CPUFREQ("Found CPU %s\n",cpu_dirent->d_name); - snprintf(sysfs_file,128,"/sys/devices/system/cpu/%s/cpufreq/%s",cpu_dirent->d_name,parameter); - if (sysfs_write_str(sysfs_file,value,checkdelay)!=0) - { - DEBUG1_CPUFREQ("Failed to set %s\n",cpu_dirent->d_name); - closedir(cpudir); - return -1; - } - done++; + DEBUG1_CPUFREQ("Failed to set %s\n",cpudata.cpulist[cpu]); + return -1; } - - cpu_dirent=readdir(cpudir); + done++; } - closedir(cpudir); return done; } + // This is just a wrapper around cpufreq_set_str with long int to string // conversion int cpufreq_set_long_int(char *parameter,long int value,long int checkdelay) diff --git a/cpulist.c b/cpulist.c new file mode 100644 index 0000000..307638d --- /dev/null +++ b/cpulist.c @@ -0,0 +1,110 @@ +#include <fcntl.h> +#include <sys/syscall.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <dirent.h> +#include <sys/types.h> +#include <stdlib.h> +#include "debug.h" +#include "sysfs.h" +#include "cputemp2maxfreq.h" + +extern struct s_config config; +extern struct s_cpudata cpudata; + +// Add a CPU to the list +void cpulist_add(char *cpu) +{ + cpudata.cpulist_len++; + cpudata.cpulist=reallocarray(cpudata.cpulist,cpudata.cpulist_len,sizeof(char *)); + cpudata.cpulist[cpudata.cpulist_len-1]=malloc(strlen(cpu)+1); + strcpy(cpudata.cpulist[cpudata.cpulist_len-1],cpu); + cpudata.cpulist[cpudata.cpulist_len-1][strlen(cpu)]=0; +} + +// Validate if we found a file named cpu[0-9][0-9][0-9] +int cpulist_is_cpu(char *name) +{ + if (strncmp(name,"cpu",3)!=0) return 0; + if ((name[3]<'0') || (name[3]>'9')) return 0; + if (name[4]==0) return 1; + + if ((name[4]<'0') || (name[4]>'9')) return 0; + if (name[5]==0) return 1; + + if ((name[5]<'0') || (name[5]>'9')) return 0; + if (name[6]==0) return 1; + + return 0; +} + +// Set a cpufreq parameter to a value +int cpulist_find_cpus() +{ + DIR *cpudir; + struct dirent *cpu_dirent; + char sysfs_file[128]; + int package; + + DEBUG1_CPULIST("Started\n") + + if (cpudata.cpulist!=NULL) + { + DEBUG1_CPULIST("cpulist already set, free list first\n"); + return -1; + } + cpudata.cpulist_len=0; + +// Open the CPU directory in sysfs + cpudir=opendir("/sys/devices/system/cpu"); + if (cpudir==NULL) + { + DEBUG1_CPULIST("Unable to find CPU's\n"); + return -1; + } + + cpu_dirent=readdir(cpudir); + while(cpu_dirent!=NULL) + { + +// Check if it's a CPU and it belongs to the correct physical package + if (cpulist_is_cpu(cpu_dirent->d_name)) + { + DEBUG2_CPULIST("Found CPU %s\n",cpu_dirent->d_name); + snprintf(sysfs_file,128,"/sys/devices/system/cpu/%s/topology/physical_package_id",cpu_dirent->d_name); + package=sysfs_read_long_int(sysfs_file); + DEBUG2_CPULIST("CPU Belongs to package id %d\n",package); + if ((package==config.cpu) || (config.cpu<0)) + { + DEBUG2_CPULIST("Add to list\n"); + cpulist_add(cpu_dirent->d_name); + } else { + DEBUG2_CPULIST("Skip this CPU\n"); + } + } + + cpu_dirent=readdir(cpudir); + } + closedir(cpudir); + + DEBUG1_CPULIST("Found %d CPU's\n",config.cpulist_len); + if (cpudata.cpulist_len==0) + { + config.logger("Warning: Found no CPU's beloning to physical CPU %d",config.cpu); + } + + return 0; +} + +void cpulist_free() +{ + int count; + if (cpudata.cpulist==NULL) return; + + for(count=0;count<cpudata.cpulist_len;count++) free(cpudata.cpulist[count]); + + free(cpudata.cpulist); + cpudata.cpulist=NULL; + cpudata.cpulist_len=0; +} diff --git a/cpulist.h b/cpulist.h new file mode 100644 index 0000000..b78fc14 --- /dev/null +++ b/cpulist.h @@ -0,0 +1,7 @@ +#ifndef HAVE_CPULIST_H +#define HAVE_CPULIST_H + +int cpulist_find_cpus(); +void cpulist_free(); + +#endif diff --git a/cputemp2maxfreq.c b/cputemp2maxfreq.c index 6921279..cd2da9f 100644 --- a/cputemp2maxfreq.c +++ b/cputemp2maxfreq.c @@ -13,6 +13,7 @@ #include "argparse.h" #include "logger.h" #include "cputemp.h" +#include "cpulist.h" // Set default config struct s_config config={ @@ -32,8 +33,19 @@ struct s_config config={ 0, // Don't use unix timestamps in log outputs -1, // Transition latency, default to autodetect 0, // Do not keep state on exit (Set CPU to lowest frequency) + -1, // Physical CPU to change +}; + +struct s_cpudata cpudata={ + 0, // CPU's minimum frequency + 0, // CPU's maximum frequency + 0, // CPU's current frequency + 0, // CPU's current temperature + 0, // Governor's maximum scaling frequency + 0, // CPU's transition latency + NULL, // Pointer to the cpulist, set by cpulist_find_cpus + 0, // Number of CPU's in cpulist, set by cpulist_find_cpus }; -struct s_cpudata cpudata; void signal_handler(int signum) { @@ -61,6 +73,8 @@ int main(int argc,char **argv) long int newfreq; struct s_sensor sensor; char *transition_latency_remark; + char sensor_string[20]; + char sysfs_file[128]; argparse(argc,argv); config.logger("%s version %s, buildtime %s %s",config.name,version(),__DATE__,__TIME__); @@ -95,6 +109,12 @@ int main(int argc,char **argv) } else { config.logger("State on exit: Always set CPU to lowest frequency"); } + if (config.cpu<0) + { + config.logger("Physical CPU to change: all"); + } else { + config.logger("Physical CPU to change: %d",config.cpu); + } if ((config.max_temp<VALID_TEMP_MIN) || (config.max_temp>VALID_TEMP_MAX)) { @@ -120,6 +140,12 @@ int main(int argc,char **argv) if (strcmp(config.temp_input,"auto")==0) { config.logger("Starting temperature sensor autodetection"); + if (config.cpu>=0) + { + sprintf(sensor_string,"Package id %d",config.cpu); + DEBUG1_MAIN("Searching for sensor \"%s\" because of -P option\n",sensor_string); + cputemp_find_sensor(sensor_string,&sensor); + } for(count=0;autodetect_sensors[count]!=NULL;count++) { DEBUG1_MAIN("Searching for sensor \"%s\"\n",autodetect_sensors[count]); @@ -143,14 +169,31 @@ int main(int argc,char **argv) } } +// Find CPU's + cpulist_find_cpus(); + if (cpudata.cpulist_len==0) + { + if (config.cpu>=0) + { + config.logger("No CPU's found for physical CPU %d, exiting",config.cpu); + } else { + config.logger("Failed to find any CPU, is sysfs mounted?"); + } + exit(1); + } + // Get and validate CPU data - cpudata.min_freq=sysfs_read_long_int("/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_min_freq"); - cpudata.max_freq=sysfs_read_long_int("/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_max_freq"); - cpudata.scale_max=sysfs_read_long_int("/sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq"); + sprintf(sysfs_file,"/sys/devices/system/cpu/%s/cpufreq/cpuinfo_min_freq",cpudata.cpulist[0]); + cpudata.min_freq=sysfs_read_long_int(sysfs_file); + sprintf(sysfs_file,"/sys/devices/system/cpu/%s/cpufreq/cpuinfo_max_freq",cpudata.cpulist[0]); + cpudata.max_freq=sysfs_read_long_int(sysfs_file); + sprintf(sysfs_file,"/sys/devices/system/cpu/%s/cpufreq/scaling_max_freq",cpudata.cpulist[0]); + cpudata.scale_max=sysfs_read_long_int(sysfs_file); if (config.transition_latency<0) { transition_latency_remark=transition_latency_remarks[0]; - cpudata.transition_latency=sysfs_read_long_int("/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_transition_latency"); + sprintf(sysfs_file,"/sys/devices/system/cpu/%s/cpufreq/cpuinfo_transition_latency",cpudata.cpulist[0]); + cpudata.transition_latency=sysfs_read_long_int(sysfs_file); if (cpudata.transition_latency<1000) transition_latency_remark=transition_latency_remarks[2]; } else { transition_latency_remark=transition_latency_remarks[1]; @@ -158,6 +201,7 @@ int main(int argc,char **argv) } config.logger("CPU data:"); + config.logger("Number of CPU's: %d",cpudata.cpulist_len); config.logger("Minimum frequency: %ld",cpudata.min_freq); config.logger("Maximum frequency: %ld",cpudata.max_freq); config.logger("Scaling maximum frequency: %ld",cpudata.scale_max); @@ -170,6 +214,7 @@ int main(int argc,char **argv) { // If we have to fail now, there's not much we can do because we have no data config.logger("Invalid CPU data, exiting"); + cpulist_free(); exit(1); } diff --git a/cputemp2maxfreq.h b/cputemp2maxfreq.h index a901e6d..aefcefc 100644 --- a/cputemp2maxfreq.h +++ b/cputemp2maxfreq.h @@ -28,6 +28,8 @@ struct s_cpudata { long int cur_temp; // CPU's current temperature long int scale_max; // Governor's maximum scaling frequency long int transition_latency; // CPU's transition latency + char **cpulist; // CPU list, set by cpulist_find_cpus + int cpulist_len; // Length of CPU list, set by cpulist_find_cpus }; struct s_config { @@ -47,6 +49,7 @@ struct s_config { char use_unixtime; // Use unixtime timestamps in logs and CSV long int transition_latency; // User configurable transition latency, <0 for autodetect int keepstate; // Keep last state on exit (0=set lowest freq) + int cpu; // CPU to monior when >=0, all on <0 }; #endif @@ -5,6 +5,7 @@ #include "cputemp2maxfreq.h" #include "cpufreq.h" #include "logger.h" +#include "cpulist.h" extern struct s_cpudata cpudata; extern struct s_config config; @@ -21,6 +22,7 @@ void failsafe(int code) if (cpufreq_set_long_int("scaling_max_freq",cpudata.min_freq,100)>0) { config.logger("Set scaling frequency to CPU's minimum frequency"); + cpulist_free(); exit(code); } config.logger("Failed to set scaling frequency to CPU's minimum frequency, error: %d (%s)",errno,strerror(errno)); @@ -29,6 +31,7 @@ void failsafe(int code) if (cpufreq_set_long_int("scaling_max_freq",config.fallback_freq,100)>0) { config.logger("Set scaling frequency to fallback frequency"); + cpulist_free(); exit(code); } config.logger("Failed to set scaling frequency to fallback frequency, error: %d (%s)",errno,strerror(errno)); @@ -40,5 +43,6 @@ void failsafe(int code) config.logger("Keeping current state due to -k option"); } + cpulist_free(); exit(code); } diff --git a/generate_debug_h.sh b/generate_debug_h.sh index 4049af9..8d0a1d4 100755 --- a/generate_debug_h.sh +++ b/generate_debug_h.sh @@ -5,7 +5,7 @@ # Configuration DEBUG_LEVELS=4 -DEBUG_PARTS="MAIN ARGPARSE SYSFS CPUFREQ LOG CPUTEMP" +DEBUG_PARTS="MAIN ARGPARSE SYSFS CPUFREQ LOG CPUTEMP CPULIST" DEBUG_HELPER_DEF=`grep -o "void .*()" debug.c | head -n 1` DEBUG_HELPER=${DEBUG_HELPER_DEF##* } HEXDUMP_HELPER_DEF=`grep -o "void .*(unsigned char \*data,int len)" debug.c` |