diff options
author | Stephane Eranian <eranian@google.com> | 2011-08-15 16:22:33 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-08-18 06:46:13 -0400 |
commit | 4aa9015f8bfd2c8d7cc33a360275b71a9d708b37 (patch) | |
tree | 868d22562ba20ed87698e69cf33d29cce19764fb /tools/perf/builtin-stat.c | |
parent | e71a059832753a8834a5a5080366879954ccdc4d (diff) |
perf stat: Add -o and --append options
This patch adds an option (-o) to save the output of perf stat into a
file. You could do this with perf record but not with perf stat.
Instead, you had to fiddle with stderr to save the counts into a
separate file.
The patch also adds the --append option so that results can be
concatenated into a single file across runs. Each run of the tool is
clearly separated by a comment line starting with a hash mark. The -A
option of perf record is already used by perf stat, so we only add a
long option.
$ perf stat -o res.txt date
$ cat res.txt
Performance counter stats for 'date':
0.791306 task-clock # 0.668 CPUs utilized
2 context-switches # 0.003 M/sec
0 CPU-migrations # 0.000 M/sec
197 page-faults # 0.249 M/sec
1878143 cycles # 2.373 GHz
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
1083367 instructions # 0.58 insns per cycle
193027 branches # 243.935 M/sec
9014 branch-misses # 4.67% of all branches
0.001184746 seconds time elapsed
The option can be combined with -x to make the output file much easier
to parse.
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20110815202233.GA18535@quad
Signed-off-by: Stephane Eranian <eranian@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-stat.c')
-rw-r--r-- | tools/perf/builtin-stat.c | 155 |
1 files changed, 92 insertions, 63 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 1ad04ce29c34..a22393d7ec6d 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -193,6 +193,8 @@ static int big_num_opt = -1; | |||
193 | static const char *cpu_list; | 193 | static const char *cpu_list; |
194 | static const char *csv_sep = NULL; | 194 | static const char *csv_sep = NULL; |
195 | static bool csv_output = false; | 195 | static bool csv_output = false; |
196 | static const char *output_name = NULL; | ||
197 | static FILE *output = NULL; | ||
196 | 198 | ||
197 | static volatile int done = 0; | 199 | static volatile int done = 0; |
198 | 200 | ||
@@ -351,7 +353,7 @@ static int read_counter_aggr(struct perf_evsel *counter) | |||
351 | update_stats(&ps->res_stats[i], count[i]); | 353 | update_stats(&ps->res_stats[i], count[i]); |
352 | 354 | ||
353 | if (verbose) { | 355 | if (verbose) { |
354 | fprintf(stderr, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", | 356 | fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", |
355 | event_name(counter), count[0], count[1], count[2]); | 357 | event_name(counter), count[0], count[1], count[2]); |
356 | } | 358 | } |
357 | 359 | ||
@@ -518,9 +520,9 @@ static void print_noise_pct(double total, double avg) | |||
518 | pct = 100.0*total/avg; | 520 | pct = 100.0*total/avg; |
519 | 521 | ||
520 | if (csv_output) | 522 | if (csv_output) |
521 | fprintf(stderr, "%s%.2f%%", csv_sep, pct); | 523 | fprintf(output, "%s%.2f%%", csv_sep, pct); |
522 | else | 524 | else |
523 | fprintf(stderr, " ( +-%6.2f%% )", pct); | 525 | fprintf(output, " ( +-%6.2f%% )", pct); |
524 | } | 526 | } |
525 | 527 | ||
526 | static void print_noise(struct perf_evsel *evsel, double avg) | 528 | static void print_noise(struct perf_evsel *evsel, double avg) |
@@ -545,16 +547,17 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
545 | csv_output ? 0 : -4, | 547 | csv_output ? 0 : -4, |
546 | evsel_list->cpus->map[cpu], csv_sep); | 548 | evsel_list->cpus->map[cpu], csv_sep); |
547 | 549 | ||
548 | fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel)); | 550 | fprintf(output, fmt, cpustr, msecs, csv_sep, event_name(evsel)); |
549 | 551 | ||
550 | if (evsel->cgrp) | 552 | if (evsel->cgrp) |
551 | fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name); | 553 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); |
552 | 554 | ||
553 | if (csv_output) | 555 | if (csv_output) |
554 | return; | 556 | return; |
555 | 557 | ||
556 | if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) | 558 | if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) |
557 | fprintf(stderr, " # %8.3f CPUs utilized ", avg / avg_stats(&walltime_nsecs_stats)); | 559 | fprintf(output, " # %8.3f CPUs utilized ", |
560 | avg / avg_stats(&walltime_nsecs_stats)); | ||
558 | } | 561 | } |
559 | 562 | ||
560 | static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg) | 563 | static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg) |
@@ -575,9 +578,9 @@ static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __us | |||
575 | else if (ratio > 10.0) | 578 | else if (ratio > 10.0) |
576 | color = PERF_COLOR_YELLOW; | 579 | color = PERF_COLOR_YELLOW; |
577 | 580 | ||
578 | fprintf(stderr, " # "); | 581 | fprintf(output, " # "); |
579 | color_fprintf(stderr, color, "%6.2f%%", ratio); | 582 | color_fprintf(output, color, "%6.2f%%", ratio); |
580 | fprintf(stderr, " frontend cycles idle "); | 583 | fprintf(output, " frontend cycles idle "); |
581 | } | 584 | } |
582 | 585 | ||
583 | static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg) | 586 | static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg) |
@@ -598,9 +601,9 @@ static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __use | |||
598 | else if (ratio > 20.0) | 601 | else if (ratio > 20.0) |
599 | color = PERF_COLOR_YELLOW; | 602 | color = PERF_COLOR_YELLOW; |
600 | 603 | ||
601 | fprintf(stderr, " # "); | 604 | fprintf(output, " # "); |
602 | color_fprintf(stderr, color, "%6.2f%%", ratio); | 605 | color_fprintf(output, color, "%6.2f%%", ratio); |
603 | fprintf(stderr, " backend cycles idle "); | 606 | fprintf(output, " backend cycles idle "); |
604 | } | 607 | } |
605 | 608 | ||
606 | static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg) | 609 | static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg) |
@@ -621,9 +624,9 @@ static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double | |||
621 | else if (ratio > 5.0) | 624 | else if (ratio > 5.0) |
622 | color = PERF_COLOR_YELLOW; | 625 | color = PERF_COLOR_YELLOW; |
623 | 626 | ||
624 | fprintf(stderr, " # "); | 627 | fprintf(output, " # "); |
625 | color_fprintf(stderr, color, "%6.2f%%", ratio); | 628 | color_fprintf(output, color, "%6.2f%%", ratio); |
626 | fprintf(stderr, " of all branches "); | 629 | fprintf(output, " of all branches "); |
627 | } | 630 | } |
628 | 631 | ||
629 | static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg) | 632 | static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg) |
@@ -644,9 +647,9 @@ static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, dou | |||
644 | else if (ratio > 5.0) | 647 | else if (ratio > 5.0) |
645 | color = PERF_COLOR_YELLOW; | 648 | color = PERF_COLOR_YELLOW; |
646 | 649 | ||
647 | fprintf(stderr, " # "); | 650 | fprintf(output, " # "); |
648 | color_fprintf(stderr, color, "%6.2f%%", ratio); | 651 | color_fprintf(output, color, "%6.2f%%", ratio); |
649 | fprintf(stderr, " of all L1-dcache hits "); | 652 | fprintf(output, " of all L1-dcache hits "); |
650 | } | 653 | } |
651 | 654 | ||
652 | static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg) | 655 | static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg) |
@@ -667,9 +670,9 @@ static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, dou | |||
667 | else if (ratio > 5.0) | 670 | else if (ratio > 5.0) |
668 | color = PERF_COLOR_YELLOW; | 671 | color = PERF_COLOR_YELLOW; |
669 | 672 | ||
670 | fprintf(stderr, " # "); | 673 | fprintf(output, " # "); |
671 | color_fprintf(stderr, color, "%6.2f%%", ratio); | 674 | color_fprintf(output, color, "%6.2f%%", ratio); |
672 | fprintf(stderr, " of all L1-icache hits "); | 675 | fprintf(output, " of all L1-icache hits "); |
673 | } | 676 | } |
674 | 677 | ||
675 | static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) | 678 | static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) |
@@ -690,9 +693,9 @@ static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do | |||
690 | else if (ratio > 5.0) | 693 | else if (ratio > 5.0) |
691 | color = PERF_COLOR_YELLOW; | 694 | color = PERF_COLOR_YELLOW; |
692 | 695 | ||
693 | fprintf(stderr, " # "); | 696 | fprintf(output, " # "); |
694 | color_fprintf(stderr, color, "%6.2f%%", ratio); | 697 | color_fprintf(output, color, "%6.2f%%", ratio); |
695 | fprintf(stderr, " of all dTLB cache hits "); | 698 | fprintf(output, " of all dTLB cache hits "); |
696 | } | 699 | } |
697 | 700 | ||
698 | static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) | 701 | static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) |
@@ -713,9 +716,9 @@ static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do | |||
713 | else if (ratio > 5.0) | 716 | else if (ratio > 5.0) |
714 | color = PERF_COLOR_YELLOW; | 717 | color = PERF_COLOR_YELLOW; |
715 | 718 | ||
716 | fprintf(stderr, " # "); | 719 | fprintf(output, " # "); |
717 | color_fprintf(stderr, color, "%6.2f%%", ratio); | 720 | color_fprintf(output, color, "%6.2f%%", ratio); |
718 | fprintf(stderr, " of all iTLB cache hits "); | 721 | fprintf(output, " of all iTLB cache hits "); |
719 | } | 722 | } |
720 | 723 | ||
721 | static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) | 724 | static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) |
@@ -736,9 +739,9 @@ static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, doub | |||
736 | else if (ratio > 5.0) | 739 | else if (ratio > 5.0) |
737 | color = PERF_COLOR_YELLOW; | 740 | color = PERF_COLOR_YELLOW; |
738 | 741 | ||
739 | fprintf(stderr, " # "); | 742 | fprintf(output, " # "); |
740 | color_fprintf(stderr, color, "%6.2f%%", ratio); | 743 | color_fprintf(output, color, "%6.2f%%", ratio); |
741 | fprintf(stderr, " of all LL-cache hits "); | 744 | fprintf(output, " of all LL-cache hits "); |
742 | } | 745 | } |
743 | 746 | ||
744 | static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | 747 | static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) |
@@ -761,10 +764,10 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
761 | else | 764 | else |
762 | cpu = 0; | 765 | cpu = 0; |
763 | 766 | ||
764 | fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel)); | 767 | fprintf(output, fmt, cpustr, avg, csv_sep, event_name(evsel)); |
765 | 768 | ||
766 | if (evsel->cgrp) | 769 | if (evsel->cgrp) |
767 | fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name); | 770 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); |
768 | 771 | ||
769 | if (csv_output) | 772 | if (csv_output) |
770 | return; | 773 | return; |
@@ -775,14 +778,14 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
775 | if (total) | 778 | if (total) |
776 | ratio = avg / total; | 779 | ratio = avg / total; |
777 | 780 | ||
778 | fprintf(stderr, " # %5.2f insns per cycle ", ratio); | 781 | fprintf(output, " # %5.2f insns per cycle ", ratio); |
779 | 782 | ||
780 | total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]); | 783 | total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]); |
781 | total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu])); | 784 | total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu])); |
782 | 785 | ||
783 | if (total && avg) { | 786 | if (total && avg) { |
784 | ratio = total / avg; | 787 | ratio = total / avg; |
785 | fprintf(stderr, "\n # %5.2f stalled cycles per insn", ratio); | 788 | fprintf(output, "\n # %5.2f stalled cycles per insn", ratio); |
786 | } | 789 | } |
787 | 790 | ||
788 | } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && | 791 | } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && |
@@ -830,7 +833,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
830 | if (total) | 833 | if (total) |
831 | ratio = avg * 100 / total; | 834 | ratio = avg * 100 / total; |
832 | 835 | ||
833 | fprintf(stderr, " # %8.3f %% of all cache refs ", ratio); | 836 | fprintf(output, " # %8.3f %% of all cache refs ", ratio); |
834 | 837 | ||
835 | } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) { | 838 | } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) { |
836 | print_stalled_cycles_frontend(cpu, evsel, avg); | 839 | print_stalled_cycles_frontend(cpu, evsel, avg); |
@@ -842,16 +845,16 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
842 | if (total) | 845 | if (total) |
843 | ratio = 1.0 * avg / total; | 846 | ratio = 1.0 * avg / total; |
844 | 847 | ||
845 | fprintf(stderr, " # %8.3f GHz ", ratio); | 848 | fprintf(output, " # %8.3f GHz ", ratio); |
846 | } else if (runtime_nsecs_stats[cpu].n != 0) { | 849 | } else if (runtime_nsecs_stats[cpu].n != 0) { |
847 | total = avg_stats(&runtime_nsecs_stats[cpu]); | 850 | total = avg_stats(&runtime_nsecs_stats[cpu]); |
848 | 851 | ||
849 | if (total) | 852 | if (total) |
850 | ratio = 1000.0 * avg / total; | 853 | ratio = 1000.0 * avg / total; |
851 | 854 | ||
852 | fprintf(stderr, " # %8.3f M/sec ", ratio); | 855 | fprintf(output, " # %8.3f M/sec ", ratio); |
853 | } else { | 856 | } else { |
854 | fprintf(stderr, " "); | 857 | fprintf(output, " "); |
855 | } | 858 | } |
856 | } | 859 | } |
857 | 860 | ||
@@ -866,7 +869,7 @@ static void print_counter_aggr(struct perf_evsel *counter) | |||
866 | int scaled = counter->counts->scaled; | 869 | int scaled = counter->counts->scaled; |
867 | 870 | ||
868 | if (scaled == -1) { | 871 | if (scaled == -1) { |
869 | fprintf(stderr, "%*s%s%*s", | 872 | fprintf(output, "%*s%s%*s", |
870 | csv_output ? 0 : 18, | 873 | csv_output ? 0 : 18, |
871 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, | 874 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, |
872 | csv_sep, | 875 | csv_sep, |
@@ -874,9 +877,9 @@ static void print_counter_aggr(struct perf_evsel *counter) | |||
874 | event_name(counter)); | 877 | event_name(counter)); |
875 | 878 | ||
876 | if (counter->cgrp) | 879 | if (counter->cgrp) |
877 | fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name); | 880 | fprintf(output, "%s%s", csv_sep, counter->cgrp->name); |
878 | 881 | ||
879 | fputc('\n', stderr); | 882 | fputc('\n', output); |
880 | return; | 883 | return; |
881 | } | 884 | } |
882 | 885 | ||
@@ -888,7 +891,7 @@ static void print_counter_aggr(struct perf_evsel *counter) | |||
888 | print_noise(counter, avg); | 891 | print_noise(counter, avg); |
889 | 892 | ||
890 | if (csv_output) { | 893 | if (csv_output) { |
891 | fputc('\n', stderr); | 894 | fputc('\n', output); |
892 | return; | 895 | return; |
893 | } | 896 | } |
894 | 897 | ||
@@ -898,9 +901,9 @@ static void print_counter_aggr(struct perf_evsel *counter) | |||
898 | avg_enabled = avg_stats(&ps->res_stats[1]); | 901 | avg_enabled = avg_stats(&ps->res_stats[1]); |
899 | avg_running = avg_stats(&ps->res_stats[2]); | 902 | avg_running = avg_stats(&ps->res_stats[2]); |
900 | 903 | ||
901 | fprintf(stderr, " [%5.2f%%]", 100 * avg_running / avg_enabled); | 904 | fprintf(output, " [%5.2f%%]", 100 * avg_running / avg_enabled); |
902 | } | 905 | } |
903 | fprintf(stderr, "\n"); | 906 | fprintf(output, "\n"); |
904 | } | 907 | } |
905 | 908 | ||
906 | /* | 909 | /* |
@@ -917,7 +920,7 @@ static void print_counter(struct perf_evsel *counter) | |||
917 | ena = counter->counts->cpu[cpu].ena; | 920 | ena = counter->counts->cpu[cpu].ena; |
918 | run = counter->counts->cpu[cpu].run; | 921 | run = counter->counts->cpu[cpu].run; |
919 | if (run == 0 || ena == 0) { | 922 | if (run == 0 || ena == 0) { |
920 | fprintf(stderr, "CPU%*d%s%*s%s%*s", | 923 | fprintf(output, "CPU%*d%s%*s%s%*s", |
921 | csv_output ? 0 : -4, | 924 | csv_output ? 0 : -4, |
922 | evsel_list->cpus->map[cpu], csv_sep, | 925 | evsel_list->cpus->map[cpu], csv_sep, |
923 | csv_output ? 0 : 18, | 926 | csv_output ? 0 : 18, |
@@ -927,9 +930,10 @@ static void print_counter(struct perf_evsel *counter) | |||
927 | event_name(counter)); | 930 | event_name(counter)); |
928 | 931 | ||
929 | if (counter->cgrp) | 932 | if (counter->cgrp) |
930 | fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name); | 933 | fprintf(output, "%s%s", |
934 | csv_sep, counter->cgrp->name); | ||
931 | 935 | ||
932 | fputc('\n', stderr); | 936 | fputc('\n', output); |
933 | continue; | 937 | continue; |
934 | } | 938 | } |
935 | 939 | ||
@@ -942,9 +946,10 @@ static void print_counter(struct perf_evsel *counter) | |||
942 | print_noise(counter, 1.0); | 946 | print_noise(counter, 1.0); |
943 | 947 | ||
944 | if (run != ena) | 948 | if (run != ena) |
945 | fprintf(stderr, " (%.2f%%)", 100.0 * run / ena); | 949 | fprintf(output, " (%.2f%%)", |
950 | 100.0 * run / ena); | ||
946 | } | 951 | } |
947 | fputc('\n', stderr); | 952 | fputc('\n', output); |
948 | } | 953 | } |
949 | } | 954 | } |
950 | 955 | ||
@@ -956,21 +961,21 @@ static void print_stat(int argc, const char **argv) | |||
956 | fflush(stdout); | 961 | fflush(stdout); |
957 | 962 | ||
958 | if (!csv_output) { | 963 | if (!csv_output) { |
959 | fprintf(stderr, "\n"); | 964 | fprintf(output, "\n"); |
960 | fprintf(stderr, " Performance counter stats for "); | 965 | fprintf(output, " Performance counter stats for "); |
961 | if(target_pid == -1 && target_tid == -1) { | 966 | if(target_pid == -1 && target_tid == -1) { |
962 | fprintf(stderr, "\'%s", argv[0]); | 967 | fprintf(output, "\'%s", argv[0]); |
963 | for (i = 1; i < argc; i++) | 968 | for (i = 1; i < argc; i++) |
964 | fprintf(stderr, " %s", argv[i]); | 969 | fprintf(output, " %s", argv[i]); |
965 | } else if (target_pid != -1) | 970 | } else if (target_pid != -1) |
966 | fprintf(stderr, "process id \'%d", target_pid); | 971 | fprintf(output, "process id \'%d", target_pid); |
967 | else | 972 | else |
968 | fprintf(stderr, "thread id \'%d", target_tid); | 973 | fprintf(output, "thread id \'%d", target_tid); |
969 | 974 | ||
970 | fprintf(stderr, "\'"); | 975 | fprintf(output, "\'"); |
971 | if (run_count > 1) | 976 | if (run_count > 1) |
972 | fprintf(stderr, " (%d runs)", run_count); | 977 | fprintf(output, " (%d runs)", run_count); |
973 | fprintf(stderr, ":\n\n"); | 978 | fprintf(output, ":\n\n"); |
974 | } | 979 | } |
975 | 980 | ||
976 | if (no_aggr) { | 981 | if (no_aggr) { |
@@ -983,15 +988,15 @@ static void print_stat(int argc, const char **argv) | |||
983 | 988 | ||
984 | if (!csv_output) { | 989 | if (!csv_output) { |
985 | if (!null_run) | 990 | if (!null_run) |
986 | fprintf(stderr, "\n"); | 991 | fprintf(output, "\n"); |
987 | fprintf(stderr, " %17.9f seconds time elapsed", | 992 | fprintf(output, " %17.9f seconds time elapsed", |
988 | avg_stats(&walltime_nsecs_stats)/1e9); | 993 | avg_stats(&walltime_nsecs_stats)/1e9); |
989 | if (run_count > 1) { | 994 | if (run_count > 1) { |
990 | fprintf(stderr, " "); | 995 | fprintf(output, " "); |
991 | print_noise_pct(stddev_stats(&walltime_nsecs_stats), | 996 | print_noise_pct(stddev_stats(&walltime_nsecs_stats), |
992 | avg_stats(&walltime_nsecs_stats)); | 997 | avg_stats(&walltime_nsecs_stats)); |
993 | } | 998 | } |
994 | fprintf(stderr, "\n\n"); | 999 | fprintf(output, "\n\n"); |
995 | } | 1000 | } |
996 | } | 1001 | } |
997 | 1002 | ||
@@ -1029,6 +1034,8 @@ static int stat__set_big_num(const struct option *opt __used, | |||
1029 | return 0; | 1034 | return 0; |
1030 | } | 1035 | } |
1031 | 1036 | ||
1037 | static bool append_file; | ||
1038 | |||
1032 | static const struct option options[] = { | 1039 | static const struct option options[] = { |
1033 | OPT_CALLBACK('e', "event", &evsel_list, "event", | 1040 | OPT_CALLBACK('e', "event", &evsel_list, "event", |
1034 | "event selector. use 'perf list' to list available events", | 1041 | "event selector. use 'perf list' to list available events", |
@@ -1067,6 +1074,9 @@ static const struct option options[] = { | |||
1067 | OPT_CALLBACK('G', "cgroup", &evsel_list, "name", | 1074 | OPT_CALLBACK('G', "cgroup", &evsel_list, "name", |
1068 | "monitor event in cgroup name only", | 1075 | "monitor event in cgroup name only", |
1069 | parse_cgroups), | 1076 | parse_cgroups), |
1077 | OPT_STRING('o', "output", &output_name, "file", | ||
1078 | "output file name"), | ||
1079 | OPT_BOOLEAN(0, "append", &append_file, "append to the output file"), | ||
1070 | OPT_END() | 1080 | OPT_END() |
1071 | }; | 1081 | }; |
1072 | 1082 | ||
@@ -1138,6 +1148,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
1138 | { | 1148 | { |
1139 | struct perf_evsel *pos; | 1149 | struct perf_evsel *pos; |
1140 | int status = -ENOMEM; | 1150 | int status = -ENOMEM; |
1151 | const char *mode; | ||
1141 | 1152 | ||
1142 | setlocale(LC_ALL, ""); | 1153 | setlocale(LC_ALL, ""); |
1143 | 1154 | ||
@@ -1148,6 +1159,23 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
1148 | argc = parse_options(argc, argv, options, stat_usage, | 1159 | argc = parse_options(argc, argv, options, stat_usage, |
1149 | PARSE_OPT_STOP_AT_NON_OPTION); | 1160 | PARSE_OPT_STOP_AT_NON_OPTION); |
1150 | 1161 | ||
1162 | output = stderr; | ||
1163 | if (output_name && strcmp(output_name, "-")) | ||
1164 | output = NULL; | ||
1165 | |||
1166 | if (!output) { | ||
1167 | struct timespec tm; | ||
1168 | mode = append_file ? "a" : "w"; | ||
1169 | |||
1170 | output = fopen(output_name, mode); | ||
1171 | if (!output) { | ||
1172 | perror("failed to create output file"); | ||
1173 | exit(-1); | ||
1174 | } | ||
1175 | clock_gettime(CLOCK_REALTIME, &tm); | ||
1176 | fprintf(output, "# started on %s\n", ctime(&tm.tv_sec)); | ||
1177 | } | ||
1178 | |||
1151 | if (csv_sep) | 1179 | if (csv_sep) |
1152 | csv_output = true; | 1180 | csv_output = true; |
1153 | else | 1181 | else |
@@ -1223,7 +1251,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) | |||
1223 | status = 0; | 1251 | status = 0; |
1224 | for (run_idx = 0; run_idx < run_count; run_idx++) { | 1252 | for (run_idx = 0; run_idx < run_count; run_idx++) { |
1225 | if (run_count != 1 && verbose) | 1253 | if (run_count != 1 && verbose) |
1226 | fprintf(stderr, "[ perf stat: executing run #%d ... ]\n", run_idx + 1); | 1254 | fprintf(output, "[ perf stat: executing run #%d ... ]\n", |
1255 | run_idx + 1); | ||
1227 | 1256 | ||
1228 | if (sync_run) | 1257 | if (sync_run) |
1229 | sync(); | 1258 | sync(); |