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.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 81cce8de
...@@ -106,6 +106,26 @@ Default is to monitor all CPUS. ...@@ -106,6 +106,26 @@ Default is to monitor all CPUS.
--zero:: --zero::
Zero history across display updates. Zero history across display updates.
-s::
--sort::
Sort by key(s): pid, comm, dso, symbol, parent
-n::
--show-nr-samples::
Show a column with the number of samples.
--show-total-period::
Show a column with the sum of periods.
--dsos::
Only consider symbols in these dsos.
--comms::
Only consider symbols in these comms.
--symbols::
Only consider these symbols.
INTERACTIVE PROMPTING KEYS INTERACTIVE PROMPTING KEYS
-------------------------- --------------------------
...@@ -130,9 +150,6 @@ INTERACTIVE PROMPTING KEYS ...@@ -130,9 +150,6 @@ INTERACTIVE PROMPTING KEYS
[S]:: [S]::
Stop annotation, return to full profile display. Stop annotation, return to full profile display.
[w]::
Toggle between weighted sum and individual count[E]r profile.
[z]:: [z]::
Toggle event count zeroing across display updates. Toggle event count zeroing across display updates.
......
...@@ -466,7 +466,6 @@ else ...@@ -466,7 +466,6 @@ else
LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o
LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o
LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o
LIB_OBJS += $(OUTPUT)util/ui/browsers/top.o
LIB_OBJS += $(OUTPUT)util/ui/helpline.o LIB_OBJS += $(OUTPUT)util/ui/helpline.o
LIB_OBJS += $(OUTPUT)util/ui/progress.o LIB_OBJS += $(OUTPUT)util/ui/progress.o
LIB_OBJS += $(OUTPUT)util/ui/util.o LIB_OBJS += $(OUTPUT)util/ui/util.o
...@@ -729,9 +728,6 @@ $(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS ...@@ -729,9 +728,6 @@ $(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
$(OUTPUT)util/ui/browsers/top.o: util/ui/browsers/top.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
......
This diff is collapsed.
...@@ -92,6 +92,41 @@ static void hist_entry__add_cpumode_period(struct hist_entry *self, ...@@ -92,6 +92,41 @@ static void hist_entry__add_cpumode_period(struct hist_entry *self,
} }
} }
static void hist_entry__decay(struct hist_entry *he)
{
he->period = (he->period * 7) / 8;
he->nr_events = (he->nr_events * 7) / 8;
}
static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
{
hists->stats.total_period -= he->period;
hist_entry__decay(he);
hists->stats.total_period += he->period;
return he->period == 0;
}
void hists__decay_entries(struct hists *hists)
{
struct rb_node *next = rb_first(&hists->entries);
struct hist_entry *n;
while (next) {
n = rb_entry(next, struct hist_entry, rb_node);
next = rb_next(&n->rb_node);
if (hists__decay_entry(hists, n)) {
rb_erase(&n->rb_node, &hists->entries);
if (sort__need_collapse)
rb_erase(&n->rb_node_in, &hists->entries_collapsed);
hist_entry__free(n);
--hists->nr_entries;
}
}
}
/* /*
* histogram, sorted on item, collects periods * histogram, sorted on item, collects periods
*/ */
...@@ -635,6 +670,21 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, ...@@ -635,6 +670,21 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
return ret; return ret;
} }
void hists__output_recalc_col_len(struct hists *hists, int max_rows)
{
struct rb_node *next = rb_first(&hists->entries);
struct hist_entry *n;
int row = 0;
hists__reset_col_len(hists);
while (next && row++ < max_rows) {
n = rb_entry(next, struct hist_entry, rb_node);
hists__calc_col_len(hists, n);
next = rb_next(&n->rb_node);
}
}
int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
struct hists *hists, struct hists *pair_hists, struct hists *hists, struct hists *pair_hists,
bool show_displacement, long displacement, bool show_displacement, long displacement,
......
...@@ -78,6 +78,9 @@ void hists__output_resort_threaded(struct hists *hists); ...@@ -78,6 +78,9 @@ void hists__output_resort_threaded(struct hists *hists);
void hists__collapse_resort(struct hists *self); void hists__collapse_resort(struct hists *self);
void hists__collapse_resort_threaded(struct hists *hists); void hists__collapse_resort_threaded(struct hists *hists);
void hists__decay_entries(struct hists *hists);
void hists__output_recalc_col_len(struct hists *hists, int max_rows);
void hists__inc_nr_events(struct hists *self, u32 type); void hists__inc_nr_events(struct hists *self, u32 type);
size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
......
...@@ -15,52 +15,6 @@ ...@@ -15,52 +15,6 @@
#include "top.h" #include "top.h"
#include <inttypes.h> #include <inttypes.h>
/*
* Ordering weight: count-1 * count-2 * ... / count-n
*/
static double sym_weight(const struct sym_entry *sym, struct perf_top *top)
{
double weight = sym->snap_count;
int counter;
if (!top->display_weighted)
return weight;
for (counter = 1; counter < top->evlist->nr_entries - 1; counter++)
weight *= sym->count[counter];
weight /= (sym->count[counter] + 1);
return weight;
}
static void perf_top__remove_active_sym(struct perf_top *top, struct sym_entry *syme)
{
pthread_mutex_lock(&top->active_symbols_lock);
list_del_init(&syme->node);
pthread_mutex_unlock(&top->active_symbols_lock);
}
static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
{
struct rb_node **p = &tree->rb_node;
struct rb_node *parent = NULL;
struct sym_entry *iter;
while (*p != NULL) {
parent = *p;
iter = rb_entry(parent, struct sym_entry, rb_node);
if (se->weight > iter->weight)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
}
rb_link_node(&se->rb_node, parent, p);
rb_insert_color(&se->rb_node, tree);
}
#define SNPRINTF(buf, size, fmt, args...) \ #define SNPRINTF(buf, size, fmt, args...) \
({ \ ({ \
size_t r = snprintf(buf, size, fmt, ## args); \ 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,7 +23,6 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
{ {
struct perf_evsel *counter;
float samples_per_sec = top->samples / top->delay_secs; float samples_per_sec = top->samples / top->delay_secs;
float ksamples_per_sec = top->kernel_samples / top->delay_secs; float ksamples_per_sec = top->kernel_samples / top->delay_secs;
float esamples_percent = (100.0 * top->exact_samples) / top->samples; 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,7 +57,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
esamples_percent); esamples_percent);
} }
if (top->evlist->nr_entries == 1 || !top->display_weighted) { if (top->evlist->nr_entries == 1) {
struct perf_evsel *first; struct perf_evsel *first;
first = list_entry(top->evlist->entries.next, struct perf_evsel, node); first = list_entry(top->evlist->entries.next, struct perf_evsel, node);
ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", 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,27 +65,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
top->freq ? "Hz" : ""); top->freq ? "Hz" : "");
} }
if (!top->display_weighted) { ret += SNPRINTF(bf + ret, size - ret, "%s", event_name(top->sym_evsel));
ret += SNPRINTF(bf + ret, size - ret, "%s",
event_name(top->sym_evsel));
} else {
/*
* Don't let events eat all the space. Leaving 30 bytes
* for the rest should be enough.
*/
size_t last_pos = size - 30;
list_for_each_entry(counter, &top->evlist->entries, node) {
ret += SNPRINTF(bf + ret, size - ret, "%s%s",
counter->idx ? "/" : "",
event_name(counter));
if (ret > last_pos) {
sprintf(bf + last_pos - 3, "..");
ret = last_pos - 1;
break;
}
}
}
ret += SNPRINTF(bf + ret, size - ret, "], "); ret += SNPRINTF(bf + ret, size - ret, "], ");
...@@ -166,73 +99,3 @@ void perf_top__reset_sample_counters(struct perf_top *top) ...@@ -166,73 +99,3 @@ void perf_top__reset_sample_counters(struct perf_top *top)
top->exact_samples = top->guest_kernel_samples = top->exact_samples = top->guest_kernel_samples =
top->guest_us_samples = 0; top->guest_us_samples = 0;
} }
float perf_top__decay_samples(struct perf_top *top, struct rb_root *root)
{
struct sym_entry *syme, *n;
float sum_ksamples = 0.0;
int snap = !top->display_weighted ? top->sym_evsel->idx : 0, j;
/* Sort the active symbols */
pthread_mutex_lock(&top->active_symbols_lock);
syme = list_entry(top->active_symbols.next, struct sym_entry, node);
pthread_mutex_unlock(&top->active_symbols_lock);
top->rb_entries = 0;
list_for_each_entry_safe_from(syme, n, &top->active_symbols, node) {
syme->snap_count = syme->count[snap];
if (syme->snap_count != 0) {
if ((top->hide_user_symbols &&
syme->map->dso->kernel == DSO_TYPE_USER) ||
(top->hide_kernel_symbols &&
syme->map->dso->kernel == DSO_TYPE_KERNEL)) {
perf_top__remove_active_sym(top, syme);
continue;
}
syme->weight = sym_weight(syme, top);
if ((int)syme->snap_count >= top->count_filter) {
rb_insert_active_sym(root, syme);
++top->rb_entries;
}
sum_ksamples += syme->snap_count;
for (j = 0; j < top->evlist->nr_entries; j++)
syme->count[j] = top->zero ? 0 : syme->count[j] * 7 / 8;
} else
perf_top__remove_active_sym(top, syme);
}
return sum_ksamples;
}
/*
* Find the longest symbol name that will be displayed
*/
void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
int *dso_width, int *dso_short_width, int *sym_width)
{
struct rb_node *nd;
int printed = 0;
*sym_width = *dso_width = *dso_short_width = 0;
for (nd = rb_first(root); nd; nd = rb_next(nd)) {
struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node);
struct symbol *sym = sym_entry__symbol(syme);
if (++printed > top->print_entries ||
(int)syme->snap_count < top->count_filter)
continue;
if (syme->map->dso->long_name_len > *dso_width)
*dso_width = syme->map->dso->long_name_len;
if (syme->map->dso->short_name_len > *dso_short_width)
*dso_short_width = syme->map->dso->short_name_len;
if (sym->namelen > *sym_width)
*sym_width = sym->namelen;
}
}
...@@ -4,64 +4,32 @@ ...@@ -4,64 +4,32 @@
#include "types.h" #include "types.h"
#include "../perf.h" #include "../perf.h"
#include <stddef.h> #include <stddef.h>
#include <pthread.h>
#include <linux/list.h>
#include <linux/rbtree.h>
struct perf_evlist; struct perf_evlist;
struct perf_evsel; struct perf_evsel;
struct perf_session; struct perf_session;
struct sym_entry {
struct rb_node rb_node;
struct list_head node;
unsigned long snap_count;
double weight;
struct map *map;
unsigned long count[0];
};
static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
{
return ((void *)self) + symbol_conf.priv_size;
}
struct perf_top { struct perf_top {
struct perf_evlist *evlist; struct perf_evlist *evlist;
/* /*
* Symbols will be added here in perf_event__process_sample and will * Symbols will be added here in perf_event__process_sample and will
* get out after decayed. * get out after decayed.
*/ */
struct list_head active_symbols;
pthread_mutex_t active_symbols_lock;
pthread_cond_t active_symbols_cond;
u64 samples; u64 samples;
u64 kernel_samples, us_samples; u64 kernel_samples, us_samples;
u64 exact_samples; u64 exact_samples;
u64 guest_us_samples, guest_kernel_samples; u64 guest_us_samples, guest_kernel_samples;
u64 total_lost_warned; u64 total_lost_warned;
int print_entries, count_filter, delay_secs; int print_entries, count_filter, delay_secs;
int display_weighted, freq, rb_entries; int freq;
pid_t target_pid, target_tid; pid_t target_pid, target_tid;
bool hide_kernel_symbols, hide_user_symbols, zero; bool hide_kernel_symbols, hide_user_symbols, zero;
const char *cpu_list; const char *cpu_list;
struct sym_entry *sym_filter_entry; struct hist_entry *sym_filter_entry;
struct perf_evsel *sym_evsel; struct perf_evsel *sym_evsel;
struct perf_session *session; struct perf_session *session;
}; };
size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
void perf_top__reset_sample_counters(struct perf_top *top); void perf_top__reset_sample_counters(struct perf_top *top);
float perf_top__decay_samples(struct perf_top *top, struct rb_root *root);
void perf_top__find_widths(struct perf_top *top, struct rb_root *root,
int *dso_width, int *dso_short_width, int *sym_width);
#ifdef NO_NEWT_SUPPORT
static inline int perf_top__tui_browser(struct perf_top *top __used)
{
return 0;
}
#else
int perf_top__tui_browser(struct perf_top *top);
#endif
#endif /* __PERF_TOP_H */ #endif /* __PERF_TOP_H */
/*
* Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
*
* Parts came from builtin-{top,stat,record}.c, see those files for further
* copyright notes.
*
* Released under the GPL v2. (and only v2, not any later version)
*/
#include "../browser.h"
#include "../../annotate.h"
#include "../helpline.h"
#include "../libslang.h"
#include "../util.h"
#include "../ui.h"
#include "../../evlist.h"
#include "../../hist.h"
#include "../../sort.h"
#include "../../symbol.h"
#include "../../session.h"
#include "../../top.h"
struct perf_top_browser {
struct ui_browser b;
struct rb_root root;
struct sym_entry *selection;
float sum_ksamples;
int dso_width;
int dso_short_width;
int sym_width;
};
static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row)
{
struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b);
struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node);
bool current_entry = ui_browser__is_current_entry(browser, row);
struct symbol *symbol = sym_entry__symbol(syme);
struct perf_top *top = browser->priv;
int width = browser->width;
double pcnt;
pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) /
top_browser->sum_ksamples));
ui_browser__set_percent_color(browser, pcnt, current_entry);
if (top->evlist->nr_entries == 1 || !top->display_weighted) {
slsmg_printf("%20.2f ", syme->weight);
width -= 21;
} else {
slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count);
width -= 20;
}
slsmg_printf("%4.1f%%", pcnt);
width -= 7;
if (verbose) {
slsmg_printf(" %016" PRIx64, symbol->start);
width -= 17;
}
slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width,
symbol->name);
width -= top_browser->sym_width;
slsmg_write_nstring(width >= syme->map->dso->long_name_len ?
syme->map->dso->long_name :
syme->map->dso->short_name, width);
if (current_entry)
top_browser->selection = syme;
}
static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser)
{
struct perf_top *top = browser->b.priv;
u64 top_idx = browser->b.top_idx;
browser->root = RB_ROOT;
browser->b.top = NULL;
browser->sum_ksamples = perf_top__decay_samples(top, &browser->root);
/*
* No active symbols
*/
if (top->rb_entries == 0)
return;
perf_top__find_widths(top, &browser->root, &browser->dso_width,
&browser->dso_short_width,
&browser->sym_width);
if (browser->sym_width + browser->dso_width > browser->b.width - 29) {
browser->dso_width = browser->dso_short_width;
if (browser->sym_width + browser->dso_width > browser->b.width - 29)
browser->sym_width = browser->b.width - browser->dso_width - 29;
}
/*
* Adjust the ui_browser indexes since the entries in the browser->root
* rb_tree may have changed, then seek it from start, so that we get a
* possible new top of the screen.
*/
browser->b.nr_entries = top->rb_entries;
if (top_idx >= browser->b.nr_entries) {
if (browser->b.height >= browser->b.nr_entries)
top_idx = browser->b.nr_entries - browser->b.height;
else
top_idx = 0;
}
if (browser->b.index >= top_idx + browser->b.height)
browser->b.index = top_idx + browser->b.index - browser->b.top_idx;
if (browser->b.index >= browser->b.nr_entries)
browser->b.index = browser->b.nr_entries - 1;
browser->b.top_idx = top_idx;
browser->b.seek(&browser->b, top_idx, SEEK_SET);
}
static void perf_top_browser__annotate(struct perf_top_browser *browser)
{
struct sym_entry *syme = browser->selection;
struct symbol *sym = sym_entry__symbol(syme);
struct annotation *notes = symbol__annotation(sym);
struct perf_top *top = browser->b.priv;
if (notes->src != NULL)
goto do_annotation;
pthread_mutex_lock(&notes->lock);
top->sym_filter_entry = NULL;
if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) {
pr_err("Not enough memory for annotating '%s' symbol!\n",
sym->name);
pthread_mutex_unlock(&notes->lock);
return;
}
top->sym_filter_entry = syme;
pthread_mutex_unlock(&notes->lock);
do_annotation:
symbol__tui_annotate(sym, syme->map, 0, NULL, NULL, top->delay_secs * 1000);
}
static void perf_top_browser__warn_lost(struct perf_top_browser *browser)
{
struct perf_top *top = browser->b.priv;
char msg[128];
int len;
top->total_lost_warned = top->session->hists.stats.total_lost;
pthread_mutex_lock(&ui__lock);
ui_browser__set_color(&browser->b, HE_COLORSET_TOP);
len = snprintf(msg, sizeof(msg),
" WARNING: LOST %" PRIu64 " events, Check IO/CPU overload",
top->total_lost_warned);
if (len > browser->b.width)
len = browser->b.width;
SLsmg_gotorc(0, browser->b.width - len);
slsmg_write_nstring(msg, len);
pthread_mutex_unlock(&ui__lock);
}
static int perf_top_browser__run(struct perf_top_browser *browser)
{
int key;
char title[160];
struct perf_top *top = browser->b.priv;
int delay_msecs = top->delay_secs * 1000;
int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, };
perf_top_browser__update_rb_tree(browser);
perf_top__header_snprintf(top, title, sizeof(title));
perf_top__reset_sample_counters(top);
if (ui_browser__show(&browser->b, title,
"ESC: exit, ENTER|->|a: Live Annotate") < 0)
return -1;
newtFormSetTimer(browser->b.form, delay_msecs);
ui_browser__add_exit_keys(&browser->b, exit_keys);
while (1) {
key = ui_browser__run(&browser->b);
switch (key) {
case -1:
/* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
perf_top_browser__update_rb_tree(browser);
perf_top__header_snprintf(top, title, sizeof(title));
perf_top__reset_sample_counters(top);
ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT);
SLsmg_gotorc(0, 0);
slsmg_write_nstring(title, browser->b.width);
if (top->total_lost_warned != top->session->hists.stats.total_lost)
perf_top_browser__warn_lost(browser);
break;
case 'a':
case NEWT_KEY_RIGHT:
case NEWT_KEY_ENTER:
if (browser->selection)
perf_top_browser__annotate(browser);
break;
case NEWT_KEY_LEFT:
continue;
case NEWT_KEY_ESCAPE:
if (!ui__dialog_yesno("Do you really want to exit?"))
continue;
/* Fall thru */
default:
goto out;
}
}
out:
ui_browser__hide(&browser->b);
return key;
}
int perf_top__tui_browser(struct perf_top *top)
{
struct perf_top_browser browser = {
.b = {
.entries = &browser.root,
.refresh = ui_browser__rb_tree_refresh,
.seek = ui_browser__rb_tree_seek,
.write = perf_top_browser__write,
.priv = top,
},
};
return perf_top_browser__run(&browser);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment