aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-stat.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2017-03-24 14:37:40 -0400
committerIngo Molnar <mingo@kernel.org>2017-03-24 14:37:40 -0400
commite3a6a62400520452fe39740dca90a1d0b94b8f92 (patch)
tree0339ad6ca5de37105e47d4fa0d3b082e091ccbb0 /tools/perf/builtin-stat.c
parent267dd0a07eefbb37264fcfad984fffc8856898ad (diff)
parentbf874fcf9f2fed58510dc83abcee388cee2b427e (diff)
Merge tag 'perf-core-for-mingo-4.12-20170324' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: User visible changes: - Allow suppressing 'uncore_' when specifying PMU events (Andi Kleen) - Collapse identically named PMU events in 'perf stat', allow not merging it via --no-merge (Andi Kleen) Fixes: - Use more precise 'grep -v' to suppress unwanted 'objdump -dS' disassembly output to not ditch line:number lines needed by 'perf annotate --print-lines' logic (Taeung Song) Infrastructure changes: - SDT (Statically Defined Tracing)/uprobes_events arguments improvements (Alexis Berlemont, Ravi Bangoria) - Improvements for the handling of JSON described vendor events, including having an expression parser to calculate metrics from multiple vendor events (Andi Kleen) - Update Intel JSON vendor event files (Andi Kleen) - Restore error reporting in 'perf probe -d' when none of the events requested to be deleted exist. (Kefeng Wang) - Bump MAX_CMDLEN in 'perf probe' to match what the kernel accepts (Ravi Bangoria) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf/builtin-stat.c')
-rw-r--r--tools/perf/builtin-stat.c146
1 files changed, 123 insertions, 23 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index f53f449d864d..01b589e3c3a6 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -140,6 +140,7 @@ 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;
@@ -1144,6 +1145,7 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
1144 out.print_metric = pm; 1145 out.print_metric = pm;
1145 out.new_line = nl; 1146 out.new_line = nl;
1146 out.ctx = &os; 1147 out.ctx = &os;
1148 out.force_header = false;
1147 1149
1148 if (csv_output && !metric_only) { 1150 if (csv_output && !metric_only) {
1149 print_noise(counter, noise); 1151 print_noise(counter, noise);
@@ -1182,11 +1184,81 @@ static void aggr_update_shadow(void)
1182 } 1184 }
1183} 1185}
1184 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
1185static void print_aggr(char *prefix) 1257static void print_aggr(char *prefix)
1186{ 1258{
1187 FILE *output = stat_config.output; 1259 FILE *output = stat_config.output;
1188 struct perf_evsel *counter; 1260 struct perf_evsel *counter;
1189 int cpu, s, s2, id, nr; 1261 int s, id, nr;
1190 double uval; 1262 double uval;
1191 u64 ena, run, val; 1263 u64 ena, run, val;
1192 bool first; 1264 bool first;
@@ -1201,23 +1273,21 @@ static void print_aggr(char *prefix)
1201 * Without each counter has its own line. 1273 * Without each counter has its own line.
1202 */ 1274 */
1203 for (s = 0; s < aggr_map->nr; s++) { 1275 for (s = 0; s < aggr_map->nr; s++) {
1276 struct aggr_data ad;
1204 if (prefix && metric_only) 1277 if (prefix && metric_only)
1205 fprintf(output, "%s", prefix); 1278 fprintf(output, "%s", prefix);
1206 1279
1207 id = aggr_map->map[s]; 1280 ad.id = id = aggr_map->map[s];
1208 first = true; 1281 first = true;
1209 evlist__for_each_entry(evsel_list, counter) { 1282 evlist__for_each_entry(evsel_list, counter) {
1210 val = ena = run = 0; 1283 ad.val = ad.ena = ad.run = 0;
1211 nr = 0; 1284 ad.nr = 0;
1212 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 1285 if (!collect_data(counter, aggr_cb, &ad))
1213 s2 = aggr_get_id(perf_evsel__cpus(counter), cpu); 1286 continue;
1214 if (s2 != id) 1287 nr = ad.nr;
1215 continue; 1288 ena = ad.ena;
1216 val += perf_counts(counter->counts, cpu, 0)->val; 1289 run = ad.run;
1217 ena += perf_counts(counter->counts, cpu, 0)->ena; 1290 val = ad.val;
1218 run += perf_counts(counter->counts, cpu, 0)->run;
1219 nr++;
1220 }
1221 if (first && metric_only) { 1291 if (first && metric_only) {
1222 first = false; 1292 first = false;
1223 aggr_printout(counter, id, nr); 1293 aggr_printout(counter, id, nr);
@@ -1261,6 +1331,21 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
1261 } 1331 }
1262} 1332}
1263 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
1264/* 1349/*
1265 * Print out the results of a single counter: 1350 * Print out the results of a single counter:
1266 * aggregated counts in system-wide mode 1351 * aggregated counts in system-wide mode
@@ -1268,23 +1353,31 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
1268static void print_counter_aggr(struct perf_evsel *counter, char *prefix) 1353static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
1269{ 1354{
1270 FILE *output = stat_config.output; 1355 FILE *output = stat_config.output;
1271 struct perf_stat_evsel *ps = counter->priv;
1272 double avg = avg_stats(&ps->res_stats[0]);
1273 double uval; 1356 double uval;
1274 double avg_enabled, avg_running; 1357 struct caggr_data cd = { .avg = 0.0 };
1275 1358
1276 avg_enabled = avg_stats(&ps->res_stats[1]); 1359 if (!collect_data(counter, counter_aggr_cb, &cd))
1277 avg_running = avg_stats(&ps->res_stats[2]); 1360 return;
1278 1361
1279 if (prefix && !metric_only) 1362 if (prefix && !metric_only)
1280 fprintf(output, "%s", prefix); 1363 fprintf(output, "%s", prefix);
1281 1364
1282 uval = avg * counter->scale; 1365 uval = cd.avg * counter->scale;
1283 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);
1284 if (!metric_only) 1367 if (!metric_only)
1285 fprintf(output, "\n"); 1368 fprintf(output, "\n");
1286} 1369}
1287 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
1288/* 1381/*
1289 * Print out the results of a single counter: 1382 * Print out the results of a single counter:
1290 * does not use aggregated count in system-wide 1383 * does not use aggregated count in system-wide
@@ -1297,9 +1390,13 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
1297 int cpu; 1390 int cpu;
1298 1391
1299 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 1392 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
1300 val = perf_counts(counter->counts, cpu, 0)->val; 1393 struct aggr_data ad = { .cpu = cpu };
1301 ena = perf_counts(counter->counts, cpu, 0)->ena; 1394
1302 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;
1303 1400
1304 if (prefix) 1401 if (prefix)
1305 fprintf(output, "%s", prefix); 1402 fprintf(output, "%s", prefix);
@@ -1384,6 +1481,7 @@ static void print_metric_headers(const char *prefix, bool no_indent)
1384 out.ctx = &os; 1481 out.ctx = &os;
1385 out.print_metric = print_metric_header; 1482 out.print_metric = print_metric_header;
1386 out.new_line = new_line_metric; 1483 out.new_line = new_line_metric;
1484 out.force_header = true;
1387 os.evsel = counter; 1485 os.evsel = counter;
1388 perf_stat__print_shadow_stats(counter, 0, 1486 perf_stat__print_shadow_stats(counter, 0,
1389 0, 1487 0,
@@ -1644,6 +1742,7 @@ static const struct option stat_options[] = {
1644 "list of cpus to monitor in system-wide"), 1742 "list of cpus to monitor in system-wide"),
1645 OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode, 1743 OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
1646 "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"),
1647 OPT_STRING('x', "field-separator", &csv_sep, "separator", 1746 OPT_STRING('x', "field-separator", &csv_sep, "separator",
1648 "print counts with custom separator"), 1747 "print counts with custom separator"),
1649 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", 1748 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
@@ -2401,6 +2500,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
2401 argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands, 2500 argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands,
2402 (const char **) stat_usage, 2501 (const char **) stat_usage,
2403 PARSE_OPT_STOP_AT_NON_OPTION); 2502 PARSE_OPT_STOP_AT_NON_OPTION);
2503 perf_stat__collect_metric_expr(evsel_list);
2404 perf_stat__init_shadow_stats(); 2504 perf_stat__init_shadow_stats();
2405 2505
2406 if (csv_sep) { 2506 if (csv_sep) {