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" | |
c16bfe9a | 13 | #include "../util.h" |
dcc101d1 | 14 | #include "../ui.h" |
c0443df1 ACM |
15 | #include "../../evlist.h" |
16 | #include "../../hist.h" | |
17 | #include "../../sort.h" | |
18 | #include "../../symbol.h" | |
dcc101d1 | 19 | #include "../../session.h" |
c0443df1 ACM |
20 | #include "../../top.h" |
21 | ||
22 | struct perf_top_browser { | |
23 | struct ui_browser b; | |
24 | struct rb_root root; | |
c97cf422 | 25 | struct sym_entry *selection; |
c0443df1 ACM |
26 | float sum_ksamples; |
27 | int dso_width; | |
28 | int dso_short_width; | |
29 | int sym_width; | |
30 | }; | |
31 | ||
32 | static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row) | |
33 | { | |
34 | struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b); | |
35 | struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node); | |
36 | bool current_entry = ui_browser__is_current_entry(browser, row); | |
37 | struct symbol *symbol = sym_entry__symbol(syme); | |
38 | struct perf_top *top = browser->priv; | |
39 | int width = browser->width; | |
40 | double pcnt; | |
41 | ||
42 | pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) / | |
43 | top_browser->sum_ksamples)); | |
44 | ui_browser__set_percent_color(browser, pcnt, current_entry); | |
45 | ||
46 | if (top->evlist->nr_entries == 1 || !top->display_weighted) { | |
47 | slsmg_printf("%20.2f ", syme->weight); | |
eb489008 | 48 | width -= 21; |
c0443df1 ACM |
49 | } else { |
50 | slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count); | |
eb489008 | 51 | width -= 20; |
c0443df1 ACM |
52 | } |
53 | ||
54 | slsmg_printf("%4.1f%%", pcnt); | |
55 | width -= 7; | |
56 | ||
57 | if (verbose) { | |
58 | slsmg_printf(" %016" PRIx64, symbol->start); | |
59 | width -= 17; | |
60 | } | |
61 | ||
62 | slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width, | |
63 | symbol->name); | |
64 | width -= top_browser->sym_width; | |
65 | slsmg_write_nstring(width >= syme->map->dso->long_name_len ? | |
66 | syme->map->dso->long_name : | |
67 | syme->map->dso->short_name, width); | |
c97cf422 ACM |
68 | |
69 | if (current_entry) | |
70 | top_browser->selection = syme; | |
c0443df1 ACM |
71 | } |
72 | ||
73 | static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser) | |
74 | { | |
75 | struct perf_top *top = browser->b.priv; | |
6435a5e3 | 76 | u64 top_idx = browser->b.top_idx; |
c0443df1 ACM |
77 | |
78 | browser->root = RB_ROOT; | |
79 | browser->b.top = NULL; | |
80 | browser->sum_ksamples = perf_top__decay_samples(top, &browser->root); | |
3166fc8f ACM |
81 | /* |
82 | * No active symbols | |
83 | */ | |
84 | if (top->rb_entries == 0) | |
85 | return; | |
86 | ||
c0443df1 ACM |
87 | perf_top__find_widths(top, &browser->root, &browser->dso_width, |
88 | &browser->dso_short_width, | |
89 | &browser->sym_width); | |
90 | if (browser->sym_width + browser->dso_width > browser->b.width - 29) { | |
91 | browser->dso_width = browser->dso_short_width; | |
92 | if (browser->sym_width + browser->dso_width > browser->b.width - 29) | |
93 | browser->sym_width = browser->b.width - browser->dso_width - 29; | |
94 | } | |
6435a5e3 ACM |
95 | |
96 | /* | |
97 | * Adjust the ui_browser indexes since the entries in the browser->root | |
98 | * rb_tree may have changed, then seek it from start, so that we get a | |
99 | * possible new top of the screen. | |
100 | */ | |
c0443df1 | 101 | browser->b.nr_entries = top->rb_entries; |
6435a5e3 ACM |
102 | |
103 | if (top_idx >= browser->b.nr_entries) { | |
104 | if (browser->b.height >= browser->b.nr_entries) | |
105 | top_idx = browser->b.nr_entries - browser->b.height; | |
106 | else | |
107 | top_idx = 0; | |
108 | } | |
109 | ||
110 | if (browser->b.index >= top_idx + browser->b.height) | |
111 | browser->b.index = top_idx + browser->b.index - browser->b.top_idx; | |
112 | ||
113 | if (browser->b.index >= browser->b.nr_entries) | |
114 | browser->b.index = browser->b.nr_entries - 1; | |
115 | ||
116 | browser->b.top_idx = top_idx; | |
117 | browser->b.seek(&browser->b, top_idx, SEEK_SET); | |
c0443df1 ACM |
118 | } |
119 | ||
c97cf422 ACM |
120 | static void perf_top_browser__annotate(struct perf_top_browser *browser) |
121 | { | |
122 | struct sym_entry *syme = browser->selection; | |
123 | struct symbol *sym = sym_entry__symbol(syme); | |
124 | struct annotation *notes = symbol__annotation(sym); | |
125 | struct perf_top *top = browser->b.priv; | |
126 | ||
127 | if (notes->src != NULL) | |
128 | goto do_annotation; | |
129 | ||
130 | pthread_mutex_lock(¬es->lock); | |
131 | ||
132 | top->sym_filter_entry = NULL; | |
133 | ||
134 | if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) { | |
135 | pr_err("Not enough memory for annotating '%s' symbol!\n", | |
136 | sym->name); | |
137 | pthread_mutex_unlock(¬es->lock); | |
138 | return; | |
139 | } | |
140 | ||
141 | top->sym_filter_entry = syme; | |
142 | ||
143 | pthread_mutex_unlock(¬es->lock); | |
144 | do_annotation: | |
81cce8de | 145 | symbol__tui_annotate(sym, syme->map, 0, NULL, NULL, top->delay_secs * 1000); |
c97cf422 ACM |
146 | } |
147 | ||
dcc101d1 ACM |
148 | static void perf_top_browser__warn_lost(struct perf_top_browser *browser) |
149 | { | |
150 | struct perf_top *top = browser->b.priv; | |
151 | char msg[128]; | |
152 | int len; | |
153 | ||
154 | top->total_lost_warned = top->session->hists.stats.total_lost; | |
155 | pthread_mutex_lock(&ui__lock); | |
156 | ui_browser__set_color(&browser->b, HE_COLORSET_TOP); | |
157 | len = snprintf(msg, sizeof(msg), | |
158 | " WARNING: LOST %" PRIu64 " events, Check IO/CPU overload", | |
159 | top->total_lost_warned); | |
160 | if (len > browser->b.width) | |
161 | len = browser->b.width; | |
162 | SLsmg_gotorc(0, browser->b.width - len); | |
163 | slsmg_write_nstring(msg, len); | |
164 | pthread_mutex_unlock(&ui__lock); | |
165 | } | |
166 | ||
c0443df1 ACM |
167 | static int perf_top_browser__run(struct perf_top_browser *browser) |
168 | { | |
169 | int key; | |
170 | char title[160]; | |
171 | struct perf_top *top = browser->b.priv; | |
172 | int delay_msecs = top->delay_secs * 1000; | |
c97cf422 | 173 | int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; |
c0443df1 ACM |
174 | |
175 | perf_top_browser__update_rb_tree(browser); | |
176 | perf_top__header_snprintf(top, title, sizeof(title)); | |
177 | perf_top__reset_sample_counters(top); | |
178 | ||
c97cf422 ACM |
179 | if (ui_browser__show(&browser->b, title, |
180 | "ESC: exit, ENTER|->|a: Live Annotate") < 0) | |
c0443df1 ACM |
181 | return -1; |
182 | ||
183 | newtFormSetTimer(browser->b.form, delay_msecs); | |
c97cf422 | 184 | ui_browser__add_exit_keys(&browser->b, exit_keys); |
c0443df1 ACM |
185 | |
186 | while (1) { | |
187 | key = ui_browser__run(&browser->b); | |
188 | ||
189 | switch (key) { | |
190 | case -1: | |
191 | /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */ | |
192 | perf_top_browser__update_rb_tree(browser); | |
193 | perf_top__header_snprintf(top, title, sizeof(title)); | |
194 | perf_top__reset_sample_counters(top); | |
195 | ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT); | |
196 | SLsmg_gotorc(0, 0); | |
197 | slsmg_write_nstring(title, browser->b.width); | |
dcc101d1 ACM |
198 | |
199 | if (top->total_lost_warned != top->session->hists.stats.total_lost) | |
200 | perf_top_browser__warn_lost(browser); | |
c0443df1 | 201 | break; |
c97cf422 ACM |
202 | case 'a': |
203 | case NEWT_KEY_RIGHT: | |
204 | case NEWT_KEY_ENTER: | |
205 | if (browser->selection) | |
206 | perf_top_browser__annotate(browser); | |
207 | break; | |
c16bfe9a ACM |
208 | case NEWT_KEY_LEFT: |
209 | continue; | |
210 | case NEWT_KEY_ESCAPE: | |
211 | if (!ui__dialog_yesno("Do you really want to exit?")) | |
212 | continue; | |
213 | /* Fall thru */ | |
c0443df1 ACM |
214 | default: |
215 | goto out; | |
216 | } | |
217 | } | |
218 | out: | |
219 | ui_browser__hide(&browser->b); | |
220 | return key; | |
221 | } | |
222 | ||
223 | int perf_top__tui_browser(struct perf_top *top) | |
224 | { | |
225 | struct perf_top_browser browser = { | |
226 | .b = { | |
227 | .entries = &browser.root, | |
228 | .refresh = ui_browser__rb_tree_refresh, | |
229 | .seek = ui_browser__rb_tree_seek, | |
230 | .write = perf_top_browser__write, | |
231 | .priv = top, | |
232 | }, | |
233 | }; | |
234 | ||
c0443df1 ACM |
235 | return perf_top_browser__run(&browser); |
236 | } |