aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/ui/browser.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/ui/browser.c')
-rw-r--r--tools/perf/util/ui/browser.c429
1 files changed, 335 insertions, 94 deletions
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c
index 611219f80680..556829124b02 100644
--- a/tools/perf/util/ui/browser.c
+++ b/tools/perf/util/ui/browser.c
@@ -1,5 +1,10 @@
1#include "../util.h"
2#include "../cache.h"
3#include "../../perf.h"
1#include "libslang.h" 4#include "libslang.h"
5#include <newt.h>
2#include "ui.h" 6#include "ui.h"
7#include "util.h"
3#include <linux/compiler.h> 8#include <linux/compiler.h>
4#include <linux/list.h> 9#include <linux/list.h>
5#include <linux/rbtree.h> 10#include <linux/rbtree.h>
@@ -7,13 +12,13 @@
7#include <sys/ttydefaults.h> 12#include <sys/ttydefaults.h>
8#include "browser.h" 13#include "browser.h"
9#include "helpline.h" 14#include "helpline.h"
15#include "keysyms.h"
10#include "../color.h" 16#include "../color.h"
11#include "../util.h"
12#include <stdio.h>
13 17
14static int ui_browser__percent_color(double percent, bool current) 18static int ui_browser__percent_color(struct ui_browser *browser,
19 double percent, bool current)
15{ 20{
16 if (current) 21 if (current && (!browser->use_navkeypressed || browser->navkeypressed))
17 return HE_COLORSET_SELECTED; 22 return HE_COLORSET_SELECTED;
18 if (percent >= MIN_RED) 23 if (percent >= MIN_RED)
19 return HE_COLORSET_TOP; 24 return HE_COLORSET_TOP;
@@ -30,7 +35,7 @@ void ui_browser__set_color(struct ui_browser *self __used, int color)
30void ui_browser__set_percent_color(struct ui_browser *self, 35void ui_browser__set_percent_color(struct ui_browser *self,
31 double percent, bool current) 36 double percent, bool current)
32{ 37{
33 int color = ui_browser__percent_color(percent, current); 38 int color = ui_browser__percent_color(self, percent, current);
34 ui_browser__set_color(self, color); 39 ui_browser__set_color(self, color);
35} 40}
36 41
@@ -39,31 +44,62 @@ void ui_browser__gotorc(struct ui_browser *self, int y, int x)
39 SLsmg_gotorc(self->y + y, self->x + x); 44 SLsmg_gotorc(self->y + y, self->x + x);
40} 45}
41 46
47static struct list_head *
48ui_browser__list_head_filter_entries(struct ui_browser *browser,
49 struct list_head *pos)
50{
51 do {
52 if (!browser->filter || !browser->filter(browser, pos))
53 return pos;
54 pos = pos->next;
55 } while (pos != browser->entries);
56
57 return NULL;
58}
59
60static struct list_head *
61ui_browser__list_head_filter_prev_entries(struct ui_browser *browser,
62 struct list_head *pos)
63{
64 do {
65 if (!browser->filter || !browser->filter(browser, pos))
66 return pos;
67 pos = pos->prev;
68 } while (pos != browser->entries);
69
70 return NULL;
71}
72
42void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence) 73void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
43{ 74{
44 struct list_head *head = self->entries; 75 struct list_head *head = self->entries;
45 struct list_head *pos; 76 struct list_head *pos;
46 77
78 if (self->nr_entries == 0)
79 return;
80
47 switch (whence) { 81 switch (whence) {
48 case SEEK_SET: 82 case SEEK_SET:
49 pos = head->next; 83 pos = ui_browser__list_head_filter_entries(self, head->next);
50 break; 84 break;
51 case SEEK_CUR: 85 case SEEK_CUR:
52 pos = self->top; 86 pos = self->top;
53 break; 87 break;
54 case SEEK_END: 88 case SEEK_END:
55 pos = head->prev; 89 pos = ui_browser__list_head_filter_prev_entries(self, head->prev);
56 break; 90 break;
57 default: 91 default:
58 return; 92 return;
59 } 93 }
60 94
95 assert(pos != NULL);
96
61 if (offset > 0) { 97 if (offset > 0) {
62 while (offset-- != 0) 98 while (offset-- != 0)
63 pos = pos->next; 99 pos = ui_browser__list_head_filter_entries(self, pos->next);
64 } else { 100 } else {
65 while (offset++ != 0) 101 while (offset++ != 0)
66 pos = pos->prev; 102 pos = ui_browser__list_head_filter_prev_entries(self, pos->prev);
67 } 103 }
68 104
69 self->top = pos; 105 self->top = pos;
@@ -127,41 +163,76 @@ bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
127 163
128void ui_browser__refresh_dimensions(struct ui_browser *self) 164void ui_browser__refresh_dimensions(struct ui_browser *self)
129{ 165{
130 int cols, rows; 166 self->width = SLtt_Screen_Cols - 1;
131 newtGetScreenSize(&cols, &rows); 167 self->height = SLtt_Screen_Rows - 2;
132
133 self->width = cols - 1;
134 self->height = rows - 2;
135 self->y = 1; 168 self->y = 1;
136 self->x = 0; 169 self->x = 0;
137} 170}
138 171
139void ui_browser__reset_index(struct ui_browser *self) 172void ui_browser__handle_resize(struct ui_browser *browser)
140{ 173{
141 self->index = self->top_idx = 0; 174 ui__refresh_dimensions(false);
142 self->seek(self, 0, SEEK_SET); 175 ui_browser__show(browser, browser->title, ui_helpline__current);
176 ui_browser__refresh(browser);
143} 177}
144 178
145void ui_browser__add_exit_key(struct ui_browser *self, int key) 179int ui_browser__warning(struct ui_browser *browser, int timeout,
180 const char *format, ...)
146{ 181{
147 newtFormAddHotKey(self->form, key); 182 va_list args;
183 char *text;
184 int key = 0, err;
185
186 va_start(args, format);
187 err = vasprintf(&text, format, args);
188 va_end(args);
189
190 if (err < 0) {
191 va_start(args, format);
192 ui_helpline__vpush(format, args);
193 va_end(args);
194 } else {
195 while ((key == ui__question_window("Warning!", text,
196 "Press any key...",
197 timeout)) == K_RESIZE)
198 ui_browser__handle_resize(browser);
199 free(text);
200 }
201
202 return key;
148} 203}
149 204
150void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]) 205int ui_browser__help_window(struct ui_browser *browser, const char *text)
151{ 206{
152 int i = 0; 207 int key;
153 208
154 while (keys[i] && i < 64) { 209 while ((key = ui__help_window(text)) == K_RESIZE)
155 ui_browser__add_exit_key(self, keys[i]); 210 ui_browser__handle_resize(browser);
156 ++i; 211
157 } 212 return key;
213}
214
215bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text)
216{
217 int key;
218
219 while ((key = ui__dialog_yesno(text)) == K_RESIZE)
220 ui_browser__handle_resize(browser);
221
222 return key == K_ENTER || toupper(key) == 'Y';
223}
224
225void ui_browser__reset_index(struct ui_browser *self)
226{
227 self->index = self->top_idx = 0;
228 self->seek(self, 0, SEEK_SET);
158} 229}
159 230
160void __ui_browser__show_title(struct ui_browser *browser, const char *title) 231void __ui_browser__show_title(struct ui_browser *browser, const char *title)
161{ 232{
162 SLsmg_gotorc(0, 0); 233 SLsmg_gotorc(0, 0);
163 ui_browser__set_color(browser, NEWT_COLORSET_ROOT); 234 ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
164 slsmg_write_nstring(title, browser->width); 235 slsmg_write_nstring(title, browser->width + 1);
165} 236}
166 237
167void ui_browser__show_title(struct ui_browser *browser, const char *title) 238void ui_browser__show_title(struct ui_browser *browser, const char *title)
@@ -174,78 +245,145 @@ void ui_browser__show_title(struct ui_browser *browser, const char *title)
174int ui_browser__show(struct ui_browser *self, const char *title, 245int ui_browser__show(struct ui_browser *self, const char *title,
175 const char *helpline, ...) 246 const char *helpline, ...)
176{ 247{
248 int err;
177 va_list ap; 249 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 250
185 ui_browser__refresh_dimensions(self); 251 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 252
196 pthread_mutex_lock(&ui__lock); 253 pthread_mutex_lock(&ui__lock);
197 __ui_browser__show_title(self, title); 254 __ui_browser__show_title(self, title);
198 255
199 ui_browser__add_exit_keys(self, keys); 256 self->title = title;
200 newtFormAddComponent(self->form, self->sb); 257 free(self->helpline);
258 self->helpline = NULL;
201 259
202 va_start(ap, helpline); 260 va_start(ap, helpline);
203 ui_helpline__vpush(helpline, ap); 261 err = vasprintf(&self->helpline, helpline, ap);
204 va_end(ap); 262 va_end(ap);
263 if (err > 0)
264 ui_helpline__push(self->helpline);
205 pthread_mutex_unlock(&ui__lock); 265 pthread_mutex_unlock(&ui__lock);
206 return 0; 266 return err ? 0 : -1;
207} 267}
208 268
209void ui_browser__hide(struct ui_browser *self) 269void ui_browser__hide(struct ui_browser *browser __used)
210{ 270{
211 pthread_mutex_lock(&ui__lock); 271 pthread_mutex_lock(&ui__lock);
212 newtFormDestroy(self->form);
213 self->form = NULL;
214 ui_helpline__pop(); 272 ui_helpline__pop();
215 pthread_mutex_unlock(&ui__lock); 273 pthread_mutex_unlock(&ui__lock);
216} 274}
217 275
218int ui_browser__refresh(struct ui_browser *self) 276static void ui_browser__scrollbar_set(struct ui_browser *browser)
277{
278 int height = browser->height, h = 0, pct = 0,
279 col = browser->width,
280 row = browser->y - 1;
281
282 if (browser->nr_entries > 1) {
283 pct = ((browser->index * (browser->height - 1)) /
284 (browser->nr_entries - 1));
285 }
286
287 SLsmg_set_char_set(1);
288
289 while (h < height) {
290 ui_browser__gotorc(browser, row++, col);
291 SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_CKBRD_CHAR);
292 ++h;
293 }
294
295 SLsmg_set_char_set(0);
296}
297
298static int __ui_browser__refresh(struct ui_browser *browser)
219{ 299{
220 int row; 300 int row;
301 int width = browser->width;
302
303 row = browser->refresh(browser);
304 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
305
306 if (!browser->use_navkeypressed || browser->navkeypressed)
307 ui_browser__scrollbar_set(browser);
308 else
309 width += 1;
310
311 SLsmg_fill_region(browser->y + row, browser->x,
312 browser->height - row, width, ' ');
313
314 return 0;
315}
221 316
317int ui_browser__refresh(struct ui_browser *browser)
318{
222 pthread_mutex_lock(&ui__lock); 319 pthread_mutex_lock(&ui__lock);
223 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); 320 __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); 321 pthread_mutex_unlock(&ui__lock);
229 322
230 return 0; 323 return 0;
231} 324}
232 325
233int ui_browser__run(struct ui_browser *self) 326/*
327 * Here we're updating nr_entries _after_ we started browsing, i.e. we have to
328 * forget about any reference to any entry in the underlying data structure,
329 * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser
330 * after an output_resort and hist decay.
331 */
332void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
234{ 333{
235 struct newtExitStruct es; 334 off_t offset = nr_entries - browser->nr_entries;
335
336 browser->nr_entries = nr_entries;
236 337
237 if (ui_browser__refresh(self) < 0) 338 if (offset < 0) {
238 return -1; 339 if (browser->top_idx < (u64)-offset)
340 offset = -browser->top_idx;
341
342 browser->index += offset;
343 browser->top_idx += offset;
344 }
345
346 browser->top = NULL;
347 browser->seek(browser, browser->top_idx, SEEK_SET);
348}
349
350int ui_browser__run(struct ui_browser *self, int delay_secs)
351{
352 int err, key;
239 353
240 while (1) { 354 while (1) {
241 off_t offset; 355 off_t offset;
242 356
243 newtFormRun(self->form, &es); 357 pthread_mutex_lock(&ui__lock);
244 358 err = __ui_browser__refresh(self);
245 if (es.reason != NEWT_EXIT_HOTKEY) 359 SLsmg_refresh();
360 pthread_mutex_unlock(&ui__lock);
361 if (err < 0)
246 break; 362 break;
247 switch (es.u.key) { 363
248 case NEWT_KEY_DOWN: 364 key = ui__getch(delay_secs);
365
366 if (key == K_RESIZE) {
367 ui__refresh_dimensions(false);
368 ui_browser__refresh_dimensions(self);
369 __ui_browser__show_title(self, self->title);
370 ui_helpline__puts(self->helpline);
371 continue;
372 }
373
374 if (self->use_navkeypressed && !self->navkeypressed) {
375 if (key == K_DOWN || key == K_UP ||
376 key == K_PGDN || key == K_PGUP ||
377 key == K_HOME || key == K_END ||
378 key == ' ') {
379 self->navkeypressed = true;
380 continue;
381 } else
382 return key;
383 }
384
385 switch (key) {
386 case K_DOWN:
249 if (self->index == self->nr_entries - 1) 387 if (self->index == self->nr_entries - 1)
250 break; 388 break;
251 ++self->index; 389 ++self->index;
@@ -254,7 +392,7 @@ int ui_browser__run(struct ui_browser *self)
254 self->seek(self, +1, SEEK_CUR); 392 self->seek(self, +1, SEEK_CUR);
255 } 393 }
256 break; 394 break;
257 case NEWT_KEY_UP: 395 case K_UP:
258 if (self->index == 0) 396 if (self->index == 0)
259 break; 397 break;
260 --self->index; 398 --self->index;
@@ -263,7 +401,7 @@ int ui_browser__run(struct ui_browser *self)
263 self->seek(self, -1, SEEK_CUR); 401 self->seek(self, -1, SEEK_CUR);
264 } 402 }
265 break; 403 break;
266 case NEWT_KEY_PGDN: 404 case K_PGDN:
267 case ' ': 405 case ' ':
268 if (self->top_idx + self->height > self->nr_entries - 1) 406 if (self->top_idx + self->height > self->nr_entries - 1)
269 break; 407 break;
@@ -275,7 +413,7 @@ int ui_browser__run(struct ui_browser *self)
275 self->top_idx += offset; 413 self->top_idx += offset;
276 self->seek(self, +offset, SEEK_CUR); 414 self->seek(self, +offset, SEEK_CUR);
277 break; 415 break;
278 case NEWT_KEY_PGUP: 416 case K_PGUP:
279 if (self->top_idx == 0) 417 if (self->top_idx == 0)
280 break; 418 break;
281 419
@@ -288,10 +426,10 @@ int ui_browser__run(struct ui_browser *self)
288 self->top_idx -= offset; 426 self->top_idx -= offset;
289 self->seek(self, -offset, SEEK_CUR); 427 self->seek(self, -offset, SEEK_CUR);
290 break; 428 break;
291 case NEWT_KEY_HOME: 429 case K_HOME:
292 ui_browser__reset_index(self); 430 ui_browser__reset_index(self);
293 break; 431 break;
294 case NEWT_KEY_END: 432 case K_END:
295 offset = self->height - 1; 433 offset = self->height - 1;
296 if (offset >= self->nr_entries) 434 if (offset >= self->nr_entries)
297 offset = self->nr_entries - 1; 435 offset = self->nr_entries - 1;
@@ -301,10 +439,8 @@ int ui_browser__run(struct ui_browser *self)
301 self->seek(self, -offset, SEEK_END); 439 self->seek(self, -offset, SEEK_END);
302 break; 440 break;
303 default: 441 default:
304 return es.u.key; 442 return key;
305 } 443 }
306 if (ui_browser__refresh(self) < 0)
307 return -1;
308 } 444 }
309 return -1; 445 return -1;
310} 446}
@@ -316,41 +452,146 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
316 int row = 0; 452 int row = 0;
317 453
318 if (self->top == NULL || self->top == self->entries) 454 if (self->top == NULL || self->top == self->entries)
319 self->top = head->next; 455 self->top = ui_browser__list_head_filter_entries(self, head->next);
320 456
321 pos = self->top; 457 pos = self->top;
322 458
323 list_for_each_from(pos, head) { 459 list_for_each_from(pos, head) {
324 ui_browser__gotorc(self, row, 0); 460 if (!self->filter || !self->filter(self, pos)) {
325 self->write(self, pos, row); 461 ui_browser__gotorc(self, row, 0);
326 if (++row == self->height) 462 self->write(self, pos, row);
327 break; 463 if (++row == self->height)
464 break;
465 }
328 } 466 }
329 467
330 return row; 468 return row;
331} 469}
332 470
333static struct newtPercentTreeColors { 471static struct ui_browser__colorset {
334 const char *topColorFg, *topColorBg; 472 const char *name, *fg, *bg;
335 const char *mediumColorFg, *mediumColorBg; 473 int colorset;
336 const char *normalColorFg, *normalColorBg; 474} ui_browser__colorsets[] = {
337 const char *selColorFg, *selColorBg; 475 {
338 const char *codeColorFg, *codeColorBg; 476 .colorset = HE_COLORSET_TOP,
339} defaultPercentTreeColors = { 477 .name = "top",
340 "red", "lightgray", 478 .fg = "red",
341 "green", "lightgray", 479 .bg = "default",
342 "black", "lightgray", 480 },
343 "lightgray", "magenta", 481 {
344 "blue", "lightgray", 482 .colorset = HE_COLORSET_MEDIUM,
483 .name = "medium",
484 .fg = "green",
485 .bg = "default",
486 },
487 {
488 .colorset = HE_COLORSET_NORMAL,
489 .name = "normal",
490 .fg = "default",
491 .bg = "default",
492 },
493 {
494 .colorset = HE_COLORSET_SELECTED,
495 .name = "selected",
496 .fg = "black",
497 .bg = "lightgray",
498 },
499 {
500 .colorset = HE_COLORSET_CODE,
501 .name = "code",
502 .fg = "blue",
503 .bg = "default",
504 },
505 {
506 .name = NULL,
507 }
345}; 508};
346 509
510
511static int ui_browser__color_config(const char *var, const char *value,
512 void *data __used)
513{
514 char *fg = NULL, *bg;
515 int i;
516
517 /* same dir for all commands */
518 if (prefixcmp(var, "colors.") != 0)
519 return 0;
520
521 for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) {
522 const char *name = var + 7;
523
524 if (strcmp(ui_browser__colorsets[i].name, name) != 0)
525 continue;
526
527 fg = strdup(value);
528 if (fg == NULL)
529 break;
530
531 bg = strchr(fg, ',');
532 if (bg == NULL)
533 break;
534
535 *bg = '\0';
536 while (isspace(*++bg));
537 ui_browser__colorsets[i].bg = bg;
538 ui_browser__colorsets[i].fg = fg;
539 return 0;
540 }
541
542 free(fg);
543 return -1;
544}
545
546void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence)
547{
548 switch (whence) {
549 case SEEK_SET:
550 browser->top = browser->entries;
551 break;
552 case SEEK_CUR:
553 browser->top = browser->top + browser->top_idx + offset;
554 break;
555 case SEEK_END:
556 browser->top = browser->top + browser->nr_entries + offset;
557 break;
558 default:
559 return;
560 }
561}
562
563unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
564{
565 unsigned int row = 0, idx = browser->top_idx;
566 char **pos;
567
568 if (browser->top == NULL)
569 browser->top = browser->entries;
570
571 pos = (char **)browser->top;
572 while (idx < browser->nr_entries) {
573 if (!browser->filter || !browser->filter(browser, *pos)) {
574 ui_browser__gotorc(browser, row, 0);
575 browser->write(browser, pos, row);
576 if (++row == browser->height)
577 break;
578 }
579
580 ++idx;
581 ++pos;
582 }
583
584 return row;
585}
586
347void ui_browser__init(void) 587void ui_browser__init(void)
348{ 588{
349 struct newtPercentTreeColors *c = &defaultPercentTreeColors; 589 int i = 0;
590
591 perf_config(ui_browser__color_config, NULL);
350 592
351 sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg); 593 while (ui_browser__colorsets[i].name) {
352 sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg); 594 struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
353 sltt_set_color(HE_COLORSET_NORMAL, NULL, c->normalColorFg, c->normalColorBg); 595 sltt_set_color(c->colorset, c->name, c->fg, c->bg);
354 sltt_set_color(HE_COLORSET_SELECTED, NULL, c->selColorFg, c->selColorBg); 596 }
355 sltt_set_color(HE_COLORSET_CODE, NULL, c->codeColorFg, c->codeColorBg);
356} 597}