aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-stat.c
diff options
context:
space:
mode:
authorStephane Eranian <eranian@google.com>2013-11-12 11:58:49 -0500
committerIngo Molnar <mingo@kernel.org>2013-11-27 05:16:39 -0500
commit410136f5dd96b6013fe6d1011b523b1c247e1ccb (patch)
treee30c0e866a1879752b570ad3973af5c0ef0e4cdd /tools/perf/builtin-stat.c
parent71ad88efebbcde374bddf904b96f3a7fc82d45d4 (diff)
tools/perf/stat: Add event unit and scale support
This patch adds perf stat support for handling event units and scales as exported by the kernel. The kernel can export PMU events actual unit and scaling factor via sysfs: $ ls -1 /sys/devices/power/events/energy-* /sys/devices/power/events/energy-cores /sys/devices/power/events/energy-cores.scale /sys/devices/power/events/energy-cores.unit /sys/devices/power/events/energy-pkg /sys/devices/power/events/energy-pkg.scale /sys/devices/power/events/energy-pkg.unit $ cat /sys/devices/power/events/energy-cores.scale 2.3283064365386962890625e-10 $ cat cat /sys/devices/power/events/energy-cores.unit Joules This patch modifies the pmu event alias code to check for the presence of the .unit and .scale files to load the corresponding values. They are then used by perf stat transparently: # perf stat -a -e power/energy-pkg/,power/energy-cores/,cycles -I 1000 sleep 1000 # time counts unit events 1.000214717 3.07 Joules power/energy-pkg/ [100.00%] 1.000214717 0.53 Joules power/energy-cores/ 1.000214717 12965028 cycles [100.00%] 2.000749289 3.01 Joules power/energy-pkg/ 2.000749289 0.52 Joules power/energy-cores/ 2.000749289 15817043 cycles When the event does not have an explicit unit exported by the kernel, nothing is printed. In csv output mode, there will be an empty field. Special thanks to Jiri for providing the supporting code in the parser to trigger reading of the scale and unit files. Signed-off-by: Stephane Eranian <eranian@google.com> Reviewed-by: Jiri Olsa <jolsa@redhat.com> Reviewed-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Peter Zijlstra <peterz@infradead.org> Cc: zheng.z.yan@intel.com Cc: bp@alien8.de Cc: maria.n.dimakopoulou@gmail.com Cc: acme@redhat.com Link: http://lkml.kernel.org/r/1384275531-10892-3-git-send-email-eranian@google.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf/builtin-stat.c')
-rw-r--r--tools/perf/builtin-stat.c114
1 files changed, 84 insertions, 30 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index ee0d565f83e3..dab98b50c9fe 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -138,6 +138,7 @@ static const char *post_cmd = NULL;
138static bool sync_run = false; 138static bool sync_run = false;
139static unsigned int interval = 0; 139static unsigned int interval = 0;
140static unsigned int initial_delay = 0; 140static unsigned int initial_delay = 0;
141static unsigned int unit_width = 4; /* strlen("unit") */
141static bool forever = false; 142static bool forever = false;
142static struct timespec ref_time; 143static struct timespec ref_time;
143static struct cpu_map *aggr_map; 144static struct cpu_map *aggr_map;
@@ -461,17 +462,17 @@ static void print_interval(void)
461 if (num_print_interval == 0 && !csv_output) { 462 if (num_print_interval == 0 && !csv_output) {
462 switch (aggr_mode) { 463 switch (aggr_mode) {
463 case AGGR_SOCKET: 464 case AGGR_SOCKET:
464 fprintf(output, "# time socket cpus counts events\n"); 465 fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit");
465 break; 466 break;
466 case AGGR_CORE: 467 case AGGR_CORE:
467 fprintf(output, "# time core cpus counts events\n"); 468 fprintf(output, "# time core cpus counts %*s events\n", unit_width, "unit");
468 break; 469 break;
469 case AGGR_NONE: 470 case AGGR_NONE:
470 fprintf(output, "# time CPU counts events\n"); 471 fprintf(output, "# time CPU counts %*s events\n", unit_width, "unit");
471 break; 472 break;
472 case AGGR_GLOBAL: 473 case AGGR_GLOBAL:
473 default: 474 default:
474 fprintf(output, "# time counts events\n"); 475 fprintf(output, "# time counts %*s events\n", unit_width, "unit");
475 } 476 }
476 } 477 }
477 478
@@ -516,6 +517,7 @@ static int __run_perf_stat(int argc, const char **argv)
516 unsigned long long t0, t1; 517 unsigned long long t0, t1;
517 struct perf_evsel *counter; 518 struct perf_evsel *counter;
518 struct timespec ts; 519 struct timespec ts;
520 size_t l;
519 int status = 0; 521 int status = 0;
520 const bool forks = (argc > 0); 522 const bool forks = (argc > 0);
521 523
@@ -565,6 +567,10 @@ static int __run_perf_stat(int argc, const char **argv)
565 return -1; 567 return -1;
566 } 568 }
567 counter->supported = true; 569 counter->supported = true;
570
571 l = strlen(counter->unit);
572 if (l > unit_width)
573 unit_width = l;
568 } 574 }
569 575
570 if (perf_evlist__apply_filters(evsel_list)) { 576 if (perf_evlist__apply_filters(evsel_list)) {
@@ -704,14 +710,25 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
704static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 710static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
705{ 711{
706 double msecs = avg / 1e6; 712 double msecs = avg / 1e6;
707 const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s"; 713 const char *fmt_v, *fmt_n;
708 char name[25]; 714 char name[25];
709 715
716 fmt_v = csv_output ? "%.6f%s" : "%18.6f%s";
717 fmt_n = csv_output ? "%s" : "%-25s";
718
710 aggr_printout(evsel, cpu, nr); 719 aggr_printout(evsel, cpu, nr);
711 720
712 scnprintf(name, sizeof(name), "%s%s", 721 scnprintf(name, sizeof(name), "%s%s",
713 perf_evsel__name(evsel), csv_output ? "" : " (msec)"); 722 perf_evsel__name(evsel), csv_output ? "" : " (msec)");
714 fprintf(output, fmt, msecs, csv_sep, name); 723
724 fprintf(output, fmt_v, msecs, csv_sep);
725
726 if (csv_output)
727 fprintf(output, "%s%s", evsel->unit, csv_sep);
728 else
729 fprintf(output, "%-*s%s", unit_width, evsel->unit, csv_sep);
730
731 fprintf(output, fmt_n, name);
715 732
716 if (evsel->cgrp) 733 if (evsel->cgrp)
717 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 734 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -908,21 +925,31 @@ static void print_ll_cache_misses(int cpu,
908static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 925static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
909{ 926{
910 double total, ratio = 0.0, total2; 927 double total, ratio = 0.0, total2;
928 double sc = evsel->scale;
911 const char *fmt; 929 const char *fmt;
912 930
913 if (csv_output) 931 if (csv_output) {
914 fmt = "%.0f%s%s"; 932 fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s";
915 else if (big_num) 933 } else {
916 fmt = "%'18.0f%s%-25s"; 934 if (big_num)
917 else 935 fmt = sc != 1.0 ? "%'18.2f%s" : "%'18.0f%s";
918 fmt = "%18.0f%s%-25s"; 936 else
937 fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s";
938 }
919 939
920 aggr_printout(evsel, cpu, nr); 940 aggr_printout(evsel, cpu, nr);
921 941
922 if (aggr_mode == AGGR_GLOBAL) 942 if (aggr_mode == AGGR_GLOBAL)
923 cpu = 0; 943 cpu = 0;
924 944
925 fprintf(output, fmt, avg, csv_sep, perf_evsel__name(evsel)); 945 fprintf(output, fmt, avg, csv_sep);
946
947 if (evsel->unit)
948 fprintf(output, "%-*s%s",
949 csv_output ? 0 : unit_width,
950 evsel->unit, csv_sep);
951
952 fprintf(output, "%-*s", csv_output ? 0 : 25, perf_evsel__name(evsel));
926 953
927 if (evsel->cgrp) 954 if (evsel->cgrp)
928 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 955 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -941,7 +968,10 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
941 968
942 if (total && avg) { 969 if (total && avg) {
943 ratio = total / avg; 970 ratio = total / avg;
944 fprintf(output, "\n # %5.2f stalled cycles per insn", ratio); 971 fprintf(output, "\n");
972 if (aggr_mode == AGGR_NONE)
973 fprintf(output, " ");
974 fprintf(output, " # %5.2f stalled cycles per insn", ratio);
945 } 975 }
946 976
947 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && 977 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
@@ -1061,6 +1091,7 @@ static void print_aggr(char *prefix)
1061{ 1091{
1062 struct perf_evsel *counter; 1092 struct perf_evsel *counter;
1063 int cpu, cpu2, s, s2, id, nr; 1093 int cpu, cpu2, s, s2, id, nr;
1094 double uval;
1064 u64 ena, run, val; 1095 u64 ena, run, val;
1065 1096
1066 if (!(aggr_map || aggr_get_id)) 1097 if (!(aggr_map || aggr_get_id))
@@ -1087,11 +1118,17 @@ static void print_aggr(char *prefix)
1087 if (run == 0 || ena == 0) { 1118 if (run == 0 || ena == 0) {
1088 aggr_printout(counter, id, nr); 1119 aggr_printout(counter, id, nr);
1089 1120
1090 fprintf(output, "%*s%s%*s", 1121 fprintf(output, "%*s%s",
1091 csv_output ? 0 : 18, 1122 csv_output ? 0 : 18,
1092 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 1123 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
1093 csv_sep, 1124 csv_sep);
1094 csv_output ? 0 : -24, 1125
1126 fprintf(output, "%-*s%s",
1127 csv_output ? 0 : unit_width,
1128 counter->unit, csv_sep);
1129
1130 fprintf(output, "%*s",
1131 csv_output ? 0 : -25,
1095 perf_evsel__name(counter)); 1132 perf_evsel__name(counter));
1096 1133
1097 if (counter->cgrp) 1134 if (counter->cgrp)
@@ -1101,11 +1138,12 @@ static void print_aggr(char *prefix)
1101 fputc('\n', output); 1138 fputc('\n', output);
1102 continue; 1139 continue;
1103 } 1140 }
1141 uval = val * counter->scale;
1104 1142
1105 if (nsec_counter(counter)) 1143 if (nsec_counter(counter))
1106 nsec_printout(id, nr, counter, val); 1144 nsec_printout(id, nr, counter, uval);
1107 else 1145 else
1108 abs_printout(id, nr, counter, val); 1146 abs_printout(id, nr, counter, uval);
1109 1147
1110 if (!csv_output) { 1148 if (!csv_output) {
1111 print_noise(counter, 1.0); 1149 print_noise(counter, 1.0);
@@ -1128,16 +1166,21 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
1128 struct perf_stat *ps = counter->priv; 1166 struct perf_stat *ps = counter->priv;
1129 double avg = avg_stats(&ps->res_stats[0]); 1167 double avg = avg_stats(&ps->res_stats[0]);
1130 int scaled = counter->counts->scaled; 1168 int scaled = counter->counts->scaled;
1169 double uval;
1131 1170
1132 if (prefix) 1171 if (prefix)
1133 fprintf(output, "%s", prefix); 1172 fprintf(output, "%s", prefix);
1134 1173
1135 if (scaled == -1) { 1174 if (scaled == -1) {
1136 fprintf(output, "%*s%s%*s", 1175 fprintf(output, "%*s%s",
1137 csv_output ? 0 : 18, 1176 csv_output ? 0 : 18,
1138 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 1177 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
1139 csv_sep, 1178 csv_sep);
1140 csv_output ? 0 : -24, 1179 fprintf(output, "%-*s%s",
1180 csv_output ? 0 : unit_width,
1181 counter->unit, csv_sep);
1182 fprintf(output, "%*s",
1183 csv_output ? 0 : -25,
1141 perf_evsel__name(counter)); 1184 perf_evsel__name(counter));
1142 1185
1143 if (counter->cgrp) 1186 if (counter->cgrp)
@@ -1147,10 +1190,12 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
1147 return; 1190 return;
1148 } 1191 }
1149 1192
1193 uval = avg * counter->scale;
1194
1150 if (nsec_counter(counter)) 1195 if (nsec_counter(counter))
1151 nsec_printout(-1, 0, counter, avg); 1196 nsec_printout(-1, 0, counter, uval);
1152 else 1197 else
1153 abs_printout(-1, 0, counter, avg); 1198 abs_printout(-1, 0, counter, uval);
1154 1199
1155 print_noise(counter, avg); 1200 print_noise(counter, avg);
1156 1201
@@ -1177,6 +1222,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
1177static void print_counter(struct perf_evsel *counter, char *prefix) 1222static void print_counter(struct perf_evsel *counter, char *prefix)
1178{ 1223{
1179 u64 ena, run, val; 1224 u64 ena, run, val;
1225 double uval;
1180 int cpu; 1226 int cpu;
1181 1227
1182 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 1228 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
@@ -1188,14 +1234,20 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
1188 fprintf(output, "%s", prefix); 1234 fprintf(output, "%s", prefix);
1189 1235
1190 if (run == 0 || ena == 0) { 1236 if (run == 0 || ena == 0) {
1191 fprintf(output, "CPU%*d%s%*s%s%*s", 1237 fprintf(output, "CPU%*d%s%*s%s",
1192 csv_output ? 0 : -4, 1238 csv_output ? 0 : -4,
1193 perf_evsel__cpus(counter)->map[cpu], csv_sep, 1239 perf_evsel__cpus(counter)->map[cpu], csv_sep,
1194 csv_output ? 0 : 18, 1240 csv_output ? 0 : 18,
1195 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 1241 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
1196 csv_sep, 1242 csv_sep);
1197 csv_output ? 0 : -24, 1243
1198 perf_evsel__name(counter)); 1244 fprintf(output, "%-*s%s",
1245 csv_output ? 0 : unit_width,
1246 counter->unit, csv_sep);
1247
1248 fprintf(output, "%*s",
1249 csv_output ? 0 : -25,
1250 perf_evsel__name(counter));
1199 1251
1200 if (counter->cgrp) 1252 if (counter->cgrp)
1201 fprintf(output, "%s%s", 1253 fprintf(output, "%s%s",
@@ -1205,10 +1257,12 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
1205 continue; 1257 continue;
1206 } 1258 }
1207 1259
1260 uval = val * counter->scale;
1261
1208 if (nsec_counter(counter)) 1262 if (nsec_counter(counter))
1209 nsec_printout(cpu, 0, counter, val); 1263 nsec_printout(cpu, 0, counter, uval);
1210 else 1264 else
1211 abs_printout(cpu, 0, counter, val); 1265 abs_printout(cpu, 0, counter, uval);
1212 1266
1213 if (!csv_output) { 1267 if (!csv_output) {
1214 print_noise(counter, 1.0); 1268 print_noise(counter, 1.0);