diff options
author | Namhyung Kim <namhyung@kernel.org> | 2016-09-13 03:45:47 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-09-13 15:35:46 -0400 |
commit | 9d97b8f512a0dd41819b8e3d9cdc7a59199e1b0c (patch) | |
tree | 7d108ca418054768654140bc5ca0dc1a8e7d4d66 | |
parent | 09034de63e427a86ba96bedf39410eef7c9014a5 (diff) |
perf hists: Introduce hists__link_hierarchy()
The hists__link_hierarchy() is to support hierarchy reports with an
event group. When it matches the leader event and the other members
(using hists__match_hierarchy()), it also needs to link unmatched member
entries with a dummy leader event so that it can show up in the output.
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20160913074552.13284-3-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/util/hist.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index be3f5ce31303..702ba3a8ead6 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -2149,6 +2149,50 @@ out: | |||
2149 | return he; | 2149 | return he; |
2150 | } | 2150 | } |
2151 | 2151 | ||
2152 | static struct hist_entry *add_dummy_hierarchy_entry(struct hists *hists, | ||
2153 | struct rb_root *root, | ||
2154 | struct hist_entry *pair) | ||
2155 | { | ||
2156 | struct rb_node **p; | ||
2157 | struct rb_node *parent = NULL; | ||
2158 | struct hist_entry *he; | ||
2159 | struct perf_hpp_fmt *fmt; | ||
2160 | |||
2161 | p = &root->rb_node; | ||
2162 | while (*p != NULL) { | ||
2163 | int64_t cmp = 0; | ||
2164 | |||
2165 | parent = *p; | ||
2166 | he = rb_entry(parent, struct hist_entry, rb_node_in); | ||
2167 | |||
2168 | perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) { | ||
2169 | cmp = fmt->collapse(fmt, he, pair); | ||
2170 | if (cmp) | ||
2171 | break; | ||
2172 | } | ||
2173 | if (!cmp) | ||
2174 | goto out; | ||
2175 | |||
2176 | if (cmp < 0) | ||
2177 | p = &parent->rb_left; | ||
2178 | else | ||
2179 | p = &parent->rb_right; | ||
2180 | } | ||
2181 | |||
2182 | he = hist_entry__new(pair, true); | ||
2183 | if (he) { | ||
2184 | rb_link_node(&he->rb_node_in, parent, p); | ||
2185 | rb_insert_color(&he->rb_node_in, root); | ||
2186 | |||
2187 | he->dummy = true; | ||
2188 | he->hists = hists; | ||
2189 | memset(&he->stat, 0, sizeof(he->stat)); | ||
2190 | hists__inc_stats(hists, he); | ||
2191 | } | ||
2192 | out: | ||
2193 | return he; | ||
2194 | } | ||
2195 | |||
2152 | static struct hist_entry *hists__find_entry(struct hists *hists, | 2196 | static struct hist_entry *hists__find_entry(struct hists *hists, |
2153 | struct hist_entry *he) | 2197 | struct hist_entry *he) |
2154 | { | 2198 | { |
@@ -2248,6 +2292,50 @@ void hists__match(struct hists *leader, struct hists *other) | |||
2248 | } | 2292 | } |
2249 | } | 2293 | } |
2250 | 2294 | ||
2295 | static int hists__link_hierarchy(struct hists *leader_hists, | ||
2296 | struct hist_entry *parent, | ||
2297 | struct rb_root *leader_root, | ||
2298 | struct rb_root *other_root) | ||
2299 | { | ||
2300 | struct rb_node *nd; | ||
2301 | struct hist_entry *pos, *leader; | ||
2302 | |||
2303 | for (nd = rb_first(other_root); nd; nd = rb_next(nd)) { | ||
2304 | pos = rb_entry(nd, struct hist_entry, rb_node_in); | ||
2305 | |||
2306 | if (hist_entry__has_pairs(pos)) { | ||
2307 | bool found = false; | ||
2308 | |||
2309 | list_for_each_entry(leader, &pos->pairs.head, pairs.node) { | ||
2310 | if (leader->hists == leader_hists) { | ||
2311 | found = true; | ||
2312 | break; | ||
2313 | } | ||
2314 | } | ||
2315 | if (!found) | ||
2316 | return -1; | ||
2317 | } else { | ||
2318 | leader = add_dummy_hierarchy_entry(leader_hists, | ||
2319 | leader_root, pos); | ||
2320 | if (leader == NULL) | ||
2321 | return -1; | ||
2322 | |||
2323 | /* do not point parent in the pos */ | ||
2324 | leader->parent_he = parent; | ||
2325 | |||
2326 | hist_entry__add_pair(pos, leader); | ||
2327 | } | ||
2328 | |||
2329 | if (!pos->leaf) { | ||
2330 | if (hists__link_hierarchy(leader_hists, leader, | ||
2331 | &leader->hroot_in, | ||
2332 | &pos->hroot_in) < 0) | ||
2333 | return -1; | ||
2334 | } | ||
2335 | } | ||
2336 | return 0; | ||
2337 | } | ||
2338 | |||
2251 | /* | 2339 | /* |
2252 | * Look for entries in the other hists that are not present in the leader, if | 2340 | * Look for entries in the other hists that are not present in the leader, if |
2253 | * we find them, just add a dummy entry on the leader hists, with period=0, | 2341 | * we find them, just add a dummy entry on the leader hists, with period=0, |
@@ -2259,6 +2347,13 @@ int hists__link(struct hists *leader, struct hists *other) | |||
2259 | struct rb_node *nd; | 2347 | struct rb_node *nd; |
2260 | struct hist_entry *pos, *pair; | 2348 | struct hist_entry *pos, *pair; |
2261 | 2349 | ||
2350 | if (symbol_conf.report_hierarchy) { | ||
2351 | /* hierarchy report always collapses entries */ | ||
2352 | return hists__link_hierarchy(leader, NULL, | ||
2353 | &leader->entries_collapsed, | ||
2354 | &other->entries_collapsed); | ||
2355 | } | ||
2356 | |||
2262 | if (hists__has(other, need_collapse)) | 2357 | if (hists__has(other, need_collapse)) |
2263 | root = &other->entries_collapsed; | 2358 | root = &other->entries_collapsed; |
2264 | else | 2359 | else |