diff options
Diffstat (limited to 'tools/perf/util/hist.c')
-rw-r--r-- | tools/perf/util/hist.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 277947a669b2..cb17e2a8c6ed 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -244,6 +244,8 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) he->ms.map->referenced = true; if (symbol_conf.use_callchain) callchain_init(he->callchain); + + INIT_LIST_HEAD(&he->pairs.node); } return he; @@ -410,6 +412,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) void hist_entry__free(struct hist_entry *he) { + free(he->branch_info); free(he); } @@ -713,3 +716,99 @@ void hists__inc_nr_events(struct hists *hists, u32 type) ++hists->stats.nr_events[0]; ++hists->stats.nr_events[type]; } + +static struct hist_entry *hists__add_dummy_entry(struct hists *hists, + struct hist_entry *pair) +{ + struct rb_node **p = &hists->entries.rb_node; + struct rb_node *parent = NULL; + struct hist_entry *he; + int cmp; + + while (*p != NULL) { + parent = *p; + he = rb_entry(parent, struct hist_entry, rb_node); + + cmp = hist_entry__cmp(pair, he); + + if (!cmp) + goto out; + + if (cmp < 0) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + he = hist_entry__new(pair); + if (he) { + memset(&he->stat, 0, sizeof(he->stat)); + he->hists = hists; + rb_link_node(&he->rb_node, parent, p); + rb_insert_color(&he->rb_node, &hists->entries); + hists__inc_nr_entries(hists, he); + } +out: + return he; +} + +static struct hist_entry *hists__find_entry(struct hists *hists, + struct hist_entry *he) +{ + struct rb_node *n = hists->entries.rb_node; + + while (n) { + struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); + int64_t cmp = hist_entry__cmp(he, iter); + + if (cmp < 0) + n = n->rb_left; + else if (cmp > 0) + n = n->rb_right; + else + return iter; + } + + return NULL; +} + +/* + * Look for pairs to link to the leader buckets (hist_entries): + */ +void hists__match(struct hists *leader, struct hists *other) +{ + struct rb_node *nd; + struct hist_entry *pos, *pair; + + for (nd = rb_first(&leader->entries); nd; nd = rb_next(nd)) { + pos = rb_entry(nd, struct hist_entry, rb_node); + pair = hists__find_entry(other, pos); + + if (pair) + hist__entry_add_pair(pos, pair); + } +} + +/* + * Look for entries in the other hists that are not present in the leader, if + * we find them, just add a dummy entry on the leader hists, with period=0, + * nr_events=0, to serve as the list header. + */ +int hists__link(struct hists *leader, struct hists *other) +{ + struct rb_node *nd; + struct hist_entry *pos, *pair; + + for (nd = rb_first(&other->entries); nd; nd = rb_next(nd)) { + pos = rb_entry(nd, struct hist_entry, rb_node); + + if (!hist_entry__has_pairs(pos)) { + pair = hists__add_dummy_entry(leader, pos); + if (pair == NULL) + return -1; + hist__entry_add_pair(pair, pos); + } + } + + return 0; +} |