2013-05-14 02:09:12

by Namhyung Kim

[permalink] [raw]
Subject: [PATCHSET 0/9] perf tools: Assorted fixes and changes on perf top/report

Hi,

This patchset is a collection of 3 changes on perf top and report
tools. I wanted to make them independent, but failed due to laziness. :)

Patch 1 is a fix for -E option handling in perf top. IIUC it only
shows a given number of entries. Patch 2 is a simple fix.

Patch 3-5 remove a set of _threaded() functions and also remove
unnecessary locking on perf report path. It leads to a small
performance gain.

Patch 6-9 implement a long-requested --percent-limit option. I
preserve the default value to 0 but an user can set it to a different
value using the .perfconfig file.

You can get it from 'perf/top-v1' branch on my tree at:

git://git.kernel.org/pub/scm/linux/kernel/git/namhyung/linux-perf.git

Any comments are welcome, thanks.
Namhyung


Namhyung Kim (9):
perf top: Fix -E option behavior
perf top: Fix percent output when no samples collected
perf top: Get rid of *_threaded() functions
perf hists: Move locking to its call-sites
perf report: Don't be bothered with locking when adding hist entries
perf report: Add --percent-limit option
perf top: Add --percent-limit option
perf report: Add report.percent-limit config variable
perf top: Reuse report.percent-limit config variable

tools/perf/Documentation/perf-report.txt | 4 ++
tools/perf/Documentation/perf-top.txt | 4 ++
tools/perf/builtin-diff.c | 2 +-
tools/perf/builtin-report.c | 50 +++++++++++------
tools/perf/builtin-top.c | 73 ++++++++++++++++--------
tools/perf/ui/browsers/hists.c | 95 +++++++++++++++++++++++++++-----
tools/perf/ui/gtk/hists.c | 13 ++++-
tools/perf/ui/stdio/hist.c | 7 ++-
tools/perf/util/hist.c | 50 +++--------------
tools/perf/util/hist.h | 14 ++---
tools/perf/util/top.c | 23 ++++++--
tools/perf/util/top.h | 1 +
12 files changed, 222 insertions(+), 114 deletions(-)

--
1.7.11.7


2013-05-14 02:09:18

by Namhyung Kim

[permalink] [raw]
Subject: [PATCH 6/9] perf report: Add --percent-limit option

From: Namhyung Kim <[email protected]>

The --percent-limit option is for not showing small overheaded entries
in the output. Maybe we want to set a certain default value like 0.1.

Cc: Andi Kleen <[email protected]>
Acked-by: Pekka Enberg <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/Documentation/perf-report.txt | 4 ++
tools/perf/builtin-diff.c | 2 +-
tools/perf/builtin-report.c | 21 +++++++--
tools/perf/builtin-top.c | 4 +-
tools/perf/ui/browsers/hists.c | 79 +++++++++++++++++++++++++++-----
tools/perf/ui/gtk/hists.c | 13 ++++--
tools/perf/ui/stdio/hist.c | 7 ++-
tools/perf/util/hist.h | 10 ++--
8 files changed, 115 insertions(+), 25 deletions(-)

diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 7d5f4f38aa52..66dab7410c1d 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -210,6 +210,10 @@ OPTIONS
Demangle symbol names to human readable form. It's enabled by default,
disable with --no-demangle.

+--percent-limit::
+ Do not show entries which have an overhead under that percent.
+ (Default: 0).
+
SEE ALSO
--------
linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index cabbea5f0bc2..a9d63c1c64c5 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -457,7 +457,7 @@ static void hists__process(struct hists *old, struct hists *new)
hists__output_resort(new);
}

- hists__fprintf(new, true, 0, 0, stdout);
+ hists__fprintf(new, true, 0, 0, 0, stdout);
}

static int __cmd_diff(void)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 0f0cf2472d9d..0a4979bdd4c4 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -52,6 +52,7 @@ struct perf_report {
symbol_filter_t annotate_init;
const char *cpu_list;
const char *symbol_filter_str;
+ float min_percent;
DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
};

@@ -456,7 +457,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
continue;

hists__fprintf_nr_sample_events(rep, hists, evname, stdout);
- hists__fprintf(hists, true, 0, 0, stdout);
+ hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
fprintf(stdout, "\n\n");
}

