diff options
author | Koan-Sin Tan <freedom.tan@linaro.org> | 2014-12-30 14:17:47 +0800 |
---|---|---|
committer | Tuukka Tikkanen <tuukka.tikkanen@linaro.org> | 2015-01-02 05:08:33 +0200 |
commit | 4f89e2ee90c16932606aa6278ec46b4f6295b4ba (patch) | |
tree | d72fa2a9acac1426848526793998863d380ea5c6 | |
parent | c4433ad725b6128eda8018dbc8aa1094e01f9b88 (diff) |
Idlestat: Save and restore kernel ftrace options
Idlestat modifies the kernel trace options via sysfs interface every
time a trace is created. The user may have prefer to have the original
trace options restored once idlestat is finished with the task. This
patch adds code to save and restore the trace options that might be
modified by idlestat.
idlestore_store_trace_options(): Saves the options by 1) record the
original trace buffer size and 2) scan the whole ftrace event
hierarchy, storing the paths of enabled event types into a list.
idlestat_restore_trace_options(): Restores the options including
buffer size and enabled events. Disables all other events.
Signed-off-by: Koan-Sin Tan <freedom.tan@linaro.org>
Signed-off-by: Tuukka Tikkanen <tuukka.tikkanen@linaro.org>
-rw-r--r-- | idlestat.c | 33 | ||||
-rw-r--r-- | trace.c | 118 | ||||
-rw-r--r-- | trace.h | 4 | ||||
-rw-r--r-- | utils.c | 24 | ||||
-rw-r--r-- | utils.h | 1 |
5 files changed, 170 insertions, 10 deletions
@@ -1578,6 +1578,7 @@ int main(int argc, char *argv[], char *const envp[]) struct init_pstates *initp = NULL; struct report_ops *output_handler = NULL; struct cpu_topology *cpu_topo = NULL; + struct trace_options *saved_trace_options = NULL; void *report_data = NULL; args = getoptions(argc, argv, &options); @@ -1616,7 +1617,6 @@ int main(int argc, char *argv[], char *const envp[]) /* Acquisition time specified means we will get the traces */ if ((options.mode == TRACE) || args < argc) { - /* Read cpu topology info from sysfs */ cpu_topo = read_sysfs_cpu_topo(); if (is_err(cpu_topo)) { @@ -1632,48 +1632,52 @@ int main(int argc, char *argv[], char *const envp[]) return 1; } + saved_trace_options = idlestat_store_trace_options(); + if (is_err(saved_trace_options)) + 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 * measurements. */ if (idlestat_init_trace(options.duration)) - return 1; + goto err_restore_trace_options; /* Remove all the previous traces */ if (idlestat_flush_trace()) - return 1; + goto err_restore_trace_options; /* Get starting timestamp */ if (get_trace_ts(&start_ts) == -1) - return 1; + goto err_restore_trace_options; initp = build_init_pstates(); /* Start the recording */ if (idlestat_trace_enable(true)) - return 1; + goto err_restore_trace_options; /* We want to prevent to begin the acquisition with a cpu in * idle state because we won't be able later to close the * state and to determine which state it was. */ if (idlestat_wake_all()) - return 1; + goto err_restore_trace_options; /* Execute the command or wait a specified delay */ if (execute(argc - args, &argv[args], envp, &options)) - return 1; + goto err_restore_trace_options; /* Wake up all cpus again to account for last idle state */ if (idlestat_wake_all()) - return 1; + goto err_restore_trace_options; /* Stop tracing */ if (idlestat_trace_enable(false)) - return 1; + goto err_restore_trace_options; /* Get ending timestamp */ if (get_trace_ts(&end_ts) == -1) - return 1; + goto err_restore_trace_options; /* At this point we should have some spurious wake up * at the beginning of the traces and at the end (wake @@ -1682,6 +1686,10 @@ int main(int argc, char *argv[], char *const envp[]) * of other traces and could be negligible. */ if (idlestat_store(options.filename, start_ts, end_ts, initp, cpu_topo)) + goto err_restore_trace_options; + + /* Restore original kernel ftrace options */ + if (idlestat_restore_trace_options(saved_trace_options)) return 1; /* Discard topology, will be reloaded during trace load */ @@ -1747,4 +1755,9 @@ int main(int argc, char *argv[], char *const envp[]) output_handler->release_report_data(report_data); return 0; + + err_restore_trace_options: + /* Restore original kernel ftrace options */ + idlestat_restore_trace_options(saved_trace_options); + return 1; } @@ -30,9 +30,43 @@ #include <stdbool.h> #include <unistd.h> #include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fts.h> #include "trace.h" #include "utils.h" +#include "list.h" + +struct trace_options { + int buffer_size; + struct list_head list; +}; + +struct enabled_eventtype { + char *name; + struct list_head list; +}; + +int idlestat_restore_trace_options(struct trace_options *options) +{ + struct enabled_eventtype *pos, *n; + int write_problem = 0; + + if (write_int(TRACE_BUFFER_SIZE_PATH, options->buffer_size)) + write_problem = -1; + + list_for_each_entry_safe(pos, n, &options->list, list) { + if (write_int(pos->name, 1)) + write_problem = -1; + + free(pos->name); + list_del(&pos->list); + free(pos); + } + free(options); + return write_problem; +} int idlestat_trace_enable(bool enable) { @@ -44,6 +78,90 @@ int idlestat_flush_trace(void) return write_int(TRACE_FILE, 0); } +static int events_scan(char *name, struct list_head *head) +{ + FTSENT *file = NULL; + char value; + struct enabled_eventtype *found_type; + char *paths[2]; + + paths[0] = name; + paths[1] = NULL; + + FTS *fts = fts_open(paths, FTS_PHYSICAL, NULL); + if (!fts) + return error("fts_open"); + + while (NULL != (file = fts_read(fts))) { + if (file->fts_info == FTS_ERR) { + fprintf(stderr, "%s: %s\n", file->fts_path, + strerror(file->fts_errno)); + fts_close(fts); + return -1; + } + + if (strcmp(file->fts_name, "enable")) + continue; + + if (read_char(file->fts_path, &value)) { + fts_close(fts); + return -1; + } + + if (value != '1') + continue; + + found_type = calloc(1, sizeof(struct enabled_eventtype)); + if (!found_type) { + fts_close(fts); + return error(__func__); + } + + found_type->name = strdup(file->fts_path); + if (!found_type->name) { + free(found_type); + return error(__func__); + } + + list_add(&found_type->list, head); + } + + fts_close(fts); + return 0; +} + +#define TRACE_EVENTS_DIR TRACE_PATH "/events/" + +struct trace_options *idlestat_store_trace_options() +{ + int status; + struct trace_options *options; + struct enabled_eventtype *pos, *n; + + options = calloc(1, sizeof(struct trace_options)); + if (!options) + return ptrerror(__func__); + INIT_LIST_HEAD(&options->list); + + if (read_int(TRACE_BUFFER_SIZE_PATH, &options->buffer_size)) + goto cannot_get_event_options; + + status = events_scan(TRACE_EVENTS_DIR, &options->list); + if (status == 0) + return options; + +cannot_get_event_options: + /* Failure, clean up */ + list_for_each_entry_safe(pos, n, &options->list, list) { + free(pos->name); + list_del(&pos->list); + free(pos); + } + + free(options); + return ptrerror(NULL); +} + int idlestat_init_trace(unsigned int duration) { int bufsize; @@ -39,8 +39,12 @@ #define TRACE_CPUFREQ_NRHITS_PER_SEC 100 #define TRACE_CPUFREQ_LENGTH 196 +struct trace_options; + extern int idlestat_trace_enable(bool enable); extern int idlestat_flush_trace(void); 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); #endif @@ -126,6 +126,30 @@ int read_int(const char *path, int *val) return 0; } +int read_char(const char *path, char *val) +{ + FILE *f; + int ret; + + f = fopen(path, "r"); + + if (!f) { + fprintf(stderr, "failed to open '%s': %m\n", path); + return -1; + } + + ret = fscanf(f, "%c", val); + fclose(f); + + if (ret != 1) { + fprintf(stderr, + "%s: failed to parse a char\n", path); + return -1; + } + + return 0; +} + int store_line(const char *line, void *data) { FILE *f = data; @@ -35,6 +35,7 @@ extern int verbose_fprintf(FILE *f, int min_level, const char *fmt, ...); extern int write_int(const char *path, int val); extern int read_int(const char *path, int *val); +extern int read_char(const char *path, char *val); extern int store_line(const char *line, void *data); extern int file_read_value(const char *path, const char *name, const char *format, void *value); |