For example: perf record -e cycles,branches ./div perf annotate main --stdio
Percent | Source code & Disassembly of div for branches,cycles (90966 samples) -------------------------------------------------------------------------------------------- ...... : for (i = 0; i < 2000000000; i++) { : flag = compute_flag(); 5.77 4.85 : 4004e8: xor %eax,%eax 0.01 0.01 : 4004ea: callq 400640 <compute_flag> : : count++; 2.38 4.38 : 4004ef: mov 0x200b57(%rip),%edx 0.00 0.00 : 4004f5: add $0x1,%edx : : if (flag) 0.00 0.00 : 4004f8: test %eax,%eax : srand(s_randseed); : : for (i = 0; i < 2000000000; i++) { : flag = compute_flag(); : : count++; 0.60 0.44 : 4004fa: mov %edx,0x200b4c(%rip) : : if (flag) 3.99 4.32 : 400500: je 400532 <main+0x82> Signed-off-by: Jin Yao <yao....@linux.intel.com> --- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-top.c | 3 +- tools/perf/util/annotate.c | 179 ++++++++++++++++++++++++++++++++---------- tools/perf/util/annotate.h | 6 +- 4 files changed, 145 insertions(+), 45 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 833866c..98663bd 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -240,7 +240,7 @@ static int hist_entry__tty_annotate(struct hist_entry *he, struct perf_annotate *ann) { return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel, - ann->print_line, ann->full_paths, 0, 0); + ann->print_line, ann->full_paths, 0, 0, he); } static void hists__find_annotations(struct hists *hists, diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index ee954bd..2287667 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -245,7 +245,8 @@ static void perf_top__show_details(struct perf_top *top) printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel, - 0, top->sym_pcnt_filter, top->print_entries, 4); + 0, top->sym_pcnt_filter, + top->print_entries, 4, NULL); if (top->evlist->enabled) { if (top->zero) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 16ec881..8630108 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1071,7 +1071,8 @@ 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) + int max_lines, struct disasm_line *queue, + struct hist_entry *he) { static const char *prev_line; static const char *prev_color; @@ -1082,31 +1083,39 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st double *ppercents = &percent; struct sym_hist_entry sample; struct sym_hist_entry *psamples = &sample; - int i, nr_percent = 1; + int i, nr_percent; const char *color; struct annotation *notes = symbol__annotation(sym); s64 offset = dl->offset; const u64 addr = start + offset; struct disasm_line *next; struct block_range *br; + struct hist_event *hevt; next = disasm__get_next_ip_line(¬es->src->source, dl); - - 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; - } + nr_percent = (evsel) ? 1 : he->event_nr; + 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, + if (evsel) { + percent = disasm__calc_percent(notes, notes->src->lines ? i : evsel->idx + i, offset, next ? next->offset : (s64) len, &path, &sample); + } else { + hevt = &he->events[i]; + notes = symbol__annotation(hevt->ms.sym); + percent = disasm__calc_percent(notes, + hevt->idx, + offset, + next ? next->offset : (s64) len, + &path, &sample); + } ppercents[i] = percent; psamples[i] = sample; @@ -1125,7 +1134,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st if (queue == dl) break; disasm_line__print(queue, sym, start, evsel, len, - 0, 0, 1, NULL); + 0, 0, 1, NULL, he); } } @@ -1179,7 +1188,9 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st if (queue) return -1; - if (perf_evsel__is_group_event(evsel)) + if (!evsel) + width *= he->event_nr; + else if (perf_evsel__is_group_event(evsel)) width *= evsel->nr_members; if (!*dl->line) @@ -1682,25 +1693,32 @@ static void symbol__free_source_line(struct symbol *sym, int len) /* 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) + struct rb_root *root, int len, + struct hist_entry *he) { 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 sym_hist *h; struct rb_root tmp_root = RB_ROOT; int nr_pcnt = 1; - u64 nr_samples = h->nr_samples; + u64 nr_samples = 0; size_t sizeof_src_line = sizeof(struct source_line); + struct hist_event *hevt; - if (perf_evsel__is_group_event(evsel)) { - for (i = 1; i < evsel->nr_members; i++) { - h = annotation__histogram(notes, evidx + i); + if (evsel) { + h = annotation__histogram(notes, evsel->idx); + nr_samples = h->nr_samples; + } else { + for (i = 0; i < he->event_nr; i++) { + hevt = &he->events[i]; + notes = symbol__annotation(hevt->ms.sym); + h = annotation__histogram(notes, hevt->idx); nr_samples += h->nr_samples; } - nr_pcnt = evsel->nr_members; + + nr_pcnt = he->event_nr; sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->samples); } @@ -1722,7 +1740,15 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, for (k = 0; k < nr_pcnt; k++) { double percent = 0.0; - h = annotation__histogram(notes, evidx + k); + if (evsel) { + h = annotation__histogram(notes, + evsel->idx + k); + } else { + hevt = &he->events[k]; + notes = symbol__annotation(hevt->ms.sym); + h = annotation__histogram(notes, hevt->idx); + } + nr_samples = h->addr[i].nr_samples; if (h->nr_samples) percent = 100.0 * nr_samples / h->nr_samples; @@ -1787,29 +1813,67 @@ static void print_summary(struct rb_root *root, const char *filename) } } -static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel) +static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel, + struct hist_entry *he) { struct annotation *notes = symbol__annotation(sym); - struct sym_hist *h = annotation__histogram(notes, evsel->idx); + struct sym_hist *h; u64 len = symbol__size(sym), offset; + int i; + struct hist_event *hevt; - for (offset = 0; offset < len; ++offset) - if (h->addr[offset].nr_samples != 0) - printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2, - sym->start + offset, h->addr[offset].nr_samples); - printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->nr_samples", h->nr_samples); + for (offset = 0; offset < len; ++offset) { + if (evsel) { + h = annotation__histogram(notes, evsel->idx); + + if (h->addr[offset].nr_samples != 0) { + printf("%*" PRIx64 ": %" PRIu64 "\n", + BITS_PER_LONG / 2, + sym->start + offset, + h->addr[offset].nr_samples); + } + } else { + for (i = 0; i < he->event_nr; i++) { + hevt = &he->events[i]; + notes = symbol__annotation(hevt->ms.sym); + h = annotation__histogram(notes, hevt->idx); + + if (h->addr[offset].nr_samples != 0) { + printf("%*" PRIx64 ": %" PRIu64 "\n", + BITS_PER_LONG / 2, + sym->start + offset, + h->addr[offset].nr_samples); + } + } + } + } + + if (evsel) { + h = annotation__histogram(notes, evsel->idx); + printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, + "h->nr_samples", h->nr_samples); + } else { + for (i = 0; i < he->event_nr; i++) { + hevt = &he->events[i]; + notes = symbol__annotation(hevt->ms.sym); + h = annotation__histogram(notes, hevt->idx); + + printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, + "h->nr_samples", h->nr_samples); + } + } } 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) + int min_pcnt, int max_lines, int context, + struct hist_entry *he) { struct dso *dso = map->dso; char *filename; const char *d_filename; - const char *evsel_name = perf_evsel__name(evsel); struct annotation *notes = symbol__annotation(sym); - struct sym_hist *h = annotation__histogram(notes, evsel->idx); + struct sym_hist *h; struct disasm_line *pos, *queue = NULL; u64 start = map__rip_2objdump(map, sym->start); int printed = 2, queue_len = 0; @@ -1817,6 +1881,30 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, u64 len; int width = symbol_conf.show_total_period ? 12 : 8; int graph_dotted_len; + char name_buf[128]; + int i, name_printed = 0; + u64 nr_samples = 0; + struct hist_event *hevt; + + if (evsel) { + strncpy(name_buf, perf_evsel__name(evsel), sizeof(name_buf)); + h = annotation__histogram(notes, evsel->idx); + nr_samples = h->nr_samples; + + } else { + for (i = 0; i < he->event_nr; i++) { + hevt = &he->events[i]; + name_printed += scnprintf(name_buf + name_printed, + sizeof(name_buf) - name_printed, + "%s%s", + perf_evsel__name(hevt->evsel), + (i < he->event_nr - 1) ? "," : ""); + + notes = symbol__annotation(hevt->ms.sym); + h = annotation__histogram(notes, hevt->idx); + nr_samples += h->nr_samples; + } + } filename = strdup(dso->long_name); if (!filename) @@ -1829,18 +1917,20 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, len = symbol__size(sym); - if (perf_evsel__is_group_event(evsel)) + if (!evsel) + width *= he->event_nr; + else if (perf_evsel__is_group_event(evsel)) width *= evsel->nr_members; graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n", width, width, symbol_conf.show_total_period ? "Event count" : "Percent", - d_filename, evsel_name, h->nr_samples); + d_filename, name_buf, nr_samples); printf("%-*.*s----\n", graph_dotted_len, graph_dotted_len, graph_dotted_line); if (verbose > 0) - symbol__annotate_hits(sym, evsel); + symbol__annotate_hits(sym, evsel, he); list_for_each_entry(pos, ¬es->src->source, node) { if (context && queue == NULL) { @@ -1850,7 +1940,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, switch (disasm_line__print(pos, sym, start, evsel, len, min_pcnt, printed, max_lines, - queue)) { + queue, he)) { case 0: ++printed; if (context) { @@ -1945,26 +2035,33 @@ size_t disasm__fprintf(struct list_head *head, FILE *fp) 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) + bool full_paths, int min_pcnt, int max_lines, + struct hist_entry *he) { struct dso *dso = map->dso; struct rb_root source_line = RB_ROOT; u64 len; + char *arch; - if (symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), + if (!evsel) + arch = perf_evsel__env_arch(he->events[0].evsel); + else + arch = perf_evsel__env_arch(evsel); + + if (symbol__disassemble(sym, map, arch, 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__get_source_line(sym, map, evsel, &source_line, len, he); print_summary(&source_line, dso->long_name); } symbol__annotate_printf(sym, map, evsel, full_paths, - min_pcnt, max_lines, 0); + min_pcnt, max_lines, 0, he); + if (print_lines) symbol__free_source_line(sym, len); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 0d44cfe..83b78ff 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -198,7 +198,8 @@ int symbol__strerror_disassemble(struct symbol *sym, struct map *map, 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); + int min_pcnt, int max_lines, int context, + struct hist_entry *he); 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); @@ -207,7 +208,8 @@ bool ui__has_annotation(void); 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); + bool full_paths, int min_pcnt, int max_lines, + struct hist_entry *he); #ifdef HAVE_SLANG_SUPPORT int symbol__tui_annotate(struct symbol *sym, struct map *map, -- 2.7.4