diff options
Diffstat (limited to 'tools/perf/builtin-timechart.c')
-rw-r--r-- | tools/perf/builtin-timechart.c | 132 |
1 files changed, 98 insertions, 34 deletions
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 9bcc38f0b706..746cf03cb05d 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 | |||
35 | static char const *input_name = "perf.data"; | 39 | static char const *input_name = "perf.data"; |
36 | static char const *output_name = "output.svg"; | 40 | static char const *output_name = "output.svg"; |
37 | 41 | ||
@@ -272,19 +276,22 @@ static int cpus_cstate_state[MAX_CPUS]; | |||
272 | static u64 cpus_pstate_start_times[MAX_CPUS]; | 276 | static u64 cpus_pstate_start_times[MAX_CPUS]; |
273 | static u64 cpus_pstate_state[MAX_CPUS]; | 277 | static u64 cpus_pstate_state[MAX_CPUS]; |
274 | 278 | ||
275 | static int process_comm_event(event_t *event, struct perf_session *session __used) | 279 | static int process_comm_event(event_t *event, struct sample_data *sample __used, |
280 | struct perf_session *session __used) | ||
276 | { | 281 | { |
277 | pid_set_comm(event->comm.tid, event->comm.comm); | 282 | pid_set_comm(event->comm.tid, event->comm.comm); |
278 | return 0; | 283 | return 0; |
279 | } | 284 | } |
280 | 285 | ||
281 | static int process_fork_event(event_t *event, struct perf_session *session __used) | 286 | static int process_fork_event(event_t *event, struct sample_data *sample __used, |
287 | struct perf_session *session __used) | ||
282 | { | 288 | { |
283 | pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); | 289 | pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); |
284 | return 0; | 290 | return 0; |
285 | } | 291 | } |
286 | 292 | ||
287 | static int process_exit_event(event_t *event, struct perf_session *session __used) | 293 | static int process_exit_event(event_t *event, struct sample_data *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 | ||
301 | struct power_entry { | 308 | #ifdef SUPPORT_OLD_POWER_EVENTS |
309 | static int use_old_power_events; | ||
310 | struct 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 | |||
318 | struct 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 |
309 | struct wakeup_entry { | 325 | struct wakeup_entry { |
@@ -470,48 +486,65 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) | |||
470 | } | 486 | } |
471 | 487 | ||
472 | 488 | ||
473 | static int process_sample_event(event_t *event, struct perf_session *session) | 489 | static int process_sample_event(event_t *event __used, |
490 | struct sample_data *sample, | ||
491 | struct perf_session *session) | ||
474 | { | 492 | { |
475 | struct sample_data data; | ||
476 | struct trace_entry *te; | 493 | struct trace_entry *te; |
477 | 494 | ||
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) { | 495 | if (session->sample_type & PERF_SAMPLE_TIME) { |
483 | if (!first_time || first_time > data.time) | 496 | if (!first_time || first_time > sample->time) |
484 | first_time = data.time; | 497 | first_time = sample->time; |
485 | if (last_time < data.time) | 498 | if (last_time < sample->time) |
486 | last_time = data.time; | 499 | last_time = sample->time; |
487 | } | 500 | } |
488 | 501 | ||
489 | te = (void *)data.raw_data; | 502 | te = (void *)sample->raw_data; |
490 | if (session->sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) { | 503 | if (session->sample_type & PERF_SAMPLE_RAW && sample->raw_size > 0) { |
491 | char *event_str; | 504 | char *event_str; |
492 | struct power_entry *pe; | 505 | #ifdef SUPPORT_OLD_POWER_EVENTS |
493 | 506 | struct power_entry_old *peo; | |
494 | pe = (void *)te; | 507 | peo = (void *)te; |
495 | 508 | #endif | |
496 | event_str = perf_header__find_event(te->type); | 509 | event_str = perf_header__find_event(te->type); |
497 | 510 | ||
498 | if (!event_str) | 511 | if (!event_str) |
499 | return 0; | 512 | return 0; |
500 | 513 | ||
501 | if (strcmp(event_str, "power:power_start") == 0) | 514 | if (strcmp(event_str, "power:cpu_idle") == 0) { |
502 | c_state_start(pe->cpu_id, data.time, pe->value); | 515 | struct power_processor_entry *ppe = (void *)te; |
516 | if (ppe->state == (u32)PWR_EVENT_EXIT) | ||
517 | c_state_end(ppe->cpu_id, sample->time); | ||
518 | else | ||
519 | c_state_start(ppe->cpu_id, sample->time, | ||
520 | ppe->state); | ||
521 | } | ||
522 | else if (strcmp(event_str, "power:cpu_frequency") == 0) { | ||
523 | struct power_processor_entry *ppe = (void *)te; | ||
524 | p_state_change(ppe->cpu_id, sample->time, ppe->state); | ||
525 | } | ||
526 | |||
527 | else if (strcmp(event_str, "sched:sched_wakeup") == 0) | ||
528 | sched_wakeup(sample->cpu, sample->time, sample->pid, te); | ||
503 | 529 | ||
504 | if (strcmp(event_str, "power:power_end") == 0) | 530 | else if (strcmp(event_str, "sched:sched_switch") == 0) |
505 | c_state_end(pe->cpu_id, data.time); | 531 | sched_switch(sample->cpu, sample->time, te); |
506 | 532 | ||
507 | if (strcmp(event_str, "power:power_frequency") == 0) | 533 | #ifdef SUPPORT_OLD_POWER_EVENTS |
508 | p_state_change(pe->cpu_id, data.time, pe->value); | 534 | if (use_old_power_events) { |
535 | if (strcmp(event_str, "power:power_start") == 0) | ||
536 | c_state_start(peo->cpu_id, sample->time, | ||
537 | peo->value); | ||
509 | 538 | ||
510 | if (strcmp(event_str, "sched:sched_wakeup") == 0) | 539 | else if (strcmp(event_str, "power:power_end") == 0) |
511 | sched_wakeup(data.cpu, data.time, data.pid, te); | 540 | c_state_end(sample->cpu, sample->time); |
512 | 541 | ||
513 | if (strcmp(event_str, "sched:sched_switch") == 0) | 542 | else if (strcmp(event_str, |
514 | sched_switch(data.cpu, data.time, te); | 543 | "power:power_frequency") == 0) |
544 | p_state_change(peo->cpu_id, sample->time, | ||
545 | peo->value); | ||
546 | } | ||
547 | #endif | ||
515 | } | 548 | } |
516 | return 0; | 549 | return 0; |
517 | } | 550 | } |
@@ -937,7 +970,8 @@ static struct perf_event_ops event_ops = { | |||
937 | 970 | ||
938 | static int __cmd_timechart(void) | 971 | static int __cmd_timechart(void) |
939 | { | 972 | { |
940 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0, false); | 973 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, |
974 | 0, false, &event_ops); | ||
941 | int ret = -EINVAL; | 975 | int ret = -EINVAL; |
942 | 976 | ||
943 | if (session == NULL) | 977 | if (session == NULL) |
@@ -968,7 +1002,8 @@ static const char * const timechart_usage[] = { | |||
968 | NULL | 1002 | NULL |
969 | }; | 1003 | }; |
970 | 1004 | ||
971 | static const char *record_args[] = { | 1005 | #ifdef SUPPORT_OLD_POWER_EVENTS |
1006 | static const char * const record_old_args[] = { | ||
972 | "record", | 1007 | "record", |
973 | "-a", | 1008 | "-a", |
974 | "-R", | 1009 | "-R", |
@@ -980,16 +1015,43 @@ static const char *record_args[] = { | |||
980 | "-e", "sched:sched_wakeup", | 1015 | "-e", "sched:sched_wakeup", |
981 | "-e", "sched:sched_switch", | 1016 | "-e", "sched:sched_switch", |
982 | }; | 1017 | }; |
1018 | #endif | ||
1019 | |||
1020 | static const char * const record_new_args[] = { | ||
1021 | "record", | ||
1022 | "-a", | ||
1023 | "-R", | ||
1024 | "-f", | ||
1025 | "-c", "1", | ||
1026 | "-e", "power:cpu_frequency", | ||
1027 | "-e", "power:cpu_idle", | ||
1028 | "-e", "sched:sched_wakeup", | ||
1029 | "-e", "sched:sched_switch", | ||
1030 | }; | ||
983 | 1031 | ||
984 | static int __cmd_record(int argc, const char **argv) | 1032 | static int __cmd_record(int argc, const char **argv) |
985 | { | 1033 | { |
986 | unsigned int rec_argc, i, j; | 1034 | unsigned int rec_argc, i, j; |
987 | const char **rec_argv; | 1035 | const char **rec_argv; |
1036 | const char * const *record_args = record_new_args; | ||
1037 | unsigned int record_elems = ARRAY_SIZE(record_new_args); | ||
1038 | |||
1039 | #ifdef SUPPORT_OLD_POWER_EVENTS | ||
1040 | if (!is_valid_tracepoint("power:cpu_idle") && | ||
1041 | is_valid_tracepoint("power:power_start")) { | ||
1042 | use_old_power_events = 1; | ||
1043 | record_args = record_old_args; | ||
1044 | record_elems = ARRAY_SIZE(record_old_args); | ||
1045 | } | ||
1046 | #endif | ||
988 | 1047 | ||
989 | rec_argc = ARRAY_SIZE(record_args) + argc - 1; | 1048 | rec_argc = record_elems + argc - 1; |
990 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 1049 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
991 | 1050 | ||
992 | for (i = 0; i < ARRAY_SIZE(record_args); i++) | 1051 | if (rec_argv == NULL) |
1052 | return -ENOMEM; | ||
1053 | |||
1054 | for (i = 0; i < record_elems; i++) | ||
993 | rec_argv[i] = strdup(record_args[i]); | 1055 | rec_argv[i] = strdup(record_args[i]); |
994 | 1056 | ||
995 | for (j = 1; j < (unsigned int)argc; j++, i++) | 1057 | for (j = 1; j < (unsigned int)argc; j++, i++) |
@@ -1018,6 +1080,8 @@ static const struct option options[] = { | |||
1018 | OPT_CALLBACK('p', "process", NULL, "process", | 1080 | OPT_CALLBACK('p', "process", NULL, "process", |
1019 | "process selector. Pass a pid or process name.", | 1081 | "process selector. Pass a pid or process name.", |
1020 | parse_process), | 1082 | parse_process), |
1083 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | ||
1084 | "Look for files with symbols relative to this directory"), | ||
1021 | OPT_END() | 1085 | OPT_END() |
1022 | }; | 1086 | }; |
1023 | 1087 | ||