diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-02-22 10:02:07 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-02-22 10:02:07 -0500 |
commit | c97cf42219b7b6037d2f96c27a5f114f2383f828 (patch) | |
tree | 2180e3eae063a217d1681074a813eed42ad91a86 /tools | |
parent | 8635bf6ea3402154eec64763e6ed14972013c1c1 (diff) |
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 <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-top.c | 36 | ||||
-rw-r--r-- | tools/perf/util/annotate.h | 6 | ||||
-rw-r--r-- | tools/perf/util/top.h | 1 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/annotate.c | 126 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/top.c | 45 |
5 files changed, 156 insertions, 58 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c9fd66d4a082..f88a2630e1fc 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -92,7 +92,6 @@ static bool dump_symtab = false; | |||
92 | static struct winsize winsize; | 92 | static struct winsize winsize; |
93 | 93 | ||
94 | static const char *sym_filter = NULL; | 94 | static const char *sym_filter = NULL; |
95 | struct sym_entry *sym_filter_entry = NULL; | ||
96 | struct sym_entry *sym_filter_entry_sched = NULL; | 95 | struct sym_entry *sym_filter_entry_sched = NULL; |
97 | static int sym_pcnt_filter = 5; | 96 | static int sym_pcnt_filter = 5; |
98 | 97 | ||
@@ -168,18 +167,19 @@ static int parse_source(struct sym_entry *syme) | |||
168 | pthread_mutex_lock(¬es->lock); | 167 | pthread_mutex_lock(¬es->lock); |
169 | 168 | ||
170 | if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { | 169 | if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { |
170 | pthread_mutex_unlock(¬es->lock); | ||
171 | pr_err("Not enough memory for annotating '%s' symbol!\n", | 171 | pr_err("Not enough memory for annotating '%s' symbol!\n", |
172 | sym->name); | 172 | sym->name); |
173 | sleep(1); | 173 | sleep(1); |
174 | goto out_unlock; | 174 | return err; |
175 | } | 175 | } |
176 | 176 | ||
177 | err = symbol__annotate(sym, syme->map, 0); | 177 | err = symbol__annotate(sym, syme->map, 0); |
178 | if (err == 0) { | 178 | if (err == 0) { |
179 | out_assign: | 179 | out_assign: |
180 | sym_filter_entry = syme; | 180 | top.sym_filter_entry = syme; |
181 | } | 181 | } |
182 | out_unlock: | 182 | |
183 | pthread_mutex_unlock(¬es->lock); | 183 | pthread_mutex_unlock(¬es->lock); |
184 | return err; | 184 | return err; |
185 | } | 185 | } |
@@ -195,7 +195,7 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) | |||
195 | struct annotation *notes; | 195 | struct annotation *notes; |
196 | struct symbol *sym; | 196 | struct symbol *sym; |
197 | 197 | ||
198 | if (syme != sym_filter_entry) | 198 | if (syme != top.sym_filter_entry) |
199 | return; | 199 | return; |
200 | 200 | ||
201 | sym = sym_entry__symbol(syme); | 201 | sym = sym_entry__symbol(syme); |
@@ -275,8 +275,8 @@ static void print_sym_table(struct perf_session *session) | |||
275 | session->hists.stats.total_lost); | 275 | session->hists.stats.total_lost); |
276 | } | 276 | } |
277 | 277 | ||
278 | if (sym_filter_entry) { | 278 | if (top.sym_filter_entry) { |
279 | show_details(sym_filter_entry); | 279 | show_details(top.sym_filter_entry); |
280 | return; | 280 | return; |
281 | } | 281 | } |
282 | 282 | ||
@@ -417,8 +417,8 @@ static void print_mapped_keys(void) | |||
417 | { | 417 | { |
418 | char *name = NULL; | 418 | char *name = NULL; |
419 | 419 | ||
420 | if (sym_filter_entry) { | 420 | if (top.sym_filter_entry) { |
421 | struct symbol *sym = sym_entry__symbol(sym_filter_entry); | 421 | struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); |
422 | name = sym->name; | 422 | name = sym->name; |
423 | } | 423 | } |
424 | 424 | ||
@@ -549,15 +549,15 @@ static void handle_keypress(struct perf_session *session, int c) | |||
549 | perf_session__fprintf_dsos(session, stderr); | 549 | perf_session__fprintf_dsos(session, stderr); |
550 | exit(0); | 550 | exit(0); |
551 | case 's': | 551 | case 's': |
552 | prompt_symbol(&sym_filter_entry, "Enter details symbol"); | 552 | prompt_symbol(&top.sym_filter_entry, "Enter details symbol"); |
553 | break; | 553 | break; |
554 | case 'S': | 554 | case 'S': |
555 | if (!sym_filter_entry) | 555 | if (!top.sym_filter_entry) |
556 | break; | 556 | break; |
557 | else { | 557 | else { |
558 | struct sym_entry *syme = sym_filter_entry; | 558 | struct sym_entry *syme = top.sym_filter_entry; |
559 | 559 | ||
560 | sym_filter_entry = NULL; | 560 | top.sym_filter_entry = NULL; |
561 | __zero_source_counters(syme); | 561 | __zero_source_counters(syme); |
562 | } | 562 | } |
563 | break; | 563 | break; |
@@ -656,7 +656,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) | |||
656 | syme->map = map; | 656 | syme->map = map; |
657 | symbol__annotate_init(map, sym); | 657 | symbol__annotate_init(map, sym); |
658 | 658 | ||
659 | if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { | 659 | if (!top.sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { |
660 | /* schedule initial sym_filter_entry setup */ | 660 | /* schedule initial sym_filter_entry setup */ |
661 | sym_filter_entry_sched = syme; | 661 | sym_filter_entry_sched = syme; |
662 | sym_filter = NULL; | 662 | sym_filter = NULL; |
@@ -750,13 +750,13 @@ static void perf_event__process_sample(const union perf_event *event, | |||
750 | 750 | ||
751 | /* let's see, whether we need to install initial sym_filter_entry */ | 751 | /* let's see, whether we need to install initial sym_filter_entry */ |
752 | if (sym_filter_entry_sched) { | 752 | if (sym_filter_entry_sched) { |
753 | sym_filter_entry = sym_filter_entry_sched; | 753 | top.sym_filter_entry = sym_filter_entry_sched; |
754 | sym_filter_entry_sched = NULL; | 754 | sym_filter_entry_sched = NULL; |
755 | if (parse_source(sym_filter_entry) < 0) { | 755 | if (parse_source(top.sym_filter_entry) < 0) { |
756 | struct symbol *sym = sym_entry__symbol(sym_filter_entry); | 756 | struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); |
757 | 757 | ||
758 | pr_err("Can't annotate %s", sym->name); | 758 | pr_err("Can't annotate %s", sym->name); |
759 | if (sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { | 759 | if (top.sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { |
760 | pr_err(": No vmlinux file was found in the path:\n"); | 760 | pr_err(": No vmlinux file was found in the path:\n"); |
761 | machine__fprintf_vmlinux_path(machine, stderr); | 761 | machine__fprintf_vmlinux_path(machine, stderr); |
762 | } else | 762 | } else |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index e848803fcd48..c2c286896801 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, | |||
90 | 90 | ||
91 | #ifdef NO_NEWT_SUPPORT | 91 | #ifdef NO_NEWT_SUPPORT |
92 | static inline int symbol__tui_annotate(struct symbol *sym __used, | 92 | static inline int symbol__tui_annotate(struct symbol *sym __used, |
93 | struct map *map __used, int evidx __used) | 93 | struct map *map __used, |
94 | int evidx __used, int refresh __used) | ||
94 | { | 95 | { |
95 | return 0; | 96 | return 0; |
96 | } | 97 | } |
97 | #else | 98 | #else |
98 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx); | 99 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, |
100 | int refresh); | ||
99 | #endif | 101 | #endif |
100 | 102 | ||
101 | #endif /* __PERF_ANNOTATE_H */ | 103 | #endif /* __PERF_ANNOTATE_H */ |
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 4f769f47e19a..e8d28e2ecdba 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h | |||
@@ -44,6 +44,7 @@ struct perf_top { | |||
44 | pid_t target_pid, target_tid; | 44 | pid_t target_pid, target_tid; |
45 | bool hide_kernel_symbols, hide_user_symbols, zero; | 45 | bool hide_kernel_symbols, hide_user_symbols, zero; |
46 | const char *cpu_list; | 46 | const char *cpu_list; |
47 | struct sym_entry *sym_filter_entry; | ||
47 | struct perf_evsel *sym_evsel; | 48 | struct perf_evsel *sym_evsel; |
48 | }; | 49 | }; |
49 | 50 | ||
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index cfb5a27f15d2..8c17a8730e4a 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include "../../sort.h" | 6 | #include "../../sort.h" |
7 | #include "../../symbol.h" | 7 | #include "../../symbol.h" |
8 | #include "../../annotate.h" | 8 | #include "../../annotate.h" |
9 | #include <pthread.h> | ||
9 | 10 | ||
10 | static void ui__error_window(const char *fmt, ...) | 11 | static void ui__error_window(const char *fmt, ...) |
11 | { | 12 | { |
@@ -138,46 +139,108 @@ static void annotate_browser__set_top(struct annotate_browser *self, | |||
138 | self->curr_hot = nd; | 139 | self->curr_hot = nd; |
139 | } | 140 | } |
140 | 141 | ||
141 | static int annotate_browser__run(struct annotate_browser *self) | 142 | static void annotate_browser__calc_percent(struct annotate_browser *browser, |
143 | int evidx) | ||
142 | { | 144 | { |
143 | struct rb_node *nd; | 145 | struct symbol *sym = browser->b.priv; |
146 | struct annotation *notes = symbol__annotation(sym); | ||
147 | struct objdump_line *pos; | ||
148 | |||
149 | browser->entries = RB_ROOT; | ||
150 | |||
151 | pthread_mutex_lock(¬es->lock); | ||
152 | |||
153 | list_for_each_entry(pos, ¬es->src->source, node) { | ||
154 | struct objdump_line_rb_node *rbpos = objdump_line__rb(pos); | ||
155 | rbpos->percent = objdump_line__calc_percent(pos, sym, evidx); | ||
156 | if (rbpos->percent < 0.01) { | ||
157 | RB_CLEAR_NODE(&rbpos->rb_node); | ||
158 | continue; | ||
159 | } | ||
160 | objdump__insert_line(&browser->entries, rbpos); | ||
161 | } | ||
162 | pthread_mutex_unlock(¬es->lock); | ||
163 | |||
164 | browser->curr_hot = rb_last(&browser->entries); | ||
165 | } | ||
166 | |||
167 | static int annotate_browser__run(struct annotate_browser *self, int evidx, | ||
168 | int refresh) | ||
169 | { | ||
170 | struct rb_node *nd = NULL; | ||
144 | struct symbol *sym = self->b.priv; | 171 | struct symbol *sym = self->b.priv; |
172 | /* | ||
173 | * RIGHT To allow builtin-annotate to cycle thru multiple symbols by | ||
174 | * examining the exit key for this function. | ||
175 | */ | ||
176 | int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB, | ||
177 | NEWT_KEY_RIGHT, 0 }; | ||
145 | int key; | 178 | int key; |
146 | 179 | ||
147 | if (ui_browser__show(&self->b, sym->name, | 180 | if (ui_browser__show(&self->b, sym->name, |
148 | "<-, -> or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0) | 181 | "<-, -> or ESC: exit, TAB/shift+TAB: " |
182 | "cycle hottest lines, H: Hottest") < 0) | ||
149 | return -1; | 183 | return -1; |
150 | /* | 184 | |
151 | * To allow builtin-annotate to cycle thru multiple symbols by | 185 | ui_browser__add_exit_keys(&self->b, exit_keys); |
152 | * examining the exit key for this function. | 186 | annotate_browser__calc_percent(self, evidx); |
153 | */ | 187 | |
154 | ui_browser__add_exit_key(&self->b, NEWT_KEY_RIGHT); | 188 | if (self->curr_hot) |
189 | annotate_browser__set_top(self, self->curr_hot); | ||
155 | 190 | ||
156 | nd = self->curr_hot; | 191 | nd = self->curr_hot; |
157 | if (nd) { | 192 | |
158 | int tabs[] = { NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0 }; | 193 | if (refresh != 0) |
159 | ui_browser__add_exit_keys(&self->b, tabs); | 194 | newtFormSetTimer(self->b.form, refresh); |
160 | } | ||
161 | 195 | ||
162 | while (1) { | 196 | while (1) { |
163 | key = ui_browser__run(&self->b); | 197 | key = ui_browser__run(&self->b); |
164 | 198 | ||
199 | if (refresh != 0) { | ||
200 | annotate_browser__calc_percent(self, evidx); | ||
201 | /* | ||
202 | * Current line focus got out of the list of most active | ||
203 | * lines, NULL it so that if TAB|UNTAB is pressed, we | ||
204 | * move to curr_hot (current hottest line). | ||
205 | */ | ||
206 | if (nd != NULL && RB_EMPTY_NODE(nd)) | ||
207 | nd = NULL; | ||
208 | } | ||
209 | |||
165 | switch (key) { | 210 | switch (key) { |
211 | case -1: | ||
212 | /* | ||
213 | * FIXME we need to check if it was | ||
214 | * es.reason == NEWT_EXIT_TIMER | ||
215 | */ | ||
216 | if (refresh != 0) | ||
217 | symbol__annotate_decay_histogram(sym, evidx); | ||
218 | continue; | ||
166 | case NEWT_KEY_TAB: | 219 | case NEWT_KEY_TAB: |
167 | nd = rb_prev(nd); | 220 | if (nd != NULL) { |
168 | if (nd == NULL) | 221 | nd = rb_prev(nd); |
169 | nd = rb_last(&self->entries); | 222 | if (nd == NULL) |
170 | annotate_browser__set_top(self, nd); | 223 | nd = rb_last(&self->entries); |
224 | } else | ||
225 | nd = self->curr_hot; | ||
171 | break; | 226 | break; |
172 | case NEWT_KEY_UNTAB: | 227 | case NEWT_KEY_UNTAB: |
173 | nd = rb_next(nd); | 228 | if (nd != NULL) |
174 | if (nd == NULL) | 229 | nd = rb_next(nd); |
175 | nd = rb_first(&self->entries); | 230 | if (nd == NULL) |
176 | annotate_browser__set_top(self, nd); | 231 | nd = rb_first(&self->entries); |
232 | else | ||
233 | nd = self->curr_hot; | ||
234 | break; | ||
235 | case 'H': | ||
236 | nd = self->curr_hot; | ||
177 | break; | 237 | break; |
178 | default: | 238 | default: |
179 | goto out; | 239 | goto out; |
180 | } | 240 | } |
241 | |||
242 | if (nd != NULL) | ||
243 | annotate_browser__set_top(self, nd); | ||
181 | } | 244 | } |
182 | out: | 245 | out: |
183 | ui_browser__hide(&self->b); | 246 | ui_browser__hide(&self->b); |
@@ -186,13 +249,13 @@ out: | |||
186 | 249 | ||
187 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx) | 250 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx) |
188 | { | 251 | { |
189 | return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx); | 252 | return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0); |
190 | } | 253 | } |
191 | 254 | ||
192 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx) | 255 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, |
256 | int refresh) | ||
193 | { | 257 | { |
194 | struct objdump_line *pos, *n; | 258 | struct objdump_line *pos, *n; |
195 | struct objdump_line_rb_node *rbpos; | ||
196 | struct annotation *notes = symbol__annotation(sym); | 259 | struct annotation *notes = symbol__annotation(sym); |
197 | struct annotate_browser browser = { | 260 | struct annotate_browser browser = { |
198 | .b = { | 261 | .b = { |
@@ -211,7 +274,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx) | |||
211 | if (map->dso->annotate_warned) | 274 | if (map->dso->annotate_warned) |
212 | return -1; | 275 | return -1; |
213 | 276 | ||
214 | if (symbol__annotate(sym, map, sizeof(*rbpos)) < 0) { | 277 | if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) { |
215 | ui__error_window(ui_helpline__last_msg); | 278 | ui__error_window(ui_helpline__last_msg); |
216 | return -1; | 279 | return -1; |
217 | } | 280 | } |
@@ -219,26 +282,17 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx) | |||
219 | ui_helpline__push("Press <- or ESC to exit"); | 282 | ui_helpline__push("Press <- or ESC to exit"); |
220 | 283 | ||
221 | list_for_each_entry(pos, ¬es->src->source, node) { | 284 | list_for_each_entry(pos, ¬es->src->source, node) { |
285 | struct objdump_line_rb_node *rbpos; | ||
222 | size_t line_len = strlen(pos->line); | 286 | size_t line_len = strlen(pos->line); |
287 | |||
223 | if (browser.b.width < line_len) | 288 | if (browser.b.width < line_len) |
224 | browser.b.width = line_len; | 289 | browser.b.width = line_len; |
225 | rbpos = objdump_line__rb(pos); | 290 | rbpos = objdump_line__rb(pos); |
226 | rbpos->idx = browser.b.nr_entries++; | 291 | rbpos->idx = browser.b.nr_entries++; |
227 | rbpos->percent = objdump_line__calc_percent(pos, sym, evidx); | ||
228 | if (rbpos->percent < 0.01) | ||
229 | continue; | ||
230 | objdump__insert_line(&browser.entries, rbpos); | ||
231 | } | 292 | } |
232 | 293 | ||
233 | /* | ||
234 | * Position the browser at the hottest line. | ||
235 | */ | ||
236 | browser.curr_hot = rb_last(&browser.entries); | ||
237 | if (browser.curr_hot) | ||
238 | annotate_browser__set_top(&browser, browser.curr_hot); | ||
239 | |||
240 | browser.b.width += 18; /* Percentage */ | 294 | browser.b.width += 18; /* Percentage */ |
241 | ret = annotate_browser__run(&browser); | 295 | ret = annotate_browser__run(&browser, evidx, refresh); |
242 | list_for_each_entry_safe(pos, n, ¬es->src->source, node) { | 296 | list_for_each_entry_safe(pos, n, ¬es->src->source, node) { |
243 | list_del(&pos->node); | 297 | list_del(&pos->node); |
244 | objdump_line__free(pos); | 298 | objdump_line__free(pos); |
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c index ca6062483a8f..377ff58c9ae9 100644 --- a/tools/perf/util/ui/browsers/top.c +++ b/tools/perf/util/ui/browsers/top.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * Released under the GPL v2. (and only v2, not any later version) | 7 | * Released under the GPL v2. (and only v2, not any later version) |
8 | */ | 8 | */ |
9 | #include "../browser.h" | 9 | #include "../browser.h" |
10 | #include "../../annotate.h" | ||
10 | #include "../helpline.h" | 11 | #include "../helpline.h" |
11 | #include "../libslang.h" | 12 | #include "../libslang.h" |
12 | #include "../../evlist.h" | 13 | #include "../../evlist.h" |
@@ -18,6 +19,7 @@ | |||
18 | struct perf_top_browser { | 19 | struct perf_top_browser { |
19 | struct ui_browser b; | 20 | struct ui_browser b; |
20 | struct rb_root root; | 21 | struct rb_root root; |
22 | struct sym_entry *selection; | ||
21 | float sum_ksamples; | 23 | float sum_ksamples; |
22 | int dso_width; | 24 | int dso_width; |
23 | int dso_short_width; | 25 | int dso_short_width; |
@@ -60,6 +62,9 @@ static void perf_top_browser__write(struct ui_browser *browser, void *entry, int | |||
60 | slsmg_write_nstring(width >= syme->map->dso->long_name_len ? | 62 | slsmg_write_nstring(width >= syme->map->dso->long_name_len ? |
61 | syme->map->dso->long_name : | 63 | syme->map->dso->long_name : |
62 | syme->map->dso->short_name, width); | 64 | syme->map->dso->short_name, width); |
65 | |||
66 | if (current_entry) | ||
67 | top_browser->selection = syme; | ||
63 | } | 68 | } |
64 | 69 | ||
65 | static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser) | 70 | 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) | |||
80 | browser->b.nr_entries = top->rb_entries; | 85 | browser->b.nr_entries = top->rb_entries; |
81 | } | 86 | } |
82 | 87 | ||
88 | static void perf_top_browser__annotate(struct perf_top_browser *browser) | ||
89 | { | ||
90 | struct sym_entry *syme = browser->selection; | ||
91 | struct symbol *sym = sym_entry__symbol(syme); | ||
92 | struct annotation *notes = symbol__annotation(sym); | ||
93 | struct perf_top *top = browser->b.priv; | ||
94 | |||
95 | if (notes->src != NULL) | ||
96 | goto do_annotation; | ||
97 | |||
98 | pthread_mutex_lock(¬es->lock); | ||
99 | |||
100 | top->sym_filter_entry = NULL; | ||
101 | |||
102 | if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) { | ||
103 | pr_err("Not enough memory for annotating '%s' symbol!\n", | ||
104 | sym->name); | ||
105 | pthread_mutex_unlock(¬es->lock); | ||
106 | return; | ||
107 | } | ||
108 | |||
109 | top->sym_filter_entry = syme; | ||
110 | |||
111 | pthread_mutex_unlock(¬es->lock); | ||
112 | do_annotation: | ||
113 | symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000); | ||
114 | } | ||
115 | |||
83 | static int perf_top_browser__run(struct perf_top_browser *browser) | 116 | static int perf_top_browser__run(struct perf_top_browser *browser) |
84 | { | 117 | { |
85 | int key; | 118 | int key; |
86 | char title[160]; | 119 | char title[160]; |
87 | struct perf_top *top = browser->b.priv; | 120 | struct perf_top *top = browser->b.priv; |
88 | int delay_msecs = top->delay_secs * 1000; | 121 | int delay_msecs = top->delay_secs * 1000; |
122 | int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; | ||
89 | 123 | ||
90 | perf_top_browser__update_rb_tree(browser); | 124 | perf_top_browser__update_rb_tree(browser); |
91 | perf_top__header_snprintf(top, title, sizeof(title)); | 125 | perf_top__header_snprintf(top, title, sizeof(title)); |
92 | perf_top__reset_sample_counters(top); | 126 | perf_top__reset_sample_counters(top); |
93 | 127 | ||
94 | if (ui_browser__show(&browser->b, title, "ESC: exit") < 0) | 128 | if (ui_browser__show(&browser->b, title, |
129 | "ESC: exit, ENTER|->|a: Live Annotate") < 0) | ||
95 | return -1; | 130 | return -1; |
96 | 131 | ||
97 | newtFormSetTimer(browser->b.form, delay_msecs); | 132 | newtFormSetTimer(browser->b.form, delay_msecs); |
133 | ui_browser__add_exit_keys(&browser->b, exit_keys); | ||
98 | 134 | ||
99 | while (1) { | 135 | while (1) { |
100 | key = ui_browser__run(&browser->b); | 136 | key = ui_browser__run(&browser->b); |
@@ -109,7 +145,12 @@ static int perf_top_browser__run(struct perf_top_browser *browser) | |||
109 | SLsmg_gotorc(0, 0); | 145 | SLsmg_gotorc(0, 0); |
110 | slsmg_write_nstring(title, browser->b.width); | 146 | slsmg_write_nstring(title, browser->b.width); |
111 | break; | 147 | break; |
112 | case NEWT_KEY_TAB: | 148 | case 'a': |
149 | case NEWT_KEY_RIGHT: | ||
150 | case NEWT_KEY_ENTER: | ||
151 | if (browser->selection) | ||
152 | perf_top_browser__annotate(browser); | ||
153 | break; | ||
113 | default: | 154 | default: |
114 | goto out; | 155 | goto out; |
115 | } | 156 | } |