diff options
author | Ingo Molnar <mingo@kernel.org> | 2016-01-09 17:17:33 +0100 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-01-09 17:17:33 +0100 |
commit | 3eb9ede23bdd96e9ba60e2b4d4d17a7c35d58448 (patch) | |
tree | 2bed2ab8e7fa6e6202154992433bb24ecdb9a24d /tools/perf/util/hist.c | |
parent | 9cc2617de5b9222abb39cd02e90d57dfea99c6d7 (diff) | |
parent | 775d8a1b0d75211cc6123915c6b5b688f2002478 (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
New features:
- Allow using trace events fields as sort order keys, making 'perf evlist --trace_fields'
show those, and then the user can select a subset and use like:
perf top -e sched:sched_switch -s prev_comm,next_comm
That works as well in 'perf report' when handling files containing
tracepoints.
The default when just tracepoint events are found in a perf.data file is to
format it like ftrace, using the libtraceevent formatters, plugins, etc (Namhyung Kim)
- Add support in 'perf script' to process 'perf stat record' generated files,
culminating in a python perf script that calculates CPI (Cycles per
Instruction) (Jiri Olsa)
- Show random perf tool tips in the 'perf report' bottom line (Namhyung Kim)
- perf report now defaults to --group if the perf.data file has grouped events, try it with:
# perf record -e '{cycles,instructions}' -a sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.093 MB perf.data (1247 samples) ]
# perf report
# Samples: 1K of event 'anon group { cycles, instructions }'
# Event count (approx.): 1955219195
#
# Overhead Command Shared Object Symbol
2.86% 0.22% swapper [kernel.kallsyms] [k] intel_idle
1.05% 0.33% firefox libxul.so [.] js::SetObjectElement
1.05% 0.00% kworker/0:3 [kernel.kallsyms] [k] gen6_ring_get_seqno
0.88% 0.17% chrome chrome [.] 0x0000000000ee27ab
0.65% 0.86% firefox libxul.so [.] js::ValueToId<(js::AllowGC)1>
0.64% 0.23% JS Helper libxul.so [.] js::SplayTree<js::jit::LiveRange*, js::jit::LiveRange>::splay
0.62% 1.27% firefox libxul.so [.] js::GetIterator
0.61% 1.74% firefox libxul.so [.] js::NativeSetProperty
0.61% 0.31% firefox libxul.so [.] js::SetPropertyByDefining
User visible fixes:
- Coect data mmaps so that the DWARF unwinder can handle usecases needing them,
like softice (Jiri Olsa)
- Decay callchains in fractal mode, fixing up cases where 'perf top -g' would
show entries with more than 100% (Namhyung Kim)
Infrastructure changes:
- Sync tools/lib with the lib/ in the kernel sources for find_bit.c and
move bitmap.[ch] from tools/perf/util/ to tools/lib/ (Arnaldo Carvalho de Melo)
- No need to set attr.sample_freq in some 'perf test' entries that only
want to deal with PERF_RECORD_ meta-events, improve a bit error output
for CQM test (Arnaldo Carvalho de Melo)
- Fix python binding build, adding some missing object files now required
due to cpumap using find_bit stuff (Arnaldo Carvalho de Melo)
- tools/build improvemnts (Jiri Olsa)
- Add more files to cscope/ctags databases (Jiri Olsa)
- Do not show 'trace' in 'perf help' if it is not compiled in (Jiri Olsa)
- Make perf_evlist__open() open evsels with their cpus and threads,
like perf record does, making them consistent (Adrian Hunter)
- Fix pmu snapshot initialization bug (Stephane Eranian)
- Add missing headers in perf's MANIFEST (Wang Nan)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf/util/hist.c')
-rw-r--r-- | tools/perf/util/hist.c | 78 |
1 files changed, 56 insertions, 22 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 56e97f5af598..c226303e3da0 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -254,6 +254,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) he_stat__decay(&he->stat); if (symbol_conf.cumulate_callchain) he_stat__decay(he->stat_acc); + decay_callchain(he->callchain); diff = prev_period - he->stat.period; @@ -369,6 +370,25 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template, if (symbol_conf.use_callchain) callchain_init(he->callchain); + if (he->raw_data) { + he->raw_data = memdup(he->raw_data, he->raw_size); + + if (he->raw_data == NULL) { + map__put(he->ms.map); + if (he->branch_info) { + map__put(he->branch_info->from.map); + map__put(he->branch_info->to.map); + free(he->branch_info); + } + if (he->mem_info) { + map__put(he->mem_info->iaddr.map); + map__put(he->mem_info->daddr.map); + } + free(he->stat_acc); + free(he); + return NULL; + } + } INIT_LIST_HEAD(&he->pairs.node); thread__get(he->thread); } @@ -461,7 +481,7 @@ 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, + struct perf_sample *sample, bool sample_self) { struct hist_entry entry = { @@ -478,15 +498,17 @@ struct hist_entry *__hists__add_entry(struct hists *hists, .level = al->level, .stat = { .nr_events = 1, - .period = period, - .weight = weight, + .period = sample->period, + .weight = sample->weight, }, .parent = sym_parent, .filtered = symbol__parent_filter(sym_parent) | al->filtered, .hists = hists, .branch_info = bi, .mem_info = mi, - .transaction = transaction, + .transaction = sample->transaction, + .raw_data = sample->raw_data, + .raw_size = sample->raw_size, }; return hists__findnew_entry(hists, &entry, al, sample_self); @@ -526,12 +548,13 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al u64 cost; struct mem_info *mi = iter->priv; struct hists *hists = evsel__hists(iter->evsel); + struct perf_sample *sample = iter->sample; struct hist_entry *he; if (mi == NULL) return -EINVAL; - cost = iter->sample->weight; + cost = sample->weight; if (!cost) cost = 1; @@ -542,8 +565,10 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al * and this is indirectly achieved by passing period=weight here * and the he_stat__add_period() function. */ + sample->period = cost; + he = __hists__add_entry(hists, al, iter->parent, NULL, mi, - cost, cost, 0, true); + sample, true); if (!he) return -ENOMEM; @@ -630,6 +655,7 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a struct branch_info *bi; struct perf_evsel *evsel = iter->evsel; struct hists *hists = evsel__hists(evsel); + struct perf_sample *sample = iter->sample; struct hist_entry *he = NULL; int i = iter->curr; int err = 0; @@ -643,9 +669,11 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a * The report shows the percentage of total branches captured * and not events sampled. Thus we use a pseudo period of 1. */ + sample->period = 1; + sample->weight = bi->flags.cycles ? bi->flags.cycles : 1; + he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL, - 1, bi->flags.cycles ? bi->flags.cycles : 1, - 0, true); + sample, true); if (he == NULL) return -ENOMEM; @@ -682,8 +710,7 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location struct hist_entry *he; he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, - sample->period, sample->weight, - sample->transaction, true); + sample, true); if (he == NULL) return -ENOMEM; @@ -744,8 +771,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter, int err = 0; he = __hists__add_entry(hists, al, iter->parent, NULL, NULL, - sample->period, sample->weight, - sample->transaction, true); + sample, true); if (he == NULL) return -ENOMEM; @@ -797,6 +823,8 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, .sym = al->sym, }, .parent = iter->parent, + .raw_data = sample->raw_data, + .raw_size = sample->raw_size, }; int i; struct callchain_cursor cursor; @@ -818,8 +846,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, } he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, - sample->period, sample->weight, - sample->transaction, false); + sample, false); if (he == NULL) return -ENOMEM; @@ -971,6 +998,8 @@ void hist_entry__delete(struct hist_entry *he) if (he->srcfile && he->srcfile[0]) free(he->srcfile); free_callchain(he->callchain); + free(he->trace_output); + free(he->raw_data); free(he); } @@ -978,9 +1007,8 @@ void hist_entry__delete(struct hist_entry *he) * collapse the histogram */ -static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, - struct rb_root *root, - struct hist_entry *he) +bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, + struct rb_root *root, struct hist_entry *he) { struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; @@ -1020,7 +1048,7 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, return true; } -static struct rb_root *hists__get_rotate_entries_in(struct hists *hists) +struct rb_root *hists__get_rotate_entries_in(struct hists *hists) { struct rb_root *root; @@ -1084,7 +1112,7 @@ static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b) int64_t cmp = 0; perf_hpp__for_each_sort_list(fmt) { - if (perf_hpp__should_skip(fmt)) + if (perf_hpp__should_skip(fmt, a->hists)) continue; cmp = fmt->sort(fmt, a, b); @@ -1555,10 +1583,8 @@ int perf_hist_config(const char *var, const char *value) return 0; } -static int hists_evsel__init(struct perf_evsel *evsel) +int __hists__init(struct hists *hists) { - struct hists *hists = evsel__hists(evsel); - memset(hists, 0, sizeof(*hists)); hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; hists->entries_in = &hists->entries_in_array[0]; @@ -1598,6 +1624,14 @@ static void hists_evsel__exit(struct perf_evsel *evsel) hists__delete_all_entries(hists); } +static int hists_evsel__init(struct perf_evsel *evsel) +{ + struct hists *hists = evsel__hists(evsel); + + __hists__init(hists); + return 0; +} + /* * XXX We probably need a hists_evsel__exit() to free the hist_entries * stored in the rbtree... |