aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorStephane Eranian <eranian@google.com>2011-08-15 16:22:33 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-08-18 06:46:13 -0400
commit4aa9015f8bfd2c8d7cc33a360275b71a9d708b37 (patch)
tree868d22562ba20ed87698e69cf33d29cce19764fb /tools/perf
parente71a059832753a8834a5a5080366879954ccdc4d (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')
-rw-r--r--tools/perf/Documentation/perf-stat.txt7
-rw-r--r--tools/perf/builtin-stat.c155
-rw-r--r--tools/perf/util/color.c2
3 files changed, 100 insertions, 64 deletions
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 918cc38ee6d1..08394c4879a8 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -94,6 +94,13 @@ an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must ha
94corresponding events, i.e., they always refer to events defined earlier on the command 94corresponding events, i.e., they always refer to events defined earlier on the command
95line. 95line.
96 96
97-o file::
98-output file::
99Print the output into the designated file.
100
101--append::
102Append to the output file designated with the -o option. Ignored if -o is not specified.
103
97EXAMPLES 104EXAMPLES
98-------- 105--------
99 106
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;
193static const char *cpu_list; 193static const char *cpu_list;
194static const char *csv_sep = NULL; 194static const char *csv_sep = NULL;
195static bool csv_output = false; 195static bool csv_output = false;
196static const char *output_name = NULL;
197static FILE *output = NULL;
196 198
197static volatile int done = 0; 199static 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
526static void print_noise(struct perf_evsel *evsel, double avg) 528static 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
560static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg) 563static 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
583static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __used, double avg) 586static 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
606static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double avg) 609static 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
629static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 632static 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
652static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 655static 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
675static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 678static 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
698static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 701static 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
721static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, double avg) 724static 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
744static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) 747static 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
1037static bool append_file;
1038
1032static const struct option options[] = { 1039static 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();
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index e191eb9a667f..521c38a79190 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -200,7 +200,7 @@ static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
200 * Auto-detect: 200 * Auto-detect:
201 */ 201 */
202 if (perf_use_color_default < 0) { 202 if (perf_use_color_default < 0) {
203 if (isatty(1) || pager_in_use()) 203 if (isatty(fileno(fp)) || pager_in_use())
204 perf_use_color_default = 1; 204 perf_use_color_default = 1;
205 else 205 else
206 perf_use_color_default = 0; 206 perf_use_color_default = 0;