~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to tools/perf/util/ui/browser.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "../util.h"
 
2
#include "../cache.h"
 
3
#include "../../perf.h"
 
4
#include "libslang.h"
 
5
#include <newt.h>
 
6
#include "ui.h"
 
7
#include "util.h"
 
8
#include <linux/compiler.h>
 
9
#include <linux/list.h>
 
10
#include <linux/rbtree.h>
 
11
#include <stdlib.h>
 
12
#include <sys/ttydefaults.h>
 
13
#include "browser.h"
 
14
#include "helpline.h"
 
15
#include "keysyms.h"
 
16
#include "../color.h"
 
17
 
 
18
static int ui_browser__percent_color(struct ui_browser *browser,
 
19
                                     double percent, bool current)
 
20
{
 
21
        if (current && (!browser->use_navkeypressed || browser->navkeypressed))
 
22
                return HE_COLORSET_SELECTED;
 
23
        if (percent >= MIN_RED)
 
24
                return HE_COLORSET_TOP;
 
25
        if (percent >= MIN_GREEN)
 
26
                return HE_COLORSET_MEDIUM;
 
27
        return HE_COLORSET_NORMAL;
 
28
}
 
29
 
 
30
void ui_browser__set_color(struct ui_browser *self __used, int color)
 
31
{
 
32
        SLsmg_set_color(color);
 
33
}
 
34
 
 
35
void ui_browser__set_percent_color(struct ui_browser *self,
 
36
                                   double percent, bool current)
 
37
{
 
38
         int color = ui_browser__percent_color(self, percent, current);
 
39
         ui_browser__set_color(self, color);
 
40
}
 
41
 
 
42
void ui_browser__gotorc(struct ui_browser *self, int y, int x)
 
43
{
 
44
        SLsmg_gotorc(self->y + y, self->x + x);
 
45
}
 
46
 
 
47
static struct list_head *
 
48
ui_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
 
 
60
static struct list_head *
 
61
ui_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
 
 
73
void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
 
74
{
 
75
        struct list_head *head = self->entries;
 
76
        struct list_head *pos;
 
77
 
 
78
        if (self->nr_entries == 0)
 
79
                return;
 
80
 
 
81
        switch (whence) {
 
82
        case SEEK_SET:
 
83
                pos = ui_browser__list_head_filter_entries(self, head->next);
 
84
                break;
 
85
        case SEEK_CUR:
 
86
                pos = self->top;
 
87
                break;
 
88
        case SEEK_END:
 
89
                pos = ui_browser__list_head_filter_prev_entries(self, head->prev);
 
90
                break;
 
91
        default:
 
92
                return;
 
93
        }
 
94
 
 
95
        assert(pos != NULL);
 
96
 
 
97
        if (offset > 0) {
 
98
                while (offset-- != 0)
 
99
                        pos = ui_browser__list_head_filter_entries(self, pos->next);
 
100
        } else {
 
101
                while (offset++ != 0)
 
102
                        pos = ui_browser__list_head_filter_prev_entries(self, pos->prev);
 
103
        }
 
104
 
 
105
        self->top = pos;
 
106
}
 
107
 
 
108
void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence)
 
109
{
 
110
        struct rb_root *root = self->entries;
 
111
        struct rb_node *nd;
 
112
 
 
113
        switch (whence) {
 
114
        case SEEK_SET:
 
115
                nd = rb_first(root);
 
116
                break;
 
117
        case SEEK_CUR:
 
118
                nd = self->top;
 
119
                break;
 
120
        case SEEK_END:
 
121
                nd = rb_last(root);
 
122
                break;
 
123
        default:
 
124
                return;
 
125
        }
 
126
 
 
127
        if (offset > 0) {
 
128
                while (offset-- != 0)
 
129
                        nd = rb_next(nd);
 
130
        } else {
 
131
                while (offset++ != 0)
 
132
                        nd = rb_prev(nd);
 
133
        }
 
134
 
 
135
        self->top = nd;
 
136
}
 
137
 
 
138
unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self)
 
139
{
 
140
        struct rb_node *nd;
 
141
        int row = 0;
 
142
 
 
143
        if (self->top == NULL)
 
144
                self->top = rb_first(self->entries);
 
145
 
 
146
        nd = self->top;
 
147
 
 
148
        while (nd != NULL) {
 
149
                ui_browser__gotorc(self, row, 0);
 
150
                self->write(self, nd, row);
 
151
                if (++row == self->height)
 
152
                        break;
 
153
                nd = rb_next(nd);
 
154
        }
 
155
 
 
156
        return row;
 
157
}
 
