[PATCH/RFC 2/4] perf annotate: Add new source code view to the annotate TUI browser

From: Taeung Song
Date: Tue Jun 27 2017 - 23:14:35 EST


Unlike asm code level, the new source code view
provides a additional viewpoint based on source code level
for performance analysis.

Of course, current disassembly view can show itself with pieces of source code
but some users want to check the result of performance analysis
based on full source code view. So add this view to the annotate TUI browser.

Users can switch to the new source code view by a 'S' key
and additionally support a 't' key toggling total period view.

Suggested-by: Namhyung Kim <namhyung@xxxxxxxxxx>
Cc: Milian Wolff <milian.wolff@xxxxxxxx>
Cc: Jiri Olsa <jolsa@xxxxxxxxxx>
Cc: Masami Hiramatsu <mhiramat@xxxxxxxxxx>
Cc: Adrian Hunter <adrian.hunter@xxxxxxxxx>
Cc: Wang Nan <wangnan0@xxxxxxxxxx>
Cc: Jin Yao <yao.jin@xxxxxxxxxxxxxxx>
Cc: Andi Kleen <ak@xxxxxxxxxxxxxxx>
Cc: Kim Phillips <kim.phillips@xxxxxxx>
Cc: David Ahern <dsahern@xxxxxxxxx>
Signed-off-by: Taeung Song <treeze.taeung@xxxxxxxxx>
---
tools/perf/ui/browsers/annotate.c | 153 +++++++++++++++++++++++++++++++++++++-
tools/perf/util/annotate.c | 6 +-
tools/perf/util/annotate.h | 7 ++
3 files changed, 161 insertions(+), 5 deletions(-)

diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index b075a32..028febe 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -44,7 +44,7 @@ static struct annotate_browser_opt {
struct arch;

struct annotate_browser {
- struct ui_browser b;
+ struct ui_browser b, cb;
struct rb_root entries;
struct rb_node *curr_hot;
struct disasm_line *selection;
@@ -58,6 +58,7 @@ struct annotate_browser {
int nr_jumps;
bool searching_backwards;
bool have_cycles;
+ bool has_src_code;
u8 addr_width;
u8 jumps_width;
u8 target_width;
@@ -110,6 +111,49 @@ static int annotate_browser__pcnt_width(struct annotate_browser *ab)
return w;
}

+static void annotate_code_browser__write(struct ui_browser *browser, void *entry, int row)
+{
+ struct annotate_browser *ab = container_of(browser, struct annotate_browser, cb);
+ struct code_line *cl = list_entry(entry, struct code_line, node);
+ bool current_entry = ui_browser__is_current_entry(browser, row);
+ int i, printed;
+ double percent, max_percent = 0.0;
+ char line[256];
+
+ for (i = 0; i < ab->nr_events; i++) {
+ if (cl->samples_sum[i].percent > max_percent)
+ max_percent = cl->samples_sum[i].percent;
+ }
+
+ for (i = 0; i < ab->nr_events; i++) {
+ if (max_percent == 0.0) {
+ ui_browser__set_percent_color(browser, 0, current_entry);
+ ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
+ break;
+ }
+
+ percent = cl->samples_sum[i].percent;
+ ui_browser__set_percent_color(browser, percent, current_entry);
+
+ if (annotate_browser__opts.show_total_period)
+ ui_browser__printf(browser, "%6" PRIu64 " ",
+ cl->samples_sum[i].nr);
+ else
+ ui_browser__printf(browser, "%6.2f ", percent);
+
+ if (max_percent < percent)
+ max_percent = percent;
+ }
+
+ SLsmg_write_char(' ');
+
+ printed = scnprintf(line, sizeof(line), "%-*d ",
+ ab->addr_width + 2, cl->line_nr);
+
+ ui_browser__write_nstring(browser, line, printed);
+ ui_browser__write_nstring(browser, cl->line, browser->width);
+}
+
static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
{
struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
@@ -304,6 +348,17 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
from, to);
}

+static unsigned int annotate_code_browser__refresh(struct ui_browser *browser)
+{
+ struct annotate_browser *ab = container_of(browser, struct annotate_browser, cb);
+ int ret = ui_browser__list_head_refresh(browser);
+ int pcnt_width = annotate_browser__pcnt_width(ab);
+
+ ui_browser__set_color(browser, HE_COLORSET_NORMAL);
+ __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
+ return ret;
+}
+
static unsigned int annotate_browser__refresh(struct ui_browser *browser)
{
struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
@@ -390,6 +445,31 @@ static void annotate_browser__set_rb_top(struct annotate_browser *browser,
browser->curr_hot = nd;
}

+static void annotate_code_browser__calc_percent(struct annotate_browser *browser,
+ struct perf_evsel *evsel)
+{
+ int i;
+ struct map_symbol *ms = browser->b.priv;
+ struct symbol *sym = ms->sym;
+ struct annotation *notes = symbol__annotation(sym);
+ struct code_line *cl;
+ struct list_head *code_lines = browser->cb.entries;
+
+ pthread_mutex_lock(&notes->lock);
+
+ list_for_each_entry(cl, code_lines, node) {
+ for (i = 0; i < browser->nr_events; i++) {
+ cl->samples_sum[i].percent = 0.0;
+ cl->samples_sum[i].nr = 0;
+ }
+
+ for (i = 0; i < cl->nr_matched_dl; i++)
+ code_line__sum_samples(cl, cl->matched_dl[i], notes, evsel);
+ }
+
+ pthread_mutex_unlock(&notes->lock);
+}
+
static void annotate_browser__calc_percent(struct annotate_browser *browser,
struct perf_evsel *evsel)
{
@@ -716,6 +796,46 @@ static void annotate_browser__update_addr_width(struct annotate_browser *browser
browser->addr_width += browser->jumps_width + 1;
}

+static int annotate_code_browser__run(struct annotate_browser *browser,
+ struct perf_evsel *evsel, int delay_secs)
+{
+ int key;
+
+ if (ui_browser__show(&browser->cb, browser->cb.title, ui_helpline__current) < 0)
+ return -1;
+ annotate_code_browser__calc_percent(browser, evsel);
+
+ while (1) {
+
+ key = ui_browser__run(&browser->cb, delay_secs);
+ if (delay_secs != 0)
+ annotate_code_browser__calc_percent(browser, evsel);
+
+ switch (key) {
+ case K_F1:
+ case 'h':
+ ui_browser__help_window(&browser->cb,
+ "UP/DOWN/PGUP\n"
+ "PGDN/SPACE Navigate\n"
+ "q/ESC/CTRL+C Return to dissembly view\n\n"
+ "t Toggle total period view\n");
+ continue;
+ case 't':
+ annotate_browser__opts.show_total_period =
+ !annotate_browser__opts.show_total_period;
+ continue;
+ case K_LEFT:
+ case K_ESC:
+ case 'q':
+ case CTRL('c'):
+ return 0;
+ default:
+ continue;
+ }
+ }
+ return 0;
+}
+
static int annotate_browser__run(struct annotate_browser *browser,
struct perf_evsel *evsel,
struct hist_browser_timer *hbt)
@@ -792,7 +912,8 @@ static int annotate_browser__run(struct annotate_browser *browser,
"J Toggle showing number of jump sources on targets\n"
"n Search next string\n"
"o Toggle disassembler output/simplified view\n"
- "s Toggle source code view\n"
+ "s Toggle pieces of source code view\n"
+ "S Switch to full source code view\n"
"t Toggle total period view\n"
"/ Search string\n"
"k Toggle line numbers\n"
@@ -815,6 +936,13 @@ static int annotate_browser__run(struct annotate_browser *browser,
if (annotate_browser__toggle_source(browser))
ui_helpline__puts(help);
continue;
+ case 'S':
+ if (browser->has_src_code) {
+ browser->cb.title = title;
+ annotate_code_browser__run(browser, evsel, delay_secs);
+ } else
+ ui_helpline__puts("No source code for the symbol");
+ continue;
case 'o':
annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
annotate_browser__update_addr_width(browser);
@@ -1116,6 +1244,26 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
browser.b.entries = &notes->src->source,
browser.b.width += 18; /* Percentage */

+ if (symbol__get_source_code(sym, map, evsel) == 0) {
+ struct source_code *code = notes->src->code;
+ struct code_line *cl;
+
+ browser.has_src_code = true;
+ browser.cb.refresh = annotate_code_browser__refresh;
+ browser.cb.seek = ui_browser__list_head_seek;
+ browser.cb.write = annotate_code_browser__write;
+ browser.cb.use_navkeypressed = true;
+ browser.cb.entries = &code->lines;
+
+ list_for_each_entry(cl, &code->lines, node) {
+ size_t line_len = strlen(cl->line);
+
+ if (browser.cb.width < line_len)
+ browser.cb.width = line_len;
+ browser.cb.nr_entries++;
+ }
+ }
+
if (annotate_browser__opts.hide_src_code)
annotate_browser__init_asm_mode(&browser);

@@ -1126,6 +1274,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map,
list_del(&pos->node);
disasm_line__free(pos);
}
+ symbol__free_source_code(sym);

out_free_offsets:
free(browser.offsets);
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 4108520..667277a 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -1419,7 +1419,7 @@ static void code_lines__free(struct list_head *code_lines)
}
}

-static int symbol__free_source_code(struct symbol *sym)
+int symbol__free_source_code(struct symbol *sym)
{
struct annotation *notes = symbol__annotation(sym);
struct source_code *code = notes->src->code;
@@ -1433,7 +1433,7 @@ static int symbol__free_source_code(struct symbol *sym)
return 0;
}

-static void code_line__sum_samples(struct code_line *cl, struct disasm_line *dl,
+void code_line__sum_samples(struct code_line *cl, struct disasm_line *dl,
struct annotation *notes, struct perf_evsel *evsel)
{
int i;
@@ -1596,7 +1596,7 @@ static int source_code__collect(struct symbol *sym, struct map *map,
return ret;
}

-static int symbol__get_source_code(struct symbol *sym, struct map *map,
+int symbol__get_source_code(struct symbol *sym, struct map *map,
struct perf_evsel *evsel)
{
int start_linenr, end_linenr, ret = -1;
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 3513807..fb352cf 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -128,6 +128,9 @@ struct source_line {
struct source_line_samples samples[1];
};

+void code_line__sum_samples(struct code_line *cl, struct disasm_line *dl,
+ struct annotation *notes, struct perf_evsel *evsel);
+
/** struct annotated_source - symbols with hits have this attached as in sannotation
*
* @histogram: Array of addr hit histograms per event being monitored
@@ -180,6 +183,10 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr);
int symbol__alloc_hist(struct symbol *sym);
void symbol__annotate_zero_histograms(struct symbol *sym);

+int symbol__free_source_code(struct symbol *sym);
+int symbol__get_source_code(struct symbol *sym, struct map *map,
+ struct perf_evsel *evsel);
+
int symbol__disassemble(struct symbol *sym, struct map *map,
const char *arch_name, size_t privsize,
struct arch **parch);
--
2.7.4