Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932863AbdCIRng (ORCPT ); Thu, 9 Mar 2017 12:43:36 -0500 Received: from mail-pg0-f67.google.com ([74.125.83.67]:34540 "EHLO mail-pg0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932756AbdCIRnT (ORCPT ); Thu, 9 Mar 2017 12:43:19 -0500 From: Taeung Song To: Arnaldo Carvalho de Melo Cc: linux-kernel@vger.kernel.org, Jiri Olsa , Namhyung Kim , Ingo Molnar , Peter Zijlstra , Wang Nan , Masami Hiramatsu , Taeung Song , Jiri Olsa Subject: [PATCH v3 7/7] perf annotate: Support the new source code view for TUI Date: Fri, 10 Mar 2017 02:35:41 +0900 Message-Id: <1489080941-3965-8-git-send-email-treeze.taeung@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1489080941-3965-1-git-send-email-treeze.taeung@gmail.com> References: <1489080941-3965-1-git-send-email-treeze.taeung@gmail.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 15765 Lines: 485 To make source code view more readable, add the new source code view for TUI instead of confusing mixed source code & dissambly view. This view can show source code per symbol(function). and it can be toggled by a 's' key. And support 'k' and 't' key for line numbers and total period. For example, if target symbol is 'hex2u64' of util/util.c Before: | Disassembly of section .text: | | 000000000053ef9e : | hex2u64(): | /* | * While we find nice hex chars, build a long_val. | * Return number of chars processed. | */ | int hex2u64(const char *ptr, u64 *long_val) | { | push %rbp 1.79 | mov %rsp,%rbp | sub $0x30,%rsp After: | * While we find nice hex chars, build a long_val. | * Return number of chars processed. | */ | int hex2u64(const char *ptr, u64 *long_val) 1.79 | { | const char *p = ptr; | *long_val = 0; | 28.57 | while (*p) { 30.36 | const int hex_val = hex(*p); | 12.50 | if (hex_val < 0) | break; | 23.21 | *long_val = (*long_val << 4) | hex_val; | p++; | } | 1.79 | return p - ptr; Cc: Namhyung Kim Cc: Jiri Olsa Signed-off-by: Taeung Song --- tools/perf/Documentation/perfconfig.example | 1 - tools/perf/ui/browsers/annotate.c | 233 ++++++++++++++++++++-------- tools/perf/util/annotate.c | 10 +- tools/perf/util/annotate.h | 7 + 4 files changed, 180 insertions(+), 71 deletions(-) diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example index 2b477c1..c9fc41b 100644 --- a/tools/perf/Documentation/perfconfig.example +++ b/tools/perf/Documentation/perfconfig.example @@ -23,7 +23,6 @@ [annotate] # Defaults - hide_src_code = false use_offset = true jump_arrows = true show_nr_jumps = false diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 03b2012..ac01d75 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -27,8 +27,7 @@ struct browser_disasm_line { }; static struct annotate_browser_opt { - bool hide_src_code, - use_offset, + bool use_offset, jump_arrows, show_linenr, show_nr_jumps, @@ -39,7 +38,7 @@ static struct annotate_browser_opt { }; 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; @@ -52,6 +51,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; @@ -68,12 +68,9 @@ static inline struct browser_disasm_line *disasm_line__browser(struct disasm_lin static bool disasm_line__filter(struct ui_browser *browser __maybe_unused, void *entry) { - if (annotate_browser__opts.hide_src_code) { - struct disasm_line *dl = list_entry(entry, struct disasm_line, node); - return dl->offset == -1; - } + struct disasm_line *dl = list_entry(entry, struct disasm_line, node); - return false; + return dl->offset == -1; } static int annotate_browser__jumps_percent_color(struct annotate_browser *browser, @@ -104,15 +101,61 @@ 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(' '); + + if (annotate_browser__opts.show_linenr) + printed = scnprintf(line, sizeof(line), "%-*d ", + ab->addr_width + 2, cl->line_nr); + else + printed = scnprintf(line, sizeof(line), "%*s ", + ab->addr_width, " "); + + 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); struct disasm_line *dl = list_entry(entry, struct disasm_line, node); struct browser_disasm_line *bdl = disasm_line__browser(dl); bool current_entry = ui_browser__is_current_entry(browser, row); - bool change_color = (!annotate_browser__opts.hide_src_code && - (!current_entry || (browser->use_navkeypressed && - !browser->navkeypressed))); + bool change_color = !current_entry || (browser->use_navkeypressed && + !browser->navkeypressed); int width = browser->width, printed; int i, pcnt_width = annotate_browser__pcnt_width(ab); double percent_max = 0.0; @@ -271,19 +314,25 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) bcursor = disasm_line__browser(cursor); btarget = disasm_line__browser(target); - if (annotate_browser__opts.hide_src_code) { - from = bcursor->idx_asm; - to = btarget->idx_asm; - } else { - from = (u64)bcursor->idx; - to = (u64)btarget->idx; - } + from = bcursor->idx_asm; + to = btarget->idx_asm; ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS); __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width, 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); @@ -364,12 +413,37 @@ static void annotate_browser__set_rb_top(struct annotate_browser *browser, bpos = rb_entry(nd, struct browser_disasm_line, rb_node); pos = ((struct disasm_line *)bpos) - 1; idx = bpos->idx; - if (annotate_browser__opts.hide_src_code) - idx = bpos->idx_asm; + idx = bpos->idx_asm; annotate_browser__set_top(browser, pos, idx); 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(¬es->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_arr[i], notes, evsel); + } + } + + pthread_mutex_unlock(¬es->lock); +} + static void annotate_browser__calc_percent(struct annotate_browser *browser, struct perf_evsel *evsel) { @@ -422,45 +496,6 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, browser->curr_hot = rb_last(&browser->entries); } -static bool annotate_browser__toggle_source(struct annotate_browser *browser) -{ - struct disasm_line *dl; - struct browser_disasm_line *bdl; - off_t offset = browser->b.index - browser->b.top_idx; - - browser->b.seek(&browser->b, offset, SEEK_CUR); - dl = list_entry(browser->b.top, struct disasm_line, node); - bdl = disasm_line__browser(dl); - - if (annotate_browser__opts.hide_src_code) { - if (bdl->idx_asm < offset) - offset = bdl->idx; - - browser->b.nr_entries = browser->nr_entries; - annotate_browser__opts.hide_src_code = false; - browser->b.seek(&browser->b, -offset, SEEK_CUR); - browser->b.top_idx = bdl->idx - offset; - browser->b.index = bdl->idx; - } else { - if (bdl->idx_asm < 0) { - ui_helpline__puts("Only available for assembly lines."); - browser->b.seek(&browser->b, -offset, SEEK_CUR); - return false; - } - - if (bdl->idx_asm < offset) - offset = bdl->idx_asm; - - browser->b.nr_entries = browser->nr_asm_entries; - annotate_browser__opts.hide_src_code = true; - browser->b.seek(&browser->b, -offset, SEEK_CUR); - browser->b.top_idx = bdl->idx_asm - offset; - browser->b.index = bdl->idx_asm; - } - - return true; -} - static void annotate_browser__init_asm_mode(struct annotate_browser *browser) { ui_browser__reset_index(&browser->b); @@ -696,6 +731,54 @@ 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" + "s Toggle source code view\n" + "t Toggle total period view\n" + "k Toggle line numbers\n"); + continue; + case 't': + annotate_browser__opts.show_total_period = + !annotate_browser__opts.show_total_period; + continue; + case 'k': + annotate_browser__opts.show_linenr = + !annotate_browser__opts.show_linenr; + continue; + case 's': + 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) @@ -775,7 +858,6 @@ static int annotate_browser__run(struct annotate_browser *browser, "s Toggle source code view\n" "t Toggle total period view\n" "/ Search string\n" - "k Toggle line numbers\n" "r Run available scripts\n" "? Search string backwards\n"); continue; @@ -792,8 +874,11 @@ static int annotate_browser__run(struct annotate_browser *browser, nd = browser->curr_hot; break; case 's': - if (annotate_browser__toggle_source(browser)) - ui_helpline__puts(help); + 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; @@ -1095,9 +1180,27 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ - if (annotate_browser__opts.hide_src_code) - annotate_browser__init_asm_mode(&browser); + 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++; + } + } + annotate_browser__init_asm_mode(&browser); annotate_browser__update_addr_width(&browser); ret = annotate_browser__run(&browser, evsel, hbt); @@ -1105,6 +1208,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); @@ -1121,7 +1225,6 @@ static struct annotate_config { const char *name; bool *value; } annotate__configs[] = { - ANNOTATE_CFG(hide_src_code), ANNOTATE_CFG(jump_arrows), ANNOTATE_CFG(show_linenr), ANNOTATE_CFG(show_nr_jumps), diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 7d1c7cc..d8a3a50 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1396,7 +1396,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; @@ -1410,8 +1410,8 @@ 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, - struct annotation *notes, struct perf_evsel *evsel) +void code_line__sum_samples(struct code_line *cl, struct disasm_line *dl, + struct annotation *notes, struct perf_evsel *evsel) { int i; u64 nr_samples; @@ -1569,8 +1569,8 @@ static int source_code__collect(struct source_code *code, return ret; } -static int symbol__get_source_code(struct symbol *sym, struct map *map, - struct perf_evsel *evsel) +int symbol__get_source_code(struct symbol *sym, struct map *map, + struct perf_evsel *evsel) { struct annotation *notes = symbol__annotation(sym); struct source_code *code; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index dd7ddae..e125eca 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -109,6 +109,9 @@ struct code_line { struct disasm_line_samples *samples_sum; }; +void code_line__sum_samples(struct code_line *cl, struct disasm_line *dl, + struct annotation *notes, struct perf_evsel *evsel); + struct source_code { char *path; int nr_events; @@ -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); enum symbol_disassemble_errno { -- 2.7.4