diff options
Diffstat (limited to 'tools/perf/util/ui/browser.c')
-rw-r--r-- | tools/perf/util/ui/browser.c | 228 |
1 files changed, 155 insertions, 73 deletions
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c index 611219f80680..a54b926efe2b 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/util/ui/browser.c | |||
@@ -1,4 +1,7 @@ | |||
1 | #include "../util.h" | ||
2 | #include "../../perf.h" | ||
1 | #include "libslang.h" | 3 | #include "libslang.h" |
4 | #include <newt.h> | ||
2 | #include "ui.h" | 5 | #include "ui.h" |
3 | #include <linux/compiler.h> | 6 | #include <linux/compiler.h> |
4 | #include <linux/list.h> | 7 | #include <linux/list.h> |
@@ -8,8 +11,8 @@ | |||
8 | #include "browser.h" | 11 | #include "browser.h" |
9 | #include "helpline.h" | 12 | #include "helpline.h" |
10 | #include "../color.h" | 13 | #include "../color.h" |
11 | #include "../util.h" | 14 | |
12 | #include <stdio.h> | 15 | int newtGetKey(void); |
13 | 16 | ||
14 | static int ui_browser__percent_color(double percent, bool current) | 17 | static int ui_browser__percent_color(double percent, bool current) |
15 | { | 18 | { |
@@ -39,31 +42,62 @@ void ui_browser__gotorc(struct ui_browser *self, int y, int x) | |||
39 | SLsmg_gotorc(self->y + y, self->x + x); | 42 | SLsmg_gotorc(self->y + y, self->x + x); |
40 | } | 43 | } |
41 | 44 | ||
45 | static struct list_head * | ||
46 | ui_browser__list_head_filter_entries(struct ui_browser *browser, | ||
47 | struct list_head *pos) | ||
48 | { | ||
49 | do { | ||
50 | if (!browser->filter || !browser->filter(browser, pos)) | ||
51 | return pos; | ||
52 | pos = pos->next; | ||
53 | } while (pos != browser->entries); | ||
54 | |||
55 | return NULL; | ||
56 | } | ||
57 | |||
58 | static struct list_head * | ||
59 | ui_browser__list_head_filter_prev_entries(struct ui_browser *browser, | ||
60 | struct list_head *pos) | ||
61 | { | ||
62 | do { | ||
63 | if (!browser->filter || !browser->filter(browser, pos)) | ||
64 | return pos; | ||
65 | pos = pos->prev; | ||
66 | } while (pos != browser->entries); | ||
67 | |||
68 | return NULL; | ||
69 | } | ||
70 | |||
42 | void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence) | 71 | void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence) |
43 | { | 72 | { |
44 | struct list_head *head = self->entries; | 73 | struct list_head *head = self->entries; |
45 | struct list_head *pos; | 74 | struct list_head *pos; |
46 | 75 | ||
76 | if (self->nr_entries == 0) | ||
77 | return; | ||
78 | |||
47 | switch (whence) { | 79 | switch (whence) { |
48 | case SEEK_SET: | 80 | case SEEK_SET: |
49 | pos = head->next; | 81 | pos = ui_browser__list_head_filter_entries(self, head->next); |
50 | break; | 82 | break; |
51 | case SEEK_CUR: | 83 | case SEEK_CUR: |
52 | pos = self->top; | 84 | pos = self->top; |
53 | break; | 85 | break; |
54 | case SEEK_END: | 86 | case SEEK_END: |
55 | pos = head->prev; | 87 | pos = ui_browser__list_head_filter_prev_entries(self, head->prev); |
56 | break; | 88 | break; |
57 | default: | 89 | default: |
58 | return; | 90 | return; |
59 | } | 91 | } |
60 | 92 | ||
93 | assert(pos != NULL); | ||
94 | |||
61 | if (offset > 0) { | 95 | if (offset > 0) { |
62 | while (offset-- != 0) | 96 | while (offset-- != 0) |
63 | pos = pos->next; | 97 | pos = ui_browser__list_head_filter_entries(self, pos->next); |
64 | } else { | 98 | } else { |
65 | while (offset++ != 0) | 99 | while (offset++ != 0) |
66 | pos = pos->prev; | 100 | pos = ui_browser__list_head_filter_prev_entries(self, pos->prev); |
67 | } | 101 | } |
68 | 102 | ||
69 | self->top = pos; | 103 | self->top = pos; |
@@ -127,11 +161,8 @@ bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row) | |||
127 | 161 | ||
128 | void ui_browser__refresh_dimensions(struct ui_browser *self) | 162 | void ui_browser__refresh_dimensions(struct ui_browser *self) |
129 | { | 163 | { |
130 | int cols, rows; | 164 | self->width = SLtt_Screen_Cols - 1; |
131 | newtGetScreenSize(&cols, &rows); | 165 | self->height = SLtt_Screen_Rows - 2; |
132 | |||
133 | self->width = cols - 1; | ||
134 | self->height = rows - 2; | ||
135 | self->y = 1; | 166 | self->y = 1; |
136 | self->x = 0; | 167 | self->x = 0; |
137 | } | 168 | } |
@@ -142,26 +173,11 @@ void ui_browser__reset_index(struct ui_browser *self) | |||
142 | self->seek(self, 0, SEEK_SET); | 173 | self->seek(self, 0, SEEK_SET); |
143 | } | 174 | } |
144 | 175 | ||
145 | void ui_browser__add_exit_key(struct ui_browser *self, int key) | ||
146 | { | ||
147 | newtFormAddHotKey(self->form, key); | ||
148 | } | ||
149 | |||
150 | void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]) | ||
151 | { | ||
152 | int i = 0; | ||
153 | |||
154 | while (keys[i] && i < 64) { | ||
155 | ui_browser__add_exit_key(self, keys[i]); | ||
156 | ++i; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | void __ui_browser__show_title(struct ui_browser *browser, const char *title) | 176 | void __ui_browser__show_title(struct ui_browser *browser, const char *title) |
161 | { | 177 | { |
162 | SLsmg_gotorc(0, 0); | 178 | SLsmg_gotorc(0, 0); |
163 | ui_browser__set_color(browser, NEWT_COLORSET_ROOT); | 179 | ui_browser__set_color(browser, NEWT_COLORSET_ROOT); |
164 | slsmg_write_nstring(title, browser->width); | 180 | slsmg_write_nstring(title, browser->width + 1); |
165 | } | 181 | } |
166 | 182 | ||
167 | void ui_browser__show_title(struct ui_browser *browser, const char *title) | 183 | void ui_browser__show_title(struct ui_browser *browser, const char *title) |
@@ -174,77 +190,143 @@ void ui_browser__show_title(struct ui_browser *browser, const char *title) | |||
174 | int ui_browser__show(struct ui_browser *self, const char *title, | 190 | int ui_browser__show(struct ui_browser *self, const char *title, |
175 | const char *helpline, ...) | 191 | const char *helpline, ...) |
176 | { | 192 | { |
193 | int err; | ||
177 | va_list ap; | 194 | va_list ap; |
178 | int keys[] = { NEWT_KEY_UP, NEWT_KEY_DOWN, NEWT_KEY_PGUP, | ||
179 | NEWT_KEY_PGDN, NEWT_KEY_HOME, NEWT_KEY_END, ' ', | ||
180 | NEWT_KEY_LEFT, NEWT_KEY_ESCAPE, 'q', CTRL('c'), 0 }; | ||
181 | |||
182 | if (self->form != NULL) | ||
183 | newtFormDestroy(self->form); | ||
184 | 195 | ||
185 | ui_browser__refresh_dimensions(self); | 196 | ui_browser__refresh_dimensions(self); |
186 | self->form = newtForm(NULL, NULL, 0); | ||
187 | if (self->form == NULL) | ||
188 | return -1; | ||
189 | |||
190 | self->sb = newtVerticalScrollbar(self->width, 1, self->height, | ||
191 | HE_COLORSET_NORMAL, | ||
192 | HE_COLORSET_SELECTED); | ||
193 | if (self->sb == NULL) | ||
194 | return -1; | ||
195 | 197 | ||
196 | pthread_mutex_lock(&ui__lock); | 198 | pthread_mutex_lock(&ui__lock); |
197 | __ui_browser__show_title(self, title); | 199 | __ui_browser__show_title(self, title); |
198 | 200 | ||
199 | ui_browser__add_exit_keys(self, keys); | 201 | self->title = title; |
200 | newtFormAddComponent(self->form, self->sb); | 202 | free(self->helpline); |
203 | self->helpline = NULL; | ||
201 | 204 | ||
202 | va_start(ap, helpline); | 205 | va_start(ap, helpline); |
203 | ui_helpline__vpush(helpline, ap); | 206 | err = vasprintf(&self->helpline, helpline, ap); |
204 | va_end(ap); | 207 | va_end(ap); |
208 | if (err > 0) | ||
209 | ui_helpline__push(self->helpline); | ||
205 | pthread_mutex_unlock(&ui__lock); | 210 | pthread_mutex_unlock(&ui__lock); |
206 | return 0; | 211 | return err ? 0 : -1; |
207 | } | 212 | } |
208 | 213 | ||
209 | void ui_browser__hide(struct ui_browser *self) | 214 | void ui_browser__hide(struct ui_browser *browser __used) |
210 | { | 215 | { |
211 | pthread_mutex_lock(&ui__lock); | 216 | pthread_mutex_lock(&ui__lock); |
212 | newtFormDestroy(self->form); | ||
213 | self->form = NULL; | ||
214 | ui_helpline__pop(); | 217 | ui_helpline__pop(); |
215 | pthread_mutex_unlock(&ui__lock); | 218 | pthread_mutex_unlock(&ui__lock); |
216 | } | 219 | } |
217 | 220 | ||
218 | int ui_browser__refresh(struct ui_browser *self) | 221 | static void ui_browser__scrollbar_set(struct ui_browser *browser) |
222 | { | ||
223 | int height = browser->height, h = 0, pct = 0, | ||
224 | col = browser->width, | ||
225 | row = browser->y - 1; | ||
226 | |||
227 | if (browser->nr_entries > 1) { | ||
228 | pct = ((browser->index * (browser->height - 1)) / | ||
229 | (browser->nr_entries - 1)); | ||
230 | } | ||
231 | |||
232 | while (h < height) { | ||
233 | ui_browser__gotorc(browser, row++, col); | ||
234 | SLsmg_set_char_set(1); | ||
235 | SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_BOARD_CHAR); | ||
236 | SLsmg_set_char_set(0); | ||
237 | ++h; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | static int __ui_browser__refresh(struct ui_browser *browser) | ||
219 | { | 242 | { |
220 | int row; | 243 | int row; |
221 | 244 | ||
245 | row = browser->refresh(browser); | ||
246 | ui_browser__set_color(browser, HE_COLORSET_NORMAL); | ||
247 | SLsmg_fill_region(browser->y + row, browser->x, | ||
248 | browser->height - row, browser->width, ' '); | ||
249 | ui_browser__scrollbar_set(browser); | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | int ui_browser__refresh(struct ui_browser *browser) | ||
255 | { | ||
222 | pthread_mutex_lock(&ui__lock); | 256 | pthread_mutex_lock(&ui__lock); |
223 | newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); | 257 | __ui_browser__refresh(browser); |
224 | row = self->refresh(self); | ||
225 | ui_browser__set_color(self, HE_COLORSET_NORMAL); | ||
226 | SLsmg_fill_region(self->y + row, self->x, | ||
227 | self->height - row, self->width, ' '); | ||
228 | pthread_mutex_unlock(&ui__lock); | 258 | pthread_mutex_unlock(&ui__lock); |
229 | 259 | ||
230 | return 0; | 260 | return 0; |
231 | } | 261 | } |
232 | 262 | ||
233 | int ui_browser__run(struct ui_browser *self) | 263 | /* |
264 | * Here we're updating nr_entries _after_ we started browsing, i.e. we have to | ||
265 | * forget about any reference to any entry in the underlying data structure, | ||
266 | * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser | ||
267 | * after an output_resort and hist decay. | ||
268 | */ | ||
269 | void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries) | ||
270 | { | ||
271 | off_t offset = nr_entries - browser->nr_entries; | ||
272 | |||
273 | browser->nr_entries = nr_entries; | ||
274 | |||
275 | if (offset < 0) { | ||
276 | if (browser->top_idx < (u64)-offset) | ||
277 | offset = -browser->top_idx; | ||
278 | |||
279 | browser->index += offset; | ||
280 | browser->top_idx += offset; | ||
281 | } | ||
282 | |||
283 | browser->top = NULL; | ||
284 | browser->seek(browser, browser->top_idx, SEEK_SET); | ||
285 | } | ||
286 | |||
287 | int ui_browser__run(struct ui_browser *self, int delay_secs) | ||
234 | { | 288 | { |
235 | struct newtExitStruct es; | 289 | int err, key; |
290 | struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL; | ||
236 | 291 | ||
237 | if (ui_browser__refresh(self) < 0) | 292 | pthread__unblock_sigwinch(); |
238 | return -1; | ||
239 | 293 | ||
240 | while (1) { | 294 | while (1) { |
241 | off_t offset; | 295 | off_t offset; |
296 | fd_set read_set; | ||
242 | 297 | ||
243 | newtFormRun(self->form, &es); | 298 | pthread_mutex_lock(&ui__lock); |
299 | err = __ui_browser__refresh(self); | ||
300 | SLsmg_refresh(); | ||
301 | pthread_mutex_unlock(&ui__lock); | ||
302 | if (err < 0) | ||
303 | break; | ||
304 | |||
305 | FD_ZERO(&read_set); | ||
306 | FD_SET(0, &read_set); | ||
307 | |||
308 | if (delay_secs) { | ||
309 | timeout.tv_sec = delay_secs; | ||
310 | timeout.tv_usec = 0; | ||
311 | } | ||
244 | 312 | ||
245 | if (es.reason != NEWT_EXIT_HOTKEY) | 313 | err = select(1, &read_set, NULL, NULL, ptimeout); |
314 | if (err > 0 && FD_ISSET(0, &read_set)) | ||
315 | key = newtGetKey(); | ||
316 | else if (err == 0) | ||
246 | break; | 317 | break; |
247 | switch (es.u.key) { | 318 | else { |
319 | pthread_mutex_lock(&ui__lock); | ||
320 | SLtt_get_screen_size(); | ||
321 | SLsmg_reinit_smg(); | ||
322 | pthread_mutex_unlock(&ui__lock); | ||
323 | ui_browser__refresh_dimensions(self); | ||
324 | __ui_browser__show_title(self, self->title); | ||
325 | ui_helpline__puts(self->helpline); | ||
326 | continue; | ||
327 | } | ||
328 | |||
329 | switch (key) { | ||
248 | case NEWT_KEY_DOWN: | 330 | case NEWT_KEY_DOWN: |
249 | if (self->index == self->nr_entries - 1) | 331 | if (self->index == self->nr_entries - 1) |
250 | break; | 332 | break; |
@@ -301,10 +383,8 @@ int ui_browser__run(struct ui_browser *self) | |||
301 | self->seek(self, -offset, SEEK_END); | 383 | self->seek(self, -offset, SEEK_END); |
302 | break; | 384 | break; |
303 | default: | 385 | default: |
304 | return es.u.key; | 386 | return key; |
305 | } | 387 | } |
306 | if (ui_browser__refresh(self) < 0) | ||
307 | return -1; | ||
308 | } | 388 | } |
309 | return -1; | 389 | return -1; |
310 | } | 390 | } |
@@ -316,27 +396,29 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *self) | |||
316 | int row = 0; | 396 | int row = 0; |
317 | 397 | ||
318 | if (self->top == NULL || self->top == self->entries) | 398 | if (self->top == NULL || self->top == self->entries) |
319 | self->top = head->next; | 399 | self->top = ui_browser__list_head_filter_entries(self, head->next); |
320 | 400 | ||
321 | pos = self->top; | 401 | pos = self->top; |
322 | 402 | ||
323 | list_for_each_from(pos, head) { | 403 | list_for_each_from(pos, head) { |
324 | ui_browser__gotorc(self, row, 0); | 404 | if (!self->filter || !self->filter(self, pos)) { |
325 | self->write(self, pos, row); | 405 | ui_browser__gotorc(self, row, 0); |
326 | if (++row == self->height) | 406 | self->write(self, pos, row); |
327 | break; | 407 | if (++row == self->height) |
408 | break; | ||
409 | } | ||
328 | } | 410 | } |
329 | 411 | ||
330 | return row; | 412 | return row; |
331 | } | 413 | } |
332 | 414 | ||
333 | static struct newtPercentTreeColors { | 415 | static struct ui_browser__colors { |
334 | const char *topColorFg, *topColorBg; | 416 | const char *topColorFg, *topColorBg; |
335 | const char *mediumColorFg, *mediumColorBg; | 417 | const char *mediumColorFg, *mediumColorBg; |
336 | const char *normalColorFg, *normalColorBg; | 418 | const char *normalColorFg, *normalColorBg; |
337 | const char *selColorFg, *selColorBg; | 419 | const char *selColorFg, *selColorBg; |
338 | const char *codeColorFg, *codeColorBg; | 420 | const char *codeColorFg, *codeColorBg; |
339 | } defaultPercentTreeColors = { | 421 | } ui_browser__default_colors = { |
340 | "red", "lightgray", | 422 | "red", "lightgray", |
341 | "green", "lightgray", | 423 | "green", "lightgray", |
342 | "black", "lightgray", | 424 | "black", "lightgray", |
@@ -346,7 +428,7 @@ static struct newtPercentTreeColors { | |||
346 | 428 | ||
347 | void ui_browser__init(void) | 429 | void ui_browser__init(void) |
348 | { | 430 | { |
349 | struct newtPercentTreeColors *c = &defaultPercentTreeColors; | 431 | struct ui_browser__colors *c = &ui_browser__default_colors; |
350 | 432 | ||
351 | sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg); | 433 | sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg); |
352 | sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg); | 434 | sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg); |