aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/ui
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/ui')
-rw-r--r--tools/perf/util/ui/browser.c117
-rw-r--r--tools/perf/util/ui/browser.h9
-rw-r--r--tools/perf/util/ui/browsers/annotate.c38
-rw-r--r--tools/perf/util/ui/browsers/hists.c327
-rw-r--r--tools/perf/util/ui/browsers/map.c32
-rw-r--r--tools/perf/util/ui/util.c4
6 files changed, 297 insertions, 230 deletions
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c
index 66f2d583d8c4..6d0df809a2ed 100644
--- a/tools/perf/util/ui/browser.c
+++ b/tools/perf/util/ui/browser.c
@@ -1,16 +1,6 @@
1#define _GNU_SOURCE
2#include <stdio.h>
3#undef _GNU_SOURCE
4/*
5 * slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks
6 * the build if it isn't defined. Use the equivalent one that glibc
7 * has on features.h.
8 */
9#include <features.h>
10#ifndef HAVE_LONG_LONG
11#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
12#endif
13#include <slang.h> 1#include <slang.h>
2#include "libslang.h"
3#include <linux/compiler.h>
14#include <linux/list.h> 4#include <linux/list.h>
15#include <linux/rbtree.h> 5#include <linux/rbtree.h>
16#include <stdlib.h> 6#include <stdlib.h>
@@ -19,17 +9,9 @@
19#include "helpline.h" 9#include "helpline.h"
20#include "../color.h" 10#include "../color.h"
21#include "../util.h" 11#include "../util.h"
12#include <stdio.h>
22 13
23#if SLANG_VERSION < 20104 14static int ui_browser__percent_color(double percent, bool current)
24#define sltt_set_color(obj, name, fg, bg) \
25 SLtt_set_color(obj,(char *)name, (char *)fg, (char *)bg)
26#else
27#define sltt_set_color SLtt_set_color
28#endif
29
30newtComponent newt_form__new(void);
31
32int ui_browser__percent_color(double percent, bool current)
33{ 15{
34 if (current) 16 if (current)
35 return HE_COLORSET_SELECTED; 17 return HE_COLORSET_SELECTED;
@@ -40,6 +22,23 @@ int ui_browser__percent_color(double percent, bool current)
40 return HE_COLORSET_NORMAL; 22 return HE_COLORSET_NORMAL;
41} 23}
42 24
25void ui_browser__set_color(struct ui_browser *self __used, int color)
26{
27 SLsmg_set_color(color);
28}
29
30void ui_browser__set_percent_color(struct ui_browser *self,
31 double percent, bool current)
32{
33 int color = ui_browser__percent_color(percent, current);
34 ui_browser__set_color(self, color);
35}
36
37void ui_browser__gotorc(struct ui_browser *self, int y, int x)
38{
39 SLsmg_gotorc(self->y + y, self->x + x);
40}
41
43void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence) 42void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
44{ 43{
45 struct list_head *head = self->entries; 44 struct list_head *head = self->entries;
@@ -111,7 +110,7 @@ unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self)
111 nd = self->top; 110 nd = self->top;
112 111
113 while (nd != NULL) { 112 while (nd != NULL) {
114 SLsmg_gotorc(self->y + row, self->x); 113 ui_browser__gotorc(self, row, 0);
115 self->write(self, nd, row); 114 self->write(self, nd, row);
116 if (++row == self->height) 115 if (++row == self->height)
117 break; 116 break;
@@ -131,13 +130,10 @@ void ui_browser__refresh_dimensions(struct ui_browser *self)
131 int cols, rows; 130 int cols, rows;
132 newtGetScreenSize(&cols, &rows); 131 newtGetScreenSize(&cols, &rows);
133 132
134 if (self->width > cols - 4) 133 self->width = cols - 1;
135 self->width = cols - 4; 134 self->height = rows - 2;
136 self->height = rows - 5; 135 self->y = 1;
137 if (self->height > self->nr_entries) 136 self->x = 0;
138 self->height = self->nr_entries;
139 self->y = (rows - self->height) / 2;
140 self->x = (cols - self->width) / 2;
141} 137}
142 138
143void ui_browser__reset_index(struct ui_browser *self) 139void ui_browser__reset_index(struct ui_browser *self)
@@ -146,34 +142,48 @@ void ui_browser__reset_index(struct ui_browser *self)
146 self->seek(self, 0, SEEK_SET); 142 self->seek(self, 0, SEEK_SET);
147} 143}
148 144
145void ui_browser__add_exit_key(struct ui_browser *self, int key)
146{
147 newtFormAddHotKey(self->form, key);
148}
149
150void 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
149int ui_browser__show(struct ui_browser *self, const char *title, 160int ui_browser__show(struct ui_browser *self, const char *title,
150 const char *helpline, ...) 161 const char *helpline, ...)
151{ 162{
152 va_list ap; 163 va_list ap;
164 int keys[] = { NEWT_KEY_UP, NEWT_KEY_DOWN, NEWT_KEY_PGUP,
165 NEWT_KEY_PGDN, NEWT_KEY_HOME, NEWT_KEY_END, ' ',
166 NEWT_KEY_LEFT, NEWT_KEY_ESCAPE, 'q', CTRL('c'), 0 };
153 167
154 if (self->form != NULL) { 168 if (self->form != NULL)
155 newtFormDestroy(self->form); 169 newtFormDestroy(self->form);
156 newtPopWindow(); 170
157 }
158 ui_browser__refresh_dimensions(self); 171 ui_browser__refresh_dimensions(self);
159 newtCenteredWindow(self->width, self->height, title); 172 self->form = newtForm(NULL, NULL, 0);
160 self->form = newt_form__new();
161 if (self->form == NULL) 173 if (self->form == NULL)
162 return -1; 174 return -1;
163 175
164 self->sb = newtVerticalScrollbar(self->width, 0, self->height, 176 self->sb = newtVerticalScrollbar(self->width, 1, self->height,
165 HE_COLORSET_NORMAL, 177 HE_COLORSET_NORMAL,
166 HE_COLORSET_SELECTED); 178 HE_COLORSET_SELECTED);
167 if (self->sb == NULL) 179 if (self->sb == NULL)
168 return -1; 180 return -1;
169 181
170 newtFormAddHotKey(self->form, NEWT_KEY_UP); 182 SLsmg_gotorc(0, 0);
171 newtFormAddHotKey(self->form, NEWT_KEY_DOWN); 183 ui_browser__set_color(self, NEWT_COLORSET_ROOT);
172 newtFormAddHotKey(self->form, NEWT_KEY_PGUP); 184 slsmg_write_nstring(title, self->width);
173 newtFormAddHotKey(self->form, NEWT_KEY_PGDN); 185
174 newtFormAddHotKey(self->form, NEWT_KEY_HOME); 186 ui_browser__add_exit_keys(self, keys);
175 newtFormAddHotKey(self->form, NEWT_KEY_END);
176 newtFormAddHotKey(self->form, ' ');
177 newtFormAddComponent(self->form, self->sb); 187 newtFormAddComponent(self->form, self->sb);
178 188
179 va_start(ap, helpline); 189 va_start(ap, helpline);
@@ -185,7 +195,6 @@ int ui_browser__show(struct ui_browser *self, const char *title,
185void ui_browser__hide(struct ui_browser *self) 195void ui_browser__hide(struct ui_browser *self)
186{ 196{
187 newtFormDestroy(self->form); 197 newtFormDestroy(self->form);
188 newtPopWindow();
189 self->form = NULL; 198 self->form = NULL;
190 ui_helpline__pop(); 199 ui_helpline__pop();
191} 200}
@@ -196,28 +205,28 @@ int ui_browser__refresh(struct ui_browser *self)
196 205
197 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); 206 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1);
198 row = self->refresh(self); 207 row = self->refresh(self);
199 SLsmg_set_color(HE_COLORSET_NORMAL); 208 ui_browser__set_color(self, HE_COLORSET_NORMAL);
200 SLsmg_fill_region(self->y + row, self->x, 209 SLsmg_fill_region(self->y + row, self->x,
201 self->height - row, self->width, ' '); 210 self->height - row, self->width, ' ');
202 211
203 return 0; 212 return 0;
204} 213}
205 214
206int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es) 215int ui_browser__run(struct ui_browser *self)
207{ 216{
217 struct newtExitStruct es;
218
208 if (ui_browser__refresh(self) < 0) 219 if (ui_browser__refresh(self) < 0)
209 return -1; 220 return -1;
210 221
211 while (1) { 222 while (1) {
212 off_t offset; 223 off_t offset;
213 224
214 newtFormRun(self->form, es); 225 newtFormRun(self->form, &es);
215 226
216 if (es->reason != NEWT_EXIT_HOTKEY) 227 if (es.reason != NEWT_EXIT_HOTKEY)
217 break; 228 break;
218 if (is_exit_key(es->u.key)) 229 switch (es.u.key) {
219 return es->u.key;
220 switch (es->u.key) {
221 case NEWT_KEY_DOWN: 230 case NEWT_KEY_DOWN:
222 if (self->index == self->nr_entries - 1) 231 if (self->index == self->nr_entries - 1)
223 break; 232 break;
@@ -274,12 +283,12 @@ int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es)
274 self->seek(self, -offset, SEEK_END); 283 self->seek(self, -offset, SEEK_END);
275 break; 284 break;
276 default: 285 default:
277 return es->u.key; 286 return es.u.key;
278 } 287 }
279 if (ui_browser__refresh(self) < 0) 288 if (ui_browser__refresh(self) < 0)
280 return -1; 289 return -1;
281 } 290 }
282 return 0; 291 return -1;
283} 292}
284 293
285unsigned int ui_browser__list_head_refresh(struct ui_browser *self) 294unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
@@ -294,7 +303,7 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
294 pos = self->top; 303 pos = self->top;
295 304
296 list_for_each_from(pos, head) { 305 list_for_each_from(pos, head) {
297 SLsmg_gotorc(self->y + row, self->x); 306 ui_browser__gotorc(self, row, 0);
298 self->write(self, pos, row); 307 self->write(self, pos, row);
299 if (++row == self->height) 308 if (++row == self->height)
300 break; 309 break;
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
index 0b9f829214f7..0dc7e4da36f5 100644
--- a/tools/perf/util/ui/browser.h
+++ b/tools/perf/util/ui/browser.h
@@ -25,16 +25,21 @@ struct ui_browser {
25}; 25};
26 26
27 27
28int ui_browser__percent_color(double percent, bool current); 28void ui_browser__set_color(struct ui_browser *self, int color);
29void ui_browser__set_percent_color(struct ui_browser *self,
30 double percent, bool current);
29bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row); 31bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row);
30void ui_browser__refresh_dimensions(struct ui_browser *self); 32void ui_browser__refresh_dimensions(struct ui_browser *self);
31void ui_browser__reset_index(struct ui_browser *self); 33void ui_browser__reset_index(struct ui_browser *self);
32 34
35void ui_browser__gotorc(struct ui_browser *self, int y, int x);
36void ui_browser__add_exit_key(struct ui_browser *self, int key);
37void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]);
33int ui_browser__show(struct ui_browser *self, const char *title, 38int ui_browser__show(struct ui_browser *self, const char *title,
34 const char *helpline, ...); 39 const char *helpline, ...);
35void ui_browser__hide(struct ui_browser *self); 40void ui_browser__hide(struct ui_browser *self);
36int ui_browser__refresh(struct ui_browser *self); 41int ui_browser__refresh(struct ui_browser *self);
37int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es); 42int ui_browser__run(struct ui_browser *self);
38 43
39void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence); 44void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence);
40unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self); 45unsigned 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 a90273e63f4f..82b78f99251b 100644
--- a/tools/perf/util/ui/browsers/annotate.c
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -40,14 +40,12 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
40 40
41 if (ol->offset != -1) { 41 if (ol->offset != -1) {
42 struct objdump_line_rb_node *olrb = objdump_line__rb(ol); 42 struct objdump_line_rb_node *olrb = objdump_line__rb(ol);
43 int color = ui_browser__percent_color(olrb->percent, current_entry); 43 ui_browser__set_percent_color(self, olrb->percent, current_entry);
44 SLsmg_set_color(color);
45 slsmg_printf(" %7.2f ", olrb->percent); 44 slsmg_printf(" %7.2f ", olrb->percent);
46 if (!current_entry) 45 if (!current_entry)
47 SLsmg_set_color(HE_COLORSET_CODE); 46 ui_browser__set_color(self, HE_COLORSET_CODE);
48 } else { 47 } else {
49 int color = ui_browser__percent_color(0, current_entry); 48 ui_browser__set_percent_color(self, 0, current_entry);
50 SLsmg_set_color(color);
51 slsmg_write_nstring(" ", 9); 49 slsmg_write_nstring(" ", 9);
52 } 50 }
53 51
@@ -135,32 +133,31 @@ static void annotate_browser__set_top(struct annotate_browser *self,
135 self->curr_hot = nd; 133 self->curr_hot = nd;
136} 134}
137 135
138static int annotate_browser__run(struct annotate_browser *self, 136static int annotate_browser__run(struct annotate_browser *self)
139 struct newtExitStruct *es)
140{ 137{
141 struct rb_node *nd; 138 struct rb_node *nd;
142 struct hist_entry *he = self->b.priv; 139 struct hist_entry *he = self->b.priv;
140 int key;
143 141
144 if (ui_browser__show(&self->b, he->ms.sym->name, 142 if (ui_browser__show(&self->b, he->ms.sym->name,
145 "<- or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0) 143 "<-, -> or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0)
146 return -1; 144 return -1;
147 145 /*
148 newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT); 146 * To allow builtin-annotate to cycle thru multiple symbols by
149 newtFormAddHotKey(self->b.form, NEWT_KEY_RIGHT); 147 * examining the exit key for this function.
148 */
149 ui_browser__add_exit_key(&self->b, NEWT_KEY_RIGHT);
150 150
151 nd = self->curr_hot; 151 nd = self->curr_hot;
152 if (nd) { 152 if (nd) {
153 newtFormAddHotKey(self->b.form, NEWT_KEY_TAB); 153 int tabs[] = { NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0 };
154 newtFormAddHotKey(self->b.form, NEWT_KEY_UNTAB); 154 ui_browser__add_exit_keys(&self->b, tabs);
155 } 155 }
156 156
157 while (1) { 157 while (1) {
158 ui_browser__run(&self->b, es); 158 key = ui_browser__run(&self->b);
159
160 if (es->reason != NEWT_EXIT_HOTKEY)
161 break;
162 159
163 switch (es->u.key) { 160 switch (key) {
164 case NEWT_KEY_TAB: 161 case NEWT_KEY_TAB:
165 nd = rb_prev(nd); 162 nd = rb_prev(nd);
166 if (nd == NULL) 163 if (nd == NULL)
@@ -179,12 +176,11 @@ static int annotate_browser__run(struct annotate_browser *self,
179 } 176 }
180out: 177out:
181 ui_browser__hide(&self->b); 178 ui_browser__hide(&self->b);
182 return es->u.key; 179 return key;
183} 180}
184 181
185int hist_entry__tui_annotate(struct hist_entry *self) 182int hist_entry__tui_annotate(struct hist_entry *self)
186{ 183{
187 struct newtExitStruct es;
188 struct objdump_line *pos, *n; 184 struct objdump_line *pos, *n;
189 struct objdump_line_rb_node *rbpos; 185 struct objdump_line_rb_node *rbpos;
190 LIST_HEAD(head); 186 LIST_HEAD(head);
@@ -232,7 +228,7 @@ int hist_entry__tui_annotate(struct hist_entry *self)
232 annotate_browser__set_top(&browser, browser.curr_hot); 228 annotate_browser__set_top(&browser, browser.curr_hot);
233 229
234 browser.b.width += 18; /* Percentage */ 230 browser.b.width += 18; /* Percentage */
235 ret = annotate_browser__run(&browser, &es); 231 ret = annotate_browser__run(&browser);
236 list_for_each_entry_safe(pos, n, &head, node) { 232 list_for_each_entry_safe(pos, n, &head, node) {
237 list_del(&pos->node); 233 list_del(&pos->node);
238 objdump_line__free(pos); 234 objdump_line__free(pos);
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index 6866aa4c41e0..ebda8c3fde9e 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -58,6 +58,11 @@ static char callchain_list__folded(const struct callchain_list *self)
58 return map_symbol__folded(&self->ms); 58 return map_symbol__folded(&self->ms);
59} 59}
60 60
61static void map_symbol__set_folding(struct map_symbol *self, bool unfold)
62{
63 self->unfolded = unfold ? self->has_children : false;
64}
65
61static int callchain_node__count_rows_rb_tree(struct callchain_node *self) 66static int callchain_node__count_rows_rb_tree(struct callchain_node *self)
62{ 67{
63 int n = 0; 68 int n = 0;
@@ -129,16 +134,16 @@ static void callchain_node__init_have_children_rb_tree(struct callchain_node *se
129 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) { 134 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
130 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node); 135 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
131 struct callchain_list *chain; 136 struct callchain_list *chain;
132 int first = true; 137 bool first = true;
133 138
134 list_for_each_entry(chain, &child->val, list) { 139 list_for_each_entry(chain, &child->val, list) {
135 if (first) { 140 if (first) {
136 first = false; 141 first = false;
137 chain->ms.has_children = chain->list.next != &child->val || 142 chain->ms.has_children = chain->list.next != &child->val ||
138 rb_first(&child->rb_root) != NULL; 143 !RB_EMPTY_ROOT(&child->rb_root);
139 } else 144 } else
140 chain->ms.has_children = chain->list.next == &child->val && 145 chain->ms.has_children = chain->list.next == &child->val &&
141 rb_first(&child->rb_root) != NULL; 146 !RB_EMPTY_ROOT(&child->rb_root);
142 } 147 }
143 148
144 callchain_node__init_have_children_rb_tree(child); 149 callchain_node__init_have_children_rb_tree(child);
@@ -150,7 +155,7 @@ static void callchain_node__init_have_children(struct callchain_node *self)
150 struct callchain_list *chain; 155 struct callchain_list *chain;
151 156
152 list_for_each_entry(chain, &self->val, list) 157 list_for_each_entry(chain, &self->val, list)
153 chain->ms.has_children = rb_first(&self->rb_root) != NULL; 158 chain->ms.has_children = !RB_EMPTY_ROOT(&self->rb_root);
154 159
155 callchain_node__init_have_children_rb_tree(self); 160 callchain_node__init_have_children_rb_tree(self);
156} 161}
@@ -168,6 +173,7 @@ static void callchain__init_have_children(struct rb_root *self)
168static void hist_entry__init_have_children(struct hist_entry *self) 173static void hist_entry__init_have_children(struct hist_entry *self)
169{ 174{
170 if (!self->init_have_children) { 175 if (!self->init_have_children) {
176 self->ms.has_children = !RB_EMPTY_ROOT(&self->sorted_chain);
171 callchain__init_have_children(&self->sorted_chain); 177 callchain__init_have_children(&self->sorted_chain);
172 self->init_have_children = true; 178 self->init_have_children = true;
173 } 179 }
@@ -195,43 +201,114 @@ static bool hist_browser__toggle_fold(struct hist_browser *self)
195 return false; 201 return false;
196} 202}
197 203
198static int hist_browser__run(struct hist_browser *self, const char *title, 204static int callchain_node__set_folding_rb_tree(struct callchain_node *self, bool unfold)
199 struct newtExitStruct *es) 205{
206 int n = 0;
207 struct rb_node *nd;
208
209 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
210 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
211 struct callchain_list *chain;
212 bool has_children = false;
213
214 list_for_each_entry(chain, &child->val, list) {
215 ++n;
216 map_symbol__set_folding(&chain->ms, unfold);
217 has_children = chain->ms.has_children;
218 }
219
220 if (has_children)
221 n += callchain_node__set_folding_rb_tree(child, unfold);
222 }
223
224 return n;
225}
226
227static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
228{
229 struct callchain_list *chain;
230 bool has_children = false;
231 int n = 0;
232
233 list_for_each_entry(chain, &node->val, list) {
234 ++n;
235 map_symbol__set_folding(&chain->ms, unfold);
236 has_children = chain->ms.has_children;
237 }
238
239 if (has_children)
240 n += callchain_node__set_folding_rb_tree(node, unfold);
241
242 return n;
243}
244
245static int callchain__set_folding(struct rb_root *chain, bool unfold)
246{
247 struct rb_node *nd;
248 int n = 0;
249
250 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
251 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
252 n += callchain_node__set_folding(node, unfold);
253 }
254
255 return n;
256}
257
258static void hist_entry__set_folding(struct hist_entry *self, bool unfold)
259{
260 hist_entry__init_have_children(self);
261 map_symbol__set_folding(&self->ms, unfold);
262
263 if (self->ms.has_children) {
264 int n = callchain__set_folding(&self->sorted_chain, unfold);
265 self->nr_rows = unfold ? n : 0;
266 } else
267 self->nr_rows = 0;
268}
269
270static void hists__set_folding(struct hists *self, bool unfold)
271{
272 struct rb_node *nd;
273
274 self->nr_entries = 0;
275
276 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
277 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
278 hist_entry__set_folding(he, unfold);
279 self->nr_entries += 1 + he->nr_rows;
280 }
281}
282
283static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
284{
285 hists__set_folding(self->hists, unfold);
286 self->b.nr_entries = self->hists->nr_entries;
287 /* Go to the start, we may be way after valid entries after a collapse */
288 ui_browser__reset_index(&self->b);
289}
290
291static int hist_browser__run(struct hist_browser *self, const char *title)
200{ 292{
201 char str[256], unit; 293 int key;
202 unsigned long nr_events = self->hists->stats.nr_events[PERF_RECORD_SAMPLE]; 294 int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't',
295 NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT, 0, };
203 296
204 self->b.entries = &self->hists->entries; 297 self->b.entries = &self->hists->entries;
205 self->b.nr_entries = self->hists->nr_entries; 298 self->b.nr_entries = self->hists->nr_entries;
206 299
207 hist_browser__refresh_dimensions(self); 300 hist_browser__refresh_dimensions(self);
208 301
209 nr_events = convert_unit(nr_events, &unit);
210 snprintf(str, sizeof(str), "Events: %lu%c ",
211 nr_events, unit);
212 newtDrawRootText(0, 0, str);
213
214 if (ui_browser__show(&self->b, title, 302 if (ui_browser__show(&self->b, title,
215 "Press '?' for help on key bindings") < 0) 303 "Press '?' for help on key bindings") < 0)
216 return -1; 304 return -1;
217 305
218 newtFormAddHotKey(self->b.form, 'a'); 306 ui_browser__add_exit_keys(&self->b, exit_keys);
219 newtFormAddHotKey(self->b.form, '?');
220 newtFormAddHotKey(self->b.form, 'h');
221 newtFormAddHotKey(self->b.form, 'd');
222 newtFormAddHotKey(self->b.form, 'D');
223 newtFormAddHotKey(self->b.form, 't');
224
225 newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT);
226 newtFormAddHotKey(self->b.form, NEWT_KEY_RIGHT);
227 newtFormAddHotKey(self->b.form, NEWT_KEY_ENTER);
228 307
229 while (1) { 308 while (1) {
230 ui_browser__run(&self->b, es); 309 key = ui_browser__run(&self->b);
231 310
232 if (es->reason != NEWT_EXIT_HOTKEY) 311 switch (key) {
233 break;
234 switch (es->u.key) {
235 case 'D': { /* Debug */ 312 case 'D': { /* Debug */
236 static int seq; 313 static int seq;
237 struct hist_entry *h = rb_entry(self->b.top, 314 struct hist_entry *h = rb_entry(self->b.top,
@@ -245,18 +322,26 @@ static int hist_browser__run(struct hist_browser *self, const char *title,
245 self->b.top_idx, 322 self->b.top_idx,
246 h->row_offset, h->nr_rows); 323 h->row_offset, h->nr_rows);
247 } 324 }
248 continue; 325 break;
326 case 'C':
327 /* Collapse the whole world. */
328 hist_browser__set_folding(self, false);
329 break;
330 case 'E':
331 /* Expand the whole world. */
332 hist_browser__set_folding(self, true);
333 break;
249 case NEWT_KEY_ENTER: 334 case NEWT_KEY_ENTER:
250 if (hist_browser__toggle_fold(self)) 335 if (hist_browser__toggle_fold(self))
251 break; 336 break;
252 /* fall thru */ 337 /* fall thru */
253 default: 338 default:
254 return 0; 339 goto out;
255 } 340 }
256 } 341 }
257 342out:
258 ui_browser__hide(&self->b); 343 ui_browser__hide(&self->b);
259 return 0; 344 return key;
260} 345}
261 346
262static char *callchain_list__sym_name(struct callchain_list *self, 347static char *callchain_list__sym_name(struct callchain_list *self,
@@ -306,15 +391,10 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
306 int color; 391 int color;
307 bool was_first = first; 392 bool was_first = first;
308 393
309 if (first) { 394 if (first)
310 first = false; 395 first = false;
311 chain->ms.has_children = chain->list.next != &child->val || 396 else
312 rb_first(&child->rb_root) != NULL;
313 } else {
314 extra_offset = LEVEL_OFFSET_STEP; 397 extra_offset = LEVEL_OFFSET_STEP;
315 chain->ms.has_children = chain->list.next == &child->val &&
316 rb_first(&child->rb_root) != NULL;
317 }
318 398
319 folded_sign = callchain_list__folded(chain); 399 folded_sign = callchain_list__folded(chain);
320 if (*row_offset != 0) { 400 if (*row_offset != 0) {
@@ -341,8 +421,8 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
341 *is_current_entry = true; 421 *is_current_entry = true;
342 } 422 }
343 423
344 SLsmg_set_color(color); 424 ui_browser__set_color(&self->b, color);
345 SLsmg_gotorc(self->b.y + row, self->b.x); 425 ui_browser__gotorc(&self->b, row, 0);
346 slsmg_write_nstring(" ", offset + extra_offset); 426 slsmg_write_nstring(" ", offset + extra_offset);
347 slsmg_printf("%c ", folded_sign); 427 slsmg_printf("%c ", folded_sign);
348 slsmg_write_nstring(str, width); 428 slsmg_write_nstring(str, width);
@@ -384,12 +464,7 @@ static int hist_browser__show_callchain_node(struct hist_browser *self,
384 list_for_each_entry(chain, &node->val, list) { 464 list_for_each_entry(chain, &node->val, list) {
385 char ipstr[BITS_PER_LONG / 4 + 1], *s; 465 char ipstr[BITS_PER_LONG / 4 + 1], *s;
386 int color; 466 int color;
387 /* 467
388 * FIXME: This should be moved to somewhere else,
389 * probably when the callchain is created, so as not to
390 * traverse it all over again
391 */
392 chain->ms.has_children = rb_first(&node->rb_root) != NULL;
393 folded_sign = callchain_list__folded(chain); 468 folded_sign = callchain_list__folded(chain);
394 469
395 if (*row_offset != 0) { 470 if (*row_offset != 0) {
@@ -405,8 +480,8 @@ static int hist_browser__show_callchain_node(struct hist_browser *self,
405 } 480 }
406 481
407 s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr)); 482 s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
408 SLsmg_gotorc(self->b.y + row, self->b.x); 483 ui_browser__gotorc(&self->b, row, 0);
409 SLsmg_set_color(color); 484 ui_browser__set_color(&self->b, color);
410 slsmg_write_nstring(" ", offset); 485 slsmg_write_nstring(" ", offset);
411 slsmg_printf("%c ", folded_sign); 486 slsmg_printf("%c ", folded_sign);
412 slsmg_write_nstring(s, width - 2); 487 slsmg_write_nstring(s, width - 2);
@@ -465,7 +540,7 @@ static int hist_browser__show_entry(struct hist_browser *self,
465 } 540 }
466 541
467 if (symbol_conf.use_callchain) { 542 if (symbol_conf.use_callchain) {
468 entry->ms.has_children = !RB_EMPTY_ROOT(&entry->sorted_chain); 543 hist_entry__init_have_children(entry);
469 folded_sign = hist_entry__folded(entry); 544 folded_sign = hist_entry__folded(entry);
470 } 545 }
471 546
@@ -484,8 +559,8 @@ static int hist_browser__show_entry(struct hist_browser *self,
484 color = HE_COLORSET_NORMAL; 559 color = HE_COLORSET_NORMAL;
485 } 560 }
486 561
487 SLsmg_set_color(color); 562 ui_browser__set_color(&self->b, color);
488 SLsmg_gotorc(self->b.y + row, self->b.x); 563 ui_browser__gotorc(&self->b, row, 0);
489 if (symbol_conf.use_callchain) { 564 if (symbol_conf.use_callchain) {
490 slsmg_printf("%c ", folded_sign); 565 slsmg_printf("%c ", folded_sign);
491 width -= 2; 566 width -= 2;
@@ -687,8 +762,6 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
687 762
688static void hist_browser__delete(struct hist_browser *self) 763static void hist_browser__delete(struct hist_browser *self)
689{ 764{
690 newtFormDestroy(self->b.form);
691 newtPopWindow();
692 free(self); 765 free(self);
693} 766}
694 767
@@ -702,21 +775,26 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *self)
702 return self->he_selection->thread; 775 return self->he_selection->thread;
703} 776}
704 777
705static int hist_browser__title(char *bf, size_t size, const char *ev_name, 778static int hists__browser_title(struct hists *self, char *bf, size_t size,
706 const struct dso *dso, const struct thread *thread) 779 const char *ev_name, const struct dso *dso,
780 const struct thread *thread)
707{ 781{
708 int printed = 0; 782 char unit;
783 int printed;
784 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
785
786 nr_events = convert_unit(nr_events, &unit);
787 printed = snprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
709 788
710 if (thread) 789 if (thread)
711 printed += snprintf(bf + printed, size - printed, 790 printed += snprintf(bf + printed, size - printed,
712 "Thread: %s(%d)", 791 ", Thread: %s(%d)",
713 (thread->comm_set ? thread->comm : ""), 792 (thread->comm_set ? thread->comm : ""),
714 thread->pid); 793 thread->pid);
715 if (dso) 794 if (dso)
716 printed += snprintf(bf + printed, size - printed, 795 printed += snprintf(bf + printed, size - printed,
717 "%sDSO: %s", thread ? " " : "", 796 ", DSO: %s", dso->short_name);
718 dso->short_name); 797 return printed;
719 return printed ?: snprintf(bf, size, "Event: %s", ev_name);
720} 798}
721 799
722int hists__browse(struct hists *self, const char *helpline, const char *ev_name) 800int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
@@ -725,7 +803,6 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
725 struct pstack *fstack; 803 struct pstack *fstack;
726 const struct thread *thread_filter = NULL; 804 const struct thread *thread_filter = NULL;
727 const struct dso *dso_filter = NULL; 805 const struct dso *dso_filter = NULL;
728 struct newtExitStruct es;
729 char msg[160]; 806 char msg[160];
730 int key = -1; 807 int key = -1;
731 808
@@ -738,9 +815,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
738 815
739 ui_helpline__push(helpline); 816 ui_helpline__push(helpline);
740 817
741 hist_browser__title(msg, sizeof(msg), ev_name, 818 hists__browser_title(self, msg, sizeof(msg), ev_name,
742 dso_filter, thread_filter); 819 dso_filter, thread_filter);
743
744 while (1) { 820 while (1) {
745 const struct thread *thread; 821 const struct thread *thread;
746 const struct dso *dso; 822 const struct dso *dso;
@@ -749,70 +825,63 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
749 annotate = -2, zoom_dso = -2, zoom_thread = -2, 825 annotate = -2, zoom_dso = -2, zoom_thread = -2,
750 browse_map = -2; 826 browse_map = -2;
751 827
752 if (hist_browser__run(browser, msg, &es)) 828 key = hist_browser__run(browser, msg);
753 break;
754 829
755 thread = hist_browser__selected_thread(browser); 830 thread = hist_browser__selected_thread(browser);
756 dso = browser->selection->map ? browser->selection->map->dso : NULL; 831 dso = browser->selection->map ? browser->selection->map->dso : NULL;
757 832
758 if (es.reason == NEWT_EXIT_HOTKEY) { 833 switch (key) {
759 key = es.u.key; 834 case NEWT_KEY_TAB:
760 835 case NEWT_KEY_UNTAB:
761 switch (key) { 836 /*
762 case NEWT_KEY_F1: 837 * Exit the browser, let hists__browser_tree
763 goto do_help; 838 * go to the next or previous
764 case NEWT_KEY_TAB: 839 */
765 case NEWT_KEY_UNTAB: 840 goto out_free_stack;
766 /* 841 case 'a':
767 * Exit the browser, let hists__browser_tree 842 if (browser->selection->map == NULL &&
768 * go to the next or previous 843 browser->selection->map->dso->annotate_warned)
769 */
770 goto out_free_stack;
771 default:;
772 }
773
774 switch (key) {
775 case 'a':
776 if (browser->selection->map == NULL ||
777 browser->selection->map->dso->annotate_warned)
778 continue;
779 goto do_annotate;
780 case 'd':
781 goto zoom_dso;
782 case 't':
783 goto zoom_thread;
784 case 'h':
785 case '?':
786do_help:
787 ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n"
788 "<- Zoom out\n"
789 "a Annotate current symbol\n"
790 "h/?/F1 Show this window\n"
791 "d Zoom into current DSO\n"
792 "t Zoom into current Thread\n"
793 "q/CTRL+C Exit browser");
794 continue; 844 continue;
795 default:; 845 goto do_annotate;
796 } 846 case 'd':
797 if (is_exit_key(key)) { 847 goto zoom_dso;
798 if (key == NEWT_KEY_ESCAPE && 848 case 't':
799 !ui__dialog_yesno("Do you really want to exit?")) 849 goto zoom_thread;
800 continue; 850 case NEWT_KEY_F1:
801 break; 851 case 'h':
802 } 852 case '?':
803 853 ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n"
804 if (es.u.key == NEWT_KEY_LEFT) { 854 "<- Zoom out\n"
805 const void *top; 855 "a Annotate current symbol\n"
856 "h/?/F1 Show this window\n"
857 "C Collapse all callchains\n"
858 "E Expand all callchains\n"
859 "d Zoom into current DSO\n"
860 "t Zoom into current Thread\n"
861 "q/CTRL+C Exit browser");
862 continue;
863 case NEWT_KEY_ENTER:
864 case NEWT_KEY_RIGHT:
865 /* menu */
866 break;
867 case NEWT_KEY_LEFT: {
868 const void *top;
806 869
807 if (pstack__empty(fstack)) 870 if (pstack__empty(fstack))
808 continue;
809 top = pstack__pop(fstack);
810 if (top == &dso_filter)
811 goto zoom_out_dso;
812 if (top == &thread_filter)
813 goto zoom_out_thread;
814 continue; 871 continue;
815 } 872 top = pstack__pop(fstack);
873 if (top == &dso_filter)
874 goto zoom_out_dso;
875 if (top == &thread_filter)
876 goto zoom_out_thread;
877 continue;
878 }
879 case NEWT_KEY_ESCAPE:
880 if (!ui__dialog_yesno("Do you really want to exit?"))
881 continue;
882 /* Fall thru */
883 default:
884 goto out_free_stack;
816 } 885 }
817 886
818 if (browser->selection->sym != NULL && 887 if (browser->selection->sym != NULL &&
@@ -885,8 +954,8 @@ zoom_out_dso:
885 pstack__push(fstack, &dso_filter); 954 pstack__push(fstack, &dso_filter);
886 } 955 }
887 hists__filter_by_dso(self, dso_filter); 956 hists__filter_by_dso(self, dso_filter);
888 hist_browser__title(msg, sizeof(msg), ev_name, 957 hists__browser_title(self, msg, sizeof(msg), ev_name,
889 dso_filter, thread_filter); 958 dso_filter, thread_filter);
890 hist_browser__reset(browser); 959 hist_browser__reset(browser);
891 } else if (choice == zoom_thread) { 960 } else if (choice == zoom_thread) {
892zoom_thread: 961zoom_thread:
@@ -903,8 +972,8 @@ zoom_out_thread:
903 pstack__push(fstack, &thread_filter); 972 pstack__push(fstack, &thread_filter);
904 } 973 }
905 hists__filter_by_thread(self, thread_filter); 974 hists__filter_by_thread(self, thread_filter);
906 hist_browser__title(msg, sizeof(msg), ev_name, 975 hists__browser_title(self, msg, sizeof(msg), ev_name,
907 dso_filter, thread_filter); 976 dso_filter, thread_filter);
908 hist_browser__reset(browser); 977 hist_browser__reset(browser);
909 } 978 }
910 } 979 }
@@ -925,10 +994,6 @@ int hists__tui_browse_tree(struct rb_root *self, const char *help)
925 const char *ev_name = __event_name(hists->type, hists->config); 994 const char *ev_name = __event_name(hists->type, hists->config);
926 995
927 key = hists__browse(hists, help, ev_name); 996 key = hists__browse(hists, help, ev_name);
928
929 if (is_exit_key(key))
930 break;
931
932 switch (key) { 997 switch (key) {
933 case NEWT_KEY_TAB: 998 case NEWT_KEY_TAB:
934 next = rb_next(nd); 999 next = rb_next(nd);
@@ -940,7 +1005,7 @@ int hists__tui_browse_tree(struct rb_root *self, const char *help)
940 continue; 1005 continue;
941 nd = rb_prev(nd); 1006 nd = rb_prev(nd);
942 default: 1007 default:
943 break; 1008 return key;
944 } 1009 }
945 } 1010 }
946 1011
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c
index 142b825b42bf..e35437dfa5b4 100644
--- a/tools/perf/util/ui/browsers/map.c
+++ b/tools/perf/util/ui/browsers/map.c
@@ -1,6 +1,5 @@
1#include "../libslang.h" 1#include "../libslang.h"
2#include <elf.h> 2#include <elf.h>
3#include <newt.h>
4#include <sys/ttydefaults.h> 3#include <sys/ttydefaults.h>
5#include <ctype.h> 4#include <ctype.h>
6#include <string.h> 5#include <string.h>
@@ -47,7 +46,6 @@ out_free_form:
47struct map_browser { 46struct map_browser {
48 struct ui_browser b; 47 struct ui_browser b;
49 struct map *map; 48 struct map *map;
50 u16 namelen;
51 u8 addrlen; 49 u8 addrlen;
52}; 50};
53 51
@@ -56,14 +54,16 @@ static void map_browser__write(struct ui_browser *self, void *nd, int row)
56 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 54 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
57 struct map_browser *mb = container_of(self, struct map_browser, b); 55 struct map_browser *mb = container_of(self, struct map_browser, b);
58 bool current_entry = ui_browser__is_current_entry(self, row); 56 bool current_entry = ui_browser__is_current_entry(self, row);
59 int color = ui_browser__percent_color(0, current_entry); 57 int width;
60 58
61 SLsmg_set_color(color); 59 ui_browser__set_percent_color(self, 0, current_entry);
62 slsmg_printf("%*llx %*llx %c ", 60 slsmg_printf("%*llx %*llx %c ",
63 mb->addrlen, sym->start, mb->addrlen, sym->end, 61 mb->addrlen, sym->start, mb->addrlen, sym->end,
64 sym->binding == STB_GLOBAL ? 'g' : 62 sym->binding == STB_GLOBAL ? 'g' :
65 sym->binding == STB_LOCAL ? 'l' : 'w'); 63 sym->binding == STB_LOCAL ? 'l' : 'w');
66 slsmg_write_nstring(sym->name, mb->namelen); 64 width = self->width - ((mb->addrlen * 2) + 4);
65 if (width > 0)
66 slsmg_write_nstring(sym->name, width);
67} 67}
68 68
69/* FIXME uber-kludgy, see comment on cmd_report... */ 69/* FIXME uber-kludgy, see comment on cmd_report... */
@@ -98,31 +98,29 @@ static int map_browser__search(struct map_browser *self)
98 return 0; 98 return 0;
99} 99}
100 100
101static int map_browser__run(struct map_browser *self, struct newtExitStruct *es) 101static int map_browser__run(struct map_browser *self)
102{ 102{
103 int key;
104
103 if (ui_browser__show(&self->b, self->map->dso->long_name, 105 if (ui_browser__show(&self->b, self->map->dso->long_name,
104 "Press <- or ESC to exit, %s / to search", 106 "Press <- or ESC to exit, %s / to search",
105 verbose ? "" : "restart with -v to use") < 0) 107 verbose ? "" : "restart with -v to use") < 0)
106 return -1; 108 return -1;
107 109
108 newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT);
109 newtFormAddHotKey(self->b.form, NEWT_KEY_ENTER);
110 if (verbose) 110 if (verbose)
111 newtFormAddHotKey(self->b.form, '/'); 111 ui_browser__add_exit_key(&self->b, '/');
112 112
113 while (1) { 113 while (1) {
114 ui_browser__run(&self->b, es); 114 key = ui_browser__run(&self->b);
115 115
116 if (es->reason != NEWT_EXIT_HOTKEY) 116 if (verbose && key == '/')
117 break;
118 if (verbose && es->u.key == '/')
119 map_browser__search(self); 117 map_browser__search(self);
120 else 118 else
121 break; 119 break;
122 } 120 }
123 121
124 ui_browser__hide(&self->b); 122 ui_browser__hide(&self->b);
125 return 0; 123 return key;
126} 124}
127 125
128int map__browse(struct map *self) 126int map__browse(struct map *self)
@@ -136,7 +134,6 @@ int map__browse(struct map *self)
136 }, 134 },
137 .map = self, 135 .map = self,
138 }; 136 };
139 struct newtExitStruct es;
140 struct rb_node *nd; 137 struct rb_node *nd;
141 char tmp[BITS_PER_LONG / 4]; 138 char tmp[BITS_PER_LONG / 4];
142 u64 maxaddr = 0; 139 u64 maxaddr = 0;
@@ -144,8 +141,6 @@ int map__browse(struct map *self)
144 for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) { 141 for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) {
145 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 142 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
146 143
147 if (mb.namelen < pos->namelen)
148 mb.namelen = pos->namelen;
149 if (maxaddr < pos->end) 144 if (maxaddr < pos->end)
150 maxaddr = pos->end; 145 maxaddr = pos->end;
151 if (verbose) { 146 if (verbose) {
@@ -156,6 +151,5 @@ int map__browse(struct map *self)
156 } 151 }
157 152
158 mb.addrlen = snprintf(tmp, sizeof(tmp), "%llx", maxaddr); 153 mb.addrlen = snprintf(tmp, sizeof(tmp), "%llx", maxaddr);
159 mb.b.width += mb.addrlen * 2 + 4 + mb.namelen; 154 return map_browser__run(&mb);
160 return map_browser__run(&mb, &es);
161} 155}
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c
index 04600e26ceea..9706d9d40279 100644
--- a/tools/perf/util/ui/util.c
+++ b/tools/perf/util/ui/util.c
@@ -11,8 +11,6 @@
11#include "helpline.h" 11#include "helpline.h"
12#include "util.h" 12#include "util.h"
13 13
14newtComponent newt_form__new(void);
15
16static void newt_form__set_exit_keys(newtComponent self) 14static void newt_form__set_exit_keys(newtComponent self)
17{ 15{
18 newtFormAddHotKey(self, NEWT_KEY_LEFT); 16 newtFormAddHotKey(self, NEWT_KEY_LEFT);
@@ -22,7 +20,7 @@ static void newt_form__set_exit_keys(newtComponent self)
22 newtFormAddHotKey(self, CTRL('c')); 20 newtFormAddHotKey(self, CTRL('c'));
23} 21}
24 22
25newtComponent newt_form__new(void) 23static newtComponent newt_form__new(void)
26{ 24{
27 newtComponent self = newtForm(NULL, NULL, 0); 25 newtComponent self = newtForm(NULL, NULL, 0);
28 if (self) 26 if (self)