summaryrefslogtreecommitdiff
path: root/tools/perf/builtin-timechart.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-timechart.c')
-rw-r--r--tools/perf/builtin-timechart.c176
1 files changed, 99 insertions, 77 deletions
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 4536a92b18f3..c2e02319347a 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -12,6 +12,8 @@
* of the License.
*/
+#include <traceevent/event-parse.h>
+
#include "builtin.h"
#include "util/util.h"
@@ -19,6 +21,7 @@
#include "util/color.h"
#include <linux/list.h>
#include "util/cache.h"
+#include "util/evlist.h"
#include "util/evsel.h"
#include <linux/rbtree.h>
#include "util/symbol.h"
@@ -328,25 +331,6 @@ struct wakeup_entry {
int success;
};
-/*
- * trace_flag_type is an enumeration that holds different
- * states when a trace occurs. These are:
- * IRQS_OFF - interrupts were disabled
- * IRQS_NOSUPPORT - arch does not support irqs_disabled_flags
- * NEED_RESCED - reschedule is requested
- * HARDIRQ - inside an interrupt handler
- * SOFTIRQ - inside a softirq handler
- */
-enum trace_flag_type {
- TRACE_FLAG_IRQS_OFF = 0x01,
- TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
- TRACE_FLAG_NEED_RESCHED = 0x04,
- TRACE_FLAG_HARDIRQ = 0x08,
- TRACE_FLAG_SOFTIRQ = 0x10,
-};
-
-
-
struct sched_switch {
struct trace_entry te;
char prev_comm[TASK_COMM_LEN];
@@ -479,6 +463,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
}
}
+typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
+ struct perf_sample *sample);
static int process_sample_event(struct perf_tool *tool __maybe_unused,
union perf_event *event __maybe_unused,
@@ -486,8 +472,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
struct perf_evsel *evsel,
struct machine *machine __maybe_unused)
{
- struct trace_entry *te;
-
if (evsel->attr.sample_type & PERF_SAMPLE_TIME) {
if (!first_time || first_time > sample->time)
first_time = sample->time;
@@ -495,69 +479,90 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
last_time = sample->time;
}
- te = (void *)sample->raw_data;
- if ((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size > 0) {
- char *event_str;
-#ifdef SUPPORT_OLD_POWER_EVENTS
- struct power_entry_old *peo;
- peo = (void *)te;
-#endif
- /*
- * FIXME: use evsel, its already mapped from id to perf_evsel,
- * remove perf_header__find_event infrastructure bits.
- * Mapping all these "power:cpu_idle" strings to the tracepoint
- * ID and then just comparing against evsel->attr.config.
- *
- * e.g.:
- *
- * if (evsel->attr.config == power_cpu_idle_id)
- */
- event_str = perf_header__find_event(te->type);
-
- if (!event_str)
- return 0;
-
- if (sample->cpu > numcpus)
- numcpus = sample->cpu;
-
- if (strcmp(event_str, "power:cpu_idle") == 0) {
- struct power_processor_entry *ppe = (void *)te;
- if (ppe->state == (u32)PWR_EVENT_EXIT)
- c_state_end(ppe->cpu_id, sample->time);
- else
- c_state_start(ppe->cpu_id, sample->time,
- ppe->state);
- }
- else if (strcmp(event_str, "power:cpu_frequency") == 0) {
- struct power_processor_entry *ppe = (void *)te;
- p_state_change(ppe->cpu_id, sample->time, ppe->state);
- }
+ if (sample->cpu > numcpus)
+ numcpus = sample->cpu;
+
+ if (evsel->handler.func != NULL) {
+ tracepoint_handler f = evsel->handler.func;
+ return f(evsel, sample);
+ }
+
+ return 0;
+}
+
+static int
+process_sample_cpu_idle(struct perf_evsel *evsel __maybe_unused,
+ struct perf_sample *sample)
+{
+ struct power_processor_entry *ppe = sample->raw_data;
+
+ if (ppe->state == (u32) PWR_EVENT_EXIT)
+ c_state_end(ppe->cpu_id, sample->time);
+ else
+ c_state_start(ppe->cpu_id, sample->time, ppe->state);
+ return 0;
+}
+
+static int
+process_sample_cpu_frequency(struct perf_evsel *evsel __maybe_unused,
+ struct perf_sample *sample)
+{
+ struct power_processor_entry *ppe = sample->raw_data;
+
+ p_state_change(ppe->cpu_id, sample->time, ppe->state);
+ return 0;
+}
+
+static int
+process_sample_sched_wakeup(struct perf_evsel *evsel __maybe_unused,
+ struct perf_sample *sample)
+{
+ struct trace_entry *te = sample->raw_data;
+
+ sched_wakeup(sample->cpu, sample->time, sample->pid, te);
+ return 0;
+}
- else if (strcmp(event_str, "sched:sched_wakeup") == 0)
- sched_wakeup(sample->cpu, sample->time, sample->pid, te);
+static int
+process_sample_sched_switch(struct perf_evsel *evsel __maybe_unused,
+ struct perf_sample *sample)
+{
+ struct trace_entry *te = sample->raw_data;
- else if (strcmp(event_str, "sched:sched_switch") == 0)
- sched_switch(sample->cpu, sample->time, te);
+ sched_switch(sample->cpu, sample->time, te);
+ return 0;
+}
#ifdef SUPPORT_OLD_POWER_EVENTS
- if (use_old_power_events) {
- if (strcmp(event_str, "power:power_start") == 0)
- c_state_start(peo->cpu_id, sample->time,
- peo->value);
-
- else if (strcmp(event_str, "power:power_end") == 0)
- c_state_end(sample->cpu, sample->time);
-
- else if (strcmp(event_str,
- "power:power_frequency") == 0)
- p_state_change(peo->cpu_id, sample->time,
- peo->value);
- }
-#endif
- }
+static int
+process_sample_power_start(struct perf_evsel *evsel __maybe_unused,
+ struct perf_sample *sample)
+{
+ struct power_entry_old *peo = sample->raw_data;
+
+ c_state_start(peo->cpu_id, sample->time, peo->value);
return 0;
}
+static int
+process_sample_power_end(struct perf_evsel *evsel __maybe_unused,
+ struct perf_sample *sample)
+{
+ c_state_end(sample->cpu, sample->time);
+ return 0;
+}
+
+static int
+process_sample_power_frequency(struct perf_evsel *evsel __maybe_unused,
+ struct perf_sample *sample)
+{
+ struct power_entry_old *peo = sample->raw_data;
+
+ p_state_change(peo->cpu_id, sample->time, peo->value);
+ return 0;
+}
+#endif /* SUPPORT_OLD_POWER_EVENTS */
+
/*
* After the last sample we need to wrap up the current C/P state
* and close out each CPU for these.
@@ -974,6 +979,17 @@ static int __cmd_timechart(const char *output_name)
.sample = process_sample_event,
.ordered_samples = true,
};
+ const struct perf_evsel_str_handler power_tracepoints[] = {
+ { "power:cpu_idle", process_sample_cpu_idle },
+ { "power:cpu_frequency", process_sample_cpu_frequency },
+ { "sched:sched_wakeup", process_sample_sched_wakeup },
+ { "sched:sched_switch", process_sample_sched_switch },
+#ifdef SUPPORT_OLD_POWER_EVENTS
+ { "power:power_start", process_sample_power_start },
+ { "power:power_end", process_sample_power_end },
+ { "power:power_frequency", process_sample_power_frequency },
+#endif
+ };
struct perf_session *session = perf_session__new(input_name, O_RDONLY,
0, false, &perf_timechart);
int ret = -EINVAL;
@@ -984,6 +1000,12 @@ static int __cmd_timechart(const char *output_name)
if (!perf_session__has_traces(session, "timechart record"))
goto out_delete;
+ if (perf_session__set_tracepoints_handlers(session,
+ power_tracepoints)) {
+ pr_err("Initializing session tracepoint handlers failed\n");
+ goto out_delete;
+ }
+
ret = perf_session__process_events(session, &perf_timechart);
if (ret)
goto out_delete;