| .. | .. |
|---|
| 13 | 13 | #include <errno.h> |
|---|
| 14 | 14 | #include <inttypes.h> |
|---|
| 15 | 15 | #include <linux/compiler.h> |
|---|
| 16 | +#include <linux/err.h> |
|---|
| 16 | 17 | #include <linux/kernel.h> |
|---|
| 17 | 18 | #include <linux/stringify.h> |
|---|
| 19 | +#include <linux/zalloc.h> |
|---|
| 18 | 20 | #include <asm/bug.h> |
|---|
| 19 | 21 | #include <sys/param.h> |
|---|
| 20 | | -#include "util.h" |
|---|
| 21 | 22 | #include "debug.h" |
|---|
| 22 | 23 | #include "builtin.h" |
|---|
| 24 | +#include <perf/cpumap.h> |
|---|
| 25 | +#include <subcmd/pager.h> |
|---|
| 23 | 26 | #include <subcmd/parse-options.h> |
|---|
| 27 | +#include "map_symbol.h" |
|---|
| 24 | 28 | #include "mem-events.h" |
|---|
| 25 | 29 | #include "session.h" |
|---|
| 26 | 30 | #include "hist.h" |
|---|
| 27 | 31 | #include "sort.h" |
|---|
| 28 | 32 | #include "tool.h" |
|---|
| 33 | +#include "cacheline.h" |
|---|
| 29 | 34 | #include "data.h" |
|---|
| 30 | 35 | #include "event.h" |
|---|
| 31 | 36 | #include "evlist.h" |
|---|
| .. | .. |
|---|
| 33 | 38 | #include "ui/browsers/hists.h" |
|---|
| 34 | 39 | #include "thread.h" |
|---|
| 35 | 40 | #include "mem2node.h" |
|---|
| 41 | +#include "symbol.h" |
|---|
| 42 | +#include "ui/ui.h" |
|---|
| 43 | +#include "ui/progress.h" |
|---|
| 44 | +#include "../perf.h" |
|---|
| 36 | 45 | |
|---|
| 37 | 46 | struct c2c_hists { |
|---|
| 38 | 47 | struct hists hists; |
|---|
| .. | .. |
|---|
| 68 | 77 | struct hist_entry he; |
|---|
| 69 | 78 | }; |
|---|
| 70 | 79 | |
|---|
| 71 | | -static char const *coalesce_default = "pid,iaddr"; |
|---|
| 80 | +static char const *coalesce_default = "iaddr"; |
|---|
| 72 | 81 | |
|---|
| 73 | 82 | struct perf_c2c { |
|---|
| 74 | 83 | struct perf_tool tool; |
|---|
| .. | .. |
|---|
| 86 | 95 | bool use_stdio; |
|---|
| 87 | 96 | bool stats_only; |
|---|
| 88 | 97 | bool symbol_full; |
|---|
| 98 | + bool stitch_lbr; |
|---|
| 89 | 99 | |
|---|
| 90 | 100 | /* HITM shared clines stats */ |
|---|
| 91 | 101 | struct c2c_stats hitm_stats; |
|---|
| .. | .. |
|---|
| 247 | 257 | static int process_sample_event(struct perf_tool *tool __maybe_unused, |
|---|
| 248 | 258 | union perf_event *event, |
|---|
| 249 | 259 | struct perf_sample *sample, |
|---|
| 250 | | - struct perf_evsel *evsel, |
|---|
| 260 | + struct evsel *evsel, |
|---|
| 251 | 261 | struct machine *machine) |
|---|
| 252 | 262 | { |
|---|
| 253 | 263 | struct c2c_hists *c2c_hists = &c2c.hists; |
|---|
| .. | .. |
|---|
| 263 | 273 | event->header.type); |
|---|
| 264 | 274 | return -1; |
|---|
| 265 | 275 | } |
|---|
| 276 | + |
|---|
| 277 | + if (c2c.stitch_lbr) |
|---|
| 278 | + al.thread->lbr_stitch_enable = true; |
|---|
| 266 | 279 | |
|---|
| 267 | 280 | ret = sample__resolve_callchain(sample, &callchain_cursor, NULL, |
|---|
| 268 | 281 | evsel, &al, sysctl_perf_event_max_stack); |
|---|
| .. | .. |
|---|
| 639 | 652 | STAT_FN(ld_llchit) |
|---|
| 640 | 653 | STAT_FN(rmt_hit) |
|---|
| 641 | 654 | |
|---|
| 642 | | -static uint64_t llc_miss(struct c2c_stats *stats) |
|---|
| 643 | | -{ |
|---|
| 644 | | - uint64_t llcmiss; |
|---|
| 645 | | - |
|---|
| 646 | | - llcmiss = stats->lcl_dram + |
|---|
| 647 | | - stats->rmt_dram + |
|---|
| 648 | | - stats->rmt_hitm + |
|---|
| 649 | | - stats->rmt_hit; |
|---|
| 650 | | - |
|---|
| 651 | | - return llcmiss; |
|---|
| 652 | | -} |
|---|
| 653 | | - |
|---|
| 654 | | -static int |
|---|
| 655 | | -ld_llcmiss_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
|---|
| 656 | | - struct hist_entry *he) |
|---|
| 657 | | -{ |
|---|
| 658 | | - struct c2c_hist_entry *c2c_he; |
|---|
| 659 | | - int width = c2c_width(fmt, hpp, he->hists); |
|---|
| 660 | | - |
|---|
| 661 | | - c2c_he = container_of(he, struct c2c_hist_entry, he); |
|---|
| 662 | | - |
|---|
| 663 | | - return scnprintf(hpp->buf, hpp->size, "%*lu", width, |
|---|
| 664 | | - llc_miss(&c2c_he->stats)); |
|---|
| 665 | | -} |
|---|
| 666 | | - |
|---|
| 667 | | -static int64_t |
|---|
| 668 | | -ld_llcmiss_cmp(struct perf_hpp_fmt *fmt __maybe_unused, |
|---|
| 669 | | - struct hist_entry *left, struct hist_entry *right) |
|---|
| 670 | | -{ |
|---|
| 671 | | - struct c2c_hist_entry *c2c_left; |
|---|
| 672 | | - struct c2c_hist_entry *c2c_right; |
|---|
| 673 | | - |
|---|
| 674 | | - c2c_left = container_of(left, struct c2c_hist_entry, he); |
|---|
| 675 | | - c2c_right = container_of(right, struct c2c_hist_entry, he); |
|---|
| 676 | | - |
|---|
| 677 | | - return (uint64_t) llc_miss(&c2c_left->stats) - |
|---|
| 678 | | - (uint64_t) llc_miss(&c2c_right->stats); |
|---|
| 679 | | -} |
|---|
| 680 | | - |
|---|
| 681 | 655 | static uint64_t total_records(struct c2c_stats *stats) |
|---|
| 682 | 656 | { |
|---|
| 683 | 657 | uint64_t lclmiss, ldcnt, total; |
|---|
| .. | .. |
|---|
| 944 | 918 | double per_left; |
|---|
| 945 | 919 | double per_right; |
|---|
| 946 | 920 | |
|---|
| 947 | | - per_left = PERCENT(left, lcl_hitm); |
|---|
| 948 | | - per_right = PERCENT(right, lcl_hitm); |
|---|
| 921 | + per_left = PERCENT(left, rmt_hitm); |
|---|
| 922 | + per_right = PERCENT(right, rmt_hitm); |
|---|
| 949 | 923 | |
|---|
| 950 | 924 | return per_left - per_right; |
|---|
| 951 | 925 | } |
|---|
| .. | .. |
|---|
| 1107 | 1081 | break; |
|---|
| 1108 | 1082 | case 1: |
|---|
| 1109 | 1083 | { |
|---|
| 1110 | | - int num = bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt); |
|---|
| 1084 | + int num = bitmap_weight(set, c2c.cpus_cnt); |
|---|
| 1111 | 1085 | struct c2c_stats *stats = &c2c_he->node_stats[node]; |
|---|
| 1112 | 1086 | |
|---|
| 1113 | 1087 | ret = scnprintf(hpp->buf, hpp->size, "%2d{%2d ", node, num); |
|---|
| .. | .. |
|---|
| 1315 | 1289 | }; |
|---|
| 1316 | 1290 | |
|---|
| 1317 | 1291 | static struct c2c_dimension dim_tot_hitm = { |
|---|
| 1318 | | - .header = HEADER_SPAN("----- LLC Load Hitm -----", "Total", 2), |
|---|
| 1292 | + .header = HEADER_SPAN("------- Load Hitm -------", "Total", 2), |
|---|
| 1319 | 1293 | .name = "tot_hitm", |
|---|
| 1320 | 1294 | .cmp = tot_hitm_cmp, |
|---|
| 1321 | 1295 | .entry = tot_hitm_entry, |
|---|
| .. | .. |
|---|
| 1323 | 1297 | }; |
|---|
| 1324 | 1298 | |
|---|
| 1325 | 1299 | static struct c2c_dimension dim_lcl_hitm = { |
|---|
| 1326 | | - .header = HEADER_SPAN_LOW("Lcl"), |
|---|
| 1300 | + .header = HEADER_SPAN_LOW("LclHitm"), |
|---|
| 1327 | 1301 | .name = "lcl_hitm", |
|---|
| 1328 | 1302 | .cmp = lcl_hitm_cmp, |
|---|
| 1329 | 1303 | .entry = lcl_hitm_entry, |
|---|
| .. | .. |
|---|
| 1331 | 1305 | }; |
|---|
| 1332 | 1306 | |
|---|
| 1333 | 1307 | static struct c2c_dimension dim_rmt_hitm = { |
|---|
| 1334 | | - .header = HEADER_SPAN_LOW("Rmt"), |
|---|
| 1308 | + .header = HEADER_SPAN_LOW("RmtHitm"), |
|---|
| 1335 | 1309 | .name = "rmt_hitm", |
|---|
| 1336 | 1310 | .cmp = rmt_hitm_cmp, |
|---|
| 1337 | 1311 | .entry = rmt_hitm_entry, |
|---|
| .. | .. |
|---|
| 1354 | 1328 | .width = 7, |
|---|
| 1355 | 1329 | }; |
|---|
| 1356 | 1330 | |
|---|
| 1357 | | -static struct c2c_dimension dim_stores = { |
|---|
| 1358 | | - .header = HEADER_SPAN("---- Store Reference ----", "Total", 2), |
|---|
| 1359 | | - .name = "stores", |
|---|
| 1331 | +static struct c2c_dimension dim_tot_stores = { |
|---|
| 1332 | + .header = HEADER_BOTH("Total", "Stores"), |
|---|
| 1333 | + .name = "tot_stores", |
|---|
| 1360 | 1334 | .cmp = store_cmp, |
|---|
| 1361 | 1335 | .entry = store_entry, |
|---|
| 1362 | 1336 | .width = 7, |
|---|
| 1363 | 1337 | }; |
|---|
| 1364 | 1338 | |
|---|
| 1365 | 1339 | static struct c2c_dimension dim_stores_l1hit = { |
|---|
| 1366 | | - .header = HEADER_SPAN_LOW("L1Hit"), |
|---|
| 1340 | + .header = HEADER_SPAN("---- Stores ----", "L1Hit", 1), |
|---|
| 1367 | 1341 | .name = "stores_l1hit", |
|---|
| 1368 | 1342 | .cmp = st_l1hit_cmp, |
|---|
| 1369 | 1343 | .entry = st_l1hit_entry, |
|---|
| .. | .. |
|---|
| 1419 | 1393 | }; |
|---|
| 1420 | 1394 | |
|---|
| 1421 | 1395 | static struct c2c_dimension dim_ld_llchit = { |
|---|
| 1422 | | - .header = HEADER_SPAN("-- LLC Load Hit --", "Llc", 1), |
|---|
| 1396 | + .header = HEADER_SPAN("- LLC Load Hit --", "LclHit", 1), |
|---|
| 1423 | 1397 | .name = "ld_lclhit", |
|---|
| 1424 | 1398 | .cmp = ld_llchit_cmp, |
|---|
| 1425 | 1399 | .entry = ld_llchit_entry, |
|---|
| .. | .. |
|---|
| 1427 | 1401 | }; |
|---|
| 1428 | 1402 | |
|---|
| 1429 | 1403 | static struct c2c_dimension dim_ld_rmthit = { |
|---|
| 1430 | | - .header = HEADER_SPAN_LOW("Rmt"), |
|---|
| 1404 | + .header = HEADER_SPAN("- RMT Load Hit --", "RmtHit", 1), |
|---|
| 1431 | 1405 | .name = "ld_rmthit", |
|---|
| 1432 | 1406 | .cmp = rmt_hit_cmp, |
|---|
| 1433 | 1407 | .entry = rmt_hit_entry, |
|---|
| 1434 | 1408 | .width = 8, |
|---|
| 1435 | | -}; |
|---|
| 1436 | | - |
|---|
| 1437 | | -static struct c2c_dimension dim_ld_llcmiss = { |
|---|
| 1438 | | - .header = HEADER_BOTH("LLC", "Ld Miss"), |
|---|
| 1439 | | - .name = "ld_llcmiss", |
|---|
| 1440 | | - .cmp = ld_llcmiss_cmp, |
|---|
| 1441 | | - .entry = ld_llcmiss_entry, |
|---|
| 1442 | | - .width = 7, |
|---|
| 1443 | 1409 | }; |
|---|
| 1444 | 1410 | |
|---|
| 1445 | 1411 | static struct c2c_dimension dim_tot_recs = { |
|---|
| .. | .. |
|---|
| 1473 | 1439 | }; |
|---|
| 1474 | 1440 | |
|---|
| 1475 | 1441 | static struct c2c_dimension dim_percent_rmt_hitm = { |
|---|
| 1476 | | - .header = HEADER_SPAN("----- HITM -----", "Rmt", 1), |
|---|
| 1442 | + .header = HEADER_SPAN("----- HITM -----", "RmtHitm", 1), |
|---|
| 1477 | 1443 | .name = "percent_rmt_hitm", |
|---|
| 1478 | 1444 | .cmp = percent_rmt_hitm_cmp, |
|---|
| 1479 | 1445 | .entry = percent_rmt_hitm_entry, |
|---|
| .. | .. |
|---|
| 1482 | 1448 | }; |
|---|
| 1483 | 1449 | |
|---|
| 1484 | 1450 | static struct c2c_dimension dim_percent_lcl_hitm = { |
|---|
| 1485 | | - .header = HEADER_SPAN_LOW("Lcl"), |
|---|
| 1451 | + .header = HEADER_SPAN_LOW("LclHitm"), |
|---|
| 1486 | 1452 | .name = "percent_lcl_hitm", |
|---|
| 1487 | 1453 | .cmp = percent_lcl_hitm_cmp, |
|---|
| 1488 | 1454 | .entry = percent_lcl_hitm_entry, |
|---|
| .. | .. |
|---|
| 1635 | 1601 | &dim_rmt_hitm, |
|---|
| 1636 | 1602 | &dim_cl_lcl_hitm, |
|---|
| 1637 | 1603 | &dim_cl_rmt_hitm, |
|---|
| 1638 | | - &dim_stores, |
|---|
| 1604 | + &dim_tot_stores, |
|---|
| 1639 | 1605 | &dim_stores_l1hit, |
|---|
| 1640 | 1606 | &dim_stores_l1miss, |
|---|
| 1641 | 1607 | &dim_cl_stores_l1hit, |
|---|
| .. | .. |
|---|
| 1645 | 1611 | &dim_ld_l2hit, |
|---|
| 1646 | 1612 | &dim_ld_llchit, |
|---|
| 1647 | 1613 | &dim_ld_rmthit, |
|---|
| 1648 | | - &dim_ld_llcmiss, |
|---|
| 1649 | 1614 | &dim_tot_recs, |
|---|
| 1650 | 1615 | &dim_tot_loads, |
|---|
| 1651 | 1616 | &dim_percent_hitm, |
|---|
| .. | .. |
|---|
| 1696 | 1661 | |
|---|
| 1697 | 1662 | if (!strcmp(dim->name, name)) |
|---|
| 1698 | 1663 | return dim; |
|---|
| 1699 | | - }; |
|---|
| 1664 | + } |
|---|
| 1700 | 1665 | |
|---|
| 1701 | 1666 | return NULL; |
|---|
| 1702 | 1667 | } |
|---|
| .. | .. |
|---|
| 1880 | 1845 | return hpp_list__parse(&c2c_hists->list, output, sort); |
|---|
| 1881 | 1846 | } |
|---|
| 1882 | 1847 | |
|---|
| 1883 | | -#define DISPLAY_LINE_LIMIT 0.0005 |
|---|
| 1848 | +#define DISPLAY_LINE_LIMIT 0.001 |
|---|
| 1884 | 1849 | |
|---|
| 1885 | 1850 | static bool he__display(struct hist_entry *he, struct c2c_stats *stats) |
|---|
| 1886 | 1851 | { |
|---|
| .. | .. |
|---|
| 1912 | 1877 | FILTER_HITM(tot_hitm); |
|---|
| 1913 | 1878 | default: |
|---|
| 1914 | 1879 | break; |
|---|
| 1915 | | - }; |
|---|
| 1880 | + } |
|---|
| 1916 | 1881 | |
|---|
| 1917 | 1882 | #undef FILTER_HITM |
|---|
| 1918 | 1883 | |
|---|
| .. | .. |
|---|
| 1971 | 1936 | set_nodestr(c2c_he); |
|---|
| 1972 | 1937 | } |
|---|
| 1973 | 1938 | |
|---|
| 1974 | | -static int filter_cb(struct hist_entry *he) |
|---|
| 1939 | +static int filter_cb(struct hist_entry *he, void *arg __maybe_unused) |
|---|
| 1975 | 1940 | { |
|---|
| 1976 | 1941 | struct c2c_hist_entry *c2c_he; |
|---|
| 1977 | 1942 | |
|---|
| .. | .. |
|---|
| 1988 | 1953 | return 0; |
|---|
| 1989 | 1954 | } |
|---|
| 1990 | 1955 | |
|---|
| 1991 | | -static int resort_cl_cb(struct hist_entry *he) |
|---|
| 1956 | +static int resort_cl_cb(struct hist_entry *he, void *arg __maybe_unused) |
|---|
| 1992 | 1957 | { |
|---|
| 1993 | 1958 | struct c2c_hist_entry *c2c_he; |
|---|
| 1994 | 1959 | struct c2c_hists *c2c_hists; |
|---|
| .. | .. |
|---|
| 2028 | 1993 | c2c.node_info = 2; |
|---|
| 2029 | 1994 | |
|---|
| 2030 | 1995 | c2c.nodes_cnt = session->header.env.nr_numa_nodes; |
|---|
| 2031 | | - c2c.cpus_cnt = session->header.env.nr_cpus_online; |
|---|
| 1996 | + c2c.cpus_cnt = session->header.env.nr_cpus_avail; |
|---|
| 2032 | 1997 | |
|---|
| 2033 | 1998 | n = session->header.env.numa_nodes; |
|---|
| 2034 | 1999 | if (!n) |
|---|
| .. | .. |
|---|
| 2050 | 2015 | c2c.cpu2node = cpu2node; |
|---|
| 2051 | 2016 | |
|---|
| 2052 | 2017 | for (node = 0; node < c2c.nodes_cnt; node++) { |
|---|
| 2053 | | - struct cpu_map *map = n[node].map; |
|---|
| 2018 | + struct perf_cpu_map *map = n[node].map; |
|---|
| 2054 | 2019 | unsigned long *set; |
|---|
| 2055 | 2020 | |
|---|
| 2056 | 2021 | set = bitmap_alloc(c2c.cpus_cnt); |
|---|
| .. | .. |
|---|
| 2060 | 2025 | nodes[node] = set; |
|---|
| 2061 | 2026 | |
|---|
| 2062 | 2027 | /* empty node, skip */ |
|---|
| 2063 | | - if (cpu_map__empty(map)) |
|---|
| 2028 | + if (perf_cpu_map__empty(map)) |
|---|
| 2064 | 2029 | continue; |
|---|
| 2065 | 2030 | |
|---|
| 2066 | 2031 | for (cpu = 0; cpu < map->nr; cpu++) { |
|---|
| .. | .. |
|---|
| 2079 | 2044 | |
|---|
| 2080 | 2045 | #define HAS_HITMS(__h) ((__h)->stats.lcl_hitm || (__h)->stats.rmt_hitm) |
|---|
| 2081 | 2046 | |
|---|
| 2082 | | -static int resort_hitm_cb(struct hist_entry *he) |
|---|
| 2047 | +static int resort_hitm_cb(struct hist_entry *he, void *arg __maybe_unused) |
|---|
| 2083 | 2048 | { |
|---|
| 2084 | 2049 | struct c2c_hist_entry *c2c_he; |
|---|
| 2085 | 2050 | c2c_he = container_of(he, struct c2c_hist_entry, he); |
|---|
| .. | .. |
|---|
| 2094 | 2059 | |
|---|
| 2095 | 2060 | static int hists__iterate_cb(struct hists *hists, hists__resort_cb_t cb) |
|---|
| 2096 | 2061 | { |
|---|
| 2097 | | - struct rb_node *next = rb_first(&hists->entries); |
|---|
| 2062 | + struct rb_node *next = rb_first_cached(&hists->entries); |
|---|
| 2098 | 2063 | int ret = 0; |
|---|
| 2099 | 2064 | |
|---|
| 2100 | 2065 | while (next) { |
|---|
| 2101 | 2066 | struct hist_entry *he; |
|---|
| 2102 | 2067 | |
|---|
| 2103 | 2068 | he = rb_entry(next, struct hist_entry, rb_node); |
|---|
| 2104 | | - ret = cb(he); |
|---|
| 2069 | + ret = cb(he, NULL); |
|---|
| 2105 | 2070 | if (ret) |
|---|
| 2106 | 2071 | break; |
|---|
| 2107 | 2072 | next = rb_next(&he->rb_node); |
|---|
| .. | .. |
|---|
| 2221 | 2186 | if (WARN_ONCE(ret, "failed to setup sort entries\n")) |
|---|
| 2222 | 2187 | return; |
|---|
| 2223 | 2188 | |
|---|
| 2224 | | - nd = rb_first(&c2c.hists.hists.entries); |
|---|
| 2189 | + nd = rb_first_cached(&c2c.hists.hists.entries); |
|---|
| 2225 | 2190 | |
|---|
| 2226 | 2191 | for (; nd; nd = rb_next(nd)) { |
|---|
| 2227 | 2192 | struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); |
|---|
| .. | .. |
|---|
| 2237 | 2202 | |
|---|
| 2238 | 2203 | static void print_c2c_info(FILE *out, struct perf_session *session) |
|---|
| 2239 | 2204 | { |
|---|
| 2240 | | - struct perf_evlist *evlist = session->evlist; |
|---|
| 2241 | | - struct perf_evsel *evsel; |
|---|
| 2205 | + struct evlist *evlist = session->evlist; |
|---|
| 2206 | + struct evsel *evsel; |
|---|
| 2242 | 2207 | bool first = true; |
|---|
| 2243 | 2208 | |
|---|
| 2244 | 2209 | fprintf(out, "=================================================\n"); |
|---|
| .. | .. |
|---|
| 2246 | 2211 | fprintf(out, "=================================================\n"); |
|---|
| 2247 | 2212 | |
|---|
| 2248 | 2213 | evlist__for_each_entry(evlist, evsel) { |
|---|
| 2249 | | - fprintf(out, "%-36s: %s\n", first ? " Events" : "", |
|---|
| 2250 | | - perf_evsel__name(evsel)); |
|---|
| 2214 | + fprintf(out, "%-36s: %s\n", first ? " Events" : "", evsel__name(evsel)); |
|---|
| 2251 | 2215 | first = false; |
|---|
| 2252 | 2216 | } |
|---|
| 2253 | 2217 | fprintf(out, " Cachelines sort on : %s HITMs\n", |
|---|
| .. | .. |
|---|
| 2289 | 2253 | static void c2c_browser__update_nr_entries(struct hist_browser *hb) |
|---|
| 2290 | 2254 | { |
|---|
| 2291 | 2255 | u64 nr_entries = 0; |
|---|
| 2292 | | - struct rb_node *nd = rb_first(&hb->hists->entries); |
|---|
| 2256 | + struct rb_node *nd = rb_first_cached(&hb->hists->entries); |
|---|
| 2293 | 2257 | |
|---|
| 2294 | 2258 | while (nd) { |
|---|
| 2295 | 2259 | struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); |
|---|
| .. | .. |
|---|
| 2349 | 2313 | struct c2c_cacheline_browser *cl_browser; |
|---|
| 2350 | 2314 | struct hist_browser *browser; |
|---|
| 2351 | 2315 | int key = -1; |
|---|
| 2352 | | - const char help[] = |
|---|
| 2316 | + static const char help[] = |
|---|
| 2353 | 2317 | " ENTER Toggle callchains (if present) \n" |
|---|
| 2354 | 2318 | " n Toggle Node details info \n" |
|---|
| 2355 | 2319 | " s Toggle full length of symbol and source line columns \n" |
|---|
| .. | .. |
|---|
| 2377 | 2341 | c2c_browser__update_nr_entries(browser); |
|---|
| 2378 | 2342 | |
|---|
| 2379 | 2343 | while (1) { |
|---|
| 2380 | | - key = hist_browser__run(browser, "? - help", true); |
|---|
| 2344 | + key = hist_browser__run(browser, "? - help", true, 0); |
|---|
| 2381 | 2345 | |
|---|
| 2382 | 2346 | switch (key) { |
|---|
| 2383 | 2347 | case 's': |
|---|
| .. | .. |
|---|
| 2430 | 2394 | { |
|---|
| 2431 | 2395 | struct hist_browser *browser; |
|---|
| 2432 | 2396 | int key = -1; |
|---|
| 2433 | | - const char help[] = |
|---|
| 2397 | + static const char help[] = |
|---|
| 2434 | 2398 | " d Display cacheline details \n" |
|---|
| 2435 | 2399 | " ENTER Toggle callchains (if present) \n" |
|---|
| 2436 | 2400 | " q Quit \n"; |
|---|
| .. | .. |
|---|
| 2446 | 2410 | c2c_browser__update_nr_entries(browser); |
|---|
| 2447 | 2411 | |
|---|
| 2448 | 2412 | while (1) { |
|---|
| 2449 | | - key = hist_browser__run(browser, "? - help", true); |
|---|
| 2413 | + key = hist_browser__run(browser, "? - help", true, 0); |
|---|
| 2450 | 2414 | |
|---|
| 2451 | 2415 | switch (key) { |
|---|
| 2452 | 2416 | case 'q': |
|---|
| .. | .. |
|---|
| 2568 | 2532 | return parse_callchain_report_opt(arg); |
|---|
| 2569 | 2533 | } |
|---|
| 2570 | 2534 | |
|---|
| 2571 | | -static int setup_callchain(struct perf_evlist *evlist) |
|---|
| 2535 | +static int setup_callchain(struct evlist *evlist) |
|---|
| 2572 | 2536 | { |
|---|
| 2573 | | - u64 sample_type = perf_evlist__combined_sample_type(evlist); |
|---|
| 2537 | + u64 sample_type = evlist__combined_sample_type(evlist); |
|---|
| 2574 | 2538 | enum perf_call_graph_mode mode = CALLCHAIN_NONE; |
|---|
| 2575 | 2539 | |
|---|
| 2576 | 2540 | if ((sample_type & PERF_SAMPLE_REGS_USER) && |
|---|
| .. | .. |
|---|
| 2590 | 2554 | ui__error("Can't register callchain params.\n"); |
|---|
| 2591 | 2555 | return -EINVAL; |
|---|
| 2592 | 2556 | } |
|---|
| 2557 | + } |
|---|
| 2558 | + |
|---|
| 2559 | + if (c2c.stitch_lbr && (mode != CALLCHAIN_LBR)) { |
|---|
| 2560 | + ui__warning("Can't find LBR callchain. Switch off --stitch-lbr.\n" |
|---|
| 2561 | + "Please apply --call-graph lbr when recording.\n"); |
|---|
| 2562 | + c2c.stitch_lbr = false; |
|---|
| 2593 | 2563 | } |
|---|
| 2594 | 2564 | |
|---|
| 2595 | 2565 | callchain_param.record_mode = mode; |
|---|
| .. | .. |
|---|
| 2724 | 2694 | "the input file to process"), |
|---|
| 2725 | 2695 | OPT_INCR('N', "node-info", &c2c.node_info, |
|---|
| 2726 | 2696 | "show extra node info in report (repeat for more info)"), |
|---|
| 2727 | | -#ifdef HAVE_SLANG_SUPPORT |
|---|
| 2728 | 2697 | OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"), |
|---|
| 2729 | | -#endif |
|---|
| 2730 | 2698 | OPT_BOOLEAN(0, "stats", &c2c.stats_only, |
|---|
| 2731 | 2699 | "Display only statistic tables (implies --stdio)"), |
|---|
| 2732 | 2700 | OPT_BOOLEAN(0, "full-symbols", &c2c.symbol_full, |
|---|
| .. | .. |
|---|
| 2743 | 2711 | OPT_STRING('c', "coalesce", &coalesce, "coalesce fields", |
|---|
| 2744 | 2712 | "coalesce fields: pid,tid,iaddr,dso"), |
|---|
| 2745 | 2713 | OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"), |
|---|
| 2714 | + OPT_BOOLEAN(0, "stitch-lbr", &c2c.stitch_lbr, |
|---|
| 2715 | + "Enable LBR callgraph stitching approach"), |
|---|
| 2746 | 2716 | OPT_PARENT(c2c_options), |
|---|
| 2747 | 2717 | OPT_END() |
|---|
| 2748 | 2718 | }; |
|---|
| .. | .. |
|---|
| 2753 | 2723 | if (argc) |
|---|
| 2754 | 2724 | usage_with_options(report_c2c_usage, options); |
|---|
| 2755 | 2725 | |
|---|
| 2726 | +#ifndef HAVE_SLANG_SUPPORT |
|---|
| 2727 | + c2c.use_stdio = true; |
|---|
| 2728 | +#endif |
|---|
| 2729 | + |
|---|
| 2756 | 2730 | if (c2c.stats_only) |
|---|
| 2757 | 2731 | c2c.use_stdio = true; |
|---|
| 2758 | 2732 | |
|---|
| 2759 | 2733 | if (!input_name || !strlen(input_name)) |
|---|
| 2760 | 2734 | input_name = "perf.data"; |
|---|
| 2761 | 2735 | |
|---|
| 2762 | | - data.file.path = input_name; |
|---|
| 2763 | | - data.force = symbol_conf.force; |
|---|
| 2736 | + data.path = input_name; |
|---|
| 2737 | + data.force = symbol_conf.force; |
|---|
| 2764 | 2738 | |
|---|
| 2765 | 2739 | err = setup_display(display); |
|---|
| 2766 | 2740 | if (err) |
|---|
| .. | .. |
|---|
| 2779 | 2753 | } |
|---|
| 2780 | 2754 | |
|---|
| 2781 | 2755 | session = perf_session__new(&data, 0, &c2c.tool); |
|---|
| 2782 | | - if (session == NULL) { |
|---|
| 2783 | | - pr_debug("No memory for session\n"); |
|---|
| 2756 | + if (IS_ERR(session)) { |
|---|
| 2757 | + err = PTR_ERR(session); |
|---|
| 2758 | + pr_debug("Error creating perf session\n"); |
|---|
| 2784 | 2759 | goto out; |
|---|
| 2785 | 2760 | } |
|---|
| 2786 | 2761 | |
|---|
| .. | .. |
|---|
| 2825 | 2800 | "dcacheline," |
|---|
| 2826 | 2801 | "dcacheline_node," |
|---|
| 2827 | 2802 | "dcacheline_count," |
|---|
| 2828 | | - "tot_recs," |
|---|
| 2829 | 2803 | "percent_hitm," |
|---|
| 2830 | 2804 | "tot_hitm,lcl_hitm,rmt_hitm," |
|---|
| 2831 | | - "stores,stores_l1hit,stores_l1miss," |
|---|
| 2832 | | - "dram_lcl,dram_rmt," |
|---|
| 2833 | | - "ld_llcmiss," |
|---|
| 2805 | + "tot_recs," |
|---|
| 2834 | 2806 | "tot_loads," |
|---|
| 2807 | + "tot_stores," |
|---|
| 2808 | + "stores_l1hit,stores_l1miss," |
|---|
| 2835 | 2809 | "ld_fbhit,ld_l1hit,ld_l2hit," |
|---|
| 2836 | | - "ld_lclhit,ld_rmthit", |
|---|
| 2810 | + "ld_lclhit,lcl_hitm," |
|---|
| 2811 | + "ld_rmthit,rmt_hitm," |
|---|
| 2812 | + "dram_lcl,dram_rmt", |
|---|
| 2837 | 2813 | c2c.display == DISPLAY_TOT ? "tot_hitm" : |
|---|
| 2838 | 2814 | c2c.display == DISPLAY_LCL ? "lcl_hitm" : "rmt_hitm" |
|---|
| 2839 | 2815 | ); |
|---|
| .. | .. |
|---|
| 2866 | 2842 | { |
|---|
| 2867 | 2843 | bool *event_set = (bool *) opt->value; |
|---|
| 2868 | 2844 | |
|---|
| 2845 | + if (!strcmp(str, "list")) { |
|---|
| 2846 | + perf_mem_events__list(); |
|---|
| 2847 | + exit(0); |
|---|
| 2848 | + } |
|---|
| 2849 | + if (perf_mem_events__parse(str)) |
|---|
| 2850 | + exit(-1); |
|---|
| 2851 | + |
|---|
| 2869 | 2852 | *event_set = true; |
|---|
| 2870 | | - return perf_mem_events__parse(str); |
|---|
| 2853 | + return 0; |
|---|
| 2871 | 2854 | } |
|---|
| 2872 | 2855 | |
|---|
| 2873 | 2856 | |
|---|
| .. | .. |
|---|
| 2888 | 2871 | bool event_set = false; |
|---|
| 2889 | 2872 | struct option options[] = { |
|---|
| 2890 | 2873 | OPT_CALLBACK('e', "event", &event_set, "event", |
|---|
| 2891 | | - "event selector. Use 'perf mem record -e list' to list available events", |
|---|
| 2874 | + "event selector. Use 'perf c2c record -e list' to list available events", |
|---|
| 2892 | 2875 | parse_record_events), |
|---|
| 2893 | 2876 | OPT_BOOLEAN('u', "all-user", &all_user, "collect only user level data"), |
|---|
| 2894 | 2877 | OPT_BOOLEAN('k', "all-kernel", &all_kernel, "collect only kernel level data"), |
|---|
| .. | .. |
|---|
| 2937 | 2920 | |
|---|
| 2938 | 2921 | rec_argv[i++] = "-e"; |
|---|
| 2939 | 2922 | rec_argv[i++] = perf_mem_events__name(j); |
|---|
| 2940 | | - }; |
|---|
| 2923 | + } |
|---|
| 2941 | 2924 | |
|---|
| 2942 | 2925 | if (all_user) |
|---|
| 2943 | 2926 | rec_argv[i++] = "--all-user"; |
|---|