From 5a1a99cd2e4e15571a74f65facf05f806d5303fd Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 6 Jan 2016 16:59:02 +0100 Subject: [PATCH] perf c2c report: Add main TUI browser Add the main cachelines TUI browser. It allows to navigate through cachelines and display their details and callchains (implemented in the following patches). Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Andi Kleen Cc: David Ahern Cc: Don Zickus Cc: Joe Mario Cc: Kim Phillips Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-pk632k4h1uwc5t0lqc7k61zg@git.kernel.org Link: http://lkml.kernel.org/r/20161021001706.GB23970@krava [ Handle file with no entries, fixing segfault reported by Kim Phillips ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-c2c.c | 117 ++++++++++++++++++++++++++++++++- tools/perf/ui/browsers/hists.c | 2 +- tools/perf/ui/browsers/hists.h | 1 + 3 files changed, 117 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 33db26c6ca63..34da2a3975b0 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -14,6 +14,7 @@ #include "data.h" #include "sort.h" #include +#include "ui/browsers/hists.h" struct c2c_hists { struct hists hists; @@ -53,6 +54,7 @@ struct perf_c2c { int node_info; bool show_src; + bool use_stdio; }; static struct perf_c2c c2c; @@ -657,6 +659,10 @@ percent_color(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, c2c_he = container_of(he, struct c2c_hist_entry, he); per = get_percent(c2c_he); +#ifdef HAVE_SLANG_SUPPORT + if (use_browser) + return __hpp__slsmg_color_printf(hpp, "%*.2f%%", width - 1, per); +#endif return hpp_color_scnprintf(hpp, "%*.2f%%", width - 1, per); } @@ -1077,6 +1083,8 @@ static struct c2c_dimension dim_dcacheline = { .width = 18, }; +static struct c2c_header header_offset_tui = HEADER_LOW("Off"); + static struct c2c_dimension dim_offset = { .header = HEADER_BOTH("Data address", "Offset"), .name = "offset", @@ -1803,6 +1811,100 @@ static void perf_c2c__hists_fprintf(FILE *out) print_pareto(out); } +#ifdef HAVE_SLANG_SUPPORT +static void c2c_browser__update_nr_entries(struct hist_browser *hb) +{ + u64 nr_entries = 0; + struct rb_node *nd = rb_first(&hb->hists->entries); + + while (nd) { + struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); + + if (!he->filtered) + nr_entries++; + + nd = rb_next(nd); + } + + hb->nr_non_filtered_entries = nr_entries; +} + +static int perf_c2c_browser__title(struct hist_browser *browser, + char *bf, size_t size) +{ + scnprintf(bf, size, + "Shared Data Cache Line Table " + "(%lu entries)", browser->nr_non_filtered_entries); + return 0; +} + +static struct hist_browser* +perf_c2c_browser__new(struct hists *hists) +{ + struct hist_browser *browser = hist_browser__new(hists); + + if (browser) { + browser->title = perf_c2c_browser__title; + browser->c2c_filter = true; + } + + return browser; +} + +static int perf_c2c__hists_browse(struct hists *hists) +{ + struct hist_browser *browser; + int key = -1; + + browser = perf_c2c_browser__new(hists); + if (browser == NULL) + return -1; + + /* reset abort key so that it can get Ctrl-C as a key */ + SLang_reset_tty(); + SLang_init_tty(0, 0, 0); + + c2c_browser__update_nr_entries(browser); + + while (1) { + key = hist_browser__run(browser, "help"); + + switch (key) { + case 'q': + goto out; + default: + break; + } + } + +out: + hist_browser__delete(browser); + return 0; +} + +static void perf_c2c_display(void) +{ + if (c2c.use_stdio) + perf_c2c__hists_fprintf(stdout); + else + perf_c2c__hists_browse(&c2c.hists.hists); +} +#else +static void perf_c2c_display(void) +{ + use_browser = 0; + perf_c2c__hists_fprintf(stdout); +} +#endif /* HAVE_SLANG_SUPPORT */ + +static void ui_quirks(void) +{ + if (!c2c.use_stdio) { + dim_offset.width = 5; + dim_offset.header = header_offset_tui; + } +} + static int perf_c2c__report(int argc, const char **argv) { struct perf_session *session; @@ -1819,6 +1921,9 @@ static int perf_c2c__report(int argc, const char **argv) "the input file to process"), OPT_INCR('N', "node-info", &c2c.node_info, "show extra node info in report (repeat for more info)"), +#ifdef HAVE_SLANG_SUPPORT + OPT_BOOLEAN(0, "stdio", &c2c.use_stdio, "Use the stdio interface"), +#endif OPT_END() }; int err = 0; @@ -1828,6 +1933,13 @@ static int perf_c2c__report(int argc, const char **argv) if (argc) usage_with_options(report_c2c_usage, c2c_options); + if (c2c.use_stdio) + use_browser = 0; + else + use_browser = 1; + + setup_browser(false); + if (!input_name || !strlen(input_name)) input_name = "perf.data"; @@ -1886,8 +1998,9 @@ static int perf_c2c__report(int argc, const char **argv) ui_progress__finish(); - use_browser = 0; - perf_c2c__hists_fprintf(stdout); + ui_quirks(); + + perf_c2c_display(); out_session: perf_session__delete(session); diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 4ffff7be9299..31d6d5a7c2dc 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -30,7 +30,7 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd, static bool hist_browser__has_filter(struct hist_browser *hb) { - return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter; + return hists__has_filter(hb->hists) || hb->min_pcnt || symbol_conf.has_filter || hb->c2c_filter; } static int hist_browser__get_folding(struct hist_browser *browser) diff --git a/tools/perf/ui/browsers/hists.h b/tools/perf/ui/browsers/hists.h index 39bd0f28f211..23d6acb84800 100644 --- a/tools/perf/ui/browsers/hists.h +++ b/tools/perf/ui/browsers/hists.h @@ -18,6 +18,7 @@ struct hist_browser { u64 nr_non_filtered_entries; u64 nr_hierarchy_entries; u64 nr_callchain_rows; + bool c2c_filter; /* Get title string. */ int (*title)(struct hist_browser *browser,