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.c190
1 files changed, 164 insertions, 26 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 13b54999ad79..01b589e3c3a6 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -140,12 +140,14 @@ static unsigned int unit_width = 4; /* strlen("unit") */
140static bool forever = false; 140static bool forever = false;
141static bool metric_only = false; 141static bool metric_only = false;
142static bool force_metric_only = false; 142static bool force_metric_only = false;
143static bool no_merge = false;
143static struct timespec ref_time; 144static struct timespec ref_time;
144static struct cpu_map *aggr_map; 145static struct cpu_map *aggr_map;
145static aggr_get_id_t aggr_get_id; 146static aggr_get_id_t aggr_get_id;
146static bool append_file; 147static bool append_file;
147static const char *output_name; 148static const char *output_name;
148static int output_fd; 149static int output_fd;
150static int print_free_counters_hint;
149 151
150struct perf_stat { 152struct perf_stat {
151 bool record; 153 bool record;
@@ -1109,6 +1111,9 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
1109 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 1111 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
1110 csv_sep); 1112 csv_sep);
1111 1113
1114 if (counter->supported)
1115 print_free_counters_hint = 1;
1116
1112 fprintf(stat_config.output, "%-*s%s", 1117 fprintf(stat_config.output, "%-*s%s",
1113 csv_output ? 0 : unit_width, 1118 csv_output ? 0 : unit_width,
1114 counter->unit, csv_sep); 1119 counter->unit, csv_sep);
@@ -1140,6 +1145,7 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
1140 out.print_metric = pm; 1145 out.print_metric = pm;
1141 out.new_line = nl; 1146 out.new_line = nl;
1142 out.ctx = &os; 1147 out.ctx = &os;
1148 out.force_header = false;
1143 1149
1144 if (csv_output && !metric_only) { 1150 if (csv_output && !metric_only) {
1145 print_noise(counter, noise); 1151 print_noise(counter, noise);
@@ -1178,11 +1184,81 @@ static void aggr_update_shadow(void)
1178 } 1184 }
1179} 1185}
1180 1186
1187static void collect_all_aliases(struct perf_evsel *counter,
1188 void (*cb)(struct perf_evsel *counter, void *data,
1189 bool first),
1190 void *data)
1191{
1192 struct perf_evsel *alias;
1193
1194 alias = list_prepare_entry(counter, &(evsel_list->entries), node);
1195 list_for_each_entry_continue (alias, &evsel_list->entries, node) {
1196 if (strcmp(perf_evsel__name(alias), perf_evsel__name(counter)) ||
1197 alias->scale != counter->scale ||
1198 alias->cgrp != counter->cgrp ||
1199 strcmp(alias->unit, counter->unit) ||
1200 nsec_counter(alias) != nsec_counter(counter))
1201 break;
1202 alias->merged_stat = true;
1203 cb(alias, data, false);
1204 }
1205}
1206
1207static bool collect_data(struct perf_evsel *counter,
1208 void (*cb)(struct perf_evsel *counter, void *data,
1209 bool first),
1210 void *data)
1211{
1212 if (counter->merged_stat)
1213 return false;
1214 cb(counter, data, true);
1215 if (!no_merge)
1216 collect_all_aliases(counter, cb, data);
1217 return true;
1218}
1219
1220struct aggr_data {
1221 u64 ena, run, val;
1222 int id;
1223 int nr;
1224 int cpu;
1225};
1226
1227static void aggr_cb(struct perf_evsel *counter, void *data, bool first)
1228{
1229 struct aggr_data *ad = data;
1230 int cpu, s2;
1231
1232 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
1233 struct perf_counts_values *counts;
1234
1235 s2 = aggr_get_id(perf_evsel__cpus(counter), cpu);
1236 if (s2 != ad->id)
1237 continue;
1238 if (first)
1239 ad->nr++;
1240 counts = perf_counts(counter->counts, cpu, 0);
1241 /*
1242 * When any result is bad, make them all to give
1243 * consistent output in interval mode.
1244 */
1245 if (counts->ena == 0 || counts->run == 0 ||
1246 counter->counts->scaled == -1) {
1247 ad->ena = 0;
1248 ad->run = 0;
1249 break;
1250 }
1251 ad->val += counts->val;
1252 ad->ena += counts->ena;
1253 ad->run += counts->run;
1254 }
1255}
1256
1181static void print_aggr(char *prefix) 1257static void print_aggr(char *prefix)
1182{ 1258{
1183 FILE *output = stat_config.output; 1259 FILE *output = stat_config.output;
1184 struct perf_evsel *counter; 1260 struct perf_evsel *counter;
1185 int cpu, s, s2, id, nr; 1261 int s, id, nr;
1186 double uval; 1262 double uval;
1187 u64 ena, run, val; 1263 u64 ena, run, val;
1188 bool first; 1264 bool first;
@@ -1197,23 +1273,21 @@ static void print_aggr(char *prefix)
1197 * Without each counter has its own line. 1273 * Without each counter has its own line.
1198 */ 1274 */
1199 for (s = 0; s < aggr_map->nr; s++) { 1275 for (s = 0; s < aggr_map->nr; s++) {
1276 struct aggr_data ad;
1200 if (prefix && metric_only) 1277 if (prefix && metric_only)
1201 fprintf(output, "%s", prefix); 1278 fprintf(output, "%s", prefix);
1202 1279
1203 id = aggr_map->map[s]; 1280 ad.id = id = aggr_map->map[s];
1204 first = true; 1281 first = true;
1205 evlist__for_each_entry(evsel_list, counter) { 1282 evlist__for_each_entry(evsel_list, counter) {
1206 val = ena = run = 0; 1283 ad.val = ad.ena = ad.run = 0;
1207 nr = 0; 1284 ad.nr = 0;
1208 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 1285 if (!collect_data(counter, aggr_cb, &ad))
1209 s2 = aggr_get_id(perf_evsel__cpus(counter), cpu); 1286 continue;
1210 if (s2 != id) 1287 nr = ad.nr;
1211 continue; 1288 ena = ad.ena;
1212 val += perf_counts(counter->counts, cpu, 0)->val; 1289 run = ad.run;
1213 ena += perf_counts(counter->counts, cpu, 0)->ena; 1290 val = ad.val;
1214 run += perf_counts(counter->counts, cpu, 0)->run;
1215 nr++;
1216 }
1217 if (first && metric_only) { 1291 if (first && metric_only) {
1218 first = false; 1292 first = false;
1219 aggr_printout(counter, id, nr); 1293 aggr_printout(counter, id, nr);
@@ -1257,6 +1331,21 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
1257 } 1331 }
1258} 1332}
1259 1333
1334struct caggr_data {
1335 double avg, avg_enabled, avg_running;
1336};
1337
1338static void counter_aggr_cb(struct perf_evsel *counter, void *data,
1339 bool first __maybe_unused)
1340{
1341 struct caggr_data *cd = data;
1342 struct perf_stat_evsel *ps = counter->priv;
1343
1344 cd->avg += avg_stats(&ps->res_stats[0]);
1345 cd->avg_enabled += avg_stats(&ps->res_stats[1]);
1346 cd->avg_running += avg_stats(&ps->res_stats[2]);
1347}
1348
1260/* 1349/*
1261 * Print out the results of a single counter: 1350 * Print out the results of a single counter:
1262 * aggregated counts in system-wide mode 1351 * aggregated counts in system-wide mode
@@ -1264,23 +1353,31 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
1264static void print_counter_aggr(struct perf_evsel *counter, char *prefix) 1353static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
1265{ 1354{
1266 FILE *output = stat_config.output; 1355 FILE *output = stat_config.output;
1267 struct perf_stat_evsel *ps = counter->priv;
1268 double avg = avg_stats(&ps->res_stats[0]);
1269 double uval; 1356 double uval;
1270 double avg_enabled, avg_running; 1357 struct caggr_data cd = { .avg = 0.0 };
1271 1358
1272 avg_enabled = avg_stats(&ps->res_stats[1]); 1359 if (!collect_data(counter, counter_aggr_cb, &cd))
1273 avg_running = avg_stats(&ps->res_stats[2]); 1360 return;
1274 1361
1275 if (prefix && !metric_only) 1362 if (prefix && !metric_only)
1276 fprintf(output, "%s", prefix); 1363 fprintf(output, "%s", prefix);
1277 1364
1278 uval = avg * counter->scale; 1365 uval = cd.avg * counter->scale;
1279 printout(-1, 0, counter, uval, prefix, avg_running, avg_enabled, avg); 1366 printout(-1, 0, counter, uval, prefix, cd.avg_running, cd.avg_enabled, cd.avg);
1280 if (!metric_only) 1367 if (!metric_only)
1281 fprintf(output, "\n"); 1368 fprintf(output, "\n");
1282} 1369}
1283 1370
1371static void counter_cb(struct perf_evsel *counter, void *data,
1372 bool first __maybe_unused)
1373{
1374 struct aggr_data *ad = data;
1375
1376 ad->val += perf_counts(counter->counts, ad->cpu, 0)->val;
1377 ad->ena += perf_counts(counter->counts, ad->cpu, 0)->ena;
1378 ad->run += perf_counts(counter->counts, ad->cpu, 0)->run;
1379}
1380
1284/* 1381/*
1285 * Print out the results of a single counter: 1382 * Print out the results of a single counter:
1286 * does not use aggregated count in system-wide 1383 * does not use aggregated count in system-wide
@@ -1293,9 +1390,13 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
1293 int cpu; 1390 int cpu;
1294 1391
1295 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 1392 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
1296 val = perf_counts(counter->counts, cpu, 0)->val; 1393 struct aggr_data ad = { .cpu = cpu };
1297 ena = perf_counts(counter->counts, cpu, 0)->ena; 1394
1298 run = perf_counts(counter->counts, cpu, 0)->run; 1395 if (!collect_data(counter, counter_cb, &ad))
1396 return;
1397 val = ad.val;
1398 ena = ad.ena;
1399 run = ad.run;
1299 1400
1300 if (prefix) 1401 if (prefix)
1301 fprintf(output, "%s", prefix); 1402 fprintf(output, "%s", prefix);
@@ -1380,6 +1481,7 @@ static void print_metric_headers(const char *prefix, bool no_indent)
1380 out.ctx = &os; 1481 out.ctx = &os;
1381 out.print_metric = print_metric_header; 1482 out.print_metric = print_metric_header;
1382 out.new_line = new_line_metric; 1483 out.new_line = new_line_metric;
1484 out.force_header = true;
1383 os.evsel = counter; 1485 os.evsel = counter;
1384 perf_stat__print_shadow_stats(counter, 0, 1486 perf_stat__print_shadow_stats(counter, 0,
1385 0, 1487 0,
@@ -1477,6 +1579,13 @@ static void print_footer(void)
1477 avg_stats(&walltime_nsecs_stats)); 1579 avg_stats(&walltime_nsecs_stats));
1478 } 1580 }
1479 fprintf(output, "\n\n"); 1581 fprintf(output, "\n\n");
1582
1583 if (print_free_counters_hint)
1584 fprintf(output,
1585"Some events weren't counted. Try disabling the NMI watchdog:\n"
1586" echo 0 > /proc/sys/kernel/nmi_watchdog\n"
1587" perf stat ...\n"
1588" echo 1 > /proc/sys/kernel/nmi_watchdog\n");
1480} 1589}
1481 1590
1482static void print_counters(struct timespec *ts, int argc, const char **argv) 1591static void print_counters(struct timespec *ts, int argc, const char **argv)
@@ -1633,6 +1742,7 @@ static const struct option stat_options[] = {
1633 "list of cpus to monitor in system-wide"), 1742 "list of cpus to monitor in system-wide"),
1634 OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode, 1743 OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
1635 "disable CPU count aggregation", AGGR_NONE), 1744 "disable CPU count aggregation", AGGR_NONE),
1745 OPT_BOOLEAN(0, "no-merge", &no_merge, "Do not merge identical named events"),
1636 OPT_STRING('x', "field-separator", &csv_sep, "separator", 1746 OPT_STRING('x', "field-separator", &csv_sep, "separator",
1637 "print counts with custom separator"), 1747 "print counts with custom separator"),
1638 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", 1748 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
@@ -2339,6 +2449,35 @@ static int __cmd_report(int argc, const char **argv)
2339 return 0; 2449 return 0;
2340} 2450}
2341 2451
2452static void setup_system_wide(int forks)
2453{
2454 /*
2455 * Make system wide (-a) the default target if
2456 * no target was specified and one of following
2457 * conditions is met:
2458 *
2459 * - there's no workload specified
2460 * - there is workload specified but all requested
2461 * events are system wide events
2462 */
2463 if (!target__none(&target))
2464 return;
2465
2466 if (!forks)
2467 target.system_wide = true;
2468 else {
2469 struct perf_evsel *counter;
2470
2471 evlist__for_each_entry(evsel_list, counter) {
2472 if (!counter->system_wide)
2473 return;
2474 }
2475
2476 if (evsel_list->nr_entries)
2477 target.system_wide = true;
2478 }
2479}
2480
2342int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) 2481int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
2343{ 2482{
2344 const char * const stat_usage[] = { 2483 const char * const stat_usage[] = {
@@ -2361,6 +2500,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
2361 argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands, 2500 argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands,
2362 (const char **) stat_usage, 2501 (const char **) stat_usage,
2363 PARSE_OPT_STOP_AT_NON_OPTION); 2502 PARSE_OPT_STOP_AT_NON_OPTION);
2503 perf_stat__collect_metric_expr(evsel_list);
2364 perf_stat__init_shadow_stats(); 2504 perf_stat__init_shadow_stats();
2365 2505
2366 if (csv_sep) { 2506 if (csv_sep) {
@@ -2445,9 +2585,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
2445 } else if (big_num_opt == 0) /* User passed --no-big-num */ 2585 } else if (big_num_opt == 0) /* User passed --no-big-num */
2446 big_num = false; 2586 big_num = false;
2447 2587
2448 /* Make system wide (-a) the default target. */ 2588 setup_system_wide(argc);
2449 if (!argc && target__none(&target))
2450 target.system_wide = true;
2451 2589
2452 if (run_count < 0) { 2590 if (run_count < 0) {
2453 pr_err("Run count must be a positive number\n"); 2591 pr_err("Run count must be a positive number\n");