diff options
-rw-r--r-- | idlestat.c | 27 | ||||
-rw-r--r-- | idlestat.h | 6 | ||||
-rw-r--r-- | trace.c | 52 | ||||
-rw-r--r-- | trace.h | 3 |
4 files changed, 77 insertions, 11 deletions
@@ -1000,6 +1000,8 @@ int getoptions(int argc, char *argv[], struct program_options *options) { "wakeup", no_argument, NULL, 'w' }, { "boxless-report", no_argument, NULL, 'B' }, { "csv-report", no_argument, NULL, 'C' }, + { "poll-interval", required_argument, NULL, 'I' }, + { "buffer-size", required_argument, NULL, 'S' }, { "version", no_argument, NULL, 'V' }, { 0, 0, 0, 0 } }; @@ -1014,7 +1016,7 @@ int getoptions(int argc, char *argv[], struct program_options *options) int optindex = 0; - c = getopt_long(argc, argv, ":b:ce:f:ho:pr:t:vwBCV", + c = getopt_long(argc, argv, ":b:ce:f:ho:pr:t:vwBCI:S:V", long_options, &optindex); if (c == -1) break; @@ -1079,6 +1081,12 @@ int getoptions(int argc, char *argv[], struct program_options *options) fprintf(stderr, "-B: report type already set to %s\n", options->report_type_name); return -1; + case 'I': + options->tbs.poll_interval = atoi(optarg); + break; + case 'S': + options->tbs.percpu_buffer_size = atoi(optarg); + break; case 0: /* getopt_long() set a variable, just keep going */ break; case ':': /* missing option argument */ @@ -1374,11 +1382,22 @@ int main(int argc, char *argv[], char *const envp[]) if (is_err(saved_trace_options)) return 1; + /* + * Calculate/verify buffer size and polling trace data + * interval. The interval or may may not be used to + * transfer data from kernel trace buffer to some + * storage media. It is needed for long eventful traces, + * but is not preferred. If the user does not specify + * the values, we will calculate reasonable defaults. + */ + if (calculate_buffer_parameters(options.duration, &options.tbs)) + return 1; + /* Initialize the traces for cpu_idle and increase the - * buffer size to let 'idlestat' to sleep instead of - * acquiring data, hence preventing it to pertubate the + * buffer size to let 'idlestat' to possibly sleep instead + * of acquiring data, hence preventing it to pertubate the * measurements. */ - if (idlestat_init_trace(options.duration)) + if (idlestat_init_trace(options.tbs.percpu_buffer_size)) goto err_restore_trace_options; /* Remove all the previous traces */ @@ -124,10 +124,16 @@ enum modes { IMPORT }; +struct trace_buffer_settings { + unsigned int percpu_buffer_size; + unsigned int poll_interval; +}; + struct program_options { int mode; int display; unsigned int duration; + struct trace_buffer_settings tbs; char *filename; char *baseline_filename; char *outfilename; @@ -36,6 +36,7 @@ #include <fts.h> #include "trace.h" +#include "idlestat.h" #include "utils.h" #include "list.h" @@ -163,9 +164,13 @@ cannot_get_event_options: return ptrerror(NULL); } -int idlestat_init_trace(unsigned int duration) +int calculate_buffer_parameters(unsigned int duration, + struct trace_buffer_settings *tbs) { - int bufsize; + unsigned int def_bufsize; + + if (tbs->poll_interval == 0) + tbs->poll_interval = duration; /* Assuming the worst case where we can have for cpuidle, * TRACE_IDLE_NRHITS_PER_SEC. Each state enter/exit line are @@ -175,17 +180,50 @@ int idlestat_init_trace(unsigned int duration) * Divide by 2^10 to have Kb. We add 1Kb to be sure to round up. */ - bufsize = 2 * TRACE_IDLE_LENGTH * TRACE_IDLE_NRHITS_PER_SEC; - bufsize += TRACE_CPUFREQ_LENGTH * TRACE_CPUFREQ_NRHITS_PER_SEC; - bufsize = (bufsize * duration / (1 << 10)) + 1; + if (tbs->percpu_buffer_size == 0) { + def_bufsize = 2 * TRACE_IDLE_LENGTH; + def_bufsize *= TRACE_IDLE_NRHITS_PER_SEC; + def_bufsize += TRACE_CPUFREQ_LENGTH * + TRACE_CPUFREQ_NRHITS_PER_SEC; + def_bufsize = (def_bufsize * tbs->poll_interval / (1 << 10)); + def_bufsize += 1; + + tbs->percpu_buffer_size = def_bufsize; + } + + if (tbs->poll_interval >= duration) { + verbose_printf(1, + "Polling is disabled during trace " + "(polling interval exceeds trace duration).\n"); + } else { + verbose_printf(1, "Polling interval: %u s\n", + tbs->poll_interval); + } + verbose_printf(1, "Per cpu trace buffer: %u kB\n", + tbs->percpu_buffer_size); + + return 0; +} - if (write_int(TRACE_BUFFER_SIZE_PATH, bufsize)) +int idlestat_init_trace(unsigned int percpu_bufsize) +{ + int bufsize = (int)percpu_bufsize; + + if (write_int(TRACE_BUFFER_SIZE_PATH, bufsize)) { + fprintf(stderr, + "Failed to set trace buffer to desired size. If the " + "error was caused by failure in memory allocation, " + "try to increase buffer size (-S, --buffer-size) " + "or decrease polling interval " + "(-I, --polling-interval).\n" + "Increase verbosity (-v) to see current values\n"); return -1; + } if (read_int(TRACE_BUFFER_TOTAL_PATH, &bufsize)) return -1; - printf("Total trace buffer: %d kB\n", bufsize); + verbose_printf(1, "Total trace buffer: %d kB\n", bufsize); /* Disable all the traces */ if (write_int(TRACE_EVENT_PATH, 0)) @@ -40,9 +40,12 @@ #define TRACE_CPUFREQ_LENGTH 196 struct trace_options; +struct trace_buffer_settings; extern int idlestat_trace_enable(bool enable); extern int idlestat_flush_trace(void); +extern int calculate_buffer_parameters(unsigned int duration, + struct trace_buffer_settings *tbs); extern int idlestat_init_trace(unsigned int duration); extern struct trace_options *idlestat_store_trace_options(void); extern int idlestat_restore_trace_options(struct trace_options *options); |