@@ -575,8 +576,8 @@ static int __cmd_report(struct perf_report *rep)
if (use_browser > 0) {
if (use_browser == 1) {
ret = perf_evlist__tui_browse_hists(session->evlist,
- help,
- NULL,
+ help, NULL,
+ rep->min_percent,
&session->header.env);
/*
* Usually "ret" is the last pressed key, and we only
@@ -587,7 +588,7 @@ static int __cmd_report(struct perf_report *rep)

} else if (use_browser == 2) {
perf_evlist__gtk_browse_hists(session->evlist, help,
- NULL);
+ NULL, rep->min_percent);
}
} else
perf_evlist__tty_browse_hists(session->evlist, rep, help);
@@ -698,6 +699,16 @@ parse_branch_mode(const struct option *opt __maybe_unused,
return 0;
}

+static int
+parse_percent_limit(const struct option *opt, const char *str,
+ int unset __maybe_unused)
+{
+ struct perf_report *rep = opt->value;
+
+ rep->min_percent = strtof(str, NULL);
+ return 0;
+}
+
int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
{
struct perf_session *session;
@@ -807,6 +818,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
"Disable symbol demangling"),
OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
+ OPT_CALLBACK(0, "percent-limit", &report, "percent",
+ "Don't show entries under that percent", parse_percent_limit),
OPT_END()
};

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index c2c973476479..19fe25f6e4f0 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -296,7 +296,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
top->print_entries - printed);
putchar('\n');
hists__fprintf(&top->sym_evsel->hists, false,
- top->print_entries - printed, win_width, stdout);
+ top->print_entries - printed, win_width, 0, stdout);
}

static void prompt_integer(int *target, const char *msg)
@@ -580,7 +580,7 @@ static void *display_thread_tui(void *arg)
list_for_each_entry(pos, &top->evlist->entries, node)
pos->hists.uid_filter_str = top->record_opts.target.uid_str;

- perf_evlist__tui_browse_hists(top->evlist, help, &hbt,
+ perf_evlist__tui_browse_hists(top->evlist, help, &hbt, 0,
&top->session->header.env);

done = 1;
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index a4268cab1921..9dfde61505cc 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -25,6 +25,8 @@ struct hist_browser {
struct map_symbol *selection;
int print_seq;
bool show_dso;
+ float min_pcnt;
+ u64 nr_pcnt_entries;
};

extern void hist_browser__init_hpp(void);
@@ -317,6 +319,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);
@@ -795,10 +799,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;
@@ -807,10 +816,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;

@@ -820,11 +837,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);
@@ -839,6 +861,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;
@@ -847,13 +872,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:
@@ -896,7 +923,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;
@@ -929,7 +957,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;
@@ -1098,14 +1127,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;
@@ -1324,11 +1356,25 @@ close_file_and_continue:
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;
@@ -1345,6 +1391,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;
@@ -1684,6 +1735,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;
};

@@ -1777,6 +1829,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) {
@@ -1838,6 +1891,7 @@ static bool filter_group_entries(struct ui_browser *self __maybe_unused,
static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
int nr_entries, const char *help,
struct hist_browser_timer *hbt,
+ float min_pcnt,
struct perf_session_env *env)
{
struct perf_evsel *pos;
@@ -1851,6 +1905,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
.nr_entries = nr_entries,
.priv = evlist,
},
+ .min_pcnt = min_pcnt,
.env = env,
};

@@ -1869,6 +1924,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,

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)
{
int nr_entries = evlist->nr_entries;
@@ -1880,7 +1936,8 @@ single_entry:
const char *ev_name = perf_evsel__name(first);

return perf_evsel__hists_browse(first, nr_entries, help,
- ev_name, false, hbt, env);
+ ev_name, false, hbt, min_pcnt,
+ env);
}

if (symbol_conf.event_group) {
@@ -1896,5 +1953,5 @@ single_entry:
}

return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
- hbt, env);
+ hbt, min_pcnt, env);
}
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 6f259b3d14e2..9708dd5fb8f3 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -124,7 +124,8 @@ void perf_gtk__init_hpp(void)
perf_gtk__hpp_color_overhead_guest_us;
}

-static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
+static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
+ float min_pcnt)
{
struct perf_hpp_fmt *fmt;
GType col_types[MAX_COLUMNS];
@@ -189,10 +190,15 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
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;
@@ -222,7 +228,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)

int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
const char *help,
- struct hist_browser_timer *hbt __maybe_unused)
+ struct hist_browser_timer *hbt __maybe_unused,
+ float min_pcnt)
{
struct perf_evsel *pos;
GtkWidget *vbox;
@@ -286,7 +293,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);

- perf_gtk__show_hists(scrolled_window, hists);
+ perf_gtk__show_hists(scrolled_window, hists, min_pcnt);

tab_label = gtk_label_new(evname);

diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index ff1f60cf442e..ae7a75432249 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -334,7 +334,7 @@ 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;
@@ -440,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)
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index bd81d799a1bf..2d3790fd99bb 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -115,7 +115,7 @@ void events_stats__inc(struct events_stats *stats, u32 type);
size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);

size_t hists__fprintf(struct hists *self, bool show_header, int max_rows,
- int max_cols, FILE *fp);
+ int max_cols, float min_pcnt, FILE *fp);

int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr);
int hist_entry__annotate(struct hist_entry *self, size_t privsize);
@@ -195,6 +195,7 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,

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);
int script_browse(const char *script_opt);
#else
@@ -202,6 +203,7 @@ static inline
int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
const char *help __maybe_unused,
struct hist_browser_timer *hbt __maybe_unused,
+ float min_pcnt __maybe_unused,
struct perf_session_env *env __maybe_unused)
{
return 0;
@@ -229,12 +231,14 @@ static inline int script_browse(const char *script_opt __maybe_unused)

#ifdef GTK2_SUPPORT
int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
- struct hist_browser_timer *hbt __maybe_unused);
+ struct hist_browser_timer *hbt __maybe_unused,
+ float min_pcnt);
#else
static inline
int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
const char *help __maybe_unused,
- struct hist_browser_timer *hbt __maybe_unused)
+ struct hist_browser_timer *hbt __maybe_unused,
+ float min_pcnt __maybe_unused)
{
return 0;
}
--
1.7.11.7

2013-05-14 02:09:16

by Namhyung Kim

[permalink] [raw]
Subject: [PATCH 7/9] perf top: Add --percent-limit option

From: Namhyung Kim <[email protected]>

The --percent-limit option is for not showing small overheaded entries
in the output.

Cc: Andi Kleen <[email protected]>
Acked-by: Pekka Enberg <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/Documentation/perf-top.txt | 4 ++++
tools/perf/builtin-top.c | 17 +++++++++++++++--
tools/perf/ui/browsers/hists.c | 16 ++++++++++++++--
tools/perf/util/top.h | 1 +
4 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 9f1a2fe54757..7fdd1909e376 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -155,6 +155,10 @@ Default is to monitor all CPUS.

Default: fractal,0.5,callee.

+--percent-limit::
+ Do not show entries which have an overhead under that percent.
+ (Default: 0).
+
INTERACTIVE PROMPTING KEYS
--------------------------

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 19fe25f6e4f0..f036af9b6f09 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -296,7 +296,8 @@ static void perf_top__print_sym_table(struct perf_top *top)
top->print_entries - printed);
putchar('\n');
hists__fprintf(&top->sym_evsel->hists, false,
- top->print_entries - printed, win_width, 0, stdout);
+ top->print_entries - printed, win_width,
+ top->min_percent, stdout);
}

static void prompt_integer(int *target, const char *msg)
@@ -580,7 +581,7 @@ static void *display_thread_tui(void *arg)
list_for_each_entry(pos, &top->evlist->entries, node)
pos->hists.uid_filter_str = top->record_opts.target.uid_str;

- perf_evlist__tui_browse_hists(top->evlist, help, &hbt, 0,
+ perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent,
&top->session->header.env);

done = 1;
@@ -1021,6 +1022,16 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
return record_parse_callchain_opt(opt, arg, unset);
}

+static int
+parse_percent_limit(const struct option *opt, const char *arg,
+ int unset __maybe_unused)
+{
+ struct perf_top *top = opt->value;
+
+ top->min_percent = strtof(arg, NULL);
+ return 0;
+}
+
int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
{
int status;
@@ -1106,6 +1117,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
"Specify disassembler style (e.g. -M intel for intel syntax)"),
OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
+ OPT_CALLBACK(0, "percent-limit", &top, "percent",
+ "Don't show entries under that percent", parse_percent_limit),
OPT_END()
};
const char * const top_usage[] = {
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 9dfde61505cc..fc0bd3843d34 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -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)
{
@@ -333,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]) {
@@ -347,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,
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index f0a862539ba9..df46be93d902 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -36,6 +36,7 @@ struct perf_top {
int realtime_prio;
int sym_pcnt_filter;
const char *sym_filter;
+ float min_percent;
};

size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
--
1.7.11.7

2013-05-14 02:09:15

by Namhyung Kim

[permalink] [raw]
Subject: [PATCH 4/9] perf hists: Move locking to its call-sites

From: Namhyung Kim <[email protected]>

It's a preparation patch to eliminate unneeded locking in the perf
report path.

Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/builtin-report.c | 26 ++++++++++++++------------
tools/perf/builtin-top.c | 3 +++
tools/perf/util/hist.c | 6 +-----
3 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index d45bf9b0361d..63febd24e912 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -297,6 +297,7 @@ static int process_sample_event(struct perf_tool *tool,
{
struct perf_report *rep = container_of(tool, struct perf_report, tool);
struct addr_location al;
+ int ret;

if (perf_event__preprocess_sample(event, machine, &al, sample,
rep->annotate_init) < 0) {
@@ -311,28 +312,29 @@ static int process_sample_event(struct perf_tool *tool,
if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
return 0;

+ pthread_mutex_lock(&evsel->hists.lock);
+
if (sort__mode == SORT_MODE__BRANCH) {
- if (perf_report__add_branch_hist_entry(tool, &al, sample,
- evsel, machine)) {
+ ret = perf_report__add_branch_hist_entry(tool, &al, sample,
+ evsel, machine);
+ if (ret < 0)
pr_debug("problem adding lbr entry, skipping event\n");
- return -1;
- }
} else if (rep->mem_mode == 1) {
- if (perf_report__add_mem_hist_entry(tool, &al, sample,
- evsel, machine, event)) {
+ ret = perf_report__add_mem_hist_entry(tool, &al, sample,
+ evsel, machine, event);
+ if (ret < 0)
pr_debug("problem adding mem entry, skipping event\n");
- return -1;
- }
} else {
if (al.map != NULL)
al.map->dso->hit = 1;

- if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) {
+ ret = perf_evsel__add_hist_entry(evsel, &al, sample, machine);
+ if (ret < 0)
pr_debug("problem incrementing symbol period, skipping event\n");
- return -1;
- }
}
- return 0;
+ pthread_mutex_unlock(&evsel->hists.lock);
+
+ return ret;
}

static int process_read_event(struct perf_tool *tool,
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 5cd41ec43ce1..c2c973476479 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -245,8 +245,11 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
{
struct hist_entry *he;

+ pthread_mutex_lock(&evsel->hists.lock);
he = __hists__add_entry(&evsel->hists, al, NULL, sample->period,
sample->weight);
+ pthread_mutex_unlock(&evsel->hists.lock);
+
if (he == NULL)
return NULL;

diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 7e0fa628e9ab..b11a6cfdb414 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -347,8 +347,6 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
struct hist_entry *he;
int cmp;

- pthread_mutex_lock(&hists->lock);
-
p = &hists->entries_in->rb_node;

while (*p != NULL) {
@@ -394,14 +392,12 @@ static struct hist_entry *add_hist_entry(struct hists *hists,

he = hist_entry__new(entry);
if (!he)
- goto out_unlock;
+ return NULL;

rb_link_node(&he->rb_node_in, parent, p);
rb_insert_color(&he->rb_node_in, hists->entries_in);
out:
hist_entry__add_cpumode_period(he, al->cpumode, period);
-out_unlock:
- pthread_mutex_unlock(&hists->lock);
return he;
}

--
1.7.11.7

2013-05-14 02:10:06

by Namhyung Kim

[permalink] [raw]
Subject: [PATCH 9/9] perf top: Reuse report.percent-limit config variable

From: Namhyung Kim <[email protected]>

Make the config variable also works for perf top.

Cc: Andi Kleen <[email protected]>
Cc: Pekka Enberg <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/builtin-top.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index f036af9b6f09..73fd40da47ba 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1032,6 +1032,19 @@ parse_percent_limit(const struct option *opt, const char *arg,
return 0;
}

+static int perf_top_config(const char *var, const char *value, void *cb)
+{
+ /* share report config variables */
+ if (!strcmp(var, "report.percent-limit")) {
+ struct perf_top *top = cb;
+
+ top->min_percent = strtof(value, NULL);
+ return 0;
+ }
+
+ return perf_default_config(var, value, cb);
+}
+
int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
{
int status;
@@ -1132,6 +1145,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)

symbol_conf.exclude_other = false;

+ perf_config(perf_top_config, &top);
+
argc = parse_options(argc, argv, options, top_usage, 0);
if (argc)
usage_with_options(top_usage, options);
--
1.7.11.7

2013-05-14 02:09:14

by Namhyung Kim

[permalink] [raw]
Subject: [PATCH 3/9] perf top: Get rid of *_threaded() functions

From: Namhyung Kim <[email protected]>

Those _threaded() functions are needed to make hist tree handling
thread-safe, but AFAICS the only thing it does is forcing it to use
the intermediate 'collapsed' tree. It can be acheived by setting
sort__need_collapse to 1 in cmd_top() so no need to keep those
_threaded() variants.

Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/builtin-top.c | 23 +++++++++++++----------
tools/perf/util/hist.c | 44 ++++++--------------------------------------
tools/perf/util/hist.h | 4 ----
3 files changed, 19 insertions(+), 52 deletions(-)

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 81adcafbac8f..5cd41ec43ce1 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -284,11 +284,11 @@ static void perf_top__print_sym_table(struct perf_top *top)
return;
}

