aboutsummaryrefslogtreecommitdiffstats
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.c152
1 files changed, 115 insertions, 37 deletions
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 9bcc38f0b706..aa26f4d66d10 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -32,6 +32,10 @@
32#include "util/session.h" 32#include "util/session.h"
33#include "util/svghelper.h" 33#include "util/svghelper.h"
34 34
35#define SUPPORT_OLD_POWER_EVENTS 1
36#define PWR_EVENT_EXIT -1
37
38
35static char const *input_name = "perf.data"; 39static char const *input_name = "perf.data";
36static char const *output_name = "output.svg"; 40static char const *output_name = "output.svg";
37 41
@@ -260,9 +264,6 @@ pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end)
260 c->start_time = start; 264 c->start_time = start;
261 if (p->start_time == 0 || p->start_time > start) 265 if (p->start_time == 0 || p->start_time > start)
262 p->start_time = start; 266 p->start_time = start;
263
264 if (cpu > numcpus)
265 numcpus = cpu;
266} 267}
267 268
268#define MAX_CPUS 4096 269#define MAX_CPUS 4096
@@ -272,19 +273,25 @@ static int cpus_cstate_state[MAX_CPUS];
272static u64 cpus_pstate_start_times[MAX_CPUS]; 273static u64 cpus_pstate_start_times[MAX_CPUS];
273static u64 cpus_pstate_state[MAX_CPUS]; 274static u64 cpus_pstate_state[MAX_CPUS];
274 275
275static int process_comm_event(event_t *event, struct perf_session *session __used) 276static int process_comm_event(union perf_event *event,
277 struct perf_sample *sample __used,
278 struct perf_session *session __used)
276{ 279{
277 pid_set_comm(event->comm.tid, event->comm.comm); 280 pid_set_comm(event->comm.tid, event->comm.comm);
278 return 0; 281 return 0;
279} 282}
280 283
281static int process_fork_event(event_t *event, struct perf_session *session __used) 284static int process_fork_event(union perf_event *event,
285 struct perf_sample *sample __used,
286 struct perf_session *session __used)
282{ 287{
283 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); 288 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
284 return 0; 289 return 0;
285} 290}
286 291
287static int process_exit_event(event_t *event, struct perf_session *session __used) 292static int process_exit_event(union perf_event *event,
293 struct perf_sample *sample __used,
294 struct perf_session *session __used)
288{ 295{
289 pid_exit(event->fork.pid, event->fork.time); 296 pid_exit(event->fork.pid, event->fork.time);
290 return 0; 297 return 0;
@@ -298,12 +305,21 @@ struct trace_entry {
298 int lock_depth; 305 int lock_depth;
299}; 306};
300 307
301struct power_entry { 308#ifdef SUPPORT_OLD_POWER_EVENTS
309static int use_old_power_events;
310struct power_entry_old {
302 struct trace_entry te; 311 struct trace_entry te;
303 u64 type; 312 u64 type;
304 u64 value; 313 u64 value;
305 u64 cpu_id; 314 u64 cpu_id;
306}; 315};
316#endif
317
318struct power_processor_entry {
319 struct trace_entry te;
320 u32 state;
321 u32 cpu_id;
322};
307 323
308#define TASK_COMM_LEN 16 324#define TASK_COMM_LEN 16
309struct wakeup_entry { 325struct wakeup_entry {
@@ -470,48 +486,79 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
470} 486}
471 487
472 488
473static int process_sample_event(event_t *event, struct perf_session *session) 489static int process_sample_event(union perf_event *event __used,
490 struct perf_sample *sample,
491 struct perf_evsel *evsel __used,
492 struct perf_session *session)
474{ 493{
475 struct sample_data data;
476 struct trace_entry *te; 494 struct trace_entry *te;
477 495
478 memset(&data, 0, sizeof(data));
479
480 event__parse_sample(event, session->sample_type, &data);
481
482 if (session->sample_type & PERF_SAMPLE_TIME) { 496 if (session->sample_type & PERF_SAMPLE_TIME) {
483 if (!first_time || first_time > data.time) 497 if (!first_time || first_time > sample->time)
484 first_time = data.time; 498 first_time = sample->time;
485 if (last_time < data.time) 499 if (last_time < sample->time)
486 last_time = data.time; 500 last_time = sample->time;
487 } 501 }
488 502
489 te = (void *)data.raw_data; 503 te = (void *)sample->raw_data;
490 if (session->sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) { 504 if (session->sample_type & PERF_SAMPLE_RAW && sample->raw_size > 0) {
491 char *event_str; 505 char *event_str;
492 struct power_entry *pe; 506#ifdef SUPPORT_OLD_POWER_EVENTS
493 507 struct power_entry_old *peo;
494 pe = (void *)te; 508 peo = (void *)te;
495 509#endif
510 /*
511 * FIXME: use evsel, its already mapped from id to perf_evsel,
512 * remove perf_header__find_event infrastructure bits.
513 * Mapping all these "power:cpu_idle" strings to the tracepoint
514 * ID and then just comparing against evsel->attr.config.
515 *
516 * e.g.:
517 *
518 * if (evsel->attr.config == power_cpu_idle_id)
519 */
496 event_str = perf_header__find_event(te->type); 520 event_str = perf_header__find_event(te->type);
497 521
498 if (!event_str) 522 if (!event_str)
499 return 0; 523 return 0;
500 524
501 if (strcmp(event_str, "power:power_start") == 0) 525 if (sample->cpu > numcpus)
502 c_state_start(pe->cpu_id, data.time, pe->value); 526 numcpus = sample->cpu;
527
528 if (strcmp(event_str, "power:cpu_idle") == 0) {
529 struct power_processor_entry *ppe = (void *)te;
530 if (ppe->state == (u32)PWR_EVENT_EXIT)
531 c_state_end(ppe->cpu_id, sample->time);
532 else
533 c_state_start(ppe->cpu_id, sample->time,
534 ppe->state);
535 }
536 else if (strcmp(event_str, "power:cpu_frequency") == 0) {
537 struct power_processor_entry *ppe = (void *)te;
538 p_state_change(ppe->cpu_id, sample->time, ppe->state);
539 }
540
541 else if (strcmp(event_str, "sched:sched_wakeup") == 0)
542 sched_wakeup(sample->cpu, sample->time, sample->pid, te);
503 543
504 if (strcmp(event_str, "power:power_end") == 0) 544 else if (strcmp(event_str, "sched:sched_switch") == 0)
505 c_state_end(pe->cpu_id, data.time); 545 sched_switch(sample->cpu, sample->time, te);
506 546
507 if (strcmp(event_str, "power:power_frequency") == 0) 547#ifdef SUPPORT_OLD_POWER_EVENTS
508 p_state_change(pe->cpu_id, data.time, pe->value); 548 if (use_old_power_events) {
549 if (strcmp(event_str, "power:power_start") == 0)
550 c_state_start(peo->cpu_id, sample->time,
551 peo->value);
509 552
510 if (strcmp(event_str, "sched:sched_wakeup") == 0) 553 else if (strcmp(event_str, "power:power_end") == 0)
511 sched_wakeup(data.cpu, data.time, data.pid, te); 554 c_state_end(sample->cpu, sample->time);
512 555
513 if (strcmp(event_str, "sched:sched_switch") == 0) 556 else if (strcmp(event_str,
514 sched_switch(data.cpu, data.time, te); 557 "power:power_frequency") == 0)
558 p_state_change(peo->cpu_id, sample->time,
559 peo->value);
560 }
561#endif
515 } 562 }
516 return 0; 563 return 0;
517} 564}
@@ -937,7 +984,8 @@ static struct perf_event_ops event_ops = {
937 984
938static int __cmd_timechart(void) 985static int __cmd_timechart(void)
939{ 986{
940 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0, false); 987 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
988 0, false, &event_ops);
941 int ret = -EINVAL; 989 int ret = -EINVAL;
942 990
943 if (session == NULL) 991 if (session == NULL)
@@ -968,7 +1016,8 @@ static const char * const timechart_usage[] = {
968 NULL 1016 NULL
969}; 1017};
970 1018
971static const char *record_args[] = { 1019#ifdef SUPPORT_OLD_POWER_EVENTS
1020static const char * const record_old_args[] = {
972 "record", 1021 "record",
973 "-a", 1022 "-a",
974 "-R", 1023 "-R",
@@ -980,16 +1029,43 @@ static const char *record_args[] = {
980 "-e", "sched:sched_wakeup", 1029 "-e", "sched:sched_wakeup",
981 "-e", "sched:sched_switch", 1030 "-e", "sched:sched_switch",
982}; 1031};
1032#endif
1033
1034static const char * const record_new_args[] = {
1035 "record",
1036 "-a",
1037 "-R",
1038 "-f",
1039 "-c", "1",
1040 "-e", "power:cpu_frequency",
1041 "-e", "power:cpu_idle",
1042 "-e", "sched:sched_wakeup",
1043 "-e", "sched:sched_switch",
1044};
983 1045
984static int __cmd_record(int argc, const char **argv) 1046static int __cmd_record(int argc, const char **argv)
985{ 1047{
986 unsigned int rec_argc, i, j; 1048 unsigned int rec_argc, i, j;
987 const char **rec_argv; 1049 const char **rec_argv;
1050 const char * const *record_args = record_new_args;
1051 unsigned int record_elems = ARRAY_SIZE(record_new_args);
1052
1053#ifdef SUPPORT_OLD_POWER_EVENTS
1054 if (!is_valid_tracepoint("power:cpu_idle") &&
1055 is_valid_tracepoint("power:power_start")) {
1056 use_old_power_events = 1;
1057 record_args = record_old_args;
1058 record_elems = ARRAY_SIZE(record_old_args);
1059 }
1060#endif
988 1061
989 rec_argc = ARRAY_SIZE(record_args) + argc - 1; 1062 rec_argc = record_elems + argc - 1;
990 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1063 rec_argv = calloc(rec_argc + 1, sizeof(char *));
991 1064
992 for (i = 0; i < ARRAY_SIZE(record_args); i++) 1065 if (rec_argv == NULL)
1066 return -ENOMEM;
1067
1068 for (i = 0; i < record_elems; i++)
993 rec_argv[i] = strdup(record_args[i]); 1069 rec_argv[i] = strdup(record_args[i]);
994 1070
995 for (j = 1; j < (unsigned int)argc; j++, i++) 1071 for (j = 1; j < (unsigned int)argc; j++, i++)
@@ -1018,6 +1094,8 @@ static const struct option options[] = {
1018 OPT_CALLBACK('p', "process", NULL, "process", 1094 OPT_CALLBACK('p', "process", NULL, "process",
1019 "process selector. Pass a pid or process name.", 1095 "process selector. Pass a pid or process name.",
1020 parse_process), 1096 parse_process),
1097 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
1098 "Look for files with symbols relative to this directory"),
1021 OPT_END() 1099 OPT_END()
1022}; 1100};
1023 1101