aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTuukka Tikkanen <tuukka.tikkanen@linaro.org>2015-01-21 00:44:32 +0200
committerTuukka Tikkanen <tuukka.tikkanen@linaro.org>2015-01-21 00:44:32 +0200
commit6efac9bed0ec6b7a2e9abc8872e03245d4918f06 (patch)
tree37455aa61d15feed236f2db5e7e12b25c0981de5
parent7d3394ec671ee1f4a80080dcdaac31ed2247a24d (diff)
Idlestat: Add command line options for managing trace buffer
As the kernel trace buffer is a finite resource, the default trace buffer size idlestat sets may either be impossibly large or insufficient to hold the data. This patch adds two new command line options to control buffer size and whether or not it will be polled during the trace period. The polling functionality while tracing is not yet implemented. Signed-off-by: Tuukka Tikkanen <tuukka.tikkanen@linaro.org>
-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);