158
 
 
159
bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
 
160
{
 
161
        return self->top_idx + row == self->index;
 
162
}
 
163
 
 
164
void ui_browser__refresh_dimensions(struct ui_browser *self)
 
165
{
 
166
        self->width = SLtt_Screen_Cols - 1;
 
167
        self->height = SLtt_Screen_Rows - 2;
 
168
        self->y = 1;
 
169
        self->x = 0;
 
170
}
 
171
 
 
172
void ui_browser__handle_resize(struct ui_browser *browser)
 
173
{
 
174
        ui__refresh_dimensions(false);
 
175
        ui_browser__show(browser, browser->title, ui_helpline__current);
 
176
        ui_browser__refresh(browser);
 
177
}
 
178
 
 
179
int ui_browser__warning(struct ui_browser *browser, int timeout,
 
180
                        const char *format, ...)
 
181
{
 
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;
 
203
}
 
204
 
 
205
int ui_browser__help_window(struct ui_browser *browser, const char *text)
 
206
{
 
207
        int key;
 
208
 
 
209
        while ((key = ui__help_window(text)) == K_RESIZE)
 
210
                ui_browser__handle_resize(browser);
 
211
 
 
212
        return key;
 
213
}
 
214
 
 
215
bool 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
 
 
225
void ui_browser__reset_index(struct ui_browser *self)
 
226
{
 
227
        self->index = self->top_idx = 0;
 
228
        self->seek(self, 0, SEEK_SET);
 
229
}
 
230
 
 
231
void __ui_browser__show_title(struct ui_browser *browser, const char *title)
 
232
{
 
233
        SLsmg_gotorc(0, 0);
 
234
        ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
 
235
        slsmg_write_nstring(title, browser->width + 1);
 
236
}
 
237
 
 
238
void ui_browser__show_title(struct ui_browser *browser, const char *title)
 
239
{
 
240
        pthread_mutex_lock(&ui__lock);
 
241
        __ui_browser__show_title(browser, title);
 
242
        pthread_mutex_unlock(&ui__lock);
 
243
}
 
244
 
 
245
int ui_browser__show(struct ui_browser *self, const char *title,
 
246
                     const char *helpline, ...)
 
247
{
 
248
        int err;
 
249
        va_list ap;
 
250
 
 
251
        ui_browser__refresh_dimensions(self);
 
252
 
 
253
        pthread_mutex_lock(&ui__lock);
 
254
        __ui_browser__show_title(self, title);
 
255
 
 
256
        self->title = title;
 
257
        free(self->helpline);
 
258
        self->helpline = NULL;
 
259
 
 
260
        va_start(ap, helpline);
 
261
        err = vasprintf(&self->helpline, helpline, ap);
 
262
        va_end(ap);
 
263
        if (err > 0)
 
264
                ui_helpline__push(self->helpline);
 
265
        pthread_mutex_unlock(&ui__lock);
 
266
        return err ? 0 : -1;
 
267
}
 
268
 
 
269
void ui_browser__hide(struct ui_browser *browser __used)
 
270
{
 
271
        pthread_mutex_lock(&ui__lock);
 
272
        ui_helpline__pop();
 
273
        pthread_mutex_unlock(&ui__lock);
 
274
}
 
275
 
 
276
static 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
 
 
298
static int __ui_browser__refresh(struct ui_browser *browser)
 
299
{
 
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
}
 
316
 
 
317
int ui_browser__refresh(struct ui_browser *browser)
 
318
{
 
319
        pthread_mutex_lock(&ui__lock);
 
320
        __ui_browser__refresh(browser);
 
321
        pthread_mutex_unlock(&ui__lock);
 
322
 
 
323
        return 0;
 
324
}
 
325
 
 
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
 */
 
332
void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
 