- hists__collapse_resort_threaded(&top->sym_evsel->hists);
- hists__output_resort_threaded(&top->sym_evsel->hists);
- hists__decay_entries_threaded(&top->sym_evsel->hists,
- top->hide_user_symbols,
- top->hide_kernel_symbols);
+ hists__collapse_resort(&top->sym_evsel->hists);
+ hists__output_resort(&top->sym_evsel->hists);
+ hists__decay_entries(&top->sym_evsel->hists,
+ top->hide_user_symbols,
+ top->hide_kernel_symbols);
hists__output_recalc_col_len(&top->sym_evsel->hists,
top->print_entries - printed);
putchar('\n');
@@ -549,11 +549,11 @@ static void perf_top__sort_new_samples(void *arg)
if (t->evlist->selected != NULL)
t->sym_evsel = t->evlist->selected;

- hists__collapse_resort_threaded(&t->sym_evsel->hists);
- hists__output_resort_threaded(&t->sym_evsel->hists);
- hists__decay_entries_threaded(&t->sym_evsel->hists,
- t->hide_user_symbols,
- t->hide_kernel_symbols);
+ hists__collapse_resort(&t->sym_evsel->hists);
+ hists__output_resort(&t->sym_evsel->hists);
+ hists__decay_entries(&t->sym_evsel->hists,
+ t->hide_user_symbols,
+ t->hide_kernel_symbols);
}

static void *display_thread_tui(void *arg)
@@ -1126,6 +1126,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
if (setup_sorting() < 0)
usage_with_options(top_usage, options);

+ /* display thread wants entries to be collapsed in a different tree */
+ sort__need_collapse = 1;
+
if (top.use_stdio)
use_browser = 0;
else if (top.use_tui)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 72b4eec820c3..7e0fa628e9ab 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -240,8 +240,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
return he->stat.period == 0;
}

-static void __hists__decay_entries(struct hists *hists, bool zap_user,
- bool zap_kernel, bool threaded)
+void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
{
struct rb_node *next = rb_first(&hists->entries);
struct hist_entry *n;
@@ -260,7 +259,7 @@ static void __hists__decay_entries(struct hists *hists, bool zap_user,
!n->used) {
rb_erase(&n->rb_node, &hists->entries);

- if (sort__need_collapse || threaded)
+ if (sort__need_collapse)
rb_erase(&n->rb_node_in, &hists->entries_collapsed);

hist_entry__free(n);
@@ -269,17 +268,6 @@ static void __hists__decay_entries(struct hists *hists, bool zap_user,
}
}

-void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
-{
- return __hists__decay_entries(hists, zap_user, zap_kernel, false);
-}
-
-void hists__decay_entries_threaded(struct hists *hists,
- bool zap_user, bool zap_kernel)
-{
- return __hists__decay_entries(hists, zap_user, zap_kernel, true);
-}
-
/*
* histogram, sorted on item, collects periods
*/
@@ -613,13 +601,13 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
hists__filter_entry_by_symbol(hists, he);
}

-static void __hists__collapse_resort(struct hists *hists, bool threaded)
+void hists__collapse_resort(struct hists *hists)
{
struct rb_root *root;
struct rb_node *next;
struct hist_entry *n;

- if (!sort__need_collapse && !threaded)
+ if (!sort__need_collapse)
return;

root = hists__get_rotate_entries_in(hists);
@@ -641,16 +629,6 @@ static void __hists__collapse_resort(struct hists *hists, bool threaded)
}
}

-void hists__collapse_resort(struct hists *hists)
-{
- return __hists__collapse_resort(hists, false);
-}
-
-void hists__collapse_resort_threaded(struct hists *hists)
-{
- return __hists__collapse_resort(hists, true);
-}
-
/*
* reverse the map, sort on period.
*/
@@ -737,7 +715,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
rb_insert_color(&he->rb_node, entries);
}

-static void __hists__output_resort(struct hists *hists, bool threaded)
+void hists__output_resort(struct hists *hists)
{
struct rb_root *root;
struct rb_node *next;
@@ -746,7 +724,7 @@ static void __hists__output_resort(struct hists *hists, bool threaded)

min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);

- if (sort__need_collapse || threaded)
+ if (sort__need_collapse)
root = &hists->entries_collapsed;
else
root = hists->entries_in;
@@ -767,16 +745,6 @@ static void __hists__output_resort(struct hists *hists, bool threaded)
}
}

-void hists__output_resort(struct hists *hists)
-{
- return __hists__output_resort(hists, false);
-}
-
-void hists__output_resort_threaded(struct hists *hists)
-{
- return __hists__output_resort(hists, true);
-}
-
static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
enum hist_filter filter)
{
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 6be88dc12b9a..bd81d799a1bf 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -104,13 +104,9 @@ struct hist_entry *__hists__add_mem_entry(struct hists *self,
u64 weight);

void hists__output_resort(struct hists *self);
-void hists__output_resort_threaded(struct hists *hists);
void hists__collapse_resort(struct hists *self);
-void hists__collapse_resort_threaded(struct hists *hists);

void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
-void hists__decay_entries_threaded(struct hists *hists, bool zap_user,
- bool zap_kernel);
void hists__output_recalc_col_len(struct hists *hists, int max_rows);

void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h);
--
1.7.11.7

2013-05-14 02:10:41

by Namhyung Kim

[permalink] [raw]
Subject: [PATCH 8/9] perf report: Add report.percent-limit config variable

From: Namhyung Kim <[email protected]>

Now an user can set a default value of --percent-limit option into the
perfconfig file.

$ cat ~/.perfconfig
[report]
percent-limit = 0.1

Cc: Andi Kleen <[email protected]>
Cc: Pekka Enberg <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/builtin-report.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 0a4979bdd4c4..ca98d34cd58b 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -62,6 +62,11 @@ static int perf_report_config(const char *var, const char *value, void *cb)
symbol_conf.event_group = perf_config_bool(var, value);
return 0;
}
+ if (!strcmp(var, "report.percent-limit")) {
+ struct perf_report *rep = cb;
+ rep->min_percent = strtof(value, NULL);
+ return 0;
+ }

return perf_default_config(var, value, cb);
}
@@ -823,7 +828,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_END()
};

- perf_config(perf_report_config, NULL);
+ perf_config(perf_report_config, &report);

argc = parse_options(argc, argv, options, report_usage, 0);

--
1.7.11.7

2013-05-14 02:10:59

by Namhyung Kim

[permalink] [raw]
Subject: [PATCH 5/9] perf report: Don't be bothered with locking when adding hist entries

From: Namhyung Kim <[email protected]>

The perf report is single-threaded, so no need to grab a lock.
Although the fast path of pthread_mutex_[un]lock() is very fast,
there's ~3% gain by eliminating it when we have huge sample data.

$ perf record -a -F 100000 -o perf.data.bench -- perf bench sched all
$ perf record -e cycles:upp -o perf.data.before -- \
> perf report -i perf.data.bench --stdio > /dev/null
... apply this patch ...
$ perf record -e cycles:upp -o perf.data.after -- \
> perf report -i perf.data.bench --stdio > /dev/null
$ perf diff perf.data.{before,after} | grep pthread
+0.02% libpthread-2.15.so [.] _pthread_cleanup_push_defer
+0.02% libpthread-2.15.so [.] _pthread_cleanup_pop_restore
0.05% -0.05% perf [.] pthread_mutex_unlock@plt
0.05% -0.05% perf [.] pthread_mutex_lock@plt
1.01% -1.01% libpthread-2.15.so [.] pthread_mutex_lock
1.68% -1.68% libpthread-2.15.so [.] __pthread_mutex_unlock_usercnt
0.05% -0.05% libpthread-2.15.so [.] pthread_mutex_unlock

Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/builtin-report.c | 4 ----
1 file changed, 4 deletions(-)

diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 63febd24e912..0f0cf2472d9d 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -312,8 +312,6 @@ static int process_sample_event(struct perf_tool *tool,
if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
return 0;

- pthread_mutex_lock(&evsel->hists.lock);
-
if (sort__mode == SORT_MODE__BRANCH) {
ret = perf_report__add_branch_hist_entry(tool, &al, sample,
evsel, machine);
@@ -332,8 +330,6 @@ static int process_sample_event(struct perf_tool *tool,
if (ret < 0)
pr_debug("problem incrementing symbol period, skipping event\n");
}
- pthread_mutex_unlock(&evsel->hists.lock);
-
return ret;
}

--
1.7.11.7

2013-05-14 02:11:28

by Namhyung Kim

[permalink] [raw]
Subject: [PATCH 1/9] perf top: Fix -E option behavior

From: Namhyung Kim <[email protected]>

The -E/--entries option controls how many lines to be printed on stdio
output but it doesn't work as it should be:

If -E option is specified, print that many lines regardless of current
window size, if not automatically adjust number of lines printed to
fit into the window size.

Reported-by: Minchan Kim <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/builtin-top.c | 17 +++++------------
1 file changed, 5 insertions(+), 12 deletions(-)

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index df9e06af89bf..81adcafbac8f 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -70,10 +70,11 @@

static volatile int done;

+#define HEADER_LINE_NR 5
+
static void perf_top__update_print_entries(struct perf_top *top)
{
- if (top->print_entries > 9)
- top->print_entries -= 9;
+ top->print_entries = top->winsize.ws_row - HEADER_LINE_NR;
}

static void perf_top__sig_winch(int sig __maybe_unused,
@@ -82,13 +83,6 @@ static void perf_top__sig_winch(int sig __maybe_unused,
struct perf_top *top = arg;

get_term_dimensions(&top->winsize);
- if (!top->print_entries
- || (top->print_entries+4) > top->winsize.ws_row) {
- top->print_entries = top->winsize.ws_row;
- } else {
- top->print_entries += 4;
- top->winsize.ws_row = top->print_entries;
- }
perf_top__update_print_entries(top);
}

@@ -296,10 +290,10 @@ static void perf_top__print_sym_table(struct perf_top *top)
top->hide_user_symbols,
top->hide_kernel_symbols);
hists__output_recalc_col_len(&top->sym_evsel->hists,
- top->winsize.ws_row - 3);
+ top->print_entries - printed);
putchar('\n');
hists__fprintf(&top->sym_evsel->hists, false,
- top->winsize.ws_row - 4 - printed, win_width, stdout);
+ top->print_entries - printed, win_width, stdout);
}

static void prompt_integer(int *target, const char *msg)
@@ -477,7 +471,6 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
perf_top__sig_winch(SIGWINCH, NULL, top);
sigaction(SIGWINCH, &act, NULL);
} else {
- perf_top__sig_winch(SIGWINCH, NULL, top);
signal(SIGWINCH, SIG_DFL);
}
break;
--
1.7.11.7

2013-05-14 02:11:27

by Namhyung Kim

[permalink] [raw]
Subject: [PATCH 2/9] perf top: Fix percent output when no samples collected

From: Namhyung Kim <[email protected]>

If there's no sample, kernel and exact percent output at the header
looked like "-nan%".

Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/util/top.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 54d37a4753c5..f857b51b6bde 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -23,20 +23,31 @@

size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
{
- float samples_per_sec = top->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 samples_per_sec;
+ float ksamples_per_sec;
+ float esamples_percent;
struct perf_record_opts *opts = &top->record_opts;
struct perf_target *target = &opts->target;
size_t ret = 0;

+ if (top->samples) {
+ samples_per_sec = top->samples / top->delay_secs;
+ ksamples_per_sec = top->kernel_samples / top->delay_secs;
+ esamples_percent = (100.0 * top->exact_samples) / top->samples;
+ } else {
+ samples_per_sec = ksamples_per_sec = esamples_percent = 0.0;
+ }
+
if (!perf_guest) {
+ float ksamples_percent = 0.0;
+
+ if (samples_per_sec)
+ ksamples_percent = (100.0 * ksamples_per_sec) /
+ samples_per_sec;
ret = SNPRINTF(bf, size,
" PerfTop:%8.0f irqs/sec kernel:%4.1f%%"
" exact: %4.1f%% [", samples_per_sec,
- 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
- samples_per_sec)),
- esamples_percent);
+ ksamples_percent, esamples_percent);
} else {
float us_samples_per_sec = top->us_samples / top->delay_secs;
float guest_kernel_samples_per_sec = top->guest_kernel_samples / top->delay_secs;
--
1.7.11.7

2013-05-14 11:05:41

by Pekka Enberg

[permalink] [raw]
Subject: Re: [PATCH 8/9] perf report: Add report.percent-limit config variable

On Tue, May 14, 2013 at 5:09 AM, Namhyung Kim <[email protected]> wrote:
> From: Namhyung Kim <[email protected]>
>
> Now an user can set a default value of --percent-limit option into the
> perfconfig file.
>
> $ cat ~/.perfconfig
> [report]
> percent-limit = 0.1
>
> Cc: Andi Kleen <[email protected]>
> Cc: Pekka Enberg <[email protected]>
> Signed-off-by: Namhyung Kim <[email protected]>

I'm not totally convinced this is useful. The limit is about "what is
significant" and that depends on what you are trying to measure.
There's an (absolute) lower limit somewhere between 0.1 and 1.0 but I
think we can just pick a reasonable default and let people use the
command line switch if they want to override it.

Pekka

2013-05-15 10:08:36

by Namhyung Kim

[permalink] [raw]
Subject: Re: [PATCH 8/9] perf report: Add report.percent-limit config variable

Hi Pekka,

On Tue, 14 May 2013 14:05:38 +0300, Pekka Enberg wrote:
> On Tue, May 14, 2013 at 5:09 AM, Namhyung Kim <[email protected]> wrote:
>> From: Namhyung Kim <[email protected]>
>>
>> Now an user can set a default value of --percent-limit option into the
>> perfconfig file.
>>
>> $ cat ~/.perfconfig
>> [report]
>> percent-limit = 0.1
>>
>> Cc: Andi Kleen <[email protected]>
>> Cc: Pekka Enberg <[email protected]>
>> Signed-off-by: Namhyung Kim <[email protected]>
>
> I'm not totally convinced this is useful. The limit is about "what is
> significant" and that depends on what you are trying to measure.
> There's an (absolute) lower limit somewhere between 0.1 and 1.0 but I
> think we can just pick a reasonable default and let people use the
> command line switch if they want to override it.

If the limit depends on what is measured, what should be the reasonable
default value? I just don't know..

I agree that we should pick a default but the config variable doesn't
harm anything in this case too. Some users might not agree with our
default for their cases and want to use other value.

But I'm not insist on it so strongly, I just gave another way.. ;)

Thanks,
Namhyung

2013-05-16 07:34:59

by Pekka Enberg

[permalink] [raw]
Subject: Re: [PATCH 8/9] perf report: Add report.percent-limit config variable

On 05/15/2013 01:08 PM, Namhyung Kim wrote:
> Hi Pekka,
>
> On Tue, 14 May 2013 14:05:38 +0300, Pekka Enberg wrote:
>> On Tue, May 14, 2013 at 5:09 AM, Namhyung Kim <[email protected]> wrote:
>>> From: Namhyung Kim <[email protected]>
>>>
>>> Now an user can set a default value of --percent-limit option into the
>>> perfconfig file.
>>>
>>> $ cat ~/.perfconfig
>>> [report]
>>> percent-limit = 0.1
>>>
>>> Cc: Andi Kleen <[email protected]>
>>> Cc: Pekka Enberg <[email protected]>
>>> Signed-off-by: Namhyung Kim <[email protected]>
>>
>> I'm not totally convinced this is useful. The limit is about "what is
>> significant" and that depends on what you are trying to measure.
>> There's an (absolute) lower limit somewhere between 0.1 and 1.0 but I
>> think we can just pick a reasonable default and let people use the
>> command line switch if they want to override it.
>
> If the limit depends on what is measured, what should be the reasonable
> default value? I just don't know..
>
> I agree that we should pick a default but the config variable doesn't
> harm anything in this case too. Some users might not agree with our
> default for their cases and want to use other value.
>
> But I'm not insist on it so strongly, I just gave another way.. ;)

I'd go for default value of 1.0 first and if people complain, drop it to
0.1. But I guess it's safer to add your config option thingy just in case:

Acked-by: Pekka Enberg <[email protected]>

Pekka

2013-05-17 14:22:11

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH 1/9] perf top: Fix -E option behavior

