mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-20 00:11:22 +00:00
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. Signed-off-by: Namhyung Kim <namhyung@kernel.org> Tested-by: Arun Sharma <asharma@fb.com> Tested-by: Rodrigo Campos <rodrigo@sdfg.com.ar> Cc: Frederic Weisbecker <fweisbec@gmail.com> Link: http://lkml.kernel.org/r/1401335910-16832-8-git-send-email-namhyung@kernel.org Signed-off-by: Jiri Olsa <jolsa@kernel.org>
This commit is contained in:
parent
c7405d85d7
commit
b4d3c8bd86
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user