diff options
author | Koan-Sin Tan <freedom.tan@linaro.org> | 2014-12-17 11:00:40 +0800 |
---|---|---|
committer | Tuukka Tikkanen <tuukka.tikkanen@linaro.org> | 2015-01-02 05:43:58 +0200 |
commit | 46a63275690ae8f0d49558f032752b747ec4ee48 (patch) | |
tree | 1302b1956b90dc2371012d042d6644c1d8ed1655 | |
parent | 241e7f176ebfcff47b35145a9bc5f6698c49ba40 (diff) |
Idlestat: Add importing 'trace-cmd report' format
trace-cmd(1) related tools are convenient for getting and
processing traces using Ftrace Linux kernel internal tracer.
Usually, trace-cmd-report(1) is used to convert files from
trace-cmd's trace-cmd.dat(5) binary format to human readable
text files.
Signed-off-by: Koan-Sin Tan <freedom.tan@linaro.org>
Reviewed-by: Tuukka Tikkanen <tuukka.tikkanen@linaro.org>
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | trace_ops.h | 1 | ||||
-rw-r--r-- | tracefile_idlestat.c | 74 | ||||
-rw-r--r-- | tracefile_tracecmd.c | 131 |
4 files changed, 174 insertions, 35 deletions
@@ -24,7 +24,8 @@ CFLAGS?=-g -Wall CC=gcc -TRACE_OBJS = tracefile_idlestat.o tracefile_ftrace.o +TRACE_OBJS = tracefile_idlestat.o tracefile_ftrace.o \ + tracefile_tracecmd.o REPORT_OBJS = default_report.o csv_report.o comparison_report.o diff --git a/trace_ops.h b/trace_ops.h index 8885263..c23d873 100644 --- a/trace_ops.h +++ b/trace_ops.h @@ -11,6 +11,7 @@ struct trace_ops { struct cpuidle_datas *(*load)(const char *filename); }; +extern int load_text_data_line(char *buffer, struct cpuidle_datas *datas, char *format, double *begin, double *end, size_t *count, size_t *start); extern void load_text_data_lines(FILE *f, char *buffer, struct cpuidle_datas *datas); #define EXPORT_TRACE_OPS(tracetype_name) \ diff --git a/tracefile_idlestat.c b/tracefile_idlestat.c index dbf468b..815ec85 100644 --- a/tracefile_idlestat.c +++ b/tracefile_idlestat.c @@ -87,48 +87,54 @@ static struct cpuidle_cstates *load_and_build_cstate_info(FILE* f, char *buffer, return cstates; } -void load_text_data_lines(FILE *f, char *buffer, struct cpuidle_datas *datas) +int load_text_data_line(char *buffer, struct cpuidle_datas *datas, char *format, double *begin, double *end, size_t *count, size_t *start) { unsigned int state, freq, cpu; - double time, begin = 0, end = 0; - size_t count = 0, start = 1; + double time; int ret; - do { - if (strstr(buffer, "cpu_idle")) { - if (sscanf(buffer, TRACE_FORMAT, &time, &state, &cpu) - != 3) { - fprintf(stderr, "warning: Unrecognized cpuidle " - "record. The result of analysis might " - "be wrong.\n"); - continue; - } + if (strstr(buffer, "cpu_idle")) { + if (sscanf(buffer, format, &time, &state, &cpu) + != 3) { + fprintf(stderr, "warning: Unrecognized cpuidle " + "record. The result of analysis might " + "be wrong.\n"); + return -1; + } - if (start) { - begin = time; - start = 0; - } - end = time; - - store_data(time, state, cpu, datas, count); - count++; - continue; - } else if (strstr(buffer, "cpu_frequency")) { - if (sscanf(buffer, TRACE_FORMAT, &time, &freq, &cpu) - != 3) { - fprintf(stderr, "warning: Unrecognized cpufreq " - "record. The result of analysis might " - "be wrong.\n"); - continue; - } - cpu_change_pstate(datas, cpu, freq, time); - count++; - continue; + if (*start) { + *begin = time; + *start = 0; + } + *end = time; + + store_data(time, state, cpu, datas, *count); + (*count)++; + return 0; + } else if (strstr(buffer, "cpu_frequency")) { + if (sscanf(buffer, format, &time, &freq, &cpu) != 3) { + fprintf(stderr, "warning: Unrecognized cpufreq " + "record. The result of analysis might " + "be wrong.\n"); + return -1; } + cpu_change_pstate(datas, cpu, freq, time); + (*count)++; + return 0; + } - ret = get_wakeup_irq(datas, buffer, count); - count += (0 == ret) ? 1 : 0; + ret = get_wakeup_irq(datas, buffer, *count); + *count += (0 == ret) ? 1 : 0; + return 0; +} +void load_text_data_lines(FILE *f, char *buffer, struct cpuidle_datas *datas) +{ + double begin = 0, end = 0; + size_t count = 0, start = 1; + + do { + load_text_data_line(buffer, datas, TRACE_FORMAT, &begin, &end, &count, &start); } while (fgets(buffer, BUFSIZE, f)); fprintf(stderr, "Log is %lf secs long with %zd events\n", diff --git a/tracefile_tracecmd.c b/tracefile_tracecmd.c new file mode 100644 index 0000000..cc7bf35 --- /dev/null +++ b/tracefile_tracecmd.c @@ -0,0 +1,131 @@ +#include "topology.h" +#include "trace_ops.h" +#include "utils.h" +#include "idlestat.h" +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <malloc.h> +#include <assert.h> +#include <values.h> + +#define TRACE_CMD_REPORT_FORMAT "%*[^]]] %lf:%*[^=]=%u%*[^=]=%d" + +void tracecmd_load_text_data_lines(FILE *f, char *buffer, struct cpuidle_datas *datas) +{ + double begin = 0, end = 0; + size_t count = 0, start = 1; + + do { + load_text_data_line(buffer, datas, TRACE_CMD_REPORT_FORMAT, &begin, &end, &count, &start); + } while (fgets(buffer, BUFSIZE, f)); + + fprintf(stderr, "Log is %lf secs long with %zd events\n", + end - begin, count); +} + +static int tracecmd_report_magic(const char *filename) +{ + FILE *f; + char *line; + char buffer[BUFSIZE]; + + f = fopen(filename, "r"); + if (!f) { + fprintf(stderr, "%s: failed to open '%s': %m\n", __func__, + filename); + return -1; + } + + line = fgets(buffer, BUFSIZE, f); + fclose(f); + + return (line != NULL) && !strncmp(buffer, "version = ", 10); +} + +static struct cpuidle_datas * tracecmd_report_load(const char *filename) +{ + FILE *f; + unsigned int nrcpus; + struct cpuidle_datas *datas; + int ret; + char *line; + char buffer[BUFSIZE]; + + f = fopen(filename, "r"); + if (!f) { + fprintf(stderr, "%s: failed to open '%s': %m\n", __func__, + filename); + return ptrerror(NULL); + } + + /* Version line */ + line = fgets(buffer, BUFSIZE, f); + if (!line) + goto error_close; + + /* Number of CPUs */ + nrcpus = 0; + line = fgets(buffer, BUFSIZE, f); + ret = sscanf(buffer, "cpus=%u", &nrcpus); + if (ret != 1) + nrcpus = 0; + line = fgets(buffer, BUFSIZE, f); + + if (!line) + goto error_close; + + if (!nrcpus) { + fclose(f); + return ptrerror("Cannot load trace file (nrcpus == 0)"); + } + + datas = calloc(sizeof(*datas), 1); + if (!datas) { + fclose(f); + return ptrerror(__func__); + } + + datas->nrcpus = nrcpus; + datas->pstates = build_pstate_info(nrcpus); + if (!datas->pstates) + goto propagate_error_free_datas; + + datas->topo = read_sysfs_cpu_topo(); + if (is_err(datas->topo)) + goto propagate_error_free_datas; + + /* Build C-state information from current host sysfs */ + datas->cstates = build_cstate_info(nrcpus); + if (is_err(datas->cstates)) + goto propagate_error_free_datas; + + tracecmd_load_text_data_lines(f, buffer, datas); + + fclose(f); + + return datas; + + propagate_error_free_datas: + fclose(f); + if (!is_err(datas->topo)) + release_cpu_topo_info(datas->topo); + if (!is_err(datas->cstates)) + release_cstate_info(datas->cstates, nrcpus); + free(datas); + return ptrerror(NULL); + + error_close: + fclose(f); + fprintf(stderr, "%s: error or EOF while reading '%s': %m", + __func__, filename); + return ptrerror(NULL); +} + +static const struct trace_ops tracecmd_report_trace_ops = { + .name = "trace-cmd report", + .check_magic = tracecmd_report_magic, + .load = tracecmd_report_load +}; + +EXPORT_TRACE_OPS(tracecmd_report); |