diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2013-11-28 09:25:19 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2013-12-02 07:22:46 -0500 |
commit | 985b12e633246750b5424f0a28d5f8cea04de07a (patch) | |
tree | d47d0c59ad500e9c2348c1f3bf581dea718f783b | |
parent | 6f9a317f2a2d4950880ecfa7eea53ed79f85255f (diff) |
perf timechart: Introduce tool struct
To avoid having all those global variables and to use the interface to
event processing that is based on passing a 'perf_tool' struct that
should be embedded in a per tool specific struct passed to all the
sample processing callbacks.
There are some more globals to move, next patches will do it.
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislav Fomichev <stfomichev@yandex-team.ru>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-0iah65pq796ezbk5u1lzwy1k@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/builtin-timechart.c | 216 |
1 files changed, 114 insertions, 102 deletions
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 680632d7e26a..e2d62f1a96e4 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -41,19 +41,18 @@ | |||
41 | #define SUPPORT_OLD_POWER_EVENTS 1 | 41 | #define SUPPORT_OLD_POWER_EVENTS 1 |
42 | #define PWR_EVENT_EXIT -1 | 42 | #define PWR_EVENT_EXIT -1 |
43 | 43 | ||
44 | static int proc_num = 15; | 44 | struct timechart { |
45 | 45 | struct perf_tool tool; | |
46 | static unsigned int numcpus; | 46 | int proc_num; |
47 | static u64 min_freq; /* Lowest CPU frequency seen */ | 47 | unsigned int numcpus; |
48 | static u64 max_freq; /* Highest CPU frequency seen */ | 48 | u64 min_freq, /* Lowest CPU frequency seen */ |
49 | static u64 turbo_frequency; | 49 | max_freq, /* Highest CPU frequency seen */ |
50 | 50 | turbo_frequency, | |
51 | static u64 first_time, last_time; | 51 | first_time, last_time; |
52 | 52 | bool power_only, | |
53 | static bool power_only; | 53 | tasks_only, |
54 | static bool tasks_only; | 54 | with_backtrace; |
55 | static bool with_backtrace; | 55 | }; |
56 | |||
57 | 56 | ||
58 | struct per_pidcomm; | 57 | struct per_pidcomm; |
59 | struct cpu_sample; | 58 | struct cpu_sample; |
@@ -326,7 +325,7 @@ static void c_state_end(int cpu, u64 timestamp) | |||
326 | power_events = pwr; | 325 | power_events = pwr; |
327 | } | 326 | } |
328 | 327 | ||
329 | static void p_state_change(int cpu, u64 timestamp, u64 new_freq) | 328 | static void p_state_change(struct timechart *tchart, int cpu, u64 timestamp, u64 new_freq) |
330 | { | 329 | { |
331 | struct power_event *pwr; | 330 | struct power_event *pwr; |
332 | 331 | ||
@@ -345,21 +344,21 @@ static void p_state_change(int cpu, u64 timestamp, u64 new_freq) | |||
345 | pwr->next = power_events; | 344 | pwr->next = power_events; |
346 | 345 | ||
347 | if (!pwr->start_time) | 346 | if (!pwr->start_time) |
348 | pwr->start_time = first_time; | 347 | pwr->start_time = tchart->first_time; |
349 | 348 | ||
350 | power_events = pwr; | 349 | power_events = pwr; |
351 | 350 | ||
352 | cpus_pstate_state[cpu] = new_freq; | 351 | cpus_pstate_state[cpu] = new_freq; |
353 | cpus_pstate_start_times[cpu] = timestamp; | 352 | cpus_pstate_start_times[cpu] = timestamp; |
354 | 353 | ||
355 | if ((u64)new_freq > max_freq) | 354 | if ((u64)new_freq > tchart->max_freq) |
356 | max_freq = new_freq; | 355 | tchart->max_freq = new_freq; |
357 | 356 | ||
358 | if (new_freq < min_freq || min_freq == 0) | 357 | if (new_freq < tchart->min_freq || tchart->min_freq == 0) |
359 | min_freq = new_freq; | 358 | tchart->min_freq = new_freq; |
360 | 359 | ||
361 | if (new_freq == max_freq - 1000) | 360 | if (new_freq == tchart->max_freq - 1000) |
362 | turbo_frequency = max_freq; | 361 | tchart->turbo_frequency = tchart->max_freq; |
363 | } | 362 | } |
364 | 363 | ||
365 | static void sched_wakeup(int cpu, u64 timestamp, int waker, int wakee, | 364 | static void sched_wakeup(int cpu, u64 timestamp, int waker, int wakee, |
@@ -506,36 +505,40 @@ exit: | |||
506 | return p; | 505 | return p; |
507 | } | 506 | } |
508 | 507 | ||
509 | typedef int (*tracepoint_handler)(struct perf_evsel *evsel, | 508 | typedef int (*tracepoint_handler)(struct timechart *tchart, |
509 | struct perf_evsel *evsel, | ||
510 | struct perf_sample *sample, | 510 | struct perf_sample *sample, |
511 | const char *backtrace); | 511 | const char *backtrace); |
512 | 512 | ||
513 | static int process_sample_event(struct perf_tool *tool __maybe_unused, | 513 | static int process_sample_event(struct perf_tool *tool, |
514 | union perf_event *event, | 514 | union perf_event *event, |
515 | struct perf_sample *sample, | 515 | struct perf_sample *sample, |
516 | struct perf_evsel *evsel, | 516 | struct perf_evsel *evsel, |
517 | struct machine *machine __maybe_unused) | 517 | struct machine *machine) |
518 | { | 518 | { |
519 | struct timechart *tchart = container_of(tool, struct timechart, tool); | ||
520 | |||
519 | if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { | 521 | if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { |
520 | if (!first_time || first_time > sample->time) | 522 | if (!tchart->first_time || tchart->first_time > sample->time) |
521 | first_time = sample->time; | 523 | tchart->first_time = sample->time; |
522 | if (last_time < sample->time) | 524 | if (tchart->last_time < sample->time) |
523 | last_time = sample->time; | 525 | tchart->last_time = sample->time; |
524 | } | 526 | } |
525 | 527 | ||
526 | if (sample->cpu > numcpus) | 528 | if (sample->cpu > tchart->numcpus) |
527 | numcpus = sample->cpu; | 529 | tchart->numcpus = sample->cpu; |
528 | 530 | ||
529 | if (evsel->handler != NULL) { | 531 | if (evsel->handler != NULL) { |
530 | tracepoint_handler f = evsel->handler; | 532 | tracepoint_handler f = evsel->handler; |
531 | return f(evsel, sample, cat_backtrace(event, sample, machine)); | 533 | return f(tchart, evsel, sample, cat_backtrace(event, sample, machine)); |
532 | } | 534 | } |
533 | 535 | ||
534 | return 0; | 536 | return 0; |
535 | } | 537 | } |
536 | 538 | ||
537 | static int | 539 | static int |
538 | process_sample_cpu_idle(struct perf_evsel *evsel, | 540 | process_sample_cpu_idle(struct timechart *tchart __maybe_unused, |
541 | struct perf_evsel *evsel, | ||
539 | struct perf_sample *sample, | 542 | struct perf_sample *sample, |
540 | const char *backtrace __maybe_unused) | 543 | const char *backtrace __maybe_unused) |
541 | { | 544 | { |
@@ -550,19 +553,21 @@ process_sample_cpu_idle(struct perf_evsel *evsel, | |||
550 | } | 553 | } |
551 | 554 | ||
552 | static int | 555 | static int |
553 | process_sample_cpu_frequency(struct perf_evsel *evsel, | 556 | process_sample_cpu_frequency(struct timechart *tchart, |
557 | struct perf_evsel *evsel, | ||
554 | struct perf_sample *sample, | 558 | struct perf_sample *sample, |
555 | const char *backtrace __maybe_unused) | 559 | const char *backtrace __maybe_unused) |
556 | { | 560 | { |
557 | u32 state = perf_evsel__intval(evsel, sample, "state"); | 561 | u32 state = perf_evsel__intval(evsel, sample, "state"); |
558 | u32 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id"); | 562 | u32 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id"); |
559 | 563 | ||
560 | p_state_change(cpu_id, sample->time, state); | 564 | p_state_change(tchart, cpu_id, sample->time, state); |
561 | return 0; | 565 | return 0; |
562 | } | 566 | } |
563 | 567 | ||
564 | static int | 568 | static int |
565 | process_sample_sched_wakeup(struct perf_evsel *evsel, | 569 | process_sample_sched_wakeup(struct timechart *tchart __maybe_unused, |
570 | struct perf_evsel *evsel, | ||
566 | struct perf_sample *sample, | 571 | struct perf_sample *sample, |
567 | const char *backtrace) | 572 | const char *backtrace) |
568 | { | 573 | { |
@@ -575,7 +580,8 @@ process_sample_sched_wakeup(struct perf_evsel *evsel, | |||
575 | } | 580 | } |
576 | 581 | ||
577 | static int | 582 | static int |
578 | process_sample_sched_switch(struct perf_evsel *evsel, | 583 | process_sample_sched_switch(struct timechart *tchart __maybe_unused, |
584 | struct perf_evsel *evsel, | ||
579 | struct perf_sample *sample, | 585 | struct perf_sample *sample, |
580 | const char *backtrace) | 586 | const char *backtrace) |
581 | { | 587 | { |
@@ -590,7 +596,8 @@ process_sample_sched_switch(struct perf_evsel *evsel, | |||
590 | 596 | ||
591 | #ifdef SUPPORT_OLD_POWER_EVENTS | 597 | #ifdef SUPPORT_OLD_POWER_EVENTS |
592 | static int | 598 | static int |
593 | process_sample_power_start(struct perf_evsel *evsel, | 599 | process_sample_power_start(struct timechart *tchart __maybe_unused, |
600 | struct perf_evsel *evsel, | ||
594 | struct perf_sample *sample, | 601 | struct perf_sample *sample, |
595 | const char *backtrace __maybe_unused) | 602 | const char *backtrace __maybe_unused) |
596 | { | 603 | { |
@@ -602,7 +609,8 @@ process_sample_power_start(struct perf_evsel *evsel, | |||
602 | } | 609 | } |
603 | 610 | ||
604 | static int | 611 | static int |
605 | process_sample_power_end(struct perf_evsel *evsel __maybe_unused, | 612 | process_sample_power_end(struct timechart *tchart __maybe_unused, |
613 | struct perf_evsel *evsel __maybe_unused, | ||
606 | struct perf_sample *sample, | 614 | struct perf_sample *sample, |
607 | const char *backtrace __maybe_unused) | 615 | const char *backtrace __maybe_unused) |
608 | { | 616 | { |
@@ -611,14 +619,15 @@ process_sample_power_end(struct perf_evsel *evsel __maybe_unused, | |||
611 | } | 619 | } |
612 | 620 | ||
613 | static int | 621 | static int |
614 | process_sample_power_frequency(struct perf_evsel *evsel, | 622 | process_sample_power_frequency(struct timechart *tchart, |
623 | struct perf_evsel *evsel, | ||
615 | struct perf_sample *sample, | 624 | struct perf_sample *sample, |
616 | const char *backtrace __maybe_unused) | 625 | const char *backtrace __maybe_unused) |
617 | { | 626 | { |
618 | u64 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id"); | 627 | u64 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id"); |
619 | u64 value = perf_evsel__intval(evsel, sample, "value"); | 628 | u64 value = perf_evsel__intval(evsel, sample, "value"); |
620 | 629 | ||
621 | p_state_change(cpu_id, sample->time, value); | 630 | p_state_change(tchart, cpu_id, sample->time, value); |
622 | return 0; | 631 | return 0; |
623 | } | 632 | } |
624 | #endif /* SUPPORT_OLD_POWER_EVENTS */ | 633 | #endif /* SUPPORT_OLD_POWER_EVENTS */ |
@@ -627,12 +636,12 @@ process_sample_power_frequency(struct perf_evsel *evsel, | |||
627 | * After the last sample we need to wrap up the current C/P state | 636 | * After the last sample we need to wrap up the current C/P state |
628 | * and close out each CPU for these. | 637 | * and close out each CPU for these. |
629 | */ | 638 | */ |
630 | static void end_sample_processing(void) | 639 | static void end_sample_processing(struct timechart *tchart) |
631 | { | 640 | { |
632 | u64 cpu; | 641 | u64 cpu; |
633 | struct power_event *pwr; | 642 | struct power_event *pwr; |
634 | 643 | ||
635 | for (cpu = 0; cpu <= numcpus; cpu++) { | 644 | for (cpu = 0; cpu <= tchart->numcpus; cpu++) { |
636 | /* C state */ | 645 | /* C state */ |
637 | #if 0 | 646 | #if 0 |
638 | pwr = zalloc(sizeof(*pwr)); | 647 | pwr = zalloc(sizeof(*pwr)); |
@@ -641,7 +650,7 @@ static void end_sample_processing(void) | |||
641 | 650 | ||
642 | pwr->state = cpus_cstate_state[cpu]; | 651 | pwr->state = cpus_cstate_state[cpu]; |
643 | pwr->start_time = cpus_cstate_start_times[cpu]; | 652 | pwr->start_time = cpus_cstate_start_times[cpu]; |
644 | pwr->end_time = last_time; | 653 | pwr->end_time = tchart->last_time; |
645 | pwr->cpu = cpu; | 654 | pwr->cpu = cpu; |
646 | pwr->type = CSTATE; | 655 | pwr->type = CSTATE; |
647 | pwr->next = power_events; | 656 | pwr->next = power_events; |
@@ -656,15 +665,15 @@ static void end_sample_processing(void) | |||
656 | 665 | ||
657 | pwr->state = cpus_pstate_state[cpu]; | 666 | pwr->state = cpus_pstate_state[cpu]; |
658 | pwr->start_time = cpus_pstate_start_times[cpu]; | 667 | pwr->start_time = cpus_pstate_start_times[cpu]; |
659 | pwr->end_time = last_time; | 668 | pwr->end_time = tchart->last_time; |
660 | pwr->cpu = cpu; | 669 | pwr->cpu = cpu; |
661 | pwr->type = PSTATE; | 670 | pwr->type = PSTATE; |
662 | pwr->next = power_events; | 671 | pwr->next = power_events; |
663 | 672 | ||
664 | if (!pwr->start_time) | 673 | if (!pwr->start_time) |
665 | pwr->start_time = first_time; | 674 | pwr->start_time = tchart->first_time; |
666 | if (!pwr->state) | 675 | if (!pwr->state) |
667 | pwr->state = min_freq; | 676 | pwr->state = tchart->min_freq; |
668 | power_events = pwr; | 677 | power_events = pwr; |
669 | } | 678 | } |
670 | } | 679 | } |
@@ -718,7 +727,7 @@ static void sort_pids(void) | |||
718 | } | 727 | } |
719 | 728 | ||
720 | 729 | ||
721 | static void draw_c_p_states(void) | 730 | static void draw_c_p_states(struct timechart *tchart) |
722 | { | 731 | { |
723 | struct power_event *pwr; | 732 | struct power_event *pwr; |
724 | pwr = power_events; | 733 | pwr = power_events; |
@@ -736,7 +745,7 @@ static void draw_c_p_states(void) | |||
736 | while (pwr) { | 745 | while (pwr) { |
737 | if (pwr->type == PSTATE) { | 746 | if (pwr->type == PSTATE) { |
738 | if (!pwr->state) | 747 | if (!pwr->state) |
739 | pwr->state = min_freq; | 748 | pwr->state = tchart->min_freq; |
740 | svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state); | 749 | svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state); |
741 | } | 750 | } |
742 | pwr = pwr->next; | 751 | pwr = pwr->next; |
@@ -833,14 +842,14 @@ static void draw_cpu_usage(void) | |||
833 | } | 842 | } |
834 | } | 843 | } |
835 | 844 | ||
836 | static void draw_process_bars(void) | 845 | static void draw_process_bars(struct timechart *tchart) |
837 | { | 846 | { |
838 | struct per_pid *p; | 847 | struct per_pid *p; |
839 | struct per_pidcomm *c; | 848 | struct per_pidcomm *c; |
840 | struct cpu_sample *sample; | 849 | struct cpu_sample *sample; |
841 | int Y = 0; | 850 | int Y = 0; |
842 | 851 | ||
843 | Y = 2 * numcpus + 2; | 852 | Y = 2 * tchart->numcpus + 2; |
844 | 853 | ||
845 | p = all_data; | 854 | p = all_data; |
846 | while (p) { | 855 | while (p) { |
@@ -922,7 +931,7 @@ static int passes_filter(struct per_pid *p, struct per_pidcomm *c) | |||
922 | return 0; | 931 | return 0; |
923 | } | 932 | } |
924 | 933 | ||
925 | static int determine_display_tasks_filtered(void) | 934 | static int determine_display_tasks_filtered(struct timechart *tchart) |
926 | { | 935 | { |
927 | struct per_pid *p; | 936 | struct per_pid *p; |
928 | struct per_pidcomm *c; | 937 | struct per_pidcomm *c; |
@@ -932,11 +941,11 @@ static int determine_display_tasks_filtered(void) | |||
932 | while (p) { | 941 | while (p) { |
933 | p->display = 0; | 942 | p->display = 0; |
934 | if (p->start_time == 1) | 943 | if (p->start_time == 1) |
935 | p->start_time = first_time; | 944 | p->start_time = tchart->first_time; |
936 | 945 | ||
937 | /* no exit marker, task kept running to the end */ | 946 | /* no exit marker, task kept running to the end */ |
938 | if (p->end_time == 0) | 947 | if (p->end_time == 0) |
939 | p->end_time = last_time; | 948 | p->end_time = tchart->last_time; |
940 | 949 | ||
941 | c = p->all; | 950 | c = p->all; |
942 | 951 | ||
@@ -944,7 +953,7 @@ static int determine_display_tasks_filtered(void) | |||
944 | c->display = 0; | 953 | c->display = 0; |
945 | 954 | ||
946 | if (c->start_time == 1) | 955 | if (c->start_time == 1) |
947 | c->start_time = first_time; | 956 | c->start_time = tchart->first_time; |
948 | 957 | ||
949 | if (passes_filter(p, c)) { | 958 | if (passes_filter(p, c)) { |
950 | c->display = 1; | 959 | c->display = 1; |
@@ -953,7 +962,7 @@ static int determine_display_tasks_filtered(void) | |||
953 | } | 962 | } |
954 | 963 | ||
955 | if (c->end_time == 0) | 964 | if (c->end_time == 0) |
956 | c->end_time = last_time; | 965 | c->end_time = tchart->last_time; |
957 | 966 | ||
958 | c = c->next; | 967 | c = c->next; |
959 | } | 968 | } |
@@ -962,24 +971,24 @@ static int determine_display_tasks_filtered(void) | |||
962 | return count; | 971 | return count; |
963 | } | 972 | } |
964 | 973 | ||
965 | static int determine_display_tasks(u64 threshold) | 974 | static int determine_display_tasks(struct timechart *tchart, u64 threshold) |
966 | { | 975 | { |
967 | struct per_pid *p; | 976 | struct per_pid *p; |
968 | struct per_pidcomm *c; | 977 | struct per_pidcomm *c; |
969 | int count = 0; | 978 | int count = 0; |
970 | 979 | ||
971 | if (process_filter) | 980 | if (process_filter) |
972 | return determine_display_tasks_filtered(); | 981 | return determine_display_tasks_filtered(tchart); |
973 | 982 | ||
974 | p = all_data; | 983 | p = all_data; |
975 | while (p) { | 984 | while (p) { |
976 | p->display = 0; | 985 | p->display = 0; |
977 | if (p->start_time == 1) | 986 | if (p->start_time == 1) |
978 | p->start_time = first_time; | 987 | p->start_time = tchart->first_time; |
979 | 988 | ||
980 | /* no exit marker, task kept running to the end */ | 989 | /* no exit marker, task kept running to the end */ |
981 | if (p->end_time == 0) | 990 | if (p->end_time == 0) |
982 | p->end_time = last_time; | 991 | p->end_time = tchart->last_time; |
983 | if (p->total_time >= threshold) | 992 | if (p->total_time >= threshold) |
984 | p->display = 1; | 993 | p->display = 1; |
985 | 994 | ||
@@ -989,7 +998,7 @@ static int determine_display_tasks(u64 threshold) | |||
989 | c->display = 0; | 998 | c->display = 0; |
990 | 999 | ||
991 | if (c->start_time == 1) | 1000 | if (c->start_time == 1) |
992 | c->start_time = first_time; | 1001 | c->start_time = tchart->first_time; |
993 | 1002 | ||
994 | if (c->total_time >= threshold) { | 1003 | if (c->total_time >= threshold) { |
995 | c->display = 1; | 1004 | c->display = 1; |
@@ -997,7 +1006,7 @@ static int determine_display_tasks(u64 threshold) | |||
997 | } | 1006 | } |
998 | 1007 | ||
999 | if (c->end_time == 0) | 1008 | if (c->end_time == 0) |
1000 | c->end_time = last_time; | 1009 | c->end_time = tchart->last_time; |
1001 | 1010 | ||
1002 | c = c->next; | 1011 | c = c->next; |
1003 | } | 1012 | } |
@@ -1010,52 +1019,45 @@ static int determine_display_tasks(u64 threshold) | |||
1010 | 1019 | ||
1011 | #define TIME_THRESH 10000000 | 1020 | #define TIME_THRESH 10000000 |
1012 | 1021 | ||
1013 | static void write_svg_file(const char *filename) | 1022 | static void write_svg_file(struct timechart *tchart, const char *filename) |
1014 | { | 1023 | { |
1015 | u64 i; | 1024 | u64 i; |
1016 | int count; | 1025 | int count; |
1017 | int thresh = TIME_THRESH; | 1026 | int thresh = TIME_THRESH; |
1018 | 1027 | ||
1019 | numcpus++; | 1028 | tchart->numcpus++; |
1020 | 1029 | ||
1021 | if (power_only) | 1030 | if (tchart->power_only) |
1022 | proc_num = 0; | 1031 | tchart->proc_num = 0; |
1023 | 1032 | ||
1024 | /* We'd like to show at least proc_num tasks; | 1033 | /* We'd like to show at least proc_num tasks; |
1025 | * be less picky if we have fewer */ | 1034 | * be less picky if we have fewer */ |
1026 | do { | 1035 | do { |
1027 | count = determine_display_tasks(thresh); | 1036 | count = determine_display_tasks(tchart, thresh); |
1028 | thresh /= 10; | 1037 | thresh /= 10; |
1029 | } while (!process_filter && thresh && count < proc_num); | 1038 | } while (!process_filter && thresh && count < tchart->proc_num); |
1030 | 1039 | ||
1031 | open_svg(filename, numcpus, count, first_time, last_time); | 1040 | open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time); |
1032 | 1041 | ||
1033 | svg_time_grid(); | 1042 | svg_time_grid(); |
1034 | svg_legenda(); | 1043 | svg_legenda(); |
1035 | 1044 | ||
1036 | for (i = 0; i < numcpus; i++) | 1045 | for (i = 0; i < tchart->numcpus; i++) |
1037 | svg_cpu_box(i, max_freq, turbo_frequency); | 1046 | svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency); |
1038 | 1047 | ||
1039 | draw_cpu_usage(); | 1048 | draw_cpu_usage(); |
1040 | if (proc_num) | 1049 | if (tchart->proc_num) |
1041 | draw_process_bars(); | 1050 | draw_process_bars(tchart); |
1042 | if (!tasks_only) | 1051 | if (!tchart->tasks_only) |
1043 | draw_c_p_states(); | 1052 | draw_c_p_states(tchart); |
1044 | if (proc_num) | 1053 | if (tchart->proc_num) |
1045 | draw_wakeups(); | 1054 | draw_wakeups(); |
1046 | 1055 | ||
1047 | svg_close(); | 1056 | svg_close(); |
1048 | } | 1057 | } |
1049 | 1058 | ||
1050 | static int __cmd_timechart(const char *output_name) | 1059 | static int __cmd_timechart(struct timechart *tchart, const char *output_name) |
1051 | { | 1060 | { |
1052 | struct perf_tool perf_timechart = { | ||
1053 | .comm = process_comm_event, | ||
1054 | .fork = process_fork_event, | ||
1055 | .exit = process_exit_event, | ||
1056 | .sample = process_sample_event, | ||
1057 | .ordered_samples = true, | ||
1058 | }; | ||
1059 | const struct perf_evsel_str_handler power_tracepoints[] = { | 1061 | const struct perf_evsel_str_handler power_tracepoints[] = { |
1060 | { "power:cpu_idle", process_sample_cpu_idle }, | 1062 | { "power:cpu_idle", process_sample_cpu_idle }, |
1061 | { "power:cpu_frequency", process_sample_cpu_frequency }, | 1063 | { "power:cpu_frequency", process_sample_cpu_frequency }, |
@@ -1073,7 +1075,7 @@ static int __cmd_timechart(const char *output_name) | |||
1073 | }; | 1075 | }; |
1074 | 1076 | ||
1075 | struct perf_session *session = perf_session__new(&file, false, | 1077 | struct perf_session *session = perf_session__new(&file, false, |
1076 | &perf_timechart); | 1078 | &tchart->tool); |
1077 | int ret = -EINVAL; | 1079 | int ret = -EINVAL; |
1078 | 1080 | ||
1079 | if (session == NULL) | 1081 | if (session == NULL) |
@@ -1088,24 +1090,24 @@ static int __cmd_timechart(const char *output_name) | |||
1088 | goto out_delete; | 1090 | goto out_delete; |
1089 | } | 1091 | } |
1090 | 1092 | ||
1091 | ret = perf_session__process_events(session, &perf_timechart); | 1093 | ret = perf_session__process_events(session, &tchart->tool); |
1092 | if (ret) | 1094 | if (ret) |
1093 | goto out_delete; | 1095 | goto out_delete; |
1094 | 1096 | ||
1095 | end_sample_processing(); | 1097 | end_sample_processing(tchart); |
1096 | 1098 | ||
1097 | sort_pids(); | 1099 | sort_pids(); |
1098 | 1100 | ||
1099 | write_svg_file(output_name); | 1101 | write_svg_file(tchart, output_name); |
1100 | 1102 | ||
1101 | pr_info("Written %2.1f seconds of trace to %s.\n", | 1103 | pr_info("Written %2.1f seconds of trace to %s.\n", |
1102 | (last_time - first_time) / 1000000000.0, output_name); | 1104 | (tchart->last_time - tchart->first_time) / 1000000000.0, output_name); |
1103 | out_delete: | 1105 | out_delete: |
1104 | perf_session__delete(session); | 1106 | perf_session__delete(session); |
1105 | return ret; | 1107 | return ret; |
1106 | } | 1108 | } |
1107 | 1109 | ||
1108 | static int __cmd_record(int argc, const char **argv) | 1110 | static int timechart__record(struct timechart *tchart, int argc, const char **argv) |
1109 | { | 1111 | { |
1110 | unsigned int rec_argc, i, j; | 1112 | unsigned int rec_argc, i, j; |
1111 | const char **rec_argv; | 1113 | const char **rec_argv; |
@@ -1153,15 +1155,15 @@ static int __cmd_record(int argc, const char **argv) | |||
1153 | } | 1155 | } |
1154 | #endif | 1156 | #endif |
1155 | 1157 | ||
1156 | if (power_only) | 1158 | if (tchart->power_only) |
1157 | tasks_args_nr = 0; | 1159 | tasks_args_nr = 0; |
1158 | 1160 | ||
1159 | if (tasks_only) { | 1161 | if (tchart->tasks_only) { |
1160 | power_args_nr = 0; | 1162 | power_args_nr = 0; |
1161 | old_power_args_nr = 0; | 1163 | old_power_args_nr = 0; |
1162 | } | 1164 | } |
1163 | 1165 | ||
1164 | if (!with_backtrace) | 1166 | if (!tchart->with_backtrace) |
1165 | backtrace_args_no = 0; | 1167 | backtrace_args_no = 0; |
1166 | 1168 | ||
1167 | record_elems = common_args_nr + tasks_args_nr + | 1169 | record_elems = common_args_nr + tasks_args_nr + |
@@ -1207,20 +1209,30 @@ parse_process(const struct option *opt __maybe_unused, const char *arg, | |||
1207 | int cmd_timechart(int argc, const char **argv, | 1209 | int cmd_timechart(int argc, const char **argv, |
1208 | const char *prefix __maybe_unused) | 1210 | const char *prefix __maybe_unused) |
1209 | { | 1211 | { |
1212 | struct timechart tchart = { | ||
1213 | .tool = { | ||
1214 | .comm = process_comm_event, | ||
1215 | .fork = process_fork_event, | ||
1216 | .exit = process_exit_event, | ||
1217 | .sample = process_sample_event, | ||
1218 | .ordered_samples = true, | ||
1219 | }, | ||
1220 | .proc_num = 15, | ||
1221 | }; | ||
1210 | const char *output_name = "output.svg"; | 1222 | const char *output_name = "output.svg"; |
1211 | const struct option timechart_options[] = { | 1223 | const struct option timechart_options[] = { |
1212 | OPT_STRING('i', "input", &input_name, "file", "input file name"), | 1224 | OPT_STRING('i', "input", &input_name, "file", "input file name"), |
1213 | OPT_STRING('o', "output", &output_name, "file", "output file name"), | 1225 | OPT_STRING('o', "output", &output_name, "file", "output file name"), |
1214 | OPT_INTEGER('w', "width", &svg_page_width, "page width"), | 1226 | OPT_INTEGER('w', "width", &svg_page_width, "page width"), |
1215 | OPT_BOOLEAN('P', "power-only", &power_only, "output power data only"), | 1227 | OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"), |
1216 | OPT_BOOLEAN('T', "tasks-only", &tasks_only, | 1228 | OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, |
1217 | "output processes data only"), | 1229 | "output processes data only"), |
1218 | OPT_CALLBACK('p', "process", NULL, "process", | 1230 | OPT_CALLBACK('p', "process", NULL, "process", |
1219 | "process selector. Pass a pid or process name.", | 1231 | "process selector. Pass a pid or process name.", |
1220 | parse_process), | 1232 | parse_process), |
1221 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | 1233 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", |
1222 | "Look for files with symbols relative to this directory"), | 1234 | "Look for files with symbols relative to this directory"), |
1223 | OPT_INTEGER('n', "proc-num", &proc_num, | 1235 | OPT_INTEGER('n', "proc-num", &tchart.proc_num, |
1224 | "min. number of tasks to print"), | 1236 | "min. number of tasks to print"), |
1225 | OPT_END() | 1237 | OPT_END() |
1226 | }; | 1238 | }; |
@@ -1230,10 +1242,10 @@ int cmd_timechart(int argc, const char **argv, | |||
1230 | }; | 1242 | }; |
1231 | 1243 | ||
1232 | const struct option record_options[] = { | 1244 | const struct option record_options[] = { |
1233 | OPT_BOOLEAN('P', "power-only", &power_only, "output power data only"), | 1245 | OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"), |
1234 | OPT_BOOLEAN('T', "tasks-only", &tasks_only, | 1246 | OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, |
1235 | "output processes data only"), | 1247 | "output processes data only"), |
1236 | OPT_BOOLEAN('g', "callchain", &with_backtrace, "record callchain"), | 1248 | OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"), |
1237 | OPT_END() | 1249 | OPT_END() |
1238 | }; | 1250 | }; |
1239 | const char * const record_usage[] = { | 1251 | const char * const record_usage[] = { |
@@ -1243,7 +1255,7 @@ int cmd_timechart(int argc, const char **argv, | |||
1243 | argc = parse_options(argc, argv, timechart_options, timechart_usage, | 1255 | argc = parse_options(argc, argv, timechart_options, timechart_usage, |
1244 | PARSE_OPT_STOP_AT_NON_OPTION); | 1256 | PARSE_OPT_STOP_AT_NON_OPTION); |
1245 | 1257 | ||
1246 | if (power_only && tasks_only) { | 1258 | if (tchart.power_only && tchart.tasks_only) { |
1247 | pr_err("-P and -T options cannot be used at the same time.\n"); | 1259 | pr_err("-P and -T options cannot be used at the same time.\n"); |
1248 | return -1; | 1260 | return -1; |
1249 | } | 1261 | } |
@@ -1254,16 +1266,16 @@ int cmd_timechart(int argc, const char **argv, | |||
1254 | argc = parse_options(argc, argv, record_options, record_usage, | 1266 | argc = parse_options(argc, argv, record_options, record_usage, |
1255 | PARSE_OPT_STOP_AT_NON_OPTION); | 1267 | PARSE_OPT_STOP_AT_NON_OPTION); |
1256 | 1268 | ||
1257 | if (power_only && tasks_only) { | 1269 | if (tchart.power_only && tchart.tasks_only) { |
1258 | pr_err("-P and -T options cannot be used at the same time.\n"); | 1270 | pr_err("-P and -T options cannot be used at the same time.\n"); |
1259 | return -1; | 1271 | return -1; |
1260 | } | 1272 | } |
1261 | 1273 | ||
1262 | return __cmd_record(argc, argv); | 1274 | return timechart__record(&tchart, argc, argv); |
1263 | } else if (argc) | 1275 | } else if (argc) |
1264 | usage_with_options(timechart_usage, timechart_options); | 1276 | usage_with_options(timechart_usage, timechart_options); |
1265 | 1277 | ||
1266 | setup_pager(); | 1278 | setup_pager(); |
1267 | 1279 | ||
1268 | return __cmd_timechart(output_name); | 1280 | return __cmd_timechart(&tchart, output_name); |
1269 | } | 1281 | } |