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.c224
1 files changed, 192 insertions, 32 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 5098f144b92d..ee0d565f83e3 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -46,6 +46,7 @@
46#include "util/util.h" 46#include "util/util.h"
47#include "util/parse-options.h" 47#include "util/parse-options.h"
48#include "util/parse-events.h" 48#include "util/parse-events.h"
49#include "util/pmu.h"
49#include "util/event.h" 50#include "util/event.h"
50#include "util/evlist.h" 51#include "util/evlist.h"
51#include "util/evsel.h" 52#include "util/evsel.h"
@@ -70,9 +71,44 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix);
70static void print_counter(struct perf_evsel *counter, char *prefix); 71static void print_counter(struct perf_evsel *counter, char *prefix);
71static void print_aggr(char *prefix); 72static void print_aggr(char *prefix);
72 73
74/* Default events used for perf stat -T */
75static const char * const transaction_attrs[] = {
76 "task-clock",
77 "{"
78 "instructions,"
79 "cycles,"
80 "cpu/cycles-t/,"
81 "cpu/tx-start/,"
82 "cpu/el-start/,"
83 "cpu/cycles-ct/"
84 "}"
85};
86
87/* More limited version when the CPU does not have all events. */
88static const char * const transaction_limited_attrs[] = {
89 "task-clock",
90 "{"
91 "instructions,"
92 "cycles,"
93 "cpu/cycles-t/,"
94 "cpu/tx-start/"
95 "}"
96};
97
98/* must match transaction_attrs and the beginning limited_attrs */
99enum {
100 T_TASK_CLOCK,
101 T_INSTRUCTIONS,
102 T_CYCLES,
103 T_CYCLES_IN_TX,
104 T_TRANSACTION_START,
105 T_ELISION_START,
106 T_CYCLES_IN_TX_CP,
107};
108
73static struct perf_evlist *evsel_list; 109static struct perf_evlist *evsel_list;
74 110
75static struct perf_target target = { 111static struct target target = {
76 .uid = UINT_MAX, 112 .uid = UINT_MAX,
77}; 113};
78 114
@@ -90,6 +126,7 @@ static enum aggr_mode aggr_mode = AGGR_GLOBAL;
90static volatile pid_t child_pid = -1; 126static volatile pid_t child_pid = -1;
91static bool null_run = false; 127static bool null_run = false;
92static int detailed_run = 0; 128static int detailed_run = 0;
129static bool transaction_run;
93static bool big_num = true; 130static bool big_num = true;
94static int big_num_opt = -1; 131static int big_num_opt = -1;
95static const char *csv_sep = NULL; 132static const char *csv_sep = NULL;
@@ -214,7 +251,10 @@ static struct stats runtime_l1_icache_stats[MAX_NR_CPUS];
214static struct stats runtime_ll_cache_stats[MAX_NR_CPUS]; 251static struct stats runtime_ll_cache_stats[MAX_NR_CPUS];
215static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS]; 252static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
216static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; 253static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
254static struct stats runtime_cycles_in_tx_stats[MAX_NR_CPUS];
217static struct stats walltime_nsecs_stats; 255static struct stats walltime_nsecs_stats;
256static struct stats runtime_transaction_stats[MAX_NR_CPUS];
257static struct stats runtime_elision_stats[MAX_NR_CPUS];
218 258
219static void perf_stat__reset_stats(struct perf_evlist *evlist) 259static void perf_stat__reset_stats(struct perf_evlist *evlist)
220{ 260{
@@ -236,6 +276,11 @@ static void perf_stat__reset_stats(struct perf_evlist *evlist)
236 memset(runtime_ll_cache_stats, 0, sizeof(runtime_ll_cache_stats)); 276 memset(runtime_ll_cache_stats, 0, sizeof(runtime_ll_cache_stats));
237 memset(runtime_itlb_cache_stats, 0, sizeof(runtime_itlb_cache_stats)); 277 memset(runtime_itlb_cache_stats, 0, sizeof(runtime_itlb_cache_stats));
238 memset(runtime_dtlb_cache_stats, 0, sizeof(runtime_dtlb_cache_stats)); 278 memset(runtime_dtlb_cache_stats, 0, sizeof(runtime_dtlb_cache_stats));
279 memset(runtime_cycles_in_tx_stats, 0,
280 sizeof(runtime_cycles_in_tx_stats));
281 memset(runtime_transaction_stats, 0,
282 sizeof(runtime_transaction_stats));
283 memset(runtime_elision_stats, 0, sizeof(runtime_elision_stats));
239 memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats)); 284 memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats));
240} 285}
241 286
@@ -249,11 +294,10 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
249 294
250 attr->inherit = !no_inherit; 295 attr->inherit = !no_inherit;
251 296
252 if (perf_target__has_cpu(&target)) 297 if (target__has_cpu(&target))
253 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); 298 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
254 299
255 if (!perf_target__has_task(&target) && 300 if (!target__has_task(&target) && perf_evsel__is_group_leader(evsel)) {
256 perf_evsel__is_group_leader(evsel)) {
257 attr->disabled = 1; 301 attr->disabled = 1;
258 if (!initial_delay) 302 if (!initial_delay)
259 attr->enable_on_exec = 1; 303 attr->enable_on_exec = 1;
@@ -274,6 +318,29 @@ static inline int nsec_counter(struct perf_evsel *evsel)
274 return 0; 318 return 0;
275} 319}
276 320
321static struct perf_evsel *nth_evsel(int n)
322{
323 static struct perf_evsel **array;
324 static int array_len;
325 struct perf_evsel *ev;
326 int j;
327
328 /* Assumes this only called when evsel_list does not change anymore. */
329 if (!array) {
330 list_for_each_entry(ev, &evsel_list->entries, node)
331 array_len++;
332 array = malloc(array_len * sizeof(void *));
333 if (!array)
334 exit(ENOMEM);
335 j = 0;
336 list_for_each_entry(ev, &evsel_list->entries, node)
337 array[j++] = ev;
338 }
339 if (n < array_len)
340 return array[n];
341 return NULL;
342}
343
277/* 344/*
278 * Update various tracking values we maintain to print 345 * Update various tracking values we maintain to print
279 * more semantic information such as miss/hit ratios, 346 * more semantic information such as miss/hit ratios,
@@ -285,6 +352,15 @@ static void update_shadow_stats(struct perf_evsel *counter, u64 *count)
285 update_stats(&runtime_nsecs_stats[0], count[0]); 352 update_stats(&runtime_nsecs_stats[0], count[0]);
286 else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES)) 353 else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
287 update_stats(&runtime_cycles_stats[0], count[0]); 354 update_stats(&runtime_cycles_stats[0], count[0]);
355 else if (transaction_run &&
356 perf_evsel__cmp(counter, nth_evsel(T_CYCLES_IN_TX)))
357 update_stats(&runtime_cycles_in_tx_stats[0], count[0]);
358 else if (transaction_run &&
359 perf_evsel__cmp(counter, nth_evsel(T_TRANSACTION_START)))
360 update_stats(&runtime_transaction_stats[0], count[0]);
361 else if (transaction_run &&
362 perf_evsel__cmp(counter, nth_evsel(T_ELISION_START)))
363 update_stats(&runtime_elision_stats[0], count[0]);
288 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) 364 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND))
289 update_stats(&runtime_stalled_cycles_front_stats[0], count[0]); 365 update_stats(&runtime_stalled_cycles_front_stats[0], count[0]);
290 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND)) 366 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND))
@@ -629,10 +705,13 @@ static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
629{ 705{
630 double msecs = avg / 1e6; 706 double msecs = avg / 1e6;
631 const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s"; 707 const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s";
708 char name[25];
632 709
633 aggr_printout(evsel, cpu, nr); 710 aggr_printout(evsel, cpu, nr);
634 711
635 fprintf(output, fmt, msecs, csv_sep, perf_evsel__name(evsel)); 712 scnprintf(name, sizeof(name), "%s%s",
713 perf_evsel__name(evsel), csv_output ? "" : " (msec)");
714 fprintf(output, fmt, msecs, csv_sep, name);
636 715
637 if (evsel->cgrp) 716 if (evsel->cgrp)
638 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 717 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -828,7 +907,7 @@ static void print_ll_cache_misses(int cpu,
828 907
829static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 908static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
830{ 909{
831 double total, ratio = 0.0; 910 double total, ratio = 0.0, total2;
832 const char *fmt; 911 const char *fmt;
833 912
834 if (csv_output) 913 if (csv_output)
@@ -853,11 +932,10 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
853 932
854 if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) { 933 if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
855 total = avg_stats(&runtime_cycles_stats[cpu]); 934 total = avg_stats(&runtime_cycles_stats[cpu]);
856 if (total) 935 if (total) {
857 ratio = avg / total; 936 ratio = avg / total;
858 937 fprintf(output, " # %5.2f insns per cycle ", ratio);
859 fprintf(output, " # %5.2f insns per cycle ", ratio); 938 }
860
861 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]); 939 total = avg_stats(&runtime_stalled_cycles_front_stats[cpu]);
862 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu])); 940 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[cpu]));
863 941
@@ -920,10 +998,47 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
920 } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) { 998 } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) {
921 total = avg_stats(&runtime_nsecs_stats[cpu]); 999 total = avg_stats(&runtime_nsecs_stats[cpu]);
922 1000
1001 if (total) {
1002 ratio = avg / total;
1003 fprintf(output, " # %8.3f GHz ", ratio);
1004 }
1005 } else if (transaction_run &&
1006 perf_evsel__cmp(evsel, nth_evsel(T_CYCLES_IN_TX))) {
1007 total = avg_stats(&runtime_cycles_stats[cpu]);
1008 if (total)
1009 fprintf(output,
1010 " # %5.2f%% transactional cycles ",
1011 100.0 * (avg / total));
1012 } else if (transaction_run &&
1013 perf_evsel__cmp(evsel, nth_evsel(T_CYCLES_IN_TX_CP))) {
1014 total = avg_stats(&runtime_cycles_stats[cpu]);
1015 total2 = avg_stats(&runtime_cycles_in_tx_stats[cpu]);
1016 if (total2 < avg)
1017 total2 = avg;
1018 if (total)
1019 fprintf(output,
1020 " # %5.2f%% aborted cycles ",
1021 100.0 * ((total2-avg) / total));
1022 } else if (transaction_run &&
1023 perf_evsel__cmp(evsel, nth_evsel(T_TRANSACTION_START)) &&
1024 avg > 0 &&
1025 runtime_cycles_in_tx_stats[cpu].n != 0) {
1026 total = avg_stats(&runtime_cycles_in_tx_stats[cpu]);
1027
923 if (total) 1028 if (total)
924 ratio = 1.0 * avg / total; 1029 ratio = total / avg;
925 1030
926 fprintf(output, " # %8.3f GHz ", ratio); 1031 fprintf(output, " # %8.0f cycles / transaction ", ratio);
1032 } else if (transaction_run &&
1033 perf_evsel__cmp(evsel, nth_evsel(T_ELISION_START)) &&
1034 avg > 0 &&
1035 runtime_cycles_in_tx_stats[cpu].n != 0) {
1036 total = avg_stats(&runtime_cycles_in_tx_stats[cpu]);
1037
1038 if (total)
1039 ratio = total / avg;
1040
1041 fprintf(output, " # %8.0f cycles / elision ", ratio);
927 } else if (runtime_nsecs_stats[cpu].n != 0) { 1042 } else if (runtime_nsecs_stats[cpu].n != 0) {
928 char unit = 'M'; 1043 char unit = 'M';
929 1044
@@ -1116,7 +1231,11 @@ static void print_stat(int argc, const char **argv)
1116 if (!csv_output) { 1231 if (!csv_output) {
1117 fprintf(output, "\n"); 1232 fprintf(output, "\n");
1118 fprintf(output, " Performance counter stats for "); 1233 fprintf(output, " Performance counter stats for ");
1119 if (!perf_target__has_task(&target)) { 1234 if (target.system_wide)
1235 fprintf(output, "\'system wide");
1236 else if (target.cpu_list)
1237 fprintf(output, "\'CPU(s) %s", target.cpu_list);
1238 else if (!target__has_task(&target)) {
1120 fprintf(output, "\'%s", argv[0]); 1239 fprintf(output, "\'%s", argv[0]);
1121 for (i = 1; i < argc; i++) 1240 for (i = 1; i < argc; i++)
1122 fprintf(output, " %s", argv[i]); 1241 fprintf(output, " %s", argv[i]);
@@ -1237,6 +1356,16 @@ static int perf_stat_init_aggr_mode(void)
1237 return 0; 1356 return 0;
1238} 1357}
1239 1358
1359static int setup_events(const char * const *attrs, unsigned len)
1360{
1361 unsigned i;
1362
1363 for (i = 0; i < len; i++) {
1364 if (parse_events(evsel_list, attrs[i]))
1365 return -1;
1366 }
1367 return 0;
1368}
1240 1369
1241/* 1370/*
1242 * Add default attributes, if there were no attributes specified or 1371 * Add default attributes, if there were no attributes specified or
@@ -1355,6 +1484,22 @@ static int add_default_attributes(void)
1355 if (null_run) 1484 if (null_run)
1356 return 0; 1485 return 0;
1357 1486
1487 if (transaction_run) {
1488 int err;
1489 if (pmu_have_event("cpu", "cycles-ct") &&
1490 pmu_have_event("cpu", "el-start"))
1491 err = setup_events(transaction_attrs,
1492 ARRAY_SIZE(transaction_attrs));
1493 else
1494 err = setup_events(transaction_limited_attrs,
1495 ARRAY_SIZE(transaction_limited_attrs));
1496 if (err < 0) {
1497 fprintf(stderr, "Cannot set up transaction events\n");
1498 return -1;
1499 }
1500 return 0;
1501 }
1502
1358 if (!evsel_list->nr_entries) { 1503 if (!evsel_list->nr_entries) {
1359 if (perf_evlist__add_default_attrs(evsel_list, default_attrs) < 0) 1504 if (perf_evlist__add_default_attrs(evsel_list, default_attrs) < 0)
1360 return -1; 1505 return -1;
@@ -1389,6 +1534,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1389 int output_fd = 0; 1534 int output_fd = 0;
1390 const char *output_name = NULL; 1535 const char *output_name = NULL;
1391 const struct option options[] = { 1536 const struct option options[] = {
1537 OPT_BOOLEAN('T', "transaction", &transaction_run,
1538 "hardware transaction statistics"),
1392 OPT_CALLBACK('e', "event", &evsel_list, "event", 1539 OPT_CALLBACK('e', "event", &evsel_list, "event",
1393 "event selector. use 'perf list' to list available events", 1540 "event selector. use 'perf list' to list available events",
1394 parse_events_option), 1541 parse_events_option),
@@ -1448,7 +1595,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1448 "perf stat [<options>] [<command>]", 1595 "perf stat [<options>] [<command>]",
1449 NULL 1596 NULL
1450 }; 1597 };
1451 int status = -ENOMEM, run_idx; 1598 int status = -EINVAL, run_idx;
1452 const char *mode; 1599 const char *mode;
1453 1600
1454 setlocale(LC_ALL, ""); 1601 setlocale(LC_ALL, "");
@@ -1466,12 +1613,15 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1466 1613
1467 if (output_name && output_fd) { 1614 if (output_name && output_fd) {
1468 fprintf(stderr, "cannot use both --output and --log-fd\n"); 1615 fprintf(stderr, "cannot use both --output and --log-fd\n");
1469 usage_with_options(stat_usage, options); 1616 parse_options_usage(stat_usage, options, "o", 1);
1617 parse_options_usage(NULL, options, "log-fd", 0);
1618 goto out;
1470 } 1619 }
1471 1620
1472 if (output_fd < 0) { 1621 if (output_fd < 0) {
1473 fprintf(stderr, "argument to --log-fd must be a > 0\n"); 1622 fprintf(stderr, "argument to --log-fd must be a > 0\n");
1474 usage_with_options(stat_usage, options); 1623 parse_options_usage(stat_usage, options, "log-fd", 0);
1624 goto out;
1475 } 1625 }
1476 1626
1477 if (!output) { 1627 if (!output) {
@@ -1508,56 +1658,66 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1508 /* User explicitly passed -B? */ 1658 /* User explicitly passed -B? */
1509 if (big_num_opt == 1) { 1659 if (big_num_opt == 1) {
1510 fprintf(stderr, "-B option not supported with -x\n"); 1660 fprintf(stderr, "-B option not supported with -x\n");
1511 usage_with_options(stat_usage, options); 1661 parse_options_usage(stat_usage, options, "B", 1);
1662 parse_options_usage(NULL, options, "x", 1);
1663 goto out;
1512 } else /* Nope, so disable big number formatting */ 1664 } else /* Nope, so disable big number formatting */
1513 big_num = false; 1665 big_num = false;
1514 } else if (big_num_opt == 0) /* User passed --no-big-num */ 1666 } else if (big_num_opt == 0) /* User passed --no-big-num */
1515 big_num = false; 1667 big_num = false;
1516 1668
1517 if (!argc && !perf_target__has_task(&target)) 1669 if (!argc && target__none(&target))
1518 usage_with_options(stat_usage, options); 1670 usage_with_options(stat_usage, options);
1671
1519 if (run_count < 0) { 1672 if (run_count < 0) {
1520 usage_with_options(stat_usage, options); 1673 pr_err("Run count must be a positive number\n");
1674 parse_options_usage(stat_usage, options, "r", 1);
1675 goto out;
1521 } else if (run_count == 0) { 1676 } else if (run_count == 0) {
1522 forever = true; 1677 forever = true;
1523 run_count = 1; 1678 run_count = 1;
1524 } 1679 }
1525 1680
1526 /* no_aggr, cgroup are for system-wide only */ 1681 /* no_aggr, cgroup are for system-wide only */
1527 if ((aggr_mode != AGGR_GLOBAL || nr_cgroups) 1682 if ((aggr_mode != AGGR_GLOBAL || nr_cgroups) &&
1528 && !perf_target__has_cpu(&target)) { 1683 !target__has_cpu(&target)) {
1529 fprintf(stderr, "both cgroup and no-aggregation " 1684 fprintf(stderr, "both cgroup and no-aggregation "
1530 "modes only available in system-wide mode\n"); 1685 "modes only available in system-wide mode\n");
1531 1686
1532 usage_with_options(stat_usage, options); 1687 parse_options_usage(stat_usage, options, "G", 1);
1533 return -1; 1688 parse_options_usage(NULL, options, "A", 1);
1689 parse_options_usage(NULL, options, "a", 1);
1690 goto out;
1534 } 1691 }
1535 1692
1536 if (add_default_attributes()) 1693 if (add_default_attributes())
1537 goto out; 1694 goto out;
1538 1695
1539 perf_target__validate(&target); 1696 target__validate(&target);
1540 1697
1541 if (perf_evlist__create_maps(evsel_list, &target) < 0) { 1698 if (perf_evlist__create_maps(evsel_list, &target) < 0) {
1542 if (perf_target__has_task(&target)) 1699 if (target__has_task(&target)) {
1543 pr_err("Problems finding threads of monitor\n"); 1700 pr_err("Problems finding threads of monitor\n");
1544 if (perf_target__has_cpu(&target)) 1701 parse_options_usage(stat_usage, options, "p", 1);
1702 parse_options_usage(NULL, options, "t", 1);
1703 } else if (target__has_cpu(&target)) {
1545 perror("failed to parse CPUs map"); 1704 perror("failed to parse CPUs map");
1546 1705 parse_options_usage(stat_usage, options, "C", 1);
1547 usage_with_options(stat_usage, options); 1706 parse_options_usage(NULL, options, "a", 1);
1548 return -1; 1707 }
1708 goto out;
1549 } 1709 }
1550 if (interval && interval < 100) { 1710 if (interval && interval < 100) {
1551 pr_err("print interval must be >= 100ms\n"); 1711 pr_err("print interval must be >= 100ms\n");
1552 usage_with_options(stat_usage, options); 1712 parse_options_usage(stat_usage, options, "I", 1);
1553 return -1; 1713 goto out_free_maps;
1554 } 1714 }
1555 1715
1556 if (perf_evlist__alloc_stats(evsel_list, interval)) 1716 if (perf_evlist__alloc_stats(evsel_list, interval))
1557 goto out_free_maps; 1717 goto out_free_maps;
1558 1718
1559 if (perf_stat_init_aggr_mode()) 1719 if (perf_stat_init_aggr_mode())
1560 goto out; 1720 goto out_free_maps;
1561 1721
1562 /* 1722 /*
1563 * We dont want to block the signals - that would cause 1723 * We dont want to block the signals - that would cause