Commit | Line | Data |
---|---|---|
c0443df1 ACM |
1 | /* |
2 | * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | |
3 | * | |
4 | * Parts came from builtin-{top,stat,record}.c, see those files for further | |
5 | * copyright notes. | |
6 | * | |
7 | * Released under the GPL v2. (and only v2, not any later version) | |
8 | */ | |
9 | #include "../browser.h" | |
c97cf422 | 10 | #include "../../annotate.h" |
c0443df1 ACM |
11 | #include "../helpline.h" |
12 | #include "../libslang.h" | |
13 | #include "../../evlist.h" | |
14 | #include "../../hist.h" | |
15 | #include "../../sort.h" | |
16 | #include "../../symbol.h" | |
17 | #include "../../top.h" | |
18 | ||
19 | struct perf_top_browser { | |
20 | struct ui_browser b; | |
21 | struct rb_root root; | |
c97cf422 | 22 | struct sym_entry *selection; |
c0443df1 ACM |
23 | float sum_ksamples; |
24 | int dso_width; | |
25 | int dso_short_width; | |
26 | int sym_width; | |
27 | }; | |
28 | ||
29 | static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row) | |
30 | { | |
31 | struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b); | |
32 | struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node); | |
33 | bool current_entry = ui_browser__is_current_entry(browser, row); | |
34 | struct symbol *symbol = sym_entry__symbol(syme); | |
35 | struct perf_top *top = browser->priv; | |
36 | int width = browser->width; | |
37 | double pcnt; | |
38 | ||
39 | pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) / | |
40 | top_browser->sum_ksamples)); | |
41 | ui_browser__set_percent_color(browser, pcnt, current_entry); | |
42 | ||
43 | if (top->evlist->nr_entries == 1 || !top->display_weighted) { | |
44 | slsmg_printf("%20.2f ", syme->weight); | |
45 | width -= 24; | |
46 | } else { | |
47 | slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count); | |
48 | width -= 23; | |
49 | } | |
50 | ||
51 | slsmg_printf("%4.1f%%", pcnt); | |
52 | width -= 7; | |
53 | ||
54 | if (verbose) { | |
55 | slsmg_printf(" %016" PRIx64, symbol->start); | |
56 | width -= 17; | |
57 | } | |
58 | ||
59 | slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width, | |
60 | symbol->name); | |
61 | width -= top_browser->sym_width; | |
62 | slsmg_write_nstring(width >= syme->map->dso->long_name_len ? | |
63 | syme->map->dso->long_name : | |
64 | syme->map->dso->short_name, width); | |
c97cf422 ACM |
65 | |
66 | if (current_entry) | |
67 | top_browser->selection = syme; | |
c0443df1 ACM |
68 | } |
69 | ||
70 | static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser) | |
71 | { | |
72 | struct perf_top *top = browser->b.priv; | |
6435a5e3 | 73 | u64 top_idx = browser->b.top_idx; |
c0443df1 ACM |
74 | |
75 | browser->root = RB_ROOT; | |
76 | browser->b.top = NULL; | |
77 | browser->sum_ksamples = perf_top__decay_samples(top, &browser->root); | |
78 | perf_top__find_widths(top, &browser->root, &browser->dso_width, | |
79 | &browser->dso_short_width, | |
80 | &browser->sym_width); | |
81 | if (browser->sym_width + browser->dso_width > browser->b.width - 29) { | |
82 | browser->dso_width = browser->dso_short_width; | |
83 | if (browser->sym_width + browser->dso_width > browser->b.width - 29) | |
84 | browser->sym_width = browser->b.width - browser->dso_width - 29; | |
85 | } | |
6435a5e3 ACM |
86 | |
87 | /* | |
88 | * Adjust the ui_browser indexes since the entries in the browser->root | |
89 | * rb_tree may have changed, then seek it from start, so that we get a | |
90 | * possible new top of the screen. | |
91 | */ | |
c0443df1 | 92 | browser->b.nr_entries = top->rb_entries; |
6435a5e3 ACM |
93 | |
94 | if (top_idx >= browser->b.nr_entries) { | |
95 | if (browser->b.height >= browser->b.nr_entries) | |
96 | top_idx = browser->b.nr_entries - browser->b.height; | |
97 | else | |
98 | top_idx = 0; | |
99 | } | |
100 | ||
101 | if (browser->b.index >= top_idx + browser->b.height) | |
102 | browser->b.index = top_idx + browser->b.index - browser->b.top_idx; | |
103 | ||
104 | if (browser->b.index >= browser->b.nr_entries) | |
105 | browser->b.index = browser->b.nr_entries - 1; | |
106 | ||
107 | browser->b.top_idx = top_idx; | |
108 | browser->b.seek(&browser->b, top_idx, SEEK_SET); | |
c0443df1 ACM |
109 | } |
110 | ||
c97cf422 ACM |
111 | static void perf_top_browser__annotate(struct perf_top_browser *browser) |
112 | { | |
113 | struct sym_entry *syme = browser->selection; | |
114 | struct symbol *sym = sym_entry__symbol(syme); | |
115 | struct annotation *notes = symbol__annotation(sym); | |
116 | struct perf_top *top = browser->b.priv; | |
117 | ||
118 | if (notes->src != NULL) | |
119 | goto do_annotation; | |
120 | ||
121 | pthread_mutex_lock(¬es->lock); | |
122 | ||
123 | top->sym_filter_entry = NULL; | |
124 | ||
125 | if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) { | |
126 | pr_err("Not enough memory for annotating '%s' symbol!\n", | |
127 | sym->name); | |
128 | pthread_mutex_unlock(¬es->lock); | |
129 | return; | |
130 | } | |
131 | ||
132 | top->sym_filter_entry = syme; | |
133 | ||
134 | pthread_mutex_unlock(¬es->lock); | |
135 | do_annotation: | |
136 | symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000); | |
137 | } | |
138 | ||
c0443df1 ACM |
139 | static int perf_top_browser__run(struct perf_top_browser *browser) |
140 | { | |
141 | int key; | |
142 | char title[160]; | |
143 | struct perf_top *top = browser->b.priv; | |
144 | int delay_msecs = top->delay_secs * 1000; | |
c97cf422 | 145 | int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; |
c0443df1 ACM |
146 | |
147 | perf_top_browser__update_rb_tree(browser); | |
148 | perf_top__header_snprintf(top, title, sizeof(title)); | |
149 | perf_top__reset_sample_counters(top); | |
150 | ||
c97cf422 ACM |
151 | if (ui_browser__show(&browser->b, title, |
152 | "ESC: exit, ENTER|->|a: Live Annotate") < 0) | |
c0443df1 ACM |
153 | return -1; |
154 | ||
155 | newtFormSetTimer(browser->b.form, delay_msecs); | |
c97cf422 | 156 | ui_browser__add_exit_keys(&browser->b, exit_keys); |
c0443df1 ACM |
157 | |
158 | while (1) { | |
159 | key = ui_browser__run(&browser->b); | |
160 | ||
161 | switch (key) { | |
162 | case -1: | |
163 | /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */ | |
164 | perf_top_browser__update_rb_tree(browser); | |
165 | perf_top__header_snprintf(top, title, sizeof(title)); | |
166 | perf_top__reset_sample_counters(top); | |
167 | ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT); | |
168 | SLsmg_gotorc(0, 0); | |
169 | slsmg_write_nstring(title, browser->b.width); | |
170 | break; | |
c97cf422 ACM |
171 | case 'a': |
172 | case NEWT_KEY_RIGHT: | |
173 | case NEWT_KEY_ENTER: | |
174 | if (browser->selection) | |
175 | perf_top_browser__annotate(browser); | |
176 | break; | |
c0443df1 ACM |
177 | default: |
178 | goto out; | |
179 | } | |
180 | } | |
181 | out: | |
182 | ui_browser__hide(&browser->b); | |
183 | return key; | |
184 | } | |
185 | ||
186 | int perf_top__tui_browser(struct perf_top *top) | |
187 | { | |
188 | struct perf_top_browser browser = { | |
189 | .b = { | |
190 | .entries = &browser.root, | |
191 | .refresh = ui_browser__rb_tree_refresh, | |
192 | .seek = ui_browser__rb_tree_seek, | |
193 | .write = perf_top_browser__write, | |
194 | .priv = top, | |
195 | }, | |
196 | }; | |
197 | ||
198 | ui_helpline__push("Press <- or ESC to exit"); | |
199 | return perf_top_browser__run(&browser); | |
200 | } |