333
{
 
334
        off_t offset = nr_entries - browser->nr_entries;
 
335
 
 
336
        browser->nr_entries = nr_entries;
 
337
 
 
338
        if (offset < 0) {
 
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
 
 
350
int ui_browser__run(struct ui_browser *self, int delay_secs)
 
351
{
 
352
        int err, key;
 
353
 
 
354
        while (1) {
 
355
                off_t offset;
 
356
 
 
357
                pthread_mutex_lock(&ui__lock);
 
358
                err = __ui_browser__refresh(self);
 
359
                SLsmg_refresh();
 
360
                pthread_mutex_unlock(&ui__lock);
 
361
                if (err < 0)
 
362
                        break;
 
363
 
 
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:
 
387
                        if (self->index == self->nr_entries - 1)
 
388
                                break;
 
389
                        ++self->index;
 
390
                        if (self->index == self->top_idx + self->height) {
 
391
                                ++self->top_idx;
 
392
                                self->seek(self, +1, SEEK_CUR);
 
393
                        }
 
394
                        break;
 
395
                case K_UP:
 
396
                        if (self->index == 0)
 
397
                                break;
 
398
                        --self->index;
 
399
                        if (self->index < self->top_idx) {
 
400
                                --self->top_idx;
 
401
                                self->seek(self, -1, SEEK_CUR);
 
402
                        }
 
403
                        break;
 
404
                case K_PGDN:
 
405
                case ' ':
 
406
                        if (self->top_idx + self->height > self->nr_entries - 1)
 
407
                                break;
 
408
 
 
409
                        offset = self->height;
 
410
                        if (self->index + offset > self->nr_entries - 1)
 
411
                                offset = self->nr_entries - 1 - self->index;
 
412
                        self->index += offset;
 
413
                        self->top_idx += offset;
 
414
                        self->seek(self, +offset, SEEK_CUR);
 
415
                        break;
 
416
                case K_PGUP:
 
417
                        if (self->top_idx == 0)
 
418
                                break;
 
419
 
 
420
                        if (self->top_idx < self->height)
 
421
                                offset = self->top_idx;
 
422
                        else
 
423
                                offset = self->height;
 
424
 
 
425
                        self->index -= offset;
 
426
                        self->top_idx -= offset;
 
427
                        self->seek(self, -offset, SEEK_CUR);
 
428
                        break;
 
429
                case K_HOME:
 
430
                        ui_browser__reset_index(self);
 
431
                        break;
 
432
                case K_END:
 
433
                        offset = self->height - 1;
 
434
                        if (offset >= self->nr_entries)
 
435
                                offset = self->nr_entries - 1;
 
436
 
 
437
                        self->index = self->nr_entries - 1;
 
438
                        self->top_idx = self->index - offset;
 
439
                        self->seek(self, -offset, SEEK_END);
 
440
                        break;
 
441
                default:
 
442
                        return key;
 
443
                }
 
444
        }
 
445
        return -1;
 
446
}
 
447
 
 
448
unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
 
449
{
 
450
        struct list_head *pos;
 
451
        struct list_head *head = self->entries;
 
452
        int row = 0;
 
453
 
 
454
        if (self->top == NULL || self->top == self->entries)
 
455
                self->top = ui_browser__list_head_filter_entries(self, head->next);
 
456
 
 
457
        pos = self->top;
 
458
 
 
459
        list_for_each_from(pos, head) {
 
460
                if (!self->filter || !self->filter(self, pos)) {
 
461
                        ui_browser__gotorc(self, row, 0);
 
462
                        self->write(self, pos, row);
 
463
                        if (++row == self->height)
 
464
                                break;
 
465
                }
 
466
        }
 
467
 
 
468
        return row;
 
469
}
 
470
 
 
471
static struct ui_browser__colorset {
 
472
        const char *name, *fg, *bg;
 
473
        int colorset;
 
474
} ui_browser__colorsets[] = {
 
475
        {
 
476
                .colorset = HE_COLORSET_TOP,
 
477
                .name     = "top",
 
478
                .fg       = "red",
 
479
                .bg       = "default",
 
480
        },
 
481
        {
 
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
        }
 
508
};
 
509
 
 
510
 
 
511
static 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
 
 
546
void 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
 
 
563
unsigned 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
 
 
587
void ui_browser__init(void)
 
588
{
 
589
        int i = 0;
 
590
 
 
591
        perf_config(ui_browser__color_config, NULL);
 
592
 
 
593
        while (ui_browser__colorsets[i].name) {
 
594
                struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
 
595
                sltt_set_color(c->colorset, c->name, c->fg, c->bg);
 
596
        }
 
597
}