On Tue, May 14, 2013 at 11:08:59AM +0900, Namhyung Kim wrote:
> From: Namhyung Kim <[email protected]>
>
> The -E/--entries option controls how many lines to be printed on stdio
> output but it doesn't work as it should be:
>
> If -E option is specified, print that many lines regardless of current
> window size, if not automatically adjust number of lines printed to
> fit into the window size.
>
> Reported-by: Minchan Kim <[email protected]>
> Signed-off-by: Namhyung Kim <[email protected]>

Tested-by: Jiri Olsa <[email protected]>

jirka

2013-05-17 14:22:55

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH 2/9] perf top: Fix percent output when no samples collected

On Tue, May 14, 2013 at 11:09:00AM +0900, Namhyung Kim wrote:
> From: Namhyung Kim <[email protected]>
>
> If there's no sample, kernel and exact percent output at the header
> looked like "-nan%".
>
> Signed-off-by: Namhyung Kim <[email protected]>
> ---
> tools/perf/util/top.c | 23 +++++++++++++++++------
> 1 file changed, 17 insertions(+), 6 deletions(-)
>

Tested-by: Jiri Olsa <[email protected]>

jirka

2013-05-17 14:28:34

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH 3/9] perf top: Get rid of *_threaded() functions

On Tue, May 14, 2013 at 11:09:01AM +0900, Namhyung Kim wrote:
> From: Namhyung Kim <[email protected]>
>
> Those _threaded() functions are needed to make hist tree handling
> thread-safe, but AFAICS the only thing it does is forcing it to use
> the intermediate 'collapsed' tree. It can be acheived by setting
> sort__need_collapse to 1 in cmd_top() so no need to keep those
> _threaded() variants.
>
> Signed-off-by: Namhyung Kim <[email protected]>
> ---
> tools/perf/builtin-top.c | 23 +++++++++++++----------
> tools/perf/util/hist.c | 44 ++++++--------------------------------------
> tools/perf/util/hist.h | 4 ----
> 3 files changed, 19 insertions(+), 52 deletions(-)

Acked-by: Jiri Olsa <[email protected]>

jirka

2013-05-17 14:39:42

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH 4/9] perf hists: Move locking to its call-sites

On Tue, May 14, 2013 at 11:09:02AM +0900, Namhyung Kim wrote:
> From: Namhyung Kim <[email protected]>
>
> It's a preparation patch to eliminate unneeded locking in the perf
> report path.
>
> Signed-off-by: Namhyung Kim <[email protected]>
> ---
> tools/perf/builtin-report.c | 26 ++++++++++++++------------
> tools/perf/builtin-top.c | 3 +++
> tools/perf/util/hist.c | 6 +-----
> 3 files changed, 18 insertions(+), 17 deletions(-)

Acked-by: Jiri Olsa <[email protected]>

jirka

2013-05-17 14:40:02

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH 5/9] perf report: Don't be bothered with locking when adding hist entries

On Tue, May 14, 2013 at 11:09:03AM +0900, Namhyung Kim wrote:
> From: Namhyung Kim <[email protected]>
>
> The perf report is single-threaded, so no need to grab a lock.
> Although the fast path of pthread_mutex_[un]lock() is very fast,
> there's ~3% gain by eliminating it when we have huge sample data.
>
> $ perf record -a -F 100000 -o perf.data.bench -- perf bench sched all
> $ perf record -e cycles:upp -o perf.data.before -- \
> > perf report -i perf.data.bench --stdio > /dev/null
> ... apply this patch ...
> $ perf record -e cycles:upp -o perf.data.after -- \
> > perf report -i perf.data.bench --stdio > /dev/null
> $ perf diff perf.data.{before,after} | grep pthread
> +0.02% libpthread-2.15.so [.] _pthread_cleanup_push_defer
> +0.02% libpthread-2.15.so [.] _pthread_cleanup_pop_restore
> 0.05% -0.05% perf [.] pthread_mutex_unlock@plt
> 0.05% -0.05% perf [.] pthread_mutex_lock@plt
> 1.01% -1.01% libpthread-2.15.so [.] pthread_mutex_lock
> 1.68% -1.68% libpthread-2.15.so [.] __pthread_mutex_unlock_usercnt
> 0.05% -0.05% libpthread-2.15.so [.] pthread_mutex_unlock
>
> Signed-off-by: Namhyung Kim <[email protected]>
> ---
> tools/perf/builtin-report.c | 4 ----
> 1 file changed, 4 deletions(-)

nice :)

Acked-by: Jiri Olsa <[email protected]>

jirka

Subject: [tip:perf/core] perf top: Fix -E option behavior

Commit-ID: 933cbb1c6c617a6ae167538c2fa503efc9c4a832
Gitweb: http://git.kernel.org/tip/933cbb1c6c617a6ae167538c2fa503efc9c4a832
Author: Namhyung Kim <[email protected]>
AuthorDate: Tue, 14 May 2013 11:08:59 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 28 May 2013 16:23:59 +0300

perf top: Fix -E option behavior

The -E/--entries option controls how many lines to be printed on stdio
output but it doesn't work as it should be:

If -E option is specified, print that many lines regardless of current
window size, if not automatically adjust number of lines printed to fit
into the window size.

Reported-by: Minchan Kim <[email protected]>
Tested-by: Jiri Olsa <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-top.c | 17 +++++------------
1 file changed, 5 insertions(+), 12 deletions(-)

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index df9e06a..81adcaf 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -70,10 +70,11 @@

static volatile int done;

+#define HEADER_LINE_NR 5
+
static void perf_top__update_print_entries(struct perf_top *top)
{
- if (top->print_entries > 9)
- top->print_entries -= 9;
+ top->print_entries = top->winsize.ws_row - HEADER_LINE_NR;
}

static void perf_top__sig_winch(int sig __maybe_unused,
@@ -82,13 +83,6 @@ static void perf_top__sig_winch(int sig __maybe_unused,
struct perf_top *top = arg;

get_term_dimensions(&top->winsize);
- if (!top->print_entries
- || (top->print_entries+4) > top->winsize.ws_row) {
- top->print_entries = top->winsize.ws_row;
- } else {
- top->print_entries += 4;
- top->winsize.ws_row = top->print_entries;
- }
perf_top__update_print_entries(top);
}

@@ -296,10 +290,10 @@ static void perf_top__print_sym_table(struct perf_top *top)
top->hide_user_symbols,
top->hide_kernel_symbols);
hists__output_recalc_col_len(&top->sym_evsel->hists,
- top->winsize.ws_row - 3);
+ top->print_entries - printed);
putchar('\n');
hists__fprintf(&top->sym_evsel->hists, false,
- top->winsize.ws_row - 4 - printed, win_width, stdout);
+ top->print_entries - printed, win_width, stdout);
}

static void prompt_integer(int *target, const char *msg)
@@ -477,7 +471,6 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
perf_top__sig_winch(SIGWINCH, NULL, top);
sigaction(SIGWINCH, &act, NULL);
} else {
- perf_top__sig_winch(SIGWINCH, NULL, top);
signal(SIGWINCH, SIG_DFL);
}
break;

Subject: [tip:perf/core] perf top: Fix percent output when no samples collected

Commit-ID: 6f29097f45f6c375f2f6a76c589577575c7feb52
Gitweb: http://git.kernel.org/tip/6f29097f45f6c375f2f6a76c589577575c7feb52
Author: Namhyung Kim <[email protected]>
AuthorDate: Tue, 14 May 2013 11:09:00 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 28 May 2013 16:23:59 +0300

perf top: Fix percent output when no samples collected

If there's no sample, kernel and exact percent output at the header
looked like "-nan%".

Tested-by: Jiri Olsa <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/top.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 54d37a4..f857b51 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -23,20 +23,31 @@

