diff options
author | Ingo Molnar <mingo@elte.hu> | 2011-10-15 10:57:48 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-10-15 10:57:48 -0400 |
commit | c73a3cb356f94b443aa7624b539493191dbf44c1 (patch) | |
tree | a813dbd5e3e2cf77ce33729e07f6fda3a819e3bb /tools/perf | |
parent | 910e94dd0cc5abacebf0bd5ffd859f61b9583857 (diff) | |
parent | 6c3c5b26d08569ed80e10d3e02d3c997ed1e6e7c (diff) |
Merge branch 'perf/core' of git://github.com/acmel/linux into perf/core
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/builtin-top.c | 25 | ||||
-rw-r--r-- | tools/perf/perf.c | 24 | ||||
-rw-r--r-- | tools/perf/perf.h | 2 | ||||
-rw-r--r-- | tools/perf/util/header.c | 2 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 24 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 11 | ||||
-rw-r--r-- | tools/perf/util/sort.h | 1 | ||||
-rw-r--r-- | tools/perf/util/ui/browser.c | 228 | ||||
-rw-r--r-- | tools/perf/util/ui/browser.h | 10 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/annotate.c | 95 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/hists.c | 110 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/map.c | 6 | ||||
-rw-r--r-- | tools/perf/util/ui/helpline.h | 2 |
13 files changed, 375 insertions, 165 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c5aebf6eb746..e211304a0dd7 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -304,7 +304,7 @@ static void print_sym_table(void) | |||
304 | 304 | ||
305 | hists__collapse_resort_threaded(&top.sym_evsel->hists); | 305 | hists__collapse_resort_threaded(&top.sym_evsel->hists); |
306 | hists__output_resort_threaded(&top.sym_evsel->hists); | 306 | hists__output_resort_threaded(&top.sym_evsel->hists); |
307 | hists__decay_entries(&top.sym_evsel->hists); | 307 | hists__decay_entries_threaded(&top.sym_evsel->hists); |
308 | hists__output_recalc_col_len(&top.sym_evsel->hists, winsize.ws_row - 3); | 308 | hists__output_recalc_col_len(&top.sym_evsel->hists, winsize.ws_row - 3); |
309 | putchar('\n'); | 309 | putchar('\n'); |
310 | hists__fprintf(&top.sym_evsel->hists, NULL, false, false, | 310 | hists__fprintf(&top.sym_evsel->hists, NULL, false, false, |
@@ -555,7 +555,7 @@ static void perf_top__sort_new_samples(void *arg) | |||
555 | 555 | ||
556 | hists__collapse_resort_threaded(&t->sym_evsel->hists); | 556 | hists__collapse_resort_threaded(&t->sym_evsel->hists); |
557 | hists__output_resort_threaded(&t->sym_evsel->hists); | 557 | hists__output_resort_threaded(&t->sym_evsel->hists); |
558 | hists__decay_entries(&t->sym_evsel->hists); | 558 | hists__decay_entries_threaded(&t->sym_evsel->hists); |
559 | hists__output_recalc_col_len(&t->sym_evsel->hists, winsize.ws_row - 3); | 559 | hists__output_recalc_col_len(&t->sym_evsel->hists, winsize.ws_row - 3); |
560 | } | 560 | } |
561 | 561 | ||
@@ -585,16 +585,31 @@ static void *display_thread(void *arg __used) | |||
585 | tc.c_cc[VMIN] = 0; | 585 | tc.c_cc[VMIN] = 0; |
586 | tc.c_cc[VTIME] = 0; | 586 | tc.c_cc[VTIME] = 0; |
587 | 587 | ||
588 | pthread__unblock_sigwinch(); | ||
588 | repeat: | 589 | repeat: |
589 | delay_msecs = top.delay_secs * 1000; | 590 | delay_msecs = top.delay_secs * 1000; |
590 | tcsetattr(0, TCSANOW, &tc); | 591 | tcsetattr(0, TCSANOW, &tc); |
591 | /* trash return*/ | 592 | /* trash return*/ |
592 | getc(stdin); | 593 | getc(stdin); |
593 | 594 | ||
594 | do { | 595 | while (1) { |
595 | print_sym_table(); | 596 | print_sym_table(); |
596 | } while (!poll(&stdin_poll, 1, delay_msecs) == 1); | 597 | /* |
597 | 598 | * Either timeout expired or we got an EINTR due to SIGWINCH, | |
599 | * refresh screen in both cases. | ||
600 | */ | ||
601 | switch (poll(&stdin_poll, 1, delay_msecs)) { | ||
602 | case 0: | ||
603 | continue; | ||
604 | case -1: | ||
605 | if (errno == EINTR) | ||
606 | continue; | ||
607 | /* Fall trhu */ | ||
608 | default: | ||
609 | goto process_hotkey; | ||
610 | } | ||
611 | } | ||
612 | process_hotkey: | ||
598 | c = getc(stdin); | 613 | c = getc(stdin); |
599 | tcsetattr(0, TCSAFLUSH, &save); | 614 | tcsetattr(0, TCSAFLUSH, &save); |
600 | 615 | ||
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index ec635b7cc8ea..73d0cac8b67e 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -427,6 +427,24 @@ static void get_debugfs_mntpt(void) | |||
427 | debugfs_mntpt[0] = '\0'; | 427 | debugfs_mntpt[0] = '\0'; |
428 | } | 428 | } |
429 | 429 | ||
430 | static void pthread__block_sigwinch(void) | ||
431 | { | ||
432 | sigset_t set; | ||
433 | |||
434 | sigemptyset(&set); | ||
435 | sigaddset(&set, SIGWINCH); | ||
436 | pthread_sigmask(SIG_BLOCK, &set, NULL); | ||
437 | } | ||
438 | |||
439 | void pthread__unblock_sigwinch(void) | ||
440 | { | ||
441 | sigset_t set; | ||
442 | |||
443 | sigemptyset(&set); | ||
444 | sigaddset(&set, SIGWINCH); | ||
445 | pthread_sigmask(SIG_UNBLOCK, &set, NULL); | ||
446 | } | ||
447 | |||
430 | int main(int argc, const char **argv) | 448 | int main(int argc, const char **argv) |
431 | { | 449 | { |
432 | const char *cmd; | 450 | const char *cmd; |
@@ -480,6 +498,12 @@ int main(int argc, const char **argv) | |||
480 | * time. | 498 | * time. |
481 | */ | 499 | */ |
482 | setup_path(); | 500 | setup_path(); |
501 | /* | ||
502 | * Block SIGWINCH notifications so that the thread that wants it can | ||
503 | * unblock and get syscalls like select interrupted instead of waiting | ||
504 | * forever while the signal goes to some other non interested thread. | ||
505 | */ | ||
506 | pthread__block_sigwinch(); | ||
483 | 507 | ||
484 | while (1) { | 508 | while (1) { |
485 | static int done_help; | 509 | static int done_help; |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 08b0b5e82a44..914c895510f7 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -183,4 +183,6 @@ struct ip_callchain { | |||
183 | extern bool perf_host, perf_guest; | 183 | extern bool perf_host, perf_guest; |
184 | extern const char perf_version_string[]; | 184 | extern const char perf_version_string[]; |
185 | 185 | ||
186 | void pthread__unblock_sigwinch(void); | ||
187 | |||
186 | #endif | 188 | #endif |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index f2ceb0f7d669..2143a32638c2 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -1289,7 +1289,7 @@ int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) | |||
1289 | if (access(linkname, F_OK)) | 1289 | if (access(linkname, F_OK)) |
1290 | goto out_free; | 1290 | goto out_free; |
1291 | 1291 | ||
1292 | if (readlink(linkname, filename, size) < 0) | 1292 | if (readlink(linkname, filename, size - 1) < 0) |
1293 | goto out_free; | 1293 | goto out_free; |
1294 | 1294 | ||
1295 | if (unlink(linkname)) | 1295 | if (unlink(linkname)) |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 50c8fece1681..a7193c5a0422 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -100,13 +100,15 @@ static void hist_entry__decay(struct hist_entry *he) | |||
100 | 100 | ||
101 | static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) | 101 | static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) |
102 | { | 102 | { |
103 | if (he->period == 0) | ||
104 | return true; | ||
103 | hists->stats.total_period -= he->period; | 105 | hists->stats.total_period -= he->period; |
104 | hist_entry__decay(he); | 106 | hist_entry__decay(he); |
105 | hists->stats.total_period += he->period; | 107 | hists->stats.total_period += he->period; |
106 | return he->period == 0; | 108 | return he->period == 0; |
107 | } | 109 | } |
108 | 110 | ||
109 | void hists__decay_entries(struct hists *hists) | 111 | static void __hists__decay_entries(struct hists *hists, bool threaded) |
110 | { | 112 | { |
111 | struct rb_node *next = rb_first(&hists->entries); | 113 | struct rb_node *next = rb_first(&hists->entries); |
112 | struct hist_entry *n; | 114 | struct hist_entry *n; |
@@ -114,11 +116,15 @@ void hists__decay_entries(struct hists *hists) | |||
114 | while (next) { | 116 | while (next) { |
115 | n = rb_entry(next, struct hist_entry, rb_node); | 117 | n = rb_entry(next, struct hist_entry, rb_node); |
116 | next = rb_next(&n->rb_node); | 118 | next = rb_next(&n->rb_node); |
117 | 119 | /* | |
118 | if (hists__decay_entry(hists, n)) { | 120 | * We may be annotating this, for instance, so keep it here in |
121 | * case some it gets new samples, we'll eventually free it when | ||
122 | * the user stops browsing and it agains gets fully decayed. | ||
123 | */ | ||
124 | if (hists__decay_entry(hists, n) && !n->used) { | ||
119 | rb_erase(&n->rb_node, &hists->entries); | 125 | rb_erase(&n->rb_node, &hists->entries); |
120 | 126 | ||
121 | if (sort__need_collapse) | 127 | if (sort__need_collapse || threaded) |
122 | rb_erase(&n->rb_node_in, &hists->entries_collapsed); | 128 | rb_erase(&n->rb_node_in, &hists->entries_collapsed); |
123 | 129 | ||
124 | hist_entry__free(n); | 130 | hist_entry__free(n); |
@@ -127,6 +133,16 @@ void hists__decay_entries(struct hists *hists) | |||
127 | } | 133 | } |
128 | } | 134 | } |
129 | 135 | ||
136 | void hists__decay_entries(struct hists *hists) | ||
137 | { | ||
138 | return __hists__decay_entries(hists, false); | ||
139 | } | ||
140 | |||
141 | void hists__decay_entries_threaded(struct hists *hists) | ||
142 | { | ||
143 | return __hists__decay_entries(hists, true); | ||
144 | } | ||
145 | |||
130 | /* | 146 | /* |
131 | * histogram, sorted on item, collects periods | 147 | * histogram, sorted on item, collects periods |
132 | */ | 148 | */ |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 7ea1e560e008..bcc8ab91e26f 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -79,6 +79,7 @@ void hists__collapse_resort(struct hists *self); | |||
79 | void hists__collapse_resort_threaded(struct hists *hists); | 79 | void hists__collapse_resort_threaded(struct hists *hists); |
80 | 80 | ||
81 | void hists__decay_entries(struct hists *hists); | 81 | void hists__decay_entries(struct hists *hists); |
82 | void hists__decay_entries_threaded(struct hists *hists); | ||
82 | void hists__output_recalc_col_len(struct hists *hists, int max_rows); | 83 | void hists__output_recalc_col_len(struct hists *hists, int max_rows); |
83 | 84 | ||
84 | void hists__inc_nr_events(struct hists *self, u32 type); | 85 | void hists__inc_nr_events(struct hists *self, u32 type); |
@@ -103,16 +104,20 @@ struct perf_evlist; | |||
103 | #ifdef NO_NEWT_SUPPORT | 104 | #ifdef NO_NEWT_SUPPORT |
104 | static inline | 105 | static inline |
105 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used, | 106 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used, |
106 | const char *help __used, void(*timer)(void *arg) __used, void *arg, | 107 | const char *help __used, |
108 | void(*timer)(void *arg) __used, | ||
109 | void *arg __used, | ||
107 | int refresh __used) | 110 | int refresh __used) |
108 | { | 111 | { |
109 | return 0; | 112 | return 0; |
110 | } | 113 | } |
111 | 114 | ||
112 | static inline int hist_entry__tui_annotate(struct hist_entry *self __used, | 115 | static inline int hist_entry__tui_annotate(struct hist_entry *self __used, |
113 | int evidx __used, int nr_events __used, | 116 | int evidx __used, |
117 | int nr_events __used, | ||
114 | void(*timer)(void *arg) __used, | 118 | void(*timer)(void *arg) __used, |
115 | void *arg __used, int delay_secs __used); | 119 | void *arg __used, |
120 | int delay_secs __used) | ||
116 | { | 121 | { |
117 | return 0; | 122 | return 0; |
118 | } | 123 | } |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 03851e301721..3f67ae395752 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -64,6 +64,7 @@ struct hist_entry { | |||
64 | 64 | ||
65 | bool init_have_children; | 65 | bool init_have_children; |
66 | char level; | 66 | char level; |
67 | bool used; | ||
67 | u8 filtered; | 68 | u8 filtered; |
68 | struct symbol *parent; | 69 | struct symbol *parent; |
69 | union { | 70 | union { |
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); |
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h index fc63dda10910..351c006dd4b5 100644 --- a/tools/perf/util/ui/browser.h +++ b/tools/perf/util/ui/browser.h | |||
@@ -2,7 +2,6 @@ | |||
2 | #define _PERF_UI_BROWSER_H_ 1 | 2 | #define _PERF_UI_BROWSER_H_ 1 |
3 | 3 | ||
4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
5 | #include <newt.h> | ||
6 | #include <sys/types.h> | 5 | #include <sys/types.h> |
7 | #include "../types.h" | 6 | #include "../types.h" |
8 | 7 | ||
@@ -13,14 +12,16 @@ | |||
13 | #define HE_COLORSET_CODE 54 | 12 | #define HE_COLORSET_CODE 54 |
14 | 13 | ||
15 | struct ui_browser { | 14 | struct ui_browser { |
16 | newtComponent form, sb; | ||
17 | u64 index, top_idx; | 15 | u64 index, top_idx; |
18 | void *top, *entries; | 16 | void *top, *entries; |
19 | u16 y, x, width, height; | 17 | u16 y, x, width, height; |
20 | void *priv; | 18 | void *priv; |
19 | const char *title; | ||
20 | char *helpline; | ||
21 | unsigned int (*refresh)(struct ui_browser *self); | 21 | unsigned int (*refresh)(struct ui_browser *self); |
22 | void (*write)(struct ui_browser *self, void *entry, int row); | 22 | void (*write)(struct ui_browser *self, void *entry, int row); |
23 | void (*seek)(struct ui_browser *self, off_t offset, int whence); | 23 | void (*seek)(struct ui_browser *self, off_t offset, int whence); |
24 | bool (*filter)(struct ui_browser *self, void *entry); | ||
24 | u32 nr_entries; | 25 | u32 nr_entries; |
25 | }; | 26 | }; |
26 | 27 | ||
@@ -32,15 +33,14 @@ void ui_browser__refresh_dimensions(struct ui_browser *self); | |||
32 | void ui_browser__reset_index(struct ui_browser *self); | 33 | void ui_browser__reset_index(struct ui_browser *self); |
33 | 34 | ||
34 | void ui_browser__gotorc(struct ui_browser *self, int y, int x); | 35 | void ui_browser__gotorc(struct ui_browser *self, int y, int x); |
35 | void ui_browser__add_exit_key(struct ui_browser *self, int key); | ||
36 | void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]); | ||
37 | void __ui_browser__show_title(struct ui_browser *browser, const char *title); | 36 | void __ui_browser__show_title(struct ui_browser *browser, const char *title); |
38 | void ui_browser__show_title(struct ui_browser *browser, const char *title); | 37 | void ui_browser__show_title(struct ui_browser *browser, const char *title); |
39 | int ui_browser__show(struct ui_browser *self, const char *title, | 38 | int ui_browser__show(struct ui_browser *self, const char *title, |
40 | const char *helpline, ...); | 39 | const char *helpline, ...); |
41 | void ui_browser__hide(struct ui_browser *self); | 40 | void ui_browser__hide(struct ui_browser *self); |
42 | int ui_browser__refresh(struct ui_browser *self); | 41 | int ui_browser__refresh(struct ui_browser *self); |
43 | int ui_browser__run(struct ui_browser *self); | 42 | int ui_browser__run(struct ui_browser *browser, int delay_secs); |
43 | void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries); | ||
44 | 44 | ||
45 | void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); | 45 | void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); |
46 | unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self); | 46 | unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self); |
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 674b55e686fd..eb2712ecb601 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c | |||
@@ -21,12 +21,16 @@ struct annotate_browser { | |||
21 | struct rb_root entries; | 21 | struct rb_root entries; |
22 | struct rb_node *curr_hot; | 22 | struct rb_node *curr_hot; |
23 | struct objdump_line *selection; | 23 | struct objdump_line *selection; |
24 | int nr_asm_entries; | ||
25 | int nr_entries; | ||
26 | bool hide_src_code; | ||
24 | }; | 27 | }; |
25 | 28 | ||
26 | struct objdump_line_rb_node { | 29 | struct objdump_line_rb_node { |
27 | struct rb_node rb_node; | 30 | struct rb_node rb_node; |
28 | double percent; | 31 | double percent; |
29 | u32 idx; | 32 | u32 idx; |
33 | int idx_asm; | ||
30 | }; | 34 | }; |
31 | 35 | ||
32 | static inline | 36 | static inline |
@@ -35,10 +39,22 @@ struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self) | |||
35 | return (struct objdump_line_rb_node *)(self + 1); | 39 | return (struct objdump_line_rb_node *)(self + 1); |
36 | } | 40 | } |
37 | 41 | ||
42 | static bool objdump_line__filter(struct ui_browser *browser, void *entry) | ||
43 | { | ||
44 | struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); | ||
45 | |||
46 | if (ab->hide_src_code) { | ||
47 | struct objdump_line *ol = list_entry(entry, struct objdump_line, node); | ||
48 | return ol->offset == -1; | ||
49 | } | ||
50 | |||
51 | return false; | ||
52 | } | ||
53 | |||
38 | static void annotate_browser__write(struct ui_browser *self, void *entry, int row) | 54 | static void annotate_browser__write(struct ui_browser *self, void *entry, int row) |
39 | { | 55 | { |
40 | struct annotate_browser *ab = container_of(self, struct annotate_browser, b); | 56 | struct annotate_browser *ab = container_of(self, struct annotate_browser, b); |
41 | struct objdump_line *ol = rb_entry(entry, struct objdump_line, node); | 57 | struct objdump_line *ol = list_entry(entry, struct objdump_line, node); |
42 | bool current_entry = ui_browser__is_current_entry(self, row); | 58 | bool current_entry = ui_browser__is_current_entry(self, row); |
43 | int width = self->width; | 59 | int width = self->width; |
44 | 60 | ||
@@ -168,6 +184,45 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, | |||
168 | browser->curr_hot = rb_last(&browser->entries); | 184 | browser->curr_hot = rb_last(&browser->entries); |
169 | } | 185 | } |
170 | 186 | ||
187 | static bool annotate_browser__toggle_source(struct annotate_browser *browser) | ||
188 | { | ||
189 | struct objdump_line *ol; | ||
190 | struct objdump_line_rb_node *olrb; | ||
191 | off_t offset = browser->b.index - browser->b.top_idx; | ||
192 | |||
193 | browser->b.seek(&browser->b, offset, SEEK_CUR); | ||
194 | ol = list_entry(browser->b.top, struct objdump_line, node); | ||
195 | olrb = objdump_line__rb(ol); | ||
196 | |||
197 | if (browser->hide_src_code) { | ||
198 | if (olrb->idx_asm < offset) | ||
199 | offset = olrb->idx; | ||
200 | |||
201 | browser->b.nr_entries = browser->nr_entries; | ||
202 | browser->hide_src_code = false; | ||
203 | browser->b.seek(&browser->b, -offset, SEEK_CUR); | ||
204 | browser->b.top_idx = olrb->idx - offset; | ||
205 | browser->b.index = olrb->idx; | ||
206 | } else { | ||
207 | if (olrb->idx_asm < 0) { | ||
208 | ui_helpline__puts("Only available for assembly lines."); | ||
209 | browser->b.seek(&browser->b, -offset, SEEK_CUR); | ||
210 | return false; | ||
211 | } | ||
212 | |||
213 | if (olrb->idx_asm < offset) | ||
214 | offset = olrb->idx_asm; | ||
215 | |||
216 | browser->b.nr_entries = browser->nr_asm_entries; | ||
217 | browser->hide_src_code = true; | ||
218 | browser->b.seek(&browser->b, -offset, SEEK_CUR); | ||
219 | browser->b.top_idx = olrb->idx_asm - offset; | ||
220 | browser->b.index = olrb->idx_asm; | ||
221 | } | ||
222 | |||
223 | return true; | ||
224 | } | ||
225 | |||
171 | static int annotate_browser__run(struct annotate_browser *self, int evidx, | 226 | static int annotate_browser__run(struct annotate_browser *self, int evidx, |
172 | int nr_events, void(*timer)(void *arg), | 227 | int nr_events, void(*timer)(void *arg), |
173 | void *arg, int delay_secs) | 228 | void *arg, int delay_secs) |
@@ -175,20 +230,14 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, | |||
175 | struct rb_node *nd = NULL; | 230 | struct rb_node *nd = NULL; |
176 | struct map_symbol *ms = self->b.priv; | 231 | struct map_symbol *ms = self->b.priv; |
177 | struct symbol *sym = ms->sym; | 232 | struct symbol *sym = ms->sym; |
178 | /* | 233 | const char *help = "<-, ESC: exit, TAB/shift+TAB: cycle hottest lines, " |
179 | * RIGHT To allow builtin-annotate to cycle thru multiple symbols by | 234 | "H: Hottest, -> Line action, S -> Toggle source " |
180 | * examining the exit key for this function. | 235 | "code view"; |
181 | */ | ||
182 | int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB, | ||
183 | NEWT_KEY_RIGHT, NEWT_KEY_ENTER, 0 }; | ||
184 | int key; | 236 | int key; |
185 | 237 | ||
186 | if (ui_browser__show(&self->b, sym->name, | 238 | if (ui_browser__show(&self->b, sym->name, help) < 0) |
187 | "<- or ESC: exit, TAB/shift+TAB: " | ||
188 | "cycle hottest lines, H: Hottest, -> Line action") < 0) | ||
189 | return -1; | 239 | return -1; |
190 | 240 | ||
191 | ui_browser__add_exit_keys(&self->b, exit_keys); | ||
192 | annotate_browser__calc_percent(self, evidx); | 241 | annotate_browser__calc_percent(self, evidx); |
193 | 242 | ||
194 | if (self->curr_hot) | 243 | if (self->curr_hot) |
@@ -196,11 +245,8 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, | |||
196 | 245 | ||
197 | nd = self->curr_hot; | 246 | nd = self->curr_hot; |
198 | 247 | ||
199 | if (delay_secs != 0) | ||
200 | newtFormSetTimer(self->b.form, delay_secs * 1000); | ||
201 | |||
202 | while (1) { | 248 | while (1) { |
203 | key = ui_browser__run(&self->b); | 249 | key = ui_browser__run(&self->b, delay_secs); |
204 | 250 | ||
205 | if (delay_secs != 0) { | 251 | if (delay_secs != 0) { |
206 | annotate_browser__calc_percent(self, evidx); | 252 | annotate_browser__calc_percent(self, evidx); |
@@ -244,6 +290,10 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, | |||
244 | case 'H': | 290 | case 'H': |
245 | nd = self->curr_hot; | 291 | nd = self->curr_hot; |
246 | break; | 292 | break; |
293 | case 'S': | ||
294 | if (annotate_browser__toggle_source(self)) | ||
295 | ui_helpline__puts(help); | ||
296 | continue; | ||
247 | case NEWT_KEY_ENTER: | 297 | case NEWT_KEY_ENTER: |
248 | case NEWT_KEY_RIGHT: | 298 | case NEWT_KEY_RIGHT: |
249 | if (self->selection == NULL) { | 299 | if (self->selection == NULL) { |
@@ -295,8 +345,13 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, | |||
295 | timer, arg, delay_secs); | 345 | timer, arg, delay_secs); |
296 | } | 346 | } |
297 | break; | 347 | break; |
298 | default: | 348 | case NEWT_KEY_LEFT: |
349 | case NEWT_KEY_ESCAPE: | ||
350 | case 'q': | ||
351 | case CTRL('c'): | ||
299 | goto out; | 352 | goto out; |
353 | default: | ||
354 | continue; | ||
300 | } | 355 | } |
301 | 356 | ||
302 | if (nd != NULL) | 357 | if (nd != NULL) |
@@ -329,6 +384,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | |||
329 | .refresh = ui_browser__list_head_refresh, | 384 | .refresh = ui_browser__list_head_refresh, |
330 | .seek = ui_browser__list_head_seek, | 385 | .seek = ui_browser__list_head_seek, |
331 | .write = annotate_browser__write, | 386 | .write = annotate_browser__write, |
387 | .filter = objdump_line__filter, | ||
332 | .priv = &ms, | 388 | .priv = &ms, |
333 | }, | 389 | }, |
334 | }; | 390 | }; |
@@ -356,9 +412,14 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | |||
356 | if (browser.b.width < line_len) | 412 | if (browser.b.width < line_len) |
357 | browser.b.width = line_len; | 413 | browser.b.width = line_len; |
358 | rbpos = objdump_line__rb(pos); | 414 | rbpos = objdump_line__rb(pos); |
359 | rbpos->idx = browser.b.nr_entries++; | 415 | rbpos->idx = browser.nr_entries++; |
416 | if (pos->offset != -1) | ||
417 | rbpos->idx_asm = browser.nr_asm_entries++; | ||
418 | else | ||
419 | rbpos->idx_asm = -1; | ||
360 | } | 420 | } |
361 | 421 | ||
422 | browser.b.nr_entries = browser.nr_entries; | ||
362 | browser.b.entries = ¬es->src->source, | 423 | browser.b.entries = ¬es->src->source, |
363 | browser.b.width += 18; /* Percentage */ | 424 | browser.b.width += 18; /* Percentage */ |
364 | ret = annotate_browser__run(&browser, evidx, nr_events, | 425 | ret = annotate_browser__run(&browser, evidx, nr_events, |
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index e64d9527f14e..b144b108029a 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c | |||
@@ -301,11 +301,7 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, | |||
301 | void(*timer)(void *arg), void *arg, int delay_secs) | 301 | void(*timer)(void *arg), void *arg, int delay_secs) |
302 | { | 302 | { |
303 | int key; | 303 | int key; |
304 | int delay_msecs = delay_secs * 1000; | ||
305 | char title[160]; | 304 | char title[160]; |
306 | int sym_exit_keys[] = { 'a', 'h', 'C', 'd', 'E', 't', 0, }; | ||
307 | int exit_keys[] = { '?', 'h', 'D', NEWT_KEY_LEFT, NEWT_KEY_RIGHT, | ||
308 | NEWT_KEY_TAB, NEWT_KEY_UNTAB, NEWT_KEY_ENTER, 0, }; | ||
309 | 305 | ||
310 | self->b.entries = &self->hists->entries; | 306 | self->b.entries = &self->hists->entries; |
311 | self->b.nr_entries = self->hists->nr_entries; | 307 | self->b.nr_entries = self->hists->nr_entries; |
@@ -318,27 +314,14 @@ static int hist_browser__run(struct hist_browser *self, const char *ev_name, | |||
318 | "Press '?' for help on key bindings") < 0) | 314 | "Press '?' for help on key bindings") < 0) |
319 | return -1; | 315 | return -1; |
320 | 316 | ||
321 | if (timer != NULL) | ||
322 | newtFormSetTimer(self->b.form, delay_msecs); | ||
323 | |||
324 | ui_browser__add_exit_keys(&self->b, exit_keys); | ||
325 | if (self->has_symbols) | ||
326 | ui_browser__add_exit_keys(&self->b, sym_exit_keys); | ||
327 | |||
328 | while (1) { | 317 | while (1) { |
329 | key = ui_browser__run(&self->b); | 318 | key = ui_browser__run(&self->b, delay_secs); |
330 | 319 | ||
331 | switch (key) { | 320 | switch (key) { |
332 | case -1: | 321 | case -1: |
333 | /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */ | 322 | /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */ |
334 | timer(arg); | 323 | timer(arg); |
335 | /* | 324 | ui_browser__update_nr_entries(&self->b, self->hists->nr_entries); |
336 | * The timer may have changed the number of entries. | ||
337 | * XXX: Find better way to keep this in synch, probably | ||
338 | * removing this timer function altogether and just sync | ||
339 | * using the hists->lock... | ||
340 | */ | ||
341 | self->b.nr_entries = self->hists->nr_entries; | ||
342 | hists__browser_title(self->hists, title, sizeof(title), | 325 | hists__browser_title(self->hists, title, sizeof(title), |
343 | ev_name, self->dso_filter, | 326 | ev_name, self->dso_filter, |
344 | self->thread_filter); | 327 | self->thread_filter); |
@@ -617,14 +600,23 @@ static int hist_browser__show_entry(struct hist_browser *self, | |||
617 | return printed; | 600 | return printed; |
618 | } | 601 | } |
619 | 602 | ||
603 | static void ui_browser__hists_init_top(struct ui_browser *browser) | ||
604 | { | ||
605 | if (browser->top == NULL) { | ||
606 | struct hist_browser *hb; | ||
607 | |||
608 | hb = container_of(browser, struct hist_browser, b); | ||
609 | browser->top = rb_first(&hb->hists->entries); | ||
610 | } | ||
611 | } | ||
612 | |||
620 | static unsigned int hist_browser__refresh(struct ui_browser *self) | 613 | static unsigned int hist_browser__refresh(struct ui_browser *self) |
621 | { | 614 | { |
622 | unsigned row = 0; | 615 | unsigned row = 0; |
623 | struct rb_node *nd; | 616 | struct rb_node *nd; |
624 | struct hist_browser *hb = container_of(self, struct hist_browser, b); | 617 | struct hist_browser *hb = container_of(self, struct hist_browser, b); |
625 | 618 | ||
626 | if (self->top == NULL) | 619 | ui_browser__hists_init_top(self); |
627 | self->top = rb_first(&hb->hists->entries); | ||
628 | 620 | ||
629 | for (nd = self->top; nd; nd = rb_next(nd)) { | 621 | for (nd = self->top; nd; nd = rb_next(nd)) { |
630 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | 622 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
@@ -676,6 +668,8 @@ static void ui_browser__hists_seek(struct ui_browser *self, | |||
676 | if (self->nr_entries == 0) | 668 | if (self->nr_entries == 0) |
677 | return; | 669 | return; |
678 | 670 | ||
671 | ui_browser__hists_init_top(self); | ||
672 | |||
679 | switch (whence) { | 673 | switch (whence) { |
680 | case SEEK_SET: | 674 | case SEEK_SET: |
681 | nd = hists__filter_entries(rb_first(self->entries)); | 675 | nd = hists__filter_entries(rb_first(self->entries)); |
@@ -931,8 +925,11 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
931 | !ui__dialog_yesno("Do you really want to exit?")) | 925 | !ui__dialog_yesno("Do you really want to exit?")) |
932 | continue; | 926 | continue; |
933 | /* Fall thru */ | 927 | /* Fall thru */ |
934 | default: | 928 | case 'q': |
929 | case CTRL('c'): | ||
935 | goto out_free_stack; | 930 | goto out_free_stack; |
931 | default: | ||
932 | continue; | ||
936 | } | 933 | } |
937 | 934 | ||
938 | if (!browser->has_symbols) | 935 | if (!browser->has_symbols) |
@@ -982,9 +979,14 @@ do_annotate: | |||
982 | he = hist_browser__selected_entry(browser); | 979 | he = hist_browser__selected_entry(browser); |
983 | if (he == NULL) | 980 | if (he == NULL) |
984 | continue; | 981 | continue; |
985 | 982 | /* | |
983 | * Don't let this be freed, say, by hists__decay_entry. | ||
984 | */ | ||
985 | he->used = true; | ||
986 | hist_entry__tui_annotate(he, evsel->idx, nr_events, | 986 | hist_entry__tui_annotate(he, evsel->idx, nr_events, |
987 | timer, arg, delay_secs); | 987 | timer, arg, delay_secs); |
988 | he->used = false; | ||
989 | ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); | ||
988 | } else if (choice == browse_map) | 990 | } else if (choice == browse_map) |
989 | map__browse(browser->selection->map); | 991 | map__browse(browser->selection->map); |
990 | else if (choice == zoom_dso) { | 992 | else if (choice == zoom_dso) { |
@@ -1061,8 +1063,6 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, | |||
1061 | int nr_events, const char *help, | 1063 | int nr_events, const char *help, |
1062 | void(*timer)(void *arg), void *arg, int delay_secs) | 1064 | void(*timer)(void *arg), void *arg, int delay_secs) |
1063 | { | 1065 | { |
1064 | int exit_keys[] = { NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; | ||
1065 | int delay_msecs = delay_secs * 1000; | ||
1066 | struct perf_evlist *evlist = menu->b.priv; | 1066 | struct perf_evlist *evlist = menu->b.priv; |
1067 | struct perf_evsel *pos; | 1067 | struct perf_evsel *pos; |
1068 | const char *ev_name, *title = "Available samples"; | 1068 | const char *ev_name, *title = "Available samples"; |
@@ -1072,13 +1072,8 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, | |||
1072 | "ESC: exit, ENTER|->: Browse histograms") < 0) | 1072 | "ESC: exit, ENTER|->: Browse histograms") < 0) |
1073 | return -1; | 1073 | return -1; |
1074 | 1074 | ||
1075 | if (timer != NULL) | ||
1076 | newtFormSetTimer(menu->b.form, delay_msecs); | ||
1077 | |||
1078 | ui_browser__add_exit_keys(&menu->b, exit_keys); | ||
1079 | |||
1080 | while (1) { | 1075 | while (1) { |
1081 | key = ui_browser__run(&menu->b); | 1076 | key = ui_browser__run(&menu->b, delay_secs); |
1082 | 1077 | ||
1083 | switch (key) { | 1078 | switch (key) { |
1084 | case -1: | 1079 | case -1: |
@@ -1090,44 +1085,53 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, | |||
1090 | if (!menu->selection) | 1085 | if (!menu->selection) |
1091 | continue; | 1086 | continue; |
1092 | pos = menu->selection; | 1087 | pos = menu->selection; |
1093 | perf_evlist__set_selected(evlist, pos); | ||
1094 | browse_hists: | 1088 | browse_hists: |
1089 | perf_evlist__set_selected(evlist, pos); | ||
1090 | /* | ||
1091 | * Give the calling tool a chance to populate the non | ||
1092 | * default evsel resorted hists tree. | ||
1093 | */ | ||
1094 | if (timer) | ||
1095 | timer(arg); | ||
1095 | ev_name = event_name(pos); | 1096 | ev_name = event_name(pos); |
1096 | key = perf_evsel__hists_browse(pos, nr_events, help, | 1097 | key = perf_evsel__hists_browse(pos, nr_events, help, |
1097 | ev_name, true, timer, | 1098 | ev_name, true, timer, |
1098 | arg, delay_secs); | 1099 | arg, delay_secs); |
1099 | ui_browser__show_title(&menu->b, title); | 1100 | ui_browser__show_title(&menu->b, title); |
1100 | break; | 1101 | switch (key) { |
1102 | case NEWT_KEY_TAB: | ||
1103 | if (pos->node.next == &evlist->entries) | ||
1104 | pos = list_entry(evlist->entries.next, struct perf_evsel, node); | ||
1105 | else | ||
1106 | pos = list_entry(pos->node.next, struct perf_evsel, node); | ||
1107 | goto browse_hists; | ||
1108 | case NEWT_KEY_UNTAB: | ||
1109 | if (pos->node.prev == &evlist->entries) | ||
1110 | pos = list_entry(evlist->entries.prev, struct perf_evsel, node); | ||
1111 | else | ||
1112 | pos = list_entry(pos->node.prev, struct perf_evsel, node); | ||
1113 | goto browse_hists; | ||
1114 | case NEWT_KEY_ESCAPE: | ||
1115 | if (!ui__dialog_yesno("Do you really want to exit?")) | ||
1116 | continue; | ||
1117 | /* Fall thru */ | ||
1118 | case 'q': | ||
1119 | case CTRL('c'): | ||
1120 | goto out; | ||
1121 | default: | ||
1122 | continue; | ||
1123 | } | ||
1101 | case NEWT_KEY_LEFT: | 1124 | case NEWT_KEY_LEFT: |
1102 | continue; | 1125 | continue; |
1103 | case NEWT_KEY_ESCAPE: | 1126 | case NEWT_KEY_ESCAPE: |
1104 | if (!ui__dialog_yesno("Do you really want to exit?")) | 1127 | if (!ui__dialog_yesno("Do you really want to exit?")) |
1105 | continue; | 1128 | continue; |
1106 | /* Fall thru */ | 1129 | /* Fall thru */ |
1107 | default: | ||
1108 | goto out; | ||
1109 | } | ||
1110 | |||
1111 | switch (key) { | ||
1112 | case NEWT_KEY_TAB: | ||
1113 | if (pos->node.next == &evlist->entries) | ||
1114 | pos = list_entry(evlist->entries.next, struct perf_evsel, node); | ||
1115 | else | ||
1116 | pos = list_entry(pos->node.next, struct perf_evsel, node); | ||
1117 | perf_evlist__set_selected(evlist, pos); | ||
1118 | goto browse_hists; | ||
1119 | case NEWT_KEY_UNTAB: | ||
1120 | if (pos->node.prev == &evlist->entries) | ||
1121 | pos = list_entry(evlist->entries.prev, struct perf_evsel, node); | ||
1122 | else | ||
1123 | pos = list_entry(pos->node.prev, struct perf_evsel, node); | ||
1124 | perf_evlist__set_selected(evlist, pos); | ||
1125 | goto browse_hists; | ||
1126 | case 'q': | 1130 | case 'q': |
1127 | case CTRL('c'): | 1131 | case CTRL('c'): |
1128 | goto out; | 1132 | goto out; |
1129 | default: | 1133 | default: |
1130 | break; | 1134 | continue; |
1131 | } | 1135 | } |
1132 | } | 1136 | } |
1133 | 1137 | ||
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c index 8462bffe20bc..6905bcc8be2d 100644 --- a/tools/perf/util/ui/browsers/map.c +++ b/tools/perf/util/ui/browsers/map.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include "../libslang.h" | 1 | #include "../libslang.h" |
2 | #include <elf.h> | 2 | #include <elf.h> |
3 | #include <newt.h> | ||
3 | #include <inttypes.h> | 4 | #include <inttypes.h> |
4 | #include <sys/ttydefaults.h> | 5 | #include <sys/ttydefaults.h> |
5 | #include <ctype.h> | 6 | #include <ctype.h> |
@@ -108,11 +109,8 @@ static int map_browser__run(struct map_browser *self) | |||
108 | verbose ? "" : "restart with -v to use") < 0) | 109 | verbose ? "" : "restart with -v to use") < 0) |
109 | return -1; | 110 | return -1; |
110 | 111 | ||
111 | if (verbose) | ||
112 | ui_browser__add_exit_key(&self->b, '/'); | ||
113 | |||
114 | while (1) { | 112 | while (1) { |
115 | key = ui_browser__run(&self->b); | 113 | key = ui_browser__run(&self->b, 0); |
116 | 114 | ||
117 | if (verbose && key == '/') | 115 | if (verbose && key == '/') |
118 | map_browser__search(self); | 116 | map_browser__search(self); |
diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/util/ui/helpline.h index ab6028d0c401..809975759080 100644 --- a/tools/perf/util/ui/helpline.h +++ b/tools/perf/util/ui/helpline.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef _PERF_UI_HELPLINE_H_ | 1 | #ifndef _PERF_UI_HELPLINE_H_ |
2 | #define _PERF_UI_HELPLINE_H_ 1 | 2 | #define _PERF_UI_HELPLINE_H_ 1 |
3 | 3 | ||
4 | #include <stdio.h> | ||
5 | |||
4 | void ui_helpline__init(void); | 6 | void ui_helpline__init(void); |
5 | void ui_helpline__pop(void); | 7 | void ui_helpline__pop(void); |
6 | void ui_helpline__push(const char *msg); | 8 | void ui_helpline__push(const char *msg); |