aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKoan-Sin Tan <freedom.tan@linaro.org>2014-12-17 11:00:40 +0800
committerTuukka Tikkanen <tuukka.tikkanen@linaro.org>2015-01-02 05:43:58 +0200
commit46a63275690ae8f0d49558f032752b747ec4ee48 (patch)
tree1302b1956b90dc2371012d042d6644c1d8ed1655
parent241e7f176ebfcff47b35145a9bc5f6698c49ba40 (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--Makefile3
-rw-r--r--trace_ops.h1
-rw-r--r--tracefile_idlestat.c74
-rw-r--r--tracefile_tracecmd.c131
4 files changed, 174 insertions, 35 deletions
diff --git a/Makefile b/Makefile
index 0739707..af22abe 100644
--- a/Makefile
+++ b/Makefile
@@ -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);