size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
{
- float samples_per_sec = top->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 samples_per_sec;
+ float ksamples_per_sec;
+ float esamples_percent;
struct perf_record_opts *opts = &top->record_opts;
struct perf_target *target = &opts->target;
size_t ret = 0;

+ if (top->samples) {
+ samples_per_sec = top->samples / top->delay_secs;
+ ksamples_per_sec = top->kernel_samples / top->delay_secs;
+ esamples_percent = (100.0 * top->exact_samples) / top->samples;
+ } else {
+ samples_per_sec = ksamples_per_sec = esamples_percent = 0.0;
+ }
+
if (!perf_guest) {
+ float ksamples_percent = 0.0;
+
+ if (samples_per_sec)
+ ksamples_percent = (100.0 * ksamples_per_sec) /
+ samples_per_sec;
ret = SNPRINTF(bf, size,
" PerfTop:%8.0f irqs/sec kernel:%4.1f%%"
" exact: %4.1f%% [", samples_per_sec,
- 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
- samples_per_sec)),
- esamples_percent);
+ ksamples_percent, esamples_percent);
} else {
float us_samples_per_sec = top->us_samples / top->delay_secs;
float guest_kernel_samples_per_sec = top->guest_kernel_samples / top->delay_secs;

Subject: [tip:perf/core] perf top: Get rid of *_threaded() functions

Commit-ID: 3a5714f8b58913ded4d9e90abdd30e7e5993f863
Gitweb: http://git.kernel.org/tip/3a5714f8b58913ded4d9e90abdd30e7e5993f863
Author: Namhyung Kim <[email protected]>
AuthorDate: Tue, 14 May 2013 11:09:01 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 28 May 2013 16:23:59 +0300

perf top: Get rid of *_threaded() functions

Those _threaded() functions are needed to make hist tree handling
thread-safe, but AFAICS the only thing it does is forcing it to use
the intermediate 'collapsed' tree.

This can be acheived by setting sort__need_collapse to 1 in cmd_top() so
no need to keep those _threaded() variants.

Signed-off-by: Namhyung Kim <[email protected]>
Acked-by: Jiri Olsa <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-top.c | 23 +++++++++++++----------
tools/perf/util/hist.c | 44 ++++++--------------------------------------
tools/perf/util/hist.h | 4 ----
3 files changed, 19 insertions(+), 52 deletions(-)

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 81adcaf..5cd41ec 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -284,11 +284,11 @@ static void perf_top__print_sym_table(struct perf_top *top)
return;
}

- hists__collapse_resort_threaded(&top->sym_evsel->hists);
- hists__output_resort_threaded(&top->sym_evsel->hists);
- hists__decay_entries_threaded(&top->sym_evsel->hists,
- top->hide_user_symbols,
- top->hide_kernel_symbols);
+ hists__collapse_resort(&top->sym_evsel->hists);
+ hists__output_resort(&top->sym_evsel->hists);
+ hists__decay_entries(&top->sym_evsel->hists,
+ top->hide_user_symbols,
+ top->hide_kernel_symbols);
hists__output_recalc_col_len(&top->sym_evsel->hists,
top->print_entries - printed);
putchar('\n');
@@ -549,11 +549,11 @@ static void perf_top__sort_new_samples(void *arg)
if (t->evlist->selected != NULL)
t->sym_evsel = t->evlist->selected;

- hists__collapse_resort_threaded(&t->sym_evsel->hists);
- hists__output_resort_threaded(&t->sym_evsel->hists);
- hists__decay_entries_threaded(&t->sym_evsel->hists,
- t->hide_user_symbols,
- t->hide_kernel_symbols);
+ hists__collapse_resort(&t->sym_evsel->hists);
+ hists__output_resort(&t->sym_evsel->hists);
+ hists__decay_entries(&t->sym_evsel->hists,
+ t->hide_user_symbols,
+ t->hide_kernel_symbols);
}

static void *display_thread_tui(void *arg)
@@ -1126,6 +1126,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
if (setup_sorting() < 0)
usage_with_options(top_usage, options);

+ /* display thread wants entries to be collapsed in a different tree */
+ sort__need_collapse = 1;
+
if (top.use_stdio)
use_browser = 0;
else if (top.use_tui)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 72b4eec..7e0fa62 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -240,8 +240,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
return he->stat.period == 0;
}

-static void __hists__decay_entries(struct hists *hists, bool zap_user,
- bool zap_kernel, bool threaded)
+void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
{
struct rb_node *next = rb_first(&hists->entries);
struct hist_entry *n;
@@ -260,7 +259,7 @@ static void __hists__decay_entries(struct hists *hists, bool zap_user,
!n->used) {
rb_erase(&n->rb_node, &hists->entries);

- if (sort__need_collapse || threaded)
+ if (sort__need_collapse)
rb_erase(&n->rb_node_in, &hists->entries_collapsed);

hist_entry__free(n);
@@ -269,17 +268,6 @@ static void __hists__decay_entries(struct hists *hists, bool zap_user,
}
}

-void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
-{
- return __hists__decay_entries(hists, zap_user, zap_kernel, false);
-}
-
-void hists__decay_entries_threaded(struct hists *hists,
- bool zap_user, bool zap_kernel)
-{
- return __hists__decay_entries(hists, zap_user, zap_kernel, true);
-}
-
/*
* histogram, sorted on item, collects periods
*/
@@ -613,13 +601,13 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
hists__filter_entry_by_symbol(hists, he);
}

-static void __hists__collapse_resort(struct hists *hists, bool threaded)
+void hists__collapse_resort(struct hists *hists)
{
struct rb_root *root;
struct rb_node *next;
struct hist_entry *n;

- if (!sort__need_collapse && !threaded)
+ if (!sort__need_collapse)
return;

root = hists__get_rotate_entries_in(hists);
@@ -641,16 +629,6 @@ static void __hists__collapse_resort(struct hists *hists, bool threaded)
}
}

-void hists__collapse_resort(struct hists *hists)
-{
- return __hists__collapse_resort(hists, false);
-}
-
-void hists__collapse_resort_threaded(struct hists *hists)
-{
- return __hists__collapse_resort(hists, true);
-}
-
/*
* reverse the map, sort on period.
*/
@@ -737,7 +715,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
rb_insert_color(&he->rb_node, entries);
}

-static void __hists__output_resort(struct hists *hists, bool threaded)
+void hists__output_resort(struct hists *hists)
{
struct rb_root *root;
struct rb_node *next;
@@ -746,7 +724,7 @@ static void __hists__output_resort(struct hists *hists, bool threaded)

min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);

- if (sort__need_collapse || threaded)
+ if (sort__need_collapse)
root = &hists->entries_collapsed;
else
root = hists->entries_in;
@@ -767,16 +745,6 @@ static void __hists__output_resort(struct hists *hists, bool threaded)
}
}

-void hists__output_resort(struct hists *hists)
-{
- return __hists__output_resort(hists, false);
-}
-
-void hists__output_resort_threaded(struct hists *hists)
-{
- return __hists__output_resort(hists, true);
-}
-
static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
enum hist_filter filter)
{
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 6be88dc..bd81d79 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -104,13 +104,9 @@ struct hist_entry *__hists__add_mem_entry(struct hists *self,
u64 weight);

void hists__output_resort(struct hists *self);
-void hists__output_resort_threaded(struct hists *hists);
void hists__collapse_resort(struct hists *self);
-void hists__collapse_resort_threaded(struct hists *hists);

void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
-void hists__decay_entries_threaded(struct hists *hists, bool zap_user,
- bool zap_kernel);
void hists__output_recalc_col_len(struct hists *hists, int max_rows);

void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h);

Subject: [tip:perf/core] perf hists: Move locking to its call-sites

Commit-ID: 27a0dcb7adb52473dd98d285a46b764b9219d303
Gitweb: http://git.kernel.org/tip/27a0dcb7adb52473dd98d285a46b764b9219d303
Author: Namhyung Kim <[email protected]>
AuthorDate: Tue, 14 May 2013 11:09:02 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 28 May 2013 16:24:00 +0300

perf hists: Move locking to its call-sites

It's a preparation patch to eliminate unneeded locking in the perf
report path.

