aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-stat.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-stat.c')
-rw-r--r--tools/perf/builtin-stat.c567
1 files changed, 463 insertions, 104 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 038e877081b6..1f19f2f999c8 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -122,6 +122,7 @@ static bool sync_run = false;
122static unsigned int initial_delay = 0; 122static unsigned int initial_delay = 0;
123static unsigned int unit_width = 4; /* strlen("unit") */ 123static unsigned int unit_width = 4; /* strlen("unit") */
124static bool forever = false; 124static bool forever = false;
125static bool metric_only = false;
125static struct timespec ref_time; 126static struct timespec ref_time;
126static struct cpu_map *aggr_map; 127static struct cpu_map *aggr_map;
127static aggr_get_id_t aggr_get_id; 128static aggr_get_id_t aggr_get_id;
@@ -735,6 +736,191 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
735 } 736 }
736} 737}
737 738
739struct outstate {
740 FILE *fh;
741 bool newline;
742 const char *prefix;
743 int nfields;
744 int id, nr;
745 struct perf_evsel *evsel;
746};
747
748#define METRIC_LEN 35
749
750static void new_line_std(void *ctx)
751{
752 struct outstate *os = ctx;
753
754 os->newline = true;
755}
756
757static void do_new_line_std(struct outstate *os)
758{
759 fputc('\n', os->fh);
760 fputs(os->prefix, os->fh);
761 aggr_printout(os->evsel, os->id, os->nr);
762 if (stat_config.aggr_mode == AGGR_NONE)
763 fprintf(os->fh, " ");
764 fprintf(os->fh, " ");
765}
766
767static void print_metric_std(void *ctx, const char *color, const char *fmt,
768 const char *unit, double val)
769{
770 struct outstate *os = ctx;
771 FILE *out = os->fh;
772 int n;
773 bool newline = os->newline;
774
775 os->newline = false;
776
777 if (unit == NULL || fmt == NULL) {
778 fprintf(out, "%-*s", METRIC_LEN, "");
779 return;
780 }
781
782 if (newline)
783 do_new_line_std(os);
784
785 n = fprintf(out, " # ");
786 if (color)
787 n += color_fprintf(out, color, fmt, val);
788 else
789 n += fprintf(out, fmt, val);
790 fprintf(out, " %-*s", METRIC_LEN - n - 1, unit);
791}
792
793static void new_line_csv(void *ctx)
794{
795 struct outstate *os = ctx;
796 int i;
797
798 fputc('\n', os->fh);
799 if (os->prefix)
800 fprintf(os->fh, "%s%s", os->prefix, csv_sep);
801 aggr_printout(os->evsel, os->id, os->nr);
802 for (i = 0; i < os->nfields; i++)
803 fputs(csv_sep, os->fh);
804}
805
806static void print_metric_csv(void *ctx,
807 const char *color __maybe_unused,
808 const char *fmt, const char *unit, double val)
809{
810 struct outstate *os = ctx;
811 FILE *out = os->fh;
812 char buf[64], *vals, *ends;
813
814 if (unit == NULL || fmt == NULL) {
815 fprintf(out, "%s%s%s%s", csv_sep, csv_sep, csv_sep, csv_sep);
816 return;
817 }
818 snprintf(buf, sizeof(buf), fmt, val);
819 vals = buf;
820 while (isspace(*vals))
821 vals++;
822 ends = vals;
823 while (isdigit(*ends) || *ends == '.')
824 ends++;
825 *ends = 0;
826 while (isspace(*unit))
827 unit++;
828 fprintf(out, "%s%s%s%s", csv_sep, vals, csv_sep, unit);
829}
830
831#define METRIC_ONLY_LEN 20
832
833/* Filter out some columns that don't work well in metrics only mode */
834
835static bool valid_only_metric(const char *unit)
836{
837 if (!unit)
838 return false;
839 if (strstr(unit, "/sec") ||
840 strstr(unit, "hz") ||
841 strstr(unit, "Hz") ||
842 strstr(unit, "CPUs utilized"))
843 return false;
844 return true;
845}
846
847static const char *fixunit(char *buf, struct perf_evsel *evsel,
848 const char *unit)
849{
850 if (!strncmp(unit, "of all", 6)) {
851 snprintf(buf, 1024, "%s %s", perf_evsel__name(evsel),
852 unit);
853 return buf;
854 }
855 return unit;
856}
857
858static void print_metric_only(void *ctx, const char *color, const char *fmt,
859 const char *unit, double val)
860{
861 struct outstate *os = ctx;
862 FILE *out = os->fh;
863 int n;
864 char buf[1024];
865 unsigned mlen = METRIC_ONLY_LEN;
866
867 if (!valid_only_metric(unit))
868 return;
869 unit = fixunit(buf, os->evsel, unit);
870 if (color)
871 n = color_fprintf(out, color, fmt, val);
872 else
873 n = fprintf(out, fmt, val);
874 if (n > METRIC_ONLY_LEN)
875 n = METRIC_ONLY_LEN;
876 if (mlen < strlen(unit))
877 mlen = strlen(unit) + 1;
878 fprintf(out, "%*s", mlen - n, "");
879}
880
881static void print_metric_only_csv(void *ctx, const char *color __maybe_unused,
882 const char *fmt,
883 const char *unit, double val)
884{
885 struct outstate *os = ctx;
886 FILE *out = os->fh;
887 char buf[64], *vals, *ends;
888 char tbuf[1024];
889
890 if (!valid_only_metric(unit))
891 return;
892 unit = fixunit(tbuf, os->evsel, unit);
893 snprintf(buf, sizeof buf, fmt, val);
894 vals = buf;
895 while (isspace(*vals))
896 vals++;
897 ends = vals;
898 while (isdigit(*ends) || *ends == '.')
899 ends++;
900 *ends = 0;
901 fprintf(out, "%s%s", vals, csv_sep);
902}
903
904static void new_line_metric(void *ctx __maybe_unused)
905{
906}
907
908static void print_metric_header(void *ctx, const char *color __maybe_unused,
909 const char *fmt __maybe_unused,
910 const char *unit, double val __maybe_unused)
911{
912 struct outstate *os = ctx;
913 char tbuf[1024];
914
915 if (!valid_only_metric(unit))
916 return;
917 unit = fixunit(tbuf, os->evsel, unit);
918 if (csv_output)
919 fprintf(os->fh, "%s%s", unit, csv_sep);
920 else
921 fprintf(os->fh, "%-*s ", METRIC_ONLY_LEN, unit);
922}
923
738static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) 924static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
739{ 925{
740 FILE *output = stat_config.output; 926 FILE *output = stat_config.output;
@@ -763,6 +949,28 @@ static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
763 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 949 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
764} 950}
765 951
952static int first_shadow_cpu(struct perf_evsel *evsel, int id)
953{
954 int i;
955
956 if (!aggr_get_id)
957 return 0;
958
959 if (stat_config.aggr_mode == AGGR_NONE)
960 return id;
961
962 if (stat_config.aggr_mode == AGGR_GLOBAL)
963 return 0;
964
965 for (i = 0; i < perf_evsel__nr_cpus(evsel); i++) {
966 int cpu2 = perf_evsel__cpus(evsel)->map[i];
967
968 if (aggr_get_id(evsel_list->cpus, cpu2) == id)
969 return cpu2;
970 }
971 return 0;
972}
973
766static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) 974static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
767{ 975{
768 FILE *output = stat_config.output; 976 FILE *output = stat_config.output;
@@ -793,22 +1001,124 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
793 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 1001 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
794} 1002}
795 1003
796static void printout(int id, int nr, struct perf_evsel *counter, double uval) 1004static void printout(int id, int nr, struct perf_evsel *counter, double uval,
1005 char *prefix, u64 run, u64 ena, double noise)
797{ 1006{
798 int cpu = cpu_map__id_to_cpu(id); 1007 struct perf_stat_output_ctx out;
1008 struct outstate os = {
1009 .fh = stat_config.output,
1010 .prefix = prefix ? prefix : "",
1011 .id = id,
1012 .nr = nr,
1013 .evsel = counter,
1014 };
1015 print_metric_t pm = print_metric_std;
1016 void (*nl)(void *);
799 1017
800 if (stat_config.aggr_mode == AGGR_GLOBAL) 1018 if (metric_only) {
801 cpu = 0; 1019 nl = new_line_metric;
1020 if (csv_output)
1021 pm = print_metric_only_csv;
1022 else
1023 pm = print_metric_only;
1024 } else
1025 nl = new_line_std;
1026
1027 if (csv_output && !metric_only) {
1028 static int aggr_fields[] = {
1029 [AGGR_GLOBAL] = 0,
1030 [AGGR_THREAD] = 1,
1031 [AGGR_NONE] = 1,
1032 [AGGR_SOCKET] = 2,
1033 [AGGR_CORE] = 2,
1034 };
1035
1036 pm = print_metric_csv;
1037 nl = new_line_csv;
1038 os.nfields = 3;
1039 os.nfields += aggr_fields[stat_config.aggr_mode];
1040 if (counter->cgrp)
1041 os.nfields++;
1042 }
1043 if (run == 0 || ena == 0 || counter->counts->scaled == -1) {
1044 if (metric_only) {
1045 pm(&os, NULL, "", "", 0);
1046 return;
1047 }
1048 aggr_printout(counter, id, nr);
1049
1050 fprintf(stat_config.output, "%*s%s",
1051 csv_output ? 0 : 18,
1052 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
1053 csv_sep);
1054
1055 fprintf(stat_config.output, "%-*s%s",
1056 csv_output ? 0 : unit_width,
1057 counter->unit, csv_sep);
1058
1059 fprintf(stat_config.output, "%*s",
1060 csv_output ? 0 : -25,
1061 perf_evsel__name(counter));
1062
1063 if (counter->cgrp)
1064 fprintf(stat_config.output, "%s%s",
1065 csv_sep, counter->cgrp->name);
802 1066
803 if (nsec_counter(counter)) 1067 if (!csv_output)
1068 pm(&os, NULL, NULL, "", 0);
1069 print_noise(counter, noise);
1070 print_running(run, ena);
1071 if (csv_output)
1072 pm(&os, NULL, NULL, "", 0);
1073 return;
1074 }
1075
1076 if (metric_only)
1077 /* nothing */;
1078 else if (nsec_counter(counter))
804 nsec_printout(id, nr, counter, uval); 1079 nsec_printout(id, nr, counter, uval);
805 else 1080 else
806 abs_printout(id, nr, counter, uval); 1081 abs_printout(id, nr, counter, uval);
807 1082
808 if (!csv_output && !stat_config.interval) 1083 out.print_metric = pm;
809 perf_stat__print_shadow_stats(stat_config.output, counter, 1084 out.new_line = nl;
810 uval, cpu, 1085 out.ctx = &os;
811 stat_config.aggr_mode); 1086
1087 if (csv_output && !metric_only) {
1088 print_noise(counter, noise);
1089 print_running(run, ena);
1090 }
1091
1092 perf_stat__print_shadow_stats(counter, uval,
1093 first_shadow_cpu(counter, id),
1094 &out);
1095 if (!csv_output && !metric_only) {
1096 print_noise(counter, noise);
1097 print_running(run, ena);
1098 }
1099}
1100
1101static void aggr_update_shadow(void)
1102{
1103 int cpu, s2, id, s;
1104 u64 val;
1105 struct perf_evsel *counter;
1106
1107 for (s = 0; s < aggr_map->nr; s++) {
1108 id = aggr_map->map[s];
1109 evlist__for_each(evsel_list, counter) {
1110 val = 0;
1111 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
1112 s2 = aggr_get_id(evsel_list->cpus, cpu);
1113 if (s2 != id)
1114 continue;
1115 val += perf_counts(counter->counts, cpu, 0)->val;
1116 }
1117 val = val * counter->scale;
1118 perf_stat__update_shadow_stats(counter, &val,
1119 first_shadow_cpu(counter, id));
1120 }
1121 }
812} 1122}
813 1123
814static void print_aggr(char *prefix) 1124static void print_aggr(char *prefix)
@@ -818,12 +1128,23 @@ static void print_aggr(char *prefix)
818 int cpu, s, s2, id, nr; 1128 int cpu, s, s2, id, nr;
819 double uval; 1129 double uval;
820 u64 ena, run, val; 1130 u64 ena, run, val;
1131 bool first;
821 1132
822 if (!(aggr_map || aggr_get_id)) 1133 if (!(aggr_map || aggr_get_id))
823 return; 1134 return;
824 1135
1136 aggr_update_shadow();
1137
1138 /*
1139 * With metric_only everything is on a single line.
1140 * Without each counter has its own line.
1141 */
825 for (s = 0; s < aggr_map->nr; s++) { 1142 for (s = 0; s < aggr_map->nr; s++) {
1143 if (prefix && metric_only)
1144 fprintf(output, "%s", prefix);
1145
826 id = aggr_map->map[s]; 1146 id = aggr_map->map[s];
1147 first = true;
827 evlist__for_each(evsel_list, counter) { 1148 evlist__for_each(evsel_list, counter) {
828 val = ena = run = 0; 1149 val = ena = run = 0;
829 nr = 0; 1150 nr = 0;
@@ -836,41 +1157,20 @@ static void print_aggr(char *prefix)
836 run += perf_counts(counter->counts, cpu, 0)->run; 1157 run += perf_counts(counter->counts, cpu, 0)->run;
837 nr++; 1158 nr++;
838 } 1159 }
839 if (prefix) 1160 if (first && metric_only) {
840 fprintf(output, "%s", prefix); 1161 first = false;
841
842 if (run == 0 || ena == 0) {
843 aggr_printout(counter, id, nr); 1162 aggr_printout(counter, id, nr);
844
845 fprintf(output, "%*s%s",
846 csv_output ? 0 : 18,
847 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
848 csv_sep);
849
850 fprintf(output, "%-*s%s",
851 csv_output ? 0 : unit_width,
852 counter->unit, csv_sep);
853
854 fprintf(output, "%*s",
855 csv_output ? 0 : -25,
856 perf_evsel__name(counter));
857
858 if (counter->cgrp)
859 fprintf(output, "%s%s",
860 csv_sep, counter->cgrp->name);
861
862 print_running(run, ena);
863 fputc('\n', output);
864 continue;
865 } 1163 }
866 uval = val * counter->scale; 1164 if (prefix && !metric_only)
867 printout(id, nr, counter, uval); 1165 fprintf(output, "%s", prefix);
868 if (!csv_output)
869 print_noise(counter, 1.0);
870 1166
871 print_running(run, ena); 1167 uval = val * counter->scale;
872 fputc('\n', output); 1168 printout(id, nr, counter, uval, prefix, run, ena, 1.0);
1169 if (!metric_only)
1170 fputc('\n', output);
873 } 1171 }
1172 if (metric_only)
1173 fputc('\n', output);
874 } 1174 }
875} 1175}
876 1176
@@ -895,12 +1195,7 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
895 fprintf(output, "%s", prefix); 1195 fprintf(output, "%s", prefix);
896 1196
897 uval = val * counter->scale; 1197 uval = val * counter->scale;
898 printout(thread, 0, counter, uval); 1198 printout(thread, 0, counter, uval, prefix, run, ena, 1.0);
899
900 if (!csv_output)
901 print_noise(counter, 1.0);
902
903 print_running(run, ena);
904 fputc('\n', output); 1199 fputc('\n', output);
905 } 1200 }
906} 1201}
@@ -914,43 +1209,19 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
914 FILE *output = stat_config.output; 1209 FILE *output = stat_config.output;
915 struct perf_stat_evsel *ps = counter->priv; 1210 struct perf_stat_evsel *ps = counter->priv;
916 double avg = avg_stats(&ps->res_stats[0]); 1211 double avg = avg_stats(&ps->res_stats[0]);
917 int scaled = counter->counts->scaled;
918 double uval; 1212 double uval;
919 double avg_enabled, avg_running; 1213 double avg_enabled, avg_running;
920 1214
921 avg_enabled = avg_stats(&ps->res_stats[1]); 1215 avg_enabled = avg_stats(&ps->res_stats[1]);
922 avg_running = avg_stats(&ps->res_stats[2]); 1216 avg_running = avg_stats(&ps->res_stats[2]);
923 1217
924 if (prefix) 1218 if (prefix && !metric_only)
925 fprintf(output, "%s", prefix); 1219 fprintf(output, "%s", prefix);
926 1220
927 if (scaled == -1 || !counter->supported) {
928 fprintf(output, "%*s%s",
929 csv_output ? 0 : 18,
930 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
931 csv_sep);
932 fprintf(output, "%-*s%s",
933 csv_output ? 0 : unit_width,
934 counter->unit, csv_sep);
935 fprintf(output, "%*s",
936 csv_output ? 0 : -25,
937 perf_evsel__name(counter));
938
939 if (counter->cgrp)
940 fprintf(output, "%s%s", csv_sep, counter->cgrp->name);
941
942 print_running(avg_running, avg_enabled);
943 fputc('\n', output);
944 return;
945 }
946
947 uval = avg * counter->scale; 1221 uval = avg * counter->scale;
948 printout(-1, 0, counter, uval); 1222 printout(-1, 0, counter, uval, prefix, avg_running, avg_enabled, avg);
949 1223 if (!metric_only)
950 print_noise(counter, avg); 1224 fprintf(output, "\n");
951
952 print_running(avg_running, avg_enabled);
953 fprintf(output, "\n");
954} 1225}
955 1226
956/* 1227/*
@@ -972,39 +1243,78 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
972 if (prefix) 1243 if (prefix)
973 fprintf(output, "%s", prefix); 1244 fprintf(output, "%s", prefix);
974 1245
975 if (run == 0 || ena == 0) { 1246 uval = val * counter->scale;
976 fprintf(output, "CPU%*d%s%*s%s", 1247 printout(cpu, 0, counter, uval, prefix, run, ena, 1.0);
977 csv_output ? 0 : -4,
978 perf_evsel__cpus(counter)->map[cpu], csv_sep,
979 csv_output ? 0 : 18,
980 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
981 csv_sep);
982 1248
983 fprintf(output, "%-*s%s", 1249 fputc('\n', output);
984 csv_output ? 0 : unit_width, 1250 }
985 counter->unit, csv_sep); 1251}
986 1252
987 fprintf(output, "%*s", 1253static void print_no_aggr_metric(char *prefix)
988 csv_output ? 0 : -25, 1254{
989 perf_evsel__name(counter)); 1255 int cpu;
1256 int nrcpus = 0;
1257 struct perf_evsel *counter;
1258 u64 ena, run, val;
1259 double uval;
990 1260
991 if (counter->cgrp) 1261 nrcpus = evsel_list->cpus->nr;
992 fprintf(output, "%s%s", 1262 for (cpu = 0; cpu < nrcpus; cpu++) {
993 csv_sep, counter->cgrp->name); 1263 bool first = true;
994 1264
995 print_running(run, ena); 1265 if (prefix)
996 fputc('\n', output); 1266 fputs(prefix, stat_config.output);
997 continue; 1267 evlist__for_each(evsel_list, counter) {
1268 if (first) {
1269 aggr_printout(counter, cpu, 0);
1270 first = false;
1271 }
1272 val = perf_counts(counter->counts, cpu, 0)->val;
1273 ena = perf_counts(counter->counts, cpu, 0)->ena;
1274 run = perf_counts(counter->counts, cpu, 0)->run;
1275
1276 uval = val * counter->scale;
1277 printout(cpu, 0, counter, uval, prefix, run, ena, 1.0);
998 } 1278 }
1279 fputc('\n', stat_config.output);
1280 }
1281}
999 1282
1000 uval = val * counter->scale; 1283static int aggr_header_lens[] = {
1001 printout(cpu, 0, counter, uval); 1284 [AGGR_CORE] = 18,
1002 if (!csv_output) 1285 [AGGR_SOCKET] = 12,
1003 print_noise(counter, 1.0); 1286 [AGGR_NONE] = 6,
1004 print_running(run, ena); 1287 [AGGR_THREAD] = 24,
1288 [AGGR_GLOBAL] = 0,
1289};
1005 1290
1006 fputc('\n', output); 1291static void print_metric_headers(char *prefix)
1292{
1293 struct perf_stat_output_ctx out;
1294 struct perf_evsel *counter;
1295 struct outstate os = {
1296 .fh = stat_config.output
1297 };
1298
1299 if (prefix)
1300 fprintf(stat_config.output, "%s", prefix);
1301
1302 if (!csv_output)
1303 fprintf(stat_config.output, "%*s",
1304 aggr_header_lens[stat_config.aggr_mode], "");
1305
1306 /* Print metrics headers only */
1307 evlist__for_each(evsel_list, counter) {
1308 os.evsel = counter;
1309 out.ctx = &os;
1310 out.print_metric = print_metric_header;
1311 out.new_line = new_line_metric;
1312 os.evsel = counter;
1313 perf_stat__print_shadow_stats(counter, 0,
1314 0,
1315 &out);
1007 } 1316 }
1317 fputc('\n', stat_config.output);
1008} 1318}
1009 1319
1010static void print_interval(char *prefix, struct timespec *ts) 1320static void print_interval(char *prefix, struct timespec *ts)
@@ -1014,7 +1324,7 @@ static void print_interval(char *prefix, struct timespec *ts)
1014 1324
1015 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep); 1325 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep);
1016 1326
1017 if (num_print_interval == 0 && !csv_output) { 1327 if (num_print_interval == 0 && !csv_output && !metric_only) {
1018 switch (stat_config.aggr_mode) { 1328 switch (stat_config.aggr_mode) {
1019 case AGGR_SOCKET: 1329 case AGGR_SOCKET:
1020 fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit"); 1330 fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit");
@@ -1101,6 +1411,17 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
1101 else 1411 else
1102 print_header(argc, argv); 1412 print_header(argc, argv);
1103 1413
1414 if (metric_only) {
1415 static int num_print_iv;
1416
1417 if (num_print_iv == 0)
1418 print_metric_headers(prefix);
1419 if (num_print_iv++ == 25)
1420 num_print_iv = 0;
1421 if (stat_config.aggr_mode == AGGR_GLOBAL && prefix)
1422 fprintf(stat_config.output, "%s", prefix);
1423 }
1424
1104 switch (stat_config.aggr_mode) { 1425 switch (stat_config.aggr_mode) {
1105 case AGGR_CORE: 1426 case AGGR_CORE:
1106 case AGGR_SOCKET: 1427 case AGGR_SOCKET:
@@ -1113,10 +1434,16 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
1113 case AGGR_GLOBAL: 1434 case AGGR_GLOBAL:
1114 evlist__for_each(evsel_list, counter) 1435 evlist__for_each(evsel_list, counter)
1115 print_counter_aggr(counter, prefix); 1436 print_counter_aggr(counter, prefix);
1437 if (metric_only)
1438 fputc('\n', stat_config.output);
1116 break; 1439 break;
1117 case AGGR_NONE: 1440 case AGGR_NONE:
1118 evlist__for_each(evsel_list, counter) 1441 if (metric_only)
1119 print_counter(counter, prefix); 1442 print_no_aggr_metric(prefix);
1443 else {
1444 evlist__for_each(evsel_list, counter)
1445 print_counter(counter, prefix);
1446 }
1120 break; 1447 break;
1121 case AGGR_UNSET: 1448 case AGGR_UNSET:
1122 default: 1449 default:
@@ -1237,6 +1564,8 @@ static const struct option stat_options[] = {
1237 "aggregate counts per thread", AGGR_THREAD), 1564 "aggregate counts per thread", AGGR_THREAD),
1238 OPT_UINTEGER('D', "delay", &initial_delay, 1565 OPT_UINTEGER('D', "delay", &initial_delay,
1239 "ms to wait before starting measurement after program start"), 1566 "ms to wait before starting measurement after program start"),
1567 OPT_BOOLEAN(0, "metric-only", &metric_only,
1568 "Only print computed metrics. No raw values"),
1240 OPT_END() 1569 OPT_END()
1241}; 1570};
1242 1571
@@ -1435,7 +1764,7 @@ static int perf_stat_init_aggr_mode_file(struct perf_stat *st)
1435 */ 1764 */
1436static int add_default_attributes(void) 1765static int add_default_attributes(void)
1437{ 1766{
1438 struct perf_event_attr default_attrs[] = { 1767 struct perf_event_attr default_attrs0[] = {
1439 1768
1440 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, 1769 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
1441 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, 1770 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES },
@@ -1443,8 +1772,14 @@ static int add_default_attributes(void)
1443 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, 1772 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
1444 1773
1445 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, 1774 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
1775};
1776 struct perf_event_attr frontend_attrs[] = {
1446 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, 1777 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND },
1778};
1779 struct perf_event_attr backend_attrs[] = {
1447 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, 1780 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND },
1781};
1782 struct perf_event_attr default_attrs1[] = {
1448 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, 1783 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
1449 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, 1784 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
1450 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, 1785 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
@@ -1561,7 +1896,19 @@ static int add_default_attributes(void)
1561 } 1896 }
1562 1897
1563 if (!evsel_list->nr_entries) { 1898 if (!evsel_list->nr_entries) {
1564 if (perf_evlist__add_default_attrs(evsel_list, default_attrs) < 0) 1899 if (perf_evlist__add_default_attrs(evsel_list, default_attrs0) < 0)
1900 return -1;
1901 if (pmu_have_event("cpu", "stalled-cycles-frontend")) {
1902 if (perf_evlist__add_default_attrs(evsel_list,
1903 frontend_attrs) < 0)
1904 return -1;
1905 }
1906 if (pmu_have_event("cpu", "stalled-cycles-backend")) {
1907 if (perf_evlist__add_default_attrs(evsel_list,
1908 backend_attrs) < 0)
1909 return -1;
1910 }
1911 if (perf_evlist__add_default_attrs(evsel_list, default_attrs1) < 0)
1565 return -1; 1912 return -1;
1566 } 1913 }
1567 1914
@@ -1825,9 +2172,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1825 if (evsel_list == NULL) 2172 if (evsel_list == NULL)
1826 return -ENOMEM; 2173 return -ENOMEM;
1827 2174
2175 parse_events__shrink_config_terms();
1828 argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands, 2176 argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands,
1829 (const char **) stat_usage, 2177 (const char **) stat_usage,
1830 PARSE_OPT_STOP_AT_NON_OPTION); 2178 PARSE_OPT_STOP_AT_NON_OPTION);
2179 perf_stat__init_shadow_stats();
1831 2180
1832 if (csv_sep) { 2181 if (csv_sep) {
1833 csv_output = true; 2182 csv_output = true;
@@ -1858,6 +2207,16 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1858 goto out; 2207 goto out;
1859 } 2208 }
1860 2209
2210 if (metric_only && stat_config.aggr_mode == AGGR_THREAD) {
2211 fprintf(stderr, "--metric-only is not supported with --per-thread\n");
2212 goto out;
2213 }
2214
2215 if (metric_only && run_count > 1) {
2216 fprintf(stderr, "--metric-only is not supported with -r\n");
2217 goto out;
2218 }
2219
1861 if (output_fd < 0) { 2220 if (output_fd < 0) {
1862 fprintf(stderr, "argument to --log-fd must be a > 0\n"); 2221 fprintf(stderr, "argument to --log-fd must be a > 0\n");
1863 parse_options_usage(stat_usage, stat_options, "log-fd", 0); 2222 parse_options_usage(stat_usage, stat_options, "log-fd", 0);