aboutsummaryrefslogtreecommitdiff
path: root/tools/perf/ui
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/ui')
-rw-r--r--tools/perf/ui/browser.c15
-rw-r--r--tools/perf/ui/browser.h1
-rw-r--r--tools/perf/ui/browsers/annotate.c191
-rw-r--r--tools/perf/ui/browsers/hists.c448
-rw-r--r--tools/perf/ui/browsers/map.c60
-rw-r--r--tools/perf/ui/browsers/scripts.c1
-rw-r--r--tools/perf/ui/gtk/annotate.c245
-rw-r--r--tools/perf/ui/gtk/browser.c235
-rw-r--r--tools/perf/ui/gtk/gtk.h10
-rw-r--r--tools/perf/ui/gtk/helpline.c23
-rw-r--r--tools/perf/ui/gtk/hists.c316
-rw-r--r--tools/perf/ui/helpline.c12
-rw-r--r--tools/perf/ui/helpline.h22
-rw-r--r--tools/perf/ui/hist.c480
-rw-r--r--tools/perf/ui/keysyms.h1
-rw-r--r--tools/perf/ui/setup.c3
-rw-r--r--tools/perf/ui/stdio/hist.c32
-rw-r--r--tools/perf/ui/tui/helpline.c29
-rw-r--r--tools/perf/ui/tui/setup.c21
-rw-r--r--tools/perf/ui/ui.h2
-rw-r--r--tools/perf/ui/util.c1
21 files changed, 1410 insertions, 738 deletions
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index 4aeb7d5df939..bbc782e364b0 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -2,7 +2,6 @@
#include "../cache.h"
#include "../../perf.h"
#include "libslang.h"
-#include <newt.h>
#include "ui.h"
#include "util.h"
#include <linux/compiler.h>
@@ -234,7 +233,7 @@ void ui_browser__reset_index(struct ui_browser *browser)
void __ui_browser__show_title(struct ui_browser *browser, const char *title)
{
SLsmg_gotorc(0, 0);
- ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
+ ui_browser__set_color(browser, HE_COLORSET_ROOT);
slsmg_write_nstring(title, browser->width + 1);
}
@@ -273,6 +272,8 @@ void ui_browser__hide(struct ui_browser *browser __maybe_unused)
{
pthread_mutex_lock(&ui__lock);
ui_helpline__pop();
+ free(browser->helpline);
+ browser->helpline = NULL;
pthread_mutex_unlock(&ui__lock);
}
@@ -471,7 +472,7 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *browser)
return row;
}
-static struct ui_browser__colorset {
+static struct ui_browser_colorset {
const char *name, *fg, *bg;
int colorset;
} ui_browser__colorsets[] = {
@@ -512,6 +513,12 @@ static struct ui_browser__colorset {
.bg = "default",
},
{
+ .colorset = HE_COLORSET_ROOT,
+ .name = "root",
+ .fg = "white",
+ .bg = "blue",
+ },
+ {
.name = NULL,
}
};
@@ -706,7 +713,7 @@ void ui_browser__init(void)
perf_config(ui_browser__color_config, NULL);
while (ui_browser__colorsets[i].name) {
- struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
+ struct ui_browser_colorset *c = &ui_browser__colorsets[i++];
sltt_set_color(c->colorset, c->name, c->fg, c->bg);
}
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
index af70314605e5..404ff66a3e36 100644
--- a/tools/perf/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -11,6 +11,7 @@
#define HE_COLORSET_SELECTED 53
#define HE_COLORSET_CODE 54
#define HE_COLORSET_ADDR 55
+#define HE_COLORSET_ROOT 56
struct ui_browser {
u64 index, top_idx;
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 5dab3ca96980..cc64d3f7fc36 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -8,15 +8,19 @@
#include "../../util/hist.h"
#include "../../util/sort.h"
#include "../../util/symbol.h"
+#include "../../util/evsel.h"
#include <pthread.h>
-#include <newt.h>
struct browser_disasm_line {
struct rb_node rb_node;
- double percent;
u32 idx;
int idx_asm;
int jump_sources;
+ /*
+ * actual length of this array is saved on the nr_events field
+ * of the struct annotate_browser
+ */
+ double percent[1];
};
static struct annotate_browser_opt {
@@ -33,8 +37,9 @@ struct annotate_browser {
struct ui_browser b;
struct rb_root entries;
struct rb_node *curr_hot;
- struct disasm_line *selection;
+ struct disasm_line *selection;
struct disasm_line **offsets;
+ int nr_events;
u64 start;
int nr_asm_entries;
int nr_entries;
@@ -94,14 +99,24 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
(!current_entry || (browser->use_navkeypressed &&
!browser->navkeypressed)));
int width = browser->width, printed;
+ int i, pcnt_width = 7 * ab->nr_events;
+ double percent_max = 0.0;
char bf[256];
- if (dl->offset != -1 && bdl->percent != 0.0) {
- ui_browser__set_percent_color(browser, bdl->percent, current_entry);
- slsmg_printf("%6.2f ", bdl->percent);
+ for (i = 0; i < ab->nr_events; i++) {
+ if (bdl->percent[i] > percent_max)
+ percent_max = bdl->percent[i];
+ }
+
+ if (dl->offset != -1 && percent_max != 0.0) {
+ for (i = 0; i < ab->nr_events; i++) {
+ ui_browser__set_percent_color(browser, bdl->percent[i],
+ current_entry);
+ slsmg_printf("%6.2f ", bdl->percent[i]);
+ }
} else {
ui_browser__set_percent_color(browser, 0, current_entry);
- slsmg_write_nstring(" ", 7);
+ slsmg_write_nstring(" ", pcnt_width);
}
SLsmg_write_char(' ');
@@ -111,12 +126,12 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
width += 1;
if (!*dl->line)
- slsmg_write_nstring(" ", width - 7);
+ slsmg_write_nstring(" ", width - pcnt_width);
else if (dl->offset == -1) {
printed = scnprintf(bf, sizeof(bf), "%*s ",
ab->addr_width, " ");
slsmg_write_nstring(bf, printed);
- slsmg_write_nstring(dl->line, width - printed - 6);
+ slsmg_write_nstring(dl->line, width - printed - pcnt_width + 1);
} else {
u64 addr = dl->offset;
int color = -1;
@@ -175,13 +190,23 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
}
disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
- slsmg_write_nstring(bf, width - 10 - printed);
+ slsmg_write_nstring(bf, width - pcnt_width - 3 - printed);
}
if (current_entry)
ab->selection = dl;
}
+static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
+{
+ if (!dl || !dl->ins || !ins__is_jump(dl->ins)
+ || !disasm_line__has_offset(dl)
+ || dl->ops.target.offset >= symbol__size(sym))
+ return false;
+
+ return true;
+}
+
static void annotate_browser__draw_current_jump(struct ui_browser *browser)
{
struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
@@ -190,13 +215,13 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
unsigned int from, to;
struct map_symbol *ms = ab->b.priv;
struct symbol *sym = ms->sym;
+ u8 pcnt_width = 7;
/* PLT symbols contain external offsets */
if (strstr(sym->name, "@plt"))
return;
- if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) ||
- !disasm_line__has_offset(cursor))
+ if (!disasm_line__is_valid_jump(cursor, sym))
return;
target = ab->offsets[cursor->ops.target.offset];
@@ -214,57 +239,44 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
to = (u64)btarget->idx;
}
+ pcnt_width *= ab->nr_events;
+
ui_browser__set_color(browser, HE_COLORSET_CODE);
- __ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to);
+ __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
+ from, to);
}
static unsigned int annotate_browser__refresh(struct ui_browser *browser)
{
+ struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
int ret = ui_browser__list_head_refresh(browser);
+ int pcnt_width;
+
+ pcnt_width = 7 * ab->nr_events;
if (annotate_browser__opts.jump_arrows)
annotate_browser__draw_current_jump(browser);
ui_browser__set_color(browser, HE_COLORSET_NORMAL);
- __ui_browser__vline(browser, 7, 0, browser->height - 1);
+ __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
return ret;
}
-static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx)
+static int disasm__cmp(struct browser_disasm_line *a,
+ struct browser_disasm_line *b, int nr_pcnt)
{
- double percent = 0.0;
-
- if (dl->offset != -1) {
- int len = sym->end - sym->start;
- unsigned int hits = 0;
- struct annotation *notes = symbol__annotation(sym);
- struct source_line *src_line = notes->src->lines;
- struct sym_hist *h = annotation__histogram(notes, evidx);
- s64 offset = dl->offset;
- struct disasm_line *next;
-
- next = disasm__get_next_ip_line(&notes->src->source, dl);
- while (offset < (s64)len &&
- (next == NULL || offset < next->offset)) {
- if (src_line) {
- percent += src_line[offset].percent;
- } else
- hits += h->addr[offset];
+ int i;
- ++offset;
- }
- /*
- * If the percentage wasn't already calculated in
- * symbol__get_source_line, do it now:
- */
- if (src_line == NULL && h->sum)
- percent = 100.0 * hits / h->sum;
+ for (i = 0; i < nr_pcnt; i++) {
+ if (a->percent[i] == b->percent[i])
+ continue;
+ return a->percent[i] < b->percent[i];
}
-
- return percent;
+ return 0;
}
-static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl)
+static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
+ int nr_events)
{
struct rb_node **p = &root->rb_node;
struct rb_node *parent = NULL;
@@ -273,7 +285,8 @@ static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_l
while (*p != NULL) {
parent = *p;
l = rb_entry(parent, struct browser_disasm_line, rb_node);
- if (bdl->percent < l->percent)
+
+ if (disasm__cmp(bdl, l, nr_events))
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
@@ -322,12 +335,13 @@ static void annotate_browser__set_rb_top(struct annotate_browser *browser,
}
static void annotate_browser__calc_percent(struct annotate_browser *browser,
- int evidx)
+ struct perf_evsel *evsel)
{
struct map_symbol *ms = browser->b.priv;
struct symbol *sym = ms->sym;
struct annotation *notes = symbol__annotation(sym);
- struct disasm_line *pos;
+ struct disasm_line *pos, *next;
+ s64 len = symbol__size(sym);
browser->entries = RB_ROOT;
@@ -335,12 +349,34 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
list_for_each_entry(pos, &notes->src->source, node) {
struct browser_disasm_line *bpos = disasm_line__browser(pos);
- bpos->percent = disasm_line__calc_percent(pos, sym, evidx);
- if (bpos->percent < 0.01) {
+ const char *path = NULL;
+ double max_percent = 0.0;
+ int i;
+
+ if (pos->offset == -1) {
RB_CLEAR_NODE(&bpos->rb_node);
continue;
}
- disasm_rb_tree__insert(&browser->entries, bpos);
+
+ next = disasm__get_next_ip_line(&notes->src->source, pos);
+
+ for (i = 0; i < browser->nr_events; i++) {
+ bpos->percent[i] = disasm__calc_percent(notes,
+ evsel->idx + i,
+ pos->offset,
+ next ? next->offset : len,
+ &path);
+
+ if (max_percent < bpos->percent[i])
+ max_percent = bpos->percent[i];
+ }
+
+ if (max_percent < 0.01) {
+ RB_CLEAR_NODE(&bpos->rb_node);
+ continue;
+ }
+ disasm_rb_tree__insert(&browser->entries, bpos,
+ browser->nr_events);
}
pthread_mutex_unlock(&notes->lock);
@@ -392,7 +428,8 @@ static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
browser->b.nr_entries = browser->nr_asm_entries;
}
-static bool annotate_browser__callq(struct annotate_browser *browser, int evidx,
+static bool annotate_browser__callq(struct annotate_browser *browser,
+ struct perf_evsel *evsel,
struct hist_browser_timer *hbt)
{
struct map_symbol *ms = browser->b.priv;
@@ -423,7 +460,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, int evidx,
}
pthread_mutex_unlock(&notes->lock);
- symbol__tui_annotate(target, ms->map, evidx, hbt);
+ symbol__tui_annotate(target, ms->map, evsel, hbt);
ui_browser__show_title(&browser->b, sym->name);
return true;
}
@@ -606,7 +643,8 @@ static void annotate_browser__update_addr_width(struct annotate_browser *browser
browser->addr_width += browser->jumps_width + 1;
}
-static int annotate_browser__run(struct annotate_browser *browser, int evidx,
+static int annotate_browser__run(struct annotate_browser *browser,
+ struct perf_evsel *evsel,
struct hist_browser_timer *hbt)
{
struct rb_node *nd = NULL;
@@ -619,7 +657,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
if (ui_browser__show(&browser->b, sym->name, help) < 0)
return -1;
- annotate_browser__calc_percent(browser, evidx);
+ annotate_browser__calc_percent(browser, evsel);
if (browser->curr_hot) {
annotate_browser__set_rb_top(browser, browser->curr_hot);
@@ -632,7 +670,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
key = ui_browser__run(&browser->b, delay_secs);
if (delay_secs != 0) {
- annotate_browser__calc_percent(browser, evidx);
+ annotate_browser__calc_percent(browser, evsel);
/*
* Current line focus got out of the list of most active
* lines, NULL it so that if TAB|UNTAB is pressed, we
@@ -648,7 +686,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
hbt->timer(hbt->arg);
if (delay_secs != 0)
- symbol__annotate_decay_histogram(sym, evidx);
+ symbol__annotate_decay_histogram(sym, evsel->idx);
continue;
case K_TAB:
if (nd != NULL) {
@@ -745,7 +783,7 @@ show_help:
goto show_sup_ins;
goto out;
} else if (!(annotate_browser__jump(browser) ||
- annotate_browser__callq(browser, evidx, hbt))) {
+ annotate_browser__callq(browser, evsel, hbt))) {
show_sup_ins:
ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
}
@@ -767,10 +805,10 @@ out:
return key;
}
-int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
+int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
struct hist_browser_timer *hbt)
{
- return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, hbt);
+ return symbol__tui_annotate(he->ms.sym, he->ms.map, evsel, hbt);
}
static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
@@ -788,17 +826,9 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser
struct disasm_line *dl = browser->offsets[offset], *dlt;
struct browser_disasm_line *bdlt;
- if (!dl || !dl->ins || !ins__is_jump(dl->ins) ||
- !disasm_line__has_offset(dl))
+ if (!disasm_line__is_valid_jump(dl, sym))
continue;
- if (dl->ops.target.offset >= size) {
- ui__error("jump to after symbol!\n"
- "size: %zx, jump target: %" PRIx64,
- size, dl->ops.target.offset);
- continue;
- }
-
dlt = browser->offsets[dl->ops.target.offset];
/*
* FIXME: Oops, no jump target? Buggy disassembler? Or do we
@@ -825,7 +855,8 @@ static inline int width_jumps(int n)
return 1;
}
-int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
+int symbol__tui_annotate(struct symbol *sym, struct map *map,
+ struct perf_evsel *evsel,
struct hist_browser_timer *hbt)
{
struct disasm_line *pos, *n;
@@ -846,6 +877,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
},
};
int ret = -1;
+ int nr_pcnt = 1;
+ size_t sizeof_bdl = sizeof(struct browser_disasm_line);
if (sym == NULL)
return -1;
@@ -861,7 +894,12 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
return -1;
}
- if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) {
+ if (perf_evsel__is_group_event(evsel)) {
+ nr_pcnt = evsel->nr_members;
+ sizeof_bdl += sizeof(double) * (nr_pcnt - 1);
+ }
+
+ if (symbol__annotate(sym, map, sizeof_bdl) < 0) {
ui__error("%s", ui_helpline__last_msg);
goto out_free_offsets;
}
@@ -899,6 +937,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
browser.max_addr_width = hex_width(sym->end);
browser.jumps_width = width_jumps(browser.max_jump_sources);
+ browser.nr_events = nr_pcnt;
browser.b.nr_entries = browser.nr_entries;
browser.b.entries = &notes->src->source,
browser.b.width += 18; /* Percentage */
@@ -908,7 +947,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
annotate_browser__update_addr_width(&browser);
- ret = annotate_browser__run(&browser, evidx, hbt);
+ ret = annotate_browser__run(&browser, evsel, hbt);
list_for_each_entry_safe(pos, n, &notes->src->source, node) {
list_del(&pos->node);
disasm_line__free(pos);
@@ -921,11 +960,11 @@ out_free_offsets:
#define ANNOTATE_CFG(n) \
{ .name = #n, .value = &annotate_browser__opts.n, }
-
+
/*
* Keep the entries sorted, they are bsearch'ed
*/
-static struct annotate__config {
+static struct annotate_config {
const char *name;
bool *value;
} annotate__configs[] = {
@@ -939,7 +978,7 @@ static struct annotate__config {
static int annotate_config__cmp(const void *name, const void *cfgp)
{
- const struct annotate__config *cfg = cfgp;
+ const struct annotate_config *cfg = cfgp;
return strcmp(name, cfg->name);
}
@@ -947,7 +986,7 @@ static int annotate_config__cmp(const void *name, const void *cfgp)
static int annotate__config(const char *var, const char *value,
void *data __maybe_unused)
{
- struct annotate__config *cfg;
+ struct annotate_config *cfg;
const char *name;
if (prefixcmp(var, "annotate.") != 0)
@@ -955,7 +994,7 @@ static int annotate__config(const char *var, const char *value,
name = var + 9;
cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
- sizeof(struct annotate__config), annotate_config__cmp);
+ sizeof(struct annotate_config), annotate_config__cmp);
if (cfg == NULL)
return -1;
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index ccc4bd161420..fc0bd3843d34 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -2,7 +2,6 @@
#include "../libslang.h"
#include <stdlib.h>
#include <string.h>
-#include <newt.h>
#include <linux/rbtree.h>
#include "../../util/evsel.h"
@@ -26,7 +25,8 @@ struct hist_browser {
struct map_symbol *selection;
int print_seq;
bool show_dso;
- bool has_symbols;
+ float min_pcnt;
+ u64 nr_pcnt_entries;
};
extern void hist_browser__init_hpp(void);
@@ -310,6 +310,8 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)
"Or reduce the sampling frequency.");
}
+static void hist_browser__update_pcnt_entries(struct hist_browser *hb);
+
static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
struct hist_browser_timer *hbt)
{
@@ -319,6 +321,8 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
browser->b.entries = &browser->hists->entries;
browser->b.nr_entries = browser->hists->nr_entries;
+ if (browser->min_pcnt)
+ browser->b.nr_entries = browser->nr_pcnt_entries;
hist_browser__refresh_dimensions(browser);
hists__browser_title(browser->hists, title, sizeof(title), ev_name);
@@ -331,9 +335,18 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
key = ui_browser__run(&browser->b, delay_secs);
switch (key) {
- case K_TIMER:
+ case K_TIMER: {
+ u64 nr_entries;
hbt->timer(hbt->arg);
- ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
+
+ if (browser->min_pcnt) {
+ hist_browser__update_pcnt_entries(browser);
+ nr_entries = browser->nr_pcnt_entries;
+ } else {
+ nr_entries = browser->hists->nr_entries;
+ }
+
+ ui_browser__update_nr_entries(&browser->b, nr_entries);
if (browser->hists->stats.nr_lost_warned !=
browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
@@ -345,6 +358,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
hists__browser_title(browser->hists, title, sizeof(title), ev_name);
ui_browser__show_title(&browser->b, title);
continue;
+ }
case 'D': { /* Debug */
static int seq;
struct hist_entry *h = rb_entry(browser->b.top,
@@ -567,26 +581,128 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
return row - first_row;
}
-#define HPP__COLOR_FN(_name, _field) \
-static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \
- struct hist_entry *he) \
+struct hpp_arg {
+ struct ui_browser *b;
+ char folded_sign;
+ bool current_entry;
+};
+
+static int __hpp__color_callchain(struct hpp_arg *arg)
+{
+ if (!symbol_conf.use_callchain)
+ return 0;
+
+ slsmg_printf("%c ", arg->folded_sign);
+ return 2;
+}
+
+static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
+ u64 (*get_field)(struct hist_entry *),
+ int (*callchain_cb)(struct hpp_arg *))
+{
+ int ret = 0;
+ double percent = 0.0;
+ struct hists *hists = he->hists;
+ struct hpp_arg *arg = hpp->ptr;
+
+ if (hists->stats.total_period)
+ percent = 100.0 * get_field(he) / hists->stats.total_period;
+
+ ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
+
+ if (callchain_cb)
+ ret += callchain_cb(arg);
+
+ ret += scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
+ slsmg_printf("%s", hpp->buf);
+
+ if (symbol_conf.event_group) {
+ int prev_idx, idx_delta;
+ struct perf_evsel *evsel = hists_to_evsel(hists);
+ struct hist_entry *pair;
+ int nr_members = evsel->nr_members;
+
+ if (nr_members <= 1)
+ goto out;
+
+ prev_idx = perf_evsel__group_idx(evsel);
+
+ list_for_each_entry(pair, &he->pairs.head, pairs.node) {
+ u64 period = get_field(pair);
+ u64 total = pair->hists->stats.total_period;
+
+ if (!total)
+ continue;
+
+ evsel = hists_to_evsel(pair->hists);
+ idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
+
+ while (idx_delta--) {
+ /*
+ * zero-fill group members in the middle which
+ * have no sample
+ */
+ ui_browser__set_percent_color(arg->b, 0.0,
+ arg->current_entry);
+ ret += scnprintf(hpp->buf, hpp->size,
+ " %6.2f%%", 0.0);
+ slsmg_printf("%s", hpp->buf);
+ }
+
+ percent = 100.0 * period / total;
+ ui_browser__set_percent_color(arg->b, percent,
+ arg->current_entry);
+ ret += scnprintf(hpp->buf, hpp->size,
+ " %6.2f%%", percent);
+ slsmg_printf("%s", hpp->buf);
+
+ prev_idx = perf_evsel__group_idx(evsel);
+ }
+
+ idx_delta = nr_members - prev_idx - 1;
+
+ while (idx_delta--) {
+ /*
+ * zero-fill group members at last which have no sample
+ */
+ ui_browser__set_percent_color(arg->b, 0.0,
+ arg->current_entry);
+ ret += scnprintf(hpp->buf, hpp->size,
+ " %6.2f%%", 0.0);
+ slsmg_printf("%s", hpp->buf);
+ }
+ }
+out:
+ if (!arg->current_entry || !arg->b->navkeypressed)
+ ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
+
+ return ret;
+}
+
+#define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \
+static u64 __hpp_get_##_field(struct hist_entry *he) \
+{ \
+ return he->stat._field; \
+} \
+ \
+static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \
+ struct hist_entry *he) \
{ \
- struct hists *hists = he->hists; \
- double percent = 100.0 * he->stat._field / hists->stats.total_period; \
- *(double *)hpp->ptr = percent; \
- return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \
+ return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \
}
-HPP__COLOR_FN(overhead, period)
-HPP__COLOR_FN(overhead_sys, period_sys)
-HPP__COLOR_FN(overhead_us, period_us)
-HPP__COLOR_FN(overhead_guest_sys, period_guest_sys)
-HPP__COLOR_FN(overhead_guest_us, period_guest_us)
+__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__color_callchain)
+__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, NULL)
+__HPP_COLOR_PERCENT_FN(overhead_us, period_us, NULL)
+__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, NULL)
+__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
-#undef HPP__COLOR_FN
+#undef __HPP_COLOR_PERCENT_FN
void hist_browser__init_hpp(void)
{
+ perf_hpp__column_enable(PERF_HPP__OVERHEAD);
+
perf_hpp__init();
perf_hpp__format[PERF_HPP__OVERHEAD].color =
@@ -606,13 +722,13 @@ static int hist_browser__show_entry(struct hist_browser *browser,
unsigned short row)
{
char s[256];
- double percent;
- int i, printed = 0;
+ int printed = 0;
int width = browser->b.width;
char folded_sign = ' ';
bool current_entry = ui_browser__is_current_entry(&browser->b, row);
off_t row_offset = entry->row_offset;
bool first = true;
+ struct perf_hpp_fmt *fmt;
if (current_entry) {
browser->he_selection = entry;
@@ -625,41 +741,30 @@ static int hist_browser__show_entry(struct hist_browser *browser,
}
if (row_offset == 0) {
+ struct hpp_arg arg = {
+ .b = &browser->b,
+ .folded_sign = folded_sign,
+ .current_entry = current_entry,
+ };
struct perf_hpp hpp = {
.buf = s,
.size = sizeof(s),
+ .ptr = &arg,
};
ui_browser__gotorc(&browser->b, row, 0);
- for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
- if (!perf_hpp__format[i].cond)
- continue;
-
+ perf_hpp__for_each_format(fmt) {
if (!first) {
slsmg_printf(" ");
width -= 2;
}
first = false;
- if (perf_hpp__format[i].color) {
- hpp.ptr = &percent;
- /* It will set percent for us. See HPP__COLOR_FN above. */
- width -= perf_hpp__format[i].color(&hpp, entry);
-
- ui_browser__set_percent_color(&browser->b, percent, current_entry);
-
- if (i == PERF_HPP__OVERHEAD && symbol_conf.use_callchain) {
- slsmg_printf("%c ", folded_sign);
- width -= 2;
- }
-
- slsmg_printf("%s", s);
-
- if (!current_entry || !browser->b.navkeypressed)
- ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
+ if (fmt->color) {
+ width -= fmt->color(&hpp, entry);
} else {
- width -= perf_hpp__format[i].entry(&hpp, entry);
+ width -= fmt->entry(&hpp, entry);
slsmg_printf("%s", s);
}
}
@@ -706,10 +811,15 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
for (nd = browser->top; nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+ float percent = h->stat.period * 100.0 /
+ hb->hists->stats.total_period;
if (h->filtered)
continue;
+ if (percent < hb->min_pcnt)
+ continue;
+
row += hist_browser__show_entry(hb, h, row);
if (row == browser->height)
break;
@@ -718,10 +828,18 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
return row;
}
-static struct rb_node *hists__filter_entries(struct rb_node *nd)
+static struct rb_node *hists__filter_entries(struct rb_node *nd,
+ struct hists *hists,
+ float min_pcnt)
{
while (nd != NULL) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+ float percent = h->stat.period * 100.0 /
+ hists->stats.total_period;
+
+ if (percent < min_pcnt)
+ return NULL;
+
if (!h->filtered)
return nd;
@@ -731,11 +849,16 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd)
return NULL;
}
-static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
+static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
+ struct hists *hists,
+ float min_pcnt)
{
while (nd != NULL) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
- if (!h->filtered)
+ float percent = h->stat.period * 100.0 /
+ hists->stats.total_period;
+
+ if (!h->filtered && percent >= min_pcnt)
return nd;
nd = rb_prev(nd);
@@ -750,6 +873,9 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
struct hist_entry *h;
struct rb_node *nd;
bool first = true;
+ struct hist_browser *hb;
+
+ hb = container_of(browser, struct hist_browser, b);
if (browser->nr_entries == 0)
return;
@@ -758,13 +884,15 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
switch (whence) {
case SEEK_SET:
- nd = hists__filter_entries(rb_first(browser->entries));
+ nd = hists__filter_entries(rb_first(browser->entries),
+ hb->hists, hb->min_pcnt);
break;
case SEEK_CUR:
nd = browser->top;
goto do_offset;
case SEEK_END:
- nd = hists__filter_prev_entries(rb_last(browser->entries));
+ nd = hists__filter_prev_entries(rb_last(browser->entries),
+ hb->hists, hb->min_pcnt);
first = false;
break;
default:
@@ -807,7 +935,8 @@ do_offset:
break;
}
}
- nd = hists__filter_entries(rb_next(nd));
+ nd = hists__filter_entries(rb_next(nd), hb->hists,
+ hb->min_pcnt);
if (nd == NULL)
break;
--offset;
@@ -840,7 +969,8 @@ do_offset:
}
}
- nd = hists__filter_prev_entries(rb_prev(nd));
+ nd = hists__filter_prev_entries(rb_prev(nd), hb->hists,
+ hb->min_pcnt);
if (nd == NULL)
break;
++offset;
@@ -1009,14 +1139,17 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
{
- struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries));
+ struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
+ browser->hists,
+ browser->min_pcnt);
int printed = 0;
while (nd) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
printed += hist_browser__fprintf_entry(browser, h, fp);
- nd = hists__filter_entries(rb_next(nd));
+ nd = hists__filter_entries(rb_next(nd), browser->hists,
+ browser->min_pcnt);
}
return printed;
@@ -1065,10 +1198,6 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
browser->b.refresh = hist_browser__refresh;
browser->b.seek = ui_browser__hists_seek;
browser->b.use_navkeypressed = true;
- if (sort__branch_mode == 1)
- browser->has_symbols = sort_sym_from.list.next != NULL;
- else
- browser->has_symbols = sort_sym.list.next != NULL;
}
return browser;
@@ -1098,6 +1227,21 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
const struct thread *thread = hists->thread_filter;
unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
u64 nr_events = hists->stats.total_period;
+ struct perf_evsel *evsel = hists_to_evsel(hists);
+ char buf[512];
+ size_t buflen = sizeof(buf);
+
+ if (perf_evsel__is_group_event(evsel)) {
+ struct perf_evsel *pos;
+
+ perf_evsel__group_desc(evsel, buf, buflen);
+ ev_name = buf;
+
+ for_each_group_member(pos, evsel) {
+ nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
+ nr_events += pos->hists.stats.total_period;
+ }
+ }
nr_samples = convert_unit(nr_samples, &unit);
printed = scnprintf(bf, size,
@@ -1135,10 +1279,114 @@ static inline bool is_report_browser(void *timer)
return timer == NULL;
}
+/*
+ * Only runtime switching of perf data file will make "input_name" point
+ * to a malloced buffer. So add "is_input_name_malloced" flag to decide
+ * whether we need to call free() for current "input_name" during the switch.
+ */
+static bool is_input_name_malloced = false;
+
+static int switch_data_file(void)
+{
+ char *pwd, *options[32], *abs_path[32], *tmp;
+ DIR *pwd_dir;
+ int nr_options = 0, choice = -1, ret = -1;
+ struct dirent *dent;
+
+ pwd = getenv("PWD");
+ if (!pwd)
+ return ret;
+
+ pwd_dir = opendir(pwd);
+ if (!pwd_dir)
+ return ret;
+
+ memset(options, 0, sizeof(options));
+ memset(options, 0, sizeof(abs_path));
+
+ while ((dent = readdir(pwd_dir))) {
+ char path[PATH_MAX];
+ u64 magic;
+ char *name = dent->d_name;
+ FILE *file;
+
+ if (!(dent->d_type == DT_REG))
+ continue;
+
+ snprintf(path, sizeof(path), "%s/%s", pwd, name);
+
+ file = fopen(path, "r");
+ if (!file)
+ continue;
+
+ if (fread(&magic, 1, 8, file) < 8)
+ goto close_file_and_continue;
+
+ if (is_perf_magic(magic)) {
+ options[nr_options] = strdup(name);
+ if (!options[nr_options])
+ goto close_file_and_continue;
+
+ abs_path[nr_options] = strdup(path);
+ if (!abs_path[nr_options]) {
+ free(options[nr_options]);
+ ui__warning("Can't search all data files due to memory shortage.\n");
+ fclose(file);
+ break;
+ }
+
+ nr_options++;
+ }
+
+close_file_and_continue:
+ fclose(file);
+ if (nr_options >= 32) {
+ ui__warning("Too many perf data files in PWD!\n"
+ "Only the first 32 files will be listed.\n");
+ break;
+ }
+ }
+ closedir(pwd_dir);
+
+ if (nr_options) {
+ choice = ui__popup_menu(nr_options, options);
+ if (choice < nr_options && choice >= 0) {
+ tmp = strdup(abs_path[choice]);
+ if (tmp) {
+ if (is_input_name_malloced)
+ free((void *)input_name);
+ input_name = tmp;
+ is_input_name_malloced = true;
+ ret = 0;
+ } else
+ ui__warning("Data switch failed due to memory shortage!\n");
+ }
+ }
+
+ free_popup_options(options, nr_options);
+ free_popup_options(abs_path, nr_options);
+ return ret;
+}
+
+static void hist_browser__update_pcnt_entries(struct hist_browser *hb)
+{
+ u64 nr_entries = 0;
+ struct rb_node *nd = rb_first(&hb->hists->entries);
+
+ while (nd) {
+ nr_entries++;
+ nd = hists__filter_entries(rb_next(nd), hb->hists,
+ hb->min_pcnt);
+ }
+
+ hb->nr_pcnt_entries = nr_entries;
+}
+
static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
const char *helpline, const char *ev_name,
bool left_exits,
struct hist_browser_timer *hbt,
+ float min_pcnt,
struct perf_session_env *env)
{
struct hists *hists = &evsel->hists;
@@ -1155,6 +1403,11 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
if (browser == NULL)
return -1;
+ if (min_pcnt) {
+ browser->min_pcnt = min_pcnt;
+ hist_browser__update_pcnt_entries(browser);
+ }
+
fstack = pstack__new(2);
if (fstack == NULL)
goto out;
@@ -1169,7 +1422,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
int choice = 0,
annotate = -2, zoom_dso = -2, zoom_thread = -2,
annotate_f = -2, annotate_t = -2, browse_map = -2;
- int scripts_comm = -2, scripts_symbol = -2, scripts_all = -2;
+ int scripts_comm = -2, scripts_symbol = -2,
+ scripts_all = -2, switch_data = -2;
nr_options = 0;
@@ -1190,7 +1444,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
*/
goto out_free_stack;
case 'a':
- if (!browser->has_symbols) {
+ if (!sort__has_sym) {
ui_browser__warning(&browser->b, delay_secs * 2,
"Annotation is only available for symbolic views, "
"include \"sym*\" in --sort to use it.");
@@ -1226,6 +1480,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
if (is_report_browser(hbt))
goto do_scripts;
continue;
+ case 's':
+ if (is_report_browser(hbt))
+ goto do_data_switch;
+ continue;
case K_F1:
case 'h':
case '?':
@@ -1245,6 +1503,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
"d Zoom into current DSO\n"
"t Zoom into current Thread\n"
"r Run available scripts('perf report' only)\n"
+ "s Switch to another data file in PWD ('perf report' only)\n"
"P Print histograms to perf.hist.N\n"
"V Verbose (DSO names in callchains, etc)\n"
"/ Filter symbol by name");
@@ -1284,10 +1543,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
continue;
}
- if (!browser->has_symbols)
+ if (!sort__has_sym)
goto add_exit_option;
- if (sort__branch_mode == 1) {
+ if (sort__mode == SORT_MODE__BRANCH) {
bi = browser->he_selection->branch_info;
if (browser->selection != NULL &&
bi &&
@@ -1352,6 +1611,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
scripts_all = nr_options++;
+ if (is_report_browser(hbt) && asprintf(&options[nr_options],
+ "Switch to another data file in PWD") > 0)
+ switch_data = nr_options++;
add_exit_option:
options[nr_options++] = (char *)"Exit";
retry_popup_menu:
@@ -1394,7 +1656,7 @@ do_annotate:
* Don't let this be freed, say, by hists__decay_entry.
*/
he->used = true;
- err = hist_entry__tui_annotate(he, evsel->idx, hbt);
+ err = hist_entry__tui_annotate(he, evsel, hbt);
he->used = false;
/*
* offer option to annotate the other branch source or target
@@ -1462,6 +1724,16 @@ do_scripts:
script_browse(script_opt);
}
+ /* Switch to another data file */
+ else if (choice == switch_data) {
+do_data_switch:
+ if (!switch_data_file()) {
+ key = K_SWITCH_INPUT_DATA;
+ break;
+ } else
+ ui__warning("Won't switch the data files due to\n"
+ "no valid data file get selected!\n");
+ }
}
out_free_stack:
pstack__delete(fstack);
@@ -1475,6 +1747,7 @@ struct perf_evsel_menu {
struct ui_browser b;
struct perf_evsel *selection;
bool lost_events, lost_events_warned;
+ float min_pcnt;
struct perf_session_env *env;
};
@@ -1494,6 +1767,16 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
HE_COLORSET_NORMAL);
+ if (perf_evsel__is_group_event(evsel)) {
+ struct perf_evsel *pos;
+
+ ev_name = perf_evsel__group_name(evsel);
+
+ for_each_group_member(pos, evsel) {
+ nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
+ }
+ }
+
nr_events = convert_unit(nr_events, &unit);
printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
unit, unit == ' ' ? "" : " ", ev_name);
@@ -1558,6 +1841,7 @@ browse_hists:
ev_name = perf_evsel__name(pos);
key = perf_evsel__hists_browse(pos, nr_events, help,
ev_name, true, hbt,
+ menu->min_pcnt,
menu->env);
ui_browser__show_title(&menu->b, title);
switch (key) {
@@ -1578,6 +1862,7 @@ browse_hists:
"Do you really want to exit?"))
continue;
/* Fall thru */
+ case K_SWITCH_INPUT_DATA:
case 'q':
case CTRL('c'):
goto out;
@@ -1604,9 +1889,21 @@ out:
return key;
}
+static bool filter_group_entries(struct ui_browser *self __maybe_unused,
+ void *entry)
+{
+ struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
+
+ if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
+ return true;
+
+ return false;
+}
+
static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
- const char *help,
+ int nr_entries, const char *help,
struct hist_browser_timer *hbt,
+ float min_pcnt,
struct perf_session_env *env)
{
struct perf_evsel *pos;
@@ -1616,9 +1913,11 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
.refresh = ui_browser__list_head_refresh,
.seek = ui_browser__list_head_seek,
.write = perf_evsel_menu__write,
- .nr_entries = evlist->nr_entries,
+ .filter = filter_group_entries,
+ .nr_entries = nr_entries,
.priv = evlist,
},
+ .min_pcnt = min_pcnt,
.env = env,
};
@@ -1632,20 +1931,39 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
menu.b.width = line_len;
}
- return perf_evsel_menu__run(&menu, evlist->nr_entries, help, hbt);
+ return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
}
int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
struct hist_browser_timer *hbt,
+ float min_pcnt,
struct perf_session_env *env)
{
- if (evlist->nr_entries == 1) {
+ int nr_entries = evlist->nr_entries;
+
+single_entry:
+ if (nr_entries == 1) {
struct perf_evsel *first = list_entry(evlist->entries.next,
struct perf_evsel, node);
const char *ev_name = perf_evsel__name(first);
- return perf_evsel__hists_browse(first, evlist->nr_entries, help,
- ev_name, false, hbt, env);
+
+ return perf_evsel__hists_browse(first, nr_entries, help,
+ ev_name, false, hbt, min_pcnt,
+ env);
+ }
+
+ if (symbol_conf.event_group) {
+ struct perf_evsel *pos;
+
+ nr_entries = 0;
+ list_for_each_entry(pos, &evlist->entries, node)
+ if (perf_evsel__is_group_leader(pos))
+ nr_entries++;
+
+ if (nr_entries == 1)
+ goto single_entry;
}
- return __perf_evlist__tui_browse_hists(evlist, help, hbt, env);
+ return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
+ hbt, min_pcnt, env);
}
diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
index 98851d55a53e..95c7cfb8f2c6 100644
--- a/tools/perf/ui/browsers/map.c
+++ b/tools/perf/ui/browsers/map.c
@@ -1,6 +1,5 @@
#include "../libslang.h"
#include <elf.h>
-#include <newt.h>
#include <inttypes.h>
#include <sys/ttydefaults.h>
#include <string.h>
@@ -10,41 +9,9 @@
#include "../../util/symbol.h"
#include "../browser.h"
#include "../helpline.h"
+#include "../keysyms.h"
#include "map.h"
-static int ui_entry__read(const char *title, char *bf, size_t size, int width)
-{
- struct newtExitStruct es;
- newtComponent form, entry;
- const char *result;
- int err = -1;
-
- newtCenteredWindow(width, 1, title);
- form = newtForm(NULL, NULL, 0);
- if (form == NULL)
- return -1;
-
- entry = newtEntry(0, 0, "0x", width, &result, NEWT_FLAG_SCROLL);
- if (entry == NULL)
- goto out_free_form;
-
- newtFormAddComponent(form, entry);
- newtFormAddHotKey(form, NEWT_KEY_ENTER);
- newtFormAddHotKey(form, NEWT_KEY_ESCAPE);
- newtFormAddHotKey(form, NEWT_KEY_LEFT);
- newtFormAddHotKey(form, CTRL('c'));
- newtFormRun(form, &es);
-
- if (result != NULL) {
- strncpy(bf, result, size);
- err = 0;
- }
-out_free_form:
- newtPopWindow();
- newtFormDestroy(form);
- return err;
-}
-
struct map_browser {
struct ui_browser b;
struct map *map;
@@ -78,10 +45,11 @@ static int map_browser__search(struct map_browser *self)
{
char target[512];
struct symbol *sym;
- int err = ui_entry__read("Search by name/addr", target, sizeof(target), 40);
-
- if (err)
- return err;
+ int err = ui_browser__input_window("Search by name/addr",
+ "Prefix with 0x to search by address",
+ target, "ENTER: OK, ESC: Cancel", 0);
+ if (err != K_ENTER)
+ return -1;
if (target[0] == '0' && tolower(target[1]) == 'x') {
u64 addr = strtoull(target, NULL, 16);
@@ -112,12 +80,20 @@ static int map_browser__run(struct map_browser *self)
while (1) {
key = ui_browser__run(&self->b, 0);
- if (verbose && key == '/')
- map_browser__search(self);
- else
+ switch (key) {
+ case '/':
+ if (verbose)
+ map_browser__search(self);
+ default:
break;
+ case K_LEFT:
+ case K_ESC:
+ case 'q':
+ case CTRL('c'):
+ goto out;
+ }
}
-
+out:
ui_browser__hide(&self->b);
return key;
}
diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c
index cbbd44b0d93e..12f009e61e94 100644
--- a/tools/perf/ui/browsers/scripts.c
+++ b/tools/perf/ui/browsers/scripts.c
@@ -1,5 +1,4 @@
#include <elf.h>
-#include <newt.h>
#include <inttypes.h>
#include <sys/ttydefaults.h>
#include <string.h>
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c
new file mode 100644
index 000000000000..f538794615db
--- /dev/null
+++ b/tools/perf/ui/gtk/annotate.c
@@ -0,0 +1,245 @@
+#include "gtk.h"
+#include "util/debug.h"
+#include "util/annotate.h"
+#include "util/evsel.h"
+#include "ui/helpline.h"
+
+
+enum {
+ ANN_COL__PERCENT,
+ ANN_COL__OFFSET,
+ ANN_COL__LINE,
+
+ MAX_ANN_COLS
+};
+
+static const char *const col_names[] = {
+ "Overhead",
+ "Offset",
+ "Line"
+};
+
+static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym,
+ struct disasm_line *dl, int evidx)
+{
+ struct sym_hist *symhist;
+ double percent = 0.0;
+ const char *markup;
+ int ret = 0;
+
+ strcpy(buf, "");
+
+ if (dl->offset == (s64) -1)
+ return 0;
+
+ symhist = annotation__histogram(symbol__annotation(sym), evidx);
+ if (!symbol_conf.event_group && !symhist->addr[dl->offset])
+ return 0;
+
+ percent = 100.0 * symhist->addr[dl->offset] / symhist->sum;
+
+ markup = perf_gtk__get_percent_color(percent);
+ if (markup)
+ ret += scnprintf(buf, size, "%s", markup);
+ ret += scnprintf(buf + ret, size - ret, "%6.2f%%", percent);
+ if (markup)
+ ret += scnprintf(buf + ret, size - ret, "</span>");
+
+ return ret;
+}
+
+static int perf_gtk__get_offset(char *buf, size_t size, struct symbol *sym,
+ struct map *map, struct disasm_line *dl)
+{
+ u64 start = map__rip_2objdump(map, sym->start);
+
+ strcpy(buf, "");
+
+ if (dl->offset == (s64) -1)
+ return 0;
+
+ return scnprintf(buf, size, "%"PRIx64, start + dl->offset);
+}
+
+static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl)
+{
+ int ret = 0;
+ char *line = g_markup_escape_text(dl->line, -1);
+ const char *markup = "<span fgcolor='gray'>";
+
+ strcpy(buf, "");
+
+ if (!line)
+ return 0;
+
+ if (dl->offset != (s64) -1)
+ markup = NULL;
+
+ if (markup)
+ ret += scnprintf(buf, size, "%s", markup);
+ ret += scnprintf(buf + ret, size - ret, "%s", line);
+ if (markup)
+ ret += scnprintf(buf + ret, size - ret, "</span>");
+
+ g_free(line);
+ return ret;
+}
+
+static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
+ struct map *map, struct perf_evsel *evsel,
+ struct hist_browser_timer *hbt __maybe_unused)
+{
+ struct disasm_line *pos, *n;
+ struct annotation *notes;
+ GType col_types[MAX_ANN_COLS];
+ GtkCellRenderer *renderer;
+ GtkListStore *store;
+ GtkWidget *view;
+ int i;
+ char s[512];
+
+ notes = symbol__annotation(sym);
+
+ for (i = 0; i < MAX_ANN_COLS; i++) {
+ col_types[i] = G_TYPE_STRING;
+ }
+ store = gtk_list_store_newv(MAX_ANN_COLS, col_types);
+
+ view = gtk_tree_view_new();
+ renderer = gtk_cell_renderer_text_new();
+
+ for (i = 0; i < MAX_ANN_COLS; i++) {
+ gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+ -1, col_names[i], renderer, "markup",
+ i, NULL);
+ }
+
+ gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
+ g_object_unref(GTK_TREE_MODEL(store));
+
+ list_for_each_entry(pos, &notes->src->source, node) {
+ GtkTreeIter iter;
+ int ret = 0;
+
+ gtk_list_store_append(store, &iter);
+
+ if (perf_evsel__is_group_event(evsel)) {
+ for (i = 0; i < evsel->nr_members; i++) {
+ ret += perf_gtk__get_percent(s + ret,
+ sizeof(s) - ret,
+ sym, pos,
+ evsel->idx + i);
+ ret += scnprintf(s + ret, sizeof(s) - ret, " ");
+ }
+ } else {
+ ret = perf_gtk__get_percent(s, sizeof(s), sym, pos,
+ evsel->idx);
+ }
+
+ if (ret)
+ gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1);
+ if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos))
+ gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1);
+ if (perf_gtk__get_line(s, sizeof(s), pos))
+ gtk_list_store_set(store, &iter, ANN_COL__LINE, s, -1);
+ }
+
+ gtk_container_add(GTK_CONTAINER(window), view);
+
+ list_for_each_entry_safe(pos, n, &notes->src->source, node) {
+ list_del(&pos->node);
+ disasm_line__free(pos);
+ }
+
+ return 0;
+}
+
+int symbol__gtk_annotate(struct symbol *sym, struct map *map,
+ struct perf_evsel *evsel,
+ struct hist_browser_timer *hbt)
+{
+ GtkWidget *window;
+ GtkWidget *notebook;
+ GtkWidget *scrolled_window;
+ GtkWidget *tab_label;
+
+ if (map->dso->annotate_warned)
+ return -1;
+
+ if (symbol__annotate(sym, map, 0) < 0) {
+ ui__error("%s", ui_helpline__current);
+ return -1;
+ }
+
+ if (perf_gtk__is_active_context(pgctx)) {
+ window = pgctx->main_window;
+ notebook = pgctx->notebook;
+ } else {
+ GtkWidget *vbox;
+ GtkWidget *infobar;
+ GtkWidget *statbar;
+
+ signal(SIGSEGV, perf_gtk__signal);
+ signal(SIGFPE, perf_gtk__signal);
+ signal(SIGINT, perf_gtk__signal);
+ signal(SIGQUIT, perf_gtk__signal);
+ signal(SIGTERM, perf_gtk__signal);
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(window), "perf annotate");
+
+ g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
+
+ pgctx = perf_gtk__activate_context(window);
+ if (!pgctx)
+ return -1;
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ notebook = gtk_notebook_new();
+ pgctx->notebook = notebook;
+
+ gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
+
+ infobar = perf_gtk__setup_info_bar();
+ if (infobar) {
+ gtk_box_pack_start(GTK_BOX(vbox), infobar,
+ FALSE, FALSE, 0);
+ }
+
+ statbar = perf_gtk__setup_statusbar();
+ gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
+
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+ }
+
+ scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+ tab_label = gtk_label_new(sym->name);
+
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window,
+ tab_label);
+
+ perf_gtk__annotate_symbol(scrolled_window, sym, map, evsel, hbt);
+ return 0;
+}
+
+void perf_gtk__show_annotations(void)
+{
+ GtkWidget *window;
+
+ if (!perf_gtk__is_active_context(pgctx))
+ return;
+
+ window = pgctx->main_window;
+ gtk_widget_show_all(window);
+
+ perf_gtk__resize_window(window);
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+
+ gtk_main();
+
+ perf_gtk__deactivate_context(&pgctx);
+}
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 253b6219a39e..c95012cdb438 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -8,15 +8,13 @@
#include <signal.h>
-#define MAX_COLUMNS 32
-
-static void perf_gtk__signal(int sig)
+void perf_gtk__signal(int sig)
{
perf_gtk__exit(false);
psignal(sig, "perf");
}
-static void perf_gtk__resize_window(GtkWidget *window)
+void perf_gtk__resize_window(GtkWidget *window)
{
GdkRectangle rect;
GdkScreen *screen;
@@ -36,7 +34,7 @@ static void perf_gtk__resize_window(GtkWidget *window)
gtk_window_resize(GTK_WINDOW(window), width, height);
}
-static const char *perf_gtk__get_percent_color(double percent)
+const char *perf_gtk__get_percent_color(double percent)
{
if (percent >= MIN_RED)
return "<span fgcolor='red'>";
@@ -45,155 +43,8 @@ static const char *perf_gtk__get_percent_color(double percent)
return NULL;
}
-#define HPP__COLOR_FN(_name, _field) \
-static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \
- struct hist_entry *he) \
-{ \
- struct hists *hists = he->hists; \
- double percent = 100.0 * he->stat._field / hists->stats.total_period; \
- const char *markup; \
- int ret = 0; \
- \
- markup = perf_gtk__get_percent_color(percent); \
- if (markup) \
- ret += scnprintf(hpp->buf, hpp->size, "%s", markup); \
- ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%6.2f%%", percent); \
- if (markup) \
- ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); \
- \
- return ret; \
-}
-
-HPP__COLOR_FN(overhead, period)
-HPP__COLOR_FN(overhead_sys, period_sys)
-HPP__COLOR_FN(overhead_us, period_us)
-HPP__COLOR_FN(overhead_guest_sys, period_guest_sys)
-HPP__COLOR_FN(overhead_guest_us, period_guest_us)
-
-#undef HPP__COLOR_FN
-
-void perf_gtk__init_hpp(void)
-{
- perf_hpp__init();
-
- perf_hpp__format[PERF_HPP__OVERHEAD].color =
- perf_gtk__hpp_color_overhead;
- perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
- perf_gtk__hpp_color_overhead_sys;
- perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
- perf_gtk__hpp_color_overhead_us;
- perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
- perf_gtk__hpp_color_overhead_guest_sys;
- perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
- perf_gtk__hpp_color_overhead_guest_us;
-}
-
-static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
-{
- GType col_types[MAX_COLUMNS];
- GtkCellRenderer *renderer;
- struct sort_entry *se;
- GtkListStore *store;
- struct rb_node *nd;
- GtkWidget *view;
- int i, col_idx;
- int nr_cols;
- char s[512];
-
- struct perf_hpp hpp = {
- .buf = s,
- .size = sizeof(s),
- };
-
- nr_cols = 0;
-
- for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
- if (!perf_hpp__format[i].cond)
- continue;
-
- col_types[nr_cols++] = G_TYPE_STRING;
- }
-
- list_for_each_entry(se, &hist_entry__sort_list, list) {
- if (se->elide)
- continue;
-
- col_types[nr_cols++] = G_TYPE_STRING;
- }
-
- store = gtk_list_store_newv(nr_cols, col_types);
-
- view = gtk_tree_view_new();
-
- renderer = gtk_cell_renderer_text_new();
-
- col_idx = 0;
-
- for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
- if (!perf_hpp__format[i].cond)
- continue;
-
- perf_hpp__format[i].header(&hpp);
-
- gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
- -1, s,
- renderer, "markup",
- col_idx++, NULL);
- }
-
- list_for_each_entry(se, &hist_entry__sort_list, list) {
- if (se->elide)
- continue;
-
- gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
- -1, se->se_header,
- renderer, "text",
- col_idx++, NULL);
- }
-
- gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
-
- g_object_unref(GTK_TREE_MODEL(store));
-
- for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
- struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
- GtkTreeIter iter;
-
- if (h->filtered)
- continue;
-
- gtk_list_store_append(store, &iter);
-
- col_idx = 0;
-
- for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
- if (!perf_hpp__format[i].cond)
- continue;
-
- if (perf_hpp__format[i].color)
- perf_hpp__format[i].color(&hpp, h);
- else
- perf_hpp__format[i].entry(&hpp, h);
-
- gtk_list_store_set(store, &iter, col_idx++, s, -1);
- }
-
- list_for_each_entry(se, &hist_entry__sort_list, list) {
- if (se->elide)
- continue;
-
- se->se_snprintf(h, s, ARRAY_SIZE(s),
- hists__col_len(hists, se->se_width_idx));
-
- gtk_list_store_set(store, &iter, col_idx++, s, -1);
- }
- }
-
- gtk_container_add(GTK_CONTAINER(window), view);
-}
-
#ifdef HAVE_GTK_INFO_BAR
-static GtkWidget *perf_gtk__setup_info_bar(void)
+GtkWidget *perf_gtk__setup_info_bar(void)
{
GtkWidget *info_bar;
GtkWidget *label;
@@ -220,7 +71,7 @@ static GtkWidget *perf_gtk__setup_info_bar(void)
}
#endif
-static GtkWidget *perf_gtk__setup_statusbar(void)
+GtkWidget *perf_gtk__setup_statusbar(void)
{
GtkWidget *stbar;
unsigned ctxid;
@@ -234,79 +85,3 @@ static GtkWidget *perf_gtk__setup_statusbar(void)
return stbar;
}
-
-int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
- const char *help,
- struct hist_browser_timer *hbt __maybe_unused)
-{
- struct perf_evsel *pos;
- GtkWidget *vbox;
- GtkWidget *notebook;
- GtkWidget *info_bar;
- GtkWidget *statbar;
- GtkWidget *window;
-
- signal(SIGSEGV, perf_gtk__signal);
- signal(SIGFPE, perf_gtk__signal);
- signal(SIGINT, perf_gtk__signal);
- signal(SIGQUIT, perf_gtk__signal);
- signal(SIGTERM, perf_gtk__signal);
-
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-
- gtk_window_set_title(GTK_WINDOW(window), "perf report");
-
- g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
-
- pgctx = perf_gtk__activate_context(window);
- if (!pgctx)
- return -1;
-
- vbox = gtk_vbox_new(FALSE, 0);
-
- notebook = gtk_notebook_new();
-
- list_for_each_entry(pos, &evlist->entries, node) {
- struct hists *hists = &pos->hists;
- const char *evname = perf_evsel__name(pos);
- GtkWidget *scrolled_window;
- GtkWidget *tab_label;
-
- scrolled_window = gtk_scrolled_window_new(NULL, NULL);
-
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
- GTK_POLICY_AUTOMATIC,
- GTK_POLICY_AUTOMATIC);
-
- perf_gtk__show_hists(scrolled_window, hists);
-
- tab_label = gtk_label_new(evname);
-
- gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
- }
-
- gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
-
- info_bar = perf_gtk__setup_info_bar();
- if (info_bar)
- gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
-
- statbar = perf_gtk__setup_statusbar();
- gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
-
- gtk_container_add(GTK_CONTAINER(window), vbox);
-
- gtk_widget_show_all(window);
-
- perf_gtk__resize_window(window);
-
- gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
-
- ui_helpline__push(help);
-
- gtk_main();
-
- perf_gtk__deactivate_context(&pgctx);
-
- return 0;
-}
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
index 856320e2cc05..3d96785ef155 100644
--- a/tools/perf/ui/gtk/gtk.h
+++ b/tools/perf/ui/gtk/gtk.h
@@ -10,6 +10,7 @@
struct perf_gtk_context {
GtkWidget *main_window;
+ GtkWidget *notebook;
#ifdef HAVE_GTK_INFO_BAR
GtkWidget *info_bar;
@@ -33,7 +34,14 @@ void perf_gtk__init_helpline(void);
void perf_gtk__init_progress(void);
void perf_gtk__init_hpp(void);
-#ifndef HAVE_GTK_INFO_BAR
+void perf_gtk__signal(int sig);
+void perf_gtk__resize_window(GtkWidget *window);
+const char *perf_gtk__get_percent_color(double percent);
+GtkWidget *perf_gtk__setup_statusbar(void);
+
+#ifdef HAVE_GTK_INFO_BAR
+GtkWidget *perf_gtk__setup_info_bar(void);
+#else
static inline GtkWidget *perf_gtk__setup_info_bar(void)
{
return NULL;
diff --git a/tools/perf/ui/gtk/helpline.c b/tools/perf/ui/gtk/helpline.c
index 5db4432ff12a..3388cbd12186 100644
--- a/tools/perf/ui/gtk/helpline.c
+++ b/tools/perf/ui/gtk/helpline.c
@@ -24,17 +24,7 @@ static void gtk_helpline_push(const char *msg)
pgctx->statbar_ctx_id, msg);
}
-static struct ui_helpline gtk_helpline_fns = {
- .pop = gtk_helpline_pop,
- .push = gtk_helpline_push,
-};
-
-void perf_gtk__init_helpline(void)
-{
- helpline_fns = &gtk_helpline_fns;
-}
-
-int perf_gtk__show_helpline(const char *fmt, va_list ap)
+static int gtk_helpline_show(const char *fmt, va_list ap)
{
int ret;
char *ptr;
@@ -54,3 +44,14 @@ int perf_gtk__show_helpline(const char *fmt, va_list ap)
return ret;
}
+
+static struct ui_helpline gtk_helpline_fns = {
+ .pop = gtk_helpline_pop,
+ .push = gtk_helpline_push,
+ .show = gtk_helpline_show,
+};
+
+void perf_gtk__init_helpline(void)
+{
+ helpline_fns = &gtk_helpline_fns;
+}
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
new file mode 100644
index 000000000000..9708dd5fb8f3
--- /dev/null
+++ b/tools/perf/ui/gtk/hists.c
@@ -0,0 +1,316 @@
+#include "../evlist.h"
+#include "../cache.h"
+#include "../evsel.h"
+#include "../sort.h"
+#include "../hist.h"
+#include "../helpline.h"
+#include "gtk.h"
+
+#define MAX_COLUMNS 32
+
+static int __percent_color_snprintf(char *buf, size_t size, double percent)
+{
+ int ret = 0;
+ const char *markup;
+
+ markup = perf_gtk__get_percent_color(percent);
+ if (markup)
+ ret += scnprintf(buf, size, markup);
+
+ ret += scnprintf(buf + ret, size - ret, " %6.2f%%", percent);
+
+ if (markup)
+ ret += scnprintf(buf + ret, size - ret, "</span>");
+
+ return ret;
+}
+
+
+static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
+ u64 (*get_field)(struct hist_entry *))
+{
+ int ret;
+ double percent = 0.0;
+ struct hists *hists = he->hists;
+ struct perf_evsel *evsel = hists_to_evsel(hists);
+
+ if (hists->stats.total_period)
+ percent = 100.0 * get_field(he) / hists->stats.total_period;
+
+ ret = __percent_color_snprintf(hpp->buf, hpp->size, percent);
+
+ if (perf_evsel__is_group_event(evsel)) {
+ int prev_idx, idx_delta;
+ struct hist_entry *pair;
+ int nr_members = evsel->nr_members;
+
+ prev_idx = perf_evsel__group_idx(evsel);
+
+ list_for_each_entry(pair, &he->pairs.head, pairs.node) {
+ u64 period = get_field(pair);
+ u64 total = pair->hists->stats.total_period;
+
+ evsel = hists_to_evsel(pair->hists);
+ idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
+
+ while (idx_delta--) {
+ /*
+ * zero-fill group members in the middle which
+ * have no sample
+ */
+ ret += __percent_color_snprintf(hpp->buf + ret,
+ hpp->size - ret,
+ 0.0);
+ }
+
+ percent = 100.0 * period / total;
+ ret += __percent_color_snprintf(hpp->buf + ret,
+ hpp->size - ret,
+ percent);
+
+ prev_idx = perf_evsel__group_idx(evsel);
+ }
+
+ idx_delta = nr_members - prev_idx - 1;
+
+ while (idx_delta--) {
+ /*
+ * zero-fill group members at last which have no sample
+ */
+ ret += __percent_color_snprintf(hpp->buf + ret,
+ hpp->size - ret,
+ 0.0);
+ }
+ }
+ return ret;
+}
+
+#define __HPP_COLOR_PERCENT_FN(_type, _field) \
+static u64 he_get_##_field(struct hist_entry *he) \
+{ \
+ return he->stat._field; \
+} \
+ \
+static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp, \
+ struct hist_entry *he) \
+{ \
+ return __hpp__color_fmt(hpp, he, he_get_##_field); \
+}
+
+__HPP_COLOR_PERCENT_FN(overhead, period)
+__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
+__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
+__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
+__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
+
+#undef __HPP_COLOR_PERCENT_FN
+
+
+void perf_gtk__init_hpp(void)
+{
+ perf_hpp__column_enable(PERF_HPP__OVERHEAD);
+
+ perf_hpp__init();
+
+ perf_hpp__format[PERF_HPP__OVERHEAD].color =
+ perf_gtk__hpp_color_overhead;
+ perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
+ perf_gtk__hpp_color_overhead_sys;
+ perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
+ perf_gtk__hpp_color_overhead_us;
+ perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
+ perf_gtk__hpp_color_overhead_guest_sys;
+ perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
+ perf_gtk__hpp_color_overhead_guest_us;
+}
+
+static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
+ float min_pcnt)
+{
+ struct perf_hpp_fmt *fmt;
+ GType col_types[MAX_COLUMNS];
+ GtkCellRenderer *renderer;
+ struct sort_entry *se;
+ GtkListStore *store;
+ struct rb_node *nd;
+ GtkWidget *view;
+ int col_idx;
+ int nr_cols;
+ char s[512];
+
+ struct perf_hpp hpp = {
+ .buf = s,
+ .size = sizeof(s),
+ .ptr = hists_to_evsel(hists),
+ };
+
+ nr_cols = 0;
+
+ perf_hpp__for_each_format(fmt)
+ col_types[nr_cols++] = G_TYPE_STRING;
+
+ list_for_each_entry(se, &hist_entry__sort_list, list) {
+ if (se->elide)
+ continue;
+
+ col_types[nr_cols++] = G_TYPE_STRING;
+ }
+
+ store = gtk_list_store_newv(nr_cols, col_types);
+
+ view = gtk_tree_view_new();
+
+ renderer = gtk_cell_renderer_text_new();
+
+ col_idx = 0;
+
+ perf_hpp__for_each_format(fmt) {
+ fmt->header(&hpp);
+
+ gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+ -1, ltrim(s),
+ renderer, "markup",
+ col_idx++, NULL);
+ }
+
+ list_for_each_entry(se, &hist_entry__sort_list, list) {
+ if (se->elide)
+ continue;
+
+ gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+ -1, se->se_header,
+ renderer, "text",
+ col_idx++, NULL);
+ }
+
+ gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
+
+ g_object_unref(GTK_TREE_MODEL(store));
+
+ for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
+ struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+ GtkTreeIter iter;
+ float percent = h->stat.period * 100.0 /
+ hists->stats.total_period;
+
+ if (h->filtered)
+ continue;
+
+ if (percent < min_pcnt)
+ continue;
+
+ gtk_list_store_append(store, &iter);
+
+ col_idx = 0;
+
+ perf_hpp__for_each_format(fmt) {
+ if (fmt->color)
+ fmt->color(&hpp, h);
+ else
+ fmt->entry(&hpp, h);
+
+ gtk_list_store_set(store, &iter, col_idx++, s, -1);
+ }
+
+ list_for_each_entry(se, &hist_entry__sort_list, list) {
+ if (se->elide)
+ continue;
+
+ se->se_snprintf(h, s, ARRAY_SIZE(s),
+ hists__col_len(hists, se->se_width_idx));
+
+ gtk_list_store_set(store, &iter, col_idx++, s, -1);
+ }
+ }
+
+ gtk_container_add(GTK_CONTAINER(window), view);
+}
+
+int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
+ const char *help,
+ struct hist_browser_timer *hbt __maybe_unused,
+ float min_pcnt)
+{
+ struct perf_evsel *pos;
+ GtkWidget *vbox;
+ GtkWidget *notebook;
+ GtkWidget *info_bar;
+ GtkWidget *statbar;
+ GtkWidget *window;
+
+ signal(SIGSEGV, perf_gtk__signal);
+ signal(SIGFPE, perf_gtk__signal);
+ signal(SIGINT, perf_gtk__signal);
+ signal(SIGQUIT, perf_gtk__signal);
+ signal(SIGTERM, perf_gtk__signal);
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+ gtk_window_set_title(GTK_WINDOW(window), "perf report");
+
+ g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
+
+ pgctx = perf_gtk__activate_context(window);
+ if (!pgctx)
+ return -1;
+
+ vbox = gtk_vbox_new(FALSE, 0);
+
+ notebook = gtk_notebook_new();
+
+ gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
+
+ info_bar = perf_gtk__setup_info_bar();
+ if (info_bar)
+ gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
+
+ statbar = perf_gtk__setup_statusbar();
+ gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
+
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+
+ list_for_each_entry(pos, &evlist->entries, node) {
+ struct hists *hists = &pos->hists;
+ const char *evname = perf_evsel__name(pos);
+ GtkWidget *scrolled_window;
+ GtkWidget *tab_label;
+ char buf[512];
+ size_t size = sizeof(buf);
+
+ if (symbol_conf.event_group) {
+ if (!perf_evsel__is_group_leader(pos))
+ continue;
+
+ if (pos->nr_members > 1) {
+ perf_evsel__group_desc(pos, buf, size);
+ evname = buf;
+ }
+ }
+
+ scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+
+ perf_gtk__show_hists(scrolled_window, hists, min_pcnt);
+
+ tab_label = gtk_label_new(evname);
+
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
+ }
+
+ gtk_widget_show_all(window);
+
+ perf_gtk__resize_window(window);
+
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+
+ ui_helpline__push(help);
+
+ gtk_main();
+
+ perf_gtk__deactivate_context(&pgctx);
+
+ return 0;
+}
diff --git a/tools/perf/ui/helpline.c b/tools/perf/ui/helpline.c
index a49bcf3c190b..700fb3cfa1c7 100644
--- a/tools/perf/ui/helpline.c
+++ b/tools/perf/ui/helpline.c
@@ -16,9 +16,16 @@ static void nop_helpline__push(const char *msg __maybe_unused)
{
}
+static int nop_helpline__show(const char *fmt __maybe_unused,
+ va_list ap __maybe_unused)
+{
+ return 0;
+}
+
static struct ui_helpline default_helpline_fns = {
.pop = nop_helpline__pop,
.push = nop_helpline__push,
+ .show = nop_helpline__show,
};
struct ui_helpline *helpline_fns = &default_helpline_fns;
@@ -59,3 +66,8 @@ void ui_helpline__puts(const char *msg)
ui_helpline__pop();
ui_helpline__push(msg);
}
+
+int ui_helpline__vshow(const char *fmt, va_list ap)
+{
+ return helpline_fns->show(fmt, ap);
+}
diff --git a/tools/perf/ui/helpline.h b/tools/perf/ui/helpline.h
index baa28a4d16b9..46181f4fc07e 100644
--- a/tools/perf/ui/helpline.h
+++ b/tools/perf/ui/helpline.h
@@ -9,6 +9,7 @@
struct ui_helpline {
void (*pop)(void);
void (*push)(const char *msg);
+ int (*show)(const char *fmt, va_list ap);
};
extern struct ui_helpline *helpline_fns;
@@ -20,28 +21,9 @@ void ui_helpline__push(const char *msg);
void ui_helpline__vpush(const char *fmt, va_list ap);
void ui_helpline__fpush(const char *fmt, ...);
void ui_helpline__puts(const char *msg);
+int ui_helpline__vshow(const char *fmt, va_list ap);
extern char ui_helpline__current[512];
-
-#ifdef NEWT_SUPPORT
extern char ui_helpline__last_msg[];
-int ui_helpline__show_help(const char *format, va_list ap);
-#else
-static inline int ui_helpline__show_help(const char *format __maybe_unused,
- va_list ap __maybe_unused)
-{
- return 0;
-}
-#endif /* NEWT_SUPPORT */
-
-#ifdef GTK2_SUPPORT
-int perf_gtk__show_helpline(const char *format, va_list ap);
-#else
-static inline int perf_gtk__show_helpline(const char *format __maybe_unused,
- va_list ap __maybe_unused)
-{
- return 0;
-}
-#endif /* GTK2_SUPPORT */
#endif /* _PERF_UI_HELPLINE_H_ */
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index aa84130024d5..4bf91b09d62d 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -3,151 +3,160 @@
#include "../util/hist.h"
#include "../util/util.h"
#include "../util/sort.h"
-
+#include "../util/evsel.h"
/* hist period print (hpp) functions */
-static int hpp__header_overhead(struct perf_hpp *hpp)
-{
- return scnprintf(hpp->buf, hpp->size, "Overhead");
-}
-
-static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused)
-{
- return 8;
-}
-
-static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
-{
- struct hists *hists = he->hists;
- double percent = 100.0 * he->stat.period / hists->stats.total_period;
-
- return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
-}
-
-static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
-{
- struct hists *hists = he->hists;
- double percent = 100.0 * he->stat.period / hists->stats.total_period;
- const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
-
- return scnprintf(hpp->buf, hpp->size, fmt, percent);
-}
-
-static int hpp__header_overhead_sys(struct perf_hpp *hpp)
-{
- const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
-
- return scnprintf(hpp->buf, hpp->size, fmt, "sys");
-}
-
-static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused)
-{
- return 7;
-}
-
-static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
-{
- struct hists *hists = he->hists;
- double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
-
- return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
-}
-
-static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
-{
- struct hists *hists = he->hists;
- double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
- const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
-
- return scnprintf(hpp->buf, hpp->size, fmt, percent);
-}
-static int hpp__header_overhead_us(struct perf_hpp *hpp)
-{
- const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
-
- return scnprintf(hpp->buf, hpp->size, fmt, "user");
-}
-
-static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused)
-{
- return 7;
-}
+typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...);
-static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
+static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
+ u64 (*get_field)(struct hist_entry *),
+ const char *fmt, hpp_snprint_fn print_fn,
+ bool fmt_percent)
{
+ int ret;
struct hists *hists = he->hists;
- double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
+ struct perf_evsel *evsel = hists_to_evsel(hists);
- return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
-}
+ if (fmt_percent) {
+ double percent = 0.0;
-static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
-{
- struct hists *hists = he->hists;
- double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
- const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
+ if (hists->stats.total_period)
+ percent = 100.0 * get_field(he) /
+ hists->stats.total_period;
- return scnprintf(hpp->buf, hpp->size, fmt, percent);
-}
+ ret = print_fn(hpp->buf, hpp->size, fmt, percent);
+ } else
+ ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he));
-static int hpp__header_overhead_guest_sys(struct perf_hpp *hpp)
-{
- return scnprintf(hpp->buf, hpp->size, "guest sys");
-}
+ if (perf_evsel__is_group_event(evsel)) {
+ int prev_idx, idx_delta;
+ struct hist_entry *pair;
+ int nr_members = evsel->nr_members;
-static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused)
-{
- return 9;
-}
+ prev_idx = perf_evsel__group_idx(evsel);
-static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp,
- struct hist_entry *he)
-{
- struct hists *hists = he->hists;
- double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
+ list_for_each_entry(pair, &he->pairs.head, pairs.node) {
+ u64 period = get_field(pair);
+ u64 total = pair->hists->stats.total_period;
- return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
-}
+ if (!total)
+ continue;
-static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp,
- struct hist_entry *he)
-{
- struct hists *hists = he->hists;
- double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
- const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
+ evsel = hists_to_evsel(pair->hists);
+ idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
- return scnprintf(hpp->buf, hpp->size, fmt, percent);
-}
+ while (idx_delta--) {
+ /*
+ * zero-fill group members in the middle which
+ * have no sample
+ */
+ ret += print_fn(hpp->buf + ret, hpp->size - ret,
+ fmt, 0);
+ }
-static int hpp__header_overhead_guest_us(struct perf_hpp *hpp)
-{
- return scnprintf(hpp->buf, hpp->size, "guest usr");
-}
+ if (fmt_percent)
+ ret += print_fn(hpp->buf + ret, hpp->size - ret,
+ fmt, 100.0 * period / total);
+ else
+ ret += print_fn(hpp->buf + ret, hpp->size - ret,
+ fmt, period);
-static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused)
-{
- return 9;
-}
+ prev_idx = perf_evsel__group_idx(evsel);
+ }
-static int hpp__color_overhead_guest_us(struct perf_hpp *hpp,
- struct hist_entry *he)
-{
- struct hists *hists = he->hists;
- double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
+ idx_delta = nr_members - prev_idx - 1;
- return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
+ while (idx_delta--) {
+ /*
+ * zero-fill group members at last which have no sample
+ */
+ ret += print_fn(hpp->buf + ret, hpp->size - ret,
+ fmt, 0);
+ }
+ }
+ return ret;
}
-static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp,
- struct hist_entry *he)
-{
- struct hists *hists = he->hists;
- double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
- const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
+#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
+static int hpp__header_##_type(struct perf_hpp *hpp) \
+{ \
+ int len = _min_width; \
+ \
+ if (symbol_conf.event_group) { \
+ struct perf_evsel *evsel = hpp->ptr; \
+ \
+ len = max(len, evsel->nr_members * _unit_width); \
+ } \
+ return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \
+}
+
+#define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \
+static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \
+{ \
+ int len = _min_width; \
+ \
+ if (symbol_conf.event_group) { \
+ struct perf_evsel *evsel = hpp->ptr; \
+ \
+ len = max(len, evsel->nr_members * _unit_width); \
+ } \
+ return len; \
+}
+
+#define __HPP_COLOR_PERCENT_FN(_type, _field) \
+static u64 he_get_##_field(struct hist_entry *he) \
+{ \
+ return he->stat._field; \
+} \
+ \
+static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
+{ \
+ return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \
+ (hpp_snprint_fn)percent_color_snprintf, true); \
+}
+
+#define __HPP_ENTRY_PERCENT_FN(_type, _field) \
+static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
+{ \
+ const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
+ return __hpp__fmt(hpp, he, he_get_##_field, fmt, \
+ scnprintf, true); \
+}
+
+#define __HPP_ENTRY_RAW_FN(_type, _field) \
+static u64 he_get_raw_##_field(struct hist_entry *he) \
+{ \
+ return he->stat._field; \
+} \
+ \
+static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
+{ \
+ const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \
+ return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \
+}
+
+#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \
+__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
+__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
+__HPP_COLOR_PERCENT_FN(_type, _field) \
+__HPP_ENTRY_PERCENT_FN(_type, _field)
+
+#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \
+__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
+__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
+__HPP_ENTRY_RAW_FN(_type, _field)
+
+
+HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8)
+HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8)
+HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8)
+HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8)
+HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
+
+HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
+HPP_RAW_FNS(period, "Period", period, 12, 12)
- return scnprintf(hpp->buf, hpp->size, fmt, percent);
-}
static int hpp__header_baseline(struct perf_hpp *hpp)
{
@@ -179,7 +188,7 @@ static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
{
double percent = baseline_percent(he);
- if (hist_entry__has_pairs(he))
+ if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
else
return scnprintf(hpp->buf, hpp->size, " ");
@@ -196,44 +205,6 @@ static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
return scnprintf(hpp->buf, hpp->size, " ");
}
-static int hpp__header_samples(struct perf_hpp *hpp)
-{
- const char *fmt = symbol_conf.field_sep ? "%s" : "%11s";
-
- return scnprintf(hpp->buf, hpp->size, fmt, "Samples");
-}
-
-static int hpp__width_samples(struct perf_hpp *hpp __maybe_unused)
-{
- return 11;
-}
-
-static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he)
-{
- const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64;
-
- return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events);
-}
-
-static int hpp__header_period(struct perf_hpp *hpp)
-{
- const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
-
- return scnprintf(hpp->buf, hpp->size, fmt, "Period");
-}
-
-static int hpp__width_period(struct perf_hpp *hpp __maybe_unused)
-{
- return 12;
-}
-
-static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he)
-{
- const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
-
- return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period);
-}
-
static int hpp__header_period_baseline(struct perf_hpp *hpp)
{
const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
@@ -254,6 +225,7 @@ static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *h
return scnprintf(hpp->buf, hpp->size, fmt, period);
}
+
static int hpp__header_delta(struct perf_hpp *hpp)
{
const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
@@ -268,14 +240,18 @@ static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
{
+ struct hist_entry *pair = hist_entry__next_pair(he);
const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
char buf[32] = " ";
- double diff;
+ double diff = 0.0;
- if (he->diff.computed)
- diff = he->diff.period_ratio_delta;
- else
- diff = perf_diff__compute_delta(he);
+ if (pair) {
+ if (he->diff.computed)
+ diff = he->diff.period_ratio_delta;
+ else
+ diff = perf_diff__compute_delta(he, pair);
+ } else
+ diff = perf_diff__period_percent(he, he->stat.period);
if (fabs(diff) >= 0.01)
scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
@@ -297,14 +273,17 @@ static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
{
+ struct hist_entry *pair = hist_entry__next_pair(he);
const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
char buf[32] = " ";
- double ratio;
+ double ratio = 0.0;
- if (he->diff.computed)
- ratio = he->diff.period_ratio;
- else
- ratio = perf_diff__compute_ratio(he);
+ if (pair) {
+ if (he->diff.computed)
+ ratio = he->diff.period_ratio;
+ else
+ ratio = perf_diff__compute_ratio(he, pair);
+ }
if (ratio > 0.0)
scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
@@ -326,14 +305,17 @@ static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
{
+ struct hist_entry *pair = hist_entry__next_pair(he);
const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
char buf[32] = " ";
- s64 wdiff;
+ s64 wdiff = 0;
- if (he->diff.computed)
- wdiff = he->diff.wdiff;
- else
- wdiff = perf_diff__compute_wdiff(he);
+ if (pair) {
+ if (he->diff.computed)
+ wdiff = he->diff.wdiff;
+ else
+ wdiff = perf_diff__compute_wdiff(he, pair);
+ }
if (wdiff != 0)
scnprintf(buf, sizeof(buf), "%14ld", wdiff);
@@ -341,30 +323,6 @@ static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
return scnprintf(hpp->buf, hpp->size, fmt, buf);
}
-static int hpp__header_displ(struct perf_hpp *hpp)
-{
- return scnprintf(hpp->buf, hpp->size, "Displ.");
-}
-
-static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused)
-{
- return 6;
-}
-
-static int hpp__entry_displ(struct perf_hpp *hpp,
- struct hist_entry *he)
-{
- struct hist_entry *pair = hist_entry__next_pair(he);
- long displacement = pair ? pair->position - he->position : 0;
- const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s";
- char buf[32] = " ";
-
- if (displacement)
- scnprintf(buf, sizeof(buf), "%+4ld", displacement);
-
- return scnprintf(hpp->buf, hpp->size, fmt, buf);
-}
-
static int hpp__header_formula(struct perf_hpp *hpp)
{
const char *fmt = symbol_conf.field_sep ? "%s" : "%70s";
@@ -379,67 +337,91 @@ static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
{
+ struct hist_entry *pair = hist_entry__next_pair(he);
const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s";
char buf[96] = " ";
- perf_diff__formula(buf, sizeof(buf), he);
+ if (pair)
+ perf_diff__formula(he, pair, buf, sizeof(buf));
+
return scnprintf(hpp->buf, hpp->size, fmt, buf);
}
-#define HPP__COLOR_PRINT_FNS(_name) \
- .header = hpp__header_ ## _name, \
- .width = hpp__width_ ## _name, \
- .color = hpp__color_ ## _name, \
- .entry = hpp__entry_ ## _name
+#define HPP__COLOR_PRINT_FNS(_name) \
+ { \
+ .header = hpp__header_ ## _name, \
+ .width = hpp__width_ ## _name, \
+ .color = hpp__color_ ## _name, \
+ .entry = hpp__entry_ ## _name \
+ }
-#define HPP__PRINT_FNS(_name) \
- .header = hpp__header_ ## _name, \
- .width = hpp__width_ ## _name, \
- .entry = hpp__entry_ ## _name
+#define HPP__PRINT_FNS(_name) \
+ { \
+ .header = hpp__header_ ## _name, \
+ .width = hpp__width_ ## _name, \
+ .entry = hpp__entry_ ## _name \
+ }
struct perf_hpp_fmt perf_hpp__format[] = {
- { .cond = false, HPP__COLOR_PRINT_FNS(baseline) },
- { .cond = true, HPP__COLOR_PRINT_FNS(overhead) },
- { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) },
- { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) },
- { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) },
- { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) },
- { .cond = false, HPP__PRINT_FNS(samples) },
- { .cond = false, HPP__PRINT_FNS(period) },
- { .cond = false, HPP__PRINT_FNS(period_baseline) },
- { .cond = false, HPP__PRINT_FNS(delta) },
- { .cond = false, HPP__PRINT_FNS(ratio) },
- { .cond = false, HPP__PRINT_FNS(wdiff) },
- { .cond = false, HPP__PRINT_FNS(displ) },
- { .cond = false, HPP__PRINT_FNS(formula) }
+ HPP__COLOR_PRINT_FNS(baseline),
+ HPP__COLOR_PRINT_FNS(overhead),
+ HPP__COLOR_PRINT_FNS(overhead_sys),
+ HPP__COLOR_PRINT_FNS(overhead_us),
+ HPP__COLOR_PRINT_FNS(overhead_guest_sys),
+ HPP__COLOR_PRINT_FNS(overhead_guest_us),
+ HPP__PRINT_FNS(samples),
+ HPP__PRINT_FNS(period),
+ HPP__PRINT_FNS(period_baseline),
+ HPP__PRINT_FNS(delta),
+ HPP__PRINT_FNS(ratio),
+ HPP__PRINT_FNS(wdiff),
+ HPP__PRINT_FNS(formula)
};
+LIST_HEAD(perf_hpp__list);
+
+
#undef HPP__COLOR_PRINT_FNS
#undef HPP__PRINT_FNS
+#undef HPP_PERCENT_FNS
+#undef HPP_RAW_FNS
+
+#undef __HPP_HEADER_FN
+#undef __HPP_WIDTH_FN
+#undef __HPP_COLOR_PERCENT_FN
+#undef __HPP_ENTRY_PERCENT_FN
+#undef __HPP_ENTRY_RAW_FN
+
+
void perf_hpp__init(void)
{
if (symbol_conf.show_cpu_utilization) {
- perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true;
- perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true;
+ perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS);
+ perf_hpp__column_enable(PERF_HPP__OVERHEAD_US);
if (perf_guest) {
- perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true;
- perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true;
+ perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS);
+ perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US);
}
}
if (symbol_conf.show_nr_samples)
- perf_hpp__format[PERF_HPP__SAMPLES].cond = true;
+ perf_hpp__column_enable(PERF_HPP__SAMPLES);
if (symbol_conf.show_total_period)
- perf_hpp__format[PERF_HPP__PERIOD].cond = true;
+ perf_hpp__column_enable(PERF_HPP__PERIOD);
+}
+
+void perf_hpp__column_register(struct perf_hpp_fmt *format)
+{
+ list_add_tail(&format->list, &perf_hpp__list);
}
-void perf_hpp__column_enable(unsigned col, bool enable)
+void perf_hpp__column_enable(unsigned col)
{
BUG_ON(col >= PERF_HPP__MAX_INDEX);
- perf_hpp__format[col].cond = enable;
+ perf_hpp__column_register(&perf_hpp__format[col]);
}
static inline void advance_hpp(struct perf_hpp *hpp, int inc)
@@ -452,27 +434,29 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
bool color)
{
const char *sep = symbol_conf.field_sep;
+ struct perf_hpp_fmt *fmt;
char *start = hpp->buf;
- int i, ret;
+ int ret;
bool first = true;
if (symbol_conf.exclude_other && !he->parent)
return 0;
- for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
- if (!perf_hpp__format[i].cond)
- continue;
-
+ perf_hpp__for_each_format(fmt) {
+ /*
+ * If there's no field_sep, we still need
+ * to display initial ' '.
+ */
if (!sep || !first) {
ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
advance_hpp(hpp, ret);
+ } else
first = false;
- }
- if (color && perf_hpp__format[i].color)
- ret = perf_hpp__format[i].color(hpp, he);
+ if (color && fmt->color)
+ ret = fmt->color(hpp, he);
else
- ret = perf_hpp__format[i].entry(hpp, he);
+ ret = fmt->entry(hpp, he);
advance_hpp(hpp, ret);
}
@@ -504,16 +488,18 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
*/
unsigned int hists__sort_list_width(struct hists *hists)
{
+ struct perf_hpp_fmt *fmt;
struct sort_entry *se;
- int i, ret = 0;
+ int i = 0, ret = 0;
+ struct perf_hpp dummy_hpp = {
+ .ptr = hists_to_evsel(hists),
+ };
- for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
- if (!perf_hpp__format[i].cond)
- continue;
+ perf_hpp__for_each_format(fmt) {
if (i)
ret += 2;
- ret += perf_hpp__format[i].width(NULL);
+ ret += fmt->width(&dummy_hpp);
}
list_for_each_entry(se, &hist_entry__sort_list, list)
diff --git a/tools/perf/ui/keysyms.h b/tools/perf/ui/keysyms.h
index 809eca5707fa..65092d576b4e 100644
--- a/tools/perf/ui/keysyms.h
+++ b/tools/perf/ui/keysyms.h
@@ -23,5 +23,6 @@
#define K_TIMER -1
#define K_ERROR -2
#define K_RESIZE -3
+#define K_SWITCH_INPUT_DATA -4
#endif /* _PERF_KEYSYMS_H_ */
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
index ebb4cc107876..ae6a789cb0f6 100644
--- a/tools/perf/ui/setup.c
+++ b/tools/perf/ui/setup.c
@@ -8,7 +8,7 @@ pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
void setup_browser(bool fallback_to_pager)
{
- if (!isatty(1) || dump_trace)
+ if (use_browser < 2 && (!isatty(1) || dump_trace))
use_browser = 0;
/* default to TUI */
@@ -30,6 +30,7 @@ void setup_browser(bool fallback_to_pager)
if (fallback_to_pager)
setup_pager();
+ perf_hpp__column_enable(PERF_HPP__OVERHEAD);
perf_hpp__init();
break;
}
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index f0ee204f99bb..ae7a75432249 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -3,6 +3,7 @@
#include "../../util/util.h"
#include "../../util/hist.h"
#include "../../util/sort.h"
+#include "../../util/evsel.h"
static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -333,19 +334,21 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
}
size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
- int max_cols, FILE *fp)
+ int max_cols, float min_pcnt, FILE *fp)
{
+ struct perf_hpp_fmt *fmt;
struct sort_entry *se;
struct rb_node *nd;
size_t ret = 0;
unsigned int width;
const char *sep = symbol_conf.field_sep;
const char *col_width = symbol_conf.col_width_list_str;
- int idx, nr_rows = 0;
+ int nr_rows = 0;
char bf[96];
struct perf_hpp dummy_hpp = {
.buf = bf,
.size = sizeof(bf),
+ .ptr = hists_to_evsel(hists),
};
bool first = true;
@@ -355,16 +358,14 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
goto print_entries;
fprintf(fp, "# ");
- for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
- if (!perf_hpp__format[idx].cond)
- continue;
+ perf_hpp__for_each_format(fmt) {
if (!first)
fprintf(fp, "%s", sep ?: " ");
else
first = false;
- perf_hpp__format[idx].header(&dummy_hpp);
+ fmt->header(&dummy_hpp);
fprintf(fp, "%s", bf);
}
@@ -400,18 +401,16 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
first = true;
fprintf(fp, "# ");
- for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
- unsigned int i;
- if (!perf_hpp__format[idx].cond)
- continue;
+ perf_hpp__for_each_format(fmt) {
+ unsigned int i;
if (!first)
fprintf(fp, "%s", sep ?: " ");
else
first = false;
- width = perf_hpp__format[idx].width(&dummy_hpp);
+ width = fmt->width(&dummy_hpp);
for (i = 0; i < width; i++)
fprintf(fp, ".");
}
@@ -441,10 +440,15 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
print_entries:
for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+ float percent = h->stat.period * 100.0 /
+ hists->stats.total_period;
if (h->filtered)
continue;
+ if (percent < min_pcnt)
+ continue;
+
ret += hist_entry__fprintf(h, max_cols, hists, fp);
if (max_rows && ++nr_rows >= max_rows)
@@ -462,7 +466,7 @@ out:
return ret;
}
-size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
+size_t events_stats__fprintf(struct events_stats *stats, FILE *fp)
{
int i;
size_t ret = 0;
@@ -470,7 +474,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
const char *name;
- if (hists->stats.nr_events[i] == 0)
+ if (stats->nr_events[i] == 0)
continue;
name = perf_event__name(i);
@@ -478,7 +482,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
continue;
ret += fprintf(fp, "%16s events: %10d\n", name,
- hists->stats.nr_events[i]);
+ stats->nr_events[i]);
}
return ret;
diff --git a/tools/perf/ui/tui/helpline.c b/tools/perf/ui/tui/helpline.c
index 2884d2f41e33..1c8b9afd5d6e 100644
--- a/tools/perf/ui/tui/helpline.c
+++ b/tools/perf/ui/tui/helpline.c
@@ -8,6 +8,8 @@
#include "../ui.h"
#include "../libslang.h"
+char ui_helpline__last_msg[1024];
+
static void tui_helpline__pop(void)
{
}
@@ -23,20 +25,7 @@ static void tui_helpline__push(const char *msg)
strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0';
}
-struct ui_helpline tui_helpline_fns = {
- .pop = tui_helpline__pop,
- .push = tui_helpline__push,
-};
-
-void ui_helpline__init(void)
-{
- helpline_fns = &tui_helpline_fns;
- ui_helpline__puts(" ");
-}
-
-char ui_helpline__last_msg[1024];
-
-int ui_helpline__show_help(const char *format, va_list ap)
+static int tui_helpline__show(const char *format, va_list ap)
{
int ret;
static int backlog;
@@ -55,3 +44,15 @@ int ui_helpline__show_help(const char *format, va_list ap)
return ret;
}
+
+struct ui_helpline tui_helpline_fns = {
+ .pop = tui_helpline__pop,
+ .push = tui_helpline__push,
+ .show = tui_helpline__show,
+};
+
+void ui_helpline__init(void)
+{
+ helpline_fns = &tui_helpline_fns;
+ ui_helpline__puts(" ");
+}
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c
index 81efa192e86c..b9401482d110 100644
--- a/tools/perf/ui/tui/setup.c
+++ b/tools/perf/ui/tui/setup.c
@@ -1,4 +1,3 @@
-#include <newt.h>
#include <signal.h>
#include <stdbool.h>
@@ -88,13 +87,6 @@ int ui__getch(int delay_secs)
return SLkp_getkey();
}
-static void newt_suspend(void *d __maybe_unused)
-{
- newtSuspend();
- raise(SIGTSTP);
- newtResume();
-}
-
static void ui__signal(int sig)
{
ui__exit(false);
@@ -106,7 +98,17 @@ int ui__init(void)
{
int err;
- newtInit();
+ SLutf8_enable(-1);
+ SLtt_get_terminfo();
+ SLtt_get_screen_size();
+
+ err = SLsmg_init_smg();
+ if (err < 0)
+ goto out;
+ err = SLang_init_tty(0, 0, 0);
+ if (err < 0)
+ goto out;
+
err = SLkp_init();
if (err < 0) {
pr_err("TUI initialization failed.\n");
@@ -115,7 +117,6 @@ int ui__init(void)
SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
- newtSetSuspendCallback(newt_suspend, NULL);
ui_helpline__init();
ui_browser__init();
ui_progress__init();
diff --git a/tools/perf/ui/ui.h b/tools/perf/ui/ui.h
index d86359c99907..70cb0d4eb8aa 100644
--- a/tools/perf/ui/ui.h
+++ b/tools/perf/ui/ui.h
@@ -12,7 +12,7 @@ extern int use_browser;
void setup_browser(bool fallback_to_pager);
void exit_browser(bool wait_for_ok);
-#ifdef NEWT_SUPPORT
+#ifdef SLANG_SUPPORT
int ui__init(void);
void ui__exit(bool wait_for_ok);
#else
diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c
index 4f989774c8c6..e3e0a963d03a 100644
--- a/tools/perf/ui/util.c
+++ b/tools/perf/ui/util.c
@@ -52,7 +52,6 @@ int ui__warning(const char *format, ...)
return ret;
}
-
/**
* perf_error__register - Register error logging functions
* @eops: The pointer to error logging function struct