Signed-off-by: Namhyung Kim <[email protected]>
Acked-by: Jiri Olsa <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-report.c | 26 ++++++++++++++------------
tools/perf/builtin-top.c | 3 +++
tools/perf/util/hist.c | 6 +-----
3 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index d45bf9b..63febd2 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -297,6 +297,7 @@ static int process_sample_event(struct perf_tool *tool,
{
struct perf_report *rep = container_of(tool, struct perf_report, tool);
struct addr_location al;
+ int ret;

if (perf_event__preprocess_sample(event, machine, &al, sample,
rep->annotate_init) < 0) {
@@ -311,28 +312,29 @@ static int process_sample_event(struct perf_tool *tool,
if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
return 0;

+ pthread_mutex_lock(&evsel->hists.lock);
+
if (sort__mode == SORT_MODE__BRANCH) {
- if (perf_report__add_branch_hist_entry(tool, &al, sample,
- evsel, machine)) {
+ ret = perf_report__add_branch_hist_entry(tool, &al, sample,
+ evsel, machine);
+ if (ret < 0)
pr_debug("problem adding lbr entry, skipping event\n");
- return -1;
- }
} else if (rep->mem_mode == 1) {
- if (perf_report__add_mem_hist_entry(tool, &al, sample,
- evsel, machine, event)) {
+ ret = perf_report__add_mem_hist_entry(tool, &al, sample,
+ evsel, machine, event);
+ if (ret < 0)
pr_debug("problem adding mem entry, skipping event\n");
- return -1;
- }
} else {
if (al.map != NULL)
al.map->dso->hit = 1;

- if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) {
+ ret = perf_evsel__add_hist_entry(evsel, &al, sample, machine);
+ if (ret < 0)
pr_debug("problem incrementing symbol period, skipping event\n");
- return -1;
- }
}
- return 0;
+ pthread_mutex_unlock(&evsel->hists.lock);
+
+ return ret;
}

static int process_read_event(struct perf_tool *tool,
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 5cd41ec..c2c9734 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -245,8 +245,11 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
{
struct hist_entry *he;

+ pthread_mutex_lock(&evsel->hists.lock);
he = __hists__add_entry(&evsel->hists, al, NULL, sample->period,
sample->weight);
+ pthread_mutex_unlock(&evsel->hists.lock);
+
if (he == NULL)
return NULL;

diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 7e0fa62..b11a6cf 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -347,8 +347,6 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
struct hist_entry *he;
int cmp;

- pthread_mutex_lock(&hists->lock);
-
p = &hists->entries_in->rb_node;

while (*p != NULL) {
@@ -394,14 +392,12 @@ static struct hist_entry *add_hist_entry(struct hists *hists,

he = hist_entry__new(entry);
if (!he)
- goto out_unlock;
+ return NULL;

rb_link_node(&he->rb_node_in, parent, p);
rb_insert_color(&he->rb_node_in, hists->entries_in);
out:
hist_entry__add_cpumode_period(he, al->cpumode, period);
-out_unlock:
- pthread_mutex_unlock(&hists->lock);
return he;
}

Subject: [tip:perf/core] perf report: Don' t bother locking when adding hist entries

Commit-ID: f3dd19817e5bbcae81e96571a3d42aa30a1581fb
Gitweb: http://git.kernel.org/tip/f3dd19817e5bbcae81e96571a3d42aa30a1581fb
Author: Namhyung Kim <[email protected]>
AuthorDate: Tue, 14 May 2013 11:09:03 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 28 May 2013 16:24:00 +0300

perf report: Don't bother locking when adding hist entries

The 'perf report'command is single-threaded, so no need to grab a lock.

Although the fast path of pthread_mutex_[un]lock() is very fast, there's
a ~3% gain by eliminating it when we have huge sample data.

$ perf record -a -F 100000 -o perf.data.bench -- perf bench sched all
$ perf record -e cycles:upp -o perf.data.before -- \
> perf report -i perf.data.bench --stdio > /dev/null
... apply this patch ...
$ perf record -e cycles:upp -o perf.data.after -- \
> perf report -i perf.data.bench --stdio > /dev/null
$ perf diff perf.data.{before,after} | grep pthread
+0.02% libpthread-2.15.so [.] _pthread_cleanup_push_defer
+0.02% libpthread-2.15.so [.] _pthread_cleanup_pop_restore
0.05% -0.05% perf [.] pthread_mutex_unlock@plt
0.05% -0.05% perf [.] pthread_mutex_lock@plt
1.01% -1.01% libpthread-2.15.so [.] pthread_mutex_lock
1.68% -1.68% libpthread-2.15.so [.] __pthread_mutex_unlock_usercnt
0.05% -0.05% libpthread-2.15.so [.] pthread_mutex_unlock

Signed-off-by: Namhyung Kim <[email protected]>
Acked-by: Jiri Olsa <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-report.c | 4 ----
1 file changed, 4 deletions(-)

diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 63febd2..0f0cf24 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -312,8 +312,6 @@ static int process_sample_event(struct perf_tool *tool,
if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
return 0;

- pthread_mutex_lock(&evsel->hists.lock);
-
if (sort__mode == SORT_MODE__BRANCH) {
ret = perf_report__add_branch_hist_entry(tool, &al, sample,
evsel, machine);
@@ -332,8 +330,6 @@ static int process_sample_event(struct perf_tool *tool,
if (ret < 0)
pr_debug("problem incrementing symbol period, skipping event\n");
}
- pthread_mutex_unlock(&evsel->hists.lock);
-
return ret;
}

Subject: [tip:perf/core] perf report: Add --percent-limit option

Commit-ID: 064f19815c4e99e8b22bc3c5f4d7f4e0b96d226a
Gitweb: http://git.kernel.org/tip/064f19815c4e99e8b22bc3c5f4d7f4e0b96d226a
Author: Namhyung Kim <[email protected]>
AuthorDate: Tue, 14 May 2013 11:09:04 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 28 May 2013 16:24:01 +0300

perf report: Add --percent-limit option

The --percent-limit option is for not showing small overhead entries in
the output. Maybe we want to set a certain default value like 0.1.

Signed-off-by: Namhyung Kim <[email protected]>
Acked-by: Pekka Enberg <[email protected]>
Cc: Andi Kleen <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/Documentation/perf-report.txt | 4 ++
tools/perf/builtin-diff.c | 2 +-
tools/perf/builtin-report.c | 21 +++++++--
tools/perf/builtin-top.c | 4 +-
tools/perf/ui/browsers/hists.c | 79 +++++++++++++++++++++++++++-----
tools/perf/ui/gtk/hists.c | 13 ++++--
tools/perf/ui/stdio/hist.c | 7 ++-
tools/perf/util/hist.h | 10 ++--
8 files changed, 115 insertions(+), 25 deletions(-)

diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 7d5f4f3..66dab74 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -210,6 +210,10 @@ OPTIONS
Demangle symbol names to human readable form. It's enabled by default,
disable with --no-demangle.

+--percent-limit::
+ Do not show entries which have an overhead under that percent.
+ (Default: 0).
+
SEE ALSO
--------
linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index cabbea5..a9d63c1 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -457,7 +457,7 @@ static void hists__process(struct hists *old, struct hists *new)
hists__output_resort(new);
}

- hists__fprintf(new, true, 0, 0, stdout);
+ hists__fprintf(new, true, 0, 0, 0, stdout);
}

static int __cmd_diff(void)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 0f0cf24..0a4979b 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -52,6 +52,7 @@ struct perf_report {
symbol_filter_t annotate_init;
const char *cpu_list;
const char *symbol_filter_str;
+ float min_percent;
DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
};

@@ -456,7 +457,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
continue;

hists__fprintf_nr_sample_events(rep, hists, evname, stdout);
- hists__fprintf(hists, true, 0, 0, stdout);
+ hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout);
fprintf(stdout, "\n\n");
}

@@ -575,8 +576,8 @@ static int __cmd_report(struct perf_report *rep)
if (use_browser > 0) {
if (use_browser == 1) {
ret = perf_evlist__tui_browse_hists(session->evlist,
- help,
- NULL,
+ help, NULL,
+ rep->min_percent,
&session->header.env);
/*
* Usually "ret" is the last pressed key, and we only
@@ -587,7 +588,7 @@ static int __cmd_report(struct perf_report *rep)

} else if (use_browser == 2) {
perf_evlist__gtk_browse_hists(session->evlist, help,
- NULL);
+ NULL, rep->min_percent);
}
} else
perf_evlist__tty_browse_hists(session->evlist, rep, help);
@@ -698,6 +699,16 @@ parse_branch_mode(const struct option *opt __maybe_unused,
return 0;
}

+static int
+parse_percent_limit(const struct option *opt, const char *str,
+ int unset __maybe_unused)
+{
+ struct perf_report *rep = opt->value;
+
+ rep->min_percent = strtof(str, NULL);
+ return 0;
+}
+
int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
{
struct perf_session *session;
@@ -807,6 +818,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
"Disable symbol demangling"),
OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
+ OPT_CALLBACK(0, "percent-limit", &report, "percent",
+ "Don't show entries under that percent", parse_percent_limit),
OPT_END()
};

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index c2c9734..19fe25f 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -296,7 +296,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
top->print_entries - printed);
putchar('\n');
hists__fprintf(&top->sym_evsel->hists, false,
- top->print_entries - printed, win_width, stdout);
+ top->print_entries - printed, win_width, 0, stdout);
}

static void prompt_integer(int *target, const char *msg)
@@ -580,7 +580,7 @@ static void *display_thread_tui(void *arg)
list_for_each_entry(pos, &top->evlist->entries, node)
pos->hists.uid_filter_str = top->record_opts.target.uid_str;

- perf_evlist__tui_browse_hists(top->evlist, help, &hbt,
+ perf_evlist__tui_browse_hists(top->evlist, help, &hbt, 0,
&top->session->header.env);

done = 1;
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index a4268ca..9dfde61 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -25,6 +25,8 @@ struct hist_browser {
struct map_symbol *selection;
int print_seq;
bool show_dso;
+ float min_pcnt;
+ u64 nr_pcnt_entries;
};

extern void hist_browser__init_hpp(void);
@@ -317,6 +319,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);
@@ -795,10 +799,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;
@@ -807,10 +816,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;

@@ -820,11 +837,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);
@@ -839,6 +861,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;
@@ -847,13 +872,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:
@@ -896,7 +923,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;
@@ -929,7 +957,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;
@@ -1098,14 +1127,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;
@@ -1324,11 +1356,25 @@ close_file_and_continue:
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;
@@ -1345,6 +1391,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;
@@ -1684,6 +1735,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;
};

@@ -1777,6 +1829,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) {
@@ -1838,6 +1891,7 @@ static bool filter_group_entries(struct ui_browser *self __maybe_unused,
static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
int nr_entries, const char *help,
struct hist_browser_timer *hbt,
+ float min_pcnt,
struct perf_session_env *env)
{
struct perf_evsel *pos;
@@ -1851,6 +1905,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
.nr_entries = nr_entries,
.priv = evlist,
},
+ .min_pcnt = min_pcnt,
.env = env,
};

@@ -1869,6 +1924,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,

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)
{
int nr_entries = evlist->nr_entries;
@@ -1880,7 +1936,8 @@ single_entry:
const char *ev_name = perf_evsel__name(first);

return perf_evsel__hists_browse(first, nr_entries, help,
- ev_name, false, hbt, env);
+ ev_name, false, hbt, min_pcnt,
+ env);
}

if (symbol_conf.event_group) {
@@ -1896,5 +1953,5 @@ single_entry:
}

return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
- hbt, env);
+ hbt, min_pcnt, env);
}
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 6f259b3..9708dd5 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -124,7 +124,8 @@ void perf_gtk__init_hpp(void)
perf_gtk__hpp_color_overhead_guest_us;
}

-static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
+static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
+ float min_pcnt)
{
struct perf_hpp_fmt *fmt;
GType col_types[MAX_COLUMNS];
@@ -189,10 +190,15 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
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;
@@ -222,7 +228,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)

int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
const char *help,
- struct hist_browser_timer *hbt __maybe_unused)
+ struct hist_browser_timer *hbt __maybe_unused,
+ float min_pcnt)
{
struct perf_evsel *pos;
GtkWidget *vbox;
@@ -286,7 +293,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);

- perf_gtk__show_hists(scrolled_window, hists);
+ perf_gtk__show_hists(scrolled_window, hists, min_pcnt);

tab_label = gtk_label_new(evname);

diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index ff1f60c..ae7a754 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -334,7 +334,7 @@ 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;
@@ -440,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)
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index bd81d79..2d3790f 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -115,7 +115,7 @@ void events_stats__inc(struct events_stats *stats, u32 type);
size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);

size_t hists__fprintf(struct hists *self, bool show_header, int max_rows,
- int max_cols, FILE *fp);
+ int max_cols, float min_pcnt, FILE *fp);

int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr);
int hist_entry__annotate(struct hist_entry *self, size_t privsize);
@@ -195,6 +195,7 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,

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);
int script_browse(const char *script_opt);
#else
@@ -202,6 +203,7 @@ static inline
int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
const char *help __maybe_unused,
struct hist_browser_timer *hbt __maybe_unused,
+ float min_pcnt __maybe_unused,
struct perf_session_env *env __maybe_unused)
{
return 0;
@@ -229,12 +231,14 @@ static inline int script_browse(const char *script_opt __maybe_unused)

#ifdef GTK2_SUPPORT
int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
- struct hist_browser_timer *hbt __maybe_unused);
+ struct hist_browser_timer *hbt __maybe_unused,
+ float min_pcnt);
#else
static inline
int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
const char *help __maybe_unused,
- struct hist_browser_timer *hbt __maybe_unused)
+ struct hist_browser_timer *hbt __maybe_unused,
+ float min_pcnt __maybe_unused)
{
return 0;
}

Subject: [tip:perf/core] perf top: Add --percent-limit option

Commit-ID: fa5df94350510571cbe825f333996f57223b3cd2
Gitweb: http://git.kernel.org/tip/fa5df94350510571cbe825f333996f57223b3cd2
Author: Namhyung Kim <[email protected]>
AuthorDate: Tue, 14 May 2013 11:09:05 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 28 May 2013 16:24:01 +0300

perf top: Add --percent-limit option

The --percent-limit option is for not showing small overhead entries in
the output.

Signed-off-by: Namhyung Kim <[email protected]>
Acked-by: Pekka Enberg <[email protected]>
Cc: Andi Kleen <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/Documentation/perf-top.txt | 4 ++++
tools/perf/builtin-top.c | 17 +++++++++++++++--
tools/perf/ui/browsers/hists.c | 16 ++++++++++++++--
tools/perf/util/top.h | 1 +
4 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 9f1a2fe..7fdd190 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -155,6 +155,10 @@ Default is to monitor all CPUS.

Default: fractal,0.5,callee.

+--percent-limit::
+ Do not show entries which have an overhead under that percent.
+ (Default: 0).
+
INTERACTIVE PROMPTING KEYS
--------------------------

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 19fe25f..f036af9 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -296,7 +296,8 @@ static void perf_top__print_sym_table(struct perf_top *top)
top->print_entries - printed);
putchar('\n');
hists__fprintf(&top->sym_evsel->hists, false,
- top->print_entries - printed, win_width, 0, stdout);
+ top->print_entries - printed, win_width,
+ top->min_percent, stdout);
}

static void prompt_integer(int *target, const char *msg)
@@ -580,7 +581,7 @@ static void *display_thread_tui(void *arg)
list_for_each_entry(pos, &top->evlist->entries, node)
pos->hists.uid_filter_str = top->record_opts.target.uid_str;

- perf_evlist__tui_browse_hists(top->evlist, help, &hbt, 0,
+ perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent,
&top->session->header.env);

done = 1;
@@ -1021,6 +1022,16 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
return record_parse_callchain_opt(opt, arg, unset);
}

+static int
+parse_percent_limit(const struct option *opt, const char *arg,
+ int unset __maybe_unused)
+{
+ struct perf_top *top = opt->value;
+
+ top->min_percent = strtof(arg, NULL);
+ return 0;
+}
+
int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
{
int status;
@@ -1106,6 +1117,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
"Specify disassembler style (e.g. -M intel for intel syntax)"),
OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
+ OPT_CALLBACK(0, "percent-limit", &top, "percent",
+ "Don't show entries under that percent", parse_percent_limit),
OPT_END()
};
const char * const top_usage[] = {
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 9dfde61..fc0bd38 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -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)
{
@@ -333,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]) {
@@ -347,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,
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index f0a8625..df46be9 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -36,6 +36,7 @@ struct perf_top {
int realtime_prio;
int sym_pcnt_filter;
const char *sym_filter;
+ float min_percent;
};

size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);

Subject: [tip:perf/core] perf report: Add report.percent-limit config variable

Commit-ID: eec574e6bc3ee4558d4a282e0e3e1bd6dd0ad67b
Gitweb: http://git.kernel.org/tip/eec574e6bc3ee4558d4a282e0e3e1bd6dd0ad67b
Author: Namhyung Kim <[email protected]>
AuthorDate: Tue, 14 May 2013 11:09:06 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Tue, 28 May 2013 16:24:02 +0300

perf report: Add report.percent-limit config variable

Now an user can set a default value of --percent-limit option into the
perfconfig file.

$ cat ~/.perfconfig
[report]
percent-limit = 0.1

Signed-off-by: Namhyung Kim <[email protected]>
Acked-by: Pekka Enberg <[email protected]>
Cc: Andi Kleen <[email protected]>
Cc: David Ahern <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Pekka Enberg <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-report.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 0a4979b..ca98d34 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -62,6 +62,11 @@ static int perf_report_config(const char *var, const char *value, void *cb)
symbol_conf.event_group = perf_config_bool(var, value);
return 0;
}
+ if (!strcmp(var, "report.percent-limit")) {
+ struct perf_report *rep = cb;
+ rep->min_percent = strtof(value, NULL);
+ return 0;
+ }

return perf_default_config(var, value, cb);
}
@@ -823,7 +828,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_END()
};

- perf_config(perf_report_config, NULL);
+ perf_config(perf_report_config, &report);

argc = parse_options(argc, argv, options, report_usage, 0);