diff options
author | Jiri Olsa <jolsa@kernel.org> | 2016-05-29 04:21:45 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-10-21 09:31:57 -0400 |
commit | 55b9577672b27f71843c07b9958129c4548a4090 (patch) | |
tree | dbdf7d8d26a3278e07f489931c96bf4e63c947c1 /tools/perf | |
parent | 9857b7173cf420654a7a78a2cdf972ddb380a8a1 (diff) |
perf c2c report: Add support to choose local HITMs
Currently we sort and limit displayed data based on the remote HITMs
count. Adding support to switch to local HITMs via --display option:
--display ... lcl,rmt
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Don Zickus <dzickus@redhat.com>
Cc: Joe Mario <jmario@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/n/tip-inykbom2f19difvsu1e18avr@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/builtin-c2c.c | 114 |
1 files changed, 95 insertions, 19 deletions
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 92b3b8171d4d..75bcf1406df3 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c | |||
@@ -63,6 +63,13 @@ struct perf_c2c { | |||
63 | /* HITM shared clines stats */ | 63 | /* HITM shared clines stats */ |
64 | struct c2c_stats hitm_stats; | 64 | struct c2c_stats hitm_stats; |
65 | int shared_clines; | 65 | int shared_clines; |
66 | |||
67 | int display; | ||
68 | }; | ||
69 | |||
70 | enum { | ||
71 | DISPLAY_LCL, | ||
72 | DISPLAY_RMT, | ||
66 | }; | 73 | }; |
67 | 74 | ||
68 | static struct perf_c2c c2c; | 75 | static struct perf_c2c c2c; |
@@ -684,15 +691,24 @@ static double percent_hitm(struct c2c_hist_entry *c2c_he) | |||
684 | struct c2c_hists *hists; | 691 | struct c2c_hists *hists; |
685 | struct c2c_stats *stats; | 692 | struct c2c_stats *stats; |
686 | struct c2c_stats *total; | 693 | struct c2c_stats *total; |
687 | int tot, st; | 694 | int tot = 0, st = 0; |
688 | double p; | 695 | double p; |
689 | 696 | ||
690 | hists = container_of(c2c_he->he.hists, struct c2c_hists, hists); | 697 | hists = container_of(c2c_he->he.hists, struct c2c_hists, hists); |
691 | stats = &c2c_he->stats; | 698 | stats = &c2c_he->stats; |
692 | total = &hists->stats; | 699 | total = &hists->stats; |
693 | 700 | ||
694 | st = stats->rmt_hitm; | 701 | switch (c2c.display) { |
695 | tot = total->rmt_hitm; | 702 | case DISPLAY_RMT: |
703 | st = stats->rmt_hitm; | ||
704 | tot = total->rmt_hitm; | ||
705 | break; | ||
706 | case DISPLAY_LCL: | ||
707 | st = stats->lcl_hitm; | ||
708 | tot = total->lcl_hitm; | ||
709 | default: | ||
710 | break; | ||
711 | } | ||
696 | 712 | ||
697 | p = tot ? (double) st / tot : 0; | 713 | p = tot ? (double) st / tot : 0; |
698 | 714 | ||
@@ -975,14 +991,26 @@ node_entry(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *hpp, | |||
975 | ret = scnprintf(hpp->buf, hpp->size, "%2d{%2d ", node, num); | 991 | ret = scnprintf(hpp->buf, hpp->size, "%2d{%2d ", node, num); |
976 | advance_hpp(hpp, ret); | 992 | advance_hpp(hpp, ret); |
977 | 993 | ||
994 | #define DISPLAY_HITM(__h) \ | ||
995 | if (c2c_he->stats.__h> 0) { \ | ||
996 | ret = scnprintf(hpp->buf, hpp->size, "%5.1f%% ", \ | ||
997 | percent(stats->__h, c2c_he->stats.__h));\ | ||
998 | } else { \ | ||
999 | ret = scnprintf(hpp->buf, hpp->size, "%6s ", "n/a"); \ | ||
1000 | } | ||
978 | 1001 | ||
979 | if (c2c_he->stats.rmt_hitm > 0) { | 1002 | switch (c2c.display) { |
980 | ret = scnprintf(hpp->buf, hpp->size, "%5.1f%% ", | 1003 | case DISPLAY_RMT: |
981 | percent(stats->rmt_hitm, c2c_he->stats.rmt_hitm)); | 1004 | DISPLAY_HITM(rmt_hitm); |
982 | } else { | 1005 | break; |
983 | ret = scnprintf(hpp->buf, hpp->size, "%6s ", "n/a"); | 1006 | case DISPLAY_LCL: |
1007 | DISPLAY_HITM(lcl_hitm); | ||
1008 | default: | ||
1009 | break; | ||
984 | } | 1010 | } |
985 | 1011 | ||
1012 | #undef DISPLAY_HITM | ||
1013 | |||
986 | advance_hpp(hpp, ret); | 1014 | advance_hpp(hpp, ret); |
987 | 1015 | ||
988 | if (c2c_he->stats.store > 0) { | 1016 | if (c2c_he->stats.store > 0) { |
@@ -1258,8 +1286,12 @@ static struct c2c_dimension dim_tot_loads = { | |||
1258 | .width = 7, | 1286 | .width = 7, |
1259 | }; | 1287 | }; |
1260 | 1288 | ||
1289 | static struct c2c_header percent_hitm_header[] = { | ||
1290 | [DISPLAY_LCL] = HEADER_BOTH("Lcl", "Hitm"), | ||
1291 | [DISPLAY_RMT] = HEADER_BOTH("Rmt", "Hitm"), | ||
1292 | }; | ||
1293 | |||
1261 | static struct c2c_dimension dim_percent_hitm = { | 1294 | static struct c2c_dimension dim_percent_hitm = { |
1262 | .header = HEADER_LOW("%hitm"), | ||
1263 | .name = "percent_hitm", | 1295 | .name = "percent_hitm", |
1264 | .cmp = percent_hitm_cmp, | 1296 | .cmp = percent_hitm_cmp, |
1265 | .entry = percent_hitm_entry, | 1297 | .entry = percent_hitm_entry, |
@@ -1654,23 +1686,39 @@ static bool he__display(struct hist_entry *he, struct c2c_stats *stats) | |||
1654 | 1686 | ||
1655 | c2c_he = container_of(he, struct c2c_hist_entry, he); | 1687 | c2c_he = container_of(he, struct c2c_hist_entry, he); |
1656 | 1688 | ||
1657 | if (stats->rmt_hitm) { | 1689 | #define FILTER_HITM(__h) \ |
1658 | ld_dist = ((double)c2c_he->stats.rmt_hitm / stats->rmt_hitm); | 1690 | if (stats->__h) { \ |
1659 | if (ld_dist < DISPLAY_LINE_LIMIT) | 1691 | ld_dist = ((double)c2c_he->stats.__h / stats->__h); \ |
1660 | he->filtered = HIST_FILTER__C2C; | 1692 | if (ld_dist < DISPLAY_LINE_LIMIT) \ |
1661 | } else { | 1693 | he->filtered = HIST_FILTER__C2C; \ |
1662 | he->filtered = HIST_FILTER__C2C; | 1694 | } else { \ |
1695 | he->filtered = HIST_FILTER__C2C; \ | ||
1663 | } | 1696 | } |
1664 | 1697 | ||
1698 | switch (c2c.display) { | ||
1699 | case DISPLAY_LCL: | ||
1700 | FILTER_HITM(lcl_hitm); | ||
1701 | break; | ||
1702 | case DISPLAY_RMT: | ||
1703 | FILTER_HITM(rmt_hitm); | ||
1704 | default: | ||
1705 | break; | ||
1706 | }; | ||
1707 | |||
1708 | #undef FILTER_HITM | ||
1709 | |||
1665 | return he->filtered == 0; | 1710 | return he->filtered == 0; |
1666 | } | 1711 | } |
1667 | 1712 | ||
1668 | static inline int valid_hitm_or_store(struct hist_entry *he) | 1713 | static inline int valid_hitm_or_store(struct hist_entry *he) |
1669 | { | 1714 | { |
1670 | struct c2c_hist_entry *c2c_he; | 1715 | struct c2c_hist_entry *c2c_he; |
1716 | bool has_hitm; | ||
1671 | 1717 | ||
1672 | c2c_he = container_of(he, struct c2c_hist_entry, he); | 1718 | c2c_he = container_of(he, struct c2c_hist_entry, he); |
1673 | return c2c_he->stats.rmt_hitm || c2c_he->stats.store; | 1719 | has_hitm = c2c.display == DISPLAY_LCL ? |
1720 | c2c_he->stats.lcl_hitm : c2c_he->stats.rmt_hitm; | ||
1721 | return has_hitm || c2c_he->stats.store; | ||
1674 | } | 1722 | } |
1675 | 1723 | ||
1676 | static int filter_cb(struct hist_entry *he) | 1724 | static int filter_cb(struct hist_entry *he) |
@@ -1951,6 +1999,8 @@ static void print_c2c_info(FILE *out, struct perf_session *session) | |||
1951 | perf_evsel__name(evsel)); | 1999 | perf_evsel__name(evsel)); |
1952 | first = false; | 2000 | first = false; |
1953 | } | 2001 | } |
2002 | fprintf(out, " Cachelines sort on : %s HITMs\n", | ||
2003 | c2c.display == DISPLAY_LCL ? "Local" : "Remote"); | ||
1954 | } | 2004 | } |
1955 | 2005 | ||
1956 | static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session) | 2006 | static void perf_c2c__hists_fprintf(FILE *out, struct perf_session *session) |
@@ -2083,8 +2133,10 @@ static int perf_c2c_browser__title(struct hist_browser *browser, | |||
2083 | char *bf, size_t size) | 2133 | char *bf, size_t size) |
2084 | { | 2134 | { |
2085 | scnprintf(bf, size, | 2135 | scnprintf(bf, size, |
2086 | "Shared Data Cache Line Table " | 2136 | "Shared Data Cache Line Table " |
2087 | "(%lu entries)", browser->nr_non_filtered_entries); | 2137 | "(%lu entries, sorted on %s HITMs)", |
2138 | browser->nr_non_filtered_entries, | ||
2139 | c2c.display == DISPLAY_LCL ? "local" : "remote"); | ||
2088 | return 0; | 2140 | return 0; |
2089 | } | 2141 | } |
2090 | 2142 | ||
@@ -2156,6 +2208,8 @@ static void ui_quirks(void) | |||
2156 | dim_offset.width = 5; | 2208 | dim_offset.width = 5; |
2157 | dim_offset.header = header_offset_tui; | 2209 | dim_offset.header = header_offset_tui; |
2158 | } | 2210 | } |
2211 | |||
2212 | dim_percent_hitm.header = percent_hitm_header[c2c.display]; | ||
2159 | } | 2213 | } |
2160 | 2214 | ||
2161 | #define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent" | 2215 | #define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent" |
@@ -2210,6 +2264,22 @@ static int setup_callchain(struct perf_evlist *evlist) | |||
2210 | return 0; | 2264 | return 0; |
2211 | } | 2265 | } |
2212 | 2266 | ||
2267 | static int setup_display(const char *str) | ||
2268 | { | ||
2269 | const char *display = str ?: "rmt"; | ||
2270 | |||
2271 | if (!strcmp(display, "rmt")) | ||
2272 | c2c.display = DISPLAY_RMT; | ||
2273 | else if (!strcmp(display, "lcl")) | ||
2274 | c2c.display = DISPLAY_LCL; | ||
2275 | else { | ||
2276 | pr_err("failed: unknown display type: %s\n", str); | ||
2277 | return -1; | ||
2278 | } | ||
2279 | |||
2280 | return 0; | ||
2281 | } | ||
2282 | |||
2213 | static int perf_c2c__report(int argc, const char **argv) | 2283 | static int perf_c2c__report(int argc, const char **argv) |
2214 | { | 2284 | { |
2215 | struct perf_session *session; | 2285 | struct perf_session *session; |
@@ -2218,6 +2288,7 @@ static int perf_c2c__report(int argc, const char **argv) | |||
2218 | .mode = PERF_DATA_MODE_READ, | 2288 | .mode = PERF_DATA_MODE_READ, |
2219 | }; | 2289 | }; |
2220 | char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT; | 2290 | char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT; |
2291 | const char *display = NULL; | ||
2221 | const struct option c2c_options[] = { | 2292 | const struct option c2c_options[] = { |
2222 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 2293 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
2223 | "file", "vmlinux pathname"), | 2294 | "file", "vmlinux pathname"), |
@@ -2236,6 +2307,7 @@ static int perf_c2c__report(int argc, const char **argv) | |||
2236 | "print_type,threshold[,print_limit],order,sort_key[,branch],value", | 2307 | "print_type,threshold[,print_limit],order,sort_key[,branch],value", |
2237 | callchain_help, &parse_callchain_opt, | 2308 | callchain_help, &parse_callchain_opt, |
2238 | callchain_default_opt), | 2309 | callchain_default_opt), |
2310 | OPT_STRING('d', "display", &display, NULL, "lcl,rmt"), | ||
2239 | OPT_END() | 2311 | OPT_END() |
2240 | }; | 2312 | }; |
2241 | int err = 0; | 2313 | int err = 0; |
@@ -2260,6 +2332,10 @@ static int perf_c2c__report(int argc, const char **argv) | |||
2260 | 2332 | ||
2261 | file.path = input_name; | 2333 | file.path = input_name; |
2262 | 2334 | ||
2335 | err = setup_display(display); | ||
2336 | if (err) | ||
2337 | goto out; | ||
2338 | |||
2263 | err = c2c_hists__init(&c2c.hists, "dcacheline", 2); | 2339 | err = c2c_hists__init(&c2c.hists, "dcacheline", 2); |
2264 | if (err) { | 2340 | if (err) { |
2265 | pr_debug("Failed to initialize hists\n"); | 2341 | pr_debug("Failed to initialize hists\n"); |
@@ -2307,7 +2383,7 @@ static int perf_c2c__report(int argc, const char **argv) | |||
2307 | "tot_loads," | 2383 | "tot_loads," |
2308 | "ld_fbhit,ld_l1hit,ld_l2hit," | 2384 | "ld_fbhit,ld_l1hit,ld_l2hit," |
2309 | "ld_lclhit,ld_rmthit", | 2385 | "ld_lclhit,ld_rmthit", |
2310 | "rmt_hitm" | 2386 | c2c.display == DISPLAY_LCL ? "lcl_hitm" : "rmt_hitm" |
2311 | ); | 2387 | ); |
2312 | 2388 | ||
2313 | ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting..."); | 2389 | ui_progress__init(&prog, c2c.hists.hists.nr_entries, "Sorting..."); |