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.c230
1 files changed, 147 insertions, 83 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 59af5a8419e2..98bf9d32f222 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -63,7 +63,6 @@
63#include "util/group.h" 63#include "util/group.h"
64#include "util/session.h" 64#include "util/session.h"
65#include "util/tool.h" 65#include "util/tool.h"
66#include "util/group.h"
67#include "util/string2.h" 66#include "util/string2.h"
68#include "util/metricgroup.h" 67#include "util/metricgroup.h"
69#include "asm/bug.h" 68#include "asm/bug.h"
@@ -214,8 +213,13 @@ static inline void diff_timespec(struct timespec *r, struct timespec *a,
214 213
215static void perf_stat__reset_stats(void) 214static void perf_stat__reset_stats(void)
216{ 215{
216 int i;
217
217 perf_evlist__reset_stats(evsel_list); 218 perf_evlist__reset_stats(evsel_list);
218 perf_stat__reset_shadow_stats(); 219 perf_stat__reset_shadow_stats();
220
221 for (i = 0; i < stat_config.stats_num; i++)
222 perf_stat__reset_shadow_per_stat(&stat_config.stats[i]);
219} 223}
220 224
221static int create_perf_stat_counter(struct perf_evsel *evsel) 225static int create_perf_stat_counter(struct perf_evsel *evsel)
@@ -272,7 +276,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
272 attr->enable_on_exec = 1; 276 attr->enable_on_exec = 1;
273 } 277 }
274 278
275 if (target__has_cpu(&target)) 279 if (target__has_cpu(&target) && !target__has_per_thread(&target))
276 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); 280 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
277 281
278 return perf_evsel__open_per_thread(evsel, evsel_list->threads); 282 return perf_evsel__open_per_thread(evsel, evsel_list->threads);
@@ -335,7 +339,7 @@ static int read_counter(struct perf_evsel *counter)
335 int nthreads = thread_map__nr(evsel_list->threads); 339 int nthreads = thread_map__nr(evsel_list->threads);
336 int ncpus, cpu, thread; 340 int ncpus, cpu, thread;
337 341
338 if (target__has_cpu(&target)) 342 if (target__has_cpu(&target) && !target__has_per_thread(&target))
339 ncpus = perf_evsel__nr_cpus(counter); 343 ncpus = perf_evsel__nr_cpus(counter);
340 else 344 else
341 ncpus = 1; 345 ncpus = 1;
@@ -458,19 +462,8 @@ static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *inf
458 workload_exec_errno = info->si_value.sival_int; 462 workload_exec_errno = info->si_value.sival_int;
459} 463}
460 464
461static bool has_unit(struct perf_evsel *counter)
462{
463 return counter->unit && *counter->unit;
464}
465
466static bool has_scale(struct perf_evsel *counter)
467{
468 return counter->scale != 1;
469}
470
471static int perf_stat_synthesize_config(bool is_pipe) 465static int perf_stat_synthesize_config(bool is_pipe)
472{ 466{
473 struct perf_evsel *counter;
474 int err; 467 int err;
475 468
476 if (is_pipe) { 469 if (is_pipe) {
@@ -482,53 +475,10 @@ static int perf_stat_synthesize_config(bool is_pipe)
482 } 475 }
483 } 476 }
484 477
485 /* 478 err = perf_event__synthesize_extra_attr(NULL,
486 * Synthesize other events stuff not carried within 479 evsel_list,
487 * attr event - unit, scale, name 480 process_synthesized_event,
488 */ 481 is_pipe);
489 evlist__for_each_entry(evsel_list, counter) {
490 if (!counter->supported)
491 continue;
492
493 /*
494 * Synthesize unit and scale only if it's defined.
495 */
496 if (has_unit(counter)) {
497 err = perf_event__synthesize_event_update_unit(NULL, counter, process_synthesized_event);
498 if (err < 0) {
499 pr_err("Couldn't synthesize evsel unit.\n");
500 return err;
501 }
502 }
503
504 if (has_scale(counter)) {
505 err = perf_event__synthesize_event_update_scale(NULL, counter, process_synthesized_event);
506 if (err < 0) {
507 pr_err("Couldn't synthesize evsel scale.\n");
508 return err;
509 }
510 }
511
512 if (counter->own_cpus) {
513 err = perf_event__synthesize_event_update_cpus(NULL, counter, process_synthesized_event);
514 if (err < 0) {
515 pr_err("Couldn't synthesize evsel scale.\n");
516 return err;
517 }
518 }
519
520 /*
521 * Name is needed only for pipe output,
522 * perf.data carries event names.
523 */
524 if (is_pipe) {
525 err = perf_event__synthesize_event_update_name(NULL, counter, process_synthesized_event);
526 if (err < 0) {
527 pr_err("Couldn't synthesize evsel name.\n");
528 return err;
529 }
530 }
531 }
532 482
533 err = perf_event__synthesize_thread_map2(NULL, evsel_list->threads, 483 err = perf_event__synthesize_thread_map2(NULL, evsel_list->threads,
534 process_synthesized_event, 484 process_synthesized_event,
@@ -1151,7 +1101,8 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
1151} 1101}
1152 1102
1153static void printout(int id, int nr, struct perf_evsel *counter, double uval, 1103static void printout(int id, int nr, struct perf_evsel *counter, double uval,
1154 char *prefix, u64 run, u64 ena, double noise) 1104 char *prefix, u64 run, u64 ena, double noise,
1105 struct runtime_stat *st)
1155{ 1106{
1156 struct perf_stat_output_ctx out; 1107 struct perf_stat_output_ctx out;
1157 struct outstate os = { 1108 struct outstate os = {
@@ -1244,7 +1195,7 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval,
1244 1195
1245 perf_stat__print_shadow_stats(counter, uval, 1196 perf_stat__print_shadow_stats(counter, uval,
1246 first_shadow_cpu(counter, id), 1197 first_shadow_cpu(counter, id),
1247 &out, &metric_events); 1198 &out, &metric_events, st);
1248 if (!csv_output && !metric_only) { 1199 if (!csv_output && !metric_only) {
1249 print_noise(counter, noise); 1200 print_noise(counter, noise);
1250 print_running(run, ena); 1201 print_running(run, ena);
@@ -1268,7 +1219,8 @@ static void aggr_update_shadow(void)
1268 val += perf_counts(counter->counts, cpu, 0)->val; 1219 val += perf_counts(counter->counts, cpu, 0)->val;
1269 } 1220 }
1270 perf_stat__update_shadow_stats(counter, val, 1221 perf_stat__update_shadow_stats(counter, val,
1271 first_shadow_cpu(counter, id)); 1222 first_shadow_cpu(counter, id),
1223 &rt_stat);
1272 } 1224 }
1273 } 1225 }
1274} 1226}
@@ -1388,7 +1340,8 @@ static void print_aggr(char *prefix)
1388 fprintf(output, "%s", prefix); 1340 fprintf(output, "%s", prefix);
1389 1341
1390 uval = val * counter->scale; 1342 uval = val * counter->scale;
1391 printout(id, nr, counter, uval, prefix, run, ena, 1.0); 1343 printout(id, nr, counter, uval, prefix, run, ena, 1.0,
1344 &rt_stat);
1392 if (!metric_only) 1345 if (!metric_only)
1393 fputc('\n', output); 1346 fputc('\n', output);
1394 } 1347 }
@@ -1397,13 +1350,24 @@ static void print_aggr(char *prefix)
1397 } 1350 }
1398} 1351}
1399 1352
1400static void print_aggr_thread(struct perf_evsel *counter, char *prefix) 1353static int cmp_val(const void *a, const void *b)
1401{ 1354{
1402 FILE *output = stat_config.output; 1355 return ((struct perf_aggr_thread_value *)b)->val -
1403 int nthreads = thread_map__nr(counter->threads); 1356 ((struct perf_aggr_thread_value *)a)->val;
1404 int ncpus = cpu_map__nr(counter->cpus); 1357}
1405 int cpu, thread; 1358
1359static struct perf_aggr_thread_value *sort_aggr_thread(
1360 struct perf_evsel *counter,
1361 int nthreads, int ncpus,
1362 int *ret)
1363{
1364 int cpu, thread, i = 0;
1406 double uval; 1365 double uval;
1366 struct perf_aggr_thread_value *buf;
1367
1368 buf = calloc(nthreads, sizeof(struct perf_aggr_thread_value));
1369 if (!buf)
1370 return NULL;
1407 1371
1408 for (thread = 0; thread < nthreads; thread++) { 1372 for (thread = 0; thread < nthreads; thread++) {
1409 u64 ena = 0, run = 0, val = 0; 1373 u64 ena = 0, run = 0, val = 0;
@@ -1414,13 +1378,63 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
1414 run += perf_counts(counter->counts, cpu, thread)->run; 1378 run += perf_counts(counter->counts, cpu, thread)->run;
1415 } 1379 }
1416 1380
1381 uval = val * counter->scale;
1382
1383 /*
1384 * Skip value 0 when enabling --per-thread globally,
1385 * otherwise too many 0 output.
1386 */
1387 if (uval == 0.0 && target__has_per_thread(&target))
1388 continue;
1389
1390 buf[i].counter = counter;
1391 buf[i].id = thread;
1392 buf[i].uval = uval;
1393 buf[i].val = val;
1394 buf[i].run = run;
1395 buf[i].ena = ena;
1396 i++;
1397 }
1398
1399 qsort(buf, i, sizeof(struct perf_aggr_thread_value), cmp_val);
1400
1401 if (ret)
1402 *ret = i;
1403
1404 return buf;
1405}
1406
1407static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
1408{
1409 FILE *output = stat_config.output;
1410 int nthreads = thread_map__nr(counter->threads);
1411 int ncpus = cpu_map__nr(counter->cpus);
1412 int thread, sorted_threads, id;
1413 struct perf_aggr_thread_value *buf;
1414
1415 buf = sort_aggr_thread(counter, nthreads, ncpus, &sorted_threads);
1416 if (!buf) {
1417 perror("cannot sort aggr thread");
1418 return;
1419 }
1420
1421 for (thread = 0; thread < sorted_threads; thread++) {
1417 if (prefix) 1422 if (prefix)
1418 fprintf(output, "%s", prefix); 1423 fprintf(output, "%s", prefix);
1419 1424
1420 uval = val * counter->scale; 1425 id = buf[thread].id;
1421 printout(thread, 0, counter, uval, prefix, run, ena, 1.0); 1426 if (stat_config.stats)
1427 printout(id, 0, buf[thread].counter, buf[thread].uval,
1428 prefix, buf[thread].run, buf[thread].ena, 1.0,
1429 &stat_config.stats[id]);
1430 else
1431 printout(id, 0, buf[thread].counter, buf[thread].uval,
1432 prefix, buf[thread].run, buf[thread].ena, 1.0,
1433 &rt_stat);
1422 fputc('\n', output); 1434 fputc('\n', output);
1423 } 1435 }
1436
1437 free(buf);
1424} 1438}
1425 1439
1426struct caggr_data { 1440struct caggr_data {
@@ -1455,7 +1469,8 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
1455 fprintf(output, "%s", prefix); 1469 fprintf(output, "%s", prefix);
1456 1470
1457 uval = cd.avg * counter->scale; 1471 uval = cd.avg * counter->scale;
1458 printout(-1, 0, counter, uval, prefix, cd.avg_running, cd.avg_enabled, cd.avg); 1472 printout(-1, 0, counter, uval, prefix, cd.avg_running, cd.avg_enabled,
1473 cd.avg, &rt_stat);
1459 if (!metric_only) 1474 if (!metric_only)
1460 fprintf(output, "\n"); 1475 fprintf(output, "\n");
1461} 1476}
@@ -1494,7 +1509,8 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
1494 fprintf(output, "%s", prefix); 1509 fprintf(output, "%s", prefix);
1495 1510
1496 uval = val * counter->scale; 1511 uval = val * counter->scale;
1497 printout(cpu, 0, counter, uval, prefix, run, ena, 1.0); 1512 printout(cpu, 0, counter, uval, prefix, run, ena, 1.0,
1513 &rt_stat);
1498 1514
1499 fputc('\n', output); 1515 fputc('\n', output);
1500 } 1516 }
@@ -1526,7 +1542,8 @@ static void print_no_aggr_metric(char *prefix)
1526 run = perf_counts(counter->counts, cpu, 0)->run; 1542 run = perf_counts(counter->counts, cpu, 0)->run;
1527 1543
1528 uval = val * counter->scale; 1544 uval = val * counter->scale;
1529 printout(cpu, 0, counter, uval, prefix, run, ena, 1.0); 1545 printout(cpu, 0, counter, uval, prefix, run, ena, 1.0,
1546 &rt_stat);
1530 } 1547 }
1531 fputc('\n', stat_config.output); 1548 fputc('\n', stat_config.output);
1532 } 1549 }
@@ -1582,7 +1599,8 @@ static void print_metric_headers(const char *prefix, bool no_indent)
1582 perf_stat__print_shadow_stats(counter, 0, 1599 perf_stat__print_shadow_stats(counter, 0,
1583 0, 1600 0,
1584 &out, 1601 &out,
1585 &metric_events); 1602 &metric_events,
1603 &rt_stat);
1586 } 1604 }
1587 fputc('\n', stat_config.output); 1605 fputc('\n', stat_config.output);
1588} 1606}
@@ -2541,6 +2559,35 @@ int process_cpu_map_event(struct perf_tool *tool,
2541 return set_maps(st); 2559 return set_maps(st);
2542} 2560}
2543 2561
2562static int runtime_stat_new(struct perf_stat_config *config, int nthreads)
2563{
2564 int i;
2565
2566 config->stats = calloc(nthreads, sizeof(struct runtime_stat));
2567 if (!config->stats)
2568 return -1;
2569
2570 config->stats_num = nthreads;
2571
2572 for (i = 0; i < nthreads; i++)
2573 runtime_stat__init(&config->stats[i]);
2574
2575 return 0;
2576}
2577
2578static void runtime_stat_delete(struct perf_stat_config *config)
2579{
2580 int i;
2581
2582 if (!config->stats)
2583 return;
2584
2585 for (i = 0; i < config->stats_num; i++)
2586 runtime_stat__exit(&config->stats[i]);
2587
2588 free(config->stats);
2589}
2590
2544static const char * const stat_report_usage[] = { 2591static const char * const stat_report_usage[] = {
2545 "perf stat report [<options>]", 2592 "perf stat report [<options>]",
2546 NULL, 2593 NULL,
@@ -2750,12 +2797,16 @@ int cmd_stat(int argc, const char **argv)
2750 run_count = 1; 2797 run_count = 1;
2751 } 2798 }
2752 2799
2753 if ((stat_config.aggr_mode == AGGR_THREAD) && !target__has_task(&target)) { 2800 if ((stat_config.aggr_mode == AGGR_THREAD) &&
2754 fprintf(stderr, "The --per-thread option is only available " 2801 !target__has_task(&target)) {
2755 "when monitoring via -p -t options.\n"); 2802 if (!target.system_wide || target.cpu_list) {
2756 parse_options_usage(NULL, stat_options, "p", 1); 2803 fprintf(stderr, "The --per-thread option is only "
2757 parse_options_usage(NULL, stat_options, "t", 1); 2804 "available when monitoring via -p -t -a "
2758 goto out; 2805 "options or only --per-thread.\n");
2806 parse_options_usage(NULL, stat_options, "p", 1);
2807 parse_options_usage(NULL, stat_options, "t", 1);
2808 goto out;
2809 }
2759 } 2810 }
2760 2811
2761 /* 2812 /*
@@ -2779,6 +2830,9 @@ int cmd_stat(int argc, const char **argv)
2779 2830
2780 target__validate(&target); 2831 target__validate(&target);
2781 2832
2833 if ((stat_config.aggr_mode == AGGR_THREAD) && (target.system_wide))
2834 target.per_thread = true;
2835
2782 if (perf_evlist__create_maps(evsel_list, &target) < 0) { 2836 if (perf_evlist__create_maps(evsel_list, &target) < 0) {
2783 if (target__has_task(&target)) { 2837 if (target__has_task(&target)) {
2784 pr_err("Problems finding threads of monitor\n"); 2838 pr_err("Problems finding threads of monitor\n");
@@ -2796,8 +2850,15 @@ int cmd_stat(int argc, const char **argv)
2796 * Initialize thread_map with comm names, 2850 * Initialize thread_map with comm names,
2797 * so we could print it out on output. 2851 * so we could print it out on output.
2798 */ 2852 */
2799 if (stat_config.aggr_mode == AGGR_THREAD) 2853 if (stat_config.aggr_mode == AGGR_THREAD) {
2800 thread_map__read_comms(evsel_list->threads); 2854 thread_map__read_comms(evsel_list->threads);
2855 if (target.system_wide) {
2856 if (runtime_stat_new(&stat_config,
2857 thread_map__nr(evsel_list->threads))) {
2858 goto out;
2859 }
2860 }
2861 }
2801 2862
2802 if (interval && interval < 100) { 2863 if (interval && interval < 100) {
2803 if (interval < 10) { 2864 if (interval < 10) {
@@ -2887,5 +2948,8 @@ out:
2887 sysfs__write_int(FREEZE_ON_SMI_PATH, 0); 2948 sysfs__write_int(FREEZE_ON_SMI_PATH, 0);
2888 2949
2889 perf_evlist__delete(evsel_list); 2950 perf_evlist__delete(evsel_list);
2951
2952 runtime_stat_delete(&stat_config);
2953
2890 return status; 2954 return status;
2891} 2955}