perf tools: Add support to accumulate hist periods (v11)
Namhyung Kim
maintainercover perf tools: Add support to accumulate hist periods (v11)
Hello,
This is a new attempt to implement cumulative hist period report. This work begins from Arun's SORT_INCLUSIVE patch [1] but I completely rewrote it from scratch.
This patchset basically adds period in a sample to every node in the callchain. A hist_entry now has an additional fields to keep the cumulative period if --children option is given on perf report.
I changed the option as a separate --children and added a new "Children" column (and renamed the default "Overhead" column into "Self"). The output will be sorted by children (cumulative) overhead for now. It also adds 'overhead_children' field to -F/--fields option to be selected by user and it'll show you "N/A" if the cumulation is not supported (due to missing callchain).
I added Tested-by from Rodrigo Campos since this version is basically rebase of previous series + bugfix. But it still needs to be tested more intensively IMHO. Also note that, this will change default behavior of perf report/top if callchain is recorded, so might confuse old users. Let's see how many of them come to shout. :) I think we need to merge Jiri's TUI column header patch at least.
* changes in v11:
- factor out hists__inc_nr_samples (Jiri)
- remove unrelated change (Jiri)
- disable accumulation on branch or mem mode
- slightly refactor hist_iter code
* changes in v10:
- fix callchain display bug in stdio, gtk
- add a testcase
- add Tested-by from Rodrigo
* changes in v9:
- support output field option
- add Acked-by tags from Jiri
* changes in v8:
- not depends on --percentage patchkit
- fix callchain resolving bug (Jiri)
- convert to sample__resolve_{mem,bstack}
- eliminate 'event' field from hist_entry_iter
* changes in v7:
- add Tested-by tags from Arun
- rebase onto current acme/perf/core
* changes in v6:
- separate struct hist_iter_ops (Jiri)
- check iter->he before calling ->add_entry_cb (Jiri)
- fix locking issue on perf top (Jiri)
* changes in v5:
- support both of --children and --call-graph (Arun)
- refactor hist_entry_iter to share with perf top (Jiri)
- various cleanups and fixes (Jiri)
- add ack's from Jiri
* changes in v4:
- change to --children option (Ingo)
- rebased on new annotation change (Arnaldo)
- support perf top also
- enable --children option by default (Ingo)
* changes in v3:
- change to --cumulate option
- fix a couple of bugs (Jiri, Rodrigo)
- rename some help functions (Arnaldo)
- cache previous hist entries rathen than just symbol and dso
- add some preparatory cleanups
- add report.cumulate config option
Let me show you an example:
$ cat abc.c
#define barrier() asm volatile("" ::: "memory") void a(void)
{
int i;
for (i = 0; i < 1000000; i++)
barrier();
}
void b(void)
{
a();
}
void c(void)
{
b();
}
int main(void)
{
c();
return 0;
}With this simple program I ran perf record and report:
$ perf record -g -e cycles:u ./abc
Case 1.
$ perf report --stdio --no-call-graph --no-children
# Overhead Command Shared Object Symbol
# ........ ....... ................. ..............
#
91.50% abc abc [.] a
8.18% abc ld-2.17.so [.] strlen
0.31% abc [kernel.kallsyms] [k] page_fault
0.01% abc ld-2.17.so [.] _start Case 2. (current default behavior)
$ perf report --stdio --call-graph --no-children
# Overhead Command Shared Object Symbol
# ........ ....... ................. ..............
#
91.50% abc abc [.] a
|
--- a
b
c
main
__libc_start_main 8.18% abc ld-2.17.so [.] strlen
|
--- strlen
_dl_sysdep_start
0.31% abc [kernel.kallsyms] [k] page_fault
|
--- page_fault
_start
0.01% abc ld-2.17.so [.] _start
|
--- _startCase 3.
$ perf report --no-call-graph --children --stdio
# Self Children Command Shared Object Symbol
# ........ ........ ....... ................. .....................
#
0.00% 91.50% abc libc-2.17.so [.] __libc_start_main
0.00% 91.50% abc abc [.] main
0.00% 91.50% abc abc [.] c
0.00% 91.50% abc abc [.] b
91.50% 91.50% abc abc [.] a
0.00% 8.18% abc ld-2.17.so [.] _dl_sysdep_start
8.18% 8.18% abc ld-2.17.so [.] strlen
0.01% 0.33% abc ld-2.17.so [.] _start
0.31% 0.31% abc [kernel.kallsyms] [k] page_fault As you can see __libc_start_main -> main -> c -> b -> a callchain show up in the output.
Finally, it looks like below with both option enabled:
Case 4. (default behavior?)
$ perf report --call-graph --children --stdio
# Self Children Command Shared Object Symbol
# ........ ........ ....... ................. .....................
#
0.00% 91.50% abc libc-2.17.so [.] __libc_start_main
|
--- __libc_start_main
0.00% 91.50% abc abc [.] main
|
--- main
__libc_start_main
0.00% 91.50% abc abc [.] c
|
--- c
main
__libc_start_main
0.00% 91.50% abc abc [.] b
|
--- b
c
main
__libc_start_main
91.50% 91.50% abc abc [.] a
|
--- a
b
c
main
__libc_start_main...
Currently the perf enables both of --call-graph and --children when it finds callchains in the samples. While this is useful for TUI or GTK, I'm not sure for stdio as it'd consume so much lines.
It does not handle all kind of cases like event annotation yet, but I really want to release it and get reviews.
You can also get this series on 'perf/cumulate-v11' branch in my tree at:
git://git.kernel.org/pub/scm/linux/kernel/git/namhyung/linux-perf.git
Any comments are welcome, thanks.
Namhyung
[1] https://lkml.org/lkml/2012/3/31/6
Namhyung Kim (27):
perf tools: Introduce hists__inc_nr_samples()
perf tools: Introduce struct hist_entry_iter
perf hists: Add support for accumulated stat of hist entry perf hists: Check if accumulated when adding a hist entry perf hists: Accumulate hist entry stat based on the callchain perf tools: Update cpumode for each cumulative entry
perf report: Cache cumulative callchains
perf callchain: Add callchain_cursor_snapshot()
perf tools: Save callchain info for each cumulative entry perf ui/hist: Add support to accumulated hist stat
perf ui/browser: Add support to accumulated hist stat
perf ui/gtk: Add support to accumulated hist stat
perf tools: Apply percent-limit to cumulative percentage perf tools: Add more hpp helper functions
perf report: Add --children option
perf report: Add report.children config option
perf tools: Do not auto-remove Children column if --fields given perf tools: Add callback function to hist_entry_iter
perf top: Convert to hist_entry_iter
perf top: Add --children option
perf top: Add top.children config option
perf tools: Enable --children option by default
perf ui/stdio: Fix invalid percentage value of cumulated hist entries perf ui/gtk: Fix callchain display
perf tools: Reset output/sort order to default
perf tests: Define and use symbolic names for fake symbols perf tests: Add a test case for cumulating callchains
tools/perf/Documentation/perf-report.txt | 7 +- tools/perf/Documentation/perf-top.txt | 8 +- tools/perf/Makefile.perf | 1 + tools/perf/builtin-annotate.c | 5 +- tools/perf/builtin-diff.c | 2 +- tools/perf/builtin-report.c | 200 ++------- tools/perf/builtin-sched.c | 2 +- tools/perf/builtin-top.c | 89 ++-- tools/perf/tests/builtin-test.c | 4 + tools/perf/tests/hists_common.c | 52 ++- tools/perf/tests/hists_common.h | 32 +- tools/perf/tests/hists_cumulate.c | 726 +++++++++++++++++++++++++++++++ tools/perf/tests/hists_filter.c | 39 +- tools/perf/tests/hists_link.c | 36 +- tools/perf/tests/hists_output.c | 31 +- tools/perf/tests/tests.h | 1 + tools/perf/ui/browsers/hists.c | 65 +-- tools/perf/ui/gtk/hists.c | 33 +- tools/perf/ui/hist.c | 119 +++++ tools/perf/ui/stdio/hist.c | 8 +- tools/perf/util/callchain.c | 45 +- tools/perf/util/callchain.h | 11 + tools/perf/util/hist.c | 513 +++++++++++++++++++++- tools/perf/util/hist.h | 49 ++- tools/perf/util/sort.c | 4 + tools/perf/util/sort.h | 18 +- tools/perf/util/symbol.c | 11 +- tools/perf/util/symbol.h | 1 + 28 files changed, 1780 insertions(+), 332 deletions(-) create mode 100644 tools/perf/tests/hists_cumulate.c
Signature · 1 line
1.9.2
Namhyung Kim
maintainerPATCH 1/27 perf tools: Introduce hists__inc_nr_samples()
There're some duplicate code for counting number of samples. Add hists__inc_nr_samples() and reuse it.
--- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-report.c | 4 +--- tools/perf/builtin-sched.c | 2 +- tools/perf/builtin-top.c | 5 +---- tools/perf/tests/hists_filter.c | 4 +--- tools/perf/util/hist.c | 7 +++++++ tools/perf/util/hist.h | 1 + 7 files changed, 13 insertions(+), 12 deletions(-)
tools/perf/builtin-annotate.c +1 -1
@@ -70,7 +70,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,return -ENOMEM ; ret =hist_entry__inc_addr_samples (he, evsel->idx, al->addr); -hists__inc_nr_events (&evsel->hists,PERF_RECORD_SAMPLE ); +hists__inc_nr_samples (&evsel->hists, true);return ret; }
tools/perf/builtin-report.c +1 -3
@@ -92,9 +92,7 @@ static void report__inc_stats(struct report *rep, struct hist_entry *he)* counted in perf_session_deliver_event(). The dump_trace * requires this info is ready before going to the output tree. */ -hists__inc_nr_events (he->hists,PERF_RECORD_SAMPLE ); -if (!he->filtered) - he->hists->stats.nr_non_filtered_samples++; +hists__inc_nr_samples (he->hists, he->filtered); } static int report__add_mem_hist_entry(struct report *rep, struct addr_location *al,
tools/perf/builtin-sched.c +1 -1
@@ -1428,7 +1428,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_int err =0 ; evsel->hists.stats.total_period += sample->period; -hists__inc_nr_events (&evsel->hists,PERF_RECORD_SAMPLE ); +hists__inc_nr_samples (&evsel->hists, true);if (evsel->handler !=NULL ) {tracepoint_handler f = evsel->handler;
tools/perf/builtin-top.c +1 -4
@@ -252,10 +252,7 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,if (he ==NULL )return NULL ; -hists__inc_nr_events (&evsel->hists,PERF_RECORD_SAMPLE ); -if (!he->filtered) - evsel->hists.stats.nr_non_filtered_samples++; - +hists__inc_nr_samples (&evsel->hists, he->filtered);return he; }
tools/perf/tests/hists_filter.c +1 -3
@@ -85,9 +85,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) fake_samples[i].map = al.map; fake_samples[i].sym = al.sym; -hists__inc_nr_events (he->hists,PERF_RECORD_SAMPLE ); -if (!he->filtered) - he->hists->stats.nr_non_filtered_samples++; +hists__inc_nr_samples (he->hists, he->filtered); } }
tools/perf/util/hist.c +7 -0
@@ -800,6 +800,13 @@ void hists__inc_nr_events(struct hists *hists, u32 type)events_stats__inc (&hists->stats, type); } +void hists__inc_nr_samples (struct hists *hists,bool filtered) +{ +events_stats__inc (&hists->stats,PERF_RECORD_SAMPLE ); +if (!filtered) + hists->stats.nr_non_filtered_samples++; +} +static struct hist_entry *hists__add_dummy_entry (struct hists *hists,struct hist_entry *pair) {
tools/perf/util/hist.h +1 -0
@@ -119,6 +119,7 @@ u64 hists__total_period(struct hists *hists);void hists__reset_stats (struct hists *hists);void hists__inc_stats (struct hists *hists,struct hist_entry *h);void hists__inc_nr_events (struct hists *hists,u32 type); +void hists__inc_nr_samples (struct hists *hists,bool filtered);void events_stats__inc (struct events_stats *stats,u32 type);size_t events_stats__fprintf (struct events_stats *stats,FILE *fp);
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf tools: Introduce hists__inc_nr_samples()
perf tools: Introduce hists__inc_nr_samples()
Commit-ID: 1844dbcbe78503e0f4a8996d69da725d5e7a5177 Gitweb: http://git.kernel.org/tip/1844dbcbe78503e0f4a8996d69da725d5e7a5177 Author: Namhyung Kim <[email protected]> AuthorDate: Wed, 28 May 2014 14:12:18 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:34:55 +0200
perf tools: Introduce hists__inc_nr_samples()
There're some duplicate code for counting number of samples. Add hists__inc_nr_samples() and reuse it.
--- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-report.c | 4 +--- tools/perf/builtin-sched.c | 2 +- tools/perf/builtin-top.c | 5 +---- tools/perf/tests/hists_filter.c | 4 +--- tools/perf/util/hist.c | 7 +++++++ tools/perf/util/hist.h | 1 + 7 files changed, 13 insertions(+), 12 deletions(-)
tools/perf/builtin-annotate.c +1 -1
@@ -70,7 +70,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,return -ENOMEM ; ret =hist_entry__inc_addr_samples (he, evsel->idx, al->addr); -hists__inc_nr_events (&evsel->hists,PERF_RECORD_SAMPLE ); +hists__inc_nr_samples (&evsel->hists, true);return ret; }
tools/perf/builtin-report.c +1 -3
@@ -92,9 +92,7 @@ static void report__inc_stats(struct report *rep, struct hist_entry *he)* counted in perf_session_deliver_event(). The dump_trace * requires this info is ready before going to the output tree. */ -hists__inc_nr_events (he->hists,PERF_RECORD_SAMPLE ); -if (!he->filtered) - he->hists->stats.nr_non_filtered_samples++; +hists__inc_nr_samples (he->hists, he->filtered); } static int report__add_mem_hist_entry(struct report *rep, struct addr_location *al,
tools/perf/builtin-sched.c +1 -1
@@ -1428,7 +1428,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_int err =0 ; evsel->hists.stats.total_period += sample->period; -hists__inc_nr_events (&evsel->hists,PERF_RECORD_SAMPLE ); +hists__inc_nr_samples (&evsel->hists, true);if (evsel->handler !=NULL ) {tracepoint_handler f = evsel->handler;
tools/perf/builtin-top.c +1 -4
@@ -252,10 +252,7 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,if (he ==NULL )return NULL ; -hists__inc_nr_events (&evsel->hists,PERF_RECORD_SAMPLE ); -if (!he->filtered) - evsel->hists.stats.nr_non_filtered_samples++; - +hists__inc_nr_samples (&evsel->hists, he->filtered);return he; }
tools/perf/tests/hists_filter.c +1 -3
@@ -85,9 +85,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) fake_samples[i].map = al.map; fake_samples[i].sym = al.sym; -hists__inc_nr_events (he->hists,PERF_RECORD_SAMPLE ); -if (!he->filtered) - he->hists->stats.nr_non_filtered_samples++; +hists__inc_nr_samples (he->hists, he->filtered); } }
tools/perf/util/hist.c +7 -0
@@ -800,6 +800,13 @@ void hists__inc_nr_events(struct hists *hists, u32 type)events_stats__inc (&hists->stats, type); } +void hists__inc_nr_samples (struct hists *hists,bool filtered) +{ +events_stats__inc (&hists->stats,PERF_RECORD_SAMPLE ); +if (!filtered) + hists->stats.nr_non_filtered_samples++; +} +static struct hist_entry *hists__add_dummy_entry (struct hists *hists,struct hist_entry *pair) {
tools/perf/util/hist.h +1 -0
@@ -119,6 +119,7 @@ u64 hists__total_period(struct hists *hists);void hists__reset_stats (struct hists *hists);void hists__inc_stats (struct hists *hists,struct hist_entry *h);void hists__inc_nr_events (struct hists *hists,u32 type); +void hists__inc_nr_samples (struct hists *hists,bool filtered);void events_stats__inc (struct events_stats *stats,u32 type);size_t events_stats__fprintf (struct events_stats *stats,FILE *fp);
Namhyung Kim
maintainerPATCH 2/27 perf tools: Introduce struct hist_entry_iter
In reply to Namhyung KimThere're some duplicate code when adding hist entries. They are different in that some have branch info or mem info but generally do same thing. So introduce new struct hist_entry_iter and add callbacks to customize each case in general way.
The new perf_evsel__add_entry() function will look like:
iter->prepare_entry();
iter->add_single_entry();
while (iter->next_entry())
iter->add_next_entry();
iter->finish_entry();This will help further work like the cumulative callchain patchset.
--- tools/perf/builtin-report.c | 192 ++++---------------------- tools/perf/tests/hists_filter.c | 16 ++- tools/perf/tests/hists_output.c | 11 +- tools/perf/util/hist.c | 299 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/hist.h | 33 +++++ 5 files changed, 372 insertions(+), 179 deletions(-)
tools/perf/builtin-report.c +24 -168
@@ -76,163 +76,16 @@ static int report__config(const char *var, const char *value, void *cb)return perf_default_config (var, value, cb); } -static void report__inc_stats (struct report *rep,struct hist_entry *he) +static void report__inc_stats (struct report *rep, +struct hist_entry *he__maybe_unused ) {/* -* The @he is either of a newly created one or an existing one -* merging current sample. We only want to count a new one so -* checking ->nr_events being 1. +* We cannot access @he at this time. Just assume it's a new entry. +* It'll be fixed once we have a callback mechanism in hist_iter. */ -if (he->stat.nr_events ==1 ) - rep->nr_entries++; - -/* -* Only counts number of samples at this stage as it's more -* natural to do it here and non-sample events are also -* counted in perf_session_deliver_event(). The dump_trace -* requires this info is ready before going to the output tree. -*/ -hists__inc_nr_samples (he->hists, he->filtered); -} - -static int report__add_mem_hist_entry (struct report *rep,struct addr_location *al, -struct perf_sample *sample,struct perf_evsel *evsel) -{ -struct symbol *parent =NULL ; -struct hist_entry *he; -struct mem_info *mi, *mx; -uint64_t cost; -int err =sample__resolve_callchain (sample, &parent, evsel, al, rep->max_stack); - -if (err) -return err; - - mi =sample__resolve_mem (sample, al); -if (!mi) -return -ENOMEM ; - -if (rep->hide_unresolved && !al->sym) -return 0 ; - - cost = sample->weight; -if (!cost) - cost =1 ; - -/* -* must pass period=weight in order to get the correct -* sorting from hists__collapse_resort() which is solely -* based on periods. We want sorting be done on nr_events * weight -* and this is indirectly achieved by passing period=weight here -* and the he_stat__add_period() function. -*/ - he =__hists__add_entry (&evsel->hists, al, parent,NULL , mi, - cost, cost,0 ); -if (!he) -return -ENOMEM ; - -if (ui__has_annotation ()) { - err =hist_entry__inc_addr_samples (he, evsel->idx, al->addr); -if (err) - goto out; - - mx = he->mem_info; - err =addr_map_symbol__inc_samples (&mx->daddr, evsel->idx); -if (err) - goto out; - } - -report__inc_stats (rep, he); - - err =hist_entry__append_callchain (he, sample); -out: -return err; -} - -static int report__add_branch_hist_entry (struct report *rep,struct addr_location *al, -struct perf_sample *sample,struct perf_evsel *evsel) -{ -struct symbol *parent =NULL ; -unsigned i; -struct hist_entry *he; -struct branch_info *bi, *bx; -int err =sample__resolve_callchain (sample, &parent, evsel, al, rep->max_stack); - -if (err) -return err; - - bi =sample__resolve_bstack (sample, al); -if (!bi) -return -ENOMEM ; - -for (i =0 ; i < sample->branch_stack->nr; i++) { -if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym)) -continue ; - - err = -ENOMEM ; - -/* overwrite the 'al' to branch-to info */ - al->map = bi[i].to.map; - al->sym = bi[i].to.sym; - al->addr = bi[i].to.addr; -/* -* The report shows the percentage of total branches captured -* and not events sampled. Thus we use a pseudo period of 1. -*/ - he =__hists__add_entry (&evsel->hists, al, parent, &bi[i],NULL , -1 ,1 ,0 ); -if (he) { -if (ui__has_annotation ()) { - bx = he->branch_info; - err =addr_map_symbol__inc_samples (&bx->from, - evsel->idx); -if (err) - goto out; - - err =addr_map_symbol__inc_samples (&bx->to, - evsel->idx); -if (err) - goto out; - } -report__inc_stats (rep, he); - }else - goto out; - } - err =0 ; -out: -free (bi); -return err; + rep->nr_entries++; } -static int report__add_hist_entry (struct report *rep,struct perf_evsel *evsel, -struct addr_location *al,struct perf_sample *sample) -{ -struct symbol *parent =NULL ; -struct hist_entry *he; -int err =sample__resolve_callchain (sample, &parent, evsel, al, rep->max_stack); - -if (err) -return err; - - he =__hists__add_entry (&evsel->hists, al, parent,NULL ,NULL , - sample->period, sample->weight, - sample->transaction); -if (he ==NULL ) -return -ENOMEM ; - - err =hist_entry__append_callchain (he, sample); -if (err) - goto out; - -if (ui__has_annotation ()) - err =hist_entry__inc_addr_samples (he, evsel->idx, al->addr); - -report__inc_stats (rep, he); - -out: -return err; -} - - static int process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample,
@@ -241,6 +94,9 @@ static int process_sample_event(struct perf_tool *tool, { struct report *rep = container_of(tool, struct report, tool);struct addr_location al; +struct hist_entry_iter iter = { + .hide_unresolved = rep->hide_unresolved, + };int ret;if (perf_event__preprocess_sample (event, machine, &al, sample) <0 ) {
@@ -255,22 +111,22 @@ static int process_sample_event(struct perf_tool *tool,if (rep->cpu_list && !test_bit (sample->cpu, rep->cpu_bitmap))return 0 ; -if (sort__mode ==SORT_MODE__BRANCH ) { - ret =report__add_branch_hist_entry (rep, &al, sample, evsel); -if (ret <0 ) -pr_debug ("problem adding lbr entry, skipping event\n" ); - }else if (rep->mem_mode ==1 ) { - ret =report__add_mem_hist_entry (rep, &al, sample, evsel); -if (ret <0 ) -pr_debug ("problem adding mem entry, skipping event\n" ); - }else { -if (al.map !=NULL ) - al.map->dso->hit =1 ; - - ret =report__add_hist_entry (rep, evsel, &al, sample); -if (ret <0 ) -pr_debug ("problem incrementing symbol period, skipping event\n" ); - } +if (sort__mode ==SORT_MODE__BRANCH ) + iter.ops = &hist_iter_branch; +else if (rep->mem_mode) + iter.ops = &hist_iter_mem; +else + iter.ops = &hist_iter_normal; + +if (al.map !=NULL ) + al.map->dso->hit =1 ; + +report__inc_stats (rep,NULL ); + + ret =hist_entry_iter__add (&iter, &al, evsel, sample, rep->max_stack); +if (ret <0 ) +pr_debug ("problem adding hist entry, skipping event\n" ); +return ret; }
tools/perf/tests/hists_filter.c +9 -7
@@ -42,11 +42,11 @@ static struct sample fake_samples[] = { { .pid = 300, .ip = 0xf0000 + 800, }, }; -static int add_hist_entries (struct perf_evlist *evlist,struct machine *machine) +static int add_hist_entries (struct perf_evlist *evlist, +struct machine *machine__maybe_unused ) {struct perf_evsel *evsel;struct addr_location al; -struct hist_entry *he;struct perf_sample sample = { .cpu =0 , };size_t i;
@@ -62,6 +62,10 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) .misc = PERF_RECORD_MISC_USER, }, }; +struct hist_entry_iter iter = { + .ops = &hist_iter_normal, + .hide_unresolved = false, + };/* make sure it has no filter at first */ evsel->hists.thread_filter =NULL ;
@@ -71,21 +75,19 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) sample.pid = fake_samples[i].pid; sample.tid = fake_samples[i].pid; sample.ip = fake_samples[i].ip; + sample.period =100 ;if (perf_event__preprocess_sample (&event, machine, &al, &sample) <0 ) goto out; - he =__hists__add_entry (&evsel->hists, &al,NULL , -NULL ,NULL ,100 ,1 ,0 ); -if (he ==NULL ) +if (hist_entry_iter__add (&iter, &al, evsel, &sample, +PERF_MAX_STACK_DEPTH ) <0 ) goto out; fake_samples[i].thread = al.thread; fake_samples[i].map = al.map; fake_samples[i].sym = al.sym; - -hists__inc_nr_samples (he->hists, he->filtered); } }
tools/perf/tests/hists_output.c +7 -4
@@ -46,7 +46,7 @@ static struct sample fake_samples[] = {static int add_hist_entries (struct hists *hists,struct machine *machine) {struct addr_location al; -struct hist_entry *he; +struct perf_evsel *evsel =hists_to_evsel (hists);struct perf_sample sample = { .period =100 , };size_t i;
@@ -56,6 +56,10 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) .misc = PERF_RECORD_MISC_USER, }, }; +struct hist_entry_iter iter = { + .ops = &hist_iter_normal, + .hide_unresolved = false, + }; sample.cpu = fake_samples[i].cpu; sample.pid = fake_samples[i].pid;
@@ -66,9 +70,8 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) &sample) < 0) goto out; - he =__hists__add_entry (hists, &al,NULL ,NULL ,NULL , - sample.period,1 ,0 ); -if (he ==NULL ) +if (hist_entry_iter__add (&iter, &al, evsel, &sample, +PERF_MAX_STACK_DEPTH ) <0 ) goto out; fake_samples[i].thread = al.thread;
tools/perf/util/hist.c +299 -0
311 lines not on this page · raw message
tools/perf/util/hist.h +33 -0
@@ -96,12 +96,45 @@ struct hists {u16 col_len[HISTC_NR_COLS ]; }; +struct hist_entry_iter ; + +struct hist_iter_ops { +int (*prepare_entry)(struct hist_entry_iter *,struct addr_location *); +int (*add_single_entry)(struct hist_entry_iter *,struct addr_location *); +int (*next_entry)(struct hist_entry_iter *,struct addr_location *); +int (*add_next_entry)(struct hist_entry_iter *,struct addr_location *); +int (*finish_entry)(struct hist_entry_iter *,struct addr_location *); +}; + +struct hist_entry_iter { +int total; +int curr; + +bool hide_unresolved; + +struct perf_evsel *evsel; +struct perf_sample *sample; +struct hist_entry *he; +struct symbol *parent; +void *priv; + +const struct hist_iter_ops *ops; +}; + +extern const struct hist_iter_ops hist_iter_normal; +extern const struct hist_iter_ops hist_iter_branch; +extern const struct hist_iter_ops hist_iter_mem; +struct hist_entry *__hists__add_entry (struct hists *hists,struct addr_location *al,struct symbol *parent,struct branch_info *bi,struct mem_info *mi,u64 period,u64 weight,u64 transaction); +int hist_entry_iter__add (struct hist_entry_iter *iter,struct addr_location *al, +struct perf_evsel *evsel,struct perf_sample *sample, +int max_stack_depth); +int64_t hist_entry__cmp (struct hist_entry *left,struct hist_entry *right);int64_t hist_entry__collapse (struct hist_entry *left,struct hist_entry *right);int hist_entry__transaction_len (void );
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf tools: Introduce struct hist_entry_iter
perf tools: Introduce struct hist_entry_iter
Commit-ID: 69bcb019fc809874f518559c8e5b0a90176f0532 Gitweb: http://git.kernel.org/tip/69bcb019fc809874f518559c8e5b0a90176f0532 Author: Namhyung Kim <[email protected]> AuthorDate: Wed, 30 Oct 2013 09:40:34 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:34:55 +0200
perf tools: Introduce struct hist_entry_iter
There're some duplicate code when adding hist entries. They are different in that some have branch info or mem info but generally do same thing. So introduce new struct hist_entry_iter and add callbacks to customize each case in general way.
The new perf_evsel__add_entry() function will look like:
iter->prepare_entry();
iter->add_single_entry();
while (iter->next_entry())
iter->add_next_entry();
iter->finish_entry();This will help further work like the cumulative callchain patchset.
--- tools/perf/builtin-report.c | 192 ++++---------------------- tools/perf/tests/hists_filter.c | 16 ++- tools/perf/tests/hists_output.c | 11 +- tools/perf/util/hist.c | 299 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/hist.h | 33 +++++ 5 files changed, 372 insertions(+), 179 deletions(-)
tools/perf/builtin-report.c +24 -168
@@ -76,163 +76,16 @@ static int report__config(const char *var, const char *value, void *cb)return perf_default_config (var, value, cb); } -static void report__inc_stats (struct report *rep,struct hist_entry *he) +static void report__inc_stats (struct report *rep, +struct hist_entry *he__maybe_unused ) {/* -* The @he is either of a newly created one or an existing one -* merging current sample. We only want to count a new one so -* checking ->nr_events being 1. +* We cannot access @he at this time. Just assume it's a new entry. +* It'll be fixed once we have a callback mechanism in hist_iter. */ -if (he->stat.nr_events ==1 ) - rep->nr_entries++; - -/* -* Only counts number of samples at this stage as it's more -* natural to do it here and non-sample events are also -* counted in perf_session_deliver_event(). The dump_trace -* requires this info is ready before going to the output tree. -*/ -hists__inc_nr_samples (he->hists, he->filtered); -} - -static int report__add_mem_hist_entry (struct report *rep,struct addr_location *al, -struct perf_sample *sample,struct perf_evsel *evsel) -{ -struct symbol *parent =NULL ; -struct hist_entry *he; -struct mem_info *mi, *mx; -uint64_t cost; -int err =sample__resolve_callchain (sample, &parent, evsel, al, rep->max_stack); - -if (err) -return err; - - mi =sample__resolve_mem (sample, al); -if (!mi) -return -ENOMEM ; - -if (rep->hide_unresolved && !al->sym) -return 0 ; - - cost = sample->weight; -if (!cost) - cost =1 ; - -/* -* must pass period=weight in order to get the correct -* sorting from hists__collapse_resort() which is solely -* based on periods. We want sorting be done on nr_events * weight -* and this is indirectly achieved by passing period=weight here -* and the he_stat__add_period() function. -*/ - he =__hists__add_entry (&evsel->hists, al, parent,NULL , mi, - cost, cost,0 ); -if (!he) -return -ENOMEM ; - -if (ui__has_annotation ()) { - err =hist_entry__inc_addr_samples (he, evsel->idx, al->addr); -if (err) - goto out; - - mx = he->mem_info; - err =addr_map_symbol__inc_samples (&mx->daddr, evsel->idx); -if (err) - goto out; - } - -report__inc_stats (rep, he); - - err =hist_entry__append_callchain (he, sample); -out: -return err; -} - -static int report__add_branch_hist_entry (struct report *rep,struct addr_location *al, -struct perf_sample *sample,struct perf_evsel *evsel) -{ -struct symbol *parent =NULL ; -unsigned i; -struct hist_entry *he; -struct branch_info *bi, *bx; -int err =sample__resolve_callchain (sample, &parent, evsel, al, rep->max_stack); - -if (err) -return err; - - bi =sample__resolve_bstack (sample, al); -if (!bi) -return -ENOMEM ; - -for (i =0 ; i < sample->branch_stack->nr; i++) { -if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym)) -continue ; - - err = -ENOMEM ; - -/* overwrite the 'al' to branch-to info */ - al->map = bi[i].to.map; - al->sym = bi[i].to.sym; - al->addr = bi[i].to.addr; -/* -* The report shows the percentage of total branches captured -* and not events sampled. Thus we use a pseudo period of 1. -*/ - he =__hists__add_entry (&evsel->hists, al, parent, &bi[i],NULL , -1 ,1 ,0 ); -if (he) { -if (ui__has_annotation ()) { - bx = he->branch_info; - err =addr_map_symbol__inc_samples (&bx->from, - evsel->idx); -if (err) - goto out; - - err =addr_map_symbol__inc_samples (&bx->to, - evsel->idx); -if (err) - goto out; - } -report__inc_stats (rep, he); - }else - goto out; - } - err =0 ; -out: -free (bi); -return err; + rep->nr_entries++; } -static int report__add_hist_entry (struct report *rep,struct perf_evsel *evsel, -struct addr_location *al,struct perf_sample *sample) -{ -struct symbol *parent =NULL ; -struct hist_entry *he; -int err =sample__resolve_callchain (sample, &parent, evsel, al, rep->max_stack); - -if (err) -return err; - - he =__hists__add_entry (&evsel->hists, al, parent,NULL ,NULL , - sample->period, sample->weight, - sample->transaction); -if (he ==NULL ) -return -ENOMEM ; - - err =hist_entry__append_callchain (he, sample); -if (err) - goto out; - -if (ui__has_annotation ()) - err =hist_entry__inc_addr_samples (he, evsel->idx, al->addr); - -report__inc_stats (rep, he); - -out: -return err; -} - - static int process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample,
@@ -241,6 +94,9 @@ static int process_sample_event(struct perf_tool *tool, { struct report *rep = container_of(tool, struct report, tool);struct addr_location al; +struct hist_entry_iter iter = { + .hide_unresolved = rep->hide_unresolved, + };int ret;if (perf_event__preprocess_sample (event, machine, &al, sample) <0 ) {
@@ -255,22 +111,22 @@ static int process_sample_event(struct perf_tool *tool,if (rep->cpu_list && !test_bit (sample->cpu, rep->cpu_bitmap))return 0 ; -if (sort__mode ==SORT_MODE__BRANCH ) { - ret =report__add_branch_hist_entry (rep, &al, sample, evsel); -if (ret <0 ) -pr_debug ("problem adding lbr entry, skipping event\n" ); - }else if (rep->mem_mode ==1 ) { - ret =report__add_mem_hist_entry (rep, &al, sample, evsel); -if (ret <0 ) -pr_debug ("problem adding mem entry, skipping event\n" ); - }else { -if (al.map !=NULL ) - al.map->dso->hit =1 ; - - ret =report__add_hist_entry (rep, evsel, &al, sample); -if (ret <0 ) -pr_debug ("problem incrementing symbol period, skipping event\n" ); - } +if (sort__mode ==SORT_MODE__BRANCH ) + iter.ops = &hist_iter_branch; +else if (rep->mem_mode) + iter.ops = &hist_iter_mem; +else + iter.ops = &hist_iter_normal; + +if (al.map !=NULL ) + al.map->dso->hit =1 ; + +report__inc_stats (rep,NULL ); + + ret =hist_entry_iter__add (&iter, &al, evsel, sample, rep->max_stack); +if (ret <0 ) +pr_debug ("problem adding hist entry, skipping event\n" ); +return ret; }
tools/perf/tests/hists_filter.c +9 -7
@@ -42,11 +42,11 @@ static struct sample fake_samples[] = { { .pid = 300, .ip = 0xf0000 + 800, }, }; -static int add_hist_entries (struct perf_evlist *evlist,struct machine *machine) +static int add_hist_entries (struct perf_evlist *evlist, +struct machine *machine__maybe_unused ) {struct perf_evsel *evsel;struct addr_location al; -struct hist_entry *he;struct perf_sample sample = { .cpu =0 , };size_t i;
@@ -62,6 +62,10 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) .misc = PERF_RECORD_MISC_USER, }, }; +struct hist_entry_iter iter = { + .ops = &hist_iter_normal, + .hide_unresolved = false, + };/* make sure it has no filter at first */ evsel->hists.thread_filter =NULL ;
@@ -71,21 +75,19 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) sample.pid = fake_samples[i].pid; sample.tid = fake_samples[i].pid; sample.ip = fake_samples[i].ip; + sample.period =100 ;if (perf_event__preprocess_sample (&event, machine, &al, &sample) <0 ) goto out; - he =__hists__add_entry (&evsel->hists, &al,NULL , -NULL ,NULL ,100 ,1 ,0 ); -if (he ==NULL ) +if (hist_entry_iter__add (&iter, &al, evsel, &sample, +PERF_MAX_STACK_DEPTH ) <0 ) goto out; fake_samples[i].thread = al.thread; fake_samples[i].map = al.map; fake_samples[i].sym = al.sym; - -hists__inc_nr_samples (he->hists, he->filtered); } }
tools/perf/tests/hists_output.c +7 -4
@@ -46,7 +46,7 @@ static struct sample fake_samples[] = {static int add_hist_entries (struct hists *hists,struct machine *machine) {struct addr_location al; -struct hist_entry *he; +struct perf_evsel *evsel =hists_to_evsel (hists);struct perf_sample sample = { .period =100 , };size_t i;
@@ -56,6 +56,10 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) .misc = PERF_RECORD_MISC_USER, }, }; +struct hist_entry_iter iter = { + .ops = &hist_iter_normal, + .hide_unresolved = false, + }; sample.cpu = fake_samples[i].cpu; sample.pid = fake_samples[i].pid;
@@ -66,9 +70,8 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) &sample) < 0) goto out; - he =__hists__add_entry (hists, &al,NULL ,NULL ,NULL , - sample.period,1 ,0 ); -if (he ==NULL ) +if (hist_entry_iter__add (&iter, &al, evsel, &sample, +PERF_MAX_STACK_DEPTH ) <0 ) goto out; fake_samples[i].thread = al.thread;
tools/perf/util/hist.c +299 -0
311 lines not on this page · raw message
tools/perf/util/hist.h +33 -0
@@ -96,12 +96,45 @@ struct hists {u16 col_len[HISTC_NR_COLS ]; }; +struct hist_entry_iter ; + +struct hist_iter_ops { +int (*prepare_entry)(struct hist_entry_iter *,struct addr_location *); +int (*add_single_entry)(struct hist_entry_iter *,struct addr_location *); +int (*next_entry)(struct hist_entry_iter *,struct addr_location *); +int (*add_next_entry)(struct hist_entry_iter *,struct addr_location *); +int (*finish_entry)(struct hist_entry_iter *,struct addr_location *); +}; + +struct hist_entry_iter { +int total; +int curr; + +bool hide_unresolved; + +struct perf_evsel *evsel; +struct perf_sample *sample; +struct hist_entry *he; +struct symbol *parent; +void *priv; + +const struct hist_iter_ops *ops; +}; + +extern const struct hist_iter_ops hist_iter_normal; +extern const struct hist_iter_ops hist_iter_branch; +extern const struct hist_iter_ops hist_iter_mem; +struct hist_entry *__hists__add_entry (struct hists *hists,struct addr_location *al,struct symbol *parent,struct branch_info *bi,struct mem_info *mi,u64 period,u64 weight,u64 transaction); +int hist_entry_iter__add (struct hist_entry_iter *iter,struct addr_location *al, +struct perf_evsel *evsel,struct perf_sample *sample, +int max_stack_depth); +int64_t hist_entry__cmp (struct hist_entry *left,struct hist_entry *right);int64_t hist_entry__collapse (struct hist_entry *left,struct hist_entry *right);int hist_entry__transaction_len (void );
Namhyung Kim
maintainerPATCH 3/27 perf hists: Add support for accumulated stat of hist entry
In reply to Namhyung KimMaintain accumulated stat information in hist_entry->stat_acc if symbol_conf.cumulate_callchain is set. Fields in ->stat_acc have same vaules initially, and will be updated as callchain is processed later.
--- tools/perf/util/hist.c | 28 ++++++++++++++++++++++++++-- tools/perf/util/sort.h | 1 + tools/perf/util/symbol.h | 1 + 3 files changed, 28 insertions(+), 2 deletions(-)
tools/perf/util/hist.c +26 -2
@@ -232,6 +232,8 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)return true;he_stat__decay (&he->stat); +if (symbol_conf.cumulate_callchain) +he_stat__decay (he->stat_acc); diff = prev_period - he->stat.period;
@@ -279,12 +281,26 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)static struct hist_entry *hist_entry__new (struct hist_entry *template) { -size_t callchain_size = symbol_conf.use_callchain ?sizeof (struct callchain_root ) :0 ; -struct hist_entry *he =zalloc (sizeof (*he) + callchain_size); +size_t callchain_size =0 ; +struct hist_entry *he; + +if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) + callchain_size =sizeof (struct callchain_root ); + + he =zalloc (sizeof (*he) + callchain_size);if (he !=NULL ) { *he = *template; +if (symbol_conf.cumulate_callchain) { + he->stat_acc =malloc (sizeof (he->stat)); +if (he->stat_acc ==NULL ) { +free (he); +return NULL ; + } +memcpy (he->stat_acc, &he->stat,sizeof (he->stat)); + } +if (he->ms.map) he->ms.map->referenced = true;
@@ -296,6 +312,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)*/ he->branch_info =malloc (sizeof (*he->branch_info));if (he->branch_info ==NULL ) { +free (he->stat_acc);free (he);return NULL ; }
@@ -359,6 +376,8 @@ static struct hist_entry *add_hist_entry(struct hists *hists,if (!cmp) {he_stat__add_period (&he->stat, period, weight); +if (symbol_conf.cumulate_callchain) +he_stat__add_period (he->stat_acc, period, weight);/* * This mem info was allocated from sample__resolve_mem
@@ -394,6 +413,8 @@ static struct hist_entry *add_hist_entry(struct hists *hists,rb_insert_color (&he->rb_node_in, hists->entries_in); out:he_stat__add_cpumode_period (&he->stat, al->cpumode, period); +if (symbol_conf.cumulate_callchain) +he_stat__add_cpumode_period (he->stat_acc, al->cpumode, period);return he; }
@@ -768,6 +789,7 @@ void hist_entry__free(struct hist_entry *he) {zfree (&he->branch_info);zfree (&he->mem_info); +zfree (&he->stat_acc);free_srcline (he->srcline);free (he); }
@@ -793,6 +815,8 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,if (!cmp) {he_stat__add_stat (&iter->stat, &he->stat); +if (symbol_conf.cumulate_callchain) +he_stat__add_stat (iter->stat_acc, he->stat_acc);if (symbol_conf.use_callchain) {callchain_cursor_reset (&callchain_cursor);
tools/perf/util/sort.h +1 -0
@@ -82,6 +82,7 @@ struct hist_entry {struct list_head head; } pairs;struct he_stat stat; +struct he_stat *stat_acc;struct map_symbol ms;struct thread *thread;struct comm *comm;
tools/perf/util/symbol.h +1 -0
@@ -109,6 +109,7 @@ struct symbol_conf { show_nr_samples, show_total_period, use_callchain, + cumulate_callchain, exclude_other, show_cpu_utilization, initialized,
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf hists: Add support for accumulated stat of hist entry
perf hists: Add support for accumulated stat of hist entry
Commit-ID: f8be1c8c48c8469d1ce95ccdc77b1e2c6a29700e Gitweb: http://git.kernel.org/tip/f8be1c8c48c8469d1ce95ccdc77b1e2c6a29700e Author: Namhyung Kim <[email protected]> AuthorDate: Tue, 11 Sep 2012 13:15:07 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:34:56 +0200
perf hists: Add support for accumulated stat of hist entry
Maintain accumulated stat information in hist_entry->stat_acc if symbol_conf.cumulate_callchain is set. Fields in ->stat_acc have same vaules initially, and will be updated as callchain is processed later.
--- tools/perf/util/hist.c | 28 ++++++++++++++++++++++++++-- tools/perf/util/sort.h | 1 + tools/perf/util/symbol.h | 1 + 3 files changed, 28 insertions(+), 2 deletions(-)
tools/perf/util/hist.c +26 -2
@@ -232,6 +232,8 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)return true;he_stat__decay (&he->stat); +if (symbol_conf.cumulate_callchain) +he_stat__decay (he->stat_acc); diff = prev_period - he->stat.period;
@@ -279,12 +281,26 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)static struct hist_entry *hist_entry__new (struct hist_entry *template) { -size_t callchain_size = symbol_conf.use_callchain ?sizeof (struct callchain_root ) :0 ; -struct hist_entry *he =zalloc (sizeof (*he) + callchain_size); +size_t callchain_size =0 ; +struct hist_entry *he; + +if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) + callchain_size =sizeof (struct callchain_root ); + + he =zalloc (sizeof (*he) + callchain_size);if (he !=NULL ) { *he = *template; +if (symbol_conf.cumulate_callchain) { + he->stat_acc =malloc (sizeof (he->stat)); +if (he->stat_acc ==NULL ) { +free (he); +return NULL ; + } +memcpy (he->stat_acc, &he->stat,sizeof (he->stat)); + } +if (he->ms.map) he->ms.map->referenced = true;
@@ -296,6 +312,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)*/ he->branch_info =malloc (sizeof (*he->branch_info));if (he->branch_info ==NULL ) { +free (he->stat_acc);free (he);return NULL ; }
@@ -359,6 +376,8 @@ static struct hist_entry *add_hist_entry(struct hists *hists,if (!cmp) {he_stat__add_period (&he->stat, period, weight); +if (symbol_conf.cumulate_callchain) +he_stat__add_period (he->stat_acc, period, weight);/* * This mem info was allocated from sample__resolve_mem
@@ -394,6 +413,8 @@ static struct hist_entry *add_hist_entry(struct hists *hists,rb_insert_color (&he->rb_node_in, hists->entries_in); out:he_stat__add_cpumode_period (&he->stat, al->cpumode, period); +if (symbol_conf.cumulate_callchain) +he_stat__add_cpumode_period (he->stat_acc, al->cpumode, period);return he; }
@@ -768,6 +789,7 @@ void hist_entry__free(struct hist_entry *he) {zfree (&he->branch_info);zfree (&he->mem_info); +zfree (&he->stat_acc);free_srcline (he->srcline);free (he); }
@@ -793,6 +815,8 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,if (!cmp) {he_stat__add_stat (&iter->stat, &he->stat); +if (symbol_conf.cumulate_callchain) +he_stat__add_stat (iter->stat_acc, he->stat_acc);if (symbol_conf.use_callchain) {callchain_cursor_reset (&callchain_cursor);
tools/perf/util/sort.h +1 -0
@@ -82,6 +82,7 @@ struct hist_entry {struct list_head head; } pairs;struct he_stat stat; +struct he_stat *stat_acc;struct map_symbol ms;struct thread *thread;struct comm *comm;
tools/perf/util/symbol.h +1 -0
@@ -109,6 +109,7 @@ struct symbol_conf { show_nr_samples, show_total_period, use_callchain, + cumulate_callchain, exclude_other, show_cpu_utilization, initialized,
Namhyung Kim
maintainerPATCH 4/27 perf hists: Check if accumulated when adding a hist entry
In reply to Namhyung KimTo support callchain accumulation, @entry should be recognized if it's accumulated or not when add_hist_entry() called. The period of an accumulated entry should be added to ->stat_acc but not ->stat. Add @sample_self arg for that.
--- tools/perf/builtin-annotate.c | 3 ++- tools/perf/builtin-diff.c | 2 +- tools/perf/builtin-top.c | 2 +- tools/perf/tests/hists_link.c | 4 ++-- tools/perf/util/hist.c | 29 ++++++++++++++++++----------- tools/perf/util/hist.h | 3 ++- 6 files changed, 26 insertions(+), 17 deletions(-)
tools/perf/builtin-annotate.c +2 -1
@@ -65,7 +65,8 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,return 0 ; } - he =__hists__add_entry (&evsel->hists, al,NULL ,NULL ,NULL ,1 ,1 ,0 ); + he =__hists__add_entry (&evsel->hists, al,NULL ,NULL ,NULL ,1 ,1 ,0 , + true);if (he ==NULL )return -ENOMEM ;
tools/perf/builtin-diff.c +1 -1
@@ -315,7 +315,7 @@ static int hists__add_entry(struct hists *hists, u64 weight, u64 transaction) { if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight, - transaction) != NULL) + transaction, true) != NULL) return 0;return -ENOMEM ; }
tools/perf/builtin-top.c +1 -1
@@ -247,7 +247,7 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,pthread_mutex_lock (&evsel->hists.lock); he =__hists__add_entry (&evsel->hists, al,NULL ,NULL ,NULL , sample->period, sample->weight, - sample->transaction); + sample->transaction, true);pthread_mutex_unlock (&evsel->hists.lock);if (he ==NULL )return NULL ;
tools/perf/tests/hists_link.c +2 -2
@@ -88,7 +88,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) goto out; he =__hists__add_entry (&evsel->hists, &al,NULL , -NULL ,NULL ,1 ,1 ,0 ); +NULL ,NULL ,1 ,1 ,0 , true);if (he ==NULL ) goto out;
@@ -112,7 +112,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) goto out; he =__hists__add_entry (&evsel->hists, &al,NULL , -NULL ,NULL ,1 ,1 ,0 ); +NULL ,NULL ,1 ,1 ,0 , true);if (he ==NULL ) goto out;
tools/perf/util/hist.c +18 -11
@@ -279,7 +279,8 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)* histogram, sorted on item, collects periods */ -static struct hist_entry *hist_entry__new (struct hist_entry *template) +static struct hist_entry *hist_entry__new (struct hist_entry *template, +bool sample_self) {size_t callchain_size =0 ;struct hist_entry *he;
@@ -299,6 +300,8 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)return NULL ; }memcpy (he->stat_acc, &he->stat,sizeof (he->stat)); +if (!sample_self) +memset (&he->stat,0 ,sizeof (he->stat)); }if (he->ms.map)
@@ -351,7 +354,8 @@ static u8 symbol__parent_filter(const struct symbol *parent)static struct hist_entry *add_hist_entry (struct hists *hists,struct hist_entry *entry, -struct addr_location *al) +struct addr_location *al, +bool sample_self) {struct rb_node **p;struct rb_node *parent =NULL ;
@@ -375,7 +379,8 @@ static struct hist_entry *add_hist_entry(struct hists *hists, cmp =hist_entry__cmp (he, entry);if (!cmp) { -he_stat__add_period (&he->stat, period, weight); +if (sample_self) +he_stat__add_period (&he->stat, period, weight);if (symbol_conf.cumulate_callchain)he_stat__add_period (he->stat_acc, period, weight);
@@ -405,14 +410,15 @@ static struct hist_entry *add_hist_entry(struct hists *hists, p = &(*p)->rb_right; } - he =hist_entry__new (entry); + he =hist_entry__new (entry, sample_self);if (!he)return NULL ;rb_link_node (&he->rb_node_in, parent, p);rb_insert_color (&he->rb_node_in, hists->entries_in); out: -he_stat__add_cpumode_period (&he->stat, al->cpumode, period); +if (sample_self) +he_stat__add_cpumode_period (&he->stat, al->cpumode, period);if (symbol_conf.cumulate_callchain)he_stat__add_cpumode_period (he->stat_acc, al->cpumode, period);return he;
@@ -423,7 +429,8 @@ struct hist_entry *__hists__add_entry(struct hists *hists, struct symbol *sym_parent, struct branch_info *bi, struct mem_info *mi, - u64 period, u64 weight, u64 transaction) + u64 period, u64 weight, u64 transaction, + bool sample_self) { struct hist_entry entry = { .thread = al->thread,
@@ -448,7 +455,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists, .transaction = transaction, }; -return add_hist_entry (hists, &entry, al); +return add_hist_entry (hists, &entry, al, sample_self); } static int
@@ -501,7 +508,7 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al* and the he_stat__add_period() function. */ he =__hists__add_entry (&iter->evsel->hists, al, iter->parent,NULL , mi, - cost, cost,0 ); + cost, cost,0 , true);if (!he)return -ENOMEM ;
@@ -608,7 +615,7 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a* and not events sampled. Thus we use a pseudo period of 1. */ he =__hists__add_entry (&evsel->hists, al, iter->parent, &bi[i],NULL , -1 ,1 ,0 ); +1 ,1 ,0 , true);if (he ==NULL )return -ENOMEM ;
@@ -657,7 +664,7 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location he =__hists__add_entry (&evsel->hists, al, iter->parent,NULL ,NULL , sample->period, sample->weight, - sample->transaction); + sample->transaction, true);if (he ==NULL )return -ENOMEM ;
@@ -1161,7 +1168,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists, p = &(*p)->rb_right; } - he =hist_entry__new (pair); + he =hist_entry__new (pair, true);if (he) {memset (&he->stat,0 ,sizeof (he->stat)); he->hists = hists;
tools/perf/util/hist.h +2 -1
@@ -130,7 +130,8 @@ struct hist_entry *__hists__add_entry(struct hists *hists,struct symbol *parent, struct branch_info *bi, struct mem_info *mi, u64 period, - u64 weight, u64 transaction); + u64 weight, u64 transaction, + bool sample_self);int hist_entry_iter__add (struct hist_entry_iter *iter,struct addr_location *al,struct perf_evsel *evsel,struct perf_sample *sample,int max_stack_depth);
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf hists: Check if accumulated when adding a hist entry
perf hists: Check if accumulated when adding a hist entry
Commit-ID: a0b51af367a6831330564c96dc4cc1ac63413701 Gitweb: http://git.kernel.org/tip/a0b51af367a6831330564c96dc4cc1ac63413701 Author: Namhyung Kim <[email protected]> AuthorDate: Tue, 11 Sep 2012 13:34:27 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:34:56 +0200
perf hists: Check if accumulated when adding a hist entry
To support callchain accumulation, @entry should be recognized if it's accumulated or not when add_hist_entry() called. The period of an accumulated entry should be added to ->stat_acc but not ->stat. Add @sample_self arg for that.
--- tools/perf/builtin-annotate.c | 3 ++- tools/perf/builtin-diff.c | 2 +- tools/perf/builtin-top.c | 2 +- tools/perf/tests/hists_link.c | 4 ++-- tools/perf/util/hist.c | 29 ++++++++++++++++++----------- tools/perf/util/hist.h | 3 ++- 6 files changed, 26 insertions(+), 17 deletions(-)
tools/perf/builtin-annotate.c +2 -1
@@ -65,7 +65,8 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,return 0 ; } - he =__hists__add_entry (&evsel->hists, al,NULL ,NULL ,NULL ,1 ,1 ,0 ); + he =__hists__add_entry (&evsel->hists, al,NULL ,NULL ,NULL ,1 ,1 ,0 , + true);if (he ==NULL )return -ENOMEM ;
tools/perf/builtin-diff.c +1 -1
@@ -315,7 +315,7 @@ static int hists__add_entry(struct hists *hists, u64 weight, u64 transaction) { if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight, - transaction) != NULL) + transaction, true) != NULL) return 0;return -ENOMEM ; }
tools/perf/builtin-top.c +1 -1
@@ -247,7 +247,7 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,pthread_mutex_lock (&evsel->hists.lock); he =__hists__add_entry (&evsel->hists, al,NULL ,NULL ,NULL , sample->period, sample->weight, - sample->transaction); + sample->transaction, true);pthread_mutex_unlock (&evsel->hists.lock);if (he ==NULL )return NULL ;
tools/perf/tests/hists_link.c +2 -2
@@ -88,7 +88,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) goto out; he =__hists__add_entry (&evsel->hists, &al,NULL , -NULL ,NULL ,1 ,1 ,0 ); +NULL ,NULL ,1 ,1 ,0 , true);if (he ==NULL ) goto out;
@@ -112,7 +112,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) goto out; he =__hists__add_entry (&evsel->hists, &al,NULL , -NULL ,NULL ,1 ,1 ,0 ); +NULL ,NULL ,1 ,1 ,0 , true);if (he ==NULL ) goto out;
tools/perf/util/hist.c +18 -11
@@ -279,7 +279,8 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)* histogram, sorted on item, collects periods */ -static struct hist_entry *hist_entry__new (struct hist_entry *template) +static struct hist_entry *hist_entry__new (struct hist_entry *template, +bool sample_self) {size_t callchain_size =0 ;struct hist_entry *he;
@@ -299,6 +300,8 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)return NULL ; }memcpy (he->stat_acc, &he->stat,sizeof (he->stat)); +if (!sample_self) +memset (&he->stat,0 ,sizeof (he->stat)); }if (he->ms.map)
@@ -351,7 +354,8 @@ static u8 symbol__parent_filter(const struct symbol *parent)static struct hist_entry *add_hist_entry (struct hists *hists,struct hist_entry *entry, -struct addr_location *al) +struct addr_location *al, +bool sample_self) {struct rb_node **p;struct rb_node *parent =NULL ;
@@ -375,7 +379,8 @@ static struct hist_entry *add_hist_entry(struct hists *hists, cmp =hist_entry__cmp (he, entry);if (!cmp) { -he_stat__add_period (&he->stat, period, weight); +if (sample_self) +he_stat__add_period (&he->stat, period, weight);if (symbol_conf.cumulate_callchain)he_stat__add_period (he->stat_acc, period, weight);
@@ -405,14 +410,15 @@ static struct hist_entry *add_hist_entry(struct hists *hists, p = &(*p)->rb_right; } - he =hist_entry__new (entry); + he =hist_entry__new (entry, sample_self);if (!he)return NULL ;rb_link_node (&he->rb_node_in, parent, p);rb_insert_color (&he->rb_node_in, hists->entries_in); out: -he_stat__add_cpumode_period (&he->stat, al->cpumode, period); +if (sample_self) +he_stat__add_cpumode_period (&he->stat, al->cpumode, period);if (symbol_conf.cumulate_callchain)he_stat__add_cpumode_period (he->stat_acc, al->cpumode, period);return he;
@@ -423,7 +429,8 @@ struct hist_entry *__hists__add_entry(struct hists *hists, struct symbol *sym_parent, struct branch_info *bi, struct mem_info *mi, - u64 period, u64 weight, u64 transaction) + u64 period, u64 weight, u64 transaction, + bool sample_self) { struct hist_entry entry = { .thread = al->thread,
@@ -448,7 +455,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists, .transaction = transaction, }; -return add_hist_entry (hists, &entry, al); +return add_hist_entry (hists, &entry, al, sample_self); } static int
@@ -501,7 +508,7 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al* and the he_stat__add_period() function. */ he =__hists__add_entry (&iter->evsel->hists, al, iter->parent,NULL , mi, - cost, cost,0 ); + cost, cost,0 , true);if (!he)return -ENOMEM ;
@@ -608,7 +615,7 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a* and not events sampled. Thus we use a pseudo period of 1. */ he =__hists__add_entry (&evsel->hists, al, iter->parent, &bi[i],NULL , -1 ,1 ,0 ); +1 ,1 ,0 , true);if (he ==NULL )return -ENOMEM ;
@@ -657,7 +664,7 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location he =__hists__add_entry (&evsel->hists, al, iter->parent,NULL ,NULL , sample->period, sample->weight, - sample->transaction); + sample->transaction, true);if (he ==NULL )return -ENOMEM ;
@@ -1161,7 +1168,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists, p = &(*p)->rb_right; } - he =hist_entry__new (pair); + he =hist_entry__new (pair, true);if (he) {memset (&he->stat,0 ,sizeof (he->stat)); he->hists = hists;
tools/perf/util/hist.h +2 -1
@@ -130,7 +130,8 @@ struct hist_entry *__hists__add_entry(struct hists *hists,struct symbol *parent, struct branch_info *bi, struct mem_info *mi, u64 period, - u64 weight, u64 transaction); + u64 weight, u64 transaction, + bool sample_self);int hist_entry_iter__add (struct hist_entry_iter *iter,struct addr_location *al,struct perf_evsel *evsel,struct perf_sample *sample,int max_stack_depth);
Namhyung Kim
maintainerPATCH 5/27 perf hists: Accumulate hist entry stat based on the callchain
In reply to Namhyung KimCall __hists__add_entry() for each callchain node to get an accumulated stat for an entry. Introduce new cumulative_iter ops to process them properly.
--- tools/perf/builtin-report.c | 2 + tools/perf/util/callchain.c | 3 +- tools/perf/util/hist.c | 96 +++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/hist.h | 1 + 4 files changed, 101 insertions(+), 1 deletion(-)
tools/perf/builtin-report.c +2 -0
@@ -115,6 +115,8 @@ static int process_sample_event(struct perf_tool *tool, iter.ops = &hist_iter_branch; else if (rep->mem_mode) iter.ops = &hist_iter_mem; + else if (symbol_conf.cumulate_callchain) + iter.ops = &hist_iter_cumulative; else iter.ops = &hist_iter_normal;
tools/perf/util/callchain.c +2 -1
@@ -616,7 +616,8 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parentif (sample->callchain ==NULL )return 0 ; -if (symbol_conf.use_callchain || sort__has_parent) { +if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain || + sort__has_parent) {return machine__resolve_callchain (al->machine, evsel, al->thread, sample, parent, al, max_stack); }
tools/perf/util/hist.c +96 -0
108 lines not on this page · raw message
tools/perf/util/hist.h +1 -0
@@ -124,6 +124,7 @@ struct hist_entry_iter {extern const struct hist_iter_ops hist_iter_normal;extern const struct hist_iter_ops hist_iter_branch;extern const struct hist_iter_ops hist_iter_mem; +extern const struct hist_iter_ops hist_iter_cumulative; struct hist_entry *__hists__add_entry(struct hists *hists, struct addr_location *al,
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf hists: Accumulate hist entry stat based on the callchain
perf hists: Accumulate hist entry stat based on the callchain
Commit-ID: 7a13aa28aa268359cee006059731f49bcd1f839e Gitweb: http://git.kernel.org/tip/7a13aa28aa268359cee006059731f49bcd1f839e Author: Namhyung Kim <[email protected]> AuthorDate: Tue, 11 Sep 2012 14:13:04 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:34:57 +0200
perf hists: Accumulate hist entry stat based on the callchain
Call __hists__add_entry() for each callchain node to get an accumulated stat for an entry. Introduce new cumulative_iter ops to process them properly.
--- tools/perf/builtin-report.c | 2 + tools/perf/util/callchain.c | 3 +- tools/perf/util/hist.c | 96 +++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/hist.h | 1 + 4 files changed, 101 insertions(+), 1 deletion(-)
tools/perf/builtin-report.c +2 -0
@@ -115,6 +115,8 @@ static int process_sample_event(struct perf_tool *tool, iter.ops = &hist_iter_branch; else if (rep->mem_mode) iter.ops = &hist_iter_mem; + else if (symbol_conf.cumulate_callchain) + iter.ops = &hist_iter_cumulative; else iter.ops = &hist_iter_normal;
tools/perf/util/callchain.c +2 -1
@@ -616,7 +616,8 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parentif (sample->callchain ==NULL )return 0 ; -if (symbol_conf.use_callchain || sort__has_parent) { +if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain || + sort__has_parent) {return machine__resolve_callchain (al->machine, evsel, al->thread, sample, parent, al, max_stack); }
tools/perf/util/hist.c +96 -0
108 lines not on this page · raw message
tools/perf/util/hist.h +1 -0
@@ -124,6 +124,7 @@ struct hist_entry_iter {extern const struct hist_iter_ops hist_iter_normal;extern const struct hist_iter_ops hist_iter_branch;extern const struct hist_iter_ops hist_iter_mem; +extern const struct hist_iter_ops hist_iter_cumulative; struct hist_entry *__hists__add_entry(struct hists *hists, struct addr_location *al,
Namhyung Kim
maintainerPATCH 6/27 perf tools: Update cpumode for each cumulative entry
In reply to Namhyung KimThe cpumode and level in struct addr_localtion was set for a sample and but updated as cumulative callchains were added. This led to have non-matching symbol and cpumode in the output.
Update it accordingly based on the fact whether the map is a part of the kernel or not. This is a reverse of what thread__find_addr_map() does.
--- tools/perf/util/callchain.c | 42 ++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/callchain.h | 2 ++ tools/perf/util/hist.c | 13 ++----------- 3 files changed, 46 insertions(+), 11 deletions(-)
tools/perf/util/callchain.c +42 -0
@@ -630,3 +630,45 @@ int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sampreturn 0 ;return callchain_append (he->callchain, &callchain_cursor, sample->period); } + +int fill_callchain_info (struct addr_location *al,struct callchain_cursor_node *node, +bool hide_unresolved) +{ + al->map = node->map; + al->sym = node->sym; +if (node->map) + al->addr = node->map->map_ip (node->map, node->ip); +else + al->addr = node->ip; + +if (al->sym ==NULL ) { +if (hide_unresolved) +return 0 ; +if (al->map ==NULL ) + goto out; + } + +if (al->map->groups == &al->machine->kmaps) { +if (machine__is_host (al->machine)) { + al->cpumode =PERF_RECORD_MISC_KERNEL ; + al->level ='k' ; + }else { + al->cpumode =PERF_RECORD_MISC_GUEST_KERNEL ; + al->level ='g' ; + } + }else { +if (machine__is_host (al->machine)) { + al->cpumode =PERF_RECORD_MISC_USER ; + al->level ='.' ; + }else if (perf_guest) { + al->cpumode =PERF_RECORD_MISC_GUEST_USER ; + al->level ='u' ; + }else { + al->cpumode =PERF_RECORD_MISC_HYPERVISOR ; + al->level ='H' ; + } + } + +out: +return 1 ; +}
tools/perf/util/callchain.h +2 -0
@@ -162,6 +162,8 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent struct perf_evsel *evsel, struct addr_location *al, int max_stack);int hist_entry__append_callchain (struct hist_entry *he,struct perf_sample *sample); +int fill_callchain_info (struct addr_location *al,struct callchain_cursor_node *node, +bool hide_unresolved);extern const char record_callchain_help[];int parse_callchain_report_opt (const char *arg);
tools/perf/util/hist.c +2 -11
@@ -743,18 +743,9 @@ iter_next_cumulative_entry(struct hist_entry_iter *iter,if (node ==NULL )return 0 ; - al->map = node->map; - al->sym = node->sym; -if (node->map) - al->addr = node->map->map_ip (node->map, node->ip); -else - al->addr = node->ip; - -if (iter->hide_unresolved && al->sym ==NULL ) -return 0 ; -callchain_cursor_advance (&callchain_cursor); -return 1 ; + +return fill_callchain_info (al, node, iter->hide_unresolved); } static int
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf tools: Update cpumode for each cumulative entry
perf tools: Update cpumode for each cumulative entry
Commit-ID: c7405d85d7a354b8ba49e2db7c4b027e6cb997c1 Gitweb: http://git.kernel.org/tip/c7405d85d7a354b8ba49e2db7c4b027e6cb997c1 Author: Namhyung Kim <[email protected]> AuthorDate: Thu, 31 Oct 2013 13:58:30 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:34:58 +0200
perf tools: Update cpumode for each cumulative entry
The cpumode and level in struct addr_localtion was set for a sample and but updated as cumulative callchains were added. This led to have non-matching symbol and cpumode in the output.
Update it accordingly based on the fact whether the map is a part of the kernel or not. This is a reverse of what thread__find_addr_map() does.
--- tools/perf/util/callchain.c | 42 ++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/callchain.h | 2 ++ tools/perf/util/hist.c | 13 ++----------- 3 files changed, 46 insertions(+), 11 deletions(-)
tools/perf/util/callchain.c +42 -0
@@ -630,3 +630,45 @@ int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sampreturn 0 ;return callchain_append (he->callchain, &callchain_cursor, sample->period); } + +int fill_callchain_info (struct addr_location *al,struct callchain_cursor_node *node, +bool hide_unresolved) +{ + al->map = node->map; + al->sym = node->sym; +if (node->map) + al->addr = node->map->map_ip (node->map, node->ip); +else + al->addr = node->ip; + +if (al->sym ==NULL ) { +if (hide_unresolved) +return 0 ; +if (al->map ==NULL ) + goto out; + } + +if (al->map->groups == &al->machine->kmaps) { +if (machine__is_host (al->machine)) { + al->cpumode =PERF_RECORD_MISC_KERNEL ; + al->level ='k' ; + }else { + al->cpumode =PERF_RECORD_MISC_GUEST_KERNEL ; + al->level ='g' ; + } + }else { +if (machine__is_host (al->machine)) { + al->cpumode =PERF_RECORD_MISC_USER ; + al->level ='.' ; + }else if (perf_guest) { + al->cpumode =PERF_RECORD_MISC_GUEST_USER ; + al->level ='u' ; + }else { + al->cpumode =PERF_RECORD_MISC_HYPERVISOR ; + al->level ='H' ; + } + } + +out: +return 1 ; +}
tools/perf/util/callchain.h +2 -0
@@ -162,6 +162,8 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent struct perf_evsel *evsel, struct addr_location *al, int max_stack);int hist_entry__append_callchain (struct hist_entry *he,struct perf_sample *sample); +int fill_callchain_info (struct addr_location *al,struct callchain_cursor_node *node, +bool hide_unresolved);extern const char record_callchain_help[];int parse_callchain_report_opt (const char *arg);
tools/perf/util/hist.c +2 -11
@@ -743,18 +743,9 @@ iter_next_cumulative_entry(struct hist_entry_iter *iter,if (node ==NULL )return 0 ; - al->map = node->map; - al->sym = node->sym; -if (node->map) - al->addr = node->map->map_ip (node->map, node->ip); -else - al->addr = node->ip; - -if (iter->hide_unresolved && al->sym ==NULL ) -return 0 ; -callchain_cursor_advance (&callchain_cursor); -return 1 ; + +return fill_callchain_info (al, node, iter->hide_unresolved); } static int
Namhyung Kim
maintainerPATCH 7/27 perf report: Cache cumulative callchains
In reply to Namhyung KimIt is possble that a callchain has cycles or recursive calls. In that case it'll end up having entries more than 100% overhead in the output. In order to prevent such entries, cache each callchain node and skip if same entry already cumulated.
--- tools/perf/util/hist.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
tools/perf/util/hist.c +42 -0
@@ -700,7 +700,22 @@ static int iter_prepare_cumulative_entry(struct hist_entry_iter *iter __maybe_unused, struct addr_location *al __maybe_unused) { + struct hist_entry **he_cache; +callchain_cursor_commit (&callchain_cursor); + +/* +* This is for detecting cycles or recursions so that they're +* cumulated only one time to prevent entries more than 100% +* overhead. +*/ + he_cache =malloc (sizeof (*he_cache) * (PERF_MAX_STACK_DEPTH +1 )); +if (he_cache ==NULL ) +return -ENOMEM ; + + iter->priv = he_cache; + iter->curr =0 ; +return 0 ; }
@@ -710,6 +725,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter, {struct perf_evsel *evsel = iter->evsel;struct perf_sample *sample = iter->sample; +struct hist_entry **he_cache = iter->priv;struct hist_entry *he;int err =0 ;
@@ -720,6 +736,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter,return -ENOMEM ; iter->he = he; + he_cache[iter->curr++] = he;/* * The iter->he will be over-written after ->add_next_entry()
@@ -754,7 +771,29 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, {struct perf_evsel *evsel = iter->evsel;struct perf_sample *sample = iter->sample; +struct hist_entry **he_cache = iter->priv;struct hist_entry *he; +struct hist_entry he_tmp = { + .cpu = al->cpu, + .thread = al->thread, + .comm =thread__comm (al->thread), + .ip = al->addr, + .ms = { + .map = al->map, + .sym = al->sym, + }, + .parent = iter->parent, + }; +int i; + +/* +* Check if there's duplicate entries in the callchain. +* It's possible that it has cycles or recursive calls. +*/ +for (i =0 ; i < iter->curr; i++) { +if (hist_entry__cmp (he_cache[i], &he_tmp) ==0 ) +return 0 ; + } he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL, sample->period, sample->weight,
@@ -763,6 +802,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,return -ENOMEM ; iter->he = he; + he_cache[iter->curr++] = he;return 0 ; }
@@ -771,7 +811,9 @@ static int iter_finish_cumulative_entry(struct hist_entry_iter *iter, struct addr_location *al __maybe_unused) { + zfree(&iter->priv); iter->he =NULL ; +return 0 ; }
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf report: Cache cumulative callchains
perf report: Cache cumulative callchains
Commit-ID: b4d3c8bd86c4eda08456691121f83b4e1db46866 Gitweb: http://git.kernel.org/tip/b4d3c8bd86c4eda08456691121f83b4e1db46866 Author: Namhyung Kim <[email protected]> AuthorDate: Thu, 31 Oct 2013 10:05:29 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:34:58 +0200
perf report: Cache cumulative callchains
It is possble that a callchain has cycles or recursive calls. In that case it'll end up having entries more than 100% overhead in the output. In order to prevent such entries, cache each callchain node and skip if same entry already cumulated.
--- tools/perf/util/hist.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+)
tools/perf/util/hist.c +42 -0
@@ -700,7 +700,22 @@ static int iter_prepare_cumulative_entry(struct hist_entry_iter *iter __maybe_unused, struct addr_location *al __maybe_unused) { + struct hist_entry **he_cache; +callchain_cursor_commit (&callchain_cursor); + +/* +* This is for detecting cycles or recursions so that they're +* cumulated only one time to prevent entries more than 100% +* overhead. +*/ + he_cache =malloc (sizeof (*he_cache) * (PERF_MAX_STACK_DEPTH +1 )); +if (he_cache ==NULL ) +return -ENOMEM ; + + iter->priv = he_cache; + iter->curr =0 ; +return 0 ; }
@@ -710,6 +725,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter, {struct perf_evsel *evsel = iter->evsel;struct perf_sample *sample = iter->sample; +struct hist_entry **he_cache = iter->priv;struct hist_entry *he;int err =0 ;
@@ -720,6 +736,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter,return -ENOMEM ; iter->he = he; + he_cache[iter->curr++] = he;/* * The iter->he will be over-written after ->add_next_entry()
@@ -754,7 +771,29 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, {struct perf_evsel *evsel = iter->evsel;struct perf_sample *sample = iter->sample; +struct hist_entry **he_cache = iter->priv;struct hist_entry *he; +struct hist_entry he_tmp = { + .cpu = al->cpu, + .thread = al->thread, + .comm =thread__comm (al->thread), + .ip = al->addr, + .ms = { + .map = al->map, + .sym = al->sym, + }, + .parent = iter->parent, + }; +int i; + +/* +* Check if there's duplicate entries in the callchain. +* It's possible that it has cycles or recursive calls. +*/ +for (i =0 ; i < iter->curr; i++) { +if (hist_entry__cmp (he_cache[i], &he_tmp) ==0 ) +return 0 ; + } he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL, sample->period, sample->weight,
@@ -763,6 +802,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,return -ENOMEM ; iter->he = he; + he_cache[iter->curr++] = he;return 0 ; }
@@ -771,7 +811,9 @@ static int iter_finish_cumulative_entry(struct hist_entry_iter *iter, struct addr_location *al __maybe_unused) { + zfree(&iter->priv); iter->he =NULL ; +return 0 ; }
Namhyung Kim
maintainerPATCH 8/27 perf callchain: Add callchain_cursor_snapshot()
In reply to Namhyung KimThe callchain_cursor_snapshot() is for saving current status of the callchain. It'll be used to accumulate callchain information for each node.
--- tools/perf/util/callchain.h | 9 +++++++++ 1 file changed, 9 insertions(+)
tools/perf/util/callchain.h +9 -0
@@ -167,4 +167,13 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *extern const char record_callchain_help[];int parse_callchain_report_opt (const char *arg); + +static inline void callchain_cursor_snapshot (struct callchain_cursor *dest, +struct callchain_cursor *src) +{ + *dest = *src; + + dest->first = src->curr; + dest->nr -= src->pos; +}#endif /* __PERF_CALLCHAIN_H */
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf callchain: Add callchain_cursor_snapshot()
perf callchain: Add callchain_cursor_snapshot()
Commit-ID: be1f13e30862ab6b0fffaecd556856a965cefa0c Gitweb: http://git.kernel.org/tip/be1f13e30862ab6b0fffaecd556856a965cefa0c Author: Namhyung Kim <[email protected]> AuthorDate: Mon, 10 Sep 2012 13:38:00 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:34:59 +0200
perf callchain: Add callchain_cursor_snapshot()
The callchain_cursor_snapshot() is for saving current status of the callchain. It'll be used to accumulate callchain information for each node.
--- tools/perf/util/callchain.h | 9 +++++++++ 1 file changed, 9 insertions(+)
tools/perf/util/callchain.h +9 -0
@@ -167,4 +167,13 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *extern const char record_callchain_help[];int parse_callchain_report_opt (const char *arg); + +static inline void callchain_cursor_snapshot (struct callchain_cursor *dest, +struct callchain_cursor *src) +{ + *dest = *src; + + dest->first = src->curr; + dest->nr -= src->pos; +}#endif /* __PERF_CALLCHAIN_H */
Namhyung Kim
maintainerPATCH 9/27 perf tools: Save callchain info for each cumulative entry
In reply to Namhyung KimWhen accumulating callchain entry, also save current snapshot of the chain so that it can show the rest of the chain.
--- tools/perf/util/hist.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
tools/perf/util/hist.c +14 -2
@@ -738,6 +738,14 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter, iter->he = he; he_cache[iter->curr++] = he; +callchain_append (he->callchain, &callchain_cursor, sample->period); + +/* +* We need to re-initialize the cursor since callchain_append() +* advanced the cursor to the end. +*/ +callchain_cursor_commit (&callchain_cursor); +/* * The iter->he will be over-written after ->add_next_entry() * called so inc stats for the original entry now.
@@ -760,8 +768,6 @@ iter_next_cumulative_entry(struct hist_entry_iter *iter,if (node ==NULL )return 0 ; -callchain_cursor_advance (&callchain_cursor); -return fill_callchain_info (al, node, iter->hide_unresolved); }
@@ -785,6 +791,11 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, .parent = iter->parent, };int i; +struct callchain_cursor cursor; + +callchain_cursor_snapshot (&cursor, &callchain_cursor); + +callchain_cursor_advance (&callchain_cursor);/* * Check if there's duplicate entries in the callchain.
@@ -804,6 +815,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, iter->he = he; he_cache[iter->curr++] = he; +callchain_append (he->callchain, &cursor, sample->period);return 0 ; }
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf tools: Save callchain info for each cumulative entry
perf tools: Save callchain info for each cumulative entry
Commit-ID: be7f855a3eebe07f797b9e4a43bf59bab8ca3dbe Gitweb: http://git.kernel.org/tip/be7f855a3eebe07f797b9e4a43bf59bab8ca3dbe Author: Namhyung Kim <[email protected]> AuthorDate: Thu, 26 Dec 2013 17:44:10 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:00 +0200
perf tools: Save callchain info for each cumulative entry
When accumulating callchain entry, also save current snapshot of the chain so that it can show the rest of the chain.
--- tools/perf/util/hist.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
tools/perf/util/hist.c +14 -2
@@ -738,6 +738,14 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter, iter->he = he; he_cache[iter->curr++] = he; +callchain_append (he->callchain, &callchain_cursor, sample->period); + +/* +* We need to re-initialize the cursor since callchain_append() +* advanced the cursor to the end. +*/ +callchain_cursor_commit (&callchain_cursor); +/* * The iter->he will be over-written after ->add_next_entry() * called so inc stats for the original entry now.
@@ -760,8 +768,6 @@ iter_next_cumulative_entry(struct hist_entry_iter *iter,if (node ==NULL )return 0 ; -callchain_cursor_advance (&callchain_cursor); -return fill_callchain_info (al, node, iter->hide_unresolved); }
@@ -785,6 +791,11 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, .parent = iter->parent, };int i; +struct callchain_cursor cursor; + +callchain_cursor_snapshot (&cursor, &callchain_cursor); + +callchain_cursor_advance (&callchain_cursor);/* * Check if there's duplicate entries in the callchain.
@@ -804,6 +815,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, iter->he = he; he_cache[iter->curr++] = he; +callchain_append (he->callchain, &cursor, sample->period);return 0 ; }
Namhyung Kim
maintainerPATCH 10/27 perf ui/hist: Add support to accumulated hist stat
In reply to Namhyung KimPrint accumulated stat of a hist entry if requested.
To do that, add new HPP_PERCENT_ACC_FNS macro and generate a perf_hpp_fmt using it. The __hpp__sort_acc() function sorts entries by accumulated period value. When accumulated periods of two entries are same (i.e. single path callchain) put the caller above since accumulation tends to put callers on higher position for obvious reason.
Also add "overhead_children" output field to be selected by user.
--- tools/perf/ui/hist.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/hist.h | 4 ++ tools/perf/util/sort.c | 1 + 3 files changed, 104 insertions(+)
tools/perf/ui/hist.c +99 -0
@@ -104,6 +104,18 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,return ret; } +int __hpp__fmt_acc (struct perf_hpp *hpp,struct hist_entry *he, +hpp_field_fn get_field,const char *fmt, +hpp_snprint_fn print_fn,bool fmt_percent) +{ +if (!symbol_conf.cumulate_callchain) { +return snprintf (hpp->buf, hpp->size,"%*s" , + fmt_percent ?8 :12 ,"N/A" ); + } + +return __hpp__fmt (hpp, he, get_field, fmt, print_fn, fmt_percent); +} +static int field_cmp (u64 field_a,u64 field_b) {if (field_a > field_b)
@@ -160,6 +172,24 @@ out:return ret; } +static int __hpp__sort_acc (struct hist_entry *a,struct hist_entry *b, +hpp_field_fn get_field) +{ +s64 ret =0 ; + +if (symbol_conf.cumulate_callchain) { +/* +* Put caller above callee when they have equal period. +*/ + ret =field_cmp (get_field (a),get_field (b)); +if (ret) +return ret; + + ret = b->callchain->max_depth - a->callchain->max_depth; + } +return ret; +} +#define __HPP_HEADER_FN (_type, _str, _min_width, _unit_width) \ static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ struct perf_hpp *hpp, \
@@ -242,6 +272,34 @@ static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \ return __hpp__sort(a, b, he_get_##_field); \ } +#define __HPP_COLOR_ACC_PERCENT_FN (_type, _field) \ +static u64 he_get_acc_##_field(struct hist_entry *he) \ +{ \ + return he->stat_acc->_field; \ +} \ + \ +static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ + struct perf_hpp *hpp, struct hist_entry *he) \ +{ \ + return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%", \ + hpp_color_scnprintf, true); \ +} + +#define __HPP_ENTRY_ACC_PERCENT_FN (_type, _field) \ +static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ + struct perf_hpp *hpp, struct hist_entry *he) \ +{ \ + const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ + return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, fmt, \ + hpp_entry_scnprintf, true); \ +} + +#define __HPP_SORT_ACC_FN (_type, _field) \ +static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \ +{ \ + return __hpp__sort_acc(a, b, he_get_acc_##_field); \ +} +#define __HPP_ENTRY_RAW_FN (_type, _field) \ static u64 he_get_raw_##_field(struct hist_entry *he) \ { \
@@ -270,18 +328,27 @@ __HPP_COLOR_PERCENT_FN(_type, _field) \ __HPP_ENTRY_PERCENT_FN(_type, _field) \ __HPP_SORT_FN(_type, _field) +#define HPP_PERCENT_ACC_FNS (_type, _str, _field, _min_width, _unit_width)\ +__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ +__HPP_WIDTH_FN(_type, _min_width, _unit_width) \ +__HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ +__HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \ +__HPP_SORT_ACC_FN(_type, _field) +#define HPP_RAW_FNS (_type, _str, _field, _min_width, _unit_width) \ __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ __HPP_ENTRY_RAW_FN(_type, _field) \ __HPP_SORT_RAW_FN(_type, _field) +__HPP_HEADER_FN(overhead_self, "Self", 8, 8) HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8) HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8) HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8) HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8) HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) +HPP_PERCENT_ACC_FNS(overhead_acc, "Children", period, 8, 8) HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)HPP_RAW_FNS (period,"Period" , period,12 ,12 )
@@ -303,6 +370,17 @@ static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused, .sort = hpp__sort_ ## _name, \ } +#define HPP__COLOR_ACC_PRINT_FNS (_name) \ + { \ + .header = hpp__header_ ## _name, \ + .width = hpp__width_ ## _name, \ + .color = hpp__color_ ## _name, \ + .entry = hpp__entry_ ## _name, \ + .cmp = hpp__nop_cmp, \ + .collapse = hpp__nop_cmp, \ + .sort = hpp__sort_ ## _name, \ + } +#define HPP__PRINT_FNS (_name) \ { \ .header = hpp__header_ ## _name, \
@@ -319,6 +397,7 @@ struct perf_hpp_fmt perf_hpp__format[] = {HPP__COLOR_PRINT_FNS (overhead_us),HPP__COLOR_PRINT_FNS (overhead_guest_sys),HPP__COLOR_PRINT_FNS (overhead_guest_us), +HPP__COLOR_ACC_PRINT_FNS (overhead_acc),HPP__PRINT_FNS (samples), HPP__PRINT_FNS(period) };
@@ -328,16 +407,23 @@ LIST_HEAD(perf_hpp__sort_list);#undef HPP__COLOR_PRINT_FNS +#undef HPP__COLOR_ACC_PRINT_FNS#undef HPP__PRINT_FNS#undef HPP_PERCENT_FNS +#undef HPP_PERCENT_ACC_FNS#undef HPP_RAW_FNS#undef __HPP_HEADER_FN#undef __HPP_WIDTH_FN#undef __HPP_COLOR_PERCENT_FN#undef __HPP_ENTRY_PERCENT_FN +#undef __HPP_COLOR_ACC_PERCENT_FN +#undef __HPP_ENTRY_ACC_PERCENT_FN#undef __HPP_ENTRY_RAW_FN +#undef __HPP_SORT_FN +#undef __HPP_SORT_ACC_FN +#undef __HPP_SORT_RAW_FNvoid perf_hpp__init (void )
@@ -361,6 +447,13 @@ void perf_hpp__init(void)if (field_order)return ; +if (symbol_conf.cumulate_callchain) { +perf_hpp__column_enable (PERF_HPP__OVERHEAD_ACC ); + + perf_hpp__format[PERF_HPP__OVERHEAD ].header = + hpp__header_overhead_self; + } +perf_hpp__column_enable (PERF_HPP__OVERHEAD );if (symbol_conf.show_cpu_utilization) {
@@ -383,6 +476,12 @@ void perf_hpp__init(void) list = &perf_hpp__format[PERF_HPP__OVERHEAD ].sort_list;if (list_empty (list))list_add (list, &perf_hpp__sort_list); + +if (symbol_conf.cumulate_callchain) { + list = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC ].sort_list; +if (list_empty (list)) +list_add (list, &perf_hpp__sort_list); + } }void perf_hpp__column_register (struct perf_hpp_fmt *format)
tools/perf/util/hist.h +4 -0
@@ -228,6 +228,7 @@ enum {PERF_HPP__OVERHEAD_US ,PERF_HPP__OVERHEAD_GUEST_SYS ,PERF_HPP__OVERHEAD_GUEST_US , +PERF_HPP__OVERHEAD_ACC ,PERF_HPP__SAMPLES , PERF_HPP__PERIOD,
@@ -254,6 +255,9 @@ typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);int __hpp__fmt (struct perf_hpp *hpp,struct hist_entry *he,hpp_field_fn get_field,const char *fmt,hpp_snprint_fn print_fn,bool fmt_percent); +int __hpp__fmt_acc (struct perf_hpp *hpp,struct hist_entry *he, +hpp_field_fn get_field,const char *fmt, +hpp_snprint_fn print_fn,bool fmt_percent);static inline void advance_hpp (struct perf_hpp *hpp,int inc) {
tools/perf/util/sort.c +1 -0
@@ -1061,6 +1061,7 @@ static struct hpp_dimension hpp_sort_dimensions[] = {DIM (PERF_HPP__OVERHEAD_US ,"overhead_us" ),DIM (PERF_HPP__OVERHEAD_GUEST_SYS ,"overhead_guest_sys" ),DIM (PERF_HPP__OVERHEAD_GUEST_US ,"overhead_guest_us" ), +DIM (PERF_HPP__OVERHEAD_ACC ,"overhead_children" ),DIM (PERF_HPP__SAMPLES ,"sample" ), DIM(PERF_HPP__PERIOD, "period"), };
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf ui/hist: Add support to accumulated hist stat
perf ui/hist: Add support to accumulated hist stat
Commit-ID: 594dcbf3186e2e1e5c08fa21e8826b90d347f23f Gitweb: http://git.kernel.org/tip/594dcbf3186e2e1e5c08fa21e8826b90d347f23f Author: Namhyung Kim <[email protected]> AuthorDate: Wed, 30 Oct 2013 16:06:59 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:00 +0200
perf ui/hist: Add support to accumulated hist stat
Print accumulated stat of a hist entry if requested.
To do that, add new HPP_PERCENT_ACC_FNS macro and generate a perf_hpp_fmt using it. The __hpp__sort_acc() function sorts entries by accumulated period value. When accumulated periods of two entries are same (i.e. single path callchain) put the caller above since accumulation tends to put callers on higher position for obvious reason.
Also add "overhead_children" output field to be selected by user.
--- tools/perf/ui/hist.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/hist.h | 4 ++ tools/perf/util/sort.c | 1 + 3 files changed, 104 insertions(+)
tools/perf/ui/hist.c +99 -0
@@ -104,6 +104,18 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,return ret; } +int __hpp__fmt_acc (struct perf_hpp *hpp,struct hist_entry *he, +hpp_field_fn get_field,const char *fmt, +hpp_snprint_fn print_fn,bool fmt_percent) +{ +if (!symbol_conf.cumulate_callchain) { +return snprintf (hpp->buf, hpp->size,"%*s" , + fmt_percent ?8 :12 ,"N/A" ); + } + +return __hpp__fmt (hpp, he, get_field, fmt, print_fn, fmt_percent); +} +static int field_cmp (u64 field_a,u64 field_b) {if (field_a > field_b)
@@ -160,6 +172,24 @@ out:return ret; } +static int __hpp__sort_acc (struct hist_entry *a,struct hist_entry *b, +hpp_field_fn get_field) +{ +s64 ret =0 ; + +if (symbol_conf.cumulate_callchain) { +/* +* Put caller above callee when they have equal period. +*/ + ret =field_cmp (get_field (a),get_field (b)); +if (ret) +return ret; + + ret = b->callchain->max_depth - a->callchain->max_depth; + } +return ret; +} +#define __HPP_HEADER_FN (_type, _str, _min_width, _unit_width) \ static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ struct perf_hpp *hpp, \
@@ -242,6 +272,34 @@ static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \ return __hpp__sort(a, b, he_get_##_field); \ } +#define __HPP_COLOR_ACC_PERCENT_FN (_type, _field) \ +static u64 he_get_acc_##_field(struct hist_entry *he) \ +{ \ + return he->stat_acc->_field; \ +} \ + \ +static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ + struct perf_hpp *hpp, struct hist_entry *he) \ +{ \ + return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%", \ + hpp_color_scnprintf, true); \ +} + +#define __HPP_ENTRY_ACC_PERCENT_FN (_type, _field) \ +static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ + struct perf_hpp *hpp, struct hist_entry *he) \ +{ \ + const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ + return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, fmt, \ + hpp_entry_scnprintf, true); \ +} + +#define __HPP_SORT_ACC_FN (_type, _field) \ +static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \ +{ \ + return __hpp__sort_acc(a, b, he_get_acc_##_field); \ +} +#define __HPP_ENTRY_RAW_FN (_type, _field) \ static u64 he_get_raw_##_field(struct hist_entry *he) \ { \
@@ -270,18 +328,27 @@ __HPP_COLOR_PERCENT_FN(_type, _field) \ __HPP_ENTRY_PERCENT_FN(_type, _field) \ __HPP_SORT_FN(_type, _field) +#define HPP_PERCENT_ACC_FNS (_type, _str, _field, _min_width, _unit_width)\ +__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ +__HPP_WIDTH_FN(_type, _min_width, _unit_width) \ +__HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ +__HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \ +__HPP_SORT_ACC_FN(_type, _field) +#define HPP_RAW_FNS (_type, _str, _field, _min_width, _unit_width) \ __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ __HPP_ENTRY_RAW_FN(_type, _field) \ __HPP_SORT_RAW_FN(_type, _field) +__HPP_HEADER_FN(overhead_self, "Self", 8, 8) HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8) HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8) HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8) HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8) HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) +HPP_PERCENT_ACC_FNS(overhead_acc, "Children", period, 8, 8) HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)HPP_RAW_FNS (period,"Period" , period,12 ,12 )
@@ -303,6 +370,17 @@ static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused, .sort = hpp__sort_ ## _name, \ } +#define HPP__COLOR_ACC_PRINT_FNS (_name) \ + { \ + .header = hpp__header_ ## _name, \ + .width = hpp__width_ ## _name, \ + .color = hpp__color_ ## _name, \ + .entry = hpp__entry_ ## _name, \ + .cmp = hpp__nop_cmp, \ + .collapse = hpp__nop_cmp, \ + .sort = hpp__sort_ ## _name, \ + } +#define HPP__PRINT_FNS (_name) \ { \ .header = hpp__header_ ## _name, \
@@ -319,6 +397,7 @@ struct perf_hpp_fmt perf_hpp__format[] = {HPP__COLOR_PRINT_FNS (overhead_us),HPP__COLOR_PRINT_FNS (overhead_guest_sys),HPP__COLOR_PRINT_FNS (overhead_guest_us), +HPP__COLOR_ACC_PRINT_FNS (overhead_acc),HPP__PRINT_FNS (samples), HPP__PRINT_FNS(period) };
@@ -328,16 +407,23 @@ LIST_HEAD(perf_hpp__sort_list);#undef HPP__COLOR_PRINT_FNS +#undef HPP__COLOR_ACC_PRINT_FNS#undef HPP__PRINT_FNS#undef HPP_PERCENT_FNS +#undef HPP_PERCENT_ACC_FNS#undef HPP_RAW_FNS#undef __HPP_HEADER_FN#undef __HPP_WIDTH_FN#undef __HPP_COLOR_PERCENT_FN#undef __HPP_ENTRY_PERCENT_FN +#undef __HPP_COLOR_ACC_PERCENT_FN +#undef __HPP_ENTRY_ACC_PERCENT_FN#undef __HPP_ENTRY_RAW_FN +#undef __HPP_SORT_FN +#undef __HPP_SORT_ACC_FN +#undef __HPP_SORT_RAW_FNvoid perf_hpp__init (void )
@@ -361,6 +447,13 @@ void perf_hpp__init(void)if (field_order)return ; +if (symbol_conf.cumulate_callchain) { +perf_hpp__column_enable (PERF_HPP__OVERHEAD_ACC ); + + perf_hpp__format[PERF_HPP__OVERHEAD ].header = + hpp__header_overhead_self; + } +perf_hpp__column_enable (PERF_HPP__OVERHEAD );if (symbol_conf.show_cpu_utilization) {
@@ -383,6 +476,12 @@ void perf_hpp__init(void) list = &perf_hpp__format[PERF_HPP__OVERHEAD ].sort_list;if (list_empty (list))list_add (list, &perf_hpp__sort_list); + +if (symbol_conf.cumulate_callchain) { + list = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC ].sort_list; +if (list_empty (list)) +list_add (list, &perf_hpp__sort_list); + } }void perf_hpp__column_register (struct perf_hpp_fmt *format)
tools/perf/util/hist.h +4 -0
@@ -228,6 +228,7 @@ enum {PERF_HPP__OVERHEAD_US ,PERF_HPP__OVERHEAD_GUEST_SYS ,PERF_HPP__OVERHEAD_GUEST_US , +PERF_HPP__OVERHEAD_ACC ,PERF_HPP__SAMPLES , PERF_HPP__PERIOD,
@@ -254,6 +255,9 @@ typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);int __hpp__fmt (struct perf_hpp *hpp,struct hist_entry *he,hpp_field_fn get_field,const char *fmt,hpp_snprint_fn print_fn,bool fmt_percent); +int __hpp__fmt_acc (struct perf_hpp *hpp,struct hist_entry *he, +hpp_field_fn get_field,const char *fmt, +hpp_snprint_fn print_fn,bool fmt_percent);static inline void advance_hpp (struct perf_hpp *hpp,int inc) {
tools/perf/util/sort.c +1 -0
@@ -1061,6 +1061,7 @@ static struct hpp_dimension hpp_sort_dimensions[] = {DIM (PERF_HPP__OVERHEAD_US ,"overhead_us" ),DIM (PERF_HPP__OVERHEAD_GUEST_SYS ,"overhead_guest_sys" ),DIM (PERF_HPP__OVERHEAD_GUEST_US ,"overhead_guest_us" ), +DIM (PERF_HPP__OVERHEAD_ACC ,"overhead_children" ),DIM (PERF_HPP__SAMPLES ,"sample" ), DIM(PERF_HPP__PERIOD, "period"), };
Namhyung Kim
maintainerPATCH 11/27 perf ui/browser: Add support to accumulated hist stat
In reply to Namhyung KimPrint accumulated stat of a hist entry if requested.
--- tools/perf/ui/browsers/hists.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
tools/perf/ui/browsers/hists.c +25 -0
@@ -651,13 +651,36 @@ hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ __hpp__slsmg_color_printf, true); \ } +#define __HPP_COLOR_ACC_PERCENT_FN (_type, _field) \ +static u64 __hpp_get_acc_##_field(struct hist_entry *he) \ +{ \ + return he->stat_acc->_field; \ +} \ + \ +static int \ +hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ + struct perf_hpp *hpp, \ + struct hist_entry *he) \ +{ \ + if (!symbol_conf.cumulate_callchain) { \ + int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \ + slsmg_printf("%s", hpp->buf); \ + \ + return ret; \ + } \ + return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%", \ + __hpp__slsmg_color_printf, true); \ +} + __HPP_COLOR_PERCENT_FN(overhead, period) __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) __HPP_COLOR_PERCENT_FN(overhead_us, period_us) __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) +__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)#undef __HPP_COLOR_PERCENT_FN +#undef __HPP_COLOR_ACC_PERCENT_FNvoid hist_browser__init_hpp (void ) {
@@ -671,6 +694,8 @@ void hist_browser__init_hpp(void) hist_browser__hpp_color_overhead_guest_sys; perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US ].color = hist_browser__hpp_color_overhead_guest_us; + perf_hpp__format[PERF_HPP__OVERHEAD_ACC ].color = + hist_browser__hpp_color_overhead_acc; } static int hist_browser__show_entry(struct hist_browser *browser,
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf ui/browser: Add support to accumulated hist stat
perf ui/browser: Add support to accumulated hist stat
Commit-ID: 0434ddd21466a61cfc539ffc3a4cb3bdc67d82ec Gitweb: http://git.kernel.org/tip/0434ddd21466a61cfc539ffc3a4cb3bdc67d82ec Author: Namhyung Kim <[email protected]> AuthorDate: Wed, 30 Oct 2013 16:12:59 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:01 +0200
perf ui/browser: Add support to accumulated hist stat
Print accumulated stat of a hist entry if requested.
--- tools/perf/ui/browsers/hists.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
tools/perf/ui/browsers/hists.c +25 -0
@@ -651,13 +651,36 @@ hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ __hpp__slsmg_color_printf, true); \ } +#define __HPP_COLOR_ACC_PERCENT_FN (_type, _field) \ +static u64 __hpp_get_acc_##_field(struct hist_entry *he) \ +{ \ + return he->stat_acc->_field; \ +} \ + \ +static int \ +hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ + struct perf_hpp *hpp, \ + struct hist_entry *he) \ +{ \ + if (!symbol_conf.cumulate_callchain) { \ + int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \ + slsmg_printf("%s", hpp->buf); \ + \ + return ret; \ + } \ + return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%", \ + __hpp__slsmg_color_printf, true); \ +} + __HPP_COLOR_PERCENT_FN(overhead, period) __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) __HPP_COLOR_PERCENT_FN(overhead_us, period_us) __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) +__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)#undef __HPP_COLOR_PERCENT_FN +#undef __HPP_COLOR_ACC_PERCENT_FNvoid hist_browser__init_hpp (void ) {
@@ -671,6 +694,8 @@ void hist_browser__init_hpp(void) hist_browser__hpp_color_overhead_guest_sys; perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US ].color = hist_browser__hpp_color_overhead_guest_us; + perf_hpp__format[PERF_HPP__OVERHEAD_ACC ].color = + hist_browser__hpp_color_overhead_acc; } static int hist_browser__show_entry(struct hist_browser *browser,
Namhyung Kim
maintainerPATCH 12/27 perf ui/gtk: Add support to accumulated hist stat
In reply to Namhyung KimPrint accumulated stat of a hist entry if requested.
--- tools/perf/ui/gtk/hists.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
tools/perf/ui/gtk/hists.c +17 -0
@@ -47,11 +47,26 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, __percent_color_snprintf, true); \ } +#define __HPP_COLOR_ACC_PERCENT_FN (_type, _field) \ +static u64 he_get_acc_##_field(struct hist_entry *he) \ +{ \ + return he->stat_acc->_field; \ +} \ + \ +static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ + struct perf_hpp *hpp, \ + struct hist_entry *he) \ +{ \ + return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%", \ + __percent_color_snprintf, true); \ +} + __HPP_COLOR_PERCENT_FN(overhead, period) __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) __HPP_COLOR_PERCENT_FN(overhead_us, period_us) __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) +__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)#undef __HPP_COLOR_PERCENT_FN
@@ -68,6 +83,8 @@ void perf_gtk__init_hpp(void) perf_gtk__hpp_color_overhead_guest_sys; perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US ].color = perf_gtk__hpp_color_overhead_guest_us; + perf_hpp__format[PERF_HPP__OVERHEAD_ACC ].color = + perf_gtk__hpp_color_overhead_acc; } static void callchain_list__sym_name(struct callchain_list *cl,
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf ui/gtk: Add support to accumulated hist stat
perf ui/gtk: Add support to accumulated hist stat
Commit-ID: b09955b2a3d5fd02ed31d279f8c0ac29b32abe83 Gitweb: http://git.kernel.org/tip/b09955b2a3d5fd02ed31d279f8c0ac29b32abe83 Author: Namhyung Kim <[email protected]> AuthorDate: Wed, 30 Oct 2013 16:15:23 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:02 +0200
perf ui/gtk: Add support to accumulated hist stat
Print accumulated stat of a hist entry if requested.
--- tools/perf/ui/gtk/hists.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
tools/perf/ui/gtk/hists.c +17 -0
@@ -47,11 +47,26 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, __percent_color_snprintf, true); \ } +#define __HPP_COLOR_ACC_PERCENT_FN (_type, _field) \ +static u64 he_get_acc_##_field(struct hist_entry *he) \ +{ \ + return he->stat_acc->_field; \ +} \ + \ +static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ + struct perf_hpp *hpp, \ + struct hist_entry *he) \ +{ \ + return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%", \ + __percent_color_snprintf, true); \ +} + __HPP_COLOR_PERCENT_FN(overhead, period) __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) __HPP_COLOR_PERCENT_FN(overhead_us, period_us) __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) +__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)#undef __HPP_COLOR_PERCENT_FN
@@ -68,6 +83,8 @@ void perf_gtk__init_hpp(void) perf_gtk__hpp_color_overhead_guest_sys; perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US ].color = perf_gtk__hpp_color_overhead_guest_us; + perf_hpp__format[PERF_HPP__OVERHEAD_ACC ].color = + perf_gtk__hpp_color_overhead_acc; } static void callchain_list__sym_name(struct callchain_list *cl,
Namhyung Kim
maintainerPATCH 13/27 perf tools: Apply percent-limit to cumulative percentage
In reply to Namhyung KimIf -g cumulative option is given, it needs to show entries which don't have self overhead. So apply percent-limit to accumulated overhead percentage in this case.
--- tools/perf/ui/browsers/hists.c | 40 +++++++++++----------------------------- tools/perf/ui/gtk/hists.c | 6 ++---- tools/perf/ui/stdio/hist.c | 4 ++-- tools/perf/util/sort.h | 17 ++++++++++++++++- 4 files changed, 31 insertions(+), 36 deletions(-)
tools/perf/ui/browsers/hists.c +11 -29
@@ -37,7 +37,6 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,static void hist_browser__update_nr_entries (struct hist_browser *hb);static struct rb_node *hists__filter_entries (struct rb_node *nd, -struct hists *hists,float min_pcnt);static bool hist_browser__has_filter (struct hist_browser *hb)
@@ -319,7 +318,7 @@ __hist_browser__set_folding(struct hist_browser *browser, bool unfold)struct hists *hists = browser->hists;for (nd =rb_first (&hists->entries); - (nd =hists__filter_entries (nd, hists, browser->min_pcnt)) !=NULL ; + (nd =hists__filter_entries (nd, browser->min_pcnt)) !=NULL ; nd =rb_next (nd)) { struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);hist_entry__set_folding (he, unfold);
@@ -808,15 +807,12 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)for (nd = browser->top; nd; nd =rb_next (nd)) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); -u64 total =hists__total_period (h->hists); -float percent =0.0 ; +float percent;if (h->filtered)continue ; -if (total) - percent = h->stat.period *100.0 / total; - + percent =hist_entry__get_percent_limit (h);if (percent < hb->min_pcnt)continue ;
@@ -829,16 +825,11 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser) }static struct rb_node *hists__filter_entries (struct rb_node *nd, -struct hists *hists,float min_pcnt) {while (nd !=NULL ) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); -u64 total =hists__total_period (hists); -float percent =0.0 ; - -if (total) - percent = h->stat.period *100.0 / total; +float percent =hist_entry__get_percent_limit (h);if (!h->filtered && percent >= min_pcnt)return nd;
@@ -850,16 +841,11 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd, }static struct rb_node *hists__filter_prev_entries (struct rb_node *nd, -struct hists *hists,float min_pcnt) {while (nd !=NULL ) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); -u64 total =hists__total_period (hists); -float percent =0.0 ; - -if (total) - percent = h->stat.period *100.0 / total; +float percent =hist_entry__get_percent_limit (h);if (!h->filtered && percent >= min_pcnt)return nd;
@@ -888,14 +874,14 @@ static void ui_browser__hists_seek(struct ui_browser *browser,switch (whence) {case SEEK_SET : nd =hists__filter_entries (rb_first (browser->entries), - hb->hists, hb->min_pcnt); + hb->min_pcnt);break ;case SEEK_CUR : nd = browser->top; goto do_offset;case SEEK_END : nd =hists__filter_prev_entries (rb_last (browser->entries), - hb->hists, hb->min_pcnt); + hb->min_pcnt); first = false;break ;default :
@@ -938,8 +924,7 @@ do_offset:break ; } } - nd =hists__filter_entries (rb_next (nd), hb->hists, - hb->min_pcnt); + nd =hists__filter_entries (rb_next (nd), hb->min_pcnt);if (nd ==NULL )break ; --offset;
@@ -972,7 +957,7 @@ do_offset: } } - nd =hists__filter_prev_entries (rb_prev (nd), hb->hists, + nd =hists__filter_prev_entries (rb_prev (nd), hb->min_pcnt);if (nd ==NULL )break ;
@@ -1151,7 +1136,6 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,static int hist_browser__fprintf (struct hist_browser *browser,FILE *fp) {struct rb_node *nd =hists__filter_entries (rb_first (browser->b.entries), - browser->hists, browser->min_pcnt);int printed =0 ;
@@ -1159,8 +1143,7 @@ static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); printed +=hist_browser__fprintf_entry (browser, h, fp); - nd =hists__filter_entries (rb_next (nd), browser->hists, - browser->min_pcnt); + nd =hists__filter_entries (rb_next (nd), browser->min_pcnt); }return printed;
@@ -1397,8 +1380,7 @@ static void hist_browser__update_nr_entries(struct hist_browser *hb)return ; } -while ((nd =hists__filter_entries (nd, hb->hists, - hb->min_pcnt)) !=NULL ) { +while ((nd =hists__filter_entries (nd, hb->min_pcnt)) !=NULL ) { nr_entries++; nd =rb_next (nd); }
tools/perf/ui/gtk/hists.c +2 -4
@@ -226,14 +226,12 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);GtkTreeIter iter;u64 total =hists__total_period (h->hists); -float percent =0.0 ; +float percent;if (h->filtered)continue ; -if (total) - percent = h->stat.period *100.0 / total; - + percent =hist_entry__get_percent_limit (h);if (percent < min_pcnt)continue ;
tools/perf/ui/stdio/hist.c +2 -2
@@ -461,12 +461,12 @@ print_entries:for (nd =rb_first (&hists->entries); nd; nd =rb_next (nd)) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); -float percent = h->stat.period *100.0 / - hists->stats.total_period; +float percent;if (h->filtered)continue ; + percent =hist_entry__get_percent_limit (h);if (percent < min_pcnt)continue ;
tools/perf/util/sort.h +16 -1
@@ -20,7 +20,7 @@#include "parse-options.h" #include "parse-events.h" - +#include "hist.h" #include "thread.h" extern regex_t parent_regex;
@@ -131,6 +131,21 @@ static inline void hist_entry__add_pair(struct hist_entry *pair,list_add_tail (&pair->pairs.node, &he->pairs.head); } +static inline float hist_entry__get_percent_limit (struct hist_entry *he) +{ +u64 period = he->stat.period; +u64 total_period =hists__total_period (he->hists); + +if (unlikely (total_period ==0 )) +return 0 ; + +if (symbol_conf.cumulate_callchain) + period = he->stat_acc->period; + +return period *100.0 / total_period; +} + +enum sort_mode {SORT_MODE__NORMAL ,SORT_MODE__BRANCH ,
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf tools: Apply percent-limit to cumulative percentage
perf tools: Apply percent-limit to cumulative percentage
Commit-ID: 14135663f1d770bb057f8bf345e5436c985eb29c Gitweb: http://git.kernel.org/tip/14135663f1d770bb057f8bf345e5436c985eb29c Author: Namhyung Kim <[email protected]> AuthorDate: Thu, 31 Oct 2013 10:17:39 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:02 +0200
perf tools: Apply percent-limit to cumulative percentage
If -g cumulative option is given, it needs to show entries which don't have self overhead. So apply percent-limit to accumulated overhead percentage in this case.
--- tools/perf/ui/browsers/hists.c | 40 +++++++++++----------------------------- tools/perf/ui/gtk/hists.c | 6 ++---- tools/perf/ui/stdio/hist.c | 4 ++-- tools/perf/util/sort.h | 17 ++++++++++++++++- 4 files changed, 31 insertions(+), 36 deletions(-)
tools/perf/ui/browsers/hists.c +11 -29
@@ -37,7 +37,6 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,static void hist_browser__update_nr_entries (struct hist_browser *hb);static struct rb_node *hists__filter_entries (struct rb_node *nd, -struct hists *hists,float min_pcnt);static bool hist_browser__has_filter (struct hist_browser *hb)
@@ -319,7 +318,7 @@ __hist_browser__set_folding(struct hist_browser *browser, bool unfold)struct hists *hists = browser->hists;for (nd =rb_first (&hists->entries); - (nd =hists__filter_entries (nd, hists, browser->min_pcnt)) !=NULL ; + (nd =hists__filter_entries (nd, browser->min_pcnt)) !=NULL ; nd =rb_next (nd)) { struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);hist_entry__set_folding (he, unfold);
@@ -808,15 +807,12 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)for (nd = browser->top; nd; nd =rb_next (nd)) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); -u64 total =hists__total_period (h->hists); -float percent =0.0 ; +float percent;if (h->filtered)continue ; -if (total) - percent = h->stat.period *100.0 / total; - + percent =hist_entry__get_percent_limit (h);if (percent < hb->min_pcnt)continue ;
@@ -829,16 +825,11 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser) }static struct rb_node *hists__filter_entries (struct rb_node *nd, -struct hists *hists,float min_pcnt) {while (nd !=NULL ) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); -u64 total =hists__total_period (hists); -float percent =0.0 ; - -if (total) - percent = h->stat.period *100.0 / total; +float percent =hist_entry__get_percent_limit (h);if (!h->filtered && percent >= min_pcnt)return nd;
@@ -850,16 +841,11 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd, }static struct rb_node *hists__filter_prev_entries (struct rb_node *nd, -struct hists *hists,float min_pcnt) {while (nd !=NULL ) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); -u64 total =hists__total_period (hists); -float percent =0.0 ; - -if (total) - percent = h->stat.period *100.0 / total; +float percent =hist_entry__get_percent_limit (h);if (!h->filtered && percent >= min_pcnt)return nd;
@@ -888,14 +874,14 @@ static void ui_browser__hists_seek(struct ui_browser *browser,switch (whence) {case SEEK_SET : nd =hists__filter_entries (rb_first (browser->entries), - hb->hists, hb->min_pcnt); + hb->min_pcnt);break ;case SEEK_CUR : nd = browser->top; goto do_offset;case SEEK_END : nd =hists__filter_prev_entries (rb_last (browser->entries), - hb->hists, hb->min_pcnt); + hb->min_pcnt); first = false;break ;default :
@@ -938,8 +924,7 @@ do_offset:break ; } } - nd =hists__filter_entries (rb_next (nd), hb->hists, - hb->min_pcnt); + nd =hists__filter_entries (rb_next (nd), hb->min_pcnt);if (nd ==NULL )break ; --offset;
@@ -972,7 +957,7 @@ do_offset: } } - nd =hists__filter_prev_entries (rb_prev (nd), hb->hists, + nd =hists__filter_prev_entries (rb_prev (nd), hb->min_pcnt);if (nd ==NULL )break ;
@@ -1151,7 +1136,6 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,static int hist_browser__fprintf (struct hist_browser *browser,FILE *fp) {struct rb_node *nd =hists__filter_entries (rb_first (browser->b.entries), - browser->hists, browser->min_pcnt);int printed =0 ;
@@ -1159,8 +1143,7 @@ static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); printed +=hist_browser__fprintf_entry (browser, h, fp); - nd =hists__filter_entries (rb_next (nd), browser->hists, - browser->min_pcnt); + nd =hists__filter_entries (rb_next (nd), browser->min_pcnt); }return printed;
@@ -1397,8 +1380,7 @@ static void hist_browser__update_nr_entries(struct hist_browser *hb)return ; } -while ((nd =hists__filter_entries (nd, hb->hists, - hb->min_pcnt)) !=NULL ) { +while ((nd =hists__filter_entries (nd, hb->min_pcnt)) !=NULL ) { nr_entries++; nd =rb_next (nd); }
tools/perf/ui/gtk/hists.c +2 -4
@@ -226,14 +226,12 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);GtkTreeIter iter;u64 total =hists__total_period (h->hists); -float percent =0.0 ; +float percent;if (h->filtered)continue ; -if (total) - percent = h->stat.period *100.0 / total; - + percent =hist_entry__get_percent_limit (h);if (percent < min_pcnt)continue ;
tools/perf/ui/stdio/hist.c +2 -2
@@ -461,12 +461,12 @@ print_entries:for (nd =rb_first (&hists->entries); nd; nd =rb_next (nd)) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); -float percent = h->stat.period *100.0 / - hists->stats.total_period; +float percent;if (h->filtered)continue ; + percent =hist_entry__get_percent_limit (h);if (percent < min_pcnt)continue ;
tools/perf/util/sort.h +16 -1
@@ -20,7 +20,7 @@#include "parse-options.h" #include "parse-events.h" - +#include "hist.h" #include "thread.h" extern regex_t parent_regex;
@@ -131,6 +131,21 @@ static inline void hist_entry__add_pair(struct hist_entry *pair,list_add_tail (&pair->pairs.node, &he->pairs.head); } +static inline float hist_entry__get_percent_limit (struct hist_entry *he) +{ +u64 period = he->stat.period; +u64 total_period =hists__total_period (he->hists); + +if (unlikely (total_period ==0 )) +return 0 ; + +if (symbol_conf.cumulate_callchain) + period = he->stat_acc->period; + +return period *100.0 / total_period; +} + +enum sort_mode {SORT_MODE__NORMAL ,SORT_MODE__BRANCH ,
Namhyung Kim
maintainerPATCH 14/27 perf tools: Add more hpp helper functions
In reply to Namhyung KimSometimes it needs to disable some columns at runtime. Add help functions to support that.
--- tools/perf/ui/hist.c | 17 +++++++++++++++++ tools/perf/util/hist.h | 4 ++++ 2 files changed, 21 insertions(+)
tools/perf/ui/hist.c +17 -0
@@ -489,6 +489,11 @@ void perf_hpp__column_register(struct perf_hpp_fmt *format)list_add_tail (&format->list, &perf_hpp__list); } +void perf_hpp__column_unregister (struct perf_hpp_fmt *format) +{ +list_del (&format->list); +} +void perf_hpp__register_sort_field (struct perf_hpp_fmt *format) {list_add_tail (&format->sort_list, &perf_hpp__sort_list);
@@ -500,6 +505,18 @@ void perf_hpp__column_enable(unsigned col)perf_hpp__column_register (&perf_hpp__format[col]); } +void perf_hpp__column_disable (unsigned col) +{ +BUG_ON (col >=PERF_HPP__MAX_INDEX ); +perf_hpp__column_unregister (&perf_hpp__format[col]); +} + +void perf_hpp__cancel_cumulate (void ) +{ +perf_hpp__column_disable (PERF_HPP__OVERHEAD_ACC ); + perf_hpp__format[PERF_HPP__OVERHEAD ].header = hpp__header_overhead; +} +void perf_hpp__setup_output_field (void ) {struct perf_hpp_fmt *fmt;
tools/perf/util/hist.h +4 -0
@@ -237,7 +237,11 @@ enum {void perf_hpp__init (void );void perf_hpp__column_register (struct perf_hpp_fmt *format); +void perf_hpp__column_unregister (struct perf_hpp_fmt *format);void perf_hpp__column_enable (unsigned col); +void perf_hpp__column_disable (unsigned col); +void perf_hpp__cancel_cumulate (void ); +void perf_hpp__register_sort_field (struct perf_hpp_fmt *format);void perf_hpp__setup_output_field (void );void perf_hpp__reset_output_field (void );
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf tools: Add more hpp helper functions
perf tools: Add more hpp helper functions
Commit-ID: 77284de326e6d8c3b8e866cda5b415c86b522e61 Gitweb: http://git.kernel.org/tip/77284de326e6d8c3b8e866cda5b415c86b522e61 Author: Namhyung Kim <[email protected]> AuthorDate: Mon, 16 Dec 2013 16:55:13 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:03 +0200
perf tools: Add more hpp helper functions
Sometimes it needs to disable some columns at runtime. Add help functions to support that.
--- tools/perf/ui/hist.c | 17 +++++++++++++++++ tools/perf/util/hist.h | 4 ++++ 2 files changed, 21 insertions(+)
tools/perf/ui/hist.c +17 -0
@@ -489,6 +489,11 @@ void perf_hpp__column_register(struct perf_hpp_fmt *format)list_add_tail (&format->list, &perf_hpp__list); } +void perf_hpp__column_unregister (struct perf_hpp_fmt *format) +{ +list_del (&format->list); +} +void perf_hpp__register_sort_field (struct perf_hpp_fmt *format) {list_add_tail (&format->sort_list, &perf_hpp__sort_list);
@@ -500,6 +505,18 @@ void perf_hpp__column_enable(unsigned col)perf_hpp__column_register (&perf_hpp__format[col]); } +void perf_hpp__column_disable (unsigned col) +{ +BUG_ON (col >=PERF_HPP__MAX_INDEX ); +perf_hpp__column_unregister (&perf_hpp__format[col]); +} + +void perf_hpp__cancel_cumulate (void ) +{ +perf_hpp__column_disable (PERF_HPP__OVERHEAD_ACC ); + perf_hpp__format[PERF_HPP__OVERHEAD ].header = hpp__header_overhead; +} +void perf_hpp__setup_output_field (void ) {struct perf_hpp_fmt *fmt;
tools/perf/util/hist.h +4 -0
@@ -237,7 +237,11 @@ enum {void perf_hpp__init (void );void perf_hpp__column_register (struct perf_hpp_fmt *format); +void perf_hpp__column_unregister (struct perf_hpp_fmt *format);void perf_hpp__column_enable (unsigned col); +void perf_hpp__column_disable (unsigned col); +void perf_hpp__cancel_cumulate (void ); +void perf_hpp__register_sort_field (struct perf_hpp_fmt *format);void perf_hpp__setup_output_field (void );void perf_hpp__reset_output_field (void );
Namhyung Kim
maintainerPATCH 15/27 perf report: Add --children option
In reply to Namhyung KimThe --children option is for showing accumulated overhead (period) value as well as self overhead.
--- tools/perf/Documentation/perf-report.txt | 7 ++++++- tools/perf/builtin-report.c | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-)
tools/perf/Documentation/perf-report.txt +6 -1
@@ -111,7 +111,7 @@ OPTIONS --fields=:: Specify output field - multiple keys can be specified in CSV format. Following fields are available: - overhead, overhead_sys, overhead_us, sample and period. + overhead, overhead_sys, overhead_us, overhead_children, sample and period. Also it can contain any sort key(s). By default, every sort keys not specified in -F will be appended
@@ -163,6 +163,11 @@ OPTIONS Default: fractal,0.5,callee,function. +--children:: + Accumulate callchain of children to parent entry so that then can + show up in the output. The output will have a new "Children" column + and will be sorted on the data. It requires callchains are recorded. + --max-stack:: Set the stack depth limit when parsing the callchain, anything beyond the specified depth will be ignored. This is a trade-off
tools/perf/builtin-report.c +14 -1
@@ -185,6 +185,14 @@ static int report__setup_sample_type(struct report *rep) } } +if (symbol_conf.cumulate_callchain) { +/* Silently ignore if callchain is missing */ +if (!(sample_type &PERF_SAMPLE_CALLCHAIN )) { + symbol_conf.cumulate_callchain = false; +perf_hpp__cancel_cumulate (); + } + } +if (sort__mode ==SORT_MODE__BRANCH ) {if (!is_pipe && !(sample_type &PERF_SAMPLE_BRANCH_STACK )) {
@@ -568,6 +576,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)OPT_CALLBACK_DEFAULT ('g' ,"call-graph" , &report,"output_type,min_percent[,print_limit],call_order" ,"Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). " "Default: fractal,0.5,callee,function" , &report_parse_callchain_opt, callchain_default_opt), +OPT_BOOLEAN (0 ,"children" , &symbol_conf.cumulate_callchain, +"Accumulate callchains of children and show total overhead as well" ),OPT_INTEGER (0 ,"max-stack" , &report.max_stack,"Set the maximum stack depth when parsing the callchain, " "anything beyond the specified depth will be ignored. "
@@ -660,8 +670,10 @@ repeat: has_br_stack =perf_header__has_feat (&session->header,HEADER_BRANCH_STACK ); -if (branch_mode ==-1 && has_br_stack) +if (branch_mode ==-1 && has_br_stack) { sort__mode =SORT_MODE__BRANCH ; + symbol_conf.cumulate_callchain = false; + }if (report.mem_mode) {if (sort__mode ==SORT_MODE__BRANCH ) {
@@ -669,6 +681,7 @@ repeat: goto error; } sort__mode =SORT_MODE__MEMORY ; + symbol_conf.cumulate_callchain = false; }if (setup_sorting () <0 ) {
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf report: Add --children option
perf report: Add --children option
Commit-ID: 793aaaabb79803a0154fc6a98c472a29bb6d5cc9 Gitweb: http://git.kernel.org/tip/793aaaabb79803a0154fc6a98c472a29bb6d5cc9 Author: Namhyung Kim <[email protected]> AuthorDate: Wed, 30 Oct 2013 17:05:55 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:04 +0200
perf report: Add --children option
The --children option is for showing accumulated overhead (period) value as well as self overhead.
--- tools/perf/Documentation/perf-report.txt | 7 ++++++- tools/perf/builtin-report.c | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-)
tools/perf/Documentation/perf-report.txt +6 -1
@@ -111,7 +111,7 @@ OPTIONS --fields=:: Specify output field - multiple keys can be specified in CSV format. Following fields are available: - overhead, overhead_sys, overhead_us, sample and period. + overhead, overhead_sys, overhead_us, overhead_children, sample and period. Also it can contain any sort key(s). By default, every sort keys not specified in -F will be appended
@@ -163,6 +163,11 @@ OPTIONS Default: fractal,0.5,callee,function. +--children:: + Accumulate callchain of children to parent entry so that then can + show up in the output. The output will have a new "Children" column + and will be sorted on the data. It requires callchains are recorded. + --max-stack:: Set the stack depth limit when parsing the callchain, anything beyond the specified depth will be ignored. This is a trade-off
tools/perf/builtin-report.c +14 -1
@@ -185,6 +185,14 @@ static int report__setup_sample_type(struct report *rep) } } +if (symbol_conf.cumulate_callchain) { +/* Silently ignore if callchain is missing */ +if (!(sample_type &PERF_SAMPLE_CALLCHAIN )) { + symbol_conf.cumulate_callchain = false; +perf_hpp__cancel_cumulate (); + } + } +if (sort__mode ==SORT_MODE__BRANCH ) {if (!is_pipe && !(sample_type &PERF_SAMPLE_BRANCH_STACK )) {
@@ -568,6 +576,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)OPT_CALLBACK_DEFAULT ('g' ,"call-graph" , &report,"output_type,min_percent[,print_limit],call_order" ,"Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). " "Default: fractal,0.5,callee,function" , &report_parse_callchain_opt, callchain_default_opt), +OPT_BOOLEAN (0 ,"children" , &symbol_conf.cumulate_callchain, +"Accumulate callchains of children and show total overhead as well" ),OPT_INTEGER (0 ,"max-stack" , &report.max_stack,"Set the maximum stack depth when parsing the callchain, " "anything beyond the specified depth will be ignored. "
@@ -660,8 +670,10 @@ repeat: has_br_stack =perf_header__has_feat (&session->header,HEADER_BRANCH_STACK ); -if (branch_mode ==-1 && has_br_stack) +if (branch_mode ==-1 && has_br_stack) { sort__mode =SORT_MODE__BRANCH ; + symbol_conf.cumulate_callchain = false; + }if (report.mem_mode) {if (sort__mode ==SORT_MODE__BRANCH ) {
@@ -669,6 +681,7 @@ repeat: goto error; } sort__mode =SORT_MODE__MEMORY ; + symbol_conf.cumulate_callchain = false; }if (setup_sorting () <0 ) {
Namhyung Kim
maintainerPATCH 16/27 perf report: Add report.children config option
In reply to Namhyung KimAdd report.children config option for setting default value of callchain accumulation. It affects the report output only if perf.data contains callchain info.
A user can write .perfconfig file like below to enable accumulation by default:
$ cat ~/.perfconfig [report] children = true
And it can be disabled through command line:
$ perf report --no-children
--- tools/perf/builtin-report.c | 4 ++++ 1 file changed, 4 insertions(+)
tools/perf/builtin-report.c +4 -0
@@ -72,6 +72,10 @@ static int report__config(const char *var, const char *value, void *cb) rep->min_percent =strtof (value,NULL );return 0 ; } +if (!strcmp (var,"report.children" )) { + symbol_conf.cumulate_callchain =perf_config_bool (var, value); +return 0 ; + }return perf_default_config (var, value, cb); }
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf report: Add report.children config option
perf report: Add report.children config option
Commit-ID: 8d8e645ceafd726b8317949f899e4b3acfb20d29 Gitweb: http://git.kernel.org/tip/8d8e645ceafd726b8317949f899e4b3acfb20d29 Author: Namhyung Kim <[email protected]> AuthorDate: Tue, 22 Jan 2013 18:09:46 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:04 +0200
perf report: Add report.children config option
Add report.children config option for setting default value of callchain accumulation. It affects the report output only if perf.data contains callchain info.
A user can write .perfconfig file like below to enable accumulation by default:
$ cat ~/.perfconfig [report] children = true
And it can be disabled through command line:
$ perf report --no-children
--- tools/perf/builtin-report.c | 4 ++++ 1 file changed, 4 insertions(+)
tools/perf/builtin-report.c +4 -0
@@ -72,6 +72,10 @@ static int report__config(const char *var, const char *value, void *cb) rep->min_percent =strtof (value,NULL );return 0 ; } +if (!strcmp (var,"report.children" )) { + symbol_conf.cumulate_callchain =perf_config_bool (var, value); +return 0 ; + }return perf_default_config (var, value, cb); }
Namhyung Kim
maintainerPATCH 17/27 perf tools: Do not auto-remove Children column if --fields given
In reply to Namhyung KimDepending on the configuration perf inserts/removes the Children column in the output automatically. But it might not be what user wants if [s]he give --fields option explicitly.
--- tools/perf/ui/hist.c | 3 +++ 1 file changed, 3 insertions(+)
tools/perf/ui/hist.c +3 -0
@@ -513,6 +513,9 @@ void perf_hpp__column_disable(unsigned col)void perf_hpp__cancel_cumulate (void ) { +if (field_order) +return ; +perf_hpp__column_disable (PERF_HPP__OVERHEAD_ACC ); perf_hpp__format[PERF_HPP__OVERHEAD ].header = hpp__header_overhead; }
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf tools: Do not auto-remove Children column if --fields given
perf tools: Do not auto-remove Children column if --fields given
Commit-ID: 2bf1a12340bda1bf621f27b9892094a51b1297fd Gitweb: http://git.kernel.org/tip/2bf1a12340bda1bf621f27b9892094a51b1297fd Author: Namhyung Kim <[email protected]> AuthorDate: Thu, 20 Mar 2014 09:10:29 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:05 +0200
perf tools: Do not auto-remove Children column if --fields given
Depending on the configuration perf inserts/removes the Children column in the output automatically. But it might not be what user wants if [s]he give --fields option explicitly.
--- tools/perf/ui/hist.c | 3 +++ 1 file changed, 3 insertions(+)
tools/perf/ui/hist.c +3 -0
@@ -513,6 +513,9 @@ void perf_hpp__column_disable(unsigned col)void perf_hpp__cancel_cumulate (void ) { +if (field_order) +return ; +perf_hpp__column_disable (PERF_HPP__OVERHEAD_ACC ); perf_hpp__format[PERF_HPP__OVERHEAD ].header = hpp__header_overhead; }
Namhyung Kim
maintainerPATCH 18/27 perf tools: Add callback function to hist_entry_iter
In reply to Namhyung KimThe new ->add_entry_cb() will be called after an entry was added to the histogram. It's used for code sharing between perf report and perf top. Note that ops->add_*_entry() should set iter->he properly in order to call the ->add_entry_cb.
Also pass @arg to the callback function. It'll be used by perf top later.
--- tools/perf/builtin-report.c | 33 +++++++++++++++++++++++++-------- tools/perf/tests/hists_filter.c | 2 +- tools/perf/tests/hists_output.c | 2 +- tools/perf/util/hist.c | 19 +++++++++++++++++-- tools/perf/util/hist.h | 5 ++++- 5 files changed, 48 insertions(+), 13 deletions(-)
tools/perf/builtin-report.c +25 -8
@@ -80,14 +80,31 @@ static int report__config(const char *var, const char *value, void *cb)return perf_default_config (var, value, cb); } -static void report__inc_stats (struct report *rep, -struct hist_entry *he__maybe_unused ) +static void report__inc_stats (struct report *rep,struct hist_entry *he) {/* -* We cannot access @he at this time. Just assume it's a new entry. -* It'll be fixed once we have a callback mechanism in hist_iter. +* The @he is either of a newly created one or an existing one +* merging current sample. We only want to count a new one so +* checking ->nr_events being 1. */ - rep->nr_entries++; +if (he->stat.nr_events ==1 ) + rep->nr_entries++; +} + +static int hist_iter__report_callback (struct hist_entry_iter *iter, +struct addr_location *al,void *arg) +{ +int err =0 ; +struct hist_entry *he = iter->he; +struct perf_evsel *evsel = iter->evsel; +struct report *rep = arg; + +if (ui__has_annotation ()) + err =hist_entry__inc_addr_samples (he, evsel->idx, al->addr); + +report__inc_stats (rep, he); + +return err; } static int process_sample_event(struct perf_tool *tool,
@@ -100,6 +117,7 @@ static int process_sample_event(struct perf_tool *tool,struct addr_location al;struct hist_entry_iter iter = { .hide_unresolved = rep->hide_unresolved, + .add_entry_cb = hist_iter__report_callback, };int ret;
@@ -127,9 +145,8 @@ static int process_sample_event(struct perf_tool *tool,if (al.map !=NULL ) al.map->dso->hit =1 ; -report__inc_stats (rep,NULL ); - - ret =hist_entry_iter__add (&iter, &al, evsel, sample, rep->max_stack); + ret =hist_entry_iter__add (&iter, &al, evsel, sample, rep->max_stack, + rep);if (ret <0 )pr_debug ("problem adding hist entry, skipping event\n" );
tools/perf/tests/hists_filter.c +1 -1
@@ -82,7 +82,7 @@ static int add_hist_entries(struct perf_evlist *evlist, goto out;if (hist_entry_iter__add (&iter, &al, evsel, &sample, -PERF_MAX_STACK_DEPTH ) <0 ) +PERF_MAX_STACK_DEPTH ,NULL ) <0 ) goto out; fake_samples[i].thread = al.thread;
tools/perf/tests/hists_output.c +1 -1
@@ -71,7 +71,7 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) goto out;if (hist_entry_iter__add (&iter, &al, evsel, &sample, -PERF_MAX_STACK_DEPTH ) <0 ) +PERF_MAX_STACK_DEPTH ,NULL ) <0 ) goto out; fake_samples[i].thread = al.thread;
tools/perf/util/hist.c +17 -2
@@ -802,8 +802,11 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,* It's possible that it has cycles or recursive calls. */ for (i =0 ; i < iter->curr; i++) { -if (hist_entry__cmp (he_cache[i], &he_tmp) ==0 ) +if (hist_entry__cmp (he_cache[i], &he_tmp) ==0 ) { +/* to avoid calling callback function */ + iter->he =NULL ;return 0 ; + } } he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
@@ -863,7 +866,7 @@ const struct hist_iter_ops hist_iter_cumulative = {int hist_entry_iter__add (struct hist_entry_iter *iter,struct addr_location *al,struct perf_evsel *evsel,struct perf_sample *sample, -int max_stack_depth) +int max_stack_depth,void *arg) {int err, err2;
@@ -883,10 +886,22 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,if (err) goto out; +if (iter->he && iter->add_entry_cb) { + err = iter->add_entry_cb (iter, al, arg); +if (err) + goto out; + } +while (iter->ops->next_entry (iter, al)) { err = iter->ops->add_next_entry (iter, al);if (err)break ; + +if (iter->he && iter->add_entry_cb) { + err = iter->add_entry_cb (iter, al, arg); +if (err) + goto out; + } } out:
tools/perf/util/hist.h +4 -1
@@ -119,6 +119,9 @@ struct hist_entry_iter {void *priv;const struct hist_iter_ops *ops; +/* user-defined callback function (optional) */ +int (*add_entry_cb)(struct hist_entry_iter *iter, +struct addr_location *al,void *arg); };extern const struct hist_iter_ops hist_iter_normal;
@@ -135,7 +138,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists, bool sample_self);int hist_entry_iter__add (struct hist_entry_iter *iter,struct addr_location *al,struct perf_evsel *evsel,struct perf_sample *sample, -int max_stack_depth); +int max_stack_depth,void *arg);int64_t hist_entry__cmp (struct hist_entry *left,struct hist_entry *right);int64_t hist_entry__collapse (struct hist_entry *left,struct hist_entry *right);
Signature · 1 line
1.9.2
Re: [PATCH 18/27] perf tools: Add callback function to hist_entry_iter
Quoted 45 lines · Namhyung Kim
The new ->add_entry_cb() will be called after an entry was added to the histogram. It's used for code sharing between perf report and perf top. Note that ops->add_*_entry() should set
iter->heproperly in order to call the ->add_entry_cb.Also pass @arg to the callback function. It'll be used by perf top later.
Tested-by Arun Sharma <[email protected]>Tested-by Rodrigo Campos <[email protected]>Acked-by Jiri Olsa <[email protected]>Cc Frederic Weisbecker <[email protected]>Signed-off-by Namhyung Kim <[email protected]>--- tools/perf/builtin-report.c | 33 +++++++++++++++++++++++++-------- tools/perf/tests/hists_filter.c | 2 +- tools/perf/tests/hists_output.c | 2 +- tools/perf/util/hist.c | 19 +++++++++++++++++-- tools/perf/util/hist.h | 5 ++++- 5 files changed, 48 insertions(+), 13 deletions(-)tools/perf/builtin-report.c +8
-5@@ -80,14 +80,31 @@ static int report__config(const char *var, const char *value, void *cb)return perf_default_config (var, value, cb); } -static void report__inc_stats (struct report *rep, -struct hist_entry *he__maybe_unused ) +static void report__inc_stats (struct report *rep,struct hist_entry *he) {/* -* We cannot access @he at this time. Just assume it's a new entry. -* It'll be fixed once we have a callback mechanism in hist_iter. +* The @he is either of a newly created one or an existing one +* merging current sample. We only want to count a new one so +* checking ->nr_events being 1. */ - rep->nr_entries++; +if (he->stat.nr_events ==1 ) + rep->nr_entries++; +} +
tools/perf/builtin-report.c static int report__config(const char *var, const char *value, void *cb) · line 103
Quoted 10 lines
tools/perf/builtin-report.c +10
-0+static int hist_iter__report_callback (struct hist_entry_iter *iter, +struct addr_location *al,void *arg) +{ +int err =0 ; +struct hist_entry *he = iter->he; +struct perf_evsel *evsel = iter->evsel; +struct report *rep = arg; + +if (ui__has_annotation ()) + err =hist_entry__inc_addr_samples (he, evsel->idx, al->addr);
if we put the annotation stats in here, shouldn't we remove all other instancies of above call from:
iter_finish_normal_entry
iter_add_single_cumulative_entry
iter_finish_mem_entry
SNIP
Quoted 11 lines
tools/perf/builtin-report.c +6
-0@@ -883,10 +886,22 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,if (err) goto out; +if (iter->he && iter->add_entry_cb) { + err = iter->add_entry_cb (iter, al, arg); +if (err) + goto out; + } +
tools/perf/builtin-report.c int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, · line 904
Quoted 10 lines
tools/perf/builtin-report.c +6
-0while (iter->ops->next_entry (iter, al)) { err = iter->ops->add_next_entry (iter, al);if (err)break ; + +if (iter->he && iter->add_entry_cb) { + err = iter->add_entry_cb (iter, al, arg); +if (err) + goto out; + }
hm, the callback code is identical.. do we want a function for this?
jirka
Re: [PATCH 18/27] perf tools: Add callback function to hist_entry_iter
Quoted 15 lines · Jiri Olsa
Review
Quoted 10 lines · Namhyung Kim
(quoted diff) +10
-0+static int hist_iter__report_callback(struct hist_entry_iter *iter, + struct addr_location *al, void *arg) +{ + int err = 0; + struct hist_entry *he = iter->he; + struct perf_evsel *evsel = iter->evsel; + struct report *rep = arg; + + if (ui__has_annotation()) + err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);if we put the annotation stats in here, shouldn't we remove all other instancies of above call from:
Quoted 3 lines
iter_finish_normal_entry
iter_add_single_cumulative_entry
iter_finish_mem_entry
Right, they were double counted.. :-/ I changed this as below and push to perf/cumulate-v12. Would you please check it again?
Thanks,
Namhyung
Quoted 1 line
From
0be9139edf446a5d6d753698f42809b2212dcf76Mon Sep 17 00:00:00 2001
From: Namhyung Kim <[email protected]>
Date: Tue, 7 Jan 2014 17:02:25 +0900
Subject: [PATCH] perf tools: Add callback function to hist_entry_iter
The new ->add_entry_cb() will be called after an entry was added to the histogram. It's used for code sharing between perf report and perf top. Note that ops->add_*_entry() should set iter->he properly in order to call the ->add_entry_cb.
Also pass @arg to the callback function. It'll be used by perf top later.
--- tools/perf/builtin-report.c | 61 ++++++++++++++++++++++++++++++++----- tools/perf/tests/hists_filter.c | 2 +- tools/perf/tests/hists_output.c | 2 +- tools/perf/util/hist.c | 67 +++++++++++++++-------------------------- tools/perf/util/hist.h | 5 ++- 5 files changed, 84 insertions(+), 53 deletions(-)
tools/perf/builtin-report.c +53 -8
@@ -80,14 +80,59 @@ static int report__config(const char *var, const char *value, void *cb)return perf_default_config (var, value, cb); } -static void report__inc_stats (struct report *rep, -struct hist_entry *he__maybe_unused ) +static void report__inc_stats (struct report *rep,struct hist_entry *he) {/* -* We cannot access @he at this time. Just assume it's a new entry. -* It'll be fixed once we have a callback mechanism in hist_iter. +* The @he is either of a newly created one or an existing one +* merging current sample. We only want to count a new one so +* checking ->nr_events being 1. */ - rep->nr_entries++; +if (he->stat.nr_events ==1 ) + rep->nr_entries++; +} + +static int hist_iter__report_callback (struct hist_entry_iter *iter, +struct addr_location *al,bool single, +void *arg) +{ +int err =0 ; +struct report *rep = arg; +struct hist_entry *he = iter->he; +struct perf_evsel *evsel = iter->evsel; +struct mem_info *mi; +struct branch_info *bi; + +report__inc_stats (rep, he); + +if (!ui__has_annotation ()) +return 0 ; + +if (sort__mode ==SORT_MODE__BRANCH ) { + bi = he->branch_info; + err =addr_map_symbol__inc_samples (&bi->from, evsel->idx); +if (err) + goto out; + + err =addr_map_symbol__inc_samples (&bi->to, evsel->idx); + + }else if (rep->mem_mode) { + mi = he->mem_info; + err =addr_map_symbol__inc_samples (&mi->daddr, evsel->idx); +if (err) + goto out; + + err =hist_entry__inc_addr_samples (he, evsel->idx, al->addr); + + }else if (symbol_conf.cumulate_callchain) { +if (single) + err =hist_entry__inc_addr_samples (he, evsel->idx, + al->addr); + }else { + err =hist_entry__inc_addr_samples (he, evsel->idx, al->addr); + } + +out: +return err; } static int process_sample_event(struct perf_tool *tool,
@@ -100,6 +145,7 @@ static int process_sample_event(struct perf_tool *tool,struct addr_location al;struct hist_entry_iter iter = { .hide_unresolved = rep->hide_unresolved, + .add_entry_cb = hist_iter__report_callback, };int ret;
@@ -127,9 +173,8 @@ static int process_sample_event(struct perf_tool *tool,if (al.map !=NULL ) al.map->dso->hit =1 ; -report__inc_stats (rep,NULL ); - - ret =hist_entry_iter__add (&iter, &al, evsel, sample, rep->max_stack); + ret =hist_entry_iter__add (&iter, &al, evsel, sample, rep->max_stack, + rep);if (ret <0 )pr_debug ("problem adding hist entry, skipping event\n" );
tools/perf/tests/hists_filter.c +1 -1
@@ -82,7 +82,7 @@ static int add_hist_entries(struct perf_evlist *evlist, goto out;if (hist_entry_iter__add (&iter, &al, evsel, &sample, -PERF_MAX_STACK_DEPTH ) <0 ) +PERF_MAX_STACK_DEPTH ,NULL ) <0 ) goto out; fake_samples[i].thread = al.thread;
tools/perf/tests/hists_output.c +1 -1
@@ -71,7 +71,7 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) goto out;if (hist_entry_iter__add (&iter, &al, evsel, &sample, -PERF_MAX_STACK_DEPTH ) <0 ) +PERF_MAX_STACK_DEPTH ,NULL ) <0 ) goto out; fake_samples[i].thread = al.thread;
tools/perf/util/hist.c +25 -42
141 lines not on this page · raw message
tools/perf/util/hist.h +4 -1
@@ -119,6 +119,9 @@ struct hist_entry_iter {void *priv;const struct hist_iter_ops *ops; +/* user-defined callback function (optional) */ +int (*add_entry_cb)(struct hist_entry_iter *iter, +struct addr_location *al,bool single,void *arg); };extern const struct hist_iter_ops hist_iter_normal;
@@ -135,7 +138,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists, bool sample_self);int hist_entry_iter__add (struct hist_entry_iter *iter,struct addr_location *al,struct perf_evsel *evsel,struct perf_sample *sample, -int max_stack_depth); +int max_stack_depth,void *arg);int64_t hist_entry__cmp (struct hist_entry *left,struct hist_entry *right);int64_t hist_entry__collapse (struct hist_entry *left,struct hist_entry *right);
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf tools: Add callback function to hist_entry_iter
perf tools: Add callback function to hist_entry_iter
Commit-ID: 9d3c02d7188866299eebe3c4a652c08140a71f40 Gitweb: http://git.kernel.org/tip/9d3c02d7188866299eebe3c4a652c08140a71f40 Author: Namhyung Kim <[email protected]> AuthorDate: Tue, 7 Jan 2014 17:02:25 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:05 +0200
perf tools: Add callback function to hist_entry_iter
The new ->add_entry_cb() will be called after an entry was added to the histogram. It's used for code sharing between perf report and perf top. Note that ops->add_*_entry() should set iter->he properly in order to call the ->add_entry_cb.
Also pass @arg to the callback function. It'll be used by perf top later.
--- tools/perf/builtin-report.c | 61 ++++++++++++++++++++++++++++++++----- tools/perf/tests/hists_filter.c | 2 +- tools/perf/tests/hists_output.c | 2 +- tools/perf/util/hist.c | 67 +++++++++++++++-------------------------- tools/perf/util/hist.h | 5 ++- 5 files changed, 84 insertions(+), 53 deletions(-)
tools/perf/builtin-report.c +53 -8
@@ -80,14 +80,59 @@ static int report__config(const char *var, const char *value, void *cb)return perf_default_config (var, value, cb); } -static void report__inc_stats (struct report *rep, -struct hist_entry *he__maybe_unused ) +static void report__inc_stats (struct report *rep,struct hist_entry *he) {/* -* We cannot access @he at this time. Just assume it's a new entry. -* It'll be fixed once we have a callback mechanism in hist_iter. +* The @he is either of a newly created one or an existing one +* merging current sample. We only want to count a new one so +* checking ->nr_events being 1. */ - rep->nr_entries++; +if (he->stat.nr_events ==1 ) + rep->nr_entries++; +} + +static int hist_iter__report_callback (struct hist_entry_iter *iter, +struct addr_location *al,bool single, +void *arg) +{ +int err =0 ; +struct report *rep = arg; +struct hist_entry *he = iter->he; +struct perf_evsel *evsel = iter->evsel; +struct mem_info *mi; +struct branch_info *bi; + +report__inc_stats (rep, he); + +if (!ui__has_annotation ()) +return 0 ; + +if (sort__mode ==SORT_MODE__BRANCH ) { + bi = he->branch_info; + err =addr_map_symbol__inc_samples (&bi->from, evsel->idx); +if (err) + goto out; + + err =addr_map_symbol__inc_samples (&bi->to, evsel->idx); + + }else if (rep->mem_mode) { + mi = he->mem_info; + err =addr_map_symbol__inc_samples (&mi->daddr, evsel->idx); +if (err) + goto out; + + err =hist_entry__inc_addr_samples (he, evsel->idx, al->addr); + + }else if (symbol_conf.cumulate_callchain) { +if (single) + err =hist_entry__inc_addr_samples (he, evsel->idx, + al->addr); + }else { + err =hist_entry__inc_addr_samples (he, evsel->idx, al->addr); + } + +out: +return err; } static int process_sample_event(struct perf_tool *tool,
@@ -100,6 +145,7 @@ static int process_sample_event(struct perf_tool *tool,struct addr_location al;struct hist_entry_iter iter = { .hide_unresolved = rep->hide_unresolved, + .add_entry_cb = hist_iter__report_callback, };int ret;
@@ -127,9 +173,8 @@ static int process_sample_event(struct perf_tool *tool,if (al.map !=NULL ) al.map->dso->hit =1 ; -report__inc_stats (rep,NULL ); - - ret =hist_entry_iter__add (&iter, &al, evsel, sample, rep->max_stack); + ret =hist_entry_iter__add (&iter, &al, evsel, sample, rep->max_stack, + rep);if (ret <0 )pr_debug ("problem adding hist entry, skipping event\n" );
tools/perf/tests/hists_filter.c +1 -1
@@ -82,7 +82,7 @@ static int add_hist_entries(struct perf_evlist *evlist, goto out;if (hist_entry_iter__add (&iter, &al, evsel, &sample, -PERF_MAX_STACK_DEPTH ) <0 ) +PERF_MAX_STACK_DEPTH ,NULL ) <0 ) goto out; fake_samples[i].thread = al.thread;
tools/perf/tests/hists_output.c +1 -1
@@ -71,7 +71,7 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) goto out;if (hist_entry_iter__add (&iter, &al, evsel, &sample, -PERF_MAX_STACK_DEPTH ) <0 ) +PERF_MAX_STACK_DEPTH ,NULL ) <0 ) goto out; fake_samples[i].thread = al.thread;
tools/perf/util/hist.c +25 -42
141 lines not on this page · raw message
tools/perf/util/hist.h +4 -1
@@ -119,6 +119,9 @@ struct hist_entry_iter {void *priv;const struct hist_iter_ops *ops; +/* user-defined callback function (optional) */ +int (*add_entry_cb)(struct hist_entry_iter *iter, +struct addr_location *al,bool single,void *arg); };extern const struct hist_iter_ops hist_iter_normal;
@@ -135,7 +138,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists, bool sample_self);int hist_entry_iter__add (struct hist_entry_iter *iter,struct addr_location *al,struct perf_evsel *evsel,struct perf_sample *sample, -int max_stack_depth); +int max_stack_depth,void *arg);int64_t hist_entry__cmp (struct hist_entry *left,struct hist_entry *right);int64_t hist_entry__collapse (struct hist_entry *left,struct hist_entry *right);
Namhyung Kim
maintainerPATCH 19/27 perf top: Convert to hist_entry_iter
In reply to Namhyung KimReuse hist_entry_iter__add() function to share the similar code with perf report. Note that it needs to be called with hists.lock so tweak some internal functions not to deadlock or hold the lock too long.
--- tools/perf/builtin-top.c | 75 ++++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 35 deletions(-)
tools/perf/builtin-top.c +40 -35
@@ -196,6 +196,12 @@ static void perf_top__record_precise_ip(struct perf_top *top,pthread_mutex_unlock (¬es->lock); +/* +* This function is now called with he->hists->lock held. +* Release it before going to sleep. +*/ +pthread_mutex_unlock (&he->hists->lock); +if (err == -ERANGE && !he->ms.map->erange_warned)ui__warn_map_erange (he->ms.map, sym, ip);else if (err == -ENOMEM ) {
@@ -203,6 +209,8 @@ static void perf_top__record_precise_ip(struct perf_top *top, sym->name);sleep (1 ); } + +pthread_mutex_lock (&he->hists->lock); }static void perf_top__show_details (struct perf_top *top)
@@ -238,24 +246,6 @@ out_unlock:pthread_mutex_unlock (¬es->lock); } -static struct hist_entry *perf_evsel__add_hist_entry (struct perf_evsel *evsel, -struct addr_location *al, -struct perf_sample *sample) -{ -struct hist_entry *he; - -pthread_mutex_lock (&evsel->hists.lock); - he =__hists__add_entry (&evsel->hists, al,NULL ,NULL ,NULL , - sample->period, sample->weight, - sample->transaction, true); -pthread_mutex_unlock (&evsel->hists.lock); -if (he ==NULL ) -return NULL ; - -hists__inc_nr_samples (&evsel->hists, he->filtered); -return he; -} -static void perf_top__print_sym_table (struct perf_top *top) {char bf[160 ];
@@ -659,6 +649,25 @@ static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)return 0 ; } +static int hist_iter__top_callback (struct hist_entry_iter *iter, +struct addr_location *al,void *arg) +{ +struct perf_top *top = arg; +struct hist_entry *he = iter->he; +struct perf_evsel *evsel = iter->evsel; + +if (sort__has_sym) { +u64 ip = al->addr; + +if (al->map) + ip = al->map->unmap_ip (al->map, ip); + +perf_top__record_precise_ip (top, he, evsel->idx, ip); + } + +return 0 ; +} + static void perf_event__process_sample(struct perf_tool *tool, const union perf_event *event, struct perf_evsel *evsel,
@@ -666,8 +675,6 @@ static void perf_event__process_sample(struct perf_tool *tool, struct machine *machine) { struct perf_top *top = container_of(tool, struct perf_top, tool); -struct symbol *parent =NULL ; -u64 ip = sample->ip;struct addr_location al;int err;
@@ -742,25 +749,23 @@ static void perf_event__process_sample(struct perf_tool *tool, }if (al.sym ==NULL || !al.sym->ignore) { -struct hist_entry *he; +struct hist_entry_iter iter = { + .add_entry_cb = hist_iter__top_callback, + }; - err =sample__resolve_callchain (sample, &parent, evsel, &al, - top->max_stack); -if (err) -return ; +if (symbol_conf.cumulate_callchain) + iter.ops = &hist_iter_cumulative; +else + iter.ops = &hist_iter_normal; - he =perf_evsel__add_hist_entry (evsel, &al, sample); -if (he ==NULL ) { -pr_err ("Problem incrementing symbol period, skipping event\n" ); -return ; - } +pthread_mutex_lock (&evsel->hists.lock); - err =hist_entry__append_callchain (he, sample); -if (err) -return ; + err =hist_entry_iter__add (&iter, &al, evsel, sample, + top->max_stack, top); +if (err <0 ) +pr_err ("Problem incrementing symbol period, skipping event\n" ); -if (sort__has_sym) -perf_top__record_precise_ip (top, he, evsel->idx, ip); +pthread_mutex_unlock (&evsel->hists.lock); }return ;
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf top: Convert to hist_entry_iter
perf top: Convert to hist_entry_iter
Commit-ID: 7c50391f536ea6ed1e75b0f4d90922a2606da3de Gitweb: http://git.kernel.org/tip/7c50391f536ea6ed1e75b0f4d90922a2606da3de Author: Namhyung Kim <[email protected]> AuthorDate: Tue, 7 Jan 2014 17:41:03 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:06 +0200
perf top: Convert to hist_entry_iter
Reuse hist_entry_iter__add() function to share the similar code with perf report. Note that it needs to be called with hists.lock so tweak some internal functions not to deadlock or hold the lock too long.
--- tools/perf/builtin-top.c | 76 ++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 35 deletions(-)
tools/perf/builtin-top.c +41 -35
@@ -196,6 +196,12 @@ static void perf_top__record_precise_ip(struct perf_top *top,pthread_mutex_unlock (¬es->lock); +/* +* This function is now called with he->hists->lock held. +* Release it before going to sleep. +*/ +pthread_mutex_unlock (&he->hists->lock); +if (err == -ERANGE && !he->ms.map->erange_warned)ui__warn_map_erange (he->ms.map, sym, ip);else if (err == -ENOMEM ) {
@@ -203,6 +209,8 @@ static void perf_top__record_precise_ip(struct perf_top *top, sym->name);sleep (1 ); } + +pthread_mutex_lock (&he->hists->lock); }static void perf_top__show_details (struct perf_top *top)
@@ -238,24 +246,6 @@ out_unlock:pthread_mutex_unlock (¬es->lock); } -static struct hist_entry *perf_evsel__add_hist_entry (struct perf_evsel *evsel, -struct addr_location *al, -struct perf_sample *sample) -{ -struct hist_entry *he; - -pthread_mutex_lock (&evsel->hists.lock); - he =__hists__add_entry (&evsel->hists, al,NULL ,NULL ,NULL , - sample->period, sample->weight, - sample->transaction, true); -pthread_mutex_unlock (&evsel->hists.lock); -if (he ==NULL ) -return NULL ; - -hists__inc_nr_samples (&evsel->hists, he->filtered); -return he; -} -static void perf_top__print_sym_table (struct perf_top *top) {char bf[160 ];
@@ -659,6 +649,26 @@ static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)return 0 ; } +static int hist_iter__top_callback (struct hist_entry_iter *iter, +struct addr_location *al,bool single, +void *arg) +{ +struct perf_top *top = arg; +struct hist_entry *he = iter->he; +struct perf_evsel *evsel = iter->evsel; + +if (sort__has_sym && single) { +u64 ip = al->addr; + +if (al->map) + ip = al->map->unmap_ip (al->map, ip); + +perf_top__record_precise_ip (top, he, evsel->idx, ip); + } + +return 0 ; +} + static void perf_event__process_sample(struct perf_tool *tool, const union perf_event *event, struct perf_evsel *evsel,
@@ -666,8 +676,6 @@ static void perf_event__process_sample(struct perf_tool *tool, struct machine *machine) { struct perf_top *top = container_of(tool, struct perf_top, tool); -struct symbol *parent =NULL ; -u64 ip = sample->ip;struct addr_location al;int err;
@@ -742,25 +750,23 @@ static void perf_event__process_sample(struct perf_tool *tool, }if (al.sym ==NULL || !al.sym->ignore) { -struct hist_entry *he; +struct hist_entry_iter iter = { + .add_entry_cb = hist_iter__top_callback, + }; - err =sample__resolve_callchain (sample, &parent, evsel, &al, - top->max_stack); -if (err) -return ; +if (symbol_conf.cumulate_callchain) + iter.ops = &hist_iter_cumulative; +else + iter.ops = &hist_iter_normal; - he =perf_evsel__add_hist_entry (evsel, &al, sample); -if (he ==NULL ) { -pr_err ("Problem incrementing symbol period, skipping event\n" ); -return ; - } +pthread_mutex_lock (&evsel->hists.lock); - err =hist_entry__append_callchain (he, sample); -if (err) -return ; + err =hist_entry_iter__add (&iter, &al, evsel, sample, + top->max_stack, top); +if (err <0 ) +pr_err ("Problem incrementing symbol period, skipping event\n" ); -if (sort__has_sym) -perf_top__record_precise_ip (top, he, evsel->idx, ip); +pthread_mutex_unlock (&evsel->hists.lock); }return ;
Namhyung Kim
maintainerPATCH 20/27 perf top: Add --children option
In reply to Namhyung KimThe --children option is for showing accumulated overhead (period) value as well as self overhead. It should be used with one of -g or --call-graph option.
--- tools/perf/Documentation/perf-top.txt | 8 +++++++- tools/perf/builtin-top.c | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-)
tools/perf/Documentation/perf-top.txt +7 -1
@@ -119,7 +119,7 @@ Default is to monitor all CPUS. --fields=:: Specify output field - multiple keys can be specified in CSV format. Following fields are available: - overhead, overhead_sys, overhead_us, sample and period. + overhead, overhead_sys, overhead_us, overhead_children, sample and period. Also it can contain any sort key(s). By default, every sort keys not specified in --field will be appended
@@ -161,6 +161,12 @@ Default is to monitor all CPUS. Setup and enable call-graph (stack chain/backtrace) recording, implies -g. +--children:: + Accumulate callchain of children to parent entry so that then can + show up in the output. The output will have a new "Children" column + and will be sorted on the data. It requires -g/--call-graph option + enabled. + --max-stack:: Set the stack depth limit when parsing the callchain, anything beyond the specified depth will be ignored. This is a trade-off
tools/perf/builtin-top.c +7 -0
@@ -1097,6 +1097,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)OPT_CALLBACK (0 ,"call-graph" , &top.record_opts,"mode[,dump_size]" , record_callchain_help, &parse_callchain_opt), +OPT_BOOLEAN (0 ,"children" , &symbol_conf.cumulate_callchain, +"Accumulate callchains of children and show total overhead as well" ),OPT_INTEGER (0 ,"max-stack" , &top.max_stack,"Set the maximum stack depth when parsing the callchain. " "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
@@ -1202,6 +1204,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) top.sym_evsel =perf_evlist__first (top.evlist); +if (!symbol_conf.use_callchain) { + symbol_conf.cumulate_callchain = false; +perf_hpp__cancel_cumulate (); + } + symbol_conf.priv_size =sizeof (struct annotation ); symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name ==NULL );
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf top: Add --children option
perf top: Add --children option
Commit-ID: 1432ec342ece6a7ef78825ae3a9ba1c91686f71d Gitweb: http://git.kernel.org/tip/1432ec342ece6a7ef78825ae3a9ba1c91686f71d Author: Namhyung Kim <[email protected]> AuthorDate: Wed, 30 Oct 2013 17:05:55 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:07 +0200
perf top: Add --children option
The --children option is for showing accumulated overhead (period) value as well as self overhead. It should be used with one of -g or --call-graph option.
--- tools/perf/Documentation/perf-top.txt | 8 +++++++- tools/perf/builtin-top.c | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-)
tools/perf/Documentation/perf-top.txt +7 -1
@@ -119,7 +119,7 @@ Default is to monitor all CPUS. --fields=:: Specify output field - multiple keys can be specified in CSV format. Following fields are available: - overhead, overhead_sys, overhead_us, sample and period. + overhead, overhead_sys, overhead_us, overhead_children, sample and period. Also it can contain any sort key(s). By default, every sort keys not specified in --field will be appended
@@ -161,6 +161,12 @@ Default is to monitor all CPUS. Setup and enable call-graph (stack chain/backtrace) recording, implies -g. +--children:: + Accumulate callchain of children to parent entry so that then can + show up in the output. The output will have a new "Children" column + and will be sorted on the data. It requires -g/--call-graph option + enabled. + --max-stack:: Set the stack depth limit when parsing the callchain, anything beyond the specified depth will be ignored. This is a trade-off
tools/perf/builtin-top.c +7 -0
@@ -1098,6 +1098,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)OPT_CALLBACK (0 ,"call-graph" , &top.record_opts,"mode[,dump_size]" , record_callchain_help, &parse_callchain_opt), +OPT_BOOLEAN (0 ,"children" , &symbol_conf.cumulate_callchain, +"Accumulate callchains of children and show total overhead as well" ),OPT_INTEGER (0 ,"max-stack" , &top.max_stack,"Set the maximum stack depth when parsing the callchain. " "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
@@ -1203,6 +1205,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) top.sym_evsel =perf_evlist__first (top.evlist); +if (!symbol_conf.use_callchain) { + symbol_conf.cumulate_callchain = false; +perf_hpp__cancel_cumulate (); + } + symbol_conf.priv_size =sizeof (struct annotation ); symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name ==NULL );
Namhyung Kim
maintainerPATCH 21/27 perf top: Add top.children config option
In reply to Namhyung KimAdd top.children config option for setting default value of callchain accumulation. It affects the output only if one of -g or --call-graph option is given as well.
A user can write .perfconfig file like below to enable accumulation by default:
$ cat ~/.perfconfig [top] children = true
And it can be disabled through command line:
$ perf top --no-children
--- tools/perf/builtin-top.c | 4 ++++ 1 file changed, 4 insertions(+)
tools/perf/builtin-top.c +4 -0
@@ -1003,6 +1003,10 @@ static int perf_top_config(const char *var, const char *value, void *cb)if (!strcmp (var,"top.call-graph" ))return record_parse_callchain (value, &top->record_opts); +if (!strcmp (var,"top.children" )) { + symbol_conf.cumulate_callchain =perf_config_bool (var, value); +return 0 ; + }return perf_default_config (var, value, cb); }
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf top: Add top.children config option
perf top: Add top.children config option
Commit-ID: 104ac991bd821773cba6f262f97a4a752ed76dd5 Gitweb: http://git.kernel.org/tip/104ac991bd821773cba6f262f97a4a752ed76dd5 Author: Namhyung Kim <[email protected]> AuthorDate: Tue, 22 Jan 2013 18:09:46 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:07 +0200
perf top: Add top.children config option
Add top.children config option for setting default value of callchain accumulation. It affects the output only if one of -g or --call-graph option is given as well.
A user can write .perfconfig file like below to enable accumulation by default:
$ cat ~/.perfconfig [top] children = true
And it can be disabled through command line:
$ perf top --no-children
--- tools/perf/builtin-top.c | 4 ++++ 1 file changed, 4 insertions(+)
tools/perf/builtin-top.c +4 -0
@@ -1004,6 +1004,10 @@ static int perf_top_config(const char *var, const char *value, void *cb)if (!strcmp (var,"top.call-graph" ))return record_parse_callchain (value, &top->record_opts); +if (!strcmp (var,"top.children" )) { + symbol_conf.cumulate_callchain =perf_config_bool (var, value); +return 0 ; + }return perf_default_config (var, value, cb); }
Namhyung Kim
maintainerPATCH 22/27 perf tools: Enable --children option by default
In reply to Namhyung KimNow perf top and perf report will show children column by default if it has callchain information.
--- tools/perf/util/symbol.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
tools/perf/util/symbol.c +6 -5
@@ -29,11 +29,12 @@ int vmlinux_path__nr_entries;char **vmlinux_path;struct symbol_conf symbol_conf = { - .use_modules = true, - .try_vmlinux_path = true, - .annotate_src = true, - .demangle = true, - .symfs ="" , + .use_modules = true, + .try_vmlinux_path = true, + .annotate_src = true, + .demangle = true, + .cumulate_callchain = true, + .symfs ="" , };static enum dso_binary_type binary_type_symtab[] = {
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf tools: Enable --children option by default
perf tools: Enable --children option by default
Commit-ID: e511db5e94f056083e821aa3ab74b03ad1216e14 Gitweb: http://git.kernel.org/tip/e511db5e94f056083e821aa3ab74b03ad1216e14 Author: Namhyung Kim <[email protected]> AuthorDate: Tue, 24 Dec 2013 16:19:25 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:08 +0200
perf tools: Enable --children option by default
Now perf top and perf report will show children column by default if it has callchain information.
--- tools/perf/util/symbol.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
tools/perf/util/symbol.c +6 -5
@@ -29,11 +29,12 @@ int vmlinux_path__nr_entries;char **vmlinux_path;struct symbol_conf symbol_conf = { - .use_modules = true, - .try_vmlinux_path = true, - .annotate_src = true, - .demangle = true, - .symfs ="" , + .use_modules = true, + .try_vmlinux_path = true, + .annotate_src = true, + .demangle = true, + .cumulate_callchain = true, + .symfs ="" , };static enum dso_binary_type binary_type_symtab[] = {
Re: [PATCH 22/27] perf tools: Enable --children option by default
In reply to Namhyung KimHi,
Quoted 9 lines · Namhyung Kim
Now perf top and perf report will show children column by default if it has callchain information.
Requested-by Ingo Molnar <[email protected]>Tested-by Rodrigo Campos <[email protected]>Tested-by Arun Sharma <[email protected]>Acked-by Jiri Olsa <[email protected]>Cc Frederic Weisbecker <[email protected]>Signed-off-by Namhyung Kim <[email protected]>
Stupid question: Why? This breaks user's usage pattern in a rather significant way because the new output is pretty much entirely useless in many cases, especially for userland programs. I think the new option is great, but why is it suddenly the default?
Greetings,
Andres Freund
Re: [PATCH 22/27] perf tools: Enable --children option by default
Hi Andres,
Quoted 13 lines · Andres Freund
Hi,
Quoted 9 lines · Namhyung Kim
Now perf top and perf report will show children column by default if it has callchain information.
Requested-by Ingo Molnar <[email protected]>Tested-by Rodrigo Campos <[email protected]>Tested-by Arun Sharma <[email protected]>Acked-by Jiri Olsa <[email protected]>Cc Frederic Weisbecker <[email protected]>Signed-off-by Namhyung Kim <[email protected]>
Quoted 4 lines
Stupid question: Why? This breaks user's usage pattern in a rather significant way because the new output is pretty much entirely useless in many cases, especially for userland programs. I think the new option is great, but why is it suddenly the default?
Yes, I knew it'd annoy some existing users like you :) But I hoped it'd be useful for new and (at least, some of) old users to see children/ cumulative overheads by default. If it lies under an option, it wouldn't have a chance to be used by normal users who simply run perf record and report most of time.
If you think it's entirely useless for you cases, you can set it to off using ~/.perfconfig file:
[report]
children = false
Thanks,
Namhyung
Re: [PATCH 22/27] perf tools: Enable --children option by default
Hi,
Quoted 17 lines · Namhyung Kim
Quoted 11 lines · Andres Freund
Quoted 9 lines · Namhyung Kim
Now perf top and perf report will show children column by default if it has callchain information.
Requested-by Ingo Molnar <[email protected]>Tested-by Rodrigo Campos <[email protected]>Tested-by Arun Sharma <[email protected]>Acked-by Jiri Olsa <[email protected]>Cc Frederic Weisbecker <[email protected]>Signed-off-by Namhyung Kim <[email protected]>Quoted 4 lines
Stupid question: Why? This breaks user's usage pattern in a rather significant way because the new output is pretty much entirely useless in many cases, especially for userland programs. I think the new option is great, but why is it suddenly the default?
Quoted 5 lines
Yes, I knew it'd annoy some existing users like you :) But I hoped it'd be useful for new and (at least, some of) old users to see children/ cumulative overheads by default. If it lies under an option, it wouldn't have a chance to be used by normal users who simply run perf record and report most of time.
By that argument every new feature would need to be enabled by default. Which normally isn't what happens.
Quoted 5 lines
If you think it's entirely useless for you cases, you can set it to off using ~/.perfconfig file:
[report]
children = false
Already done that ;).
The problem is still that I can't use --no-children on older systems, so I can't write benchmarking scripts anymore that don't take depend on the perf version...
I guess it's too late to argue effectively though :)
Greetings,
Andres Freund
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 22/27] perf tools: Enable --children option by default
Em Tue, Jul 29, 2014 at 01:45:48PM +0200, Andres Freund escreveu:
Quoted 2 lines · Namhyung Kim
Quoted 1 line
Yes, I knew it'd annoy some existing users like you :)
And me :-)
Quoted 8 lines
Quoted 4 lines
But I hoped it'd be useful for new and (at least, some of) old users to see children/ cumulative overheads by default. If it lies under an option, it wouldn't have a chance to be used by normal users who simply run perf record and report most of time.
By that argument every new feature would need to be enabled by default. Which normally isn't what happens.
Quoted 7 lines
Quoted 5 lines
If you think it's entirely useless for you cases, you can set it to off using ~/.perfconfig file:
[report]
children = falseAlready done that ;).
:-)
Quoted 5 lines
The problem is still that I can't use --no-children on older systems, so I can't write benchmarking scripts anymore that don't take depend on the perf version...
I guess it's too late to argue effectively though :)
yeah, changing the output people are used to in such a big way is not nice.
Perhaps next time we should instead present a dialog box at 'perf report' start allowing people to opt-in, having a nice explanation about why one would want to switch the default while alowing people to say:
[x] No, Thanks
- Arnaldo
Namhyung Kim
maintainerRe: [PATCH 22/27] perf tools: Enable --children option by default
In reply to Andres FreundHi Andres,
Quoted 18 lines · Andres Freund
Quoted 17 lines · Namhyung Kim
Quoted 15 lines · Andres Freund
Quoted 9 lines · Namhyung Kim
Now perf top and perf report will show children column by default if it has callchain information.
Requested-by Ingo Molnar <[email protected]>Tested-by Rodrigo Campos <[email protected]>Tested-by Arun Sharma <[email protected]>Acked-by Jiri Olsa <[email protected]>Cc Frederic Weisbecker <[email protected]>Signed-off-by Namhyung Kim <[email protected]>Stupid question: Why? This breaks user's usage pattern in a rather significant way because the new output is pretty much entirely useless in many cases, especially for userland programs. I think the new option is great, but why is it suddenly the default?
Quoted 8 lines
Quoted 5 lines
Yes, I knew it'd annoy some existing users like you :) But I hoped it'd be useful for new and (at least, some of) old users to see children/ cumulative overheads by default. If it lies under an option, it wouldn't have a chance to be used by normal users who simply run perf record and report most of time.
By that argument every new feature would need to be enabled by default. Which normally isn't what happens.
Yes, I know and that's what we usually do. What I wanted to say was it's a special case. :)
Quoted 8 lines
Quoted 6 lines
If you think it's entirely useless for you cases, you can set it to off using ~/.perfconfig file:
[report]
children = falseAlready done that ;).
Good. :)
Quoted 4 lines
The problem is still that I can't use --no-children on older systems, so I can't write benchmarking scripts anymore that don't take depend on the perf version...
Hmm.. I don't understand what's your problem. If you set the config option you don't need to use --no-children at all and it'd work in a same way for old and new versions, no?
Quoted 2 lines
I guess it's too late to argue effectively though :)
Well, I think it can be changed later, if enough number of users yell at me - now I have two. :)
Thanks,
Namhyung
Namhyung Kim
maintainerPATCH 23/27 perf ui/stdio: Fix invalid percentage value of cumulated hist entries
In reply to Namhyung KimOn stdio, there's a problem that it shows invalid values for callchains in cumulated hist entries. It's because it only cares about the self period. But with --children behavior, we always add callchain info to the cumulated entries so it should use the value in that case.
Before:
# Children Self Command Shared Object Symbol
# ........ ........ ....... ................. ................
#
61.22% 0.32% swapper [kernel.kallsyms] [k] cpu_idle
|
--- cpu_idle
|
|--16530.76%-- start_secondary
|
|--2758.70%-- rest_init
| start_kernel
| x86_64_start_reservations
| x86_64_start_kernel
--6837850969203030.00%-- [...]After:
# Children Self Command Shared Object Symbol
# ........ ........ ....... ................. ................
#
61.22% 0.32% swapper [kernel.kallsyms] [k] cpu_idle
|
--- cpu_idle
|
|--85.70%-- start_secondary
|
--14.30%-- rest_init
start_kernel
x86_64_start_reservations
x86_64_start_kernel--- tools/perf/ui/stdio/hist.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/ui/stdio/hist.c +3 -1
@@ -271,7 +271,9 @@ 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->stat.period, +return callchain__fprintf_graph (fp, &he->sorted_chain, + symbol_conf.cumulate_callchain ? + he->stat_acc->period : he->stat.period, left_margin);break ;case CHAIN_GRAPH_ABS :
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf ui/stdio: Fix invalid percentage value of cumulated hist entries
perf ui/stdio: Fix invalid percentage value of cumulated hist entries
Commit-ID: 56772ad4750e23460a4b80f7ece5377d8c922ee1 Gitweb: http://git.kernel.org/tip/56772ad4750e23460a4b80f7ece5377d8c922ee1 Author: Namhyung Kim <[email protected]> AuthorDate: Fri, 23 May 2014 18:31:52 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:09 +0200
perf ui/stdio: Fix invalid percentage value of cumulated hist entries
On stdio, there's a problem that it shows invalid values for callchains in cumulated hist entries. It's because it only cares about the self period. But with --children behavior, we always add callchain info to the cumulated entries so it should use the value in that case.
Before:
# Children Self Command Shared Object Symbol
# ........ ........ ....... ................. ................
#
61.22% 0.32% swapper [kernel.kallsyms] [k] cpu_idle
|
--- cpu_idle
|
|--16530.76%-- start_secondary
|
|--2758.70%-- rest_init
| start_kernel
| x86_64_start_reservations
| x86_64_start_kernel
--6837850969203030.00%-- [...]After:
# Children Self Command Shared Object Symbol
# ........ ........ ....... ................. ................
#
61.22% 0.32% swapper [kernel.kallsyms] [k] cpu_idle
|
--- cpu_idle
|
|--85.70%-- start_secondary
|
--14.30%-- rest_init
start_kernel
x86_64_start_reservations
x86_64_start_kernel--- tools/perf/ui/stdio/hist.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/ui/stdio/hist.c +3 -1
@@ -271,7 +271,9 @@ 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->stat.period, +return callchain__fprintf_graph (fp, &he->sorted_chain, + symbol_conf.cumulate_callchain ? + he->stat_acc->period : he->stat.period, left_margin);break ;case CHAIN_GRAPH_ABS :
Namhyung Kim
maintainerPATCH 24/27 perf ui/gtk: Fix callchain display
In reply to Namhyung KimWith current output field change, GTK browser cannot display callchain information correctly since it couldn't determine where the symbol column is. This is a problem - just for now I changed to use the last column since it'll work for most cases.
Also it has a same problem of the percentage as stdio code.
--- tools/perf/ui/gtk/hists.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
tools/perf/ui/gtk/hists.c +9 -1
@@ -198,6 +198,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,if (perf_hpp__should_skip (fmt))continue ; +/* +* XXX no way to determine where symcol column is.. +* Just use last column for now. +*/ +if (perf_hpp__is_sort_entry (fmt)) + sym_col = col_idx; + fmt->header (fmt, &hpp,hists_to_evsel (hists)); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
@@ -253,7 +260,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,if (symbol_conf.use_callchain && sort__has_sym) {if (callchain_param.mode ==CHAIN_GRAPH_REL ) - total = h->stat.period; + total = symbol_conf.cumulate_callchain ? + h->stat_acc->period : h->stat.period;perf_gtk__add_callchain (&h->sorted_chain, store, &iter, sym_col, total);
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf ui/gtk: Fix callchain display
perf ui/gtk: Fix callchain display
Commit-ID: e4cf6f886f3158061fb589df9ed452f9b30f67f1 Gitweb: http://git.kernel.org/tip/e4cf6f886f3158061fb589df9ed452f9b30f67f1 Author: Namhyung Kim <[email protected]> AuthorDate: Fri, 23 May 2014 18:49:33 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:09 +0200
perf ui/gtk: Fix callchain display
With current output field change, GTK browser cannot display callchain information correctly since it couldn't determine where the symbol column is. This is a problem - just for now I changed to use the last column since it'll work for most cases.
Also it has a same problem of the percentage as stdio code.
--- tools/perf/ui/gtk/hists.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
tools/perf/ui/gtk/hists.c +9 -1
@@ -198,6 +198,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,if (perf_hpp__should_skip (fmt))continue ; +/* +* XXX no way to determine where symcol column is.. +* Just use last column for now. +*/ +if (perf_hpp__is_sort_entry (fmt)) + sym_col = col_idx; + fmt->header (fmt, &hpp,hists_to_evsel (hists)); gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
@@ -253,7 +260,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,if (symbol_conf.use_callchain && sort__has_sym) {if (callchain_param.mode ==CHAIN_GRAPH_REL ) - total = h->stat.period; + total = symbol_conf.cumulate_callchain ? + h->stat_acc->period : h->stat.period;perf_gtk__add_callchain (&h->sorted_chain, store, &iter, sym_col, total);
Namhyung Kim
maintainerPATCH 25/27 perf tools: Reset output/sort order to default
In reply to Namhyung KimWhen reset_output_field() is called, also reset field/sort order to NULL so that it can have the default values. It's needed for testing.
--- tools/perf/util/sort.c | 3 +++ 1 file changed, 3 insertions(+)
tools/perf/util/sort.c +3 -0
@@ -1582,6 +1582,9 @@ void reset_output_field(void) sort__has_sym =0 ; sort__has_dso =0 ; + field_order =NULL ; + sort_order =NULL ; +reset_dimensions ();perf_hpp__reset_output_field (); }
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf tools: Reset output/sort order to default
perf tools: Reset output/sort order to default
Commit-ID: d69b2962a0aebd431cdda939f4418dd606e2f77e Gitweb: http://git.kernel.org/tip/d69b2962a0aebd431cdda939f4418dd606e2f77e Author: Namhyung Kim <[email protected]> AuthorDate: Fri, 23 May 2014 10:59:01 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:10 +0200
perf tools: Reset output/sort order to default
When reset_output_field() is called, also reset field/sort order to NULL so that it can have the default values. It's needed for testing.
--- tools/perf/util/sort.c | 3 +++ 1 file changed, 3 insertions(+)
tools/perf/util/sort.c +3 -0
@@ -1582,6 +1582,9 @@ void reset_output_field(void) sort__has_sym =0 ; sort__has_dso =0 ; + field_order =NULL ; + sort_order =NULL ; +reset_dimensions ();perf_hpp__reset_output_field (); }
Namhyung Kim
maintainerPATCH 26/27 perf tests: Define and use symbolic names for fake symbols
In reply to Namhyung KimIn various histogram test cases, fake symbols are used as raw numbers. Define macros for each pid, map, symbols so that it can increase readability somewhat.
--- tools/perf/tests/hists_common.c | 47 ++++++++++++++++++++++------------------- tools/perf/tests/hists_common.h | 32 ++++++++++++++++++++++++++-- tools/perf/tests/hists_filter.c | 23 ++++++++++---------- tools/perf/tests/hists_link.c | 32 ++++++++++++++-------------- tools/perf/tests/hists_output.c | 20 +++++++++--------- 5 files changed, 92 insertions(+), 62 deletions(-)
tools/perf/tests/hists_common.c +25 -22
@@ -12,9 +12,9 @@ static struct {u32 pid;const char *comm; } fake_threads[] = { - { 100, "perf" }, - { 200, "perf" }, - { 300, "bash" }, + { FAKE_PID_PERF1, "perf" }, + { FAKE_PID_PERF2, "perf" }, + { FAKE_PID_BASH, "bash" }, }; static struct {
@@ -22,15 +22,15 @@ static struct {u64 start;const char *filename; } fake_mmap_info[] = { - { 100, 0x40000, "perf" }, - { 100, 0x50000, "libc" }, - { 100, 0xf0000, "[kernel]" }, - { 200, 0x40000, "perf" }, - { 200, 0x50000, "libc" }, - { 200, 0xf0000, "[kernel]" }, - { 300, 0x40000, "bash" }, - { 300, 0x50000, "libc" }, - { 300, 0xf0000, "[kernel]" }, + { FAKE_PID_PERF1, FAKE_MAP_PERF, "perf" }, + { FAKE_PID_PERF1, FAKE_MAP_LIBC, "libc" }, + { FAKE_PID_PERF1, FAKE_MAP_KERNEL, "[kernel]" }, + { FAKE_PID_PERF2, FAKE_MAP_PERF, "perf" }, + { FAKE_PID_PERF2, FAKE_MAP_LIBC, "libc" }, + { FAKE_PID_PERF2, FAKE_MAP_KERNEL, "[kernel]" }, + { FAKE_PID_BASH, FAKE_MAP_BASH, "bash" }, + { FAKE_PID_BASH, FAKE_MAP_LIBC, "libc" }, + { FAKE_PID_BASH, FAKE_MAP_KERNEL, "[kernel]" }, }; struct fake_sym {
@@ -40,27 +40,30 @@ struct fake_sym { };static struct fake_sym perf_syms[] = { - {700 ,100 ,"main" }, - {800 ,100 ,"run_command" }, - {900 ,100 ,"cmd_record" }, + {FAKE_SYM_OFFSET1 ,FAKE_SYM_LENGTH ,"main" }, + {FAKE_SYM_OFFSET2 ,FAKE_SYM_LENGTH ,"run_command" }, + {FAKE_SYM_OFFSET3 ,FAKE_SYM_LENGTH ,"cmd_record" }, };static struct fake_sym bash_syms[] = { - {700 ,100 ,"main" }, - {800 ,100 ,"xmalloc" }, - {900 ,100 ,"xfree" }, + {FAKE_SYM_OFFSET1 ,FAKE_SYM_LENGTH ,"main" }, + {FAKE_SYM_OFFSET2 ,FAKE_SYM_LENGTH ,"xmalloc" }, + {FAKE_SYM_OFFSET3 ,FAKE_SYM_LENGTH ,"xfree" }, };static struct fake_sym libc_syms[] = { {700 ,100 ,"malloc" }, {800 ,100 ,"free" }, {900 ,100 ,"realloc" }, + {FAKE_SYM_OFFSET1 ,FAKE_SYM_LENGTH ,"malloc" }, + {FAKE_SYM_OFFSET2 ,FAKE_SYM_LENGTH ,"free" }, + {FAKE_SYM_OFFSET3 ,FAKE_SYM_LENGTH ,"realloc" }, };static struct fake_sym kernel_syms[] = { - {700 ,100 ,"schedule" }, - {800 ,100 ,"page_fault" }, - {900 ,100 ,"sys_perf_event_open" }, + {FAKE_SYM_OFFSET1 ,FAKE_SYM_LENGTH ,"schedule" }, + {FAKE_SYM_OFFSET2 ,FAKE_SYM_LENGTH ,"page_fault" }, + {FAKE_SYM_OFFSET3 ,FAKE_SYM_LENGTH ,"sys_perf_event_open" }, }; static struct {
@@ -102,7 +105,7 @@ struct machine *setup_fake_machine(struct machines *machines) .pid = fake_mmap_info[i].pid, .tid = fake_mmap_info[i].pid, .start = fake_mmap_info[i].start, - .len = 0x1000ULL, + .len = FAKE_MAP_LENGTH, .pgoff = 0ULL, }, };
tools/perf/tests/hists_common.h +30 -2
@@ -4,6 +4,34 @@struct machine ;struct machines ; +#define FAKE_PID_PERF1 100 +#define FAKE_PID_PERF2 200 +#define FAKE_PID_BASH 300 + +#define FAKE_MAP_PERF 0x400000 +#define FAKE_MAP_BASH 0x400000 +#define FAKE_MAP_LIBC 0x500000 +#define FAKE_MAP_KERNEL 0xf00000 +#define FAKE_MAP_LENGTH 0x100000 + +#define FAKE_SYM_OFFSET1 700 +#define FAKE_SYM_OFFSET2 800 +#define FAKE_SYM_OFFSET3 900 +#define FAKE_SYM_LENGTH 100 + +#define FAKE_IP_PERF_MAIN FAKE_MAP_PERF + FAKE_SYM_OFFSET1 +#define FAKE_IP_PERF_RUN_COMMAND FAKE_MAP_PERF + FAKE_SYM_OFFSET2 +#define FAKE_IP_PERF_CMD_RECORD FAKE_MAP_PERF + FAKE_SYM_OFFSET3 +#define FAKE_IP_BASH_MAIN FAKE_MAP_BASH + FAKE_SYM_OFFSET1 +#define FAKE_IP_BASH_XMALLOC FAKE_MAP_BASH + FAKE_SYM_OFFSET2 +#define FAKE_IP_BASH_XFREE FAKE_MAP_BASH + FAKE_SYM_OFFSET3 +#define FAKE_IP_LIBC_MALLOC FAKE_MAP_LIBC + FAKE_SYM_OFFSET1 +#define FAKE_IP_LIBC_FREE FAKE_MAP_LIBC + FAKE_SYM_OFFSET2 +#define FAKE_IP_LIBC_REALLOC FAKE_MAP_LIBC + FAKE_SYM_OFFSET3 +#define FAKE_IP_KERNEL_SCHEDULE FAKE_MAP_KERNEL + FAKE_SYM_OFFSET1 +#define FAKE_IP_KERNEL_PAGE_FAULT FAKE_MAP_KERNEL + FAKE_SYM_OFFSET2 +#define FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN FAKE_MAP_KERNEL + FAKE_SYM_OFFSET3 +/* * The setup_fake_machine() provides a test environment which consists * of 3 processes that have 3 mappings and in turn, have 3 symbols
@@ -13,7 +41,7 @@ struct machines;* ............. ............. ................... * perf: 100 perf main * perf: 100 perf run_command -* perf: 100 perf comd_record +* perf: 100 perf cmd_record * perf: 100 libc malloc * perf: 100 libc free * perf: 100 libc realloc
@@ -22,7 +50,7 @@ struct machines;* perf: 100 [kernel] sys_perf_event_open * perf: 200 perf main * perf: 200 perf run_command -* perf: 200 perf comd_record +* perf: 200 perf cmd_record * perf: 200 libc malloc * perf: 200 libc free * perf: 200 libc realloc
tools/perf/tests/hists_filter.c +11 -12
@@ -21,25 +21,25 @@ struct sample {/* For the numbers, see hists_common.c */ static struct sample fake_samples[] = {/* perf [kernel] schedule() */ - { .pid =100 , .ip =0xf0000 +700 , }, + { .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_KERNEL_SCHEDULE , },/* perf [perf] main() */ - { .pid =100 , .ip =0x40000 +700 , }, + { .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_PERF_MAIN , },/* perf [libc] malloc() */ - { .pid =100 , .ip =0x50000 +700 , }, + { .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_LIBC_MALLOC , },/* perf [perf] main() */ - { .pid =200 , .ip =0x40000 +700 , },/* will be merged */ + { .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_PERF_MAIN , },/* will be merged */ /* perf [perf] cmd_record() */ - { .pid =200 , .ip =0x40000 +900 , }, + { .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_PERF_CMD_RECORD , },/* perf [kernel] page_fault() */ - { .pid =200 , .ip =0xf0000 +800 , }, + { .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_KERNEL_PAGE_FAULT , },/* bash [bash] main() */ - { .pid =300 , .ip =0x40000 +700 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_BASH_MAIN , },/* bash [bash] xmalloc() */ - { .pid =300 , .ip =0x40000 +800 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_BASH_XMALLOC , },/* bash [libc] malloc() */ - { .pid =300 , .ip =0x50000 +700 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_LIBC_MALLOC , },/* bash [kernel] page_fault() */ - { .pid =300 , .ip =0xf0000 +800 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_KERNEL_PAGE_FAULT , }, }; static int add_hist_entries(struct perf_evlist *evlist,
@@ -47,7 +47,7 @@ static int add_hist_entries(struct perf_evlist *evlist, {struct perf_evsel *evsel;struct addr_location al; -struct perf_sample sample = { .cpu =0 , }; +struct perf_sample sample = { .period =100 , };size_t i;/*
@@ -75,7 +75,6 @@ static int add_hist_entries(struct perf_evlist *evlist, sample.pid = fake_samples[i].pid; sample.tid = fake_samples[i].pid; sample.ip = fake_samples[i].ip; - sample.period =100 ;if (perf_event__preprocess_sample (&event, machine, &al, &sample) <0 )
tools/perf/tests/hists_link.c +16 -16
@@ -21,41 +21,41 @@ struct sample {/* For the numbers, see hists_common.c */ static struct sample fake_common_samples[] = {/* perf [kernel] schedule() */ - { .pid =100 , .ip =0xf0000 +700 , }, + { .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_KERNEL_SCHEDULE , },/* perf [perf] main() */ - { .pid =200 , .ip =0x40000 +700 , }, + { .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_PERF_MAIN , },/* perf [perf] cmd_record() */ - { .pid =200 , .ip =0x40000 +900 , }, + { .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_PERF_CMD_RECORD , },/* bash [bash] xmalloc() */ - { .pid =300 , .ip =0x40000 +800 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_BASH_XMALLOC , },/* bash [libc] malloc() */ - { .pid =300 , .ip =0x50000 +700 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_LIBC_MALLOC , }, };static struct sample fake_samples[][5 ] = { {/* perf [perf] run_command() */ - { .pid =100 , .ip =0x40000 +800 , }, + { .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_PERF_RUN_COMMAND , },/* perf [libc] malloc() */ - { .pid =100 , .ip =0x50000 +700 , }, + { .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_LIBC_MALLOC , },/* perf [kernel] page_fault() */ - { .pid =100 , .ip =0xf0000 +800 , }, + { .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_KERNEL_PAGE_FAULT , },/* perf [kernel] sys_perf_event_open() */ - { .pid =200 , .ip =0xf0000 +900 , }, + { .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN , },/* bash [libc] free() */ - { .pid =300 , .ip =0x50000 +800 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_LIBC_FREE , }, }, {/* perf [libc] free() */ - { .pid =200 , .ip =0x50000 +800 , }, + { .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_LIBC_FREE , },/* bash [libc] malloc() */ - { .pid =300 , .ip =0x50000 +700 , },/* will be merged */ + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_LIBC_MALLOC , },/* will be merged */ /* bash [bash] xfee() */ - { .pid =300 , .ip =0x40000 +900 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_BASH_XFREE , },/* bash [libc] realloc() */ - { .pid =300 , .ip =0x50000 +900 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_LIBC_REALLOC , },/* bash [kernel] page_fault() */ - { .pid =300 , .ip =0xf0000 +800 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_KERNEL_PAGE_FAULT , }, }, };
@@ -64,7 +64,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)struct perf_evsel *evsel;struct addr_location al;struct hist_entry *he; -struct perf_sample sample = { .cpu =0 , }; +struct perf_sample sample = { .period =1 , };size_t i =0 , k;/*
tools/perf/tests/hists_output.c +10 -10
@@ -22,25 +22,25 @@ struct sample {/* For the numbers, see hists_common.c */ static struct sample fake_samples[] = {/* perf [kernel] schedule() */ - { .cpu =0 , .pid =100 , .ip =0xf0000 +700 , }, + { .cpu =0 , .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_KERNEL_SCHEDULE , },/* perf [perf] main() */ - { .cpu =1 , .pid =100 , .ip =0x40000 +700 , }, + { .cpu =1 , .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_PERF_MAIN , },/* perf [perf] cmd_record() */ - { .cpu =1 , .pid =100 , .ip =0x40000 +900 , }, + { .cpu =1 , .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_PERF_CMD_RECORD , },/* perf [libc] malloc() */ - { .cpu =1 , .pid =100 , .ip =0x50000 +700 , }, + { .cpu =1 , .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_LIBC_MALLOC , },/* perf [libc] free() */ - { .cpu =2 , .pid =100 , .ip =0x50000 +800 , }, + { .cpu =2 , .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_LIBC_FREE , },/* perf [perf] main() */ - { .cpu =2 , .pid =200 , .ip =0x40000 +700 , }, + { .cpu =2 , .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_PERF_MAIN , },/* perf [kernel] page_fault() */ - { .cpu =2 , .pid =200 , .ip =0xf0000 +800 , }, + { .cpu =2 , .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_KERNEL_PAGE_FAULT , },/* bash [bash] main() */ - { .cpu =3 , .pid =300 , .ip =0x40000 +700 , }, + { .cpu =3 , .pid =FAKE_PID_BASH , .ip =FAKE_IP_BASH_MAIN , },/* bash [bash] xmalloc() */ - { .cpu =0 , .pid =300 , .ip =0x40000 +800 , }, + { .cpu =0 , .pid =FAKE_PID_BASH , .ip =FAKE_IP_BASH_XMALLOC , },/* bash [kernel] page_fault() */ - { .cpu =1 , .pid =300 , .ip =0xf0000 +800 , }, + { .cpu =1 , .pid =FAKE_PID_BASH , .ip =FAKE_IP_KERNEL_PAGE_FAULT , }, };static int add_hist_entries (struct hists *hists,struct machine *machine)
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf tests: Define and use symbolic names for fake symbols
perf tests: Define and use symbolic names for fake symbols
Commit-ID: a1891aa4805fa77d98db44ec6e1d93e2921828fb Gitweb: http://git.kernel.org/tip/a1891aa4805fa77d98db44ec6e1d93e2921828fb Author: Namhyung Kim <[email protected]> AuthorDate: Fri, 23 May 2014 14:59:57 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:11 +0200
perf tests: Define and use symbolic names for fake symbols
In various histogram test cases, fake symbols are used as raw numbers. Define macros for each pid, map, symbols so that it can increase readability somewhat.
--- tools/perf/tests/hists_common.c | 47 ++++++++++++++++++++++------------------- tools/perf/tests/hists_common.h | 32 ++++++++++++++++++++++++++-- tools/perf/tests/hists_filter.c | 23 ++++++++++---------- tools/perf/tests/hists_link.c | 32 ++++++++++++++-------------- tools/perf/tests/hists_output.c | 20 +++++++++--------- 5 files changed, 92 insertions(+), 62 deletions(-)
tools/perf/tests/hists_common.c +25 -22
@@ -12,9 +12,9 @@ static struct {u32 pid;const char *comm; } fake_threads[] = { - { 100, "perf" }, - { 200, "perf" }, - { 300, "bash" }, + { FAKE_PID_PERF1, "perf" }, + { FAKE_PID_PERF2, "perf" }, + { FAKE_PID_BASH, "bash" }, }; static struct {
@@ -22,15 +22,15 @@ static struct {u64 start;const char *filename; } fake_mmap_info[] = { - { 100, 0x40000, "perf" }, - { 100, 0x50000, "libc" }, - { 100, 0xf0000, "[kernel]" }, - { 200, 0x40000, "perf" }, - { 200, 0x50000, "libc" }, - { 200, 0xf0000, "[kernel]" }, - { 300, 0x40000, "bash" }, - { 300, 0x50000, "libc" }, - { 300, 0xf0000, "[kernel]" }, + { FAKE_PID_PERF1, FAKE_MAP_PERF, "perf" }, + { FAKE_PID_PERF1, FAKE_MAP_LIBC, "libc" }, + { FAKE_PID_PERF1, FAKE_MAP_KERNEL, "[kernel]" }, + { FAKE_PID_PERF2, FAKE_MAP_PERF, "perf" }, + { FAKE_PID_PERF2, FAKE_MAP_LIBC, "libc" }, + { FAKE_PID_PERF2, FAKE_MAP_KERNEL, "[kernel]" }, + { FAKE_PID_BASH, FAKE_MAP_BASH, "bash" }, + { FAKE_PID_BASH, FAKE_MAP_LIBC, "libc" }, + { FAKE_PID_BASH, FAKE_MAP_KERNEL, "[kernel]" }, }; struct fake_sym {
@@ -40,27 +40,30 @@ struct fake_sym { };static struct fake_sym perf_syms[] = { - {700 ,100 ,"main" }, - {800 ,100 ,"run_command" }, - {900 ,100 ,"cmd_record" }, + {FAKE_SYM_OFFSET1 ,FAKE_SYM_LENGTH ,"main" }, + {FAKE_SYM_OFFSET2 ,FAKE_SYM_LENGTH ,"run_command" }, + {FAKE_SYM_OFFSET3 ,FAKE_SYM_LENGTH ,"cmd_record" }, };static struct fake_sym bash_syms[] = { - {700 ,100 ,"main" }, - {800 ,100 ,"xmalloc" }, - {900 ,100 ,"xfree" }, + {FAKE_SYM_OFFSET1 ,FAKE_SYM_LENGTH ,"main" }, + {FAKE_SYM_OFFSET2 ,FAKE_SYM_LENGTH ,"xmalloc" }, + {FAKE_SYM_OFFSET3 ,FAKE_SYM_LENGTH ,"xfree" }, };static struct fake_sym libc_syms[] = { {700 ,100 ,"malloc" }, {800 ,100 ,"free" }, {900 ,100 ,"realloc" }, + {FAKE_SYM_OFFSET1 ,FAKE_SYM_LENGTH ,"malloc" }, + {FAKE_SYM_OFFSET2 ,FAKE_SYM_LENGTH ,"free" }, + {FAKE_SYM_OFFSET3 ,FAKE_SYM_LENGTH ,"realloc" }, };static struct fake_sym kernel_syms[] = { - {700 ,100 ,"schedule" }, - {800 ,100 ,"page_fault" }, - {900 ,100 ,"sys_perf_event_open" }, + {FAKE_SYM_OFFSET1 ,FAKE_SYM_LENGTH ,"schedule" }, + {FAKE_SYM_OFFSET2 ,FAKE_SYM_LENGTH ,"page_fault" }, + {FAKE_SYM_OFFSET3 ,FAKE_SYM_LENGTH ,"sys_perf_event_open" }, }; static struct {
@@ -102,7 +105,7 @@ struct machine *setup_fake_machine(struct machines *machines) .pid = fake_mmap_info[i].pid, .tid = fake_mmap_info[i].pid, .start = fake_mmap_info[i].start, - .len = 0x1000ULL, + .len = FAKE_MAP_LENGTH, .pgoff = 0ULL, }, };
tools/perf/tests/hists_common.h +30 -2
@@ -4,6 +4,34 @@struct machine ;struct machines ; +#define FAKE_PID_PERF1 100 +#define FAKE_PID_PERF2 200 +#define FAKE_PID_BASH 300 + +#define FAKE_MAP_PERF 0x400000 +#define FAKE_MAP_BASH 0x400000 +#define FAKE_MAP_LIBC 0x500000 +#define FAKE_MAP_KERNEL 0xf00000 +#define FAKE_MAP_LENGTH 0x100000 + +#define FAKE_SYM_OFFSET1 700 +#define FAKE_SYM_OFFSET2 800 +#define FAKE_SYM_OFFSET3 900 +#define FAKE_SYM_LENGTH 100 + +#define FAKE_IP_PERF_MAIN FAKE_MAP_PERF + FAKE_SYM_OFFSET1 +#define FAKE_IP_PERF_RUN_COMMAND FAKE_MAP_PERF + FAKE_SYM_OFFSET2 +#define FAKE_IP_PERF_CMD_RECORD FAKE_MAP_PERF + FAKE_SYM_OFFSET3 +#define FAKE_IP_BASH_MAIN FAKE_MAP_BASH + FAKE_SYM_OFFSET1 +#define FAKE_IP_BASH_XMALLOC FAKE_MAP_BASH + FAKE_SYM_OFFSET2 +#define FAKE_IP_BASH_XFREE FAKE_MAP_BASH + FAKE_SYM_OFFSET3 +#define FAKE_IP_LIBC_MALLOC FAKE_MAP_LIBC + FAKE_SYM_OFFSET1 +#define FAKE_IP_LIBC_FREE FAKE_MAP_LIBC + FAKE_SYM_OFFSET2 +#define FAKE_IP_LIBC_REALLOC FAKE_MAP_LIBC + FAKE_SYM_OFFSET3 +#define FAKE_IP_KERNEL_SCHEDULE FAKE_MAP_KERNEL + FAKE_SYM_OFFSET1 +#define FAKE_IP_KERNEL_PAGE_FAULT FAKE_MAP_KERNEL + FAKE_SYM_OFFSET2 +#define FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN FAKE_MAP_KERNEL + FAKE_SYM_OFFSET3 +/* * The setup_fake_machine() provides a test environment which consists * of 3 processes that have 3 mappings and in turn, have 3 symbols
@@ -13,7 +41,7 @@ struct machines;* ............. ............. ................... * perf: 100 perf main * perf: 100 perf run_command -* perf: 100 perf comd_record +* perf: 100 perf cmd_record * perf: 100 libc malloc * perf: 100 libc free * perf: 100 libc realloc
@@ -22,7 +50,7 @@ struct machines;* perf: 100 [kernel] sys_perf_event_open * perf: 200 perf main * perf: 200 perf run_command -* perf: 200 perf comd_record +* perf: 200 perf cmd_record * perf: 200 libc malloc * perf: 200 libc free * perf: 200 libc realloc
tools/perf/tests/hists_filter.c +11 -12
@@ -21,25 +21,25 @@ struct sample {/* For the numbers, see hists_common.c */ static struct sample fake_samples[] = {/* perf [kernel] schedule() */ - { .pid =100 , .ip =0xf0000 +700 , }, + { .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_KERNEL_SCHEDULE , },/* perf [perf] main() */ - { .pid =100 , .ip =0x40000 +700 , }, + { .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_PERF_MAIN , },/* perf [libc] malloc() */ - { .pid =100 , .ip =0x50000 +700 , }, + { .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_LIBC_MALLOC , },/* perf [perf] main() */ - { .pid =200 , .ip =0x40000 +700 , },/* will be merged */ + { .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_PERF_MAIN , },/* will be merged */ /* perf [perf] cmd_record() */ - { .pid =200 , .ip =0x40000 +900 , }, + { .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_PERF_CMD_RECORD , },/* perf [kernel] page_fault() */ - { .pid =200 , .ip =0xf0000 +800 , }, + { .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_KERNEL_PAGE_FAULT , },/* bash [bash] main() */ - { .pid =300 , .ip =0x40000 +700 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_BASH_MAIN , },/* bash [bash] xmalloc() */ - { .pid =300 , .ip =0x40000 +800 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_BASH_XMALLOC , },/* bash [libc] malloc() */ - { .pid =300 , .ip =0x50000 +700 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_LIBC_MALLOC , },/* bash [kernel] page_fault() */ - { .pid =300 , .ip =0xf0000 +800 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_KERNEL_PAGE_FAULT , }, }; static int add_hist_entries(struct perf_evlist *evlist,
@@ -47,7 +47,7 @@ static int add_hist_entries(struct perf_evlist *evlist, {struct perf_evsel *evsel;struct addr_location al; -struct perf_sample sample = { .cpu =0 , }; +struct perf_sample sample = { .period =100 , };size_t i;/*
@@ -75,7 +75,6 @@ static int add_hist_entries(struct perf_evlist *evlist, sample.pid = fake_samples[i].pid; sample.tid = fake_samples[i].pid; sample.ip = fake_samples[i].ip; - sample.period =100 ;if (perf_event__preprocess_sample (&event, machine, &al, &sample) <0 )
tools/perf/tests/hists_link.c +16 -16
@@ -21,41 +21,41 @@ struct sample {/* For the numbers, see hists_common.c */ static struct sample fake_common_samples[] = {/* perf [kernel] schedule() */ - { .pid =100 , .ip =0xf0000 +700 , }, + { .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_KERNEL_SCHEDULE , },/* perf [perf] main() */ - { .pid =200 , .ip =0x40000 +700 , }, + { .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_PERF_MAIN , },/* perf [perf] cmd_record() */ - { .pid =200 , .ip =0x40000 +900 , }, + { .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_PERF_CMD_RECORD , },/* bash [bash] xmalloc() */ - { .pid =300 , .ip =0x40000 +800 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_BASH_XMALLOC , },/* bash [libc] malloc() */ - { .pid =300 , .ip =0x50000 +700 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_LIBC_MALLOC , }, };static struct sample fake_samples[][5 ] = { {/* perf [perf] run_command() */ - { .pid =100 , .ip =0x40000 +800 , }, + { .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_PERF_RUN_COMMAND , },/* perf [libc] malloc() */ - { .pid =100 , .ip =0x50000 +700 , }, + { .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_LIBC_MALLOC , },/* perf [kernel] page_fault() */ - { .pid =100 , .ip =0xf0000 +800 , }, + { .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_KERNEL_PAGE_FAULT , },/* perf [kernel] sys_perf_event_open() */ - { .pid =200 , .ip =0xf0000 +900 , }, + { .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN , },/* bash [libc] free() */ - { .pid =300 , .ip =0x50000 +800 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_LIBC_FREE , }, }, {/* perf [libc] free() */ - { .pid =200 , .ip =0x50000 +800 , }, + { .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_LIBC_FREE , },/* bash [libc] malloc() */ - { .pid =300 , .ip =0x50000 +700 , },/* will be merged */ + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_LIBC_MALLOC , },/* will be merged */ /* bash [bash] xfee() */ - { .pid =300 , .ip =0x40000 +900 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_BASH_XFREE , },/* bash [libc] realloc() */ - { .pid =300 , .ip =0x50000 +900 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_LIBC_REALLOC , },/* bash [kernel] page_fault() */ - { .pid =300 , .ip =0xf0000 +800 , }, + { .pid =FAKE_PID_BASH , .ip =FAKE_IP_KERNEL_PAGE_FAULT , }, }, };
@@ -64,7 +64,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)struct perf_evsel *evsel;struct addr_location al;struct hist_entry *he; -struct perf_sample sample = { .cpu =0 , }; +struct perf_sample sample = { .period =1 , };size_t i =0 , k;/*
tools/perf/tests/hists_output.c +10 -10
@@ -22,25 +22,25 @@ struct sample {/* For the numbers, see hists_common.c */ static struct sample fake_samples[] = {/* perf [kernel] schedule() */ - { .cpu =0 , .pid =100 , .ip =0xf0000 +700 , }, + { .cpu =0 , .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_KERNEL_SCHEDULE , },/* perf [perf] main() */ - { .cpu =1 , .pid =100 , .ip =0x40000 +700 , }, + { .cpu =1 , .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_PERF_MAIN , },/* perf [perf] cmd_record() */ - { .cpu =1 , .pid =100 , .ip =0x40000 +900 , }, + { .cpu =1 , .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_PERF_CMD_RECORD , },/* perf [libc] malloc() */ - { .cpu =1 , .pid =100 , .ip =0x50000 +700 , }, + { .cpu =1 , .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_LIBC_MALLOC , },/* perf [libc] free() */ - { .cpu =2 , .pid =100 , .ip =0x50000 +800 , }, + { .cpu =2 , .pid =FAKE_PID_PERF1 , .ip =FAKE_IP_LIBC_FREE , },/* perf [perf] main() */ - { .cpu =2 , .pid =200 , .ip =0x40000 +700 , }, + { .cpu =2 , .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_PERF_MAIN , },/* perf [kernel] page_fault() */ - { .cpu =2 , .pid =200 , .ip =0xf0000 +800 , }, + { .cpu =2 , .pid =FAKE_PID_PERF2 , .ip =FAKE_IP_KERNEL_PAGE_FAULT , },/* bash [bash] main() */ - { .cpu =3 , .pid =300 , .ip =0x40000 +700 , }, + { .cpu =3 , .pid =FAKE_PID_BASH , .ip =FAKE_IP_BASH_MAIN , },/* bash [bash] xmalloc() */ - { .cpu =0 , .pid =300 , .ip =0x40000 +800 , }, + { .cpu =0 , .pid =FAKE_PID_BASH , .ip =FAKE_IP_BASH_XMALLOC , },/* bash [kernel] page_fault() */ - { .cpu =1 , .pid =300 , .ip =0xf0000 +800 , }, + { .cpu =1 , .pid =FAKE_PID_BASH , .ip =FAKE_IP_KERNEL_PAGE_FAULT , }, };static int add_hist_entries (struct hists *hists,struct machine *machine)
Namhyung Kim
maintainerPATCH 27/27 perf tests: Add a test case for cumulating callchains
In reply to Namhyung KimNow it adds a new testcase to verify --children option working correctly.
--- tools/perf/Makefile.perf | 1 + tools/perf/tests/builtin-test.c | 4 + tools/perf/tests/hists_common.c | 5 +- tools/perf/tests/hists_cumulate.c | 726 ++++++++++++++++++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + 5 files changed, 735 insertions(+), 2 deletions(-) create mode 100644 tools/perf/tests/hists_cumulate.c
tools/perf/Makefile.perf +1 -0
@@ -400,6 +400,7 @@ LIB_OBJS += $(OUTPUT)tests/hists_common.o LIB_OBJS += $(OUTPUT)tests/hists_link.o LIB_OBJS += $(OUTPUT)tests/hists_filter.o LIB_OBJS += $(OUTPUT)tests/hists_output.o +LIB_OBJS += $(OUTPUT)tests/hists_cumulate.o LIB_OBJS += $(OUTPUT)tests/python-use.o LIB_OBJS += $(OUTPUT)tests/bp_signal.o LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
tools/perf/tests/builtin-test.c +4 -0
@@ -140,6 +140,10 @@ static struct test { .func = test__hists_output, }, { + .desc = "Test cumulation of child hist entries", + .func = test__hists_cumulate, + }, + { .func = NULL, }, };
tools/perf/tests/hists_common.c +3 -2
@@ -196,10 +196,11 @@ void print_hists_out(struct hists *hists) he = rb_entry(node, struct hist_entry, rb_node);if (!he->filtered) { -pr_info ("%2d: entry: %8s:%5d [%-8s] %20s: period = %" PRIu64"\n" , +pr_info ("%2d: entry: %8s:%5d [%-8s] %20s: period = %" PRIu64"/%" PRIu64"\n" , i,thread__comm_str (he->thread), he->thread->tid, he->ms.map->dso->short_name, - he->ms.sym->name, he->stat.period); + he->ms.sym->name, he->stat.period, + he->stat_acc ? he->stat_acc->period :0 ); } i++;
tools/perf/tests/hists_cumulate.c new file +726 -0
726 lines not on this page · raw message
tools/perf/tests/tests.h +1 -0
@@ -45,6 +45,7 @@ int test__hists_filter(void);int test__mmap_thread_lookup (void );int test__thread_mg_share (void );int test__hists_output (void ); +int test__hists_cumulate (void );#if defined(__x86_64__) || defined(__i386__) || defined(__arm__)#ifdef HAVE_DWARF_UNWIND_SUPPORT
Signature · 1 line
1.9.2
tip-bot for Namhyung Kim
merge bot[tip:perf/core] perf tests: Add a test case for cumulating callchains
perf tests: Add a test case for cumulating callchains
Commit-ID: 0506aecce999d4370b979892f88cf1118cfe8dcb Gitweb: http://git.kernel.org/tip/0506aecce999d4370b979892f88cf1118cfe8dcb Author: Namhyung Kim <[email protected]> AuthorDate: Fri, 23 May 2014 18:04:42 +0900 Committer: Jiri Olsa <[email protected]> CommitDate: Sun, 1 Jun 2014 14:35:11 +0200
perf tests: Add a test case for cumulating callchains
Now it adds a new testcase to verify --children option working correctly.
--- tools/perf/Makefile.perf | 1 + tools/perf/tests/builtin-test.c | 4 + tools/perf/tests/hists_common.c | 5 +- tools/perf/tests/hists_cumulate.c | 726 ++++++++++++++++++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + 5 files changed, 735 insertions(+), 2 deletions(-)
tools/perf/Makefile.perf +1 -0
@@ -400,6 +400,7 @@ LIB_OBJS += $(OUTPUT)tests/hists_common.o LIB_OBJS += $(OUTPUT)tests/hists_link.o LIB_OBJS += $(OUTPUT)tests/hists_filter.o LIB_OBJS += $(OUTPUT)tests/hists_output.o +LIB_OBJS += $(OUTPUT)tests/hists_cumulate.o LIB_OBJS += $(OUTPUT)tests/python-use.o LIB_OBJS += $(OUTPUT)tests/bp_signal.o LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
tools/perf/tests/builtin-test.c +4 -0
@@ -140,6 +140,10 @@ static struct test { .func = test__hists_output, }, { + .desc = "Test cumulation of child hist entries", + .func = test__hists_cumulate, + }, + { .func = NULL, }, };
tools/perf/tests/hists_common.c +3 -2
@@ -196,10 +196,11 @@ void print_hists_out(struct hists *hists) he = rb_entry(node, struct hist_entry, rb_node);if (!he->filtered) { -pr_info ("%2d: entry: %8s:%5d [%-8s] %20s: period = %" PRIu64"\n" , +pr_info ("%2d: entry: %8s:%5d [%-8s] %20s: period = %" PRIu64"/%" PRIu64"\n" , i,thread__comm_str (he->thread), he->thread->tid, he->ms.map->dso->short_name, - he->ms.sym->name, he->stat.period); + he->ms.sym->name, he->stat.period, + he->stat_acc ? he->stat_acc->period :0 ); } i++;
tools/perf/tests/hists_cumulate.c new file +726 -0
726 lines not on this page · raw message
tools/perf/tests/tests.h +1 -0
@@ -45,6 +45,7 @@ int test__hists_filter(void);int test__mmap_thread_lookup (void );int test__thread_mg_share (void );int test__hists_output (void ); +int test__hists_cumulate (void );#if defined(__x86_64__) || defined(__i386__) || defined(__arm__)#ifdef HAVE_DWARF_UNWIND_SUPPORT
Quoted 25 lines · Namhyung Kim
Hello,
This is a new attempt to implement cumulative hist period report. This work begins from Arun's
SORT_INCLUSIVEpatch [1] but I completely rewrote it from scratch.This patchset basically adds period in a sample to every node in the callchain. A
hist_entrynow has an additional fields to keep the cumulative period if --children option is given on perf report.I changed the option as a separate --children and added a new "Children" column (and renamed the default "Overhead" column into "Self"). The output will be sorted by children (cumulative) overhead for now. It also adds '
overhead_children' field to -F/--fields option to be selected by user and it'll show you "N/A" if the cumulation is not supported (due to missing callchain).I added Tested-by from Rodrigo Campos since this version is basically rebase of previous series + bugfix. But it still needs to be tested more intensively IMHO. Also note that, this will change default behavior of perf report/top if callchain is recorded, so might confuse old users. Let's see how many of them come to shout. :) I think we need to merge Jiri's TUI column header patch at least.
Quoted 5 lines
* changes in v11:
- factor outhists__inc_nr_samples(Jiri)
- remove unrelated change (Jiri)
- disable accumulation on branch or mem mode
- slightly refactorhist_itercode
apart from that comment I sent, I think it's ready to go in
thanks,
jirka
Namhyung Kim
maintainerQuoted 26 lines · Jiri Olsa
Quoted 25 lines · Namhyung Kim
Hello,
This is a new attempt to implement cumulative hist period report. This work begins from Arun's
SORT_INCLUSIVEpatch [1] but I completely rewrote it from scratch.This patchset basically adds period in a sample to every node in the callchain. A
hist_entrynow has an additional fields to keep the cumulative period if --children option is given on perf report.I changed the option as a separate --children and added a new "Children" column (and renamed the default "Overhead" column into "Self"). The output will be sorted by children (cumulative) overhead for now. It also adds '
overhead_children' field to -F/--fields option to be selected by user and it'll show you "N/A" if the cumulation is not supported (due to missing callchain).I added Tested-by from Rodrigo Campos since this version is basically rebase of previous series + bugfix. But it still needs to be tested more intensively IMHO. Also note that, this will change default behavior of perf report/top if callchain is recorded, so might confuse old users. Let's see how many of them come to shout. :) I think we need to merge Jiri's TUI column header patch at least.
Quoted 7 lines
Quoted 5 lines
* changes in v11:
- factor outhists__inc_nr_samples(Jiri)
- remove unrelated change (Jiri)
- disable accumulation on branch or mem mode
- slightly refactorhist_itercodeapart from that comment I sent, I think it's ready to go in
Thanks! As I said, I've pushed v12 to korg with change you commented.
And I also found that the overhead in perf_hpp__should_skip() is strangely high.. will check your patch.
Thanks,
Namhyung