.. | .. |
---|
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"; |
---|