hc
2023-12-09 b22da3d8526a935aa31e086e63f60ff3246cb61c
kernel/tools/perf/builtin-c2c.c
....@@ -13,19 +13,24 @@
1313 #include <errno.h>
1414 #include <inttypes.h>
1515 #include <linux/compiler.h>
16
+#include <linux/err.h>
1617 #include <linux/kernel.h>
1718 #include <linux/stringify.h>
19
+#include <linux/zalloc.h>
1820 #include <asm/bug.h>
1921 #include <sys/param.h>
20
-#include "util.h"
2122 #include "debug.h"
2223 #include "builtin.h"
24
+#include <perf/cpumap.h>
25
+#include <subcmd/pager.h>
2326 #include <subcmd/parse-options.h>
27
+#include "map_symbol.h"
2428 #include "mem-events.h"
2529 #include "session.h"
2630 #include "hist.h"
2731 #include "sort.h"
2832 #include "tool.h"
33
+#include "cacheline.h"
2934 #include "data.h"
3035 #include "event.h"
3136 #include "evlist.h"
....@@ -33,6 +38,10 @@
3338 #include "ui/browsers/hists.h"
3439 #include "thread.h"
3540 #include "mem2node.h"
41
+#include "symbol.h"
42
+#include "ui/ui.h"
43
+#include "ui/progress.h"
44
+#include "../perf.h"
3645
3746 struct c2c_hists {
3847 struct hists hists;
....@@ -68,7 +77,7 @@
6877 struct hist_entry he;
6978 };
7079
71
-static char const *coalesce_default = "pid,iaddr";
80
+static char const *coalesce_default = "iaddr";
7281
7382 struct perf_c2c {
7483 struct perf_tool tool;
....@@ -86,6 +95,7 @@
8695 bool use_stdio;
8796 bool stats_only;
8897 bool symbol_full;
98
+ bool stitch_lbr;
8999
90100 /* HITM shared clines stats */
91101 struct c2c_stats hitm_stats;
....@@ -247,7 +257,7 @@
247257 static int process_sample_event(struct perf_tool *tool __maybe_unused,
248258 union perf_event *event,
249259 struct perf_sample *sample,
250
- struct perf_evsel *evsel,
260
+ struct evsel *evsel,
251261 struct machine *machine)
252262 {
253263 struct c2c_hists *c2c_hists = &c2c.hists;
....@@ -263,6 +273,9 @@
263273 event->header.type);
264274 return -1;
265275 }
276
+
277
+ if (c2c.stitch_lbr)
278
+ al.thread->lbr_stitch_enable = true;
266279
267280 ret = sample__resolve_callchain(sample, &callchain_cursor, NULL,
268281 evsel, &al, sysctl_perf_event_max_stack);
....@@ -639,45 +652,6 @@
639652 STAT_FN(ld_llchit)
640653 STAT_FN(rmt_hit)
641654
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
-
681655 static uint64_t total_records(struct c2c_stats *stats)
682656 {
683657 uint64_t lclmiss, ldcnt, total;
....@@ -944,8 +918,8 @@
944918 double per_left;
945919 double per_right;
946920
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);
949923
950924 return per_left - per_right;
951925 }
....@@ -1107,7 +1081,7 @@
11071081 break;
11081082 case 1:
11091083 {
1110
- int num = bitmap_weight(c2c_he->cpuset, c2c.cpus_cnt);
1084
+ int num = bitmap_weight(set, c2c.cpus_cnt);
11111085 struct c2c_stats *stats = &c2c_he->node_stats[node];
11121086
11131087 ret = scnprintf(hpp->buf, hpp->size, "%2d{%2d ", node, num);
....@@ -1315,7 +1289,7 @@
13151289 };
13161290
13171291 static struct c2c_dimension dim_tot_hitm = {
1318
- .header = HEADER_SPAN("----- LLC Load Hitm -----", "Total", 2),
1292
+ .header = HEADER_SPAN("------- Load Hitm -------", "Total", 2),
13191293 .name = "tot_hitm",
13201294 .cmp = tot_hitm_cmp,
13211295 .entry = tot_hitm_entry,
....@@ -1323,7 +1297,7 @@
13231297 };
13241298
13251299 static struct c2c_dimension dim_lcl_hitm = {
1326
- .header = HEADER_SPAN_LOW("Lcl"),
1300
+ .header = HEADER_SPAN_LOW("LclHitm"),
13271301 .name = "lcl_hitm",
13281302 .cmp = lcl_hitm_cmp,
13291303 .entry = lcl_hitm_entry,
....@@ -1331,7 +1305,7 @@
13311305 };
13321306
13331307 static struct c2c_dimension dim_rmt_hitm = {
1334
- .header = HEADER_SPAN_LOW("Rmt"),
1308
+ .header = HEADER_SPAN_LOW("RmtHitm"),
13351309 .name = "rmt_hitm",
13361310 .cmp = rmt_hitm_cmp,
13371311 .entry = rmt_hitm_entry,
....@@ -1354,16 +1328,16 @@
13541328 .width = 7,
13551329 };
13561330
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",
13601334 .cmp = store_cmp,
13611335 .entry = store_entry,
13621336 .width = 7,
13631337 };
13641338
13651339 static struct c2c_dimension dim_stores_l1hit = {
1366
- .header = HEADER_SPAN_LOW("L1Hit"),
1340
+ .header = HEADER_SPAN("---- Stores ----", "L1Hit", 1),
13671341 .name = "stores_l1hit",
13681342 .cmp = st_l1hit_cmp,
13691343 .entry = st_l1hit_entry,
....@@ -1419,7 +1393,7 @@
14191393 };
14201394
14211395 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),
14231397 .name = "ld_lclhit",
14241398 .cmp = ld_llchit_cmp,
14251399 .entry = ld_llchit_entry,
....@@ -1427,19 +1401,11 @@
14271401 };
14281402
14291403 static struct c2c_dimension dim_ld_rmthit = {
1430
- .header = HEADER_SPAN_LOW("Rmt"),
1404
+ .header = HEADER_SPAN("- RMT Load Hit --", "RmtHit", 1),
14311405 .name = "ld_rmthit",
14321406 .cmp = rmt_hit_cmp,
14331407 .entry = rmt_hit_entry,
14341408 .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,
14431409 };
14441410
14451411 static struct c2c_dimension dim_tot_recs = {
....@@ -1473,7 +1439,7 @@
14731439 };
14741440
14751441 static struct c2c_dimension dim_percent_rmt_hitm = {
1476
- .header = HEADER_SPAN("----- HITM -----", "Rmt", 1),
1442
+ .header = HEADER_SPAN("----- HITM -----", "RmtHitm", 1),
14771443 .name = "percent_rmt_hitm",
14781444 .cmp = percent_rmt_hitm_cmp,
14791445 .entry = percent_rmt_hitm_entry,
....@@ -1482,7 +1448,7 @@
14821448 };
14831449
14841450 static struct c2c_dimension dim_percent_lcl_hitm = {
1485
- .header = HEADER_SPAN_LOW("Lcl"),
1451
+ .header = HEADER_SPAN_LOW("LclHitm"),
14861452 .name = "percent_lcl_hitm",
14871453 .cmp = percent_lcl_hitm_cmp,
14881454 .entry = percent_lcl_hitm_entry,
....@@ -1635,7 +1601,7 @@
16351601 &dim_rmt_hitm,
16361602 &dim_cl_lcl_hitm,
16371603 &dim_cl_rmt_hitm,
1638
- &dim_stores,
1604
+ &dim_tot_stores,
16391605 &dim_stores_l1hit,
16401606 &dim_stores_l1miss,
16411607 &dim_cl_stores_l1hit,
....@@ -1645,7 +1611,6 @@
16451611 &dim_ld_l2hit,
16461612 &dim_ld_llchit,
16471613 &dim_ld_rmthit,
1648
- &dim_ld_llcmiss,
16491614 &dim_tot_recs,
16501615 &dim_tot_loads,
16511616 &dim_percent_hitm,
....@@ -1696,7 +1661,7 @@
16961661
16971662 if (!strcmp(dim->name, name))
16981663 return dim;
1699
- };
1664
+ }
17001665
17011666 return NULL;
17021667 }
....@@ -1880,7 +1845,7 @@
18801845 return hpp_list__parse(&c2c_hists->list, output, sort);
18811846 }
18821847
1883
-#define DISPLAY_LINE_LIMIT 0.0005
1848
+#define DISPLAY_LINE_LIMIT 0.001
18841849
18851850 static bool he__display(struct hist_entry *he, struct c2c_stats *stats)
18861851 {
....@@ -1912,7 +1877,7 @@
19121877 FILTER_HITM(tot_hitm);
19131878 default:
19141879 break;
1915
- };
1880
+ }
19161881
19171882 #undef FILTER_HITM
19181883
....@@ -1971,7 +1936,7 @@
19711936 set_nodestr(c2c_he);
19721937 }
19731938
1974
-static int filter_cb(struct hist_entry *he)
1939
+static int filter_cb(struct hist_entry *he, void *arg __maybe_unused)
19751940 {
19761941 struct c2c_hist_entry *c2c_he;
19771942
....@@ -1988,7 +1953,7 @@
19881953 return 0;
19891954 }
19901955
1991
-static int resort_cl_cb(struct hist_entry *he)
1956
+static int resort_cl_cb(struct hist_entry *he, void *arg __maybe_unused)
19921957 {
19931958 struct c2c_hist_entry *c2c_he;
19941959 struct c2c_hists *c2c_hists;
....@@ -2028,7 +1993,7 @@
20281993 c2c.node_info = 2;
20291994
20301995 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;
20321997
20331998 n = session->header.env.numa_nodes;
20341999 if (!n)
....@@ -2050,7 +2015,7 @@
20502015 c2c.cpu2node = cpu2node;
20512016
20522017 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;
20542019 unsigned long *set;
20552020
20562021 set = bitmap_alloc(c2c.cpus_cnt);
....@@ -2060,7 +2025,7 @@
20602025 nodes[node] = set;
20612026
20622027 /* empty node, skip */
2063
- if (cpu_map__empty(map))
2028
+ if (perf_cpu_map__empty(map))
20642029 continue;
20652030
20662031 for (cpu = 0; cpu < map->nr; cpu++) {
....@@ -2079,7 +2044,7 @@
20792044
20802045 #define HAS_HITMS(__h) ((__h)->stats.lcl_hitm || (__h)->stats.rmt_hitm)
20812046
2082
-static int resort_hitm_cb(struct hist_entry *he)
2047
+static int resort_hitm_cb(struct hist_entry *he, void *arg __maybe_unused)
20832048 {
20842049 struct c2c_hist_entry *c2c_he;
20852050 c2c_he = container_of(he, struct c2c_hist_entry, he);
....@@ -2094,14 +2059,14 @@
20942059
20952060 static int hists__iterate_cb(struct hists *hists, hists__resort_cb_t cb)
20962061 {
2097
- struct rb_node *next = rb_first(&hists->entries);
2062
+ struct rb_node *next = rb_first_cached(&hists->entries);
20982063 int ret = 0;
20992064
21002065 while (next) {
21012066 struct hist_entry *he;
21022067
21032068 he = rb_entry(next, struct hist_entry, rb_node);
2104
- ret = cb(he);
2069
+ ret = cb(he, NULL);
21052070 if (ret)
21062071 break;
21072072 next = rb_next(&he->rb_node);
....@@ -2221,7 +2186,7 @@
22212186 if (WARN_ONCE(ret, "failed to setup sort entries\n"))
22222187 return;
22232188
2224
- nd = rb_first(&c2c.hists.hists.entries);
2189
+ nd = rb_first_cached(&c2c.hists.hists.entries);
22252190
22262191 for (; nd; nd = rb_next(nd)) {
22272192 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
....@@ -2237,8 +2202,8 @@
22372202
22382203 static void print_c2c_info(FILE *out, struct perf_session *session)
22392204 {
2240
- struct perf_evlist *evlist = session->evlist;
2241
- struct perf_evsel *evsel;
2205
+ struct evlist *evlist = session->evlist;
2206
+ struct evsel *evsel;
22422207 bool first = true;
22432208
22442209 fprintf(out, "=================================================\n");
....@@ -2246,8 +2211,7 @@
22462211 fprintf(out, "=================================================\n");
22472212
22482213 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));
22512215 first = false;
22522216 }
22532217 fprintf(out, " Cachelines sort on : %s HITMs\n",
....@@ -2289,7 +2253,7 @@
22892253 static void c2c_browser__update_nr_entries(struct hist_browser *hb)
22902254 {
22912255 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);
22932257
22942258 while (nd) {
22952259 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
....@@ -2349,7 +2313,7 @@
23492313 struct c2c_cacheline_browser *cl_browser;
23502314 struct hist_browser *browser;
23512315 int key = -1;
2352
- const char help[] =
2316
+ static const char help[] =
23532317 " ENTER Toggle callchains (if present) \n"
23542318 " n Toggle Node details info \n"
23552319 " s Toggle full length of symbol and source line columns \n"
....@@ -2377,7 +2341,7 @@
23772341 c2c_browser__update_nr_entries(browser);
23782342
23792343 while (1) {
2380
- key = hist_browser__run(browser, "? - help", true);
2344
+ key = hist_browser__run(browser, "? - help", true, 0);
23812345
23822346 switch (key) {
23832347 case 's':
....@@ -2430,7 +2394,7 @@
24302394 {
24312395 struct hist_browser *browser;
24322396 int key = -1;
2433
- const char help[] =
2397
+ static const char help[] =
24342398 " d Display cacheline details \n"
24352399 " ENTER Toggle callchains (if present) \n"
24362400 " q Quit \n";
....@@ -2446,7 +2410,7 @@
24462410 c2c_browser__update_nr_entries(browser);
24472411
24482412 while (1) {
2449
- key = hist_browser__run(browser, "? - help", true);
2413
+ key = hist_browser__run(browser, "? - help", true, 0);
24502414
24512415 switch (key) {
24522416 case 'q':
....@@ -2568,9 +2532,9 @@
25682532 return parse_callchain_report_opt(arg);
25692533 }
25702534
2571
-static int setup_callchain(struct perf_evlist *evlist)
2535
+static int setup_callchain(struct evlist *evlist)
25722536 {
2573
- u64 sample_type = perf_evlist__combined_sample_type(evlist);
2537
+ u64 sample_type = evlist__combined_sample_type(evlist);
25742538 enum perf_call_graph_mode mode = CALLCHAIN_NONE;
25752539
25762540 if ((sample_type & PERF_SAMPLE_REGS_USER) &&
....@@ -2590,6 +2554,12 @@
25902554 ui__error("Can't register callchain params.\n");
25912555 return -EINVAL;
25922556 }
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;
25932563 }
25942564
25952565 callchain_param.record_mode = mode;
....@@ -2724,9 +2694,7 @@
27242694 "the input file to process"),
27252695 OPT_INCR('N', "node-info", &c2c.node_info,
27262696 "show extra node info in report (repeat for more info)"),
2727
-#ifdef HAVE_SLANG_SUPPORT
27282697 OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"),
2729
-#endif
27302698 OPT_BOOLEAN(0, "stats", &c2c.stats_only,
27312699 "Display only statistic tables (implies --stdio)"),
27322700 OPT_BOOLEAN(0, "full-symbols", &c2c.symbol_full,
....@@ -2743,6 +2711,8 @@
27432711 OPT_STRING('c', "coalesce", &coalesce, "coalesce fields",
27442712 "coalesce fields: pid,tid,iaddr,dso"),
27452713 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"),
27462716 OPT_PARENT(c2c_options),
27472717 OPT_END()
27482718 };
....@@ -2753,14 +2723,18 @@
27532723 if (argc)
27542724 usage_with_options(report_c2c_usage, options);
27552725
2726
+#ifndef HAVE_SLANG_SUPPORT
2727
+ c2c.use_stdio = true;
2728
+#endif
2729
+
27562730 if (c2c.stats_only)
27572731 c2c.use_stdio = true;
27582732
27592733 if (!input_name || !strlen(input_name))
27602734 input_name = "perf.data";
27612735
2762
- data.file.path = input_name;
2763
- data.force = symbol_conf.force;
2736
+ data.path = input_name;
2737
+ data.force = symbol_conf.force;
27642738
27652739 err = setup_display(display);
27662740 if (err)
....@@ -2779,8 +2753,9 @@
27792753 }
27802754
27812755 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");
27842759 goto out;
27852760 }
27862761
....@@ -2825,15 +2800,16 @@
28252800 "dcacheline,"
28262801 "dcacheline_node,"
28272802 "dcacheline_count,"
2828
- "tot_recs,"
28292803 "percent_hitm,"
28302804 "tot_hitm,lcl_hitm,rmt_hitm,"
2831
- "stores,stores_l1hit,stores_l1miss,"
2832
- "dram_lcl,dram_rmt,"
2833
- "ld_llcmiss,"
2805
+ "tot_recs,"
28342806 "tot_loads,"
2807
+ "tot_stores,"
2808
+ "stores_l1hit,stores_l1miss,"
28352809 "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",
28372813 c2c.display == DISPLAY_TOT ? "tot_hitm" :
28382814 c2c.display == DISPLAY_LCL ? "lcl_hitm" : "rmt_hitm"
28392815 );
....@@ -2866,8 +2842,15 @@
28662842 {
28672843 bool *event_set = (bool *) opt->value;
28682844
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
+
28692852 *event_set = true;
2870
- return perf_mem_events__parse(str);
2853
+ return 0;
28712854 }
28722855
28732856
....@@ -2888,7 +2871,7 @@
28882871 bool event_set = false;
28892872 struct option options[] = {
28902873 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",
28922875 parse_record_events),
28932876 OPT_BOOLEAN('u', "all-user", &all_user, "collect only user level data"),
28942877 OPT_BOOLEAN('k', "all-kernel", &all_kernel, "collect only kernel level data"),
....@@ -2937,7 +2920,7 @@
29372920
29382921 rec_argv[i++] = "-e";
29392922 rec_argv[i++] = perf_mem_events__name(j);
2940
- };
2923
+ }
29412924
29422925 if (all_user)
29432926 rec_argv[i++] = "--all-user";