aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--idlestat.c27
-rw-r--r--idlestat.h6
-rw-r--r--trace.c52
-rw-r--r--trace.h3
4 files changed, 77 insertions, 11 deletions
diff --git a/idlestat.c b/idlestat.c
index 68b47f5..1c1e8ac 100644
--- a/idlestat.c
+++ b/idlestat.c
@@ -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 */
diff --git a/idlestat.h b/idlestat.h
index 4018b8d..076f6a5 100644
--- a/idlestat.h
+++ b/idlestat.h
@@ -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;
diff --git a/trace.c b/trace.c
index 09f9573..f365032 100644
--- a/trace.c
+++ b/trace.c
@@ -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))
diff --git a/trace.h b/trace.h
index 52893ee..a2f5867 100644
--- a/trace.h
+++ b/trace.h
@@ -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);