From 78f7defedbb4da73b9a07635c357c1afcaa55c8f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 4 Feb 2011 09:45:46 -0200 Subject: perf annotate: Move annotate functions to util/ They will be used by perf top, so that we have just one set of routines to do annotation. Rename "struct sym_priv" to "struct annotation", etc, to clarify this code a bit. Rename "struct sym_ext" to "struct source_line", to give it a meaningful name, that clarifies that it is a the result of an addr2line call, that is sorted by percentage one particular source code line appeared in the annotation. And since we're moving things around also rename 'sym_hist->ip' to 'sym_hist->addr' as we want to do data structure annotation at some point. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/annotate.c | 43 ++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 17 deletions(-) (limited to 'tools/perf/util/ui/browsers/annotate.c') diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 82b78f99251..daa7138d801 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -1,9 +1,11 @@ #include "../browser.h" #include "../helpline.h" #include "../libslang.h" +#include "../../annotate.h" #include "../../hist.h" #include "../../sort.h" #include "../../symbol.h" +#include "../../annotate.h" static void ui__error_window(const char *fmt, ...) { @@ -66,24 +68,26 @@ static double objdump_line__calc_percent(struct objdump_line *self, if (self->offset != -1) { int len = sym->end - sym->start; unsigned int hits = 0; - struct sym_priv *priv = symbol__priv(sym); - struct sym_ext *sym_ext = priv->ext; - struct sym_hist *h = priv->hist; + struct annotation *notes = symbol__annotation(sym); + struct source_line *src_line = notes->src_line; + struct sym_hist *h = notes->histogram; s64 offset = self->offset; struct objdump_line *next = objdump__get_next_ip_line(head, self); - while (offset < (s64)len && (next == NULL || offset < next->offset)) { - if (sym_ext) { - percent += sym_ext[offset].percent; + if (src_line) { + percent += src_line[offset].percent; } else - hits += h->ip[offset]; + hits += h->addr[offset]; ++offset; } - - if (sym_ext == NULL && h->sum) + /* + * If the percentage wasn't already calculated in + * symbol__get_source_line, do it now: + */ + if (src_line == NULL && h->sum) percent = 100.0 * hits / h->sum; } @@ -136,10 +140,10 @@ static void annotate_browser__set_top(struct annotate_browser *self, static int annotate_browser__run(struct annotate_browser *self) { struct rb_node *nd; - struct hist_entry *he = self->b.priv; + struct symbol *sym = self->b.priv; int key; - if (ui_browser__show(&self->b, he->ms.sym->name, + if (ui_browser__show(&self->b, sym->name, "<-, -> or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0) return -1; /* @@ -179,7 +183,12 @@ out: return key; } -int hist_entry__tui_annotate(struct hist_entry *self) +int hist_entry__tui_annotate(struct hist_entry *he) +{ + return symbol__tui_annotate(he->ms.sym, he->ms.map); +} + +int symbol__tui_annotate(struct symbol *sym, struct map *map) { struct objdump_line *pos, *n; struct objdump_line_rb_node *rbpos; @@ -190,18 +199,18 @@ int hist_entry__tui_annotate(struct hist_entry *self) .refresh = ui_browser__list_head_refresh, .seek = ui_browser__list_head_seek, .write = annotate_browser__write, - .priv = self, + .priv = sym, }, }; int ret; - if (self->ms.sym == NULL) + if (sym == NULL) return -1; - if (self->ms.map->dso->annotate_warned) + if (map->dso->annotate_warned) return -1; - if (hist_entry__annotate(self, &head, sizeof(*rbpos)) < 0) { + if (symbol__annotate(sym, map, &head, sizeof(*rbpos)) < 0) { ui__error_window(ui_helpline__last_msg); return -1; } @@ -214,7 +223,7 @@ int hist_entry__tui_annotate(struct hist_entry *self) browser.b.width = line_len; rbpos = objdump_line__rb(pos); rbpos->idx = browser.b.nr_entries++; - rbpos->percent = objdump_line__calc_percent(pos, &head, self->ms.sym); + rbpos->percent = objdump_line__calc_percent(pos, &head, sym); if (rbpos->percent < 0.01) continue; objdump__insert_line(&browser.entries, rbpos); -- cgit v1.2.3-70-g09d2 From 2f525d0148ef2734c8a172201e5e1e9167a8a5fd Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 4 Feb 2011 13:43:24 -0200 Subject: perf annotate: Support multiple histograms in annotation The perf annotate tool continues aggregating everything on just one histograms, but to support the top model add support for one histogram perf evsel in the evlist. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 29 ++++++++++++----- tools/perf/builtin-report.c | 15 +++++++-- tools/perf/util/annotate.c | 57 ++++++++++++++++------------------ tools/perf/util/annotate.h | 29 ++++++++++++++--- tools/perf/util/hist.c | 4 +-- tools/perf/util/hist.h | 16 +++++----- tools/perf/util/ui/browsers/annotate.c | 12 +++---- tools/perf/util/ui/browsers/hists.c | 9 +++--- 8 files changed, 106 insertions(+), 65 deletions(-) (limited to 'tools/perf/util/ui/browsers/annotate.c') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 9072ef44cfc..f3e44231b10 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -57,7 +57,18 @@ static int hists__add_entry(struct hists *self, struct addr_location *al) if (he == NULL) return -ENOMEM; - return hist_entry__inc_addr_samples(he, al->addr); + if (he->ms.sym != NULL) { + /* + * All aggregated on the first sym_hist. + */ + struct annotation *notes = symbol__annotation(he->ms.sym); + if (notes->histograms == NULL && symbol__alloc_hist(he->ms.sym, 1) < 0) + return -ENOMEM; + + return hist_entry__inc_addr_samples(he, 0, al->addr); + } + + return 0; } static int process_sample_event(union perf_event *event, @@ -81,9 +92,9 @@ static int process_sample_event(union perf_event *event, return 0; } -static int hist_entry__tty_annotate(struct hist_entry *he) +static int hist_entry__tty_annotate(struct hist_entry *he, int evidx) { - return symbol__tty_annotate(he->ms.sym, he->ms.map, + return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx, print_line, full_paths); } @@ -100,7 +111,7 @@ static void hists__find_annotations(struct hists *self) goto find_next; notes = symbol__annotation(he->ms.sym); - if (notes->histogram == NULL) { + if (notes->histograms == NULL) { find_next: if (key == KEY_LEFT) nd = rb_prev(nd); @@ -110,7 +121,8 @@ find_next: } if (use_browser > 0) { - key = hist_entry__tui_annotate(he); + /* For now all is aggregated on the first */ + key = hist_entry__tui_annotate(he, 0); switch (key) { case KEY_RIGHT: next = rb_next(nd); @@ -125,15 +137,16 @@ find_next: if (next != NULL) nd = next; } else { - hist_entry__tty_annotate(he); + /* For now all is aggregated on the first */ + hist_entry__tty_annotate(he, 0); nd = rb_next(nd); /* * Since we have a hist_entry per IP for the same * symbol, free he->ms.sym->histogram to signal we already * processed this symbol. */ - free(notes->histogram); - notes->histogram = NULL; + free(notes->histograms); + notes->histograms = NULL; } } } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 91e4cdba933..de06bf55eff 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -118,8 +118,17 @@ static int perf_session__add_hist_entry(struct perf_session *session, * so we don't allocated the extra space needed because the stdio * code will not use it. */ - if (use_browser > 0) - err = hist_entry__inc_addr_samples(he, al->addr); + if (al->sym != NULL && use_browser > 0) { + /* + * All aggregated on the first sym_hist. + */ + struct annotation *notes = symbol__annotation(he->ms.sym); + if (notes->histograms == NULL && + symbol__alloc_hist(he->ms.sym, 1) < 0) + err = -ENOMEM; + else + err = hist_entry__inc_addr_samples(he, 0, al->addr); + } return err; } @@ -349,7 +358,7 @@ static int __cmd_report(void) } if (use_browser > 0) - hists__tui_browse_tree(&session->hists_tree, help); + hists__tui_browse_tree(&session->hists_tree, help, 0); else hists__tty_browse_tree(&session->hists_tree, help); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 9b25575b980..7488fe99502 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -15,44 +15,40 @@ #include "debug.h" #include "annotate.h" -static int symbol__alloc_hist(struct symbol *sym) +int symbol__alloc_hist(struct symbol *sym, int nevents) { struct annotation *notes = symbol__annotation(sym); - const int size = (sizeof(*notes->histogram) + - (sym->end - sym->start) * sizeof(u64)); - notes->histogram = zalloc(size); - return notes->histogram == NULL ? -1 : 0; + notes->sizeof_sym_hist = (sizeof(*notes->histograms) + + (sym->end - sym->start) * sizeof(u64)); + notes->histograms = calloc(nevents, notes->sizeof_sym_hist); + return notes->histograms == NULL ? -1 : 0; } -int symbol__inc_addr_samples(struct symbol *sym, struct map *map, u64 addr) +int symbol__inc_addr_samples(struct symbol *sym, struct map *map, + int evidx, u64 addr) { - unsigned int sym_size, offset; + unsigned offset; struct annotation *notes; struct sym_hist *h; - if (!sym || !map) - return 0; - notes = symbol__annotation(sym); - if (notes->histogram == NULL && symbol__alloc_hist(sym) < 0) + if (notes->histograms == NULL) return -ENOMEM; - sym_size = sym->end - sym->start; - offset = addr - sym->start; - pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); - if (offset >= sym_size) + if (addr >= sym->end) return 0; - h = notes->histogram; + offset = addr - sym->start; + h = annotation__histogram(notes, evidx); h->sum++; h->addr[offset]++; pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64 - "] => %" PRIu64 "\n", sym->start, sym->name, - addr, addr - sym->start, h->addr[offset]); + ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name, + addr, addr - sym->start, evidx, h->addr[offset]); return 0; } @@ -90,8 +86,8 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head, } static void objdump_line__print(struct objdump_line *oline, - struct list_head *head, - struct symbol *sym, u64 len) + struct list_head *head, struct symbol *sym, + int evidx, u64 len) { static const char *prev_line; static const char *prev_color; @@ -103,7 +99,7 @@ static void objdump_line__print(struct objdump_line *oline, const char *color; struct annotation *notes = symbol__annotation(sym); struct source_line *src_line = notes->src_line; - struct sym_hist *h = notes->histogram; + struct sym_hist *h = annotation__histogram(notes, evidx); s64 offset = oline->offset; struct objdump_line *next = objdump__get_next_ip_line(head, oline); @@ -328,7 +324,7 @@ 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 rb_root *root, int len, + int evidx, struct rb_root *root, int len, const char *filename) { u64 start; @@ -336,7 +332,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, char cmd[PATH_MAX * 2]; struct source_line *src_line; struct annotation *notes = symbol__annotation(sym); - struct sym_hist *h = notes->histogram; + struct sym_hist *h = annotation__histogram(notes, evidx); if (!h->sum) return 0; @@ -409,10 +405,10 @@ static void print_summary(struct rb_root *root, const char *filename) } } -static void symbol__annotate_hits(struct symbol *sym) +static void symbol__annotate_hits(struct symbol *sym, int evidx) { struct annotation *notes = symbol__annotation(sym); - struct sym_hist *h = notes->histogram; + struct sym_hist *h = annotation__histogram(notes, evidx); u64 len = sym->end - sym->start, offset; for (offset = 0; offset < len; ++offset) @@ -422,8 +418,8 @@ static void symbol__annotate_hits(struct symbol *sym) printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); } -int symbol__tty_annotate(struct symbol *sym, struct map *map, bool print_lines, - bool full_paths) +int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, + bool print_lines, bool full_paths) { struct dso *dso = map->dso; const char *filename = dso->long_name, *d_filename; @@ -443,7 +439,8 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, bool print_lines, len = sym->end - sym->start; if (print_lines) { - symbol__get_source_line(sym, map, &source_line, len, filename); + symbol__get_source_line(sym, map, evidx, &source_line, + len, filename); print_summary(&source_line, filename); } @@ -452,10 +449,10 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, bool print_lines, printf("------------------------------------------------\n"); if (verbose) - symbol__annotate_hits(sym); + symbol__annotate_hits(sym, evidx); list_for_each_entry_safe(pos, n, &head, node) { - objdump_line__print(pos, &head, sym, len); + objdump_line__print(pos, &head, sym, evidx, len); list_del(&pos->node); objdump_line__free(pos); } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 6e2fbc20529..0a5069ca6dd 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -28,9 +28,21 @@ struct source_line { char *path; }; +/** struct annotation - symbols with hits have this attached as in sannotation + * + * @histogram: Array of addr hit histograms per event being monitored + * @src_line: If 'print_lines' is specified, per source code line percentages + * + * src_line is allocated, percentages calculated and all sorted by percentage + * when the annotation is about to be presented, so the percentages are for + * one of the entries in the histogram array, i.e. for the event/counter being + * presented. It is deallocated right after symbol__{tui,tty,etc}_annotate + * returns. + */ struct annotation { - struct sym_hist *histogram; struct source_line *src_line; + struct sym_hist *histograms; + int sizeof_sym_hist; }; struct sannotation { @@ -38,28 +50,35 @@ struct sannotation { struct symbol symbol; }; +static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) +{ + return ((void *)notes->histograms) + (notes->sizeof_sym_hist * idx); +} + static inline struct annotation *symbol__annotation(struct symbol *sym) { struct sannotation *a = container_of(sym, struct sannotation, symbol); return &a->annotation; } -int symbol__inc_addr_samples(struct symbol *sym, struct map *map, u64 addr); +int symbol__inc_addr_samples(struct symbol *sym, struct map *map, + int evidx, u64 addr); +int symbol__alloc_hist(struct symbol *sym, int nevents); int symbol__annotate(struct symbol *sym, struct map *map, struct list_head *head, size_t privsize); -int symbol__tty_annotate(struct symbol *sym, struct map *map, +int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, bool print_lines, bool full_paths); #ifdef NO_NEWT_SUPPORT static inline int symbol__tui_annotate(symbol *sym __used, - struct map *map __used) + struct map *map __used, int evidx __used) { return 0; } #else -int symbol__tui_annotate(struct symbol *sym, struct map *map); +int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx); #endif #endif /* __PERF_ANNOTATE_H */ diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 6d9c92c3d7c..bac5ab68496 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -950,9 +950,9 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread) } } -int hist_entry__inc_addr_samples(struct hist_entry *he, u64 ip) +int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) { - return symbol__inc_addr_samples(he->ms.sym, he->ms.map, ip); + return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); } int hist_entry__annotate(struct hist_entry *he, struct list_head *head, diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 8a201f75553..2c6cdae6a76 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -77,7 +77,7 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); size_t hists__fprintf(struct hists *self, struct hists *pair, bool show_displacement, FILE *fp); -int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip); +int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); int hist_entry__annotate(struct hist_entry *self, struct list_head *head, size_t privsize); @@ -91,18 +91,20 @@ bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len); #ifdef NO_NEWT_SUPPORT static inline int hists__browse(struct hists *self __used, const char *helpline __used, - const char *ev_name __used) + const char *ev_name __used, int evidx __used) { return 0; } static inline int hists__tui_browse_tree(struct rb_root *self __used, - const char *help __used) + const char *help __used, + int evidx __used) { return 0; } -static inline int hist_entry__tui_annotate(struct hist_entry *self __used) +static inline int hist_entry__tui_annotate(struct hist_entry *self __used, + int evidx __used) { return 0; } @@ -111,13 +113,13 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used) #else #include int hists__browse(struct hists *self, const char *helpline, - const char *ev_name); -int hist_entry__tui_annotate(struct hist_entry *self); + const char *ev_name, int evidx); +int hist_entry__tui_annotate(struct hist_entry *self, int evidx); #define KEY_LEFT NEWT_KEY_LEFT #define KEY_RIGHT NEWT_KEY_RIGHT -int hists__tui_browse_tree(struct rb_root *self, const char *help); +int hists__tui_browse_tree(struct rb_root *self, const char *help, int evidx); #endif unsigned int hists__sort_list_width(struct hists *self); diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index daa7138d801..8d8a16895af 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -61,7 +61,7 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro static double objdump_line__calc_percent(struct objdump_line *self, struct list_head *head, - struct symbol *sym) + struct symbol *sym, int evidx) { double percent = 0.0; @@ -70,7 +70,7 @@ static double objdump_line__calc_percent(struct objdump_line *self, unsigned int hits = 0; struct annotation *notes = symbol__annotation(sym); struct source_line *src_line = notes->src_line; - struct sym_hist *h = notes->histogram; + struct sym_hist *h = annotation__histogram(notes, evidx); s64 offset = self->offset; struct objdump_line *next = objdump__get_next_ip_line(head, self); @@ -183,12 +183,12 @@ out: return key; } -int hist_entry__tui_annotate(struct hist_entry *he) +int hist_entry__tui_annotate(struct hist_entry *he, int evidx) { - return symbol__tui_annotate(he->ms.sym, he->ms.map); + return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx); } -int symbol__tui_annotate(struct symbol *sym, struct map *map) +int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx) { struct objdump_line *pos, *n; struct objdump_line_rb_node *rbpos; @@ -223,7 +223,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map) browser.b.width = line_len; rbpos = objdump_line__rb(pos); rbpos->idx = browser.b.nr_entries++; - rbpos->percent = objdump_line__calc_percent(pos, &head, sym); + rbpos->percent = objdump_line__calc_percent(pos, &head, sym, evidx); if (rbpos->percent < 0.01) continue; objdump__insert_line(&browser.entries, rbpos); diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 86428239fa6..294b4953852 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -797,7 +797,8 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size, return printed; } -int hists__browse(struct hists *self, const char *helpline, const char *ev_name) +int hists__browse(struct hists *self, const char *helpline, + const char *ev_name, int evidx) { struct hist_browser *browser = hist_browser__new(self); struct pstack *fstack; @@ -935,7 +936,7 @@ do_annotate: if (he == NULL) continue; - hist_entry__tui_annotate(he); + hist_entry__tui_annotate(he, evidx); } else if (choice == browse_map) map__browse(browser->selection->map); else if (choice == zoom_dso) { @@ -984,7 +985,7 @@ out: return key; } -int hists__tui_browse_tree(struct rb_root *self, const char *help) +int hists__tui_browse_tree(struct rb_root *self, const char *help, int evidx) { struct rb_node *first = rb_first(self), *nd = first, *next; int key = 0; @@ -993,7 +994,7 @@ int hists__tui_browse_tree(struct rb_root *self, const char *help) struct hists *hists = rb_entry(nd, struct hists, rb_node); const char *ev_name = __event_name(hists->type, hists->config); - key = hists__browse(hists, help, ev_name); + key = hists__browse(hists, help, ev_name, evidx); switch (key) { case NEWT_KEY_TAB: next = rb_next(nd); -- cgit v1.2.3-70-g09d2 From ce6f4fab4059cd72638a0cfa596a8ee2c79c1c8e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 8 Feb 2011 13:27:39 -0200 Subject: perf annotate: Move locking to struct annotation Since we'll need it when implementing the live annotate TUI browser. This also simplifies things a bit by having the list head for the source code to be in the dynamicly allocated part of struct annotation, that way we don't have to pass it around, it can be found from the struct symbol that is passed everywhere. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 14 +++--- tools/perf/builtin-report.c | 5 +- tools/perf/builtin-top.c | 67 ++++++++++++++------------- tools/perf/util/annotate.c | 85 ++++++++++++++++++++-------------- tools/perf/util/annotate.h | 34 ++++++++------ tools/perf/util/hist.c | 5 +- tools/perf/util/hist.h | 3 +- tools/perf/util/top.h | 6 --- tools/perf/util/ui/browsers/annotate.c | 18 +++---- 9 files changed, 126 insertions(+), 111 deletions(-) (limited to 'tools/perf/util/ui/browsers/annotate.c') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index ea6a1165956..427182953fd 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -62,7 +62,8 @@ static int hists__add_entry(struct hists *self, struct addr_location *al) * All aggregated on the first sym_hist. */ struct annotation *notes = symbol__annotation(he->ms.sym); - if (notes->histograms == NULL && symbol__alloc_hist(he->ms.sym, 1) < 0) + if (notes->src == NULL && + symbol__alloc_hist(he->ms.sym, 1) < 0) return -ENOMEM; return hist_entry__inc_addr_samples(he, 0, al->addr); @@ -77,7 +78,8 @@ static int process_sample_event(union perf_event *event, { struct addr_location al; - if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) { + if (perf_event__preprocess_sample(event, session, &al, sample, + symbol__annotate_init) < 0) { pr_warning("problem processing %d event, skipping it.\n", event->header.type); return -1; @@ -111,7 +113,7 @@ static void hists__find_annotations(struct hists *self) goto find_next; notes = symbol__annotation(he->ms.sym); - if (notes->histograms == NULL) { + if (notes->src == NULL) { find_next: if (key == KEY_LEFT) nd = rb_prev(nd); @@ -142,11 +144,11 @@ find_next: nd = rb_next(nd); /* * Since we have a hist_entry per IP for the same - * symbol, free he->ms.sym->histogram to signal we already + * symbol, free he->ms.sym->src to signal we already * processed this symbol. */ - free(notes->histograms); - notes->histograms = NULL; + free(notes->src); + notes->src = NULL; } } } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index de06bf55eff..f403aced4cb 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -123,7 +123,7 @@ static int perf_session__add_hist_entry(struct perf_session *session, * All aggregated on the first sym_hist. */ struct annotation *notes = symbol__annotation(he->ms.sym); - if (notes->histograms == NULL && + if (notes->src == NULL && symbol__alloc_hist(he->ms.sym, 1) < 0) err = -ENOMEM; else @@ -166,7 +166,8 @@ static int process_sample_event(union perf_event *event, struct addr_location al; struct perf_event_attr *attr; - if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) { + if (perf_event__preprocess_sample(event, session, &al, sample, + symbol__annotate_init) < 0) { fprintf(stderr, "problem processing %d event, skipping it.\n", event->header.type); return -1; diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index b790673cb0a..7dbf22d096b 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -139,7 +139,7 @@ static void sig_winch_handler(int sig __used) static int parse_source(struct sym_entry *syme) { struct symbol *sym; - struct sym_entry_source *source; + struct annotation *notes; struct map *map; int err = -1; @@ -152,39 +152,35 @@ static int parse_source(struct sym_entry *syme) /* * We can't annotate with just /proc/kallsyms */ - if (map->dso->origin == DSO__ORIG_KERNEL) + if (map->dso->origin == DSO__ORIG_KERNEL) { + pr_err("Can't annotate %s: No vmlinux file was found in the " + "path\n", sym->name); + sleep(1); return -1; - - if (syme->src == NULL) { - syme->src = zalloc(sizeof(*source)); - if (syme->src == NULL) - return -1; - pthread_mutex_init(&syme->src->lock, NULL); - INIT_LIST_HEAD(&syme->src->head); } - source = syme->src; - - if (symbol__annotation(sym)->histograms != NULL) { - pthread_mutex_lock(&source->lock); + notes = symbol__annotation(sym); + if (notes->src != NULL) { + pthread_mutex_lock(¬es->lock); goto out_assign; } - pthread_mutex_lock(&source->lock); + pthread_mutex_lock(¬es->lock); if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { pr_err("Not enough memory for annotating '%s' symbol!\n", sym->name); + sleep(1); goto out_unlock; } - err = symbol__annotate(sym, syme->map, &source->head, 0); + err = symbol__annotate(sym, syme->map, 0); if (err == 0) { out_assign: sym_filter_entry = syme; } out_unlock: - pthread_mutex_unlock(&source->lock); + pthread_mutex_unlock(¬es->lock); return err; } @@ -196,20 +192,27 @@ static void __zero_source_counters(struct sym_entry *syme) static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) { + struct annotation *notes; + struct symbol *sym; + if (syme != sym_filter_entry) return; - if (pthread_mutex_trylock(&syme->src->lock)) + sym = sym_entry__symbol(syme); + notes = symbol__annotation(sym); + + if (pthread_mutex_trylock(¬es->lock)) return; ip = syme->map->map_ip(syme->map, ip); - symbol__inc_addr_samples(sym_entry__symbol(syme), syme->map, counter, ip); + symbol__inc_addr_samples(sym, syme->map, counter, ip); - pthread_mutex_unlock(&syme->src->lock); + pthread_mutex_unlock(¬es->lock); } static void show_details(struct sym_entry *syme) { + struct annotation *notes; struct symbol *symbol; int more; @@ -217,24 +220,26 @@ static void show_details(struct sym_entry *syme) return; symbol = sym_entry__symbol(syme); - if (!syme->src || symbol__annotation(symbol)->histograms == NULL) - return; + notes = symbol__annotation(symbol); + + pthread_mutex_lock(¬es->lock); + + if (notes->src == NULL) + goto out_unlock; printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); - pthread_mutex_lock(&syme->src->lock); - more = symbol__annotate_printf(symbol, syme->map, &syme->src->head, - top.sym_evsel->idx, 0, sym_pcnt_filter, - top.print_entries); + more = symbol__annotate_printf(symbol, syme->map, top.sym_evsel->idx, + 0, sym_pcnt_filter, top.print_entries); if (top.zero) symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); else - symbol__annotate_decay_histogram(symbol, &syme->src->head, - top.sym_evsel->idx); - pthread_mutex_unlock(&syme->src->lock); + symbol__annotate_decay_histogram(symbol, top.sym_evsel->idx); if (more != 0) printf("%d lines not displayed, maybe increase display entries [e]\n", more); +out_unlock: + pthread_mutex_unlock(¬es->lock); } static const char CONSOLE_CLEAR[] = ""; @@ -372,10 +377,8 @@ static void prompt_symbol(struct sym_entry **target, const char *msg) /* zero counters of active symbol */ if (syme) { - pthread_mutex_lock(&syme->src->lock); __zero_source_counters(syme); *target = NULL; - pthread_mutex_unlock(&syme->src->lock); } fprintf(stdout, "\n%s: ", msg); @@ -554,10 +557,8 @@ static void handle_keypress(struct perf_session *session, int c) else { struct sym_entry *syme = sym_filter_entry; - pthread_mutex_lock(&syme->src->lock); sym_filter_entry = NULL; __zero_source_counters(syme); - pthread_mutex_unlock(&syme->src->lock); } break; case 'U': @@ -653,7 +654,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) syme = symbol__priv(sym); syme->map = map; - syme->src = NULL; + symbol__annotate_init(map, sym); if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { /* schedule initial sym_filter_entry setup */ diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 6db435167d7..c777bdaf91d 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -14,25 +14,39 @@ #include "symbol.h" #include "debug.h" #include "annotate.h" +#include -int symbol__alloc_hist(struct symbol *sym, int nevents) +int symbol__annotate_init(struct map *map __used, struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); + pthread_mutex_init(¬es->lock, NULL); + return 0; +} - notes->sizeof_sym_hist = (sizeof(*notes->histograms) + +int symbol__alloc_hist(struct symbol *sym, int nevents) +{ + struct annotation *notes = symbol__annotation(sym); + size_t sizeof_sym_hist = (sizeof(struct sym_hist) + (sym->end - sym->start) * sizeof(u64)); - notes->histograms = calloc(nevents, notes->sizeof_sym_hist); - notes->nr_histograms = nevents; - return notes->histograms == NULL ? -1 : 0; + + notes->src = zalloc(sizeof(*notes->src) + nevents * sizeof_sym_hist); + if (notes->src == NULL) + return -1; + notes->src->sizeof_sym_hist = sizeof_sym_hist; + notes->src->nr_histograms = nevents; + INIT_LIST_HEAD(¬es->src->source); + return 0; } void symbol__annotate_zero_histograms(struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); - if (notes->histograms != NULL) - memset(notes->histograms, 0, - notes->nr_histograms * notes->sizeof_sym_hist); + pthread_mutex_lock(¬es->lock); + if (notes->src != NULL) + memset(notes->src->histograms, 0, + notes->src->nr_histograms * notes->src->sizeof_sym_hist); + pthread_mutex_unlock(¬es->lock); } int symbol__inc_addr_samples(struct symbol *sym, struct map *map, @@ -43,7 +57,7 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, struct sym_hist *h; notes = symbol__annotation(sym); - if (notes->histograms == NULL) + if (notes->src == NULL) return -ENOMEM; pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); @@ -95,8 +109,7 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head, return NULL; } -static int objdump_line__print(struct objdump_line *oline, - struct list_head *head, struct symbol *sym, +static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, int evidx, u64 len, int min_pcnt, int printed, int max_lines) { @@ -109,10 +122,12 @@ static int objdump_line__print(struct objdump_line *oline, double percent = 0.0; const char *color; struct annotation *notes = symbol__annotation(sym); - struct source_line *src_line = notes->src_line; + struct source_line *src_line = notes->src->lines; struct sym_hist *h = annotation__histogram(notes, evidx); s64 offset = oline->offset; - struct objdump_line *next = objdump__get_next_ip_line(head, oline); + struct objdump_line *next; + + next = objdump__get_next_ip_line(¬es->src->source, oline); while (offset < (s64)len && (next == NULL || offset < next->offset)) { @@ -166,9 +181,10 @@ static int objdump_line__print(struct objdump_line *oline, return 0; } -static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, FILE *file, - struct list_head *head, size_t privsize) +static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, + FILE *file, size_t privsize) { + struct annotation *notes = symbol__annotation(sym); struct objdump_line *objdump_line; char *line = NULL, *tmp, *tmp2, *c; size_t line_len; @@ -222,13 +238,12 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, FILE free(line); return -1; } - objdump__add_line(head, objdump_line); + objdump__add_line(¬es->src->source, objdump_line); return 0; } -int symbol__annotate(struct symbol *sym, struct map *map, - struct list_head *head, size_t privsize) +int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) { struct dso *dso = map->dso; char *filename = dso__build_id_filename(dso, NULL, 0); @@ -297,7 +312,7 @@ fallback: goto out_free_filename; while (!feof(file)) - if (symbol__parse_objdump_line(sym, map, file, head, privsize) < 0) + if (symbol__parse_objdump_line(sym, map, file, privsize) < 0) break; pclose(file); @@ -330,14 +345,14 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin static void symbol__free_source_line(struct symbol *sym, int len) { struct annotation *notes = symbol__annotation(sym); - struct source_line *src_line = notes->src_line; + struct source_line *src_line = notes->src->lines; int i; for (i = 0; i < len; i++) free(src_line[i].path); free(src_line); - notes->src_line = NULL; + notes->src->lines = NULL; } /* Get the filename:line for the colored entries */ @@ -355,8 +370,8 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, if (!h->sum) return 0; - src_line = notes->src_line = calloc(len, sizeof(struct source_line)); - if (!notes->src_line) + src_line = notes->src->lines = calloc(len, sizeof(struct source_line)); + if (!notes->src->lines) return -1; start = map->unmap_ip(map, sym->start); @@ -436,12 +451,12 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx) printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); } -int symbol__annotate_printf(struct symbol *sym, struct map *map, - struct list_head *head, int evidx, bool full_paths, - int min_pcnt, int max_lines) +int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, + bool full_paths, int min_pcnt, int max_lines) { struct dso *dso = map->dso; const char *filename = dso->long_name, *d_filename; + struct annotation *notes = symbol__annotation(sym); struct objdump_line *pos; int printed = 2; int more = 0; @@ -460,8 +475,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, if (verbose) symbol__annotate_hits(sym, evidx); - list_for_each_entry(pos, head, node) { - switch (objdump_line__print(pos, head, sym, evidx, len, min_pcnt, + list_for_each_entry(pos, ¬es->src->source, node) { + switch (objdump_line__print(pos, sym, evidx, len, min_pcnt, printed, max_lines)) { case 0: ++printed; @@ -485,11 +500,10 @@ void symbol__annotate_zero_histogram(struct symbol *sym, int evidx) struct annotation *notes = symbol__annotation(sym); struct sym_hist *h = annotation__histogram(notes, evidx); - memset(h, 0, notes->sizeof_sym_hist); + memset(h, 0, notes->src->sizeof_sym_hist); } -void symbol__annotate_decay_histogram(struct symbol *sym, - struct list_head *head, int evidx) +void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) { struct annotation *notes = symbol__annotation(sym); struct sym_hist *h = annotation__histogram(notes, evidx); @@ -497,7 +511,7 @@ void symbol__annotate_decay_histogram(struct symbol *sym, h->sum = 0; - list_for_each_entry(pos, head, node) { + list_for_each_entry(pos, ¬es->src->source, node) { if (pos->offset != -1) { h->addr[pos->offset] = h->addr[pos->offset] * 7 / 8; h->sum += h->addr[pos->offset]; @@ -522,10 +536,9 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, struct dso *dso = map->dso; const char *filename = dso->long_name; struct rb_root source_line = RB_ROOT; - LIST_HEAD(head); u64 len; - if (symbol__annotate(sym, map, &head, 0) < 0) + if (symbol__annotate(sym, map, 0) < 0) return -1; len = sym->end - sym->start; @@ -536,12 +549,12 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, print_summary(&source_line, filename); } - symbol__annotate_printf(sym, map, &head, evidx, full_paths, + symbol__annotate_printf(sym, map, evidx, full_paths, min_pcnt, max_lines); if (print_lines) symbol__free_source_line(sym, len); - objdump_line_list__purge(&head); + objdump_line_list__purge(&symbol__annotation(sym)->src->source); return 0; } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index bc08b36a713..b237c8678c2 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -28,22 +28,29 @@ struct source_line { char *path; }; -/** struct annotation - symbols with hits have this attached as in sannotation +/** struct annotated_source - symbols with hits have this attached as in sannotation * * @histogram: Array of addr hit histograms per event being monitored - * @src_line: If 'print_lines' is specified, per source code line percentages + * @lines: If 'print_lines' is specified, per source code line percentages + * @source: source parsed from objdump -dS * - * src_line is allocated, percentages calculated and all sorted by percentage + * lines is allocated, percentages calculated and all sorted by percentage * when the annotation is about to be presented, so the percentages are for * one of the entries in the histogram array, i.e. for the event/counter being * presented. It is deallocated right after symbol__{tui,tty,etc}_annotate * returns. */ -struct annotation { - struct source_line *src_line; - struct sym_hist *histograms; +struct annotated_source { + struct list_head source; + struct source_line *lines; int nr_histograms; int sizeof_sym_hist; + struct sym_hist histograms[0]; +}; + +struct annotation { + pthread_mutex_t lock; + struct annotated_source *src; }; struct sannotation { @@ -53,7 +60,8 @@ struct sannotation { static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) { - return ((void *)notes->histograms) + (notes->sizeof_sym_hist * idx); + return (((void *)¬es->src->histograms) + + (notes->src->sizeof_sym_hist * idx)); } static inline struct annotation *symbol__annotation(struct symbol *sym) @@ -67,14 +75,12 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, int symbol__alloc_hist(struct symbol *sym, int nevents); void symbol__annotate_zero_histograms(struct symbol *sym); -int symbol__annotate(struct symbol *sym, struct map *map, - struct list_head *head, size_t privsize); -int symbol__annotate_printf(struct symbol *sym, struct map *map, - struct list_head *head, int evidx, bool full_paths, - int min_pcnt, int max_lines); +int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); +int symbol__annotate_init(struct map *map __used, struct symbol *sym); +int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, + bool full_paths, int min_pcnt, int max_lines); void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); -void symbol__annotate_decay_histogram(struct symbol *sym, - struct list_head *head, int evidx); +void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); void objdump_line_list__purge(struct list_head *head); int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index bac5ab68496..3f437236f19 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -955,10 +955,9 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); } -int hist_entry__annotate(struct hist_entry *he, struct list_head *head, - size_t privsize) +int hist_entry__annotate(struct hist_entry *he, size_t privsize) { - return symbol__annotate(he->ms.sym, he->ms.map, head, privsize); + return symbol__annotate(he->ms.sym, he->ms.map, privsize); } void hists__inc_nr_events(struct hists *self, u32 type) diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 2c6cdae6a76..37c79089de0 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -78,8 +78,7 @@ size_t hists__fprintf(struct hists *self, struct hists *pair, bool show_displacement, FILE *fp); int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); -int hist_entry__annotate(struct hist_entry *self, struct list_head *head, - size_t privsize); +int hist_entry__annotate(struct hist_entry *self, size_t privsize); void hists__filter_by_dso(struct hists *self, const struct dso *dso); void hists__filter_by_thread(struct hists *self, const struct thread *thread); diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 62e32939f3d..4f769f47e19 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -11,11 +11,6 @@ struct perf_evlist; struct perf_evsel; -struct sym_entry_source { - struct list_head head; - pthread_mutex_t lock; -}; - struct sym_entry { struct rb_node rb_node; struct list_head node; @@ -24,7 +19,6 @@ struct sym_entry { int skip; u8 origin; struct map *map; - struct sym_entry_source *src; unsigned long count[0]; }; diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 8d8a16895af..1aa39658539 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -60,7 +60,6 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro } static double objdump_line__calc_percent(struct objdump_line *self, - struct list_head *head, struct symbol *sym, int evidx) { double percent = 0.0; @@ -69,11 +68,12 @@ static double objdump_line__calc_percent(struct objdump_line *self, int len = sym->end - sym->start; unsigned int hits = 0; struct annotation *notes = symbol__annotation(sym); - struct source_line *src_line = notes->src_line; + struct source_line *src_line = notes->src->lines; struct sym_hist *h = annotation__histogram(notes, evidx); s64 offset = self->offset; - struct objdump_line *next = objdump__get_next_ip_line(head, self); + struct objdump_line *next; + next = objdump__get_next_ip_line(¬es->src->source, self); while (offset < (s64)len && (next == NULL || offset < next->offset)) { if (src_line) { @@ -192,10 +192,10 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx) { struct objdump_line *pos, *n; struct objdump_line_rb_node *rbpos; - LIST_HEAD(head); + struct annotation *notes = symbol__annotation(sym); struct annotate_browser browser = { .b = { - .entries = &head, + .entries = ¬es->src->source, .refresh = ui_browser__list_head_refresh, .seek = ui_browser__list_head_seek, .write = annotate_browser__write, @@ -210,20 +210,20 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx) if (map->dso->annotate_warned) return -1; - if (symbol__annotate(sym, map, &head, sizeof(*rbpos)) < 0) { + if (symbol__annotate(sym, map, sizeof(*rbpos)) < 0) { ui__error_window(ui_helpline__last_msg); return -1; } ui_helpline__push("Press <- or ESC to exit"); - list_for_each_entry(pos, &head, node) { + list_for_each_entry(pos, ¬es->src->source, node) { size_t line_len = strlen(pos->line); if (browser.b.width < line_len) browser.b.width = line_len; rbpos = objdump_line__rb(pos); rbpos->idx = browser.b.nr_entries++; - rbpos->percent = objdump_line__calc_percent(pos, &head, sym, evidx); + rbpos->percent = objdump_line__calc_percent(pos, sym, evidx); if (rbpos->percent < 0.01) continue; objdump__insert_line(&browser.entries, rbpos); @@ -238,7 +238,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx) browser.b.width += 18; /* Percentage */ ret = annotate_browser__run(&browser); - list_for_each_entry_safe(pos, n, &head, node) { + list_for_each_entry_safe(pos, n, ¬es->src->source, node) { list_del(&pos->node); objdump_line__free(pos); } -- cgit v1.2.3-70-g09d2 From b99976e2d277c963138e090ae17bf835f8a07680 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 9 Feb 2011 13:59:14 -0200 Subject: perf annotate browser: Use the percent color for the whole line Not just for the percentage number, to see the hot lines more easily. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ui/browsers/annotate.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tools/perf/util/ui/browsers/annotate.c') diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 1aa39658539..cfb5a27f15d 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -44,8 +44,6 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro struct objdump_line_rb_node *olrb = objdump_line__rb(ol); ui_browser__set_percent_color(self, olrb->percent, current_entry); slsmg_printf(" %7.2f ", olrb->percent); - if (!current_entry) - ui_browser__set_color(self, HE_COLORSET_CODE); } else { ui_browser__set_percent_color(self, 0, current_entry); slsmg_write_nstring(" ", 9); @@ -57,6 +55,9 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro slsmg_write_nstring(" ", width - 18); else slsmg_write_nstring(ol->line, width - 18); + + if (!current_entry) + ui_browser__set_color(self, HE_COLORSET_CODE); } static double objdump_line__calc_percent(struct objdump_line *self, -- cgit v1.2.3-70-g09d2 From c97cf42219b7b6037d2f96c27a5f114f2383f828 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 22 Feb 2011 12:02:07 -0300 Subject: perf top: Live TUI Annotation Now one has just to press the right key, 'a' or Enter on the main 'perf top --tui' screen to live annotate the symbol under the cursor. The annotate window starts centered on the hottest line (the one with most samples so far) then TAB and shift+TAB can be used to go to the prev/next hot line. Pressing 'H' at any point will center again the screen on the hottest line. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 36 +++++----- tools/perf/util/annotate.h | 6 +- tools/perf/util/top.h | 1 + tools/perf/util/ui/browsers/annotate.c | 126 +++++++++++++++++++++++---------- tools/perf/util/ui/browsers/top.c | 45 +++++++++++- 5 files changed, 156 insertions(+), 58 deletions(-) (limited to 'tools/perf/util/ui/browsers/annotate.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c9fd66d4a08..f88a2630e1f 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -92,7 +92,6 @@ static bool dump_symtab = false; static struct winsize winsize; static const char *sym_filter = NULL; -struct sym_entry *sym_filter_entry = NULL; struct sym_entry *sym_filter_entry_sched = NULL; static int sym_pcnt_filter = 5; @@ -168,18 +167,19 @@ static int parse_source(struct sym_entry *syme) pthread_mutex_lock(¬es->lock); if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { + pthread_mutex_unlock(¬es->lock); pr_err("Not enough memory for annotating '%s' symbol!\n", sym->name); sleep(1); - goto out_unlock; + return err; } err = symbol__annotate(sym, syme->map, 0); if (err == 0) { out_assign: - sym_filter_entry = syme; + top.sym_filter_entry = syme; } -out_unlock: + pthread_mutex_unlock(¬es->lock); return err; } @@ -195,7 +195,7 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) struct annotation *notes; struct symbol *sym; - if (syme != sym_filter_entry) + if (syme != top.sym_filter_entry) return; sym = sym_entry__symbol(syme); @@ -275,8 +275,8 @@ static void print_sym_table(struct perf_session *session) session->hists.stats.total_lost); } - if (sym_filter_entry) { - show_details(sym_filter_entry); + if (top.sym_filter_entry) { + show_details(top.sym_filter_entry); return; } @@ -417,8 +417,8 @@ static void print_mapped_keys(void) { char *name = NULL; - if (sym_filter_entry) { - struct symbol *sym = sym_entry__symbol(sym_filter_entry); + if (top.sym_filter_entry) { + struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); name = sym->name; } @@ -549,15 +549,15 @@ static void handle_keypress(struct perf_session *session, int c) perf_session__fprintf_dsos(session, stderr); exit(0); case 's': - prompt_symbol(&sym_filter_entry, "Enter details symbol"); + prompt_symbol(&top.sym_filter_entry, "Enter details symbol"); break; case 'S': - if (!sym_filter_entry) + if (!top.sym_filter_entry) break; else { - struct sym_entry *syme = sym_filter_entry; + struct sym_entry *syme = top.sym_filter_entry; - sym_filter_entry = NULL; + top.sym_filter_entry = NULL; __zero_source_counters(syme); } break; @@ -656,7 +656,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) syme->map = map; symbol__annotate_init(map, sym); - if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { + if (!top.sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { /* schedule initial sym_filter_entry setup */ sym_filter_entry_sched = syme; sym_filter = NULL; @@ -750,13 +750,13 @@ static void perf_event__process_sample(const union perf_event *event, /* let's see, whether we need to install initial sym_filter_entry */ if (sym_filter_entry_sched) { - sym_filter_entry = sym_filter_entry_sched; + top.sym_filter_entry = sym_filter_entry_sched; sym_filter_entry_sched = NULL; - if (parse_source(sym_filter_entry) < 0) { - struct symbol *sym = sym_entry__symbol(sym_filter_entry); + if (parse_source(top.sym_filter_entry) < 0) { + struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); pr_err("Can't annotate %s", sym->name); - if (sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { + if (top.sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { pr_err(": No vmlinux file was found in the path:\n"); machine__fprintf_vmlinux_path(machine, stderr); } else diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index e848803fcd4..c2c28689680 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -90,12 +90,14 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, #ifdef NO_NEWT_SUPPORT static inline int symbol__tui_annotate(struct symbol *sym __used, - struct map *map __used, int evidx __used) + struct map *map __used, + int evidx __used, int refresh __used) { return 0; } #else -int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx); +int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, + int refresh); #endif #endif /* __PERF_ANNOTATE_H */ diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 4f769f47e19..e8d28e2ecdb 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -44,6 +44,7 @@ struct perf_top { pid_t target_pid, target_tid; bool hide_kernel_symbols, hide_user_symbols, zero; const char *cpu_list; + struct sym_entry *sym_filter_entry; struct perf_evsel *sym_evsel; }; diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index cfb5a27f15d..8c17a8730e4 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -6,6 +6,7 @@ #include "../../sort.h" #include "../../symbol.h" #include "../../annotate.h" +#include static void ui__error_window(const char *fmt, ...) { @@ -138,46 +139,108 @@ static void annotate_browser__set_top(struct annotate_browser *self, self->curr_hot = nd; } -static int annotate_browser__run(struct annotate_browser *self) +static void annotate_browser__calc_percent(struct annotate_browser *browser, + int evidx) { - struct rb_node *nd; + struct symbol *sym = browser->b.priv; + struct annotation *notes = symbol__annotation(sym); + struct objdump_line *pos; + + browser->entries = RB_ROOT; + + pthread_mutex_lock(¬es->lock); + + list_for_each_entry(pos, ¬es->src->source, node) { + struct objdump_line_rb_node *rbpos = objdump_line__rb(pos); + rbpos->percent = objdump_line__calc_percent(pos, sym, evidx); + if (rbpos->percent < 0.01) { + RB_CLEAR_NODE(&rbpos->rb_node); + continue; + } + objdump__insert_line(&browser->entries, rbpos); + } + pthread_mutex_unlock(¬es->lock); + + browser->curr_hot = rb_last(&browser->entries); +} + +static int annotate_browser__run(struct annotate_browser *self, int evidx, + int refresh) +{ + struct rb_node *nd = NULL; struct symbol *sym = self->b.priv; + /* + * RIGHT To allow builtin-annotate to cycle thru multiple symbols by + * examining the exit key for this function. + */ + int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB, + NEWT_KEY_RIGHT, 0 }; int key; if (ui_browser__show(&self->b, sym->name, - "<-, -> or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0) + "<-, -> or ESC: exit, TAB/shift+TAB: " + "cycle hottest lines, H: Hottest") < 0) return -1; - /* - * To allow builtin-annotate to cycle thru multiple symbols by - * examining the exit key for this function. - */ - ui_browser__add_exit_key(&self->b, NEWT_KEY_RIGHT); + + ui_browser__add_exit_keys(&self->b, exit_keys); + annotate_browser__calc_percent(self, evidx); + + if (self->curr_hot) + annotate_browser__set_top(self, self->curr_hot); nd = self->curr_hot; - if (nd) { - int tabs[] = { NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0 }; - ui_browser__add_exit_keys(&self->b, tabs); - } + + if (refresh != 0) + newtFormSetTimer(self->b.form, refresh); while (1) { key = ui_browser__run(&self->b); + if (refresh != 0) { + annotate_browser__calc_percent(self, evidx); + /* + * Current line focus got out of the list of most active + * lines, NULL it so that if TAB|UNTAB is pressed, we + * move to curr_hot (current hottest line). + */ + if (nd != NULL && RB_EMPTY_NODE(nd)) + nd = NULL; + } + switch (key) { + case -1: + /* + * FIXME we need to check if it was + * es.reason == NEWT_EXIT_TIMER + */ + if (refresh != 0) + symbol__annotate_decay_histogram(sym, evidx); + continue; case NEWT_KEY_TAB: - nd = rb_prev(nd); - if (nd == NULL) - nd = rb_last(&self->entries); - annotate_browser__set_top(self, nd); + if (nd != NULL) { + nd = rb_prev(nd); + if (nd == NULL) + nd = rb_last(&self->entries); + } else + nd = self->curr_hot; break; case NEWT_KEY_UNTAB: - nd = rb_next(nd); - if (nd == NULL) - nd = rb_first(&self->entries); - annotate_browser__set_top(self, nd); + if (nd != NULL) + nd = rb_next(nd); + if (nd == NULL) + nd = rb_first(&self->entries); + else + nd = self->curr_hot; + break; + case 'H': + nd = self->curr_hot; break; default: goto out; } + + if (nd != NULL) + annotate_browser__set_top(self, nd); } out: ui_browser__hide(&self->b); @@ -186,13 +249,13 @@ out: int hist_entry__tui_annotate(struct hist_entry *he, int evidx) { - return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx); + return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0); } -int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx) +int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, + int refresh) { struct objdump_line *pos, *n; - struct objdump_line_rb_node *rbpos; struct annotation *notes = symbol__annotation(sym); struct annotate_browser browser = { .b = { @@ -211,7 +274,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx) if (map->dso->annotate_warned) return -1; - if (symbol__annotate(sym, map, sizeof(*rbpos)) < 0) { + if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) { ui__error_window(ui_helpline__last_msg); return -1; } @@ -219,26 +282,17 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx) ui_helpline__push("Press <- or ESC to exit"); list_for_each_entry(pos, ¬es->src->source, node) { + struct objdump_line_rb_node *rbpos; size_t line_len = strlen(pos->line); + if (browser.b.width < line_len) browser.b.width = line_len; rbpos = objdump_line__rb(pos); rbpos->idx = browser.b.nr_entries++; - rbpos->percent = objdump_line__calc_percent(pos, sym, evidx); - if (rbpos->percent < 0.01) - continue; - objdump__insert_line(&browser.entries, rbpos); } - /* - * Position the browser at the hottest line. - */ - browser.curr_hot = rb_last(&browser.entries); - if (browser.curr_hot) - annotate_browser__set_top(&browser, browser.curr_hot); - browser.b.width += 18; /* Percentage */ - ret = annotate_browser__run(&browser); + ret = annotate_browser__run(&browser, evidx, refresh); list_for_each_entry_safe(pos, n, ¬es->src->source, node) { list_del(&pos->node); objdump_line__free(pos); diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c index ca6062483a8..377ff58c9ae 100644 --- a/tools/perf/util/ui/browsers/top.c +++ b/tools/perf/util/ui/browsers/top.c @@ -7,6 +7,7 @@ * Released under the GPL v2. (and only v2, not any later version) */ #include "../browser.h" +#include "../../annotate.h" #include "../helpline.h" #include "../libslang.h" #include "../../evlist.h" @@ -18,6 +19,7 @@ struct perf_top_browser { struct ui_browser b; struct rb_root root; + struct sym_entry *selection; float sum_ksamples; int dso_width; int dso_short_width; @@ -60,6 +62,9 @@ static void perf_top_browser__write(struct ui_browser *browser, void *entry, int slsmg_write_nstring(width >= syme->map->dso->long_name_len ? syme->map->dso->long_name : syme->map->dso->short_name, width); + + if (current_entry) + top_browser->selection = syme; } static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser) @@ -80,21 +85,52 @@ static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser) browser->b.nr_entries = top->rb_entries; } +static void perf_top_browser__annotate(struct perf_top_browser *browser) +{ + struct sym_entry *syme = browser->selection; + struct symbol *sym = sym_entry__symbol(syme); + struct annotation *notes = symbol__annotation(sym); + struct perf_top *top = browser->b.priv; + + if (notes->src != NULL) + goto do_annotation; + + pthread_mutex_lock(¬es->lock); + + top->sym_filter_entry = NULL; + + if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) { + pr_err("Not enough memory for annotating '%s' symbol!\n", + sym->name); + pthread_mutex_unlock(¬es->lock); + return; + } + + top->sym_filter_entry = syme; + + pthread_mutex_unlock(¬es->lock); +do_annotation: + symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000); +} + static int perf_top_browser__run(struct perf_top_browser *browser) { int key; char title[160]; struct perf_top *top = browser->b.priv; int delay_msecs = top->delay_secs * 1000; + int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; perf_top_browser__update_rb_tree(browser); perf_top__header_snprintf(top, title, sizeof(title)); perf_top__reset_sample_counters(top); - if (ui_browser__show(&browser->b, title, "ESC: exit") < 0) + if (ui_browser__show(&browser->b, title, + "ESC: exit, ENTER|->|a: Live Annotate") < 0) return -1; newtFormSetTimer(browser->b.form, delay_msecs); + ui_browser__add_exit_keys(&browser->b, exit_keys); while (1) { key = ui_browser__run(&browser->b); @@ -109,7 +145,12 @@ static int perf_top_browser__run(struct perf_top_browser *browser) SLsmg_gotorc(0, 0); slsmg_write_nstring(title, browser->b.width); break; - case NEWT_KEY_TAB: + case 'a': + case NEWT_KEY_RIGHT: + case NEWT_KEY_ENTER: + if (browser->selection) + perf_top_browser__annotate(browser); + break; default: goto out; } -- cgit v1.2.3-70-g09d2