From 640d5175a671cd0df0b9e3b5935dc80fc5248973 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 3 Nov 2017 15:13:29 -0300 Subject: perf evlist: Set the correct idx when adding dummy events The evsel->idx field is used mainly to access the right bucket in per-event arrays such as the annotation ones, but also to set evsel->tracking, that in turn will decide what of the events will ask for PERF_RECORD_{MMAP,COMM,EXEC} to be generated, i.e. which perf_event_attr will have its mmap, etc fields set. When we were adding the "dummy" event using perf_evlist__add_dummy() we were not setting it correctly, which could result in multiple tracking events. Now that I'll try using a dummy event to be the tracking one when using 'perf record --delay', i.e. when we process the --delay setting we may already have the evlist set up, like with: perf record -e cycles,instructions --delay 1000 ./workload We will need to add a "dummy" event, then reset evsel->tracking for the first event, "cycles", and set it instead to the dummy one, and also setting its attr.enable_on_exec, so that we get the PERF_RECORD_MMAP, etc metadata events while waiting to enable the explicitely requested events, so lets get this straight and set the right evsel->idx. Cc: Adrian Hunter Cc: Bram Stolk Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-nrdfchshqxf7diszhxcecqb9@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index c6c891e154a6..ccb749f9a83f 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -257,7 +257,7 @@ int perf_evlist__add_dummy(struct perf_evlist *evlist) .config = PERF_COUNT_SW_DUMMY, .size = sizeof(attr), /* to capture ABI version */ }; - struct perf_evsel *evsel = perf_evsel__new(&attr); + struct perf_evsel *evsel = perf_evsel__new_idx(&attr, evlist->nr_entries); if (evsel == NULL) return -ENOMEM; -- cgit v1.2.3 From a17c4ca0ddef659d33fb6661995bd74e1a6a6101 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:25 +0200 Subject: perf annotate: Add annotation_line struct In order to make the annotation support generic, addadding 'struct annotation_line', which will hold generic data common to annotation sources (such as the one for python scripts, coming on upcoming patches). Having this, we can add different annotation line support other than objdump disasm. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-3-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 34 +++++++++++++++++----------------- tools/perf/ui/gtk/annotate.c | 6 +++--- tools/perf/util/annotate.c | 20 ++++++++++---------- tools/perf/util/annotate.h | 20 ++++++++++++-------- 4 files changed, 42 insertions(+), 38 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 8f7f59d1a2b5..a8c2f7405a41 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -84,7 +84,7 @@ 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); + struct disasm_line *dl = list_entry(entry, struct disasm_line, al.node); return dl->offset == -1; } @@ -123,7 +123,7 @@ static int annotate_browser__cycles_width(struct annotate_browser *ab) 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 disasm_line *dl = list_entry(entry, struct disasm_line, al.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 && @@ -286,7 +286,7 @@ static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sy static bool is_fused(struct annotate_browser *ab, struct disasm_line *cursor) { - struct disasm_line *pos = list_prev_entry(cursor, node); + struct disasm_line *pos = list_prev_entry(cursor, al.node); const char *name; if (!pos) @@ -404,16 +404,16 @@ static void annotate_browser__set_top(struct annotate_browser *browser, browser->b.top_idx = browser->b.index = idx; while (browser->b.top_idx != 0 && back != 0) { - pos = list_entry(pos->node.prev, struct disasm_line, node); + pos = list_entry(pos->al.node.prev, struct disasm_line, al.node); - if (disasm_line__filter(&browser->b, &pos->node)) + if (disasm_line__filter(&browser->b, &pos->al.node)) continue; --browser->b.top_idx; --back; } - browser->b.top = pos; + browser->b.top = &pos->al; browser->b.navkeypressed = true; } @@ -446,7 +446,7 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, pthread_mutex_lock(¬es->lock); - list_for_each_entry(pos, ¬es->src->source, node) { + list_for_each_entry(pos, ¬es->src->source, al.node) { struct browser_disasm_line *bpos = disasm_line__browser(pos); const char *path = NULL; double max_percent = 0.0; @@ -492,7 +492,7 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser) 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); + dl = list_entry(browser->b.top, struct disasm_line, al.node); bdl = disasm_line__browser(dl); if (annotate_browser__opts.hide_src_code) { @@ -589,10 +589,10 @@ struct disasm_line *annotate_browser__find_offset(struct annotate_browser *brows struct disasm_line *pos; *idx = 0; - list_for_each_entry(pos, ¬es->src->source, node) { + list_for_each_entry(pos, ¬es->src->source, al.node) { if (pos->offset == offset) return pos; - if (!disasm_line__filter(&browser->b, &pos->node)) + if (!disasm_line__filter(&browser->b, &pos->al.node)) ++*idx; } @@ -630,8 +630,8 @@ struct disasm_line *annotate_browser__find_string(struct annotate_browser *brows struct disasm_line *pos = browser->selection; *idx = browser->b.index; - list_for_each_entry_continue(pos, ¬es->src->source, node) { - if (disasm_line__filter(&browser->b, &pos->node)) + list_for_each_entry_continue(pos, ¬es->src->source, al.node) { + if (disasm_line__filter(&browser->b, &pos->al.node)) continue; ++*idx; @@ -669,8 +669,8 @@ struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browse struct disasm_line *pos = browser->selection; *idx = browser->b.index; - list_for_each_entry_continue_reverse(pos, ¬es->src->source, node) { - if (disasm_line__filter(&browser->b, &pos->node)) + list_for_each_entry_continue_reverse(pos, ¬es->src->source, al.node) { + if (disasm_line__filter(&browser->b, &pos->al.node)) continue; --*idx; @@ -1134,7 +1134,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, notes = symbol__annotation(sym); browser.start = map__rip_2objdump(map, sym->start); - list_for_each_entry(pos, ¬es->src->source, node) { + list_for_each_entry(pos, ¬es->src->source, al.node) { struct browser_disasm_line *bpos; size_t line_len = strlen(pos->line); @@ -1174,8 +1174,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, annotate_browser__update_addr_width(&browser); ret = annotate_browser__run(&browser, evsel, hbt); - list_for_each_entry_safe(pos, n, ¬es->src->source, node) { - list_del(&pos->node); + list_for_each_entry_safe(pos, n, ¬es->src->source, al.node) { + list_del(&pos->al.node); disasm_line__free(pos); } diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index fc7a2e105bfd..cf8092676c7a 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c @@ -119,7 +119,7 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); g_object_unref(GTK_TREE_MODEL(store)); - list_for_each_entry(pos, ¬es->src->source, node) { + list_for_each_entry(pos, ¬es->src->source, al.node) { GtkTreeIter iter; int ret = 0; @@ -148,8 +148,8 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, gtk_container_add(GTK_CONTAINER(window), view); - list_for_each_entry_safe(pos, n, ¬es->src->source, node) { - list_del(&pos->node); + list_for_each_entry_safe(pos, n, ¬es->src->source, al.node) { + list_del(&pos->al.node); disasm_line__free(pos); } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index da1c4c4a0dd8..004e33dc897c 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -931,12 +931,12 @@ int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool r static void disasm__add(struct list_head *head, struct disasm_line *line) { - list_add_tail(&line->node, head); + list_add_tail(&line->al.node, head); } struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos) { - list_for_each_entry_continue(pos, head, node) + list_for_each_entry_continue(pos, head, al.node) if (pos->offset >= 0) return pos; @@ -1122,7 +1122,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st return 1; if (queue != NULL) { - list_for_each_entry_from(queue, ¬es->src->source, node) { + list_for_each_entry_from(queue, ¬es->src->source, al.node) { if (queue == dl) break; disasm_line__print(queue, sym, start, evsel, len, @@ -1305,7 +1305,7 @@ static void delete_last_nop(struct symbol *sym) struct disasm_line *dl; while (!list_empty(list)) { - dl = list_entry(list->prev, struct disasm_line, node); + dl = list_entry(list->prev, struct disasm_line, al.node); if (dl->ins.ops) { if (dl->ins.ops != &nop_ops) @@ -1317,7 +1317,7 @@ static void delete_last_nop(struct symbol *sym) return; } - list_del(&dl->node); + list_del(&dl->al.node); disasm_line__free(dl); } } @@ -1844,7 +1844,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, if (verbose > 0) symbol__annotate_hits(sym, evsel); - list_for_each_entry(pos, ¬es->src->source, node) { + list_for_each_entry(pos, ¬es->src->source, al.node) { if (context && queue == NULL) { queue = pos; queue_len = 0; @@ -1874,7 +1874,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, if (!context) break; if (queue_len == context) - queue = list_entry(queue->node.next, typeof(*queue), node); + queue = list_entry(queue->al.node.next, typeof(*queue), al.node); else ++queue_len; break; @@ -1911,8 +1911,8 @@ void disasm__purge(struct list_head *head) { struct disasm_line *pos, *n; - list_for_each_entry_safe(pos, n, head, node) { - list_del(&pos->node); + list_for_each_entry_safe(pos, n, head, al.node) { + list_del(&pos->al.node); disasm_line__free(pos); } } @@ -1939,7 +1939,7 @@ size_t disasm__fprintf(struct list_head *head, FILE *fp) struct disasm_line *pos; size_t printed = 0; - list_for_each_entry(pos, head, node) + list_for_each_entry(pos, head, al.node) printed += disasm_line__fprintf(pos, fp); return printed; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index f6ba3560de5e..cc3cf6b50d55 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -59,15 +59,19 @@ bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2); struct annotation; +struct annotation_line { + struct list_head node; +}; + struct disasm_line { - struct list_head node; - s64 offset; - char *line; - struct ins ins; - int line_nr; - float ipc; - u64 cycles; - struct ins_operands ops; + struct annotation_line al; + s64 offset; + char *line; + struct ins ins; + int line_nr; + float ipc; + u64 cycles; + struct ins_operands ops; }; static inline bool disasm_line__has_offset(const struct disasm_line *dl) -- cgit v1.2.3 From d5490b9647e6e41b203186ed0d73b4103f139fda Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:26 +0200 Subject: perf annotate: Move line/offset into annotation_line struct Move the line/line_nr/offset menbers to the annotation_line struct to be used as generic members for any annotation source. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-4-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 45 ++++++++++++++++++++------------------- tools/perf/ui/gtk/annotate.c | 14 ++++++------ tools/perf/util/annotate.c | 41 ++++++++++++++++++----------------- tools/perf/util/annotate.h | 6 +++--- 4 files changed, 54 insertions(+), 52 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index a8c2f7405a41..73d921c3e3ec 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -84,8 +84,9 @@ 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, al.node); - return dl->offset == -1; + struct annotation_line *al = list_entry(entry, struct annotation_line, node); + + return al->offset == -1; } return false; @@ -141,7 +142,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int percent_max = bdl->samples[i].percent; } - if ((row == 0) && (dl->offset == -1 || percent_max == 0.0)) { + if ((row == 0) && (dl->al.offset == -1 || percent_max == 0.0)) { if (ab->have_cycles) { if (dl->ipc == 0.0 && dl->cycles == 0) show_title = true; @@ -149,7 +150,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int show_title = true; } - if (dl->offset != -1 && percent_max != 0.0) { + if (dl->al.offset != -1 && percent_max != 0.0) { for (i = 0; i < ab->nr_events; i++) { ui_browser__set_percent_color(browser, bdl->samples[i].percent, @@ -199,19 +200,19 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int if (!browser->navkeypressed) width += 1; - if (!*dl->line) + if (!*dl->al.line) ui_browser__write_nstring(browser, " ", width - pcnt_width - cycles_width); - else if (dl->offset == -1) { - if (dl->line_nr && annotate_browser__opts.show_linenr) + else if (dl->al.offset == -1) { + if (dl->al.line_nr && annotate_browser__opts.show_linenr) printed = scnprintf(bf, sizeof(bf), "%-*d ", - ab->addr_width + 1, dl->line_nr); + ab->addr_width + 1, dl->al.line_nr); else printed = scnprintf(bf, sizeof(bf), "%*s ", ab->addr_width, " "); ui_browser__write_nstring(browser, bf, printed); - ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width - cycles_width + 1); + ui_browser__write_nstring(browser, dl->al.line, width - printed - pcnt_width - cycles_width + 1); } else { - u64 addr = dl->offset; + u64 addr = dl->al.offset; int color = -1; if (!annotate_browser__opts.use_offset) @@ -247,7 +248,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int ui_browser__set_color(browser, color); if (dl->ins.ops && dl->ins.ops->scnprintf) { if (ins__is_jump(&dl->ins)) { - bool fwd = dl->ops.target.offset > dl->offset; + bool fwd = dl->ops.target.offset > dl->al.offset; ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR : SLSMG_UARROW_CHAR); @@ -452,7 +453,7 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, double max_percent = 0.0; int i; - if (pos->offset == -1) { + if (pos->al.offset == -1) { RB_CLEAR_NODE(&bpos->rb_node); continue; } @@ -464,8 +465,8 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, bpos->samples[i].percent = disasm__calc_percent(notes, evsel->idx + i, - pos->offset, - next ? next->offset : len, + pos->al.offset, + next ? next->al.offset : len, &path, &sample); bpos->samples[i].he = sample; @@ -590,7 +591,7 @@ struct disasm_line *annotate_browser__find_offset(struct annotate_browser *brows *idx = 0; list_for_each_entry(pos, ¬es->src->source, al.node) { - if (pos->offset == offset) + if (pos->al.offset == offset) return pos; if (!disasm_line__filter(&browser->b, &pos->al.node)) ++*idx; @@ -636,7 +637,7 @@ struct disasm_line *annotate_browser__find_string(struct annotate_browser *brows ++*idx; - if (pos->line && strstr(pos->line, s) != NULL) + if (pos->al.line && strstr(pos->al.line, s) != NULL) return pos; } @@ -675,7 +676,7 @@ struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browse --*idx; - if (pos->line && strstr(pos->line, s) != NULL) + if (pos->al.line && strstr(pos->al.line, s) != NULL) return pos; } @@ -901,7 +902,7 @@ show_help: case K_RIGHT: if (browser->selection == NULL) ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); - else if (browser->selection->offset == -1) + else if (browser->selection->al.offset == -1) ui_helpline__puts("Actions are only available for assembly lines."); else if (!browser->selection->ins.ops) goto show_sup_ins; @@ -1136,13 +1137,13 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, list_for_each_entry(pos, ¬es->src->source, al.node) { struct browser_disasm_line *bpos; - size_t line_len = strlen(pos->line); + size_t line_len = strlen(pos->al.line); if (browser.b.width < line_len) browser.b.width = line_len; bpos = disasm_line__browser(pos); bpos->idx = browser.nr_entries++; - if (pos->offset != -1) { + if (pos->al.offset != -1) { bpos->idx_asm = browser.nr_asm_entries++; /* * FIXME: short term bandaid to cope with assembly @@ -1151,8 +1152,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, * * E.g. copy_user_generic_unrolled */ - if (pos->offset < (s64)size) - browser.offsets[pos->offset] = pos; + if (pos->al.offset < (s64)size) + browser.offsets[pos->al.offset] = pos; } else bpos->idx_asm = -1; } diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index cf8092676c7a..162f15712d2d 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c @@ -31,14 +31,14 @@ static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym, strcpy(buf, ""); - if (dl->offset == (s64) -1) + if (dl->al.offset == (s64) -1) return 0; symhist = annotation__histogram(symbol__annotation(sym), evidx); - if (!symbol_conf.event_group && !symhist->addr[dl->offset].nr_samples) + if (!symbol_conf.event_group && !symhist->addr[dl->al.offset].nr_samples) return 0; - percent = 100.0 * symhist->addr[dl->offset].nr_samples / symhist->nr_samples; + percent = 100.0 * symhist->addr[dl->al.offset].nr_samples / symhist->nr_samples; markup = perf_gtk__get_percent_color(percent); if (markup) @@ -57,16 +57,16 @@ static int perf_gtk__get_offset(char *buf, size_t size, struct symbol *sym, strcpy(buf, ""); - if (dl->offset == (s64) -1) + if (dl->al.offset == (s64) -1) return 0; - return scnprintf(buf, size, "%"PRIx64, start + dl->offset); + return scnprintf(buf, size, "%"PRIx64, start + dl->al.offset); } static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl) { int ret = 0; - char *line = g_markup_escape_text(dl->line, -1); + char *line = g_markup_escape_text(dl->al.line, -1); const char *markup = ""; strcpy(buf, ""); @@ -74,7 +74,7 @@ static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl) if (!line) return 0; - if (dl->offset != (s64) -1) + if (dl->al.offset != (s64) -1) markup = NULL; if (markup) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 004e33dc897c..e8b69001229d 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -886,14 +886,15 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); if (dl != NULL) { - dl->offset = offset; - dl->line = strdup(line); - dl->line_nr = line_nr; - if (dl->line == NULL) + dl->al.offset = offset; + dl->al.line = strdup(line); + dl->al.line_nr = line_nr; + + if (dl->al.line == NULL) goto out_delete; if (offset != -1) { - if (disasm_line__parse(dl->line, &dl->ins.name, &dl->ops.raw) < 0) + if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0) goto out_free_line; disasm_line__init_ins(dl, arch, map); @@ -903,7 +904,7 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, return dl; out_free_line: - zfree(&dl->line); + zfree(&dl->al.line); out_delete: free(dl); return NULL; @@ -911,7 +912,7 @@ out_delete: void disasm_line__free(struct disasm_line *dl) { - zfree(&dl->line); + zfree(&dl->al.line); if (dl->ins.ops && dl->ins.ops->free) dl->ins.ops->free(&dl->ops); else @@ -937,7 +938,7 @@ static void disasm__add(struct list_head *head, struct disasm_line *line) struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos) { list_for_each_entry_continue(pos, head, al.node) - if (pos->offset >= 0) + if (pos->al.offset >= 0) return pos; return NULL; @@ -1077,7 +1078,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st static const char *prev_line; static const char *prev_color; - if (dl->offset != -1) { + if (dl->al.offset != -1) { const char *path = NULL; double percent, max_percent = 0.0; double *ppercents = &percent; @@ -1086,7 +1087,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st int i, nr_percent = 1; const char *color; struct annotation *notes = symbol__annotation(sym); - s64 offset = dl->offset; + s64 offset = dl->al.offset; const u64 addr = start + offset; struct disasm_line *next; struct block_range *br; @@ -1106,7 +1107,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st percent = disasm__calc_percent(notes, notes->src->lines ? i : evsel->idx + i, offset, - next ? next->offset : (s64) len, + next ? next->al.offset : (s64) len, &path, &sample); ppercents[i] = percent; @@ -1165,7 +1166,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st br = block_range__find(addr); color_fprintf(stdout, annotate__address_color(br), " %" PRIx64 ":", addr); - color_fprintf(stdout, annotate__asm_color(br), "%s", dl->line); + color_fprintf(stdout, annotate__asm_color(br), "%s", dl->al.line); annotate__branch_printf(br, addr); printf("\n"); @@ -1186,10 +1187,10 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st if (perf_evsel__is_group_event(evsel)) width *= evsel->nr_members; - if (!*dl->line) + if (!*dl->al.line) printf(" %*s:\n", width, " "); else - printf(" %*s: %s\n", width, " ", dl->line); + printf(" %*s: %s\n", width, " ", dl->al.line); } return 0; @@ -1311,9 +1312,9 @@ static void delete_last_nop(struct symbol *sym) if (dl->ins.ops != &nop_ops) return; } else { - if (!strstr(dl->line, " nop ") && - !strstr(dl->line, " nopl ") && - !strstr(dl->line, " nopw ")) + if (!strstr(dl->al.line, " nop ") && + !strstr(dl->al.line, " nopl ") && + !strstr(dl->al.line, " nopw ")) return; } @@ -1921,10 +1922,10 @@ static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp) { size_t printed; - if (dl->offset == -1) - return fprintf(fp, "%s\n", dl->line); + if (dl->al.offset == -1) + return fprintf(fp, "%s\n", dl->al.line); - printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->ins.name); + printed = fprintf(fp, "%#" PRIx64 " %s", dl->al.offset, dl->ins.name); if (dl->ops.raw[0] != '\0') { printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ", diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index cc3cf6b50d55..b7ca62855760 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -61,14 +61,14 @@ struct annotation; struct annotation_line { struct list_head node; + s64 offset; + char *line; + int line_nr; }; struct disasm_line { struct annotation_line al; - s64 offset; - char *line; struct ins ins; - int line_nr; float ipc; u64 cycles; struct ins_operands ops; -- cgit v1.2.3 From 37236d5e0b6a765319dec3e64d828cb44ebecac6 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:27 +0200 Subject: perf annotate: Move ipc/cycles into annotation_line struct Move ipc/cycles into annotation_line struct to be used as generic members for any annotation source. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-5-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 16 ++++++++-------- tools/perf/util/annotate.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 73d921c3e3ec..d1aff2f7cb6c 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -144,7 +144,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int if ((row == 0) && (dl->al.offset == -1 || percent_max == 0.0)) { if (ab->have_cycles) { - if (dl->ipc == 0.0 && dl->cycles == 0) + if (dl->al.ipc == 0.0 && dl->al.cycles == 0) show_title = true; } else show_title = true; @@ -178,16 +178,16 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int } } if (ab->have_cycles) { - if (dl->ipc) - ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc); + if (dl->al.ipc) + ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->al.ipc); else if (!show_title) ui_browser__write_nstring(browser, " ", IPC_WIDTH); else ui_browser__printf(browser, "%*s ", IPC_WIDTH - 1, "IPC"); - if (dl->cycles) + if (dl->al.cycles) ui_browser__printf(browser, "%*" PRIu64 " ", - CYCLES_WIDTH - 1, dl->cycles); + CYCLES_WIDTH - 1, dl->al.cycles); else if (!show_title) ui_browser__write_nstring(browser, " ", CYCLES_WIDTH); else @@ -474,7 +474,7 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, max_percent = bpos->samples[i].percent; } - if (max_percent < 0.01 && pos->ipc == 0) { + if (max_percent < 0.01 && pos->al.ipc == 0) { RB_CLEAR_NODE(&bpos->rb_node); continue; } @@ -994,7 +994,7 @@ static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end, struct disasm_line *dl = browser->offsets[offset]; if (dl) - dl->ipc = ipc; + dl->al.ipc = ipc; } } } @@ -1025,7 +1025,7 @@ static void annotate__compute_ipc(struct annotate_browser *browser, size_t size, count_and_fill(browser, ch->start, offset, ch); dl = browser->offsets[offset]; if (dl && ch->num_aggr) - dl->cycles = ch->cycles_aggr / ch->num_aggr; + dl->al.cycles = ch->cycles_aggr / ch->num_aggr; browser->have_cycles = true; } } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index b7ca62855760..a822c0a4987e 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -64,13 +64,13 @@ struct annotation_line { s64 offset; char *line; int line_nr; + float ipc; + u64 cycles; }; struct disasm_line { struct annotation_line al; struct ins ins; - float ipc; - u64 cycles; struct ins_operands ops; }; -- cgit v1.2.3 From c34df25b40c20b478634b954a709749aebdc241a Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:28 +0200 Subject: perf annotate: Add symbol__annotate function Add symbol__annotate function to have generic annotation function to be called for all annotation sources. It calls the generic annotation init and then the specific annotation data retrieval function. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-6-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 +- tools/perf/ui/browsers/annotate.c | 6 ++-- tools/perf/ui/gtk/annotate.c | 4 +-- tools/perf/util/annotate.c | 58 ++++++++++++++++++++++----------------- tools/perf/util/annotate.h | 6 ++-- 5 files changed, 42 insertions(+), 34 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 477a8699f0b5..adfeeb488f1a 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -134,7 +134,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) return err; } - err = symbol__disassemble(sym, map, NULL, 0, NULL, NULL); + err = symbol__annotate(sym, map, NULL, 0, NULL, NULL); if (err == 0) { out_assign: top->sym_filter_entry = he; diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index d1aff2f7cb6c..d77994c1cba9 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -1120,9 +1120,9 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, (nr_pcnt - 1); } - err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), - sizeof_bdl, &browser.arch, - perf_evsel__env_cpuid(evsel)); + err = symbol__annotate(sym, map, perf_evsel__env_arch(evsel), + sizeof_bdl, &browser.arch, + perf_evsel__env_cpuid(evsel)); if (err) { char msg[BUFSIZ]; symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index 162f15712d2d..b498f1a92bb1 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c @@ -169,8 +169,8 @@ static int symbol__gtk_annotate(struct symbol *sym, struct map *map, if (map->dso->annotate_warned) return -1; - err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), - 0, NULL, NULL); + err = symbol__annotate(sym, map, perf_evsel__env_arch(evsel), + 0, NULL, NULL); if (err) { char msg[BUFSIZ]; symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index e8b69001229d..f0093918882d 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1425,13 +1425,11 @@ static const char *annotate__norm_arch(const char *arch_name) return normalize_arch((char *)arch_name); } -int symbol__disassemble(struct symbol *sym, struct map *map, - const char *arch_name, size_t privsize, - struct arch **parch, char *cpuid) +static int symbol__disassemble(struct symbol *sym, struct map *map, + size_t privsize, struct arch *arch) { struct dso *dso = map->dso; char command[PATH_MAX * 2]; - struct arch *arch = NULL; FILE *file; char symfs_filename[PATH_MAX]; struct kcore_extract kce; @@ -1445,25 +1443,6 @@ int symbol__disassemble(struct symbol *sym, struct map *map, if (err) return err; - arch_name = annotate__norm_arch(arch_name); - if (!arch_name) - return -1; - - arch = arch__find(arch_name); - if (arch == NULL) - return -ENOTSUP; - - if (parch) - *parch = arch; - - if (arch->init) { - err = arch->init(arch, cpuid); - if (err) { - pr_err("%s: failed to initialize %s arch priv area\n", __func__, arch->name); - return err; - } - } - pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, symfs_filename, sym->name, map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end)); @@ -1581,6 +1560,35 @@ out_close_stdout: goto out_remove_tmp; } +int symbol__annotate(struct symbol *sym, struct map *map, + const char *arch_name, size_t privsize, + struct arch **parch, char *cpuid) +{ + struct arch *arch; + int err; + + arch_name = annotate__norm_arch(arch_name); + if (!arch_name) + return -1; + + arch = arch__find(arch_name); + if (arch == NULL) + return -ENOTSUP; + + if (parch) + *parch = arch; + + if (arch->init) { + err = arch->init(arch, cpuid); + if (err) { + pr_err("%s: failed to initialize %s arch priv area\n", __func__, arch->name); + return err; + } + } + + return symbol__disassemble(sym, map, privsize, arch); +} + static void insert_source_line(struct rb_root *root, struct source_line *src_line) { struct source_line *iter; @@ -1954,8 +1962,8 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, struct rb_root source_line = RB_ROOT; u64 len; - if (symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), - 0, NULL, NULL) < 0) + if (symbol__annotate(sym, map, perf_evsel__env_arch(evsel), + 0, NULL, NULL) < 0) return -1; len = symbol__size(sym); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index a822c0a4987e..e577f9d13a58 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -173,9 +173,9 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *samp int symbol__alloc_hist(struct symbol *sym); void symbol__annotate_zero_histograms(struct symbol *sym); -int symbol__disassemble(struct symbol *sym, struct map *map, - const char *arch_name, size_t privsize, - struct arch **parch, char *cpuid); +int symbol__annotate(struct symbol *sym, struct map *map, + const char *arch_name, size_t privsize, + struct arch **parch, char *cpuid); enum symbol_disassemble_errno { SYMBOL_ANNOTATE_ERRNO__SUCCESS = 0, -- cgit v1.2.3 From ea07c5aaed33d23875cd59da8b0892f76e882ccd Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:29 +0200 Subject: perf annotate: Add struct annotate_args Adding struct annotate_args to reduce the number of arguments, that need to travel all the way to line allocation. This makes the code easier to read and ease up the changes for following patches. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-7-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index f0093918882d..f5bd6826fa66 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -878,12 +878,17 @@ out_free_name: return -1; } -static struct disasm_line *disasm_line__new(s64 offset, char *line, - size_t privsize, int line_nr, +struct annotate_args { + size_t privsize; +}; + +static struct disasm_line *disasm_line__new(struct annotate_args *args, + s64 offset, char *line, + int line_nr, struct arch *arch, struct map *map) { - struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); + struct disasm_line *dl = zalloc(sizeof(*dl) + args->privsize); if (dl != NULL) { dl->al.offset = offset; @@ -1217,8 +1222,8 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st * The ops.raw part will be parsed further according to type of the instruction. */ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, - struct arch *arch, - FILE *file, size_t privsize, + struct arch *arch, FILE *file, + struct annotate_args *args, int *line_nr) { struct annotation *notes = symbol__annotation(sym); @@ -1264,7 +1269,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, parsed_line = tmp2 + 1; } - dl = disasm_line__new(offset, parsed_line, privsize, *line_nr, arch, map); + dl = disasm_line__new(args, offset, parsed_line, *line_nr, arch, map); free(line); (*line_nr)++; @@ -1426,7 +1431,8 @@ static const char *annotate__norm_arch(const char *arch_name) } static int symbol__disassemble(struct symbol *sym, struct map *map, - size_t privsize, struct arch *arch) + struct annotate_args *args, + struct arch *arch) { struct dso *dso = map->dso; char command[PATH_MAX * 2]; @@ -1526,7 +1532,7 @@ static int symbol__disassemble(struct symbol *sym, struct map *map, * can associate it with the instructions till the next one. * See disasm_line__new() and struct disasm_line::line_nr. */ - if (symbol__parse_objdump_line(sym, map, arch, file, privsize, + if (symbol__parse_objdump_line(sym, map, arch, file, args, &lineno) < 0) break; nline++; @@ -1564,6 +1570,9 @@ int symbol__annotate(struct symbol *sym, struct map *map, const char *arch_name, size_t privsize, struct arch **parch, char *cpuid) { + struct annotate_args args = { + .privsize = privsize, + }; struct arch *arch; int err; @@ -1586,7 +1595,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, } } - return symbol__disassemble(sym, map, privsize, arch); + return symbol__disassemble(sym, map, &args, arch); } static void insert_source_line(struct rb_root *root, struct source_line *src_line) -- cgit v1.2.3 From 24fe7b88934b702442597662643222cd0a6a44a6 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:30 +0200 Subject: perf annotate: Add arch into struct annotate_args Add arch into struct annotate_args to reduce the number of arguments that need to travel all the way to line allocation. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-8-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index f5bd6826fa66..b4d3454618b0 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -880,12 +880,12 @@ out_free_name: struct annotate_args { size_t privsize; + struct arch *arch; }; static struct disasm_line *disasm_line__new(struct annotate_args *args, s64 offset, char *line, int line_nr, - struct arch *arch, struct map *map) { struct disasm_line *dl = zalloc(sizeof(*dl) + args->privsize); @@ -902,7 +902,7 @@ static struct disasm_line *disasm_line__new(struct annotate_args *args, if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0) goto out_free_line; - disasm_line__init_ins(dl, arch, map); + disasm_line__init_ins(dl, args->arch, map); } } @@ -1222,7 +1222,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st * The ops.raw part will be parsed further according to type of the instruction. */ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, - struct arch *arch, FILE *file, + FILE *file, struct annotate_args *args, int *line_nr) { @@ -1269,7 +1269,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, parsed_line = tmp2 + 1; } - dl = disasm_line__new(args, offset, parsed_line, *line_nr, arch, map); + dl = disasm_line__new(args, offset, parsed_line, *line_nr, map); free(line); (*line_nr)++; @@ -1431,8 +1431,7 @@ static const char *annotate__norm_arch(const char *arch_name) } static int symbol__disassemble(struct symbol *sym, struct map *map, - struct annotate_args *args, - struct arch *arch) + struct annotate_args *args) { struct dso *dso = map->dso; char command[PATH_MAX * 2]; @@ -1532,7 +1531,7 @@ static int symbol__disassemble(struct symbol *sym, struct map *map, * can associate it with the instructions till the next one. * See disasm_line__new() and struct disasm_line::line_nr. */ - if (symbol__parse_objdump_line(sym, map, arch, file, args, + if (symbol__parse_objdump_line(sym, map, file, args, &lineno) < 0) break; nline++; @@ -1580,7 +1579,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, if (!arch_name) return -1; - arch = arch__find(arch_name); + args.arch = arch = arch__find(arch_name); if (arch == NULL) return -ENOTSUP; @@ -1595,7 +1594,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, } } - return symbol__disassemble(sym, map, &args, arch); + return symbol__disassemble(sym, map, &args); } static void insert_source_line(struct rb_root *root, struct source_line *src_line) -- cgit v1.2.3 From 1a04db70dcbf621f9919e95456c372281779c053 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:31 +0200 Subject: perf annotate: Add map into struct annotate_args Add map into struct annotate_args to reduce the number of arguments that need to travel all the way to line allocation. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-9-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index b4d3454618b0..30da4402a3e4 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -881,12 +881,12 @@ out_free_name: struct annotate_args { size_t privsize; struct arch *arch; + struct map *map; }; static struct disasm_line *disasm_line__new(struct annotate_args *args, s64 offset, char *line, - int line_nr, - struct map *map) + int line_nr) { struct disasm_line *dl = zalloc(sizeof(*dl) + args->privsize); @@ -902,7 +902,7 @@ static struct disasm_line *disasm_line__new(struct annotate_args *args, if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0) goto out_free_line; - disasm_line__init_ins(dl, args->arch, map); + disasm_line__init_ins(dl, args->arch, args->map); } } @@ -1221,11 +1221,11 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st * means that it's not a disassembly line so should be treated differently. * The ops.raw part will be parsed further according to type of the instruction. */ -static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, - FILE *file, +static int symbol__parse_objdump_line(struct symbol *sym, FILE *file, struct annotate_args *args, int *line_nr) { + struct map *map = args->map; struct annotation *notes = symbol__annotation(sym); struct disasm_line *dl; char *line = NULL, *parsed_line, *tmp, *tmp2; @@ -1269,7 +1269,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, parsed_line = tmp2 + 1; } - dl = disasm_line__new(args, offset, parsed_line, *line_nr, map); + dl = disasm_line__new(args, offset, parsed_line, *line_nr); free(line); (*line_nr)++; @@ -1430,9 +1430,9 @@ static const char *annotate__norm_arch(const char *arch_name) return normalize_arch((char *)arch_name); } -static int symbol__disassemble(struct symbol *sym, struct map *map, - struct annotate_args *args) +static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) { + struct map *map = args->map; struct dso *dso = map->dso; char command[PATH_MAX * 2]; FILE *file; @@ -1531,8 +1531,7 @@ static int symbol__disassemble(struct symbol *sym, struct map *map, * can associate it with the instructions till the next one. * See disasm_line__new() and struct disasm_line::line_nr. */ - if (symbol__parse_objdump_line(sym, map, file, args, - &lineno) < 0) + if (symbol__parse_objdump_line(sym, file, args, &lineno) < 0) break; nline++; } @@ -1571,6 +1570,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, { struct annotate_args args = { .privsize = privsize, + .map = map, }; struct arch *arch; int err; @@ -1594,7 +1594,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, } } - return symbol__disassemble(sym, map, &args); + return symbol__disassemble(sym, &args); } static void insert_source_line(struct rb_root *root, struct source_line *src_line) -- cgit v1.2.3 From 4748834f96903f843719b02190f98e36b2c55192 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:32 +0200 Subject: perf annotate: Add offset/line/line_nr into struct annotate_args Add offset/line/line_nr into struct annotate_args to reduce the number of arguments that need to travel all the way to line allocation. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-10-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 30da4402a3e4..681c9c4ce9f9 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -882,23 +882,24 @@ struct annotate_args { size_t privsize; struct arch *arch; struct map *map; + s64 offset; + char *line; + int line_nr; }; -static struct disasm_line *disasm_line__new(struct annotate_args *args, - s64 offset, char *line, - int line_nr) +static struct disasm_line *disasm_line__new(struct annotate_args *args) { struct disasm_line *dl = zalloc(sizeof(*dl) + args->privsize); if (dl != NULL) { - dl->al.offset = offset; - dl->al.line = strdup(line); - dl->al.line_nr = line_nr; + dl->al.offset = args->offset; + dl->al.line = strdup(args->line); + dl->al.line_nr = args->line_nr; if (dl->al.line == NULL) goto out_delete; - if (offset != -1) { + if (args->offset != -1) { if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0) goto out_free_line; @@ -1269,7 +1270,11 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file, parsed_line = tmp2 + 1; } - dl = disasm_line__new(args, offset, parsed_line, *line_nr); + args->offset = offset; + args->line = parsed_line; + args->line_nr = *line_nr; + + dl = disasm_line__new(args); free(line); (*line_nr)++; -- cgit v1.2.3 From d03a686ea6e77b25edacc3eed386cef870e8d248 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:33 +0200 Subject: perf annotate: Add evsel into struct annotation_line_args Add evsel into struct annotate_args to reduce the number of arguments that need to travel all the way to line allocation. This change also allow us to move the arch name initialization under symbol__annotate function. Link: http://lkml.kernel.org/n/tip-a9ok53rrgt1s5e8uglyvy6qt@git.kernel.org Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-11-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 2 +- tools/perf/ui/gtk/annotate.c | 3 +-- tools/perf/util/annotate.c | 11 ++++++++--- tools/perf/util/annotate.h | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index d77994c1cba9..3b72519c085f 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -1120,7 +1120,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, (nr_pcnt - 1); } - err = symbol__annotate(sym, map, perf_evsel__env_arch(evsel), + err = symbol__annotate(sym, map, evsel, sizeof_bdl, &browser.arch, perf_evsel__env_cpuid(evsel)); if (err) { diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index b498f1a92bb1..5e0a56df0b4c 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c @@ -169,8 +169,7 @@ static int symbol__gtk_annotate(struct symbol *sym, struct map *map, if (map->dso->annotate_warned) return -1; - err = symbol__annotate(sym, map, perf_evsel__env_arch(evsel), - 0, NULL, NULL); + err = symbol__annotate(sym, map, evsel, 0, NULL, NULL); if (err) { char msg[BUFSIZ]; symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 681c9c4ce9f9..75f54eab22c8 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -882,6 +882,7 @@ struct annotate_args { size_t privsize; struct arch *arch; struct map *map; + struct perf_evsel *evsel; s64 offset; char *line; int line_nr; @@ -1570,16 +1571,21 @@ out_close_stdout: } int symbol__annotate(struct symbol *sym, struct map *map, - const char *arch_name, size_t privsize, + struct perf_evsel *evsel, size_t privsize, struct arch **parch, char *cpuid) { struct annotate_args args = { .privsize = privsize, .map = map, + .evsel = evsel, }; + const char *arch_name = NULL; struct arch *arch; int err; + if (evsel) + arch_name = perf_evsel__env_arch(evsel); + arch_name = annotate__norm_arch(arch_name); if (!arch_name) return -1; @@ -1975,8 +1981,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, struct rb_root source_line = RB_ROOT; u64 len; - if (symbol__annotate(sym, map, perf_evsel__env_arch(evsel), - 0, NULL, NULL) < 0) + if (symbol__annotate(sym, map, evsel, 0, NULL, NULL) < 0) return -1; len = symbol__size(sym); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index e577f9d13a58..baf34032504a 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -174,7 +174,7 @@ int symbol__alloc_hist(struct symbol *sym); void symbol__annotate_zero_histograms(struct symbol *sym); int symbol__annotate(struct symbol *sym, struct map *map, - const char *arch_name, size_t privsize, + struct perf_evsel *evsel, size_t privsize, struct arch **parch, char *cpuid); enum symbol_disassemble_errno { -- cgit v1.2.3 From c4c724364d398a9746410d5ff482e8c4c7228249 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:34 +0200 Subject: perf annotate: Add annotation_line__next function Rename disasm__get_next_ip_line() to annotation_line__next() to make it work over a generic struct annotation_line. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-12-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 7 ++++--- tools/perf/util/annotate.c | 13 +++++++------ tools/perf/util/annotate.h | 3 ++- 3 files changed, 13 insertions(+), 10 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 3b72519c085f..881ad6122057 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -440,7 +440,8 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, struct map_symbol *ms = browser->b.priv; struct symbol *sym = ms->sym; struct annotation *notes = symbol__annotation(sym); - struct disasm_line *pos, *next; + struct annotation_line *next; + struct disasm_line *pos; s64 len = symbol__size(sym); browser->entries = RB_ROOT; @@ -458,7 +459,7 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, continue; } - next = disasm__get_next_ip_line(¬es->src->source, pos); + next = annotation_line__next(&pos->al, ¬es->src->source); for (i = 0; i < browser->nr_events; i++) { struct sym_hist_entry sample; @@ -466,7 +467,7 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, bpos->samples[i].percent = disasm__calc_percent(notes, evsel->idx + i, pos->al.offset, - next ? next->al.offset : len, + next ? next->offset : len, &path, &sample); bpos->samples[i].he = sample; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 75f54eab22c8..e7da88d7bb27 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -942,10 +942,11 @@ static void disasm__add(struct list_head *head, struct disasm_line *line) list_add_tail(&line->al.node, head); } -struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos) +struct annotation_line * +annotation_line__next(struct annotation_line *pos, struct list_head *head) { - list_for_each_entry_continue(pos, head, al.node) - if (pos->al.offset >= 0) + list_for_each_entry_continue(pos, head, node) + if (pos->offset >= 0) return pos; return NULL; @@ -1096,10 +1097,10 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st struct annotation *notes = symbol__annotation(sym); s64 offset = dl->al.offset; const u64 addr = start + offset; - struct disasm_line *next; + struct annotation_line *next; struct block_range *br; - next = disasm__get_next_ip_line(¬es->src->source, dl); + next = annotation_line__next(&dl->al, ¬es->src->source); if (perf_evsel__is_group_event(evsel)) { nr_percent = evsel->nr_members; @@ -1114,7 +1115,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st percent = disasm__calc_percent(notes, notes->src->lines ? i : evsel->idx + i, offset, - next ? next->al.offset : (s64) len, + next ? next->offset : (s64) len, &path, &sample); ppercents[i] = percent; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index baf34032504a..43bef6cacbc4 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -85,7 +85,8 @@ struct sym_hist_entry { }; void disasm_line__free(struct disasm_line *dl); -struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); +struct annotation_line * +annotation_line__next(struct annotation_line *pos, struct list_head *head); int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); size_t disasm__fprintf(struct list_head *head, FILE *fp); double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, -- cgit v1.2.3 From 82b9d7ff096b7e7ae3efaeb341ee673bb494bb61 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:35 +0200 Subject: perf annotate: Add annotation_line__add function Rename disasm__add() into annotation_line__add() to make it work over a generic struct annotation_line. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-13-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index e7da88d7bb27..11c7743203a0 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -937,9 +937,9 @@ int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool r return ins__scnprintf(&dl->ins, bf, size, &dl->ops); } -static void disasm__add(struct list_head *head, struct disasm_line *line) +static void annotation_line__add(struct annotation_line *al, struct list_head *head) { - list_add_tail(&line->al.node, head); + list_add_tail(&al->node, head); } struct annotation_line * @@ -1301,7 +1301,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file, dl->ops.target.name = strdup(target.sym->name); } - disasm__add(¬es->src->source, dl); + annotation_line__add(&dl->al, ¬es->src->source); return 0; } -- cgit v1.2.3 From 5b12adc849be011fd6d99a16e39d83afee43c0a0 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:36 +0200 Subject: perf annotate: Move rb_node to struct annotation_line Move rb_node to struct annotation_line to make struct annotation_line the rb tree node for sorted lines used in both stdio and TUI code. This way we can unite the sorted lines lines codes for both TUI and stdio in the following patches. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-14-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 30 ++++++++++++++++-------------- tools/perf/util/annotate.h | 1 + 2 files changed, 17 insertions(+), 14 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 881ad6122057..cfde5a2ca3f4 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -26,7 +26,6 @@ struct disasm_line_samples { #define CYCLES_WIDTH 6 struct browser_disasm_line { - struct rb_node rb_node; u32 idx; int idx_asm; int jump_sources; @@ -362,9 +361,11 @@ static unsigned int annotate_browser__refresh(struct ui_browser *browser) return ret; } -static int disasm__cmp(struct browser_disasm_line *a, - struct browser_disasm_line *b, int nr_pcnt) +static int disasm__cmp(struct disasm_line *da, + struct disasm_line *db, int nr_pcnt) { + struct browser_disasm_line *a = disasm_line__browser(da); + struct browser_disasm_line *b = disasm_line__browser(db); int i; for (i = 0; i < nr_pcnt; i++) { @@ -375,24 +376,24 @@ static int disasm__cmp(struct browser_disasm_line *a, return 0; } -static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl, +static void disasm_rb_tree__insert(struct rb_root *root, struct disasm_line *dl, int nr_events) { struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; - struct browser_disasm_line *l; + struct disasm_line *l; while (*p != NULL) { parent = *p; - l = rb_entry(parent, struct browser_disasm_line, rb_node); + l = rb_entry(parent, struct disasm_line, al.rb_node); - if (disasm__cmp(bdl, l, nr_events)) + if (disasm__cmp(dl, l, nr_events)) p = &(*p)->rb_left; else p = &(*p)->rb_right; } - rb_link_node(&bdl->rb_node, parent, p); - rb_insert_color(&bdl->rb_node, root); + rb_link_node(&dl->al.rb_node, parent, p); + rb_insert_color(&dl->al.rb_node, root); } static void annotate_browser__set_top(struct annotate_browser *browser, @@ -425,8 +426,9 @@ static void annotate_browser__set_rb_top(struct annotate_browser *browser, struct disasm_line *pos; u32 idx; - bpos = rb_entry(nd, struct browser_disasm_line, rb_node); - pos = ((struct disasm_line *)bpos) - 1; + pos = rb_entry(nd, struct disasm_line, al.rb_node); + bpos = disasm_line__browser(pos); + idx = bpos->idx; if (annotate_browser__opts.hide_src_code) idx = bpos->idx_asm; @@ -455,7 +457,7 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, int i; if (pos->al.offset == -1) { - RB_CLEAR_NODE(&bpos->rb_node); + RB_CLEAR_NODE(&pos->al.rb_node); continue; } @@ -476,10 +478,10 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, } if (max_percent < 0.01 && pos->al.ipc == 0) { - RB_CLEAR_NODE(&bpos->rb_node); + RB_CLEAR_NODE(&pos->al.rb_node); continue; } - disasm_rb_tree__insert(&browser->entries, bpos, + disasm_rb_tree__insert(&browser->entries, pos, browser->nr_events); } pthread_mutex_unlock(¬es->lock); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 43bef6cacbc4..6f01e6117936 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -61,6 +61,7 @@ struct annotation; struct annotation_line { struct list_head node; + struct rb_node rb_node; s64 offset; char *line; int line_nr; -- cgit v1.2.3 From c835e1914c4bcfdd41f43d270cafc6d8119d7782 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:37 +0200 Subject: perf annotate: Add annotation_line__(new|delete) functions Changing the way the annotation lines are allocated and adding annotation_line__(new|delete) functions to deal with this. Before the allocation schema was as follows: ----------------------------------------------------------- struct disasm_line | struct annotation_line | private space ----------------------------------------------------------- Where the private space is used in TUI code to store computed annotation data for events. The stdio code computes the data on the fly. The goal is to compute and store annotation line's data directly in the struct annotation_line itself, so this patch changes the line allocation schema as follows: ------------------------------------------------------------ privsize space | struct disasm_line | struct annotation_line ------------------------------------------------------------ Moving struct annotation_line to the end, because in following changes we will move here the non-fixed length event's data. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-15-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 4 ++- tools/perf/util/annotate.c | 63 ++++++++++++++++++++++++++++++++++----- tools/perf/util/annotate.h | 10 ++++++- 3 files changed, 68 insertions(+), 9 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index cfde5a2ca3f4..7ca5ae625cc9 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -76,7 +76,9 @@ struct annotate_browser { static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl) { - return (struct browser_disasm_line *)(dl + 1); + struct annotation_line *al = &dl->al; + + return (void *) al - al->privsize; } static bool disasm_line__filter(struct ui_browser *browser __maybe_unused, diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 11c7743203a0..7c74700ae6d7 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -888,14 +888,64 @@ struct annotate_args { int line_nr; }; +static void annotation_line__delete(struct annotation_line *al) +{ + void *ptr = (void *) al - al->privsize; + + zfree(&al->line); + free(ptr); +} + +/* + * Allocating the annotation line data with following + * structure: + * + * -------------------------------------- + * private space | struct annotation_line + * -------------------------------------- + * + * Size of the private space is stored in 'struct annotation_line'. + * + */ +static struct annotation_line * +annotation_line__new(struct annotate_args *args, size_t privsize) +{ + struct annotation_line *al; + size_t size = privsize + sizeof(*al); + + al = zalloc(size); + if (al) { + al = (void *) al + privsize; + al->privsize = privsize; + al->offset = args->offset; + al->line = strdup(args->line); + al->line_nr = args->line_nr; + } + + return al; +} + +/* + * Allocating the disasm annotation line data with + * following structure: + * + * ------------------------------------------------------------ + * privsize space | struct disasm_line | struct annotation_line + * ------------------------------------------------------------ + * + * We have 'struct annotation_line' member as last member + * of 'struct disasm_line' to have an easy access. + * + */ static struct disasm_line *disasm_line__new(struct annotate_args *args) { - struct disasm_line *dl = zalloc(sizeof(*dl) + args->privsize); + struct disasm_line *dl = NULL; + struct annotation_line *al; + size_t privsize = args->privsize + offsetof(struct disasm_line, al); - if (dl != NULL) { - dl->al.offset = args->offset; - dl->al.line = strdup(args->line); - dl->al.line_nr = args->line_nr; + al = annotation_line__new(args, privsize); + if (al != NULL) { + dl = disasm_line(al); if (dl->al.line == NULL) goto out_delete; @@ -919,14 +969,13 @@ out_delete: void disasm_line__free(struct disasm_line *dl) { - zfree(&dl->al.line); if (dl->ins.ops && dl->ins.ops->free) dl->ins.ops->free(&dl->ops); else ins__delete(&dl->ops); free((void *)dl->ins.name); dl->ins.name = NULL; - free(dl); + annotation_line__delete(&dl->al); } int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 6f01e6117936..2e7a08afb04f 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -67,14 +67,22 @@ struct annotation_line { int line_nr; float ipc; u64 cycles; + size_t privsize; }; struct disasm_line { - struct annotation_line al; struct ins ins; struct ins_operands ops; + + /* This needs to be at the end. */ + struct annotation_line al; }; +static inline struct disasm_line *disasm_line(struct annotation_line *al) +{ + return al ? container_of(al, struct disasm_line, al) : NULL; +} + static inline bool disasm_line__has_offset(const struct disasm_line *dl) { return dl->ops.target.offset_avail; -- cgit v1.2.3 From f8eb37bd7c33babc01d9c2e3074ce001eec6cfbb Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:38 +0200 Subject: perf annotate: Add annotated_source__purge function Mov disasm__purge() to annotated_source__purge() to make it work over a generic struct annotation_line. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-16-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 8 +++----- tools/perf/util/annotate.c | 12 ++++++------ tools/perf/util/annotate.h | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 7ca5ae625cc9..4c54d5e76008 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -1084,7 +1084,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, struct perf_evsel *evsel, struct hist_browser_timer *hbt) { - struct disasm_line *pos, *n; + struct disasm_line *pos; struct annotation *notes; size_t size; struct map_symbol ms = { @@ -1180,10 +1180,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, annotate_browser__update_addr_width(&browser); ret = annotate_browser__run(&browser, evsel, hbt); - list_for_each_entry_safe(pos, n, ¬es->src->source, al.node) { - list_del(&pos->al.node); - disasm_line__free(pos); - } + + annotated_source__purge(notes->src); out_free_offsets: free(browser.offsets); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 7c74700ae6d7..0c2eb95ba90a 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1985,13 +1985,13 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) } } -void disasm__purge(struct list_head *head) +void annotated_source__purge(struct annotated_source *as) { - struct disasm_line *pos, *n; + struct annotation_line *al, *n; - list_for_each_entry_safe(pos, n, head, al.node) { - list_del(&pos->al.node); - disasm_line__free(pos); + list_for_each_entry_safe(al, n, &as->source, node) { + list_del(&al->node); + disasm_line__free(disasm_line(al)); } } @@ -2047,7 +2047,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, if (print_lines) symbol__free_source_line(sym, len); - disasm__purge(&symbol__annotation(sym)->src->source); + annotated_source__purge(symbol__annotation(sym)->src); return 0; } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 2e7a08afb04f..cb60cafae1fb 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -212,7 +212,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int min_pcnt, int max_lines, int context); void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); -void disasm__purge(struct list_head *head); +void annotated_source__purge(struct annotated_source *as); bool ui__has_annotation(void); -- cgit v1.2.3 From 7e304557ead5b309d59807b2f05ed47f2c0076c6 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:39 +0200 Subject: perf annotate: Add samples into struct annotation_line Add samples array into struct annotation_line to hold the annotation data. The data is populated in the following patches. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-17-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 8 ++++++++ tools/perf/util/annotate.h | 17 ++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 0c2eb95ba90a..313fb2e90dba 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -911,7 +911,14 @@ static struct annotation_line * annotation_line__new(struct annotate_args *args, size_t privsize) { struct annotation_line *al; + struct perf_evsel *evsel = args->evsel; size_t size = privsize + sizeof(*al); + int nr = 1; + + if (perf_evsel__is_group_event(evsel)) + nr = evsel->nr_members; + + size += sizeof(al->samples[0]) * nr; al = zalloc(size); if (al) { @@ -920,6 +927,7 @@ annotation_line__new(struct annotate_args *args, size_t privsize) al->offset = args->offset; al->line = strdup(args->line); al->line_nr = args->line_nr; + al->samples_nr = nr; } return al; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index cb60cafae1fb..55bdd9015f33 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -59,6 +59,16 @@ bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2); struct annotation; +struct sym_hist_entry { + u64 nr_samples; + u64 period; +}; + +struct annotation_data { + double percent; + struct sym_hist_entry he; +}; + struct annotation_line { struct list_head node; struct rb_node rb_node; @@ -68,6 +78,8 @@ struct annotation_line { float ipc; u64 cycles; size_t privsize; + int samples_nr; + struct annotation_data samples[0]; }; struct disasm_line { @@ -88,11 +100,6 @@ static inline bool disasm_line__has_offset(const struct disasm_line *dl) return dl->ops.target.offset_avail; } -struct sym_hist_entry { - u64 nr_samples; - u64 period; -}; - void disasm_line__free(struct disasm_line *dl); struct annotation_line * annotation_line__next(struct annotation_line *pos, struct list_head *head); -- cgit v1.2.3 From 073ae601edc211383b62618effaaedaa8b1d22db Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:40 +0200 Subject: perf annotate: Add symbol__calc_percent function Add symbol__calc_percent function, that calculates annotation data for symbol and put the data in the struct annotation_line::samples array. Committer notes: Made symbol__calc_percent non static to be used in the next two patches, which will get some fixups from jolsa, doing it this way to keep this bisectable. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-18-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 62 +++++++++++++++++++++++++++++++++++++++++++++- tools/perf/util/annotate.h | 1 + 2 files changed, 62 insertions(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 313fb2e90dba..ff1036096347 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1628,6 +1628,62 @@ out_close_stdout: goto out_remove_tmp; } +static void calc_percent(struct sym_hist *hist, + struct annotation_data *sample, + s64 offset, s64 end) +{ + unsigned int hits = 0; + u64 period = 0; + + while (offset < end) { + hits += hist->addr[offset].nr_samples; + period += hist->addr[offset].period; + ++offset; + } + + if (hist->nr_samples) { + sample->he.period = period; + sample->he.nr_samples = hits; + sample->percent = 100.0 * hits / hist->nr_samples; + } +} + +static int annotation__calc_percent(struct annotation *notes, + struct perf_evsel *evsel, s64 len) +{ + struct annotation_line *al, *next; + + list_for_each_entry(al, ¬es->src->source, node) { + s64 end; + int i; + + if (al->offset == -1) + continue; + + next = annotation_line__next(al, ¬es->src->source); + end = next ? next->offset : len; + + for (i = 0; i < al->samples_nr; i++) { + struct annotation_data *sample; + struct sym_hist *hist; + + hist = annotation__histogram(notes, evsel->idx + i); + sample = &al->samples[i]; + + calc_percent(hist, sample, al->offset, end); + } + } + + return 0; +} + +int symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel) +{ + struct annotation *notes = symbol__annotation(sym); + + return annotation__calc_percent(notes, evsel, symbol__size(sym)); +} + int symbol__annotate(struct symbol *sym, struct map *map, struct perf_evsel *evsel, size_t privsize, struct arch **parch, char *cpuid) @@ -1663,7 +1719,11 @@ int symbol__annotate(struct symbol *sym, struct map *map, } } - return symbol__disassemble(sym, &args); + err = symbol__disassemble(sym, &args); + if (err) + return err; + + return symbol__calc_percent(sym, evsel); } static void insert_source_line(struct rb_root *root, struct source_line *src_line) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 55bdd9015f33..6056840da4c9 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -107,6 +107,7 @@ int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool r size_t disasm__fprintf(struct list_head *head, FILE *fp); double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, s64 end, const char **path, struct sym_hist_entry *sample); +int symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); struct sym_hist { u64 nr_samples; -- cgit v1.2.3 From 8b4c74dc5cd40a3bc77f8bc2b6b7b33dc125e302 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:41 +0200 Subject: perf annotate: Add symbol__calc_lines function Replace symbol__get_source_line() with symbol__calc_lines(), which calculates the source line tree over the struct annotation_line. This will allow us to remove redundant struct source_line in following patches. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-19-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 186 ++++++++++++++++----------------------------- tools/perf/util/annotate.h | 2 + 2 files changed, 68 insertions(+), 120 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ff1036096347..96cf6767b5ce 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -892,6 +892,7 @@ static void annotation_line__delete(struct annotation_line *al) { void *ptr = (void *) al - al->privsize; + free_srcline(al->path); zfree(&al->line); free(ptr); } @@ -1726,21 +1727,21 @@ int symbol__annotate(struct symbol *sym, struct map *map, return symbol__calc_percent(sym, evsel); } -static void insert_source_line(struct rb_root *root, struct source_line *src_line) +static void insert_source_line(struct rb_root *root, struct annotation_line *al) { - struct source_line *iter; + struct annotation_line *iter; struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; int i, ret; while (*p != NULL) { parent = *p; - iter = rb_entry(parent, struct source_line, node); + iter = rb_entry(parent, struct annotation_line, rb_node); - ret = strcmp(iter->path, src_line->path); + ret = strcmp(iter->path, al->path); if (ret == 0) { - for (i = 0; i < src_line->nr_pcnt; i++) - iter->samples[i].percent_sum += src_line->samples[i].percent; + for (i = 0; i < al->samples_nr; i++) + iter->samples[i].percent_sum += al->samples[i].percent; return; } @@ -1750,18 +1751,18 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin p = &(*p)->rb_right; } - for (i = 0; i < src_line->nr_pcnt; i++) - src_line->samples[i].percent_sum = src_line->samples[i].percent; + for (i = 0; i < al->samples_nr; i++) + al->samples[i].percent_sum = al->samples[i].percent; - rb_link_node(&src_line->node, parent, p); - rb_insert_color(&src_line->node, root); + rb_link_node(&al->rb_node, parent, p); + rb_insert_color(&al->rb_node, root); } -static int cmp_source_line(struct source_line *a, struct source_line *b) +static int cmp_source_line(struct annotation_line *a, struct annotation_line *b) { int i; - for (i = 0; i < a->nr_pcnt; i++) { + for (i = 0; i < a->samples_nr; i++) { if (a->samples[i].percent_sum == b->samples[i].percent_sum) continue; return a->samples[i].percent_sum > b->samples[i].percent_sum; @@ -1770,135 +1771,47 @@ static int cmp_source_line(struct source_line *a, struct source_line *b) return 0; } -static void __resort_source_line(struct rb_root *root, struct source_line *src_line) +static void __resort_source_line(struct rb_root *root, struct annotation_line *al) { - struct source_line *iter; + struct annotation_line *iter; struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; while (*p != NULL) { parent = *p; - iter = rb_entry(parent, struct source_line, node); + iter = rb_entry(parent, struct annotation_line, rb_node); - if (cmp_source_line(src_line, iter)) + if (cmp_source_line(al, iter)) p = &(*p)->rb_left; else p = &(*p)->rb_right; } - rb_link_node(&src_line->node, parent, p); - rb_insert_color(&src_line->node, root); + rb_link_node(&al->rb_node, parent, p); + rb_insert_color(&al->rb_node, root); } static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root) { - struct source_line *src_line; + struct annotation_line *al; struct rb_node *node; node = rb_first(src_root); while (node) { struct rb_node *next; - src_line = rb_entry(node, struct source_line, node); + al = rb_entry(node, struct annotation_line, rb_node); next = rb_next(node); rb_erase(node, src_root); - __resort_source_line(dest_root, src_line); + __resort_source_line(dest_root, al); node = next; } } -static void symbol__free_source_line(struct symbol *sym, int len) -{ - struct annotation *notes = symbol__annotation(sym); - struct source_line *src_line = notes->src->lines; - size_t sizeof_src_line; - int i; - - sizeof_src_line = sizeof(*src_line) + - (sizeof(src_line->samples) * (src_line->nr_pcnt - 1)); - - for (i = 0; i < len; i++) { - free_srcline(src_line->path); - src_line = (void *)src_line + sizeof_src_line; - } - - zfree(¬es->src->lines); -} - -/* Get the filename:line for the colored entries */ -static int symbol__get_source_line(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, - struct rb_root *root, int len) -{ - u64 start; - int i, k; - int evidx = evsel->idx; - struct source_line *src_line; - struct annotation *notes = symbol__annotation(sym); - struct sym_hist *h = annotation__histogram(notes, evidx); - struct rb_root tmp_root = RB_ROOT; - int nr_pcnt = 1; - u64 nr_samples = h->nr_samples; - size_t sizeof_src_line = sizeof(struct source_line); - - if (perf_evsel__is_group_event(evsel)) { - for (i = 1; i < evsel->nr_members; i++) { - h = annotation__histogram(notes, evidx + i); - nr_samples += h->nr_samples; - } - nr_pcnt = evsel->nr_members; - sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->samples); - } - - if (!nr_samples) - return 0; - - src_line = notes->src->lines = calloc(len, sizeof_src_line); - if (!notes->src->lines) - return -1; - - start = map__rip_2objdump(map, sym->start); - - for (i = 0; i < len; i++) { - u64 offset; - double percent_max = 0.0; - - src_line->nr_pcnt = nr_pcnt; - - for (k = 0; k < nr_pcnt; k++) { - double percent = 0.0; - - h = annotation__histogram(notes, evidx + k); - nr_samples = h->addr[i].nr_samples; - if (h->nr_samples) - percent = 100.0 * nr_samples / h->nr_samples; - - if (percent > percent_max) - percent_max = percent; - src_line->samples[k].percent = percent; - src_line->samples[k].nr = nr_samples; - } - - if (percent_max <= 0.5) - goto next; - - offset = start + i; - src_line->path = get_srcline(map->dso, offset, NULL, - false, true); - insert_source_line(&tmp_root, src_line); - - next: - src_line = (void *)src_line + sizeof_src_line; - } - - resort_source_line(root, &tmp_root); - return 0; -} - static void print_summary(struct rb_root *root, const char *filename) { - struct source_line *src_line; + struct annotation_line *al; struct rb_node *node; printf("\nSorted summary for file %s\n", filename); @@ -1916,9 +1829,9 @@ static void print_summary(struct rb_root *root, const char *filename) char *path; int i; - src_line = rb_entry(node, struct source_line, node); - for (i = 0; i < src_line->nr_pcnt; i++) { - percent = src_line->samples[i].percent_sum; + al = rb_entry(node, struct annotation_line, rb_node); + for (i = 0; i < al->samples_nr; i++) { + percent = al->samples[i].percent_sum; color = get_percent_color(percent); color_fprintf(stdout, color, " %7.2f", percent); @@ -1926,7 +1839,7 @@ static void print_summary(struct rb_root *root, const char *filename) percent_max = percent; } - path = src_line->path; + path = al->path; color = get_percent_color(percent_max); color_fprintf(stdout, color, " %s\n", path); @@ -2091,29 +2004,62 @@ size_t disasm__fprintf(struct list_head *head, FILE *fp) return printed; } +static void annotation__calc_lines(struct annotation *notes, struct map *map, + struct rb_root *root, u64 start) +{ + struct annotation_line *al; + struct rb_root tmp_root = RB_ROOT; + + list_for_each_entry(al, ¬es->src->source, node) { + double percent_max = 0.0; + int i; + + for (i = 0; i < al->samples_nr; i++) { + struct annotation_data *sample; + + sample = &al->samples[i]; + + if (sample->percent > percent_max) + percent_max = sample->percent; + } + + if (percent_max <= 0.5) + continue; + + al->path = get_srcline(map->dso, start + al->offset, NULL, false, true); + insert_source_line(&tmp_root, al); + } + + resort_source_line(root, &tmp_root); +} + +static void symbol__calc_lines(struct symbol *sym, struct map *map, + struct rb_root *root) +{ + struct annotation *notes = symbol__annotation(sym); + u64 start = map__rip_2objdump(map, sym->start); + + annotation__calc_lines(notes, map, root, start); +} + int symbol__tty_annotate(struct symbol *sym, struct map *map, struct perf_evsel *evsel, bool print_lines, bool full_paths, int min_pcnt, int max_lines) { struct dso *dso = map->dso; struct rb_root source_line = RB_ROOT; - u64 len; if (symbol__annotate(sym, map, evsel, 0, NULL, NULL) < 0) return -1; - len = symbol__size(sym); - if (print_lines) { srcline_full_filename = full_paths; - symbol__get_source_line(sym, map, evsel, &source_line, len); + symbol__calc_lines(sym, map, &source_line); print_summary(&source_line, dso->long_name); } symbol__annotate_printf(sym, map, evsel, full_paths, min_pcnt, max_lines, 0); - if (print_lines) - symbol__free_source_line(sym, len); annotated_source__purge(symbol__annotation(sym)->src); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 6056840da4c9..927810b19f0d 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -66,6 +66,7 @@ struct sym_hist_entry { struct annotation_data { double percent; + double percent_sum; struct sym_hist_entry he; }; @@ -78,6 +79,7 @@ struct annotation_line { float ipc; u64 cycles; size_t privsize; + char *path; int samples_nr; struct annotation_data samples[0]; }; -- cgit v1.2.3 From f681d593d1ce7d2fc665c4047b45f4316408b892 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:42 +0200 Subject: perf annotate: Remove disasm__calc_percent() from disasm_line__print() Remove disasm__calc_percent() from disasm_line__print(), because we already have the data calculated in struct annotation_line. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-20-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 3 +++ tools/perf/util/annotate.c | 59 ++++++++++++---------------------------------- 2 files changed, 18 insertions(+), 44 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index adfeeb488f1a..0789f95ca2f3 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -226,6 +226,7 @@ static void perf_top__record_precise_ip(struct perf_top *top, static void perf_top__show_details(struct perf_top *top) { struct hist_entry *he = top->sym_filter_entry; + struct perf_evsel *evsel = hists_to_evsel(he->hists); struct annotation *notes; struct symbol *symbol; int more; @@ -238,6 +239,8 @@ static void perf_top__show_details(struct perf_top *top) pthread_mutex_lock(¬es->lock); + symbol__calc_percent(symbol, evsel); + if (notes->src == NULL) goto out_unlock; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 96cf6767b5ce..209a25545542 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1145,41 +1145,19 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st static const char *prev_color; if (dl->al.offset != -1) { - const char *path = NULL; - double percent, max_percent = 0.0; - double *ppercents = &percent; - struct sym_hist_entry sample; - struct sym_hist_entry *psamples = &sample; + double max_percent = 0.0; int i, nr_percent = 1; const char *color; struct annotation *notes = symbol__annotation(sym); s64 offset = dl->al.offset; const u64 addr = start + offset; - struct annotation_line *next; struct block_range *br; - next = annotation_line__next(&dl->al, ¬es->src->source); + for (i = 0; i < dl->al.samples_nr; i++) { + struct annotation_data *sample = &dl->al.samples[i]; - if (perf_evsel__is_group_event(evsel)) { - nr_percent = evsel->nr_members; - ppercents = calloc(nr_percent, sizeof(double)); - psamples = calloc(nr_percent, sizeof(struct sym_hist_entry)); - if (ppercents == NULL || psamples == NULL) { - return -1; - } - } - - for (i = 0; i < nr_percent; i++) { - percent = disasm__calc_percent(notes, - notes->src->lines ? i : evsel->idx + i, - offset, - next ? next->offset : (s64) len, - &path, &sample); - - ppercents[i] = percent; - psamples[i] = sample; - if (percent > max_percent) - max_percent = percent; + if (sample->percent > max_percent) + max_percent = sample->percent; } if (max_percent < min_pcnt) @@ -1204,28 +1182,28 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st * the same color than the percentage. Don't print it * twice for close colored addr with the same filename:line */ - if (path) { - if (!prev_line || strcmp(prev_line, path) + if (dl->al.path) { + if (!prev_line || strcmp(prev_line, dl->al.path) || color != prev_color) { - color_fprintf(stdout, color, " %s", path); - prev_line = path; + color_fprintf(stdout, color, " %s", dl->al.path); + prev_line = dl->al.path; prev_color = color; } } for (i = 0; i < nr_percent; i++) { - percent = ppercents[i]; - sample = psamples[i]; - color = get_percent_color(percent); + struct annotation_data *sample = &dl->al.samples[i]; + + color = get_percent_color(sample->percent); if (symbol_conf.show_total_period) color_fprintf(stdout, color, " %11" PRIu64, - sample.period); + sample->he.period); else if (symbol_conf.show_nr_samples) color_fprintf(stdout, color, " %7" PRIu64, - sample.nr_samples); + sample->he.nr_samples); else - color_fprintf(stdout, color, " %7.2f", percent); + color_fprintf(stdout, color, " %7.2f", sample->percent); } printf(" : "); @@ -1235,13 +1213,6 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st color_fprintf(stdout, annotate__asm_color(br), "%s", dl->al.line); annotate__branch_printf(br, addr); printf("\n"); - - if (ppercents != &percent) - free(ppercents); - - if (psamples != &sample) - free(psamples); - } else if (max_lines && printed >= max_lines) return 1; else { -- cgit v1.2.3 From 81e436a0b3a7a2f3ac0311674ce407b7cdd23f0b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:44 +0200 Subject: perf annotate: Remove disasm__calc_percent function Remove disasm__calc_percent() function, because it's no longer needed. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-22-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 44 -------------------------------------------- tools/perf/util/annotate.h | 2 -- 2 files changed, 46 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 209a25545542..29cf2a5ef620 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1010,50 +1010,6 @@ annotation_line__next(struct annotation_line *pos, struct list_head *head) return NULL; } -double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, - s64 end, const char **path, struct sym_hist_entry *sample) -{ - struct source_line *src_line = notes->src->lines; - double percent = 0.0; - - sample->nr_samples = sample->period = 0; - - if (src_line) { - size_t sizeof_src_line = sizeof(*src_line) + - sizeof(src_line->samples) * (src_line->nr_pcnt - 1); - - while (offset < end) { - src_line = (void *)notes->src->lines + - (sizeof_src_line * offset); - - if (*path == NULL) - *path = src_line->path; - - percent += src_line->samples[evidx].percent; - sample->nr_samples += src_line->samples[evidx].nr; - offset++; - } - } else { - struct sym_hist *h = annotation__histogram(notes, evidx); - unsigned int hits = 0; - u64 period = 0; - - while (offset < end) { - hits += h->addr[offset].nr_samples; - period += h->addr[offset].period; - ++offset; - } - - if (h->nr_samples) { - sample->period = period; - sample->nr_samples = hits; - percent = 100.0 * hits / h->nr_samples; - } - } - - return percent; -} - static const char *annotate__address_color(struct block_range *br) { double cov = block_range__coverage(br); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 927810b19f0d..f98acb2ad721 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -107,8 +107,6 @@ struct annotation_line * annotation_line__next(struct annotation_line *pos, struct list_head *head); int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); size_t disasm__fprintf(struct list_head *head, FILE *fp); -double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, - s64 end, const char **path, struct sym_hist_entry *sample); int symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); struct sym_hist { -- cgit v1.2.3 From fa1924eb4abcd756febc031d819ba75c3849ca45 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:45 +0200 Subject: perf annotate: Remove struct source_line Remove struct source_line*, no longer needed. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-23-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.h | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index f98acb2ad721..4fc805a271d2 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -126,19 +126,6 @@ struct cyc_hist { u16 reset; }; -struct source_line_samples { - double percent; - double percent_sum; - u64 nr; -}; - -struct source_line { - struct rb_node node; - char *path; - int nr_pcnt; - struct source_line_samples samples[1]; -}; - /** struct annotated_source - symbols with hits have this attached as in sannotation * * @histogram: Array of addr hit histograms per event being monitored @@ -154,7 +141,6 @@ struct source_line { */ struct annotated_source { struct list_head source; - struct source_line *lines; int nr_histograms; size_t sizeof_sym_hist; struct cyc_hist *cycles_hist; -- cgit v1.2.3 From 8f25b8197d43885a4cc19bea581e37bf46ed9958 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:46 +0200 Subject: perf annotate: Add annotation_line__print function Separating struct annotation_line display function, it will hold the generic line display code. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-24-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 29cf2a5ef620..5c6f739ac3ac 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1189,6 +1189,18 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st return 0; } +static int +annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, + struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, + int max_lines, struct annotation_line *aq) +{ + struct disasm_line *dl = container_of(al, struct disasm_line, al); + struct disasm_line *queue = container_of(aq, struct disasm_line, al); + + return disasm_line__print(dl, sym, start, evsel, len, min_pcnt, printed, + max_lines, queue); +} + /* * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw) * which looks like following @@ -1797,7 +1809,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, const char *evsel_name = perf_evsel__name(evsel); struct annotation *notes = symbol__annotation(sym); struct sym_hist *h = annotation__histogram(notes, evsel->idx); - struct disasm_line *pos, *queue = NULL; + struct annotation_line *pos, *queue = NULL; u64 start = map__rip_2objdump(map, sym->start); int printed = 2, queue_len = 0; int more = 0; @@ -1830,15 +1842,19 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, if (verbose > 0) symbol__annotate_hits(sym, evsel); - list_for_each_entry(pos, ¬es->src->source, al.node) { + list_for_each_entry(pos, ¬es->src->source, node) { + int err; + if (context && queue == NULL) { queue = pos; queue_len = 0; } - switch (disasm_line__print(pos, sym, start, evsel, len, - min_pcnt, printed, max_lines, - queue)) { + err = annotation_line__print(pos, sym, start, evsel, len, + min_pcnt, printed, max_lines, + queue); + + switch (err) { case 0: ++printed; if (context) { @@ -1860,7 +1876,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, if (!context) break; if (queue_len == context) - queue = list_entry(queue->al.node.next, typeof(*queue), al.node); + queue = list_entry(queue->node.next, typeof(*queue), node); else ++queue_len; break; -- cgit v1.2.3 From 29971f9a82a5d005b37d65fbb73edaf9073279b0 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:47 +0200 Subject: perf annotate: Factor annotation_line__print from disasm_line__print Move generic annotation line display code into annotation_line__print function. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-25-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 69 ++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 36 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 5c6f739ac3ac..cb065ca431ee 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1093,24 +1093,36 @@ static void annotate__branch_printf(struct block_range *br, u64 addr) } -static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, - struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, - int max_lines, struct disasm_line *queue) +static int disasm_line__print(struct disasm_line *dl, u64 start) { + s64 offset = dl->al.offset; + const u64 addr = start + offset; + struct block_range *br; + + br = block_range__find(addr); + color_fprintf(stdout, annotate__address_color(br), " %" PRIx64 ":", addr); + color_fprintf(stdout, annotate__asm_color(br), "%s", dl->al.line); + annotate__branch_printf(br, addr); + return 0; +} + +static int +annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, + struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, + int max_lines, struct annotation_line *queue) +{ + struct disasm_line *dl = container_of(al, struct disasm_line, al); static const char *prev_line; static const char *prev_color; - if (dl->al.offset != -1) { + if (al->offset != -1) { double max_percent = 0.0; int i, nr_percent = 1; const char *color; struct annotation *notes = symbol__annotation(sym); - s64 offset = dl->al.offset; - const u64 addr = start + offset; - struct block_range *br; - for (i = 0; i < dl->al.samples_nr; i++) { - struct annotation_data *sample = &dl->al.samples[i]; + for (i = 0; i < al->samples_nr; i++) { + struct annotation_data *sample = &al->samples[i]; if (sample->percent > max_percent) max_percent = sample->percent; @@ -1123,11 +1135,11 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st return 1; if (queue != NULL) { - list_for_each_entry_from(queue, ¬es->src->source, al.node) { - if (queue == dl) + list_for_each_entry_from(queue, ¬es->src->source, node) { + if (queue == al) break; - disasm_line__print(queue, sym, start, evsel, len, - 0, 0, 1, NULL); + annotation_line__print(queue, sym, start, evsel, len, + 0, 0, 1, NULL); } } @@ -1138,17 +1150,17 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st * the same color than the percentage. Don't print it * twice for close colored addr with the same filename:line */ - if (dl->al.path) { - if (!prev_line || strcmp(prev_line, dl->al.path) + if (al->path) { + if (!prev_line || strcmp(prev_line, al->path) || color != prev_color) { - color_fprintf(stdout, color, " %s", dl->al.path); - prev_line = dl->al.path; + color_fprintf(stdout, color, " %s", al->path); + prev_line = al->path; prev_color = color; } } for (i = 0; i < nr_percent; i++) { - struct annotation_data *sample = &dl->al.samples[i]; + struct annotation_data *sample = &al->samples[i]; color = get_percent_color(sample->percent); @@ -1164,10 +1176,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st printf(" : "); - br = block_range__find(addr); - color_fprintf(stdout, annotate__address_color(br), " %" PRIx64 ":", addr); - color_fprintf(stdout, annotate__asm_color(br), "%s", dl->al.line); - annotate__branch_printf(br, addr); + disasm_line__print(dl, start); printf("\n"); } else if (max_lines && printed >= max_lines) return 1; @@ -1180,27 +1189,15 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st if (perf_evsel__is_group_event(evsel)) width *= evsel->nr_members; - if (!*dl->al.line) + if (!*al->line) printf(" %*s:\n", width, " "); else - printf(" %*s: %s\n", width, " ", dl->al.line); + printf(" %*s: %s\n", width, " ", al->line); } return 0; } -static int -annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, - struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, - int max_lines, struct annotation_line *aq) -{ - struct disasm_line *dl = container_of(al, struct disasm_line, al); - struct disasm_line *queue = container_of(aq, struct disasm_line, al); - - return disasm_line__print(dl, sym, start, evsel, len, min_pcnt, printed, - max_lines, queue); -} - /* * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw) * which looks like following -- cgit v1.2.3 From f48e7c407050e5f5f53a0fa9a266d83b001dd356 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 11 Oct 2017 17:01:58 +0200 Subject: perf annotate: Align source and offset lines Align source with offset lines, which are more advanced, because of the address column. Before: : static void *worker_thread(void *__tdata) : { 0.00 : 48a971: push %rbp 0.00 : 48a972: mov %rsp,%rbp 0.00 : 48a975: sub $0x30,%rsp 0.00 : 48a979: mov %rdi,-0x28(%rbp) 0.00 : 48a97d: mov %fs:0x28,%rax 0.00 : 48a986: mov %rax,-0x8(%rbp) 0.00 : 48a98a: xor %eax,%eax : struct thread_data *td = __tdata; 0.00 : 48a98c: mov -0x28(%rbp),%rax 0.00 : 48a990: mov %rax,-0x10(%rbp) : int m = 0, i; 0.00 : 48a994: movl $0x0,-0x1c(%rbp) : int ret; : : for (i = 0; i < loops; i++) { 0.00 : 48a99b: movl $0x0,-0x18(%rbp) After: : static void *worker_thread(void *__tdata) : { 0.00 : 48a971: push %rbp 0.00 : 48a972: mov %rsp,%rbp 0.00 : 48a975: sub $0x30,%rsp 0.00 : 48a979: mov %rdi,-0x28(%rbp) 0.00 : 48a97d: mov %fs:0x28,%rax 0.00 : 48a986: mov %rax,-0x8(%rbp) 0.00 : 48a98a: xor %eax,%eax : struct thread_data *td = __tdata; 0.00 : 48a98c: mov -0x28(%rbp),%rax 0.00 : 48a990: mov %rax,-0x10(%rbp) : int m = 0, i; 0.00 : 48a994: movl $0x0,-0x1c(%rbp) : int ret; : : for (i = 0; i < loops; i++) { 0.00 : 48a99b: movl $0x0,-0x18(%rbp) It makes bigger different when displaying script sources, where the comment lines looks oddly shifted from the lines which actually hold code. I'll send script support separately. Committer note: Do not use a fixed column width for the addresses, as kernel ones se more than 10 columns, look at the last offset and get the right width. Signed-off-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171011150158.11895-36-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index cb065ca431ee..eab4a8e3c679 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1092,15 +1092,14 @@ static void annotate__branch_printf(struct block_range *br, u64 addr) } } - -static int disasm_line__print(struct disasm_line *dl, u64 start) +static int disasm_line__print(struct disasm_line *dl, u64 start, int addr_fmt_width) { s64 offset = dl->al.offset; const u64 addr = start + offset; struct block_range *br; br = block_range__find(addr); - color_fprintf(stdout, annotate__address_color(br), " %" PRIx64 ":", addr); + color_fprintf(stdout, annotate__address_color(br), " %*" PRIx64 ":", addr_fmt_width, addr); color_fprintf(stdout, annotate__asm_color(br), "%s", dl->al.line); annotate__branch_printf(br, addr); return 0; @@ -1109,7 +1108,7 @@ static int disasm_line__print(struct disasm_line *dl, u64 start) static int annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, - int max_lines, struct annotation_line *queue) + int max_lines, struct annotation_line *queue, int addr_fmt_width) { struct disasm_line *dl = container_of(al, struct disasm_line, al); static const char *prev_line; @@ -1139,7 +1138,7 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start if (queue == al) break; annotation_line__print(queue, sym, start, evsel, len, - 0, 0, 1, NULL); + 0, 0, 1, NULL, addr_fmt_width); } } @@ -1174,9 +1173,9 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start color_fprintf(stdout, color, " %7.2f", sample->percent); } - printf(" : "); + printf(" : "); - disasm_line__print(dl, start); + disasm_line__print(dl, start, addr_fmt_width); printf("\n"); } else if (max_lines && printed >= max_lines) return 1; @@ -1192,7 +1191,7 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start if (!*al->line) printf(" %*s:\n", width, " "); else - printf(" %*s: %s\n", width, " ", al->line); + printf(" %*s: %*s %s\n", width, " ", addr_fmt_width, " ", al->line); } return 0; @@ -1796,6 +1795,19 @@ static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel) printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->nr_samples", h->nr_samples); } +static int annotated_source__addr_fmt_width(struct list_head *lines, u64 start) +{ + char bf[32]; + struct annotation_line *line; + + list_for_each_entry_reverse(line, lines, node) { + if (line->offset != -1) + return scnprintf(bf, sizeof(bf), "%" PRIx64, start + line->offset); + } + + return 0; +} + int symbol__annotate_printf(struct symbol *sym, struct map *map, struct perf_evsel *evsel, bool full_paths, int min_pcnt, int max_lines, int context) @@ -1808,7 +1820,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, struct sym_hist *h = annotation__histogram(notes, evsel->idx); struct annotation_line *pos, *queue = NULL; u64 start = map__rip_2objdump(map, sym->start); - int printed = 2, queue_len = 0; + int printed = 2, queue_len = 0, addr_fmt_width; int more = 0; u64 len; int width = symbol_conf.show_total_period ? 12 : 8; @@ -1839,6 +1851,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, if (verbose > 0) symbol__annotate_hits(sym, evsel); + addr_fmt_width = annotated_source__addr_fmt_width(¬es->src->source, start); + list_for_each_entry(pos, ¬es->src->source, node) { int err; @@ -1849,7 +1863,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, err = annotation_line__print(pos, sym, start, evsel, len, min_pcnt, printed, max_lines, - queue); + queue, addr_fmt_width); switch (err) { case 0: -- cgit v1.2.3 From c2f1cead19b628d7a23d2cfc43e444af669f9eab Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Fri, 20 Oct 2017 13:27:55 -0700 Subject: perf record: Fix -c/-F options for cpu event aliases The Intel PMU event aliases have a implicit period= specifier to set the default period. Unfortunately this breaks overriding these periods with -c or -F, because the alias terms look like they are user specified to the internal parser, and user specified event qualifiers override the command line options. Track that they are coming from aliases by adding a "weak" state to the term. Any weak terms don't override command line options. I only did it for -c/-F for now, I think that's the only case that's broken currently. Before: $ perf record -c 1000 -vv -e uops_issued.any ... { sample_period, sample_freq } 2000003 After: $ perf record -c 1000 -vv -e uops_issued.any ... { sample_period, sample_freq } 1000 Signed-off-by: Andi Kleen Acked-by: Jiri Olsa Link: http://lkml.kernel.org/r/20171020202755.21410-2-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 12 ++++++++---- tools/perf/util/evsel.h | 1 + tools/perf/util/parse-events.c | 2 ++ tools/perf/util/parse-events.h | 3 +++ tools/perf/util/pmu.c | 5 +++++ 5 files changed, 19 insertions(+), 4 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index f894893c203d..bfde6a7a80f2 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -733,12 +733,16 @@ static void apply_config_terms(struct perf_evsel *evsel, list_for_each_entry(term, config_terms, list) { switch (term->type) { case PERF_EVSEL__CONFIG_TERM_PERIOD: - attr->sample_period = term->val.period; - attr->freq = 0; + if (!(term->weak && opts->user_interval != ULLONG_MAX)) { + attr->sample_period = term->val.period; + attr->freq = 0; + } break; case PERF_EVSEL__CONFIG_TERM_FREQ: - attr->sample_freq = term->val.freq; - attr->freq = 1; + if (!(term->weak && opts->user_freq != UINT_MAX)) { + attr->sample_freq = term->val.freq; + attr->freq = 1; + } break; case PERF_EVSEL__CONFIG_TERM_TIME: if (term->val.time) diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 9277df96ffda..157f49e8a772 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -67,6 +67,7 @@ struct perf_evsel_config_term { bool overwrite; char *branch; } val; + bool weak; }; struct perf_stat_evsel; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index a7fcd95961ef..170316795a18 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1116,6 +1116,7 @@ do { \ INIT_LIST_HEAD(&__t->list); \ __t->type = PERF_EVSEL__CONFIG_TERM_ ## __type; \ __t->val.__name = __val; \ + __t->weak = term->weak; \ list_add_tail(&__t->list, head_terms); \ } while (0) @@ -2410,6 +2411,7 @@ static int new_term(struct parse_events_term **_term, *term = *temp; INIT_LIST_HEAD(&term->list); + term->weak = false; switch (term->type_val) { case PARSE_EVENTS__TERM_TYPE_NUM: diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index be337c266697..88108cd11b4c 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -101,6 +101,9 @@ struct parse_events_term { /* error string indexes for within parsed string */ int err_term; int err_val; + + /* Coming from implicit alias */ + bool weak; }; struct parse_events_error { diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 07cb2ac041d7..80fb1593913a 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -405,6 +405,11 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias, parse_events_terms__purge(&list); return ret; } + /* + * Weak terms don't override command line options, + * which we don't want for implicit terms in aliases. + */ + cloned->weak = true; list_add_tail(&cloned->list, &list); } list_splice(&list, terms); -- cgit v1.2.3 From d0565132605f454179699a1b8a3276fc0f8cc87b Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Fri, 20 Oct 2017 13:27:54 -0700 Subject: perf evsel: Enable type checking for perf_evsel_config_term types Use a typed enum for the perf_evsel_config_term type enum. This allows gcc to do much stronger type checks, and also check for missing case statements. I removed the unused _MAX member from the number. It found one missing case. I'm not sure it's a real problem, so I just turned it into a BUG_ON for now. Signed-off-by: Andi Kleen Acked-by: Jiri Olsa Link: http://lkml.kernel.org/r/20171020202755.21410-1-andi@firstfloor.org [ Renamed the enum name to term_type as per jolsa's request ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 2 ++ tools/perf/util/evsel.h | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index bfde6a7a80f2..4376cdfaea49 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -779,6 +779,8 @@ static void apply_config_terms(struct perf_evsel *evsel, case PERF_EVSEL__CONFIG_TERM_OVERWRITE: attr->write_backward = term->val.overwrite ? 1 : 0; break; + case PERF_EVSEL__CONFIG_TERM_DRV_CFG: + BUG_ON(1); default: break; } diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 157f49e8a772..0688880227e1 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -38,7 +38,7 @@ struct cgroup_sel; * It is allocated within event parsing and attached to * perf_evsel::config_terms list head. */ -enum { +enum term_type { PERF_EVSEL__CONFIG_TERM_PERIOD, PERF_EVSEL__CONFIG_TERM_FREQ, PERF_EVSEL__CONFIG_TERM_TIME, @@ -49,12 +49,11 @@ enum { PERF_EVSEL__CONFIG_TERM_OVERWRITE, PERF_EVSEL__CONFIG_TERM_DRV_CFG, PERF_EVSEL__CONFIG_TERM_BRANCH, - PERF_EVSEL__CONFIG_TERM_MAX, }; struct perf_evsel_config_term { struct list_head list; - int type; + enum term_type type; union { u64 period; u64 freq; -- cgit v1.2.3 From 82806c3aae7496d6974429f3bd43ebeeef18b9b2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 9 Nov 2017 12:03:40 -0300 Subject: perf evsel: Fix up leftover perf_evsel_stat usage via evsel->priv I forgot one conversion, which got noticed by Thomas when running: $ perf stat -e '{cpu-clock,instructions}' kill kill: not enough arguments Segmentation fault (core dumped) $ Fix it, those stats are in evsel->stats, not anymore in evsel->priv. Reported-by: Thomas-Mich Richter Tested-by: Thomas-Mich Richter Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Hendrik Brueckner Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Fixes: e669e833da8d ("perf evsel: Restore evsel->priv as a tool private area") Link: http://lkml.kernel.org/r/20171109150046.GN4333@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 4376cdfaea49..cb9bcdb065ea 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1377,7 +1377,7 @@ perf_evsel__process_group_data(struct perf_evsel *leader, static int perf_evsel__read_group(struct perf_evsel *leader, int cpu, int thread) { - struct perf_stat_evsel *ps = leader->priv; + struct perf_stat_evsel *ps = leader->stats; u64 read_format = leader->attr.read_format; int size = perf_evsel__read_size(leader); u64 *data = ps->group_data; -- cgit v1.2.3 From 19993b82a571893e661afd90f1d77fa698785cee Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 13 Nov 2017 16:06:29 -0300 Subject: perf machine: Guard against NULL in machine__exit() A recent fix for 'perf trace' introduced a bug where machine__exit(trace->host) could be called while trace->host was still NULL, so make this more robust by guarding against NULL, just like free() does. The problem happens, for instance, when !root users try to run 'perf trace': [acme@jouet linux]$ trace Error: No permissions to read /sys/kernel/debug/tracing/events/raw_syscalls/sys_(enter|exit) Hint: Try 'sudo mount -o remount,mode=755 /sys/kernel/debug/tracing' perf: Segmentation fault Obtained 7 stack frames. [0x4f1b2e] /lib64/libc.so.6(+0x3671f) [0x7f43a1dd971f] [0x4f3fec] [0x47468b] [0x42a2db] /lib64/libc.so.6(__libc_start_main+0xe9) [0x7f43a1dc3509] [0x42a6c9] Segmentation fault (core dumped) [acme@jouet linux]$ Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andrei Vagin Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Vasily Averin Cc: Wang Nan Fixes: 33974a414ce2 ("perf trace: Call machine__exit() at exit") Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tools/perf/util') diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 6a8d03c3d9b7..270f3223c6df 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -172,6 +172,9 @@ void machine__exit(struct machine *machine) { int i; + if (machine == NULL) + return; + machine__destroy_kernel_maps(machine); map_groups__exit(&machine->kmaps); dsos__exit(&machine->dsos); -- cgit v1.2.3 From 648388ae68e953b312e28eaf869fe6c01e2f70cc Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Tue, 14 Nov 2017 08:55:40 +0530 Subject: perf annotate: Do not truncate instruction names at 6 chars There are many instructions, esp on PowerPC, whose mnemonics are longer than 6 characters. Using precision limit causes truncation of such mnemonics. Fix this by removing precision limit. Note that, 'width' is still 6, so alignment won't get affected for length <= 6. Before: li r11,-1 xscvdp vs1,vs1 add. r10,r10,r11 After: li r11,-1 xscvdpsxds vs1,vs1 add. r10,r10,r11 Reported-by: Donald Stence Signed-off-by: Ravi Bangoria Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Taeung Song Link: http://lkml.kernel.org/r/20171114032540.4564-1-ravi.bangoria@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index eab4a8e3c679..30d74dabdc42 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -165,7 +165,7 @@ static void ins__delete(struct ins_operands *ops) static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops) { - return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw); + return scnprintf(bf, size, "%-6s %s", ins->name, ops->raw); } int ins__scnprintf(struct ins *ins, char *bf, size_t size, @@ -230,12 +230,12 @@ static int call__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops) { if (ops->target.name) - return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name); + return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.name); if (ops->target.addr == 0) return ins__raw_scnprintf(ins, bf, size, ops); - return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr); + return scnprintf(bf, size, "%-6s *%" PRIx64, ins->name, ops->target.addr); } static struct ins_ops call_ops = { @@ -299,7 +299,7 @@ static int jump__scnprintf(struct ins *ins, char *bf, size_t size, c++; } - return scnprintf(bf, size, "%-6.6s %.*s%" PRIx64, + return scnprintf(bf, size, "%-6s %.*s%" PRIx64, ins->name, c ? c - ops->raw : 0, ops->raw, ops->target.offset); } @@ -372,7 +372,7 @@ static int lock__scnprintf(struct ins *ins, char *bf, size_t size, if (ops->locked.ins.ops == NULL) return ins__raw_scnprintf(ins, bf, size, ops); - printed = scnprintf(bf, size, "%-6.6s ", ins->name); + printed = scnprintf(bf, size, "%-6s ", ins->name); return printed + ins__scnprintf(&ops->locked.ins, bf + printed, size - printed, ops->locked.ops); } @@ -448,7 +448,7 @@ out_free_source: static int mov__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops) { - return scnprintf(bf, size, "%-6.6s %s,%s", ins->name, + return scnprintf(bf, size, "%-6s %s,%s", ins->name, ops->source.name ?: ops->source.raw, ops->target.name ?: ops->target.raw); } @@ -488,7 +488,7 @@ static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops static int dec__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops) { - return scnprintf(bf, size, "%-6.6s %s", ins->name, + return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.name ?: ops->target.raw); } @@ -500,7 +500,7 @@ static struct ins_ops dec_ops = { static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size, struct ins_operands *ops __maybe_unused) { - return scnprintf(bf, size, "%-6.6s", "nop"); + return scnprintf(bf, size, "%-6s", "nop"); } static struct ins_ops nop_ops = { @@ -990,7 +990,7 @@ void disasm_line__free(struct disasm_line *dl) int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw) { if (raw || !dl->ins.ops) - return scnprintf(bf, size, "%-6.6s %s", dl->ins.name, dl->ops.raw); + return scnprintf(bf, size, "%-6s %s", dl->ins.name, dl->ops.raw); return ins__scnprintf(&dl->ins, bf, size, &dl->ops); } -- cgit v1.2.3 From 07d6f446a9e45b7e6e7438f8560e40d4dcfa0321 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 14 Nov 2017 11:01:06 -0300 Subject: perf evlist: Add helper to check if attr.exclude_kernel is set in all evsels The warning about kptr_restrict needs to be emitted only when it is set and we ask for kernel space samples, so add a helper to help with that. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-fh7drty6yljei9gxxzer6eup@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 12 ++++++++++++ tools/perf/util/evlist.h | 2 ++ 2 files changed, 14 insertions(+) (limited to 'tools/perf/util') diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index ccb749f9a83f..b62e523a7035 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1786,3 +1786,15 @@ void perf_evlist__toggle_bkw_mmap(struct perf_evlist *evlist, state_err: return; } + +bool perf_evlist__exclude_kernel(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel; + + evlist__for_each_entry(evlist, evsel) { + if (!evsel->attr.exclude_kernel) + return false; + } + + return true; +} diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index e72ae64c11ac..491f69542920 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -312,4 +312,6 @@ perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, const char *str); struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, union perf_event *event); + +bool perf_evlist__exclude_kernel(struct perf_evlist *evlist); #endif /* __PERF_EVLIST_H */ -- cgit v1.2.3 From 114bc191c37028d87a540251d93e7b328f4de3fe Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Tue, 14 Nov 2017 15:04:52 -0600 Subject: perf evsel: Say which PMU Hardware event doesn't support sampling/overflow-interrupts Help identify to the user the event with the unsupported sampling error. Also suggest a corrective action. BEFORE: $ sudo ./oldperf record -e armv8_pmuv3/mem_access/,ccn/cycles/,armv8_pmuv3/l2d_cache/ true Error: PMU Hardware doesn't support sampling/overflow-interrupts. AFTER: $ sudo ./newperf record -e armv8_pmuv3/mem_access/,ccn/cycles/,armv8_pmuv3/l2d_cache/ true Error: ccn/cycles/: PMU Hardware doesn't support sampling/overflow-interrupts. Try 'perf stat' Signed-off-by: Kim Phillips Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171114150452.e846f2e23684c7d7d8ee706f@arm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index cb9bcdb065ea..b8e9def77f44 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -2745,8 +2745,9 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, break; case EOPNOTSUPP: if (evsel->attr.sample_period != 0) - return scnprintf(msg, size, "%s", - "PMU Hardware doesn't support sampling/overflow-interrupts."); + return scnprintf(msg, size, + "%s: PMU Hardware doesn't support sampling/overflow-interrupts. Try 'perf stat'", + perf_evsel__name(evsel)); if (evsel->attr.precise_ip) return scnprintf(msg, size, "%s", "\'precise\' request may not be supported. Try removing 'p' modifier."); -- cgit v1.2.3 From 914eb9ca51117776d83e6761a1c555fb76f0ded2 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 6 Aug 2017 16:39:39 +0200 Subject: perf callchain: Reset cursor arg instead of callchain_cursor We already pass cursor into thread__resolve_callchain function, so there's no point in resetting the global instance. Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-puk015qvuppao9m1xtdy9v7j@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 270f3223c6df..64d255f6a537 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -2204,7 +2204,7 @@ int thread__resolve_callchain(struct thread *thread, { int ret = 0; - callchain_cursor_reset(&callchain_cursor); + callchain_cursor_reset(cursor); if (callchain_param.order == ORDER_CALLEE) { ret = thread__resolve_callchain_sample(thread, cursor, -- cgit v1.2.3 From 3ad31d8a0df257c3f18c989119359c1f25cd009d Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 3 Aug 2017 16:07:05 +0200 Subject: perf evsel: Centralize perf_sample initialization Move the initialization bits into common place at the beginning of the function. Also removing some superfluous zero initialization for addr and transaction, because we zero all the data at the top. Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-1gv5t6fvv735t1rt3mxpy1h9@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index b8e9def77f44..03d7abcdc6b7 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1983,6 +1983,8 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, data->stream_id = data->id = data->time = -1ULL; data->period = evsel->attr.sample_period; data->cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + data->id = -1ULL; + data->data_src = PERF_MEM_DATA_SRC_NONE; if (event->header.type != PERF_RECORD_SAMPLE) { if (!evsel->attr.sample_id_all) @@ -2000,7 +2002,6 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, if (evsel->sample_size + sizeof(event->header) > event->header.size) return -EFAULT; - data->id = -1ULL; if (type & PERF_SAMPLE_IDENTIFIER) { data->id = *array; array++; @@ -2030,7 +2031,6 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, array++; } - data->addr = 0; if (type & PERF_SAMPLE_ADDR) { data->addr = *array; array++; @@ -2194,14 +2194,12 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, array++; } - data->data_src = PERF_MEM_DATA_SRC_NONE; if (type & PERF_SAMPLE_DATA_SRC) { OVERFLOW_CHECK_u64(array); data->data_src = *array; array++; } - data->transaction = 0; if (type & PERF_SAMPLE_TRANSACTION) { OVERFLOW_CHECK_u64(array); data->transaction = *array; -- cgit v1.2.3 From 014681208ea0d1a7e5ea2f014242e7d196d04c34 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 3 Aug 2017 13:10:28 +0200 Subject: perf evlist: Add perf_evlist__parse_sample_timestamp function Add perf_evlist__parse_sample_timestamp to retrieve the timestamp of the sample. The idea is to use this function instead of the full sample parsing before we queue the sample. At that time only the timestamp is needed and we parse the sample once again later on delivery. Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-o7syqo8lipj4or7renpu8e8y@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 11 ++++++++ tools/perf/util/evlist.h | 4 +++ tools/perf/util/evsel.c | 65 +++++++++++++++++++++++++++++++++++++++++++----- tools/perf/util/evsel.h | 4 +++ 4 files changed, 78 insertions(+), 6 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index b62e523a7035..199bb82efbcd 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1582,6 +1582,17 @@ int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *even return perf_evsel__parse_sample(evsel, event, sample); } +int perf_evlist__parse_sample_timestamp(struct perf_evlist *evlist, + union perf_event *event, + u64 *timestamp) +{ + struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event); + + if (!evsel) + return -EFAULT; + return perf_evsel__parse_sample_timestamp(evsel, event, timestamp); +} + size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp) { struct perf_evsel *evsel; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 491f69542920..4e8131dacbd7 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -205,6 +205,10 @@ u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist); int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, struct perf_sample *sample); +int perf_evlist__parse_sample_timestamp(struct perf_evlist *evlist, + union perf_event *event, + u64 *timestamp); + bool perf_evlist__valid_sample_type(struct perf_evlist *evlist); bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist); bool perf_evlist__valid_read_format(struct perf_evlist *evlist); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 03d7abcdc6b7..95853c51c0ca 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1962,6 +1962,20 @@ static inline bool overflow(const void *endp, u16 max_size, const void *offset, #define OVERFLOW_CHECK_u64(offset) \ OVERFLOW_CHECK(offset, sizeof(u64), sizeof(u64)) +static int +perf_event__check_size(union perf_event *event, unsigned int sample_size) +{ + /* + * The evsel's sample_size is based on PERF_SAMPLE_MASK which includes + * up to PERF_SAMPLE_PERIOD. After that overflow() must be used to + * check the format does not go past the end of the event. + */ + if (sample_size + sizeof(event->header) > event->header.size) + return -EFAULT; + + return 0; +} + int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, struct perf_sample *data) { @@ -1994,12 +2008,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, array = event->sample.array; - /* - * The evsel's sample_size is based on PERF_SAMPLE_MASK which includes - * up to PERF_SAMPLE_PERIOD. After that overflow() must be used to - * check the format does not go past the end of the event. - */ - if (evsel->sample_size + sizeof(event->header) > event->header.size) + if (perf_event__check_size(event, evsel->sample_size)) return -EFAULT; if (type & PERF_SAMPLE_IDENTIFIER) { @@ -2232,6 +2241,50 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, return 0; } +int perf_evsel__parse_sample_timestamp(struct perf_evsel *evsel, + union perf_event *event, + u64 *timestamp) +{ + u64 type = evsel->attr.sample_type; + const u64 *array; + + if (!(type & PERF_SAMPLE_TIME)) + return -1; + + if (event->header.type != PERF_RECORD_SAMPLE) { + struct perf_sample data = { + .time = -1ULL, + }; + + if (!evsel->attr.sample_id_all) + return -1; + if (perf_evsel__parse_id_sample(evsel, event, &data)) + return -1; + + *timestamp = data.time; + return 0; + } + + array = event->sample.array; + + if (perf_event__check_size(event, evsel->sample_size)) + return -EFAULT; + + if (type & PERF_SAMPLE_IDENTIFIER) + array++; + + if (type & PERF_SAMPLE_IP) + array++; + + if (type & PERF_SAMPLE_TID) + array++; + + if (type & PERF_SAMPLE_TIME) + *timestamp = *array; + + return 0; +} + size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format) { diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 0688880227e1..c3663a70c9b9 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -338,6 +338,10 @@ static inline int perf_evsel__read_on_cpu_scaled(struct perf_evsel *evsel, int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, struct perf_sample *sample); +int perf_evsel__parse_sample_timestamp(struct perf_evsel *evsel, + union perf_event *event, + u64 *timestamp); + static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel) { return list_entry(evsel->node.next, struct perf_evsel, node); -- cgit v1.2.3 From dc83e1394083d6e12625a3158bf88396dfaec633 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 3 Aug 2017 13:24:33 +0200 Subject: perf ordered_events: Pass timestamp arg in perf_session__queue_event There's no need to pass whole sample data, because it's only timestamp that is used. Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-xd1hpoze3kgb1rb639o3vehb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kvm.c | 2 +- tools/perf/util/ordered-events.c | 3 +-- tools/perf/util/ordered-events.h | 2 +- tools/perf/util/session.c | 6 +++--- tools/perf/util/session.h | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 0c36f2ac6a0e..cd253db6917f 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -754,7 +754,7 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx, return -1; } - err = perf_session__queue_event(kvm->session, event, &sample, 0); + err = perf_session__queue_event(kvm->session, event, sample.time, 0); /* * FIXME: Here we can't consume the event, as perf_session__queue_event will * point to it, and it'll get possibly overwritten by the kernel. diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c index 8e09fd2d842f..bad9e0296e9a 100644 --- a/tools/perf/util/ordered-events.c +++ b/tools/perf/util/ordered-events.c @@ -157,9 +157,8 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *eve } int ordered_events__queue(struct ordered_events *oe, union perf_event *event, - struct perf_sample *sample, u64 file_offset) + u64 timestamp, u64 file_offset) { - u64 timestamp = sample->time; struct ordered_event *oevent; if (!timestamp || timestamp == ~0ULL) diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h index 96e5292d88e2..8c7a2948593e 100644 --- a/tools/perf/util/ordered-events.h +++ b/tools/perf/util/ordered-events.h @@ -45,7 +45,7 @@ struct ordered_events { }; int ordered_events__queue(struct ordered_events *oe, union perf_event *event, - struct perf_sample *sample, u64 file_offset); + u64 timestamp, u64 file_offset); void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event); int ordered_events__flush(struct ordered_events *oe, enum oe_flush how); void ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t deliver); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 5c412310f266..8976e417eab2 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -873,9 +873,9 @@ static int process_finished_round(struct perf_tool *tool __maybe_unused, } int perf_session__queue_event(struct perf_session *s, union perf_event *event, - struct perf_sample *sample, u64 file_offset) + u64 timestamp, u64 file_offset) { - return ordered_events__queue(&s->ordered_events, event, sample, file_offset); + return ordered_events__queue(&s->ordered_events, event, timestamp, file_offset); } static void callchain__lbr_callstack_printf(struct perf_sample *sample) @@ -1517,7 +1517,7 @@ static s64 perf_session__process_event(struct perf_session *session, return ret; if (tool->ordered_events) { - ret = perf_session__queue_event(session, event, &sample, file_offset); + ret = perf_session__queue_event(session, event, sample.time, file_offset); if (ret != -ETIME) return ret; } diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 80bc80de8362..5b1c32b3694a 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -53,7 +53,7 @@ int perf_session__peek_event(struct perf_session *session, off_t file_offset, int perf_session__process_events(struct perf_session *session); int perf_session__queue_event(struct perf_session *s, union perf_event *event, - struct perf_sample *sample, u64 file_offset); + u64 timestamp, u64 file_offset); void perf_tool__fill_defaults(struct perf_tool *tool); -- cgit v1.2.3 From 93d10af26bb7159349158b721ba2e258291d53c3 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 3 Aug 2017 13:21:14 +0200 Subject: perf tools: Optimize sample parsing for ordered events Currently when using ordered events we parse the sample twice (the perf_evlist__parse_sample function). Once before we queue the sample for sorting: perf_session__process_event perf_evlist__parse_sample(sample) perf_session__queue_event(sample.time) And then when we deliver the sorted sample: ordered_events__deliver_event perf_evlist__parse_sample perf_session__deliver_event We can skip the initial full sample parsing by using perf_evlist__parse_sample_timestamp function, which got introduced earlier. The new path looks like: perf_session__process_event perf_evlist__parse_sample_timestamp perf_session__queue_event ordered_events__deliver_event perf_session__deliver_event perf_evlist__parse_sample It saves some instructions and is slightly faster: Before: Performance counter stats for './perf.old report --stdio' (5 runs): 64,396,007,225 cycles:u ( +- 0.97% ) 105,882,112,735 instructions:u # 1.64 insn per cycle ( +- 0.00% ) 21.618103465 seconds time elapsed ( +- 1.12% ) After: Performance counter stats for './perf report --stdio' (5 runs): 60,567,807,182 cycles:u ( +- 0.40% ) 104,853,333,514 instructions:u # 1.73 insn per cycle ( +- 0.00% ) 20.168895243 seconds time elapsed ( +- 0.32% ) Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-cjp2tuk0qkjs9dxzlpmm34ua@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kvm.c | 8 ++++---- tools/perf/util/session.c | 41 ++++++++++++++++++----------------------- 2 files changed, 22 insertions(+), 27 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index cd253db6917f..597c7de9bec9 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -741,20 +741,20 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx, u64 *mmap_time) { union perf_event *event; - struct perf_sample sample; + u64 timestamp; s64 n = 0; int err; *mmap_time = ULLONG_MAX; while ((event = perf_evlist__mmap_read(kvm->evlist, idx)) != NULL) { - err = perf_evlist__parse_sample(kvm->evlist, event, &sample); + err = perf_evlist__parse_sample_timestamp(kvm->evlist, event, ×tamp); if (err) { perf_evlist__mmap_consume(kvm->evlist, idx); pr_err("Failed to parse sample\n"); return -1; } - err = perf_session__queue_event(kvm->session, event, sample.time, 0); + err = perf_session__queue_event(kvm->session, event, timestamp, 0); /* * FIXME: Here we can't consume the event, as perf_session__queue_event will * point to it, and it'll get possibly overwritten by the kernel. @@ -768,7 +768,7 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx, /* save time stamp of our first sample for this mmap */ if (n == 0) - *mmap_time = sample.time; + *mmap_time = timestamp; /* limit events per mmap handled all at once */ n++; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 8976e417eab2..df2857137908 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -27,7 +27,6 @@ static int perf_session__deliver_event(struct perf_session *session, union perf_event *event, - struct perf_sample *sample, struct perf_tool *tool, u64 file_offset); @@ -107,17 +106,10 @@ static void perf_session__set_comm_exec(struct perf_session *session) static int ordered_events__deliver_event(struct ordered_events *oe, struct ordered_event *event) { - struct perf_sample sample; struct perf_session *session = container_of(oe, struct perf_session, ordered_events); - int ret = perf_evlist__parse_sample(session->evlist, event->event, &sample); - - if (ret) { - pr_err("Can't parse sample, err = %d\n", ret); - return ret; - } - return perf_session__deliver_event(session, event->event, &sample, + return perf_session__deliver_event(session, event->event, session->tool, event->file_offset); } @@ -1328,20 +1320,26 @@ static int machines__deliver_event(struct machines *machines, static int perf_session__deliver_event(struct perf_session *session, union perf_event *event, - struct perf_sample *sample, struct perf_tool *tool, u64 file_offset) { + struct perf_sample sample; int ret; - ret = auxtrace__process_event(session, event, sample, tool); + ret = perf_evlist__parse_sample(session->evlist, event, &sample); + if (ret) { + pr_err("Can't parse sample, err = %d\n", ret); + return ret; + } + + ret = auxtrace__process_event(session, event, &sample, tool); if (ret < 0) return ret; if (ret > 0) return 0; return machines__deliver_event(&session->machines, session->evlist, - event, sample, tool, file_offset); + event, &sample, tool, file_offset); } static s64 perf_session__process_user_event(struct perf_session *session, @@ -1495,7 +1493,6 @@ static s64 perf_session__process_event(struct perf_session *session, { struct perf_evlist *evlist = session->evlist; struct perf_tool *tool = session->tool; - struct perf_sample sample; int ret; if (session->header.needs_swap) @@ -1509,21 +1506,19 @@ static s64 perf_session__process_event(struct perf_session *session, if (event->header.type >= PERF_RECORD_USER_TYPE_START) return perf_session__process_user_event(session, event, file_offset); - /* - * For all kernel events we get the sample data - */ - ret = perf_evlist__parse_sample(evlist, event, &sample); - if (ret) - return ret; - if (tool->ordered_events) { - ret = perf_session__queue_event(session, event, sample.time, file_offset); + u64 timestamp; + + ret = perf_evlist__parse_sample_timestamp(evlist, event, ×tamp); + if (ret) + return ret; + + ret = perf_session__queue_event(session, event, timestamp, file_offset); if (ret != -ETIME) return ret; } - return perf_session__deliver_event(session, event, &sample, tool, - file_offset); + return perf_session__deliver_event(session, event, tool, file_offset); } void perf_event_header__bswap(struct perf_event_header *hdr) -- cgit v1.2.3 From 9e4e0a9d2ef37c7bc60c32e2a3189bd1f04067a5 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 15 Nov 2017 12:05:59 +0100 Subject: perf tools: Change (symbol|annotation)__calc_percent return type to void There's no need for symbol__calc_percent and annotation__calc_percent functions to return any value, since it's always zero. Changing both function to return void. Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-z0gs28hh24m4gia1t1ctraye@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 17 ++++++++--------- tools/perf/util/annotate.h | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 30d74dabdc42..846abb4955ac 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1584,8 +1584,8 @@ static void calc_percent(struct sym_hist *hist, } } -static int annotation__calc_percent(struct annotation *notes, - struct perf_evsel *evsel, s64 len) +static void annotation__calc_percent(struct annotation *notes, + struct perf_evsel *evsel, s64 len) { struct annotation_line *al, *next; @@ -1609,15 +1609,13 @@ static int annotation__calc_percent(struct annotation *notes, calc_percent(hist, sample, al->offset, end); } } - - return 0; } -int symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel) +void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel) { struct annotation *notes = symbol__annotation(sym); - return annotation__calc_percent(notes, evsel, symbol__size(sym)); + annotation__calc_percent(notes, evsel, symbol__size(sym)); } int symbol__annotate(struct symbol *sym, struct map *map, @@ -1656,10 +1654,11 @@ int symbol__annotate(struct symbol *sym, struct map *map, } err = symbol__disassemble(sym, &args); - if (err) - return err; + if (!err) + symbol__calc_percent(sym, evsel); + + return err; - return symbol__calc_percent(sym, evsel); } static void insert_source_line(struct rb_root *root, struct annotation_line *al) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 4fc805a271d2..6d7289e88fa3 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -107,7 +107,7 @@ struct annotation_line * annotation_line__next(struct annotation_line *pos, struct list_head *head); int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); size_t disasm__fprintf(struct list_head *head, FILE *fp); -int symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); +void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); struct sym_hist { u64 nr_samples; -- cgit v1.2.3 From 05d3f1a1d5a3d37ca4b591d5524f5a5b159d0564 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 15 Nov 2017 12:20:08 +0100 Subject: perf tools: Move symbol__calc_percent() call to outside symbol__disassemble() We need to call symbol__calc_percent() periodicaly for top, so it's no longer convenient to keep it in symbol__disassemble(). Let's separate the symbol__disassemble() to allocate and init the symbol annotation structs and symbol__calc_percent() to compute the lines percentages based on symbol hists data. Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-gtnp8t4tb00q6lag07psn5nq@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 2 ++ tools/perf/ui/gtk/annotate.c | 2 ++ tools/perf/util/annotate.c | 9 +++------ 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 5a2f37a91feb..03b7363a49c9 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -1126,6 +1126,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, goto out_free_offsets; } + symbol__calc_percent(sym, evsel); + ui_helpline__push("Press ESC to exit"); notes = symbol__annotation(sym); diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index 5e0a56df0b4c..cdb5ecf91666 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c @@ -177,6 +177,8 @@ static int symbol__gtk_annotate(struct symbol *sym, struct map *map, return -1; } + symbol__calc_percent(sym, evsel); + if (perf_gtk__is_active_context(pgctx)) { window = pgctx->main_window; notebook = pgctx->notebook; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 846abb4955ac..22ea7936d92f 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1653,12 +1653,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, } } - err = symbol__disassemble(sym, &args); - if (!err) - symbol__calc_percent(sym, evsel); - - return err; - + return symbol__disassemble(sym, &args); } static void insert_source_line(struct rb_root *root, struct annotation_line *al) @@ -2005,6 +2000,8 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, if (symbol__annotate(sym, map, evsel, 0, NULL, NULL) < 0) return -1; + symbol__calc_percent(sym, evsel); + if (print_lines) { srcline_full_filename = full_paths; symbol__calc_lines(sym, map, &source_line); -- cgit v1.2.3