aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2011-10-05 18:16:15 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-10-07 15:56:44 -0400
commitab81f3fd350c510730adb1ca40ef55c2b2952121 (patch)
tree7b442d9592dd5666eb2cae6194962e545bd693a7 /tools/perf/util
parent81cce8de9437be9234f651be1f03e596c1b1a79a (diff)
perf top: Reuse the 'report' hist_entry/hists classes
This actually fixes several problems we had in the old 'perf top': 1. Unresolved symbols not show, limitation that came from the old "KernelTop" codebase, to solve it we would need to do changes that would make sym_entry have most of the hist_entry fields. 2. It was using the number of samples, not the sum of sample->period. And brings the --sort code that allows us to have all the views in 'perf report', for instance: [root@emilia ~]# perf top --sort dso PerfTop: 5903 irqs/sec kernel:77.5% exact: 0.0% [1000Hz cycles], (all, 8 CPUs) ------------------------------------------------------------------------------ 31.59% libcrypto.so.1.0.0 21.55% [kernel] 18.57% libpython2.6.so.1.0 7.04% libc-2.12.so 6.99% _backend_agg.so 4.72% sshd 1.48% multiarray.so 1.39% libfreetype.so.6.3.22 1.37% perf 0.71% libgobject-2.0.so.0.2200.5 0.53% [tg3] 0.48% libglib-2.0.so.0.2200.5 0.44% libstdc++.so.6.0.13 0.40% libcairo.so.2.10800.8 0.38% libm-2.12.so 0.34% umath.so 0.30% libgdk-x11-2.0.so.0.1800.9 0.22% libpthread-2.12.so 0.20% libgtk-x11-2.0.so.0.1800.9 0.20% librt-2.12.so 0.15% _path.so 0.13% libpango-1.0.so.0.2800.1 0.11% libatlas.so.3.0 0.09% ft2font.so 0.09% libpangoft2-1.0.so.0.2800.1 0.08% libX11.so.6.3.0 0.07% [vdso] 0.06% cyclictest ^C All the filter lists can be used as well: --dsos, --comms, --symbols, etc. The 'perf report' TUI is also reused, being possible to apply all the zoom operations, do annotation, etc. This change will allow multiple simplifications in the symbol system as well, that will be detailed in upcoming changesets. Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/n/tip-xzaaldxq7zhqrrxdxjifk1mh@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/hist.c50
-rw-r--r--tools/perf/util/hist.h3
-rw-r--r--tools/perf/util/top.c141
-rw-r--r--tools/perf/util/top.h36
-rw-r--r--tools/perf/util/ui/browsers/top.c236
5 files changed, 57 insertions, 409 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 80fe30d90d72..87ef5c7797de 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -92,6 +92,41 @@ static void hist_entry__add_cpumode_period(struct hist_entry *self,
92 } 92 }
93} 93}
94 94
95static void hist_entry__decay(struct hist_entry *he)
96{
97 he->period = (he->period * 7) / 8;
98 he->nr_events = (he->nr_events * 7) / 8;
99}
100
101static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
102{
103 hists->stats.total_period -= he->period;
104 hist_entry__decay(he);
105 hists->stats.total_period += he->period;
106 return he->period == 0;
107}
108
109void hists__decay_entries(struct hists *hists)
110{
111 struct rb_node *next = rb_first(&hists->entries);
112 struct hist_entry *n;
113
114 while (next) {
115 n = rb_entry(next, struct hist_entry, rb_node);
116 next = rb_next(&n->rb_node);
117
118 if (hists__decay_entry(hists, n)) {
119 rb_erase(&n->rb_node, &hists->entries);
120
121 if (sort__need_collapse)
122 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
123
124 hist_entry__free(n);
125 --hists->nr_entries;
126 }
127 }
128}
129
95/* 130/*
96 * histogram, sorted on item, collects periods 131 * histogram, sorted on item, collects periods
97 */ 132 */
@@ -635,6 +670,21 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
635 return ret; 670 return ret;
636} 671}
637 672
673void hists__output_recalc_col_len(struct hists *hists, int max_rows)
674{
675 struct rb_node *next = rb_first(&hists->entries);
676 struct hist_entry *n;
677 int row = 0;
678
679 hists__reset_col_len(hists);
680
681 while (next && row++ < max_rows) {
682 n = rb_entry(next, struct hist_entry, rb_node);
683 hists__calc_col_len(hists, n);
684 next = rb_next(&n->rb_node);
685 }
686}
687
638int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, 688int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
639 struct hists *hists, struct hists *pair_hists, 689 struct hists *hists, struct hists *pair_hists,
640 bool show_displacement, long displacement, 690 bool show_displacement, long displacement,
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 424f9eb8310c..f87677bfaff9 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -78,6 +78,9 @@ void hists__output_resort_threaded(struct hists *hists);
78void hists__collapse_resort(struct hists *self); 78void hists__collapse_resort(struct hists *self);
79void hists__collapse_resort_threaded(struct hists *hists); 79void hists__collapse_resort_threaded(struct hists *hists);
80 80
81void hists__decay_entries(struct hists *hists);
82void hists__output_recalc_col_len(struct hists *hists, int max_rows);
83
81void hists__inc_nr_events(struct hists *self, u32 type); 84void hists__inc_nr_events(struct hists *self, u32 type);
82size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); 85size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
83 86
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index a11f60735a18..500471dffa4f 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -15,52 +15,6 @@
15#include "top.h" 15#include "top.h"
16#include <inttypes.h> 16#include <inttypes.h>
17 17
18/*
19 * Ordering weight: count-1 * count-2 * ... / count-n
20 */
21static double sym_weight(const struct sym_entry *sym, struct perf_top *top)
22{
23 double weight = sym->snap_count;
24 int counter;
25
26 if (!top->display_weighted)
27 return weight;
28
29 for (counter = 1; counter < top->evlist->nr_entries - 1; counter++)
30 weight *= sym->count[counter];
31
32 weight /= (sym->count[counter] + 1);
33
34 return weight;
35}
36
37static void perf_top__remove_active_sym(struct perf_top *top, struct sym_entry *syme)
38{
39 pthread_mutex_lock(&top->active_symbols_lock);
40 list_del_init(&syme->node);
41 pthread_mutex_unlock(&top->active_symbols_lock);
42}
43
44static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
45{
46 struct rb_node **p = &tree->rb_node;
47 struct rb_node *parent = NULL;
48 struct sym_entry *iter;
49
50 while (*p != NULL) {
51 parent = *p;
52 iter = rb_entry(parent, struct sym_entry, rb_node);
53
54 if (se->weight > iter->weight)
55 p = &(*p)->rb_left;
56 else
57 p = &(*p)->rb_right;
58 }
59
60 rb_link_node(&se->rb_node, parent, p);
61 rb_insert_color(&se->rb_node, tree);
62}
63
64#define SNPRINTF(buf, size, fmt, args...) \ 18#define SNPRINTF(buf, size, fmt, args...) \
65({ \ 19({ \
66 size_t r = snprintf(buf, size, fmt, ## args); \ 20 size_t r = snprintf(buf, size, fmt, ## args); \
@@ -69,7 +23,6 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
69 23
70size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) 24size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
71{ 25{
72 struct perf_evsel *counter;
73 float samples_per_sec = top->samples / top->delay_secs; 26 float samples_per_sec = top->samples / top->delay_secs;
74 float ksamples_per_sec = top->kernel_samples / top->delay_secs; 27 float ksamples_per_sec = top->kernel_samples / top->delay_secs;
75 float esamples_percent = (100.0 * top->exact_samples) / top->samples; 28 float esamples_percent = (100.0 * top->exact_samples) / top->samples;
@@ -104,7 +57,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
104 esamples_percent); 57 esamples_percent);
105 } 58 }
106 59
107 if (top->evlist->nr_entries == 1 || !top->display_weighted) { 60 if (top->evlist->nr_entries == 1) {
108 struct perf_evsel *first; 61 struct perf_evsel *first;
109 first = list_entry(top->evlist->entries.next, struct perf_evsel, node); 62 first = list_entry(top->evlist->entries.next, struct perf_evsel, node);
110 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", 63 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ",
@@ -112,27 +65,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
112 top->freq ? "Hz" : ""); 65 top->freq ? "Hz" : "");
113 } 66 }
114 67
115 if (!top->display_weighted) { 68 ret += SNPRINTF(bf + ret, size - ret, "%s", event_name(top->sym_evsel));
116 ret += SNPRINTF(bf + ret, size - ret, "%s",
117 event_name(top->sym_evsel));
118 } else {
119 /*
120 * Don't let events eat all the space. Leaving 30 bytes
121 * for the rest should be enough.
122 */
123 size_t last_pos = size - 30;
124
125 list_for_each_entry(counter, &top->evlist->entries, node) {
126 ret += SNPRINTF(bf + ret, size - ret, "%s%s",
127 counter->idx ? "/" : "",
128 event_name(counter));
129 if (ret > last_pos) {
130 sprintf(bf + last_pos - 3, "..");
131 ret = last_pos - 1;
132 break;
133 }
134 }
135 }
136 69
137 ret += SNPRINTF(bf + ret, size - ret, "], "); 70 ret += SNPRINTF(bf + ret, size - ret, "], ");
138 71
@@ -166,73 +99,3 @@ void perf_top__reset_sample_counters(struct perf_top *top)
166 top->exact_samples = top->guest_kernel_samples = 99 top->exact_samples = top->guest_kernel_samples =
167 top->guest_us_samples = 0; 100 top->guest_us_samples = 0;
168} 101}
169
170float perf_top__decay_samples(struct perf_top *top, struct rb_root *root)
171{
172 struct sym_entry *syme, *n;
173 float sum_ksamples = 0.0;
174 int snap = !top->display_weighted ? top->sym_evsel->idx : 0, j;
175
176 /* Sort the active symbols */
177 pthread_mutex_lock(&top->active_symbols_lock);
178 syme = list_entry(top->active_symbols.next, struct sym_entry, node);
179 pthread_mutex_unlock(&top->active_symbols_lock);
180
181 top->rb_entries = 0;
182 list_for_each_entry_safe_from(syme, n, &top->active_symbols, node) {
183 syme->snap_count = syme->count[snap];
184 if (syme->snap_count != 0) {
185
186 if ((top->hide_user_symbols &&
187 syme->map->dso->kernel == DSO_TYPE_USER) ||
188 (top->hide_kernel_symbols &&
189 syme->map->dso->kernel == DSO_TYPE_KERNEL)) {
190 perf_top__remove_active_sym(top, syme);
191 continue;
192 }
193 syme->weight = sym_weight(syme, top);
194
195 if ((int)syme->snap_count >= top->count_filter) {
196 rb_insert_active_sym(root, syme);
197 ++top->rb_entries;
198 }
199 sum_ksamples += syme->snap_count;
200
201 for (j = 0; j < top->evlist->nr_entries; j++)
202 syme->count[j] = top->zero ? 0 : syme->count[j] * 7 / 8;
203 } else
204 perf_top__remove_active_sym(top, syme);
205 }
206
207 return sum_ksamples;
208}
209
210/*
211 * Find the longest symbol name that will be displayed
212 */
213void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
214 int *dso_width, int *dso_short_width, int *sym_width)
215{
216 struct rb_node *nd;
217 int printed = 0;
218
219 *sym_width = *dso_width = *dso_short_width = 0;
220
221 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
222 struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
223 struct symbol *sym = sym_entry__symbol(syme);
224
225 if (++printed > top->print_entries ||
226 (int)syme->snap_count < top->count_filter)
227 continue;
228
229 if (syme->map->dso->long_name_len > *dso_width)
230 *dso_width = syme->map->dso->long_name_len;
231
232 if (syme->map->dso->short_name_len > *dso_short_width)
233 *dso_short_width = syme->map->dso->short_name_len;
234
235 if (sym->namelen > *sym_width)
236 *sym_width = sym->namelen;
237 }
238}
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index b07b0410463c..01d1057f3074 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -4,64 +4,32 @@
4#include "types.h" 4#include "types.h"
5#include "../perf.h" 5#include "../perf.h"
6#include <stddef.h> 6#include <stddef.h>
7#include <pthread.h>
8#include <linux/list.h>
9#include <linux/rbtree.h>
10 7
11struct perf_evlist; 8struct perf_evlist;
12struct perf_evsel; 9struct perf_evsel;
13struct perf_session; 10struct perf_session;
14 11
15struct sym_entry {
16 struct rb_node rb_node;
17 struct list_head node;
18 unsigned long snap_count;
19 double weight;
20 struct map *map;
21 unsigned long count[0];
22};
23
24static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
25{
26 return ((void *)self) + symbol_conf.priv_size;
27}
28
29struct perf_top { 12struct perf_top {
30 struct perf_evlist *evlist; 13 struct perf_evlist *evlist;
31 /* 14 /*
32 * Symbols will be added here in perf_event__process_sample and will 15 * Symbols will be added here in perf_event__process_sample and will
33 * get out after decayed. 16 * get out after decayed.
34 */ 17 */
35 struct list_head active_symbols;
36 pthread_mutex_t active_symbols_lock;
37 pthread_cond_t active_symbols_cond;
38 u64 samples; 18 u64 samples;
39 u64 kernel_samples, us_samples; 19 u64 kernel_samples, us_samples;
40 u64 exact_samples; 20 u64 exact_samples;
41 u64 guest_us_samples, guest_kernel_samples; 21 u64 guest_us_samples, guest_kernel_samples;
42 u64 total_lost_warned; 22 u64 total_lost_warned;
43 int print_entries, count_filter, delay_secs; 23 int print_entries, count_filter, delay_secs;
44 int display_weighted, freq, rb_entries; 24 int freq;
45 pid_t target_pid, target_tid; 25 pid_t target_pid, target_tid;
46 bool hide_kernel_symbols, hide_user_symbols, zero; 26 bool hide_kernel_symbols, hide_user_symbols, zero;
47 const char *cpu_list; 27 const char *cpu_list;
48 struct sym_entry *sym_filter_entry; 28 struct hist_entry *sym_filter_entry;
49 struct perf_evsel *sym_evsel; 29 struct perf_evsel *sym_evsel;
50 struct perf_session *session; 30 struct perf_session *session;
51}; 31};
52 32
53size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 33size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
54void perf_top__reset_sample_counters(struct perf_top *top); 34void perf_top__reset_sample_counters(struct perf_top *top);
55float perf_top__decay_samples(struct perf_top *top, struct rb_root *root);
56void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
57 int *dso_width, int *dso_short_width, int *sym_width);
58
59#ifdef NO_NEWT_SUPPORT
60static inline int perf_top__tui_browser(struct perf_top *top __used)
61{
62 return 0;
63}
64#else
65int perf_top__tui_browser(struct perf_top *top);
66#endif
67#endif /* __PERF_TOP_H */ 35#endif /* __PERF_TOP_H */
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c
deleted file mode 100644
index d43875b2356f..000000000000
--- a/tools/perf/util/ui/browsers/top.c
+++ /dev/null
@@ -1,236 +0,0 @@
1/*
2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Parts came from builtin-{top,stat,record}.c, see those files for further
5 * copyright notes.
6 *
7 * Released under the GPL v2. (and only v2, not any later version)
8 */
9#include "../browser.h"
10#include "../../annotate.h"
11#include "../helpline.h"
12#include "../libslang.h"
13#include "../util.h"
14#include "../ui.h"
15#include "../../evlist.h"
16#include "../../hist.h"
17#include "../../sort.h"
18#include "../../symbol.h"
19#include "../../session.h"
20#include "../../top.h"
21
22struct perf_top_browser {
23 struct ui_browser b;
24 struct rb_root root;
25 struct sym_entry *selection;
26 float sum_ksamples;
27 int dso_width;
28 int dso_short_width;
29 int sym_width;
30};
31
32static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row)
33{
34 struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b);
35 struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node);
36 bool current_entry = ui_browser__is_current_entry(browser, row);
37 struct symbol *symbol = sym_entry__symbol(syme);
38 struct perf_top *top = browser->priv;
39 int width = browser->width;
40 double pcnt;
41
42 pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) /
43 top_browser->sum_ksamples));
44 ui_browser__set_percent_color(browser, pcnt, current_entry);
45
46 if (top->evlist->nr_entries == 1 || !top->display_weighted) {
47 slsmg_printf("%20.2f ", syme->weight);
48 width -= 21;
49 } else {
50 slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count);
51 width -= 20;
52 }
53
54 slsmg_printf("%4.1f%%", pcnt);
55 width -= 7;
56
57 if (verbose) {
58 slsmg_printf(" %016" PRIx64, symbol->start);
59 width -= 17;
60 }
61
62 slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width,
63 symbol->name);
64 width -= top_browser->sym_width;
65 slsmg_write_nstring(width >= syme->map->dso->long_name_len ?
66 syme->map->dso->long_name :
67 syme->map->dso->short_name, width);
68
69 if (current_entry)
70 top_browser->selection = syme;
71}
72
73static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser)
74{
75 struct perf_top *top = browser->b.priv;
76 u64 top_idx = browser->b.top_idx;
77
78 browser->root = RB_ROOT;
79 browser->b.top = NULL;
80 browser->sum_ksamples = perf_top__decay_samples(top, &browser->root);
81 /*
82 * No active symbols
83 */
84 if (top->rb_entries == 0)
85 return;
86
87 perf_top__find_widths(top, &browser->root, &browser->dso_width,
88 &browser->dso_short_width,
89 &browser->sym_width);
90 if (browser->sym_width + browser->dso_width > browser->b.width - 29) {
91 browser->dso_width = browser->dso_short_width;
92 if (browser->sym_width + browser->dso_width > browser->b.width - 29)
93 browser->sym_width = browser->b.width - browser->dso_width - 29;
94 }
95
96 /*
97 * Adjust the ui_browser indexes since the entries in the browser->root
98 * rb_tree may have changed, then seek it from start, so that we get a
99 * possible new top of the screen.
100 */
101 browser->b.nr_entries = top->rb_entries;
102
103 if (top_idx >= browser->b.nr_entries) {
104 if (browser->b.height >= browser->b.nr_entries)
105 top_idx = browser->b.nr_entries - browser->b.height;
106 else
107 top_idx = 0;
108 }
109
110 if (browser->b.index >= top_idx + browser->b.height)
111 browser->b.index = top_idx + browser->b.index - browser->b.top_idx;
112
113 if (browser->b.index >= browser->b.nr_entries)
114 browser->b.index = browser->b.nr_entries - 1;
115
116 browser->b.top_idx = top_idx;
117 browser->b.seek(&browser->b, top_idx, SEEK_SET);
118}
119
120static void perf_top_browser__annotate(struct perf_top_browser *browser)
121{
122 struct sym_entry *syme = browser->selection;
123 struct symbol *sym = sym_entry__symbol(syme);
124 struct annotation *notes = symbol__annotation(sym);
125 struct perf_top *top = browser->b.priv;
126
127 if (notes->src != NULL)
128 goto do_annotation;
129
130 pthread_mutex_lock(&notes->lock);
131
132 top->sym_filter_entry = NULL;
133
134 if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) {
135 pr_err("Not enough memory for annotating '%s' symbol!\n",
136 sym->name);
137 pthread_mutex_unlock(&notes->lock);
138 return;
139 }
140
141 top->sym_filter_entry = syme;
142
143 pthread_mutex_unlock(&notes->lock);
144do_annotation:
145 symbol__tui_annotate(sym, syme->map, 0, NULL, NULL, top->delay_secs * 1000);
146}
147
148static void perf_top_browser__warn_lost(struct perf_top_browser *browser)
149{
150 struct perf_top *top = browser->b.priv;
151 char msg[128];
152 int len;
153
154 top->total_lost_warned = top->session->hists.stats.total_lost;
155 pthread_mutex_lock(&ui__lock);
156 ui_browser__set_color(&browser->b, HE_COLORSET_TOP);
157 len = snprintf(msg, sizeof(msg),
158 " WARNING: LOST %" PRIu64 " events, Check IO/CPU overload",
159 top->total_lost_warned);
160 if (len > browser->b.width)
161 len = browser->b.width;
162 SLsmg_gotorc(0, browser->b.width - len);
163 slsmg_write_nstring(msg, len);
164 pthread_mutex_unlock(&ui__lock);
165}
166
167static int perf_top_browser__run(struct perf_top_browser *browser)
168{
169 int key;
170 char title[160];
171 struct perf_top *top = browser->b.priv;
172 int delay_msecs = top->delay_secs * 1000;
173 int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
174
175 perf_top_browser__update_rb_tree(browser);
176 perf_top__header_snprintf(top, title, sizeof(title));
177 perf_top__reset_sample_counters(top);
178
179 if (ui_browser__show(&browser->b, title,
180 "ESC: exit, ENTER|->|a: Live Annotate") < 0)
181 return -1;
182
183 newtFormSetTimer(browser->b.form, delay_msecs);
184 ui_browser__add_exit_keys(&browser->b, exit_keys);
185
186 while (1) {
187 key = ui_browser__run(&browser->b);
188
189 switch (key) {
190 case -1:
191 /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
192 perf_top_browser__update_rb_tree(browser);
193 perf_top__header_snprintf(top, title, sizeof(title));
194 perf_top__reset_sample_counters(top);
195 ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT);
196 SLsmg_gotorc(0, 0);
197 slsmg_write_nstring(title, browser->b.width);
198
199 if (top->total_lost_warned != top->session->hists.stats.total_lost)
200 perf_top_browser__warn_lost(browser);
201 break;
202 case 'a':
203 case NEWT_KEY_RIGHT:
204 case NEWT_KEY_ENTER:
205 if (browser->selection)
206 perf_top_browser__annotate(browser);
207 break;
208 case NEWT_KEY_LEFT:
209 continue;
210 case NEWT_KEY_ESCAPE:
211 if (!ui__dialog_yesno("Do you really want to exit?"))
212 continue;
213 /* Fall thru */
214 default:
215 goto out;
216 }
217 }
218out:
219 ui_browser__hide(&browser->b);
220 return key;
221}
222
223int perf_top__tui_browser(struct perf_top *top)
224{
225 struct perf_top_browser browser = {
226 .b = {
227 .entries = &browser.root,
228 .refresh = ui_browser__rb_tree_refresh,
229 .seek = ui_browser__rb_tree_seek,
230 .write = perf_top_browser__write,
231 .priv = top,
232 },
233 };
234
235 return perf_top_browser__run(&browser);
236}