aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2013-11-28 09:25:19 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2013-12-02 07:22:46 -0500
commit985b12e633246750b5424f0a28d5f8cea04de07a (patch)
treed47d0c59ad500e9c2348c1f3bf581dea718f783b
parent6f9a317f2a2d4950880ecfa7eea53ed79f85255f (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.c216
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
44static int proc_num = 15; 44struct timechart {
45 45 struct perf_tool tool;
46static unsigned int numcpus; 46 int proc_num;
47static u64 min_freq; /* Lowest CPU frequency seen */ 47 unsigned int numcpus;
48static u64 max_freq; /* Highest CPU frequency seen */ 48 u64 min_freq, /* Lowest CPU frequency seen */
49static u64 turbo_frequency; 49 max_freq, /* Highest CPU frequency seen */
50 50 turbo_frequency,
51static u64 first_time, last_time; 51 first_time, last_time;
52 52 bool power_only,
53static bool power_only; 53 tasks_only,
54static bool tasks_only; 54 with_backtrace;
55static bool with_backtrace; 55};
56
57 56
58struct per_pidcomm; 57struct per_pidcomm;
59struct cpu_sample; 58struct 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
329static void p_state_change(int cpu, u64 timestamp, u64 new_freq) 328static 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
365static void sched_wakeup(int cpu, u64 timestamp, int waker, int wakee, 364static 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
509typedef int (*tracepoint_handler)(struct perf_evsel *evsel, 508typedef 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
513static int process_sample_event(struct perf_tool *tool __maybe_unused, 513static 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
537static int 539static int
538process_sample_cpu_idle(struct perf_evsel *evsel, 540process_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
552static int 555static int
553process_sample_cpu_frequency(struct perf_evsel *evsel, 556process_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
564static int 568static int
565process_sample_sched_wakeup(struct perf_evsel *evsel, 569process_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
577static int 582static int
578process_sample_sched_switch(struct perf_evsel *evsel, 583process_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
592static int 598static int
593process_sample_power_start(struct perf_evsel *evsel, 599process_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
604static int 611static int
605process_sample_power_end(struct perf_evsel *evsel __maybe_unused, 612process_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
613static int 621static int
614process_sample_power_frequency(struct perf_evsel *evsel, 622process_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 */
630static void end_sample_processing(void) 639static 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
721static void draw_c_p_states(void) 730static 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
836static void draw_process_bars(void) 845static 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
925static int determine_display_tasks_filtered(void) 934static 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
965static int determine_display_tasks(u64 threshold) 974static 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
1013static void write_svg_file(const char *filename) 1022static 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
1050static int __cmd_timechart(const char *output_name) 1059static 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);
1103out_delete: 1105out_delete:
1104 perf_session__delete(session); 1106 perf_session__delete(session);
1105 return ret; 1107 return ret;
1106} 1108}
1107 1109
1108static int __cmd_record(int argc, const char **argv) 1110static 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,
1207int cmd_timechart(int argc, const char **argv, 1209int 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}