Hi,
This is my v3 of event group view support.
For basic idea and usage example, please see my original post [1].
I rebased the series on top of selected hpp changes from Jiri's diff
patchset [2] since it contains cleanups and improves that can be used
in this series too.
You can also get it via my tree at:
git://git.kernel.org/pub/scm/linux/kernel/git/namhyung/linux-perf.git perf/group-v3
Any comments are welcome, thanks,
Namhyung
v2 -> v3:
* drop patch 1 since it's merged into acme/perf/core
* cherry-pick Jiri's hpp changes
* add missing bswap_32 on reading nr_groups (Jiri)
* remove perf_evlist__recalc_nr_groups() in favor of list_is_last (Jiri)
v1 -> v2:
* save group relation to header (Jiri)
[1] https://lkml.org/lkml/2012/7/24/81
[2] https://lkml.org/lkml/2012/9/27/254
Jiri Olsa (6):
perf hists: Add struct hists pointer to struct hist_entry
perf diff: Refactor diff displacement possition info
perf hists: Separate overhead and baseline columns
perf tools: Removing hists pair argument from output path
perf tool: Add hpp interface to enable/disable hpp column
perf diff: Removing the total_period argument from output code
Namhyung Kim (14):
perf hists: Introduce struct he_stat
perf hists: Move he->stat.nr_events initialization to a template
perf hists: Add more helpers for hist entry stat
perf tools: Keep group information
perf header: Add HEADER_GROUP_DESC feature
perf hists: Collapse group hist_entries to a leader
perf hists: Maintain total periods of group members in the leader
perf report: Make another loop for output resorting
perf ui/hist: Add support for event group view
perf ui/browser: Add support for event group view
perf ui/gtk: Add support for event group view
perf report: Bypass non-leader events when event group is enabled
perf report: Show group description when event group is enabled
perf report: Add --group option
tools/perf/builtin-diff.c | 68 ++++++++++----
tools/perf/builtin-record.c | 3 +
tools/perf/builtin-report.c | 33 ++++++-
tools/perf/builtin-top.c | 2 +-
tools/perf/ui/browsers/hists.c | 115 +++++++++++++++++++---
tools/perf/ui/gtk/browser.c | 74 ++++++++++++---
tools/perf/ui/hist.c | 204 +++++++++++++++++++++++++++++-----------
tools/perf/ui/setup.c | 2 +-
tools/perf/ui/stdio/hist.c | 47 ++++-----
tools/perf/util/evlist.c | 10 +-
tools/perf/util/evlist.h | 1 +
tools/perf/util/evsel.c | 25 +++++
tools/perf/util/evsel.h | 23 +++++
tools/perf/util/header.c | 152 ++++++++++++++++++++++++++++++
tools/perf/util/header.h | 2 +
tools/perf/util/hist.c | 195 ++++++++++++++++++++++++++++++++------
tools/perf/util/hist.h | 12 +--
tools/perf/util/parse-events.c | 1 +
tools/perf/util/parse-events.h | 1 +
tools/perf/util/parse-events.y | 10 ++
tools/perf/util/sort.h | 20 ++--
tools/perf/util/symbol.c | 4 +
tools/perf/util/symbol.h | 3 +-
23 files changed, 826 insertions(+), 181 deletions(-)
--
1.7.9.2
From: Jiri Olsa <[email protected]>
Adding pointer back to the parent struct hists for struct hists_entry.
This will be useful in future for any hist_entry's data computation,
that depends on total data of its parent hists.
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Namhyung Kim <[email protected]>
Signed-off-by: Jiri Olsa <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/util/hist.c | 2 ++
tools/perf/util/sort.h | 1 +
2 files changed, 3 insertions(+)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 236bc9d98ff2..040f34c79a53 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -325,6 +325,7 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
.parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent),
.branch_info = bi,
+ .hists = self,
};
return add_hist_entry(self, &entry, al, period);
@@ -346,6 +347,7 @@ struct hist_entry *__hists__add_entry(struct hists *self,
.period = period,
.parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent),
+ .hists = self,
};
return add_hist_entry(self, &entry, al, period);
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 12d634792de5..eb3959b8e9d9 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -79,6 +79,7 @@ struct hist_entry {
struct rb_root sorted_chain;
};
struct branch_info *branch_info;
+ struct hists *hists;
struct callchain_root callchain[0];
};
--
1.7.9.2
From: Jiri Olsa <[email protected]>
Moving the position calculation into the diff command, so the position
is prepared inside struct hist_entry data and there's no need to compute
in the output display path.
Removing 'displacement' from struct perf_hpp as it is no longer needed.
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Namhyung Kim <[email protected]>
Signed-off-by: Jiri Olsa <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/builtin-diff.c | 49 ++++++++++++++++++++++++++++---------------
tools/perf/builtin-report.c | 2 +-
tools/perf/builtin-top.c | 2 +-
tools/perf/ui/hist.c | 8 ++++---
tools/perf/ui/stdio/hist.c | 17 +++------------
tools/perf/util/hist.h | 4 +---
tools/perf/util/sort.h | 2 +-
7 files changed, 44 insertions(+), 40 deletions(-)
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 761f4197a9e2..5cb577a3c5b2 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -70,8 +70,8 @@ static struct perf_tool tool = {
.ordering_requires_timestamps = true,
};
-static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
- struct hist_entry *he)
+static void insert_hist_entry_by_name(struct rb_root *root,
+ struct hist_entry *he)
{
struct rb_node **p = &root->rb_node;
struct rb_node *parent = NULL;
@@ -90,7 +90,7 @@ static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
rb_insert_color(&he->rb_node, root);
}
-static void hists__resort_entries(struct hists *self)
+static void hists__name_resort(struct hists *self, bool sort)
{
unsigned long position = 1;
struct rb_root tmp = RB_ROOT;
@@ -100,12 +100,16 @@ static void hists__resort_entries(struct hists *self)
struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
next = rb_next(&n->rb_node);
- rb_erase(&n->rb_node, &self->entries);
n->position = position++;
- perf_session__insert_hist_entry_by_name(&tmp, n);
+
+ if (sort) {
+ rb_erase(&n->rb_node, &self->entries);
+ insert_hist_entry_by_name(&tmp, n);
+ }
}
- self->entries = tmp;
+ if (sort)
+ self->entries = tmp;
}
static struct hist_entry *hists__find_entry(struct hists *self,
@@ -121,7 +125,7 @@ static struct hist_entry *hists__find_entry(struct hists *self,
n = n->rb_left;
else if (cmp > 0)
n = n->rb_right;
- else
+ else
return iter;
}
@@ -150,6 +154,24 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
return NULL;
}
+static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name)
+{
+ struct perf_evsel *evsel;
+
+ list_for_each_entry(evsel, &evlist->entries, node) {
+ struct hists *hists = &evsel->hists;
+
+ hists__output_resort(hists);
+
+ /*
+ * The hists__name_resort only sets possition
+ * if name is false.
+ */
+ if (name || ((!name) && show_displacement))
+ hists__name_resort(hists, name);
+ }
+}
+
static int __cmd_diff(void)
{
int ret, i;
@@ -176,15 +198,8 @@ static int __cmd_diff(void)
evlist_old = older->evlist;
evlist_new = newer->evlist;
- list_for_each_entry(evsel, &evlist_new->entries, node)
- hists__output_resort(&evsel->hists);
-
- list_for_each_entry(evsel, &evlist_old->entries, node) {
- hists__output_resort(&evsel->hists);
-
- if (show_displacement)
- hists__resort_entries(&evsel->hists);
- }
+ perf_evlist__resort_hists(evlist_old, true);
+ perf_evlist__resort_hists(evlist_new, false);
list_for_each_entry(evsel, &evlist_new->entries, node) {
struct perf_evsel *evsel_old;
@@ -200,7 +215,7 @@ static int __cmd_diff(void)
hists__match(&evsel_old->hists, &evsel->hists);
hists__fprintf(&evsel->hists, &evsel_old->hists,
- show_displacement, true, 0, 0, stdout);
+ true, 0, 0, stdout);
}
out_delete:
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 1da243dfbc3e..6748cac919d1 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -320,7 +320,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
const char *evname = perf_evsel__name(pos);
hists__fprintf_nr_sample_events(hists, evname, stdout);
- hists__fprintf(hists, NULL, false, true, 0, 0, stdout);
+ hists__fprintf(hists, NULL, true, 0, 0, stdout);
fprintf(stdout, "\n\n");
}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index e434a16bb5ac..6b8c62918f41 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -316,7 +316,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
hists__output_recalc_col_len(&top->sym_evsel->hists,
top->winsize.ws_row - 3);
putchar('\n');
- hists__fprintf(&top->sym_evsel->hists, NULL, false, false,
+ hists__fprintf(&top->sym_evsel->hists, NULL, false,
top->winsize.ws_row - 4 - printed, win_width, stdout);
}
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index e3f8cd46e7d7..55b9ca8f084c 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -244,13 +244,15 @@ static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused)
}
static int hpp__entry_displ(struct perf_hpp *hpp,
- struct hist_entry *he __maybe_unused)
+ struct hist_entry *he)
{
+ struct hist_entry *pair = he->pair;
+ long displacement = pair ? pair->position - he->position : 0;
const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s";
char buf[32] = " ";
- if (hpp->displacement)
- scnprintf(buf, sizeof(buf), "%+4ld", hpp->displacement);
+ if (displacement)
+ scnprintf(buf, sizeof(buf), "%+4ld", displacement);
return scnprintf(hpp->buf, hpp->size, fmt, buf);
}
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 882461a42830..d7405f064e88 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -308,7 +308,7 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
static int hist_entry__fprintf(struct hist_entry *he, size_t size,
struct hists *hists, struct hists *pair_hists,
- long displacement, u64 total_period, FILE *fp)
+ u64 total_period, FILE *fp)
{
char bf[512];
int ret;
@@ -316,7 +316,6 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
.buf = bf,
.size = size,
.total_period = total_period,
- .displacement = displacement,
.ptr = pair_hists,
};
bool color = !symbol_conf.field_sep;
@@ -337,15 +336,13 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
}
size_t hists__fprintf(struct hists *hists, struct hists *pair,
- bool show_displacement, bool show_header, int max_rows,
+ bool show_header, int max_rows,
int max_cols, FILE *fp)
{
struct sort_entry *se;
struct rb_node *nd;
size_t ret = 0;
u64 total_period;
- unsigned long position = 1;
- long displacement = 0;
unsigned int width;
const char *sep = symbol_conf.field_sep;
const char *col_width = symbol_conf.col_width_list_str;
@@ -449,15 +446,7 @@ print_entries:
if (h->filtered)
continue;
- if (show_displacement) {
- if (h->pair != NULL)
- displacement = ((long)h->pair->position -
- (long)position);
- else
- displacement = 0;
- ++position;
- }
- ret += hist_entry__fprintf(h, max_cols, hists, pair, displacement,
+ ret += hist_entry__fprintf(h, max_cols, hists, pair,
total_period, fp);
if (max_rows && ++nr_rows >= max_rows)
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 6ca74079d5c9..efb8fc8a4d24 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -99,8 +99,7 @@ void hists__inc_nr_events(struct hists *self, u32 type);
size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
size_t hists__fprintf(struct hists *self, struct hists *pair,
- bool show_displacement, bool show_header,
- int max_rows, int max_cols, FILE *fp);
+ bool show_header, int max_rows, int max_cols, 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);
@@ -120,7 +119,6 @@ struct perf_hpp {
size_t size;
u64 total_period;
const char *sep;
- long displacement;
void *ptr;
};
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index eb3959b8e9d9..f070b523c81a 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -73,8 +73,8 @@ struct hist_entry {
u8 filtered;
char *srcline;
struct symbol *parent;
+ unsigned long position;
union {
- unsigned long position;
struct hist_entry *pair;
struct rb_root sorted_chain;
};
--
1.7.9.2
From: Jiri Olsa <[email protected]>
The hists pointer is now part of the 'struct hist_entry'.
And since the overhead and baseline columns are split now,
there's no reason to pass it through the output path.
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Namhyung Kim <[email protected]>
Signed-off-by: Jiri Olsa <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/builtin-diff.c | 3 +--
tools/perf/builtin-report.c | 2 +-
tools/perf/builtin-top.c | 2 +-
tools/perf/ui/hist.c | 9 +++++----
tools/perf/ui/stdio/hist.c | 10 +++-------
tools/perf/util/hist.h | 4 ++--
6 files changed, 13 insertions(+), 17 deletions(-)
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 5cb577a3c5b2..413c65a1ba39 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -214,8 +214,7 @@ static int __cmd_diff(void)
first = false;
hists__match(&evsel_old->hists, &evsel->hists);
- hists__fprintf(&evsel->hists, &evsel_old->hists,
- true, 0, 0, stdout);
+ hists__fprintf(&evsel->hists, true, 0, 0, stdout);
}
out_delete:
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 6748cac919d1..95e7ea879b8a 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -320,7 +320,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
const char *evname = perf_evsel__name(pos);
hists__fprintf_nr_sample_events(hists, evname, stdout);
- hists__fprintf(hists, NULL, true, 0, 0, stdout);
+ hists__fprintf(hists, true, 0, 0, stdout);
fprintf(stdout, "\n\n");
}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 6b8c62918f41..dd7ff2b74675 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -316,7 +316,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
hists__output_recalc_col_len(&top->sym_evsel->hists,
top->winsize.ws_row - 3);
putchar('\n');
- hists__fprintf(&top->sym_evsel->hists, NULL, false,
+ hists__fprintf(&top->sym_evsel->hists, false,
top->winsize.ws_row - 4 - printed, win_width, stdout);
}
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 532a60177c32..6b0138e5f332 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -228,16 +228,17 @@ 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 hists *pair_hists = hpp->ptr;
+ struct hist_entry *pair = he->pair;
+ struct hists *pair_hists = pair ? pair->hists : NULL;
u64 old_total, new_total;
double old_percent = 0, new_percent = 0;
double diff;
const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
char buf[32] = " ";
- old_total = pair_hists->stats.total_period;
- if (old_total > 0 && he->pair)
- old_percent = 100.0 * he->pair->period / old_total;
+ old_total = pair_hists ? pair_hists->stats.total_period : 0;
+ if (old_total > 0 && pair)
+ old_percent = 100.0 * pair->period / old_total;
new_total = hpp->total_period;
if (new_total > 0)
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 0aa6776caba5..1340c93aa619 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -307,8 +307,7 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
}
static int hist_entry__fprintf(struct hist_entry *he, size_t size,
- struct hists *hists, struct hists *pair_hists,
- u64 total_period, FILE *fp)
+ struct hists *hists, u64 total_period, FILE *fp)
{
char bf[512];
int ret;
@@ -316,7 +315,6 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
.buf = bf,
.size = size,
.total_period = total_period,
- .ptr = pair_hists,
};
bool color = !symbol_conf.field_sep;
@@ -335,8 +333,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
return ret;
}
-size_t hists__fprintf(struct hists *hists, struct hists *pair,
- bool show_header, int max_rows,
+size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
int max_cols, FILE *fp)
{
struct sort_entry *se;
@@ -351,7 +348,6 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
struct perf_hpp dummy_hpp = {
.buf = bf,
.size = sizeof(bf),
- .ptr = pair,
};
bool first = true;
@@ -453,7 +449,7 @@ print_entries:
if (h->filtered)
continue;
- ret += hist_entry__fprintf(h, max_cols, hists, pair,
+ ret += hist_entry__fprintf(h, max_cols, hists,
total_period, fp);
if (max_rows && ++nr_rows >= max_rows)
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index b1a2b9d9b658..b83a2268b5d2 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -98,8 +98,8 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows);
void hists__inc_nr_events(struct hists *self, u32 type);
size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
-size_t hists__fprintf(struct hists *self, struct hists *pair,
- bool show_header, int max_rows, int max_cols, FILE *fp);
+size_t hists__fprintf(struct hists *self, bool show_header, int max_rows,
+ int max_cols, 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);
--
1.7.9.2
From: Jiri Olsa <[email protected]>
Adding perf_hpp__column_enable function to enable/disable hists
column and removing diff command specific stuff 'need_pair and
show_displacement' from hpp code.
The diff command now enables/disables columns separately according
to the user arguments. This will be helpful in future patches where
more columns are added into diff output.
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Namhyung Kim <[email protected]>
Signed-off-by: Jiri Olsa <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/builtin-diff.c | 18 +++++++++++++++++-
tools/perf/builtin-report.c | 2 +-
tools/perf/ui/browsers/hists.c | 2 +-
tools/perf/ui/gtk/browser.c | 2 +-
tools/perf/ui/hist.c | 15 ++++++---------
tools/perf/ui/setup.c | 2 +-
tools/perf/util/hist.h | 3 ++-
7 files changed, 29 insertions(+), 15 deletions(-)
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 413c65a1ba39..a0b531c14b97 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -256,6 +256,21 @@ static const struct option options[] = {
OPT_END()
};
+static void ui_init(void)
+{
+ perf_hpp__init();
+
+ /* No overhead column. */
+ perf_hpp__column_enable(PERF_HPP__OVERHEAD, false);
+
+ /* Display baseline/delta/displacement columns. */
+ perf_hpp__column_enable(PERF_HPP__BASELINE, true);
+ perf_hpp__column_enable(PERF_HPP__DELTA, true);
+
+ if (show_displacement)
+ perf_hpp__column_enable(PERF_HPP__DISPL, true);
+}
+
int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
{
sort_order = diff__default_sort_order;
@@ -278,7 +293,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
if (symbol__init() < 0)
return -1;
- perf_hpp__init(true, show_displacement);
+ ui_init();
+
setup_sorting(diff_usage, options);
setup_pager();
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 95e7ea879b8a..a61725d89d3e 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -691,7 +691,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
setup_browser(true);
else {
use_browser = 0;
- perf_hpp__init(false, false);
+ perf_hpp__init();
}
setup_sorting(report_usage, options);
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index a21f40bebbac..bbd11c2f69db 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -584,7 +584,7 @@ HPP__COLOR_FN(overhead_guest_us, period_guest_us)
void hist_browser__init_hpp(void)
{
- perf_hpp__init(false, false);
+ perf_hpp__init();
perf_hpp__format[PERF_HPP__OVERHEAD].color =
hist_browser__hpp_color_overhead;
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 7ff99ec1d95e..2bc08f6af714 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -73,7 +73,7 @@ HPP__COLOR_FN(overhead_guest_us, period_guest_us)
void perf_gtk__init_hpp(void)
{
- perf_hpp__init(false, false);
+ perf_hpp__init();
perf_hpp__format[PERF_HPP__OVERHEAD].color =
perf_gtk__hpp_color_overhead;
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 6b0138e5f332..e8853f7780a3 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -302,7 +302,7 @@ struct perf_hpp_fmt perf_hpp__format[] = {
#undef HPP__COLOR_PRINT_FNS
#undef HPP__PRINT_FNS
-void perf_hpp__init(bool need_pair, bool show_displacement)
+void perf_hpp__init(void)
{
if (symbol_conf.show_cpu_utilization) {
perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true;
@@ -319,15 +319,12 @@ void perf_hpp__init(bool need_pair, bool show_displacement)
if (symbol_conf.show_total_period)
perf_hpp__format[PERF_HPP__PERIOD].cond = true;
+}
- if (need_pair) {
- perf_hpp__format[PERF_HPP__OVERHEAD].cond = false;
- perf_hpp__format[PERF_HPP__BASELINE].cond = true;
- perf_hpp__format[PERF_HPP__DELTA].cond = true;
-
- if (show_displacement)
- perf_hpp__format[PERF_HPP__DISPL].cond = true;
- }
+void perf_hpp__column_enable(unsigned col, bool enable)
+{
+ BUG_ON(col >= PERF_HPP__MAX_INDEX);
+ perf_hpp__format[col].cond = enable;
}
static inline void advance_hpp(struct perf_hpp *hpp, int inc)
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
index bd7d460f844c..ebb4cc107876 100644
--- a/tools/perf/ui/setup.c
+++ b/tools/perf/ui/setup.c
@@ -30,7 +30,7 @@ void setup_browser(bool fallback_to_pager)
if (fallback_to_pager)
setup_pager();
- perf_hpp__init(false, false);
+ perf_hpp__init();
break;
}
}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index b83a2268b5d2..a7f69d69dc66 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -147,7 +147,8 @@ enum {
PERF_HPP__MAX_INDEX
};
-void perf_hpp__init(bool need_pair, bool show_displacement);
+void perf_hpp__init(void);
+void perf_hpp__column_enable(unsigned col, bool enable);
int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
bool color);
--
1.7.9.2
From: Jiri Olsa <[email protected]>
The total_period is available in struct hists data via the 'struct
hist_entry::hists' pointer. There's no need to carry it through the
output code path.
Removing 'struct perf_hpp::total_period' pointer, because it's no
longer needed.
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Namhyung Kim <[email protected]>
Signed-off-by: Jiri Olsa <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/ui/browsers/hists.c | 4 ++--
tools/perf/ui/gtk/browser.c | 4 ++--
tools/perf/ui/hist.c | 37 ++++++++++++++++++++++++++-----------
tools/perf/ui/stdio/hist.c | 15 +++++----------
tools/perf/util/hist.h | 1 -
5 files changed, 35 insertions(+), 26 deletions(-)
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index bbd11c2f69db..d359795454d0 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -569,7 +569,8 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \
struct hist_entry *he) \
{ \
- double percent = 100.0 * he->_field / hpp->total_period; \
+ struct hists *hists = he->hists; \
+ double percent = 100.0 * he->_field / hists->stats.total_period;\
*(double *)hpp->ptr = percent; \
return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \
}
@@ -624,7 +625,6 @@ static int hist_browser__show_entry(struct hist_browser *browser,
struct perf_hpp hpp = {
.buf = s,
.size = sizeof(s),
- .total_period = browser->hists->stats.total_period,
};
ui_browser__gotorc(&browser->b, row, 0);
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 2bc08f6af714..3cbb1d622ed2 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -49,7 +49,8 @@ static const char *perf_gtk__get_percent_color(double percent)
static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \
struct hist_entry *he) \
{ \
- double percent = 100.0 * he->_field / hpp->total_period; \
+ struct hists *hists = he->hists; \
+ double percent = 100.0 * he->_field / hists->stats.total_period; \
const char *markup; \
int ret = 0; \
\
@@ -102,7 +103,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
struct perf_hpp hpp = {
.buf = s,
.size = sizeof(s),
- .total_period = hists->stats.total_period,
};
nr_cols = 0;
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index e8853f7780a3..7f043394bef1 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -18,14 +18,16 @@ static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused)
static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
{
- double percent = 100.0 * he->period / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->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)
{
- double percent = 100.0 * he->period / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->period / hists->stats.total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
return scnprintf(hpp->buf, hpp->size, fmt, percent);
@@ -45,13 +47,16 @@ static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused)
static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
{
- double percent = 100.0 * he->period_sys / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->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)
{
- double percent = 100.0 * he->period_sys / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->period_sys / hists->stats.total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
return scnprintf(hpp->buf, hpp->size, fmt, percent);
@@ -71,13 +76,16 @@ static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused)
static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
{
- double percent = 100.0 * he->period_us / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->period_us / hists->stats.total_period;
+
return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
}
static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
{
- double percent = 100.0 * he->period_us / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->period_us / hists->stats.total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
return scnprintf(hpp->buf, hpp->size, fmt, percent);
@@ -96,14 +104,17 @@ static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused)
static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp,
struct hist_entry *he)
{
- double percent = 100.0 * he->period_guest_sys / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->period_guest_sys / hists->stats.total_period;
+
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
}
static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp,
struct hist_entry *he)
{
- double percent = 100.0 * he->period_guest_sys / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->period_guest_sys / hists->stats.total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
return scnprintf(hpp->buf, hpp->size, fmt, percent);
@@ -122,14 +133,17 @@ static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused)
static int hpp__color_overhead_guest_us(struct perf_hpp *hpp,
struct hist_entry *he)
{
- double percent = 100.0 * he->period_guest_us / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->period_guest_us / hists->stats.total_period;
+
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
}
static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp,
struct hist_entry *he)
{
- double percent = 100.0 * he->period_guest_us / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->period_guest_us / hists->stats.total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
return scnprintf(hpp->buf, hpp->size, fmt, percent);
@@ -230,6 +244,7 @@ static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hist_entry *pair = he->pair;
struct hists *pair_hists = pair ? pair->hists : NULL;
+ struct hists *hists = he->hists;
u64 old_total, new_total;
double old_percent = 0, new_percent = 0;
double diff;
@@ -240,7 +255,7 @@ static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
if (old_total > 0 && pair)
old_percent = 100.0 * pair->period / old_total;
- new_total = hpp->total_period;
+ new_total = hists->stats.total_period;
if (new_total > 0)
new_percent = 100.0 * he->period / new_total;
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 1340c93aa619..850c6d293f46 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -292,9 +292,10 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
struct hists *hists,
- u64 total_period, FILE *fp)
+ FILE *fp)
{
int left_margin = 0;
+ u64 total_period = hists->stats.total_period;
if (sort__first_dimension == SORT_COMM) {
struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
@@ -307,14 +308,13 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
}
static int hist_entry__fprintf(struct hist_entry *he, size_t size,
- struct hists *hists, u64 total_period, FILE *fp)
+ struct hists *hists, FILE *fp)
{
char bf[512];
int ret;
struct perf_hpp hpp = {
.buf = bf,
.size = size,
- .total_period = total_period,
};
bool color = !symbol_conf.field_sep;
@@ -327,8 +327,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
ret = fprintf(fp, "%s\n", bf);
if (symbol_conf.use_callchain)
- ret += hist_entry__callchain_fprintf(he, hists,
- total_period, fp);
+ ret += hist_entry__callchain_fprintf(he, hists, fp);
return ret;
}
@@ -339,7 +338,6 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
struct sort_entry *se;
struct rb_node *nd;
size_t ret = 0;
- u64 total_period;
unsigned int width;
const char *sep = symbol_conf.field_sep;
const char *col_width = symbol_conf.col_width_list_str;
@@ -441,16 +439,13 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
goto out;
print_entries:
- total_period = hists->stats.total_period;
-
for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
if (h->filtered)
continue;
- ret += hist_entry__fprintf(h, max_cols, hists,
- total_period, fp);
+ ret += hist_entry__fprintf(h, max_cols, hists, fp);
if (max_rows && ++nr_rows >= max_rows)
goto out;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index a7f69d69dc66..66cb31fe81d2 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -117,7 +117,6 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *he);
struct perf_hpp {
char *buf;
size_t size;
- u64 total_period;
const char *sep;
void *ptr;
};
--
1.7.9.2
From: Namhyung Kim <[email protected]>
The struct he_stat is for separating out statistics data of a hist
entry. It is required for later changes.
It's just a mechanical change and should have no functional
differences.
Cc: Jiri Olsa <[email protected]>
Cc: Arun Sharma <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/ui/browsers/hists.c | 8 +++----
tools/perf/ui/gtk/browser.c | 2 +-
tools/perf/ui/hist.c | 30 +++++++++++------------
tools/perf/ui/stdio/hist.c | 2 +-
tools/perf/util/hist.c | 52 +++++++++++++++++++++-------------------
tools/perf/util/sort.h | 16 ++++++++-----
6 files changed, 59 insertions(+), 51 deletions(-)
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index d359795454d0..0568536ecf67 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -570,7 +570,7 @@ static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \
struct hist_entry *he) \
{ \
struct hists *hists = he->hists; \
- double percent = 100.0 * he->_field / hists->stats.total_period;\
+ double percent = 100.0 * he->stat._field / hists->stats.total_period; \
*(double *)hpp->ptr = percent; \
return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \
}
@@ -982,7 +982,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
folded_sign = hist_entry__folded(he);
hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists);
- percent = (he->period * 100.0) / browser->hists->stats.total_period;
+ percent = (he->stat.period * 100.0) / browser->hists->stats.total_period;
if (symbol_conf.use_callchain)
printed += fprintf(fp, "%c ", folded_sign);
@@ -990,10 +990,10 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
printed += fprintf(fp, " %5.2f%%", percent);
if (symbol_conf.show_nr_samples)
- printed += fprintf(fp, " %11u", he->nr_events);
+ printed += fprintf(fp, " %11u", he->stat.nr_events);
if (symbol_conf.show_total_period)
- printed += fprintf(fp, " %12" PRIu64, he->period);
+ printed += fprintf(fp, " %12" PRIu64, he->stat.period);
printed += fprintf(fp, "%s\n", rtrim(s));
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 3cbb1d622ed2..4125c6284114 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -50,7 +50,7 @@ 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->_field / hists->stats.total_period; \
+ double percent = 100.0 * he->stat._field / hists->stats.total_period; \
const char *markup; \
int ret = 0; \
\
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 7f043394bef1..f5a1e4f65263 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -19,7 +19,7 @@ static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused)
static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hists *hists = he->hists;
- double percent = 100.0 * he->period / hists->stats.total_period;
+ double percent = 100.0 * he->stat.period / hists->stats.total_period;
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
}
@@ -27,7 +27,7 @@ static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hists *hists = he->hists;
- double percent = 100.0 * he->period / hists->stats.total_period;
+ 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);
@@ -48,7 +48,7 @@ static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused)
static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hists *hists = he->hists;
- double percent = 100.0 * he->period_sys / hists->stats.total_period;
+ double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
}
@@ -56,7 +56,7 @@ static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hists *hists = he->hists;
- double percent = 100.0 * he->period_sys / hists->stats.total_period;
+ 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);
@@ -77,7 +77,7 @@ static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused)
static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hists *hists = he->hists;
- double percent = 100.0 * he->period_us / hists->stats.total_period;
+ double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
}
@@ -85,7 +85,7 @@ static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hists *hists = he->hists;
- double percent = 100.0 * he->period_us / hists->stats.total_period;
+ double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
return scnprintf(hpp->buf, hpp->size, fmt, percent);
@@ -105,7 +105,7 @@ 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->period_guest_sys / hists->stats.total_period;
+ double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
}
@@ -114,7 +114,7 @@ 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->period_guest_sys / hists->stats.total_period;
+ double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
return scnprintf(hpp->buf, hpp->size, fmt, percent);
@@ -134,7 +134,7 @@ 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->period_guest_us / hists->stats.total_period;
+ double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
}
@@ -143,7 +143,7 @@ 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->period_guest_us / hists->stats.total_period;
+ double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
return scnprintf(hpp->buf, hpp->size, fmt, percent);
@@ -167,7 +167,7 @@ static double baseline_percent(struct hist_entry *he)
if (pair) {
u64 total_period = pair_hists->stats.total_period;
- u64 base_period = pair->period;
+ u64 base_period = pair->stat.period;
percent = 100.0 * base_period / total_period;
}
@@ -206,7 +206,7 @@ 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->nr_events);
+ return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events);
}
static int hpp__header_period(struct perf_hpp *hpp)
@@ -225,7 +225,7 @@ 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->period);
+ return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period);
}
static int hpp__header_delta(struct perf_hpp *hpp)
@@ -253,11 +253,11 @@ static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
old_total = pair_hists ? pair_hists->stats.total_period : 0;
if (old_total > 0 && pair)
- old_percent = 100.0 * pair->period / old_total;
+ old_percent = 100.0 * pair->stat.period / old_total;
new_total = hists->stats.total_period;
if (new_total > 0)
- new_percent = 100.0 * he->period / new_total;
+ new_percent = 100.0 * he->stat.period / new_total;
diff = new_percent - old_percent;
if (fabs(diff) >= 0.01)
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 850c6d293f46..fbd4e32d0743 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -271,7 +271,7 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
{
switch (callchain_param.mode) {
case CHAIN_GRAPH_REL:
- return callchain__fprintf_graph(fp, &he->sorted_chain, he->period,
+ return callchain__fprintf_graph(fp, &he->sorted_chain, he->stat.period,
left_margin);
break;
case CHAIN_GRAPH_ABS:
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 040f34c79a53..3197f3f50018 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -135,16 +135,16 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he,
{
switch (cpumode) {
case PERF_RECORD_MISC_KERNEL:
- he->period_sys += period;
+ he->stat.period_sys += period;
break;
case PERF_RECORD_MISC_USER:
- he->period_us += period;
+ he->stat.period_us += period;
break;
case PERF_RECORD_MISC_GUEST_KERNEL:
- he->period_guest_sys += period;
+ he->stat.period_guest_sys += period;
break;
case PERF_RECORD_MISC_GUEST_USER:
- he->period_guest_us += period;
+ he->stat.period_guest_us += period;
break;
default:
break;
@@ -153,13 +153,13 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he,
static void hist_entry__decay(struct hist_entry *he)
{
- he->period = (he->period * 7) / 8;
- he->nr_events = (he->nr_events * 7) / 8;
+ he->stat.period = (he->stat.period * 7) / 8;
+ he->stat.nr_events = (he->stat.nr_events * 7) / 8;
}
static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
{
- u64 prev_period = he->period;
+ u64 prev_period = he->stat.period;
if (prev_period == 0)
return true;
@@ -167,9 +167,9 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
hist_entry__decay(he);
if (!he->filtered)
- hists->stats.total_period -= prev_period - he->period;
+ hists->stats.total_period -= prev_period - he->stat.period;
- return he->period == 0;
+ return he->stat.period == 0;
}
static void __hists__decay_entries(struct hists *hists, bool zap_user,
@@ -223,7 +223,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
if (he != NULL) {
*he = *template;
- he->nr_events = 1;
+ he->stat.nr_events = 1;
if (he->ms.map)
he->ms.map->referenced = true;
if (symbol_conf.use_callchain)
@@ -238,7 +238,7 @@ static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
if (!h->filtered) {
hists__calc_col_len(hists, h);
++hists->nr_entries;
- hists->stats.total_period += h->period;
+ hists->stats.total_period += h->stat.period;
}
}
@@ -270,8 +270,8 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
cmp = hist_entry__cmp(entry, he);
if (!cmp) {
- he->period += period;
- ++he->nr_events;
+ he->stat.period += period;
+ ++he->stat.nr_events;
/* If the map of an existing hist_entry has
* become out-of-date due to an exec() or
@@ -321,7 +321,9 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
.cpu = al->cpu,
.ip = bi->to.addr,
.level = al->level,
- .period = period,
+ .stat = {
+ .period = period,
+ },
.parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent),
.branch_info = bi,
@@ -344,7 +346,9 @@ struct hist_entry *__hists__add_entry(struct hists *self,
.cpu = al->cpu,
.ip = al->addr,
.level = al->level,
- .period = period,
+ .stat = {
+ .period = period,
+ },
.parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent),
.hists = self,
@@ -412,12 +416,12 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
cmp = hist_entry__collapse(iter, he);
if (!cmp) {
- iter->period += he->period;
- iter->period_sys += he->period_sys;
- iter->period_us += he->period_us;
- iter->period_guest_sys += he->period_guest_sys;
- iter->period_guest_us += he->period_guest_us;
- iter->nr_events += he->nr_events;
+ iter->stat.period += he->stat.period;
+ iter->stat.period_sys += he->stat.period_sys;
+ iter->stat.period_us += he->stat.period_us;
+ iter->stat.period_guest_sys += he->stat.period_guest_sys;
+ iter->stat.period_guest_us += he->stat.period_guest_us;
+ iter->stat.nr_events += he->stat.nr_events;
if (symbol_conf.use_callchain) {
callchain_cursor_reset(&callchain_cursor);
@@ -520,7 +524,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
parent = *p;
iter = rb_entry(parent, struct hist_entry, rb_node);
- if (he->period > iter->period)
+ if (he->stat.period > iter->stat.period)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
@@ -581,8 +585,8 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
if (h->ms.unfolded)
hists->nr_entries += h->nr_rows;
h->row_offset = 0;
- hists->stats.total_period += h->period;
- hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
+ hists->stats.total_period += h->stat.period;
+ hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->stat.nr_events;
hists__calc_col_len(hists, h);
}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index f070b523c81a..5786f323b597 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -43,6 +43,15 @@ extern struct sort_entry sort_sym_from;
extern struct sort_entry sort_sym_to;
extern enum sort_type sort__first_dimension;
+struct he_stat {
+ u64 period;
+ u64 period_sys;
+ u64 period_us;
+ u64 period_guest_sys;
+ u64 period_guest_us;
+ u32 nr_events;
+};
+
/**
* struct hist_entry - histogram entry
*
@@ -52,16 +61,11 @@ extern enum sort_type sort__first_dimension;
struct hist_entry {
struct rb_node rb_node_in;
struct rb_node rb_node;
- u64 period;
- u64 period_sys;
- u64 period_us;
- u64 period_guest_sys;
- u64 period_guest_us;
+ struct he_stat stat;
struct map_symbol ms;
struct thread *thread;
u64 ip;
s32 cpu;
- u32 nr_events;
/* XXX These two should move to some tree widget lib */
u16 row_offset;
--
1.7.9.2
From: Namhyung Kim <[email protected]>
Add and use he_stat__add_{period,stat} for calculating hist entry's
stat. It will be used for accumulated stats later as well.
Cc: Jiri Olsa <[email protected]>
Cc: Arun Sharma <[email protected]>
Cc: Stephane Eranian <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/util/hist.c | 26 ++++++++++++++++++--------
1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 02476cb3167d..277947a669b2 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -151,6 +151,22 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he,
}
}
+static void he_stat__add_period(struct he_stat *he_stat, u64 period)
+{
+ he_stat->period += period;
+ he_stat->nr_events += 1;
+}
+
+static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
+{
+ dest->period += src->period;
+ dest->period_sys += src->period_sys;
+ dest->period_us += src->period_us;
+ dest->period_guest_sys += src->period_guest_sys;
+ dest->period_guest_us += src->period_guest_us;
+ dest->nr_events += src->nr_events;
+}
+
static void hist_entry__decay(struct hist_entry *he)
{
he->stat.period = (he->stat.period * 7) / 8;
@@ -270,8 +286,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
cmp = hist_entry__cmp(entry, he);
if (!cmp) {
- he->stat.period += period;
- ++he->stat.nr_events;
+ he_stat__add_period(&he->stat, period);
/* If the map of an existing hist_entry has
* become out-of-date due to an exec() or
@@ -418,12 +433,7 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
cmp = hist_entry__collapse(iter, he);
if (!cmp) {
- iter->stat.period += he->stat.period;
- iter->stat.period_sys += he->stat.period_sys;
- iter->stat.period_us += he->stat.period_us;
- iter->stat.period_guest_sys += he->stat.period_guest_sys;
- iter->stat.period_guest_us += he->stat.period_guest_us;
- iter->stat.nr_events += he->stat.nr_events;
+ he_stat__add_stat(&iter->stat, &he->stat);
if (symbol_conf.use_callchain) {
callchain_cursor_reset(&callchain_cursor);
--
1.7.9.2
From: Namhyung Kim <[email protected]>
Add a few of group-related field in struct perf_{evlist,evsel} so that
the group information in a evlist can be known easily. It only counts
groups which have more than 1 members since leader-only groups are
treated as non-group events.
Cc: Jiri Olsa <[email protected]>
Cc: Stephane Eranian <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/util/evlist.c | 10 ++++++++--
tools/perf/util/evlist.h | 1 +
tools/perf/util/evsel.h | 10 ++++++++++
tools/perf/util/parse-events.c | 1 +
tools/perf/util/parse-events.h | 1 +
tools/perf/util/parse-events.y | 10 ++++++++++
6 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index ae89686102f4..ac9730c12884 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -111,20 +111,26 @@ void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
void __perf_evlist__set_leader(struct list_head *list)
{
struct perf_evsel *evsel, *leader;
+ int count = 0;
leader = list_entry(list->next, struct perf_evsel, node);
leader->leader = NULL;
list_for_each_entry(evsel, list, node) {
- if (evsel != leader)
+ if (evsel != leader) {
evsel->leader = leader;
+ evsel->group_idx = count++;
+ }
}
+ leader->nr_members = count;
}
void perf_evlist__set_leader(struct perf_evlist *evlist)
{
- if (evlist->nr_entries)
+ if (evlist->nr_entries) {
+ evlist->nr_groups = evlist->nr_entries > 1 ? 1 : 0;
__perf_evlist__set_leader(&evlist->entries);
+ }
}
int perf_evlist__add_default(struct perf_evlist *evlist)
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 3f1fb66be022..a3a4906d4a4e 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -21,6 +21,7 @@ struct perf_evlist {
struct list_head entries;
struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
int nr_entries;
+ int nr_groups;
int nr_fds;
int nr_mmaps;
int mmap_len;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 3ead0d59c03d..407c8e84fee3 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -74,6 +74,10 @@ struct perf_evsel {
int exclude_GH;
struct perf_evsel *leader;
char *group_name;
+ union {
+ int nr_members;
+ int group_idx;
+ };
};
struct cpu_map;
@@ -225,4 +229,10 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel)
{
return list_entry(evsel->node.next, struct perf_evsel, node);
}
+
+/* Treat a non-group event as a leader */
+static inline bool perf_evsel__is_group_leader(struct perf_evsel *evsel)
+{
+ return evsel->leader == NULL;
+}
#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index aed38e4b9dfa..364e518b0fce 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -816,6 +816,7 @@ int parse_events(struct perf_evlist *evlist, const char *str,
if (!ret) {
int entries = data.idx - evlist->nr_entries;
perf_evlist__splice_list_tail(evlist, &data.list, entries);
+ evlist->nr_groups += data.nr_groups;
return 0;
}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index c356e443448d..f6b0254afe17 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -65,6 +65,7 @@ struct parse_events__term {
struct parse_events_data__events {
struct list_head list;
int idx;
+ int nr_groups;
};
struct parse_events_data__terms {
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index cd88209e3c58..a7810dd0938a 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -122,6 +122,11 @@ group_def:
PE_NAME '{' events '}'
{
struct list_head *list = $3;
+ struct parse_events_data__events *data = _data;
+
+ /* Count groups only have more than 1 members */
+ if (!list_is_last(list->next, list))
+ data->nr_groups++;
parse_events__set_leader($1, list);
$$ = list;
@@ -130,6 +135,11 @@ PE_NAME '{' events '}'
'{' events '}'
{
struct list_head *list = $2;
+ struct parse_events_data__events *data = _data;
+
+ /* Count groups only have more than 1 members */
+ if (!list_is_last(list->next, list))
+ data->nr_groups++;
parse_events__set_leader(NULL, list);
$$ = list;
--
1.7.9.2
From: Namhyung Kim <[email protected]>
To support viewing an event group together, collapse all of members in
the group to the leader's tree. The entries in the leaders' tree will
have group_stats to store those information.
This patch introduced an additional field 'event_group' in symbol_conf
to distinguish whether event grouping is enabled or not.
Cc: Jiri Olsa <[email protected]>
Cc: Stephane Eranian <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/util/evsel.h | 5 +++
tools/perf/util/hist.c | 108 ++++++++++++++++++++++++++++++++++++++++++----
tools/perf/util/sort.h | 1 +
tools/perf/util/symbol.c | 4 ++
tools/perf/util/symbol.h | 3 +-
5 files changed, 112 insertions(+), 9 deletions(-)
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 407c8e84fee3..039c67297388 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -235,4 +235,9 @@ static inline bool perf_evsel__is_group_leader(struct perf_evsel *evsel)
{
return evsel->leader == NULL;
}
+
+static inline struct perf_evsel *hists_2_evsel(struct hists *hists)
+{
+ return container_of(hists, struct perf_evsel, hists);
+}
#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 277947a669b2..95415716c708 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -4,6 +4,7 @@
#include "hist.h"
#include "session.h"
#include "sort.h"
+#include "evsel.h"
#include <math.h>
static bool hists__filter_entry_by_dso(struct hists *hists,
@@ -167,6 +168,32 @@ static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
dest->nr_events += src->nr_events;
}
+static void hist_entry__add_group_stat(struct hist_entry *he_dest,
+ struct he_stat *src,
+ struct perf_evsel *evsel)
+{
+ struct perf_evsel *leader = evsel->leader;
+
+ if (perf_evsel__is_group_leader(evsel))
+ leader = evsel;
+
+ if (leader->nr_members && !he_dest->group_stats) {
+ /*
+ * A group whose nr_members equals to 0 is a leader-only group.
+ * So no need to allocate group_stats.
+ */
+ he_dest->group_stats = calloc(leader->nr_members,
+ sizeof(struct he_stat));
+ if (!he_dest->group_stats)
+ return;
+ }
+
+ if (perf_evsel__is_group_leader(evsel))
+ he_stat__add_stat(&he_dest->stat, src);
+ else
+ he_stat__add_stat(&he_dest->group_stats[evsel->group_idx], src);
+}
+
static void hist_entry__decay(struct hist_entry *he)
{
he->stat.period = (he->stat.period * 7) / 8;
@@ -417,13 +444,14 @@ void hist_entry__free(struct hist_entry *he)
* collapse the histogram
*/
-static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
+static bool hists__collapse_insert_entry(struct hists *hists,
struct rb_root *root,
struct hist_entry *he)
{
struct rb_node **p = &root->rb_node;
struct rb_node *parent = NULL;
struct hist_entry *iter;
+ struct perf_evsel *evsel = hists_2_evsel(hists);
int64_t cmp;
while (*p != NULL) {
@@ -433,7 +461,10 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
cmp = hist_entry__collapse(iter, he);
if (!cmp) {
- he_stat__add_stat(&iter->stat, &he->stat);
+ if (symbol_conf.event_group)
+ hist_entry__add_group_stat(iter, &he->stat, evsel);
+ else
+ he_stat__add_stat(&iter->stat, &he->stat);
if (symbol_conf.use_callchain) {
callchain_cursor_reset(&callchain_cursor);
@@ -451,6 +482,19 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
p = &(*p)->rb_right;
}
+ if (symbol_conf.event_group) {
+ /*
+ * 'he' is not found in the leader's tree.
+ * Insert it to the tree and setup stats properly.
+ */
+ hist_entry__add_group_stat(he, &he->stat, evsel);
+
+ if (!perf_evsel__is_group_leader(evsel)) {
+ he->hists = &evsel->leader->hists;
+ memset(&he->stat, 0, sizeof(he->stat));
+ }
+ }
+
rb_link_node(&he->rb_node_in, parent, p);
rb_insert_color(&he->rb_node_in, root);
return true;
@@ -481,6 +525,7 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
static void __hists__collapse_resort(struct hists *hists, bool threaded)
{
struct rb_root *root;
+ struct rb_root *dest;
struct rb_node *next;
struct hist_entry *n;
@@ -488,14 +533,26 @@ static void __hists__collapse_resort(struct hists *hists, bool threaded)
return;
root = hists__get_rotate_entries_in(hists);
+ dest = &hists->entries_collapsed;
next = rb_first(root);
+ if (symbol_conf.event_group) {
+ /*
+ * Collapse hist entries to the leader's tree.
+ * If evsel->leader == NULL, it's the leader.
+ */
+ struct perf_evsel *leader = hists_2_evsel(hists)->leader;
+
+ if (leader)
+ dest = &leader->hists.entries_collapsed;
+ }
+
while (next) {
n = rb_entry(next, struct hist_entry, rb_node_in);
next = rb_next(&n->rb_node_in);
rb_erase(&n->rb_node_in, root);
- if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n)) {
+ if (hists__collapse_insert_entry(hists, dest, n)) {
/*
* If it wasn't combined with one of the entries already
* collapsed, we need to apply the filters that may have
@@ -520,13 +577,38 @@ void hists__collapse_resort_threaded(struct hists *hists)
* reverse the map, sort on period.
*/
-static void __hists__insert_output_entry(struct rb_root *entries,
+static int __hists__output_cmp(struct hist_entry *left,
+ struct hist_entry *right,
+ int nr_group_stats)
+{
+ if (left->stat.period > right->stat.period)
+ return 1;
+ if (left->stat.period < right->stat.period)
+ return -1;
+
+ if (symbol_conf.event_group) {
+ int i;
+
+ for (i = 0; i < nr_group_stats; i++) {
+ if (left->group_stats[i].period >
+ right->group_stats[i].period)
+ return 1;
+ if (left->group_stats[i].period <
+ right->group_stats[i].period)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static void __hists__insert_output_entry(struct hists *hists,
struct hist_entry *he,
u64 min_callchain_hits)
{
- struct rb_node **p = &entries->rb_node;
+ struct rb_node **p = &hists->entries.rb_node;
struct rb_node *parent = NULL;
struct hist_entry *iter;
+ struct perf_evsel *evsel = hists_2_evsel(hists);
if (symbol_conf.use_callchain)
callchain_param.sort(&he->sorted_chain, he->callchain,
@@ -536,14 +618,14 @@ static void __hists__insert_output_entry(struct rb_root *entries,
parent = *p;
iter = rb_entry(parent, struct hist_entry, rb_node);
- if (he->stat.period > iter->stat.period)
+ if (__hists__output_cmp(he, iter, evsel->nr_members) > 0)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
}
rb_link_node(&he->rb_node, parent, p);
- rb_insert_color(&he->rb_node, entries);
+ rb_insert_color(&he->rb_node, &hists->entries);
}
static void __hists__output_resort(struct hists *hists, bool threaded)
@@ -553,6 +635,16 @@ static void __hists__output_resort(struct hists *hists, bool threaded)
struct hist_entry *n;
u64 min_callchain_hits;
+ if (symbol_conf.event_group) {
+ struct perf_evsel *evsel = hists_2_evsel(hists);
+
+ /*
+ * We've collapsed all member entries to the leader.
+ */
+ if (!perf_evsel__is_group_leader(evsel))
+ return;
+ }
+
min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
if (sort__need_collapse || threaded)
@@ -571,7 +663,7 @@ static void __hists__output_resort(struct hists *hists, bool threaded)
n = rb_entry(next, struct hist_entry, rb_node_in);
next = rb_next(&n->rb_node_in);
- __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
+ __hists__insert_output_entry(hists, n, min_callchain_hits);
hists__inc_nr_entries(hists, n);
}
}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 5786f323b597..5b9ca063286b 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -62,6 +62,7 @@ struct hist_entry {
struct rb_node rb_node_in;
struct rb_node rb_node;
struct he_stat stat;
+ struct he_stat *group_stats;
struct map_symbol ms;
struct thread *thread;
u64 ip;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index e2e8c697cffe..bb2ef6920ccf 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -11,6 +11,7 @@
#include <inttypes.h>
#include "build-id.h"
#include "util.h"
+#include "sort.h"
#include "debug.h"
#include "symbol.h"
#include "strlist.h"
@@ -2033,6 +2034,9 @@ int symbol__init(void)
symbol_conf.kptr_restrict = symbol__read_kptr_restrict();
+ if (symbol_conf.event_group)
+ sort__need_collapse = 1;
+
symbol_conf.initialized = true;
return 0;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index e1484bb080e6..5fd7d0dd06dc 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -100,7 +100,8 @@ struct symbol_conf {
initialized,
kptr_restrict,
annotate_asm_raw,
- annotate_src;
+ annotate_src,
+ event_group;
const char *vmlinux_name,
*kallsyms_name,
*source_prefix,
--
1.7.9.2
From: Namhyung Kim <[email protected]>
Now the event grouping viewing requires collapsing all members in a
group to the leader. Thus hists__output_resort should be called after
collapsing all entries in evlist.
Cc: Jiri Olsa <[email protected]>
Cc: Stephane Eranian <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/builtin-report.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index a61725d89d3e..b7e250d63892 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -416,6 +416,11 @@ static int __cmd_report(struct perf_report *rep)
hists->symbol_filter_str = rep->symbol_filter_str;
hists__collapse_resort(hists);
+ }
+
+ list_for_each_entry(pos, &session->evlist->entries, node) {
+ struct hists *hists = &pos->hists;
+
hists__output_resort(hists);
nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
}
--
1.7.9.2
From: Namhyung Kim <[email protected]>
Show group members' overhead also when showing the leader's if event
group is enabled. At this time, only implemented overhead part in
order to ease review and other parts can be added later once this
patch settled down.
Cc: Jiri Olsa <[email protected]>
Cc: Stephane Eranian <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/ui/browsers/hists.c | 33 +++++++++++++++++++++++++++++++--
tools/perf/ui/hist.c | 5 ++++-
2 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 0568536ecf67..df0ddeeeb860 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -565,6 +565,34 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
return row - first_row;
}
+static int hist_browser__hpp_color_overhead(struct perf_hpp *hpp,
+ struct hist_entry *he)
+{
+ int ret;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->stat.period / hists->stats.total_period;
+
+ /* the leader determines color */
+ *(double *) hpp->ptr = percent;
+
+ ret = scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
+
+ if (symbol_conf.event_group) {
+ int i;
+ struct perf_evsel *evsel = hists_2_evsel(hists);
+
+ for (i = 0; i < evsel->nr_members; i++) {
+ u64 period = he->group_stats[i].period;
+ u64 total = hists->group_stats[i].total_period;
+
+ percent = 100.0 * period / total;
+ ret += scnprintf(hpp->buf + ret, hpp->size - ret,
+ " %6.2f%%", percent);
+ }
+ }
+ return ret;
+}
+
#define HPP__COLOR_FN(_name, _field) \
static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \
struct hist_entry *he) \
@@ -575,7 +603,6 @@ static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \
return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \
}
-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)
@@ -610,6 +637,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
char folded_sign = ' ';
bool current_entry = ui_browser__is_current_entry(&browser->b, row);
off_t row_offset = entry->row_offset;
+ bool first = true;
if (current_entry) {
browser->he_selection = entry;
@@ -633,10 +661,11 @@ static int hist_browser__show_entry(struct hist_browser *browser,
if (!perf_hpp__format[i].cond)
continue;
- if (i) {
+ if (!first) {
slsmg_printf(" ");
width -= 2;
}
+ first = false;
if (perf_hpp__format[i].color) {
hpp.ptr = &percent;
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index ad4efb772796..624f3d08937f 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -462,6 +462,9 @@ unsigned int hists__sort_list_width(struct hists *hists)
{
struct sort_entry *se;
int i, ret = 0;
+ struct perf_hpp dummy_hpp = {
+ .ptr = hists_2_evsel(hists),
+ };
for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
if (!perf_hpp__format[i].cond)
@@ -469,7 +472,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
if (i)
ret += 2;
- ret += perf_hpp__format[i].width(NULL);
+ ret += perf_hpp__format[i].width(&dummy_hpp);
}
list_for_each_entry(se, &hist_entry__sort_list, list)
--
1.7.9.2
From: Namhyung Kim <[email protected]>
Show group members' overhead also when showing the leader's if event
group is enabled. At this time, only implemented overhead part in
order to ease review and other parts can be added later once this
patch settled down.
Cc: Jiri Olsa <[email protected]>
Cc: Stephane Eranian <[email protected]>
Cc: Pekka Enberg <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/ui/gtk/browser.c | 60 +++++++++++++++++++++++++++++++++----------
1 file changed, 46 insertions(+), 14 deletions(-)
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 4125c6284114..b2c8b8e69e4d 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -45,26 +45,57 @@ static const char *perf_gtk__get_percent_color(double percent)
return NULL;
}
+static int perf_gtk__percent_color_snprintf(char *buf, size_t size,
+ u64 period, u64 total_period)
+{
+ int ret = 0;
+ const char *markup;
+ double percent = 100.0 * period / total_period;
+
+ 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 perf_gtk__hpp_color_overhead(struct perf_hpp *hpp,
+ struct hist_entry *he)
+{
+ int ret;
+ struct hists *hists = he->hists;
+
+ ret = perf_gtk__percent_color_snprintf(hpp->buf, hpp->size,
+ he->stat.period, hists->stats.total_period);
+
+ if (symbol_conf.event_group) {
+ int i;
+ struct perf_evsel *evsel = hists_2_evsel(hists);
+
+ for (i = 0; i < evsel->nr_members; i++) {
+ ret += scnprintf(hpp->buf + ret, hpp->size - ret, " ");
+ ret += perf_gtk__percent_color_snprintf(hpp->buf + ret,
+ hpp->size - ret,
+ he->group_stats[i].period,
+ hists->group_stats[i].total_period);
+ }
+ }
+ return ret;
+}
+
#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; \
+ return perf_gtk__percent_color_snprintf(hpp->buf, hpp->size, \
+ he->stat._field, he->hists->stats.total_period); \
}
-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)
@@ -103,6 +134,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
struct perf_hpp hpp = {
.buf = s,
.size = sizeof(s),
+ .ptr = hists_2_evsel(hists),
};
nr_cols = 0;
--
1.7.9.2
From: Namhyung Kim <[email protected]>
When using event group viewer, it's better to show the group
description rather than the leader information alone.
If a leader did not contain any member, it's a non-group event.
Cc: Jiri Olsa <[email protected]>
Cc: Stephane Eranian <[email protected]>
Cc: Pekka Enberg <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/builtin-report.c | 18 ++++++++++++++++++
tools/perf/ui/browsers/hists.c | 31 +++++++++++++++++++++++++++++++
tools/perf/ui/gtk/browser.c | 14 +++++++++++---
tools/perf/util/evsel.c | 25 +++++++++++++++++++++++++
tools/perf/util/evsel.h | 8 ++++++++
5 files changed, 93 insertions(+), 3 deletions(-)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index ba5cfb40818d..e9c9687e021a 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -299,6 +299,24 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
char unit;
unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE];
u64 nr_events = self->stats.total_period;
+ struct perf_evsel *evsel = hists_2_evsel(self);
+ char buf[512];
+ size_t size = sizeof(buf);
+
+ if (symbol_conf.event_group && evsel->nr_members) {
+ int i;
+ struct events_stats *stats;
+
+ perf_evsel__group_desc(evsel, buf, size);
+ evname = buf;
+
+ for (i = 0; i < evsel->nr_members; i++) {
+ stats = &self->group_stats[i];
+
+ nr_samples += stats->nr_events[PERF_RECORD_SAMPLE];
+ nr_events += stats->total_period;
+ }
+ }
nr_samples = convert_unit(nr_samples, &unit);
ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 43eb90969799..e81773bd272e 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -1123,6 +1123,24 @@ 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_2_evsel(hists);
+ char buf[512];
+ size_t buflen = sizeof(buf);
+
+ if (symbol_conf.event_group && evsel->nr_members) {
+ int i;
+ struct events_stats *stats;
+
+ perf_evsel__group_desc(evsel, buf, buflen);
+ ev_name = buf;
+
+ for (i = 0; i < evsel->nr_members; i++) {
+ stats = &hists->group_stats[i];
+
+ nr_samples += stats->nr_events[PERF_RECORD_SAMPLE];
+ nr_events += stats->total_period;
+ }
+ }
nr_samples = convert_unit(nr_samples, &unit);
printed = scnprintf(bf, size,
@@ -1469,6 +1487,19 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
HE_COLORSET_NORMAL);
+ if (symbol_conf.event_group && evsel->nr_members) {
+ int i;
+ struct events_stats *stats;
+
+ ev_name = perf_evsel__group_name(evsel);
+
+ for (i = 0; i < evsel->nr_members; i++) {
+ stats = &evsel->hists.group_stats[i];
+
+ nr_events += 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);
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index ae6b941ef3d4..2c0e3e95dbca 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -305,10 +305,18 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
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 &&
- !perf_evsel__is_group_leader(pos))
- continue;
+ if (symbol_conf.event_group) {
+ if (!perf_evsel__is_group_leader(pos))
+ continue;
+
+ if (pos->nr_members) {
+ perf_evsel__group_desc(pos, buf, size);
+ evname = buf;
+ }
+ }
scrolled_window = gtk_scrolled_window_new(NULL, NULL);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index ffdd94e9c9c3..919b4d2ea799 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -404,6 +404,31 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
return evsel->name ?: "unknown";
}
+const char *perf_evsel__group_name(struct perf_evsel *evsel)
+{
+ return evsel->group_name ?: "anon group";
+}
+
+int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
+{
+ int ret;
+ struct perf_evsel *pos;
+ const char *group_name = perf_evsel__group_name(evsel);
+
+ ret = scnprintf(buf, size, "%s", group_name);
+
+ ret += scnprintf(buf + ret, size - ret, " { %s",
+ perf_evsel__name(evsel));
+
+ for_each_group_member(pos, evsel)
+ ret += scnprintf(buf + ret, size - ret, ", %s",
+ perf_evsel__name(pos));
+
+ ret += scnprintf(buf + ret, size - ret, " }");
+
+ return ret;
+}
+
void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
struct perf_evsel *first)
{
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 039c67297388..8d5937d98887 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -114,6 +114,8 @@ extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX];
int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
char *bf, size_t size);
const char *perf_evsel__name(struct perf_evsel *evsel);
+const char *perf_evsel__group_name(struct perf_evsel *evsel);
+int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
@@ -240,4 +242,10 @@ static inline struct perf_evsel *hists_2_evsel(struct hists *hists)
{
return container_of(hists, struct perf_evsel, hists);
}
+
+#define for_each_group_member(_evsel, _leader) \
+for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \
+ (_evsel) && (_evsel)->leader == (_leader); \
+ (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node))
+
#endif /* __PERF_EVSEL_H */
--
1.7.9.2
From: Namhyung Kim <[email protected]>
Since we have all necessary information in the leader events and
other members don't, bypass members. Member events will be shown
along with the leaders if event group is enabled.
Cc: Jiri Olsa <[email protected]>
Cc: Stephane Eranian <[email protected]>
Cc: Pekka Enberg <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/builtin-report.c | 4 ++++
tools/perf/ui/browsers/hists.c | 39 +++++++++++++++++++++++++++++++++------
tools/perf/ui/gtk/browser.c | 4 ++++
3 files changed, 41 insertions(+), 6 deletions(-)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index b7e250d63892..ba5cfb40818d 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -319,6 +319,10 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
struct hists *hists = &pos->hists;
const char *evname = perf_evsel__name(pos);
+ if (symbol_conf.event_group &&
+ !perf_evsel__is_group_leader(pos))
+ continue;
+
hists__fprintf_nr_sample_events(hists, evname, stdout);
hists__fprintf(hists, true, 0, 0, stdout);
fprintf(stdout, "\n\n");
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index df0ddeeeb860..43eb90969799 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -1578,8 +1578,19 @@ 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,
void(*timer)(void *arg), void *arg,
int delay_secs)
{
@@ -1590,7 +1601,8 @@ 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,
},
};
@@ -1605,7 +1617,7 @@ 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, timer,
+ return perf_evsel_menu__run(&menu, nr_entries, help, timer,
arg, delay_secs);
}
@@ -1613,15 +1625,30 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
void(*timer)(void *arg), void *arg,
int delay_secs)
{
- 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,
+ return perf_evsel__hists_browse(first, nr_entries, help,
ev_name, false, timer, arg,
delay_secs);
}
- return __perf_evlist__tui_browse_hists(evlist, help,
+ 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, nr_entries, help,
timer, arg, delay_secs);
}
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index b2c8b8e69e4d..ae6b941ef3d4 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -306,6 +306,10 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
GtkWidget *scrolled_window;
GtkWidget *tab_label;
+ if (symbol_conf.event_group &&
+ !perf_evsel__is_group_leader(pos))
+ continue;
+
scrolled_window = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
--
1.7.9.2
From: Namhyung Kim <[email protected]>
Add --group option to enable event grouping. When enabled, all the
group members information will be shown together with the leader.
Cc: Jiri Olsa <[email protected]>
Cc: Stephane Eranian <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/builtin-report.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index e9c9687e021a..9ed3a64315da 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -664,6 +664,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
"Specify disassembler style (e.g. -M intel for intel syntax)"),
OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
"Show a column with the sum of periods"),
+ OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
+ "Show event group information together"),
OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "",
"use branch records for histogram filling", parse_branch_mode),
OPT_STRING(0, "objdump", &objdump_path, "path",
--
1.7.9.2
From: Namhyung Kim <[email protected]>
Show group members' overhead also when showing the leader's if event
group is enabled. At this time, only implemented overhead part in
order to ease review and other parts can be added later once this
patch settled down.
Cc: Jiri Olsa <[email protected]>
Cc: Stephane Eranian <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/ui/hist.c | 66 ++++++++++++++++++++++++++++++++++++++++----
tools/perf/ui/stdio/hist.c | 2 ++
2 files changed, 63 insertions(+), 5 deletions(-)
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index f5a1e4f65263..ad4efb772796 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -3,34 +3,90 @@
#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");
+ int len = 8;
+
+ if (symbol_conf.event_group) {
+ struct perf_evsel *evsel = hpp->ptr;
+
+ BUG_ON(!perf_evsel__is_group_leader(evsel));
+
+ len += evsel->nr_members * 8;
+ }
+ return scnprintf(hpp->buf, hpp->size, "%*s", len, "Overhead");
}
-static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused)
+static int hpp__width_overhead(struct perf_hpp *hpp)
{
- return 8;
+ int len = 8;
+
+ if (symbol_conf.event_group) {
+ struct perf_evsel *evsel = hpp->ptr;
+
+ len += evsel->nr_members * 8;
+ }
+ return len;
}
static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
{
+ int ret;
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);
+ ret = percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
+
+ if (symbol_conf.event_group) {
+ int i;
+ struct perf_evsel *evsel = hists_2_evsel(hists);
+
+ for (i = 0; i < evsel->nr_members; i++) {
+ u64 period = he->group_stats[i].period;
+ u64 total = hists->group_stats[i].total_period;
+
+ percent = 100.0 * period / total;
+ ret += percent_color_snprintf(hpp->buf + ret,
+ hpp->size - ret,
+ " %6.2f%%", percent);
+ }
+
+ }
+ return ret;
}
static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
{
+ int ret;
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);
+ ret = scnprintf(hpp->buf, hpp->size, fmt, percent);
+
+ if (symbol_conf.event_group) {
+ int i;
+ struct perf_evsel *evsel = hists_2_evsel(hists);
+
+ for (i = 0; i < evsel->nr_members; i++) {
+ u64 period = he->group_stats[i].period;
+ u64 total = hists->group_stats[i].total_period;
+
+ if (symbol_conf.field_sep) {
+ ret += scnprintf(hpp->buf + ret,
+ hpp->size - ret, " ");
+ }
+ percent = 100.0 * period / total;
+ ret += scnprintf(hpp->buf + ret, hpp->size - ret,
+ fmt, percent);
+ }
+
+ }
+ return ret;
}
static int hpp__header_overhead_sys(struct perf_hpp *hpp)
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index fbd4e32d0743..1d4f1ddc8bf8 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)
@@ -346,6 +347,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
struct perf_hpp dummy_hpp = {
.buf = bf,
.size = sizeof(bf),
+ .ptr = hists_2_evsel(hists),
};
bool first = true;
--
1.7.9.2
From: Namhyung Kim <[email protected]>
Like group_stats in hist_entry, total periods information also need to
be known to the leader.
Cc: Jiri Olsa <[email protected]>
Cc: Stephane Eranian <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/util/hist.c | 25 +++++++++++++++++++++++++
tools/perf/util/hist.h | 1 +
2 files changed, 26 insertions(+)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 95415716c708..48488057c3da 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -194,6 +194,28 @@ static void hist_entry__add_group_stat(struct hist_entry *he_dest,
he_stat__add_stat(&he_dest->group_stats[evsel->group_idx], src);
}
+static void hists__add_group_stat(struct hists *hists)
+{
+ struct perf_evsel *evsel = hists_2_evsel(hists);
+ struct perf_evsel *leader = evsel->leader;
+ struct hists *leader_hists;
+
+ if (perf_evsel__is_group_leader(evsel))
+ return;
+
+ leader_hists = &leader->hists;
+
+ if (!leader_hists->group_stats) {
+ leader_hists->group_stats = calloc(leader->nr_members,
+ sizeof(struct events_stats));
+ if (!leader_hists->group_stats)
+ return;
+ }
+
+ memcpy(&leader_hists->group_stats[evsel->group_idx],
+ &hists->stats, sizeof(struct events_stats));
+}
+
static void hist_entry__decay(struct hist_entry *he)
{
he->stat.period = (he->stat.period * 7) / 8;
@@ -561,6 +583,9 @@ static void __hists__collapse_resort(struct hists *hists, bool threaded)
hists__apply_filters(hists, n);
}
}
+
+ if (symbol_conf.event_group)
+ hists__add_group_stat(hists);
}
void hists__collapse_resort(struct hists *hists)
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 66cb31fe81d2..e150cf86b94a 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -66,6 +66,7 @@ struct hists {
const char *symbol_filter_str;
pthread_mutex_t lock;
struct events_stats stats;
+ struct events_stats *group_stats;
u64 event_stream;
u16 col_len[HISTC_NR_COLS];
};
--
1.7.9.2
From: Namhyung Kim <[email protected]>
Save group relationship information so that it can be restored when
perf report is running.
Cc: Jiri Olsa <[email protected]>
Cc: Stephane Eranian <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/builtin-record.c | 3 +
tools/perf/util/header.c | 152 +++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/header.h | 2 +
3 files changed, 157 insertions(+)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 8c029fe2e22c..7940f0dd3db9 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -558,6 +558,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
goto out_delete_session;
}
+ if (!evsel_list->nr_groups)
+ perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
+
/*
* perf_session__delete(session) will be called at perf_record__exit()
*/
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 7daad237dea5..caceb33d8d1b 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1072,6 +1072,41 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
}
/*
+ * File format:
+ *
+ * struct group_descs {
+ * u32 nr_groups;
+ * struct group_desc {
+ * char name[];
+ * u32 leader_idx;
+ * u32 nr_members;
+ * }[nr_groups];
+ * };
+ */
+static int write_group_desc(int fd, struct perf_header *h __maybe_unused,
+ struct perf_evlist *evlist)
+{
+ u32 nr_groups = evlist->nr_groups;
+ struct perf_evsel *evsel;
+
+ do_write(fd, &nr_groups, sizeof(nr_groups));
+
+ list_for_each_entry(evsel, &evlist->entries, node) {
+ if (perf_evsel__is_group_leader(evsel) &&
+ evsel->nr_members > 0) {
+ const char *name = evsel->group_name ?: "{anon_group}";
+ u32 leader_idx = evsel->idx;
+ u32 nr_members = evsel->nr_members;
+
+ do_write_string(fd, name);
+ do_write(fd, &leader_idx, sizeof(leader_idx));
+ do_write(fd, &nr_members, sizeof(nr_members));
+ }
+ }
+ return 0;
+}
+
+/*
* default get_cpuid(): nothing gets recorded
* actual implementation must be in arch/$(ARCH)/util/header.c
*/
@@ -1432,6 +1467,31 @@ error:
fprintf(fp, "# pmu mappings: unable to read\n");
}
+static void print_group_desc(struct perf_header *ph, int fd __maybe_unused,
+ FILE *fp)
+{
+ struct perf_session *session;
+ struct perf_evsel *evsel;
+ u32 nr = 0;
+
+ session = container_of(ph, struct perf_session, header);
+
+ list_for_each_entry(evsel, &session->evlist->entries, node) {
+ if (perf_evsel__is_group_leader(evsel) &&
+ evsel->nr_members > 0) {
+ fprintf(fp, "# group: %s{%s", evsel->group_name ?: "",
+ perf_evsel__name(evsel));
+
+ nr = evsel->nr_members;
+ } else if (nr) {
+ fprintf(fp, ",%s", perf_evsel__name(evsel));
+
+ if (--nr == 0)
+ fprintf(fp, "}\n");
+ }
+ }
+}
+
static int __event_process_build_id(struct build_id_event *bev,
char *filename,
struct perf_session *session)
@@ -1946,6 +2006,97 @@ error:
return -1;
}
+static int process_group_desc(struct perf_file_section *section __maybe_unused,
+ struct perf_header *ph, int fd,
+ void *data __maybe_unused)
+{
+ size_t ret = -1;
+ u32 i, nr, nr_groups;
+ struct perf_session *session;
+ struct perf_evsel *evsel, *leader;
+ struct group_desc {
+ char *name;
+ u32 leader_idx;
+ u32 nr_members;
+ } *desc;
+
+ ret = read(fd, &nr_groups, sizeof(nr_groups));
+ if (ret != sizeof(nr_groups))
+ return -1;
+
+ if (ph->needs_swap)
+ nr_groups = bswap_32(nr_groups);
+
+ ph->env.nr_groups = nr_groups;
+ if (!nr_groups) {
+ pr_debug("group desc not available\n");
+ return 0;
+ }
+
+ desc = calloc(nr_groups, sizeof(*desc));
+ if (!desc)
+ return -1;
+
+ for (i = 0; i < nr_groups; i++) {
+ desc[i].name = do_read_string(fd, ph);
+ if (!desc[i].name)
+ goto out_free;
+
+ ret = read(fd, &desc[i].leader_idx, sizeof(u32));
+ if (ret != sizeof(u32))
+ goto out_free;
+
+ ret = read(fd, &desc[i].nr_members, sizeof(u32));
+ if (ret != sizeof(u32))
+ goto out_free;
+
+ if (ph->needs_swap) {
+ desc[i].leader_idx = bswap_32(desc[i].leader_idx);
+ desc[i].nr_members = bswap_32(desc[i].nr_members);
+ }
+ }
+
+ /*
+ * Rebuild group relationship based on the group_desc
+ */
+ session = container_of(ph, struct perf_session, header);
+ session->evlist->nr_groups = nr_groups;
+
+ i = nr = 0;
+ list_for_each_entry(evsel, &session->evlist->entries, node) {
+ if (evsel->idx == (int) desc[i].leader_idx) {
+ evsel->leader = NULL;
+ /* {anon_group} is a dummy name */
+ if (strcmp(desc[i].name, "{anon_group}"))
+ evsel->group_name = desc[i].name;
+ evsel->nr_members = desc[i].nr_members;
+
+ BUG_ON(i >= nr_groups);
+ BUG_ON(nr > 0);
+
+ leader = evsel;
+ nr = evsel->nr_members;
+ i++;
+ } else if (nr) {
+ /* This is a group member */
+ evsel->leader = leader;
+ /* group_idx starts from 0 */
+ evsel->group_idx = leader->nr_members - nr;
+ nr--;
+ }
+ }
+
+ BUG_ON(i != nr_groups);
+ BUG_ON(nr != 0);
+
+out_free:
+ while ((int) --i >= 0)
+ free(desc[i].name);
+ free(desc);
+
+ return ret;
+}
+
struct feature_ops {
int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1985,6 +2136,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),
FEAT_OPA(HEADER_BRANCH_STACK, branch_stack),
FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings),
+ FEAT_OPP(HEADER_GROUP_DESC, group_desc),
};
struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 99bdd3abce59..f143aa7153a2 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -29,6 +29,7 @@ enum {
HEADER_NUMA_TOPOLOGY,
HEADER_BRANCH_STACK,
HEADER_PMU_MAPPINGS,
+ HEADER_GROUP_DESC,
HEADER_LAST_FEATURE,
HEADER_FEAT_BITS = 256,
};
@@ -79,6 +80,7 @@ struct perf_session_env {
char *numa_nodes;
int nr_pmu_mappings;
char *pmu_mappings;
+ int nr_groups;
};
struct perf_header {
--
1.7.9.2
From: Namhyung Kim <[email protected]>
Since it is set to 1 for a new hist entry, no need to set to
separately. Move it to a template entry.
Cc: Jiri Olsa <[email protected]>
Cc: Arun Sharma <[email protected]>
Cc: Stephane Eranian <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/util/hist.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 3197f3f50018..02476cb3167d 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -223,7 +223,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
if (he != NULL) {
*he = *template;
- he->stat.nr_events = 1;
+
if (he->ms.map)
he->ms.map->referenced = true;
if (symbol_conf.use_callchain)
@@ -323,6 +323,7 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
.level = al->level,
.stat = {
.period = period,
+ .nr_events = 1,
},
.parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent),
@@ -348,6 +349,7 @@ struct hist_entry *__hists__add_entry(struct hists *self,
.level = al->level,
.stat = {
.period = period,
+ .nr_events = 1,
},
.parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent),
--
1.7.9.2
From: Jiri Olsa <[email protected]>
Currently the overhead and baseline columns are handled within
single function and the distinction is made by 'baseline hists'
pointer passed by 'struct perf_hpp::ptr'.
Since hists pointer is now part of each hist_entry, it's possible
to locate paired hists pointer directly from the passed struct
hist_entry pointer.
Also separating those 2 columns makes the code more obvious.
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Namhyung Kim <[email protected]>
Signed-off-by: Jiri Olsa <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
tools/perf/ui/hist.c | 74 ++++++++++++++++++++++++++++----------------
tools/perf/ui/stdio/hist.c | 11 +++++--
tools/perf/util/hist.h | 1 +
3 files changed, 58 insertions(+), 28 deletions(-)
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 55b9ca8f084c..532a60177c32 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -8,9 +8,7 @@
/* hist period print (hpp) functions */
static int hpp__header_overhead(struct perf_hpp *hpp)
{
- const char *fmt = hpp->ptr ? "Baseline" : "Overhead";
-
- return scnprintf(hpp->buf, hpp->size, fmt);
+ return scnprintf(hpp->buf, hpp->size, "Overhead");
}
static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused)
@@ -22,17 +20,6 @@ static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
{
double percent = 100.0 * he->period / hpp->total_period;
- if (hpp->ptr) {
- struct hists *old_hists = hpp->ptr;
- u64 total_period = old_hists->stats.total_period;
- u64 base_period = he->pair ? he->pair->period : 0;
-
- if (total_period)
- percent = 100.0 * base_period / total_period;
- else
- percent = 0.0;
- }
-
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
}
@@ -41,17 +28,6 @@ static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
double percent = 100.0 * he->period / hpp->total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
- if (hpp->ptr) {
- struct hists *old_hists = hpp->ptr;
- u64 total_period = old_hists->stats.total_period;
- u64 base_period = he->pair ? he->pair->period : 0;
-
- if (total_period)
- percent = 100.0 * base_period / total_period;
- else
- percent = 0.0;
- }
-
return scnprintf(hpp->buf, hpp->size, fmt, percent);
}
@@ -159,6 +135,47 @@ static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp,
return scnprintf(hpp->buf, hpp->size, fmt, percent);
}
+static int hpp__header_baseline(struct perf_hpp *hpp)
+{
+ return scnprintf(hpp->buf, hpp->size, "Baseline");
+}
+
+static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused)
+{
+ return 8;
+}
+
+static double baseline_percent(struct hist_entry *he)
+{
+ struct hist_entry *pair = he->pair;
+ struct hists *pair_hists = pair ? pair->hists : NULL;
+ double percent = 0.0;
+
+ if (pair) {
+ u64 total_period = pair_hists->stats.total_period;
+ u64 base_period = pair->period;
+
+ percent = 100.0 * base_period / total_period;
+ }
+
+ return percent;
+}
+
+static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
+{
+ double percent = baseline_percent(he);
+
+ return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
+}
+
+static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
+{
+ double percent = baseline_percent(he);
+ const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
+
+ return scnprintf(hpp->buf, hpp->size, fmt, percent);
+}
+
static int hpp__header_samples(struct perf_hpp *hpp)
{
const char *fmt = symbol_conf.field_sep ? "%s" : "%11s";
@@ -269,6 +286,7 @@ static int hpp__entry_displ(struct perf_hpp *hpp,
.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) },
@@ -302,6 +320,8 @@ void perf_hpp__init(bool need_pair, bool show_displacement)
perf_hpp__format[PERF_HPP__PERIOD].cond = true;
if (need_pair) {
+ perf_hpp__format[PERF_HPP__OVERHEAD].cond = false;
+ perf_hpp__format[PERF_HPP__BASELINE].cond = true;
perf_hpp__format[PERF_HPP__DELTA].cond = true;
if (show_displacement)
@@ -321,6 +341,7 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
const char *sep = symbol_conf.field_sep;
char *start = hpp->buf;
int i, ret;
+ bool first = true;
if (symbol_conf.exclude_other && !he->parent)
return 0;
@@ -329,9 +350,10 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
if (!perf_hpp__format[i].cond)
continue;
- if (!sep || i > 0) {
+ if (!sep || !first) {
ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
advance_hpp(hpp, ret);
+ first = false;
}
if (color && perf_hpp__format[i].color)
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index d7405f064e88..0aa6776caba5 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -353,6 +353,7 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
.size = sizeof(bf),
.ptr = pair,
};
+ bool first = true;
init_rem_hits();
@@ -364,8 +365,10 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
if (!perf_hpp__format[idx].cond)
continue;
- if (idx)
+ if (!first)
fprintf(fp, "%s", sep ?: " ");
+ else
+ first = false;
perf_hpp__format[idx].header(&dummy_hpp);
fprintf(fp, "%s", bf);
@@ -400,6 +403,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
if (sep)
goto print_entries;
+ first = true;
+
fprintf(fp, "# ");
for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
unsigned int i;
@@ -407,8 +412,10 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
if (!perf_hpp__format[idx].cond)
continue;
- if (idx)
+ if (!first)
fprintf(fp, "%s", sep ?: " ");
+ else
+ first = false;
width = perf_hpp__format[idx].width(&dummy_hpp);
for (i = 0; i < width; i++)
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index efb8fc8a4d24..b1a2b9d9b658 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -133,6 +133,7 @@ struct perf_hpp_fmt {
extern struct perf_hpp_fmt perf_hpp__format[];
enum {
+ PERF_HPP__BASELINE,
PERF_HPP__OVERHEAD,
PERF_HPP__OVERHEAD_SYS,
PERF_HPP__OVERHEAD_US,
--
1.7.9.2
From: Namhyung Kim <[email protected]>
Save group relationship information so that it can be restored when
perf report is running.
Cc: Jiri Olsa <[email protected]>
Cc: Stephane Eranian <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
Initialize leader to NULL in order to avoid 'may be used uninitialized'
warning from gcc (gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5.1))
tools/perf/builtin-record.c | 3 +
tools/perf/util/header.c | 152 +++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/header.h | 2 +
3 files changed, 157 insertions(+)
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 8c029fe2e22c..7940f0dd3db9 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -558,6 +558,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
goto out_delete_session;
}
+ if (!evsel_list->nr_groups)
+ perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
+
/*
* perf_session__delete(session) will be called at perf_record__exit()
*/
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 7daad237dea5..8969c20986c2 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1072,6 +1072,41 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
}
/*
+ * File format:
+ *
+ * struct group_descs {
+ * u32 nr_groups;
+ * struct group_desc {
+ * char name[];
+ * u32 leader_idx;
+ * u32 nr_members;
+ * }[nr_groups];
+ * };
+ */
+static int write_group_desc(int fd, struct perf_header *h __maybe_unused,
+ struct perf_evlist *evlist)
+{
+ u32 nr_groups = evlist->nr_groups;
+ struct perf_evsel *evsel;
+
+ do_write(fd, &nr_groups, sizeof(nr_groups));
+
+ list_for_each_entry(evsel, &evlist->entries, node) {
+ if (perf_evsel__is_group_leader(evsel) &&
+ evsel->nr_members > 0) {
+ const char *name = evsel->group_name ?: "{anon_group}";
+ u32 leader_idx = evsel->idx;
+ u32 nr_members = evsel->nr_members;
+
+ do_write_string(fd, name);
+ do_write(fd, &leader_idx, sizeof(leader_idx));
+ do_write(fd, &nr_members, sizeof(nr_members));
+ }
+ }
+ return 0;
+}
+
+/*
* default get_cpuid(): nothing gets recorded
* actual implementation must be in arch/$(ARCH)/util/header.c
*/
@@ -1432,6 +1467,31 @@ error:
fprintf(fp, "# pmu mappings: unable to read\n");
}
+static void print_group_desc(struct perf_header *ph, int fd __maybe_unused,
+ FILE *fp)
+{
+ struct perf_session *session;
+ struct perf_evsel *evsel;
+ u32 nr = 0;
+
+ session = container_of(ph, struct perf_session, header);
+
+ list_for_each_entry(evsel, &session->evlist->entries, node) {
+ if (perf_evsel__is_group_leader(evsel) &&
+ evsel->nr_members > 0) {
+ fprintf(fp, "# group: %s{%s", evsel->group_name ?: "",
+ perf_evsel__name(evsel));
+
+ nr = evsel->nr_members;
+ } else if (nr) {
+ fprintf(fp, ",%s", perf_evsel__name(evsel));
+
+ if (--nr == 0)
+ fprintf(fp, "}\n");
+ }
+ }
+}
+
static int __event_process_build_id(struct build_id_event *bev,
char *filename,
struct perf_session *session)
@@ -1946,6 +2006,97 @@ error:
return -1;
}
+static int process_group_desc(struct perf_file_section *section __maybe_unused,
+ struct perf_header *ph, int fd,
+ void *data __maybe_unused)
+{
+ size_t ret = -1;
+ u32 i, nr, nr_groups;
+ struct perf_session *session;
+ struct perf_evsel *evsel, *leader = NULL;
+ struct group_desc {
+ char *name;
+ u32 leader_idx;
+ u32 nr_members;
+ } *desc;
+
+ ret = read(fd, &nr_groups, sizeof(nr_groups));
+ if (ret != sizeof(nr_groups))
+ return -1;
+
+ if (ph->needs_swap)
+ nr_groups = bswap_32(nr_groups);
+
+ ph->env.nr_groups = nr_groups;
+ if (!nr_groups) {
+ pr_debug("group desc not available\n");
+ return 0;
+ }
+
+ desc = calloc(nr_groups, sizeof(*desc));
+ if (!desc)
+ return -1;
+
+ for (i = 0; i < nr_groups; i++) {
+ desc[i].name = do_read_string(fd, ph);
+ if (!desc[i].name)
+ goto out_free;
+
+ ret = read(fd, &desc[i].leader_idx, sizeof(u32));
+ if (ret != sizeof(u32))
+ goto out_free;
+
+ ret = read(fd, &desc[i].nr_members, sizeof(u32));
+ if (ret != sizeof(u32))
+ goto out_free;
+
+ if (ph->needs_swap) {
+ desc[i].leader_idx = bswap_32(desc[i].leader_idx);
+ desc[i].nr_members = bswap_32(desc[i].nr_members);
+ }
+ }
+
+ /*
+ * Rebuild group relationship based on the group_desc
+ */
+ session = container_of(ph, struct perf_session, header);
+ session->evlist->nr_groups = nr_groups;
+
+ i = nr = 0;
+ list_for_each_entry(evsel, &session->evlist->entries, node) {
+ if (evsel->idx == (int) desc[i].leader_idx) {
+ evsel->leader = NULL;
+ /* {anon_group} is a dummy name */
+ if (strcmp(desc[i].name, "{anon_group}"))
+ evsel->group_name = desc[i].name;
+ evsel->nr_members = desc[i].nr_members;
+
+ BUG_ON(i >= nr_groups);
+ BUG_ON(nr > 0);
+
+ leader = evsel;
+ nr = evsel->nr_members;
+ i++;
+ } else if (nr) {
+ /* This is a group member */
+ evsel->leader = leader;
+ /* group_idx starts from 0 */
+ evsel->group_idx = leader->nr_members - nr;
+ nr--;
+ }
+ }
+
+ BUG_ON(i != nr_groups);
+ BUG_ON(nr != 0);
+
+out_free:
+ while ((int) --i >= 0)
+ free(desc[i].name);
+ free(desc);
+
+ return ret;
+}
+
struct feature_ops {
int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1985,6 +2136,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),
FEAT_OPA(HEADER_BRANCH_STACK, branch_stack),
FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings),
+ FEAT_OPP(HEADER_GROUP_DESC, group_desc),
};
struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 99bdd3abce59..f143aa7153a2 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -29,6 +29,7 @@ enum {
HEADER_NUMA_TOPOLOGY,
HEADER_BRANCH_STACK,
HEADER_PMU_MAPPINGS,
+ HEADER_GROUP_DESC,
HEADER_LAST_FEATURE,
HEADER_FEAT_BITS = 256,
};
@@ -79,6 +80,7 @@ struct perf_session_env {
char *numa_nodes;
int nr_pmu_mappings;
char *pmu_mappings;
+ int nr_groups;
};
struct perf_header {
--
1.7.9.2
Commit-ID: ae359f193a80e19166efaed7d400d1476057b865
Gitweb: http://git.kernel.org/tip/ae359f193a80e19166efaed7d400d1476057b865
Author: Jiri Olsa <[email protected]>
AuthorDate: Thu, 4 Oct 2012 21:49:35 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 4 Oct 2012 13:27:00 -0300
perf hists: Add struct hists pointer to struct hist_entry
Adding pointer back to the parent struct hists for struct hists_entry.
This will be useful in future for any hist_entry's data computation,
that depends on total data of its parent hists.
Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[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: Namhyung Kim <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/hist.c | 2 ++
tools/perf/util/sort.h | 1 +
2 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 236bc9d..040f34c 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -325,6 +325,7 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
.parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent),
.branch_info = bi,
+ .hists = self,
};
return add_hist_entry(self, &entry, al, period);
@@ -346,6 +347,7 @@ struct hist_entry *__hists__add_entry(struct hists *self,
.period = period,
.parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent),
+ .hists = self,
};
return add_hist_entry(self, &entry, al, period);
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 12d6347..eb3959b 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -79,6 +79,7 @@ struct hist_entry {
struct rb_root sorted_chain;
};
struct branch_info *branch_info;
+ struct hists *hists;
struct callchain_root callchain[0];
};
Commit-ID: dd464345f330c1103f93daad309e8b44845e96cf
Gitweb: http://git.kernel.org/tip/dd464345f330c1103f93daad309e8b44845e96cf
Author: Jiri Olsa <[email protected]>
AuthorDate: Thu, 4 Oct 2012 21:49:36 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 4 Oct 2012 13:27:56 -0300
perf diff: Refactor diff displacement possition info
Moving the position calculation into the diff command, so the position
as prepared inside struct hist_entry data and there's no need to compute
in the output display path.
Removing 'displacement' from struct perf_hpp as it is no longer needed.
Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[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: Namhyung Kim <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-diff.c | 49 ++++++++++++++++++++++++++++---------------
tools/perf/builtin-report.c | 2 +-
tools/perf/builtin-top.c | 2 +-
tools/perf/ui/hist.c | 8 ++++--
tools/perf/ui/stdio/hist.c | 17 ++------------
tools/perf/util/hist.h | 4 +--
tools/perf/util/sort.h | 2 +-
7 files changed, 44 insertions(+), 40 deletions(-)
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 761f419..5cb577a 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -70,8 +70,8 @@ static struct perf_tool tool = {
.ordering_requires_timestamps = true,
};
-static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
- struct hist_entry *he)
+static void insert_hist_entry_by_name(struct rb_root *root,
+ struct hist_entry *he)
{
struct rb_node **p = &root->rb_node;
struct rb_node *parent = NULL;
@@ -90,7 +90,7 @@ static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
rb_insert_color(&he->rb_node, root);
}
-static void hists__resort_entries(struct hists *self)
+static void hists__name_resort(struct hists *self, bool sort)
{
unsigned long position = 1;
struct rb_root tmp = RB_ROOT;
@@ -100,12 +100,16 @@ static void hists__resort_entries(struct hists *self)
struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
next = rb_next(&n->rb_node);
- rb_erase(&n->rb_node, &self->entries);
n->position = position++;
- perf_session__insert_hist_entry_by_name(&tmp, n);
+
+ if (sort) {
+ rb_erase(&n->rb_node, &self->entries);
+ insert_hist_entry_by_name(&tmp, n);
+ }
}
- self->entries = tmp;
+ if (sort)
+ self->entries = tmp;
}
static struct hist_entry *hists__find_entry(struct hists *self,
@@ -121,7 +125,7 @@ static struct hist_entry *hists__find_entry(struct hists *self,
n = n->rb_left;
else if (cmp > 0)
n = n->rb_right;
- else
+ else
return iter;
}
@@ -150,6 +154,24 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
return NULL;
}
+static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name)
+{
+ struct perf_evsel *evsel;
+
+ list_for_each_entry(evsel, &evlist->entries, node) {
+ struct hists *hists = &evsel->hists;
+
+ hists__output_resort(hists);
+
+ /*
+ * The hists__name_resort only sets possition
+ * if name is false.
+ */
+ if (name || ((!name) && show_displacement))
+ hists__name_resort(hists, name);
+ }
+}
+
static int __cmd_diff(void)
{
int ret, i;
@@ -176,15 +198,8 @@ static int __cmd_diff(void)
evlist_old = older->evlist;
evlist_new = newer->evlist;
- list_for_each_entry(evsel, &evlist_new->entries, node)
- hists__output_resort(&evsel->hists);
-
- list_for_each_entry(evsel, &evlist_old->entries, node) {
- hists__output_resort(&evsel->hists);
-
- if (show_displacement)
- hists__resort_entries(&evsel->hists);
- }
+ perf_evlist__resort_hists(evlist_old, true);
+ perf_evlist__resort_hists(evlist_new, false);
list_for_each_entry(evsel, &evlist_new->entries, node) {
struct perf_evsel *evsel_old;
@@ -200,7 +215,7 @@ static int __cmd_diff(void)
hists__match(&evsel_old->hists, &evsel->hists);
hists__fprintf(&evsel->hists, &evsel_old->hists,
- show_displacement, true, 0, 0, stdout);
+ true, 0, 0, stdout);
}
out_delete:
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 1da243d..6748cac 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -320,7 +320,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
const char *evname = perf_evsel__name(pos);
hists__fprintf_nr_sample_events(hists, evname, stdout);
- hists__fprintf(hists, NULL, false, true, 0, 0, stdout);
+ hists__fprintf(hists, NULL, true, 0, 0, stdout);
fprintf(stdout, "\n\n");
}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index f0c1c4f..3571158 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -316,7 +316,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
hists__output_recalc_col_len(&top->sym_evsel->hists,
top->winsize.ws_row - 3);
putchar('\n');
- hists__fprintf(&top->sym_evsel->hists, NULL, false, false,
+ hists__fprintf(&top->sym_evsel->hists, NULL, false,
top->winsize.ws_row - 4 - printed, win_width, stdout);
}
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index e3f8cd4..55b9ca8 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -244,13 +244,15 @@ static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused)
}
static int hpp__entry_displ(struct perf_hpp *hpp,
- struct hist_entry *he __maybe_unused)
+ struct hist_entry *he)
{
+ struct hist_entry *pair = he->pair;
+ long displacement = pair ? pair->position - he->position : 0;
const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s";
char buf[32] = " ";
- if (hpp->displacement)
- scnprintf(buf, sizeof(buf), "%+4ld", hpp->displacement);
+ if (displacement)
+ scnprintf(buf, sizeof(buf), "%+4ld", displacement);
return scnprintf(hpp->buf, hpp->size, fmt, buf);
}
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 882461a..d7405f0 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -308,7 +308,7 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
static int hist_entry__fprintf(struct hist_entry *he, size_t size,
struct hists *hists, struct hists *pair_hists,
- long displacement, u64 total_period, FILE *fp)
+ u64 total_period, FILE *fp)
{
char bf[512];
int ret;
@@ -316,7 +316,6 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
.buf = bf,
.size = size,
.total_period = total_period,
- .displacement = displacement,
.ptr = pair_hists,
};
bool color = !symbol_conf.field_sep;
@@ -337,15 +336,13 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
}
size_t hists__fprintf(struct hists *hists, struct hists *pair,
- bool show_displacement, bool show_header, int max_rows,
+ bool show_header, int max_rows,
int max_cols, FILE *fp)
{
struct sort_entry *se;
struct rb_node *nd;
size_t ret = 0;
u64 total_period;
- unsigned long position = 1;
- long displacement = 0;
unsigned int width;
const char *sep = symbol_conf.field_sep;
const char *col_width = symbol_conf.col_width_list_str;
@@ -449,15 +446,7 @@ print_entries:
if (h->filtered)
continue;
- if (show_displacement) {
- if (h->pair != NULL)
- displacement = ((long)h->pair->position -
- (long)position);
- else
- displacement = 0;
- ++position;
- }
- ret += hist_entry__fprintf(h, max_cols, hists, pair, displacement,
+ ret += hist_entry__fprintf(h, max_cols, hists, pair,
total_period, fp);
if (max_rows && ++nr_rows >= max_rows)
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 6ca7407..efb8fc8 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -99,8 +99,7 @@ void hists__inc_nr_events(struct hists *self, u32 type);
size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
size_t hists__fprintf(struct hists *self, struct hists *pair,
- bool show_displacement, bool show_header,
- int max_rows, int max_cols, FILE *fp);
+ bool show_header, int max_rows, int max_cols, 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);
@@ -120,7 +119,6 @@ struct perf_hpp {
size_t size;
u64 total_period;
const char *sep;
- long displacement;
void *ptr;
};
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index eb3959b..f070b52 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -73,8 +73,8 @@ struct hist_entry {
u8 filtered;
char *srcline;
struct symbol *parent;
+ unsigned long position;
union {
- unsigned long position;
struct hist_entry *pair;
struct rb_root sorted_chain;
};
Commit-ID: 5395a04841fcdd9220177f2c21353fe6d4cd0729
Gitweb: http://git.kernel.org/tip/5395a04841fcdd9220177f2c21353fe6d4cd0729
Author: Jiri Olsa <[email protected]>
AuthorDate: Thu, 4 Oct 2012 21:49:37 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 4 Oct 2012 13:28:49 -0300
perf hists: Separate overhead and baseline columns
Currently the overhead and baseline columns are handled within single
function and the distinction is made by 'baseline hists' pointer passed
by 'struct perf_hpp::ptr'.
Since hists pointer is now part of each hist_entry, it's possible to
locate paired hists pointer directly from the passed struct hist_entry
pointer.
Also separating those 2 columns makes the code more obvious.
Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Namhyung Kim <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/ui/hist.c | 74 ++++++++++++++++++++++++++++---------------
tools/perf/ui/stdio/hist.c | 11 +++++-
tools/perf/util/hist.h | 1 +
3 files changed, 58 insertions(+), 28 deletions(-)
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 55b9ca8..532a601 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -8,9 +8,7 @@
/* hist period print (hpp) functions */
static int hpp__header_overhead(struct perf_hpp *hpp)
{
- const char *fmt = hpp->ptr ? "Baseline" : "Overhead";
-
- return scnprintf(hpp->buf, hpp->size, fmt);
+ return scnprintf(hpp->buf, hpp->size, "Overhead");
}
static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused)
@@ -22,17 +20,6 @@ static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
{
double percent = 100.0 * he->period / hpp->total_period;
- if (hpp->ptr) {
- struct hists *old_hists = hpp->ptr;
- u64 total_period = old_hists->stats.total_period;
- u64 base_period = he->pair ? he->pair->period : 0;
-
- if (total_period)
- percent = 100.0 * base_period / total_period;
- else
- percent = 0.0;
- }
-
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
}
@@ -41,17 +28,6 @@ static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
double percent = 100.0 * he->period / hpp->total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
- if (hpp->ptr) {
- struct hists *old_hists = hpp->ptr;
- u64 total_period = old_hists->stats.total_period;
- u64 base_period = he->pair ? he->pair->period : 0;
-
- if (total_period)
- percent = 100.0 * base_period / total_period;
- else
- percent = 0.0;
- }
-
return scnprintf(hpp->buf, hpp->size, fmt, percent);
}
@@ -159,6 +135,47 @@ static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp,
return scnprintf(hpp->buf, hpp->size, fmt, percent);
}
+static int hpp__header_baseline(struct perf_hpp *hpp)
+{
+ return scnprintf(hpp->buf, hpp->size, "Baseline");
+}
+
+static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused)
+{
+ return 8;
+}
+
+static double baseline_percent(struct hist_entry *he)
+{
+ struct hist_entry *pair = he->pair;
+ struct hists *pair_hists = pair ? pair->hists : NULL;
+ double percent = 0.0;
+
+ if (pair) {
+ u64 total_period = pair_hists->stats.total_period;
+ u64 base_period = pair->period;
+
+ percent = 100.0 * base_period / total_period;
+ }
+
+ return percent;
+}
+
+static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
+{
+ double percent = baseline_percent(he);
+
+ return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
+}
+
+static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
+{
+ double percent = baseline_percent(he);
+ const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
+
+ return scnprintf(hpp->buf, hpp->size, fmt, percent);
+}
+
static int hpp__header_samples(struct perf_hpp *hpp)
{
const char *fmt = symbol_conf.field_sep ? "%s" : "%11s";
@@ -269,6 +286,7 @@ static int hpp__entry_displ(struct perf_hpp *hpp,
.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) },
@@ -302,6 +320,8 @@ void perf_hpp__init(bool need_pair, bool show_displacement)
perf_hpp__format[PERF_HPP__PERIOD].cond = true;
if (need_pair) {
+ perf_hpp__format[PERF_HPP__OVERHEAD].cond = false;
+ perf_hpp__format[PERF_HPP__BASELINE].cond = true;
perf_hpp__format[PERF_HPP__DELTA].cond = true;
if (show_displacement)
@@ -321,6 +341,7 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
const char *sep = symbol_conf.field_sep;
char *start = hpp->buf;
int i, ret;
+ bool first = true;
if (symbol_conf.exclude_other && !he->parent)
return 0;
@@ -329,9 +350,10 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
if (!perf_hpp__format[i].cond)
continue;
- if (!sep || i > 0) {
+ if (!sep || !first) {
ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
advance_hpp(hpp, ret);
+ first = false;
}
if (color && perf_hpp__format[i].color)
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index d7405f0..0aa6776 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -353,6 +353,7 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
.size = sizeof(bf),
.ptr = pair,
};
+ bool first = true;
init_rem_hits();
@@ -364,8 +365,10 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
if (!perf_hpp__format[idx].cond)
continue;
- if (idx)
+ if (!first)
fprintf(fp, "%s", sep ?: " ");
+ else
+ first = false;
perf_hpp__format[idx].header(&dummy_hpp);
fprintf(fp, "%s", bf);
@@ -400,6 +403,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
if (sep)
goto print_entries;
+ first = true;
+
fprintf(fp, "# ");
for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
unsigned int i;
@@ -407,8 +412,10 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
if (!perf_hpp__format[idx].cond)
continue;
- if (idx)
+ if (!first)
fprintf(fp, "%s", sep ?: " ");
+ else
+ first = false;
width = perf_hpp__format[idx].width(&dummy_hpp);
for (i = 0; i < width; i++)
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index efb8fc8..b1a2b9d 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -133,6 +133,7 @@ struct perf_hpp_fmt {
extern struct perf_hpp_fmt perf_hpp__format[];
enum {
+ PERF_HPP__BASELINE,
PERF_HPP__OVERHEAD,
PERF_HPP__OVERHEAD_SYS,
PERF_HPP__OVERHEAD_US,
Commit-ID: 41724e4cf6c443d2dc575669b8555f0e2ae427a9
Gitweb: http://git.kernel.org/tip/41724e4cf6c443d2dc575669b8555f0e2ae427a9
Author: Jiri Olsa <[email protected]>
AuthorDate: Thu, 4 Oct 2012 21:49:38 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 4 Oct 2012 13:29:45 -0300
perf tools: Removing hists pair argument from output path
The hists pointer is now part of the 'struct hist_entry'.
And since the overhead and baseline columns are split now, there's no
reason to pass it through the output path.
Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[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: Namhyung Kim <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-diff.c | 3 +--
tools/perf/builtin-report.c | 2 +-
tools/perf/builtin-top.c | 2 +-
tools/perf/ui/hist.c | 9 +++++----
tools/perf/ui/stdio/hist.c | 10 +++-------
tools/perf/util/hist.h | 4 ++--
6 files changed, 13 insertions(+), 17 deletions(-)
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 5cb577a..413c65a1b 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -214,8 +214,7 @@ static int __cmd_diff(void)
first = false;
hists__match(&evsel_old->hists, &evsel->hists);
- hists__fprintf(&evsel->hists, &evsel_old->hists,
- true, 0, 0, stdout);
+ hists__fprintf(&evsel->hists, true, 0, 0, stdout);
}
out_delete:
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 6748cac..95e7ea8 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -320,7 +320,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
const char *evname = perf_evsel__name(pos);
hists__fprintf_nr_sample_events(hists, evname, stdout);
- hists__fprintf(hists, NULL, true, 0, 0, stdout);
+ hists__fprintf(hists, true, 0, 0, stdout);
fprintf(stdout, "\n\n");
}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 3571158..ff6db80 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -316,7 +316,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
hists__output_recalc_col_len(&top->sym_evsel->hists,
top->winsize.ws_row - 3);
putchar('\n');
- hists__fprintf(&top->sym_evsel->hists, NULL, false,
+ hists__fprintf(&top->sym_evsel->hists, false,
top->winsize.ws_row - 4 - printed, win_width, stdout);
}
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 532a601..6b0138e 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -228,16 +228,17 @@ 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 hists *pair_hists = hpp->ptr;
+ struct hist_entry *pair = he->pair;
+ struct hists *pair_hists = pair ? pair->hists : NULL;
u64 old_total, new_total;
double old_percent = 0, new_percent = 0;
double diff;
const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
char buf[32] = " ";
- old_total = pair_hists->stats.total_period;
- if (old_total > 0 && he->pair)
- old_percent = 100.0 * he->pair->period / old_total;
+ old_total = pair_hists ? pair_hists->stats.total_period : 0;
+ if (old_total > 0 && pair)
+ old_percent = 100.0 * pair->period / old_total;
new_total = hpp->total_period;
if (new_total > 0)
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 0aa6776..1340c93 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -307,8 +307,7 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
}
static int hist_entry__fprintf(struct hist_entry *he, size_t size,
- struct hists *hists, struct hists *pair_hists,
- u64 total_period, FILE *fp)
+ struct hists *hists, u64 total_period, FILE *fp)
{
char bf[512];
int ret;
@@ -316,7 +315,6 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
.buf = bf,
.size = size,
.total_period = total_period,
- .ptr = pair_hists,
};
bool color = !symbol_conf.field_sep;
@@ -335,8 +333,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
return ret;
}
-size_t hists__fprintf(struct hists *hists, struct hists *pair,
- bool show_header, int max_rows,
+size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
int max_cols, FILE *fp)
{
struct sort_entry *se;
@@ -351,7 +348,6 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
struct perf_hpp dummy_hpp = {
.buf = bf,
.size = sizeof(bf),
- .ptr = pair,
};
bool first = true;
@@ -453,7 +449,7 @@ print_entries:
if (h->filtered)
continue;
- ret += hist_entry__fprintf(h, max_cols, hists, pair,
+ ret += hist_entry__fprintf(h, max_cols, hists,
total_period, fp);
if (max_rows && ++nr_rows >= max_rows)
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index b1a2b9d..b83a226 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -98,8 +98,8 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows);
void hists__inc_nr_events(struct hists *self, u32 type);
size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
-size_t hists__fprintf(struct hists *self, struct hists *pair,
- bool show_header, int max_rows, int max_cols, FILE *fp);
+size_t hists__fprintf(struct hists *self, bool show_header, int max_rows,
+ int max_cols, 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);
Commit-ID: 1d77822ea6245e89149872405a3844e0778a004a
Gitweb: http://git.kernel.org/tip/1d77822ea6245e89149872405a3844e0778a004a
Author: Jiri Olsa <[email protected]>
AuthorDate: Thu, 4 Oct 2012 21:49:39 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 4 Oct 2012 13:30:27 -0300
perf tool: Add hpp interface to enable/disable hpp column
Adding perf_hpp__column_enable function to enable/disable hists column
and removing diff command specific stuff 'need_pair and
show_displacement' from hpp code.
The diff command now enables/disables columns separately according to
the user arguments. This will be helpful in future patches where more
columns are added into diff output.
Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Namhyung Kim <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-diff.c | 18 +++++++++++++++++-
tools/perf/builtin-report.c | 2 +-
tools/perf/ui/browsers/hists.c | 2 +-
tools/perf/ui/gtk/browser.c | 2 +-
tools/perf/ui/hist.c | 15 ++++++---------
tools/perf/ui/setup.c | 2 +-
tools/perf/util/hist.h | 3 ++-
7 files changed, 29 insertions(+), 15 deletions(-)
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 413c65a1b..a0b531c 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -256,6 +256,21 @@ static const struct option options[] = {
OPT_END()
};
+static void ui_init(void)
+{
+ perf_hpp__init();
+
+ /* No overhead column. */
+ perf_hpp__column_enable(PERF_HPP__OVERHEAD, false);
+
+ /* Display baseline/delta/displacement columns. */
+ perf_hpp__column_enable(PERF_HPP__BASELINE, true);
+ perf_hpp__column_enable(PERF_HPP__DELTA, true);
+
+ if (show_displacement)
+ perf_hpp__column_enable(PERF_HPP__DISPL, true);
+}
+
int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
{
sort_order = diff__default_sort_order;
@@ -278,7 +293,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
if (symbol__init() < 0)
return -1;
- perf_hpp__init(true, show_displacement);
+ ui_init();
+
setup_sorting(diff_usage, options);
setup_pager();
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 95e7ea8..a61725d 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -691,7 +691,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
setup_browser(true);
else {
use_browser = 0;
- perf_hpp__init(false, false);
+ perf_hpp__init();
}
setup_sorting(report_usage, options);
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index a21f40b..bbd11c2 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -584,7 +584,7 @@ HPP__COLOR_FN(overhead_guest_us, period_guest_us)
void hist_browser__init_hpp(void)
{
- perf_hpp__init(false, false);
+ perf_hpp__init();
perf_hpp__format[PERF_HPP__OVERHEAD].color =
hist_browser__hpp_color_overhead;
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 7ff99ec..2bc08f6 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -73,7 +73,7 @@ HPP__COLOR_FN(overhead_guest_us, period_guest_us)
void perf_gtk__init_hpp(void)
{
- perf_hpp__init(false, false);
+ perf_hpp__init();
perf_hpp__format[PERF_HPP__OVERHEAD].color =
perf_gtk__hpp_color_overhead;
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 6b0138e..e8853f7 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -302,7 +302,7 @@ struct perf_hpp_fmt perf_hpp__format[] = {
#undef HPP__COLOR_PRINT_FNS
#undef HPP__PRINT_FNS
-void perf_hpp__init(bool need_pair, bool show_displacement)
+void perf_hpp__init(void)
{
if (symbol_conf.show_cpu_utilization) {
perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true;
@@ -319,15 +319,12 @@ void perf_hpp__init(bool need_pair, bool show_displacement)
if (symbol_conf.show_total_period)
perf_hpp__format[PERF_HPP__PERIOD].cond = true;
+}
- if (need_pair) {
- perf_hpp__format[PERF_HPP__OVERHEAD].cond = false;
- perf_hpp__format[PERF_HPP__BASELINE].cond = true;
- perf_hpp__format[PERF_HPP__DELTA].cond = true;
-
- if (show_displacement)
- perf_hpp__format[PERF_HPP__DISPL].cond = true;
- }
+void perf_hpp__column_enable(unsigned col, bool enable)
+{
+ BUG_ON(col >= PERF_HPP__MAX_INDEX);
+ perf_hpp__format[col].cond = enable;
}
static inline void advance_hpp(struct perf_hpp *hpp, int inc)
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
index bd7d460..ebb4cc1 100644
--- a/tools/perf/ui/setup.c
+++ b/tools/perf/ui/setup.c
@@ -30,7 +30,7 @@ void setup_browser(bool fallback_to_pager)
if (fallback_to_pager)
setup_pager();
- perf_hpp__init(false, false);
+ perf_hpp__init();
break;
}
}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index b83a226..a7f69d6 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -147,7 +147,8 @@ enum {
PERF_HPP__MAX_INDEX
};
-void perf_hpp__init(bool need_pair, bool show_displacement);
+void perf_hpp__init(void);
+void perf_hpp__column_enable(unsigned col, bool enable);
int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
bool color);
Commit-ID: b5ff71c3bab10a7a4b321b5de072ac5bd73ef9a4
Gitweb: http://git.kernel.org/tip/b5ff71c3bab10a7a4b321b5de072ac5bd73ef9a4
Author: Jiri Olsa <[email protected]>
AuthorDate: Thu, 4 Oct 2012 21:49:40 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 4 Oct 2012 13:31:30 -0300
perf diff: Removing the total_period argument from output code
The total_period is available in struct hists data via the 'struct
hist_entry::hists' pointer. There's no need to carry it through the
output code path.
Removing 'struct perf_hpp::total_period' pointer, because it's no longer
needed.
Signed-off-by: Jiri Olsa <[email protected]>
Cc: Corey Ashford <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Namhyung Kim <[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: Namhyung Kim <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/ui/browsers/hists.c | 4 ++--
tools/perf/ui/gtk/browser.c | 4 ++--
tools/perf/ui/hist.c | 37 ++++++++++++++++++++++++++-----------
tools/perf/ui/stdio/hist.c | 15 +++++----------
tools/perf/util/hist.h | 1 -
5 files changed, 35 insertions(+), 26 deletions(-)
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index bbd11c2..d359795 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -569,7 +569,8 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \
struct hist_entry *he) \
{ \
- double percent = 100.0 * he->_field / hpp->total_period; \
+ struct hists *hists = he->hists; \
+ double percent = 100.0 * he->_field / hists->stats.total_period;\
*(double *)hpp->ptr = percent; \
return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \
}
@@ -624,7 +625,6 @@ static int hist_browser__show_entry(struct hist_browser *browser,
struct perf_hpp hpp = {
.buf = s,
.size = sizeof(s),
- .total_period = browser->hists->stats.total_period,
};
ui_browser__gotorc(&browser->b, row, 0);
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 2bc08f6..3cbb1d6 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -49,7 +49,8 @@ static const char *perf_gtk__get_percent_color(double percent)
static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \
struct hist_entry *he) \
{ \
- double percent = 100.0 * he->_field / hpp->total_period; \
+ struct hists *hists = he->hists; \
+ double percent = 100.0 * he->_field / hists->stats.total_period; \
const char *markup; \
int ret = 0; \
\
@@ -102,7 +103,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
struct perf_hpp hpp = {
.buf = s,
.size = sizeof(s),
- .total_period = hists->stats.total_period,
};
nr_cols = 0;
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index e8853f7..7f04339 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -18,14 +18,16 @@ static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused)
static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
{
- double percent = 100.0 * he->period / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->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)
{
- double percent = 100.0 * he->period / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->period / hists->stats.total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
return scnprintf(hpp->buf, hpp->size, fmt, percent);
@@ -45,13 +47,16 @@ static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused)
static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
{
- double percent = 100.0 * he->period_sys / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->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)
{
- double percent = 100.0 * he->period_sys / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->period_sys / hists->stats.total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
return scnprintf(hpp->buf, hpp->size, fmt, percent);
@@ -71,13 +76,16 @@ static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused)
static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
{
- double percent = 100.0 * he->period_us / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->period_us / hists->stats.total_period;
+
return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
}
static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
{
- double percent = 100.0 * he->period_us / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->period_us / hists->stats.total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
return scnprintf(hpp->buf, hpp->size, fmt, percent);
@@ -96,14 +104,17 @@ static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused)
static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp,
struct hist_entry *he)
{
- double percent = 100.0 * he->period_guest_sys / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->period_guest_sys / hists->stats.total_period;
+
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
}
static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp,
struct hist_entry *he)
{
- double percent = 100.0 * he->period_guest_sys / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->period_guest_sys / hists->stats.total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
return scnprintf(hpp->buf, hpp->size, fmt, percent);
@@ -122,14 +133,17 @@ static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused)
static int hpp__color_overhead_guest_us(struct perf_hpp *hpp,
struct hist_entry *he)
{
- double percent = 100.0 * he->period_guest_us / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->period_guest_us / hists->stats.total_period;
+
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
}
static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp,
struct hist_entry *he)
{
- double percent = 100.0 * he->period_guest_us / hpp->total_period;
+ struct hists *hists = he->hists;
+ double percent = 100.0 * he->period_guest_us / hists->stats.total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
return scnprintf(hpp->buf, hpp->size, fmt, percent);
@@ -230,6 +244,7 @@ static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hist_entry *pair = he->pair;
struct hists *pair_hists = pair ? pair->hists : NULL;
+ struct hists *hists = he->hists;
u64 old_total, new_total;
double old_percent = 0, new_percent = 0;
double diff;
@@ -240,7 +255,7 @@ static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
if (old_total > 0 && pair)
old_percent = 100.0 * pair->period / old_total;
- new_total = hpp->total_period;
+ new_total = hists->stats.total_period;
if (new_total > 0)
new_percent = 100.0 * he->period / new_total;
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 1340c93..850c6d2 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -292,9 +292,10 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
struct hists *hists,
- u64 total_period, FILE *fp)
+ FILE *fp)
{
int left_margin = 0;
+ u64 total_period = hists->stats.total_period;
if (sort__first_dimension == SORT_COMM) {
struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
@@ -307,14 +308,13 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
}
static int hist_entry__fprintf(struct hist_entry *he, size_t size,
- struct hists *hists, u64 total_period, FILE *fp)
+ struct hists *hists, FILE *fp)
{
char bf[512];
int ret;
struct perf_hpp hpp = {
.buf = bf,
.size = size,
- .total_period = total_period,
};
bool color = !symbol_conf.field_sep;
@@ -327,8 +327,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
ret = fprintf(fp, "%s\n", bf);
if (symbol_conf.use_callchain)
- ret += hist_entry__callchain_fprintf(he, hists,
- total_period, fp);
+ ret += hist_entry__callchain_fprintf(he, hists, fp);
return ret;
}
@@ -339,7 +338,6 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
struct sort_entry *se;
struct rb_node *nd;
size_t ret = 0;
- u64 total_period;
unsigned int width;
const char *sep = symbol_conf.field_sep;
const char *col_width = symbol_conf.col_width_list_str;
@@ -441,16 +439,13 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
goto out;
print_entries:
- total_period = hists->stats.total_period;
-
for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
if (h->filtered)
continue;
- ret += hist_entry__fprintf(h, max_cols, hists,
- total_period, fp);
+ ret += hist_entry__fprintf(h, max_cols, hists, fp);
if (max_rows && ++nr_rows >= max_rows)
goto out;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index a7f69d6..66cb31f 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -117,7 +117,6 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *he);
struct perf_hpp {
char *buf;
size_t size;
- u64 total_period;
const char *sep;
void *ptr;
};
Commit-ID: b24c28f794e1821c1bba3ef7e9e948ab77ee00ac
Gitweb: http://git.kernel.org/tip/b24c28f794e1821c1bba3ef7e9e948ab77ee00ac
Author: Namhyung Kim <[email protected]>
AuthorDate: Thu, 4 Oct 2012 21:49:41 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 4 Oct 2012 13:34:22 -0300
perf hists: Introduce struct he_stat
The struct he_stat is for separating out statistics data of a hist
entry. It is required for later changes.
It's just a mechanical change and should have no functional differences.
Signed-off-by: Namhyung Kim <[email protected]>
Cc: Arun Sharma <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[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/ui/browsers/hists.c | 8 +++---
tools/perf/ui/gtk/browser.c | 2 +-
tools/perf/ui/hist.c | 30 +++++++++++-----------
tools/perf/ui/stdio/hist.c | 2 +-
tools/perf/util/hist.c | 52 +++++++++++++++++++++------------------
tools/perf/util/sort.h | 16 +++++++----
6 files changed, 59 insertions(+), 51 deletions(-)
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index d359795..0568536 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -570,7 +570,7 @@ static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \
struct hist_entry *he) \
{ \
struct hists *hists = he->hists; \
- double percent = 100.0 * he->_field / hists->stats.total_period;\
+ double percent = 100.0 * he->stat._field / hists->stats.total_period; \
*(double *)hpp->ptr = percent; \
return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \
}
@@ -982,7 +982,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
folded_sign = hist_entry__folded(he);
hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists);
- percent = (he->period * 100.0) / browser->hists->stats.total_period;
+ percent = (he->stat.period * 100.0) / browser->hists->stats.total_period;
if (symbol_conf.use_callchain)
printed += fprintf(fp, "%c ", folded_sign);
@@ -990,10 +990,10 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
printed += fprintf(fp, " %5.2f%%", percent);
if (symbol_conf.show_nr_samples)
- printed += fprintf(fp, " %11u", he->nr_events);
+ printed += fprintf(fp, " %11u", he->stat.nr_events);
if (symbol_conf.show_total_period)
- printed += fprintf(fp, " %12" PRIu64, he->period);
+ printed += fprintf(fp, " %12" PRIu64, he->stat.period);
printed += fprintf(fp, "%s\n", rtrim(s));
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 3cbb1d6..4125c62 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -50,7 +50,7 @@ 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->_field / hists->stats.total_period; \
+ double percent = 100.0 * he->stat._field / hists->stats.total_period; \
const char *markup; \
int ret = 0; \
\
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 7f04339..f5a1e4f 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -19,7 +19,7 @@ static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused)
static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hists *hists = he->hists;
- double percent = 100.0 * he->period / hists->stats.total_period;
+ double percent = 100.0 * he->stat.period / hists->stats.total_period;
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
}
@@ -27,7 +27,7 @@ static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hists *hists = he->hists;
- double percent = 100.0 * he->period / hists->stats.total_period;
+ 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);
@@ -48,7 +48,7 @@ static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused)
static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hists *hists = he->hists;
- double percent = 100.0 * he->period_sys / hists->stats.total_period;
+ double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
}
@@ -56,7 +56,7 @@ static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hists *hists = he->hists;
- double percent = 100.0 * he->period_sys / hists->stats.total_period;
+ 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);
@@ -77,7 +77,7 @@ static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused)
static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hists *hists = he->hists;
- double percent = 100.0 * he->period_us / hists->stats.total_period;
+ double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
}
@@ -85,7 +85,7 @@ static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hists *hists = he->hists;
- double percent = 100.0 * he->period_us / hists->stats.total_period;
+ double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
return scnprintf(hpp->buf, hpp->size, fmt, percent);
@@ -105,7 +105,7 @@ 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->period_guest_sys / hists->stats.total_period;
+ double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
}
@@ -114,7 +114,7 @@ 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->period_guest_sys / hists->stats.total_period;
+ double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
return scnprintf(hpp->buf, hpp->size, fmt, percent);
@@ -134,7 +134,7 @@ 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->period_guest_us / hists->stats.total_period;
+ double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
}
@@ -143,7 +143,7 @@ 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->period_guest_us / hists->stats.total_period;
+ double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
return scnprintf(hpp->buf, hpp->size, fmt, percent);
@@ -167,7 +167,7 @@ static double baseline_percent(struct hist_entry *he)
if (pair) {
u64 total_period = pair_hists->stats.total_period;
- u64 base_period = pair->period;
+ u64 base_period = pair->stat.period;
percent = 100.0 * base_period / total_period;
}
@@ -206,7 +206,7 @@ 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->nr_events);
+ return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events);
}
static int hpp__header_period(struct perf_hpp *hpp)
@@ -225,7 +225,7 @@ 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->period);
+ return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period);
}
static int hpp__header_delta(struct perf_hpp *hpp)
@@ -253,11 +253,11 @@ static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
old_total = pair_hists ? pair_hists->stats.total_period : 0;
if (old_total > 0 && pair)
- old_percent = 100.0 * pair->period / old_total;
+ old_percent = 100.0 * pair->stat.period / old_total;
new_total = hists->stats.total_period;
if (new_total > 0)
- new_percent = 100.0 * he->period / new_total;
+ new_percent = 100.0 * he->stat.period / new_total;
diff = new_percent - old_percent;
if (fabs(diff) >= 0.01)
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 850c6d2..fbd4e32 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -271,7 +271,7 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
{
switch (callchain_param.mode) {
case CHAIN_GRAPH_REL:
- return callchain__fprintf_graph(fp, &he->sorted_chain, he->period,
+ return callchain__fprintf_graph(fp, &he->sorted_chain, he->stat.period,
left_margin);
break;
case CHAIN_GRAPH_ABS:
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 040f34c..3197f3f 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -135,16 +135,16 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he,
{
switch (cpumode) {
case PERF_RECORD_MISC_KERNEL:
- he->period_sys += period;
+ he->stat.period_sys += period;
break;
case PERF_RECORD_MISC_USER:
- he->period_us += period;
+ he->stat.period_us += period;
break;
case PERF_RECORD_MISC_GUEST_KERNEL:
- he->period_guest_sys += period;
+ he->stat.period_guest_sys += period;
break;
case PERF_RECORD_MISC_GUEST_USER:
- he->period_guest_us += period;
+ he->stat.period_guest_us += period;
break;
default:
break;
@@ -153,13 +153,13 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he,
static void hist_entry__decay(struct hist_entry *he)
{
- he->period = (he->period * 7) / 8;
- he->nr_events = (he->nr_events * 7) / 8;
+ he->stat.period = (he->stat.period * 7) / 8;
+ he->stat.nr_events = (he->stat.nr_events * 7) / 8;
}
static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
{
- u64 prev_period = he->period;
+ u64 prev_period = he->stat.period;
if (prev_period == 0)
return true;
@@ -167,9 +167,9 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
hist_entry__decay(he);
if (!he->filtered)
- hists->stats.total_period -= prev_period - he->period;
+ hists->stats.total_period -= prev_period - he->stat.period;
- return he->period == 0;
+ return he->stat.period == 0;
}
static void __hists__decay_entries(struct hists *hists, bool zap_user,
@@ -223,7 +223,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
if (he != NULL) {
*he = *template;
- he->nr_events = 1;
+ he->stat.nr_events = 1;
if (he->ms.map)
he->ms.map->referenced = true;
if (symbol_conf.use_callchain)
@@ -238,7 +238,7 @@ static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
if (!h->filtered) {
hists__calc_col_len(hists, h);
++hists->nr_entries;
- hists->stats.total_period += h->period;
+ hists->stats.total_period += h->stat.period;
}
}
@@ -270,8 +270,8 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
cmp = hist_entry__cmp(entry, he);
if (!cmp) {
- he->period += period;
- ++he->nr_events;
+ he->stat.period += period;
+ ++he->stat.nr_events;
/* If the map of an existing hist_entry has
* become out-of-date due to an exec() or
@@ -321,7 +321,9 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
.cpu = al->cpu,
.ip = bi->to.addr,
.level = al->level,
- .period = period,
+ .stat = {
+ .period = period,
+ },
.parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent),
.branch_info = bi,
@@ -344,7 +346,9 @@ struct hist_entry *__hists__add_entry(struct hists *self,
.cpu = al->cpu,
.ip = al->addr,
.level = al->level,
- .period = period,
+ .stat = {
+ .period = period,
+ },
.parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent),
.hists = self,
@@ -412,12 +416,12 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
cmp = hist_entry__collapse(iter, he);
if (!cmp) {
- iter->period += he->period;
- iter->period_sys += he->period_sys;
- iter->period_us += he->period_us;
- iter->period_guest_sys += he->period_guest_sys;
- iter->period_guest_us += he->period_guest_us;
- iter->nr_events += he->nr_events;
+ iter->stat.period += he->stat.period;
+ iter->stat.period_sys += he->stat.period_sys;
+ iter->stat.period_us += he->stat.period_us;
+ iter->stat.period_guest_sys += he->stat.period_guest_sys;
+ iter->stat.period_guest_us += he->stat.period_guest_us;
+ iter->stat.nr_events += he->stat.nr_events;
if (symbol_conf.use_callchain) {
callchain_cursor_reset(&callchain_cursor);
@@ -520,7 +524,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
parent = *p;
iter = rb_entry(parent, struct hist_entry, rb_node);
- if (he->period > iter->period)
+ if (he->stat.period > iter->stat.period)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
@@ -581,8 +585,8 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
if (h->ms.unfolded)
hists->nr_entries += h->nr_rows;
h->row_offset = 0;
- hists->stats.total_period += h->period;
- hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
+ hists->stats.total_period += h->stat.period;
+ hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->stat.nr_events;
hists__calc_col_len(hists, h);
}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index f070b52..5786f32 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -43,6 +43,15 @@ extern struct sort_entry sort_sym_from;
extern struct sort_entry sort_sym_to;
extern enum sort_type sort__first_dimension;
+struct he_stat {
+ u64 period;
+ u64 period_sys;
+ u64 period_us;
+ u64 period_guest_sys;
+ u64 period_guest_us;
+ u32 nr_events;
+};
+
/**
* struct hist_entry - histogram entry
*
@@ -52,16 +61,11 @@ extern enum sort_type sort__first_dimension;
struct hist_entry {
struct rb_node rb_node_in;
struct rb_node rb_node;
- u64 period;
- u64 period_sys;
- u64 period_us;
- u64 period_guest_sys;
- u64 period_guest_us;
+ struct he_stat stat;
struct map_symbol ms;
struct thread *thread;
u64 ip;
s32 cpu;
- u32 nr_events;
/* XXX These two should move to some tree widget lib */
u16 row_offset;
Commit-ID: c4b35351ef3145c9abad64999d1de0de1b8361ab
Gitweb: http://git.kernel.org/tip/c4b35351ef3145c9abad64999d1de0de1b8361ab
Author: Namhyung Kim <[email protected]>
AuthorDate: Thu, 4 Oct 2012 21:49:42 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 4 Oct 2012 13:35:14 -0300
perf hists: Move he->stat.nr_events initialization to a template
Since it is set to 1 for a new hist entry, no need to set to separately.
Move it to a template entry.
Signed-off-by: Namhyung Kim <[email protected]>
Cc: Arun Sharma <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[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/hist.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 3197f3f..02476cb 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -223,7 +223,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
if (he != NULL) {
*he = *template;
- he->stat.nr_events = 1;
+
if (he->ms.map)
he->ms.map->referenced = true;
if (symbol_conf.use_callchain)
@@ -323,6 +323,7 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
.level = al->level,
.stat = {
.period = period,
+ .nr_events = 1,
},
.parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent),
@@ -348,6 +349,7 @@ struct hist_entry *__hists__add_entry(struct hists *self,
.level = al->level,
.stat = {
.period = period,
+ .nr_events = 1,
},
.parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent),
Commit-ID: 139c0815903de1a7865fe1d6beac5e995fefdf46
Gitweb: http://git.kernel.org/tip/139c0815903de1a7865fe1d6beac5e995fefdf46
Author: Namhyung Kim <[email protected]>
AuthorDate: Thu, 4 Oct 2012 21:49:43 +0900
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 4 Oct 2012 13:36:18 -0300
perf hists: Add more helpers for hist entry stat
Add and use he_stat__add_{period,stat} for calculating hist entry's
stat. It will be used for accumulated stats later as well.
Signed-off-by: Namhyung Kim <[email protected]>
Cc: Arun Sharma <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Jiri Olsa <[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/hist.c | 26 ++++++++++++++++++--------
1 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 02476cb..277947a 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -151,6 +151,22 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he,
}
}
+static void he_stat__add_period(struct he_stat *he_stat, u64 period)
+{
+ he_stat->period += period;
+ he_stat->nr_events += 1;
+}
+
+static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
+{
+ dest->period += src->period;
+ dest->period_sys += src->period_sys;
+ dest->period_us += src->period_us;
+ dest->period_guest_sys += src->period_guest_sys;
+ dest->period_guest_us += src->period_guest_us;
+ dest->nr_events += src->nr_events;
+}
+
static void hist_entry__decay(struct hist_entry *he)
{
he->stat.period = (he->stat.period * 7) / 8;
@@ -270,8 +286,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
cmp = hist_entry__cmp(entry, he);
if (!cmp) {
- he->stat.period += period;
- ++he->stat.nr_events;
+ he_stat__add_period(&he->stat, period);
/* If the map of an existing hist_entry has
* become out-of-date due to an exec() or
@@ -418,12 +433,7 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
cmp = hist_entry__collapse(iter, he);
if (!cmp) {
- iter->stat.period += he->stat.period;
- iter->stat.period_sys += he->stat.period_sys;
- iter->stat.period_us += he->stat.period_us;
- iter->stat.period_guest_sys += he->stat.period_guest_sys;
- iter->stat.period_guest_us += he->stat.period_guest_us;
- iter->stat.nr_events += he->stat.nr_events;
+ he_stat__add_stat(&iter->stat, &he->stat);
if (symbol_conf.use_callchain) {
callchain_cursor_reset(&callchain_cursor);
On Thu, Oct 04, 2012 at 09:49:34PM +0900, Namhyung Kim wrote:
> Hi,
>
> This is my v3 of event group view support.
> For basic idea and usage example, please see my original post [1].
>
> I rebased the series on top of selected hpp changes from Jiri's diff
> patchset [2] since it contains cleanups and improves that can be used
> in this series too.
>
> You can also get it via my tree at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/namhyung/linux-perf.git perf/group-v3
>
> Any comments are welcome, thanks,
> Namhyung
>
> v2 -> v3:
> * drop patch 1 since it's merged into acme/perf/core
> * cherry-pick Jiri's hpp changes
> * add missing bswap_32 on reading nr_groups (Jiri)
> * remove perf_evlist__recalc_nr_groups() in favor of list_is_last (Jiri)
Acked-by: Jiri Olsa <[email protected]>
for patches 10 to 20, the rest is already in
thanks,
jirka