[PATCH v1 2/4] perf annotate: Display multiple events for stdio mode

From: Jin Yao
Date: Tue Aug 15 2017 - 22:23:01 EST


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.jin@xxxxxxxxxxxxxxx>
---
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(&notes->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, &notes->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