From 16fb812a46d0e8cde432b58f7dbf6fce147eb89f Mon Sep 17 00:00:00 2001 From: PA4WDH Date: Wed, 24 May 2023 12:57:25 +0200 Subject: Add CSV logging --- argparse.c | 13 ++++++++++- cputemp2maxfreq.c | 14 ++++++++++++ cputemp2maxfreq.h | 3 +++ failsafe.c | 4 ++++ generate_debug_h.sh | 2 +- logger.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++--- logger.h | 3 +++ 7 files changed, 100 insertions(+), 5 deletions(-) diff --git a/argparse.c b/argparse.c index 7df1239..75ca20d 100644 --- a/argparse.c +++ b/argparse.c @@ -14,6 +14,9 @@ void printhelp() "Usage: %s \n" "\n" "Options:\n" + "-c Write CSV log for later analysis to file. Append data if the\n" + " file already exists\n" + "-C Same as -c but overwrite existing file\n" "-f Fallback frequency in KHz, used when everything fails\n" " Default: %ld\n" "-g cpufreq governor to use, use \"keep\" to keep current governor\n" @@ -56,11 +59,19 @@ void argparse(int argc, char **argv) memcpy(&userconfig,&config,sizeof(struct s_config)); // Parse options - while((opt=getopt(argc,argv,"f:g:hi:l:mp:s:t:"))!=-1) + while((opt=getopt(argc,argv,"c:C:f:g:hi:l:mp:s:t:"))!=-1) { DEBUG1_ARGPARSE("Argument: %c Value: %s\n",opt,optarg); switch(opt) { + case 'c': + strncpy(userconfig.csvlog,optarg,sizeof(userconfig.csvlog)); + userconfig.csvoverwrite=0; + break; + case 'C': + strncpy(userconfig.csvlog,optarg,sizeof(userconfig.csvlog)); + userconfig.csvoverwrite=1; + break; case 'f': userconfig.fallback_freq=strtoll(optarg,NULL,10); break; diff --git a/cputemp2maxfreq.c b/cputemp2maxfreq.c index 826655a..556e404 100644 --- a/cputemp2maxfreq.c +++ b/cputemp2maxfreq.c @@ -25,6 +25,9 @@ struct s_config config={ "stdout", // Logger name &logger_stdout, // Logger function 0, // Don't log measurement data + "", // CSV logfile + 0, // Don't overwrite CSV logfile + NULL, // File handler for CSV file }; struct s_cpudata cpudata; @@ -52,6 +55,13 @@ int main(int argc,char **argv) config.logger("Interval: %d",config.interval); config.logger("Logger: %s (%p)",config.logger_name,config.logger); config.logger("Log measurement data: %d",config.log_data); + if (config.csvlog[0]==0) + { + config.logger("CSV Log file: Disabled"); + } else { + config.logger("CSV Log file: %s",config.csvlog); + config.logger("Overwrite CSV log: %d",config.csvoverwrite); + } if ((config.max_tempVALID_TEMP_MAX)) { @@ -114,6 +124,9 @@ int main(int argc,char **argv) } } +// Initialise CSV logging + if (config.csvlog[0]!=0) csvlog_init(); + // Set signal handlers signal(SIGTERM,signal_handler); signal(SIGINT,signal_handler); @@ -141,6 +154,7 @@ int main(int argc,char **argv) { config.logger("CPU Temperature: %ld, CPU Frequency: %ld",cpudata.cur_temp/1000,cpudata.cur_freq); } + if (config.csvfile!=NULL) csvlog_write(); // Check if we should increase if ((cpudata.cur_temp #include "cputemp2maxfreq.h" #include "cpufreq.h" +#include "logger.h" extern struct s_cpudata cpudata; extern struct s_config config; void failsafe(int code) { +// Close CSV log if used + if (config.csvfile!=NULL) csvlog_close(); + // First try to set the CPU to it's minimum frequency if (cpufreq_set_long_int("scaling_max_freq",cpudata.min_freq,100)>0) { diff --git a/generate_debug_h.sh b/generate_debug_h.sh index f32ac5c..209495c 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" +DEBUG_PARTS="MAIN ARGPARSE SYSFS CPUFREQ LOG" 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` diff --git a/logger.c b/logger.c index 83e92e1..143b62e 100644 --- a/logger.c +++ b/logger.c @@ -3,13 +3,16 @@ #include #include #include -#include "cputemp2maxfreq.h" #include +#include +#include "cputemp2maxfreq.h" +#include "debug.h" extern struct s_config config; +extern struct s_cpudata cpudata; -// These functions are not called directly. They are set by argparse in the -// config.logger function pointer. +// The logger_* functions are not called directly. They are set by argparse in +// the config.logger function pointer. // No logging at all void logger_none(char *format,...) { } @@ -69,3 +72,60 @@ void logger_kmsg(char *format,...) config.logger(buffer); } } + +// CSV logging fields: +// 1: Timestamp +// 2: CPU Minimum frequency +// 3: CPU Maximum frequency +// 4: CPU Current frequency +// 5: CPU Temperature +// 6: Target temperature +// 7: Scaling maximum frequency before increase/decrease +void csvlog_init() +{ + int exists; + + DEBUG1_LOG("Started\n"); + exists=access(config.csvlog,F_OK); + DEBUG1_LOG("File %s exists: %d\n",config.csvlog,exists); + + if ((exists!=0) || (config.csvoverwrite==1)) + { + DEBUG1_LOG("Creating/overwriting CSV file\n"); + config.csvfile=fopen(config.csvlog,"w"); + fputs("\"timestamp\"," + "\"CPU Minumum frequency\"," + "\"CPU Maximum frequency\"," + "\"CPU Current frequency\"," + "\"CPU Temperature\"," + "\"Target temperature\"," + "\"Scaling maximum frequency\"\n",config.csvfile); + } else { + DEBUG1_LOG("Appending to CSV file\n"); + config.csvfile=fopen(config.csvlog,"a"); + } +} + +// Write a single line of CSV data +void csvlog_write() +{ + struct timeval unixtime; + struct tm *time; + char timestring[255]; + + DEBUG1_LOG("Writing data series to CSV file\n"); + + gettimeofday(&unixtime,NULL); + time=localtime(&unixtime.tv_sec); + strftime(timestring,255,"%F %T",time); + + fprintf(config.csvfile,"\"%s\",\"%ld\",\"%ld\",\"%ld\",\"%ld\",\"%ld\",\"%ld\"\n",timestring,cpudata.min_freq,cpudata.max_freq,cpudata.cur_freq,cpudata.cur_temp/1000,config.max_temp/1000,cpudata.scale_max); +} + +// Close the CSV file +void csvlog_close() +{ + DEBUG1_LOG("Closing CSV file\n"); + fclose(config.csvfile); + config.csvfile=NULL; +} diff --git a/logger.h b/logger.h index b9ee787..c8535f1 100644 --- a/logger.h +++ b/logger.h @@ -5,5 +5,8 @@ void logger_none(char *format,...); void logger_stdout(char *format,...); void logger_syslog(char *format,...); void logger_kmsg(char *format,...); +void csvlog_init(); +void csvlog_write(); +void csvlog_close(); #endif -- cgit v1.2.3