Skip to content

Commit 80c8ab9

Browse files
fweisbecIngo Molnar
authored and
Ingo Molnar
committed
perf_counter tools: Various fixes for callchains
The symbol resolving has of course revealed some bugs in the callchain tree handling. This patch fixes some of them, including: - inherit the children from the parents while splitting a node - fix list range moving - fix indexes setting in callchains - create a child on the current node if the path doesn't match in the existent children (was only done on the root) - compare using symbols when possible so that we can match a function using any ip inside by referring to its start address. The practical effects are: - remove double callchains - fix upside down or any random order of callchains - fix wrong paths - fix bad hits and percentage accounts Signed-off-by: Frederic Weisbecker <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Mike Galbraith <[email protected]> Cc: Paul Mackerras <[email protected]> Cc: Anton Blanchard <[email protected]> Cc: Arnaldo Carvalho de Melo <[email protected]> LKML-Reference: <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> --- yaml --- svn_rev: 155184 current_ref: refs/heads/rpi-3.18.y current_commit: deac911 head_branch: refs/heads/rpi-3.18.y migrated_from: v3
1 parent c41dc33 commit 80c8ab9

File tree

2 files changed

+91
-33
lines changed

2 files changed

+91
-33
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
refs/heads/rpi-3.18.y: 4424961ad6621a02c6b4c9093e801002c1bb9f65
2+
refs/heads/rpi-3.18.y: deac911cbdcb124fa0cee47c588e0cb0400b23b7

trunk/tools/perf/util/callchain.c

Lines changed: 90 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
* Handle the callchains from the stream in an ad-hoc radix tree and then
55
* sort them in an rbtree.
66
*
7+
* Using a radix for code path provides a fast retrieval and factorizes
8+
* memory use. Also that lets us use the paths in a hierarchical graph view.
9+
*
710
*/
811

912
#include <stdlib.h>
@@ -14,7 +17,8 @@
1417
#include "callchain.h"
1518

1619

17-
static void rb_insert_callchain(struct rb_root *root, struct callchain_node *chain)
20+
static void
21+
rb_insert_callchain(struct rb_root *root, struct callchain_node *chain)
1822
{
1923
struct rb_node **p = &root->rb_node;
2024
struct rb_node *parent = NULL;
@@ -49,7 +53,12 @@ void sort_chain_to_rbtree(struct rb_root *rb_root, struct callchain_node *node)
4953
rb_insert_callchain(rb_root, node);
5054
}
5155

52-
static struct callchain_node *create_child(struct callchain_node *parent)
56+
/*
57+
* Create a child for a parent. If inherit_children, then the new child
58+
* will become the new parent of it's parent children
59+
*/
60+
static struct callchain_node *
61+
create_child(struct callchain_node *parent, bool inherit_children)
5362
{
5463
struct callchain_node *new;
5564

@@ -61,14 +70,27 @@ static struct callchain_node *create_child(struct callchain_node *parent)
6170
new->parent = parent;
6271
INIT_LIST_HEAD(&new->children);
6372
INIT_LIST_HEAD(&new->val);
73+
74+
if (inherit_children) {
75+
struct callchain_node *next;
76+
77+
list_splice(&parent->children, &new->children);
78+
INIT_LIST_HEAD(&parent->children);
79+
80+
list_for_each_entry(next, &new->children, brothers)
81+
next->parent = new;
82+
}
6483
list_add_tail(&new->brothers, &parent->children);
6584

6685
return new;
6786
}
6887

88+
/*
89+
* Fill the node with callchain values
90+
*/
6991
static void
70-
fill_node(struct callchain_node *node, struct ip_callchain *chain, int start,
71-
struct symbol **syms)
92+
fill_node(struct callchain_node *node, struct ip_callchain *chain,
93+
int start, struct symbol **syms)
7294
{
7395
int i;
7496

@@ -84,54 +106,80 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain, int start,
84106
call->sym = syms[i];
85107
list_add_tail(&call->list, &node->val);
86108
}
87-
node->val_nr = i - start;
109+
node->val_nr = chain->nr - start;
110+
if (!node->val_nr)
111+
printf("Warning: empty node in callchain tree\n");
88112
}
89113

90-
static void add_child(struct callchain_node *parent, struct ip_callchain *chain,
91-
struct symbol **syms)
114+
static void
115+
add_child(struct callchain_node *parent, struct ip_callchain *chain,
116+
int start, struct symbol **syms)
92117
{
93118
struct callchain_node *new;
94119

95-
new = create_child(parent);
96-
fill_node(new, chain, parent->val_nr, syms);
120+
new = create_child(parent, false);
121+
fill_node(new, chain, start, syms);
97122

98123
new->hit = 1;
99124
}
100125

126+
/*
127+
* Split the parent in two parts (a new child is created) and
128+
* give a part of its callchain to the created child.
129+
* Then create another child to host the given callchain of new branch
130+
*/
101131
static void
102132
split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
103-
struct callchain_list *to_split, int idx, struct symbol **syms)
133+
struct callchain_list *to_split, int idx_parents, int idx_local,
134+
struct symbol **syms)
104135
{
105136
struct callchain_node *new;
137+
struct list_head *old_tail;
138+
int idx_total = idx_parents + idx_local;
106139

107140
/* split */
108-
new = create_child(parent);
109-
list_move_tail(&to_split->list, &new->val);
110-
new->hit = parent->hit;
111-
parent->hit = 0;
112-
parent->val_nr = idx;
141+
new = create_child(parent, true);
142+
143+
/* split the callchain and move a part to the new child */
144+
old_tail = parent->val.prev;
145+
list_del_range(&to_split->list, old_tail);
146+
new->val.next = &to_split->list;
147+
new->val.prev = old_tail;
148+
to_split->list.prev = &new->val;
149+
old_tail->next = &new->val;
113150

114-
/* create the new one */
115-
add_child(parent, chain, syms);
151+
/* split the hits */
152+
new->hit = parent->hit;
153+
new->val_nr = parent->val_nr - idx_local;
154+
parent->val_nr = idx_local;
155+
156+
/* create a new child for the new branch if any */
157+
if (idx_total < chain->nr) {
158+
parent->hit = 0;
159+
add_child(parent, chain, idx_total, syms);
160+
} else {
161+
parent->hit = 1;
162+
}
116163
}
117164

118165
static int
119166
__append_chain(struct callchain_node *root, struct ip_callchain *chain,
120167
int start, struct symbol **syms);
121168

122-
static int
169+
static void
123170
__append_chain_children(struct callchain_node *root, struct ip_callchain *chain,
124-
struct symbol **syms)
171+
struct symbol **syms, int start)
125172
{
126173
struct callchain_node *rnode;
127174

128175
/* lookup in childrens */
129176
list_for_each_entry(rnode, &root->children, brothers) {
130-
int ret = __append_chain(rnode, chain, root->val_nr, syms);
177+
int ret = __append_chain(rnode, chain, start, syms);
131178
if (!ret)
132-
return 0;
179+
return;
133180
}
134-
return -1;
181+
/* nothing in children, add to the current node */
182+
add_child(root, chain, start, syms);
135183
}
136184

137185
static int
@@ -142,38 +190,48 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
142190
int i = start;
143191
bool found = false;
144192

145-
/* lookup in the current node */
193+
/*
194+
* Lookup in the current node
195+
* If we have a symbol, then compare the start to match
196+
* anywhere inside a function.
197+
*/
146198
list_for_each_entry(cnode, &root->val, list) {
147-
if (cnode->ip != chain->ips[i++])
199+
if (i == chain->nr)
200+
break;
201+
if (cnode->sym && syms[i]) {
202+
if (cnode->sym->start != syms[i]->start)
203+
break;
204+
} else if (cnode->ip != chain->ips[i])
148205
break;
149206
if (!found)
150207
found = true;
151-
if (i == chain->nr)
152-
break;
208+
i++;
153209
}
154210

155211
/* matches not, relay on the parent */
156212
if (!found)
157213
return -1;
158214

159215
/* we match only a part of the node. Split it and add the new chain */
160-
if (i < root->val_nr) {
161-
split_add_child(root, chain, cnode, i, syms);
216+
if (i - start < root->val_nr) {
217+
split_add_child(root, chain, cnode, start, i - start, syms);
162218
return 0;
163219
}
164220

165221
/* we match 100% of the path, increment the hit */
166-
if (i == root->val_nr) {
222+
if (i - start == root->val_nr && i == chain->nr) {
167223
root->hit++;
168224
return 0;
169225
}
170226

171-
return __append_chain_children(root, chain, syms);
227+
/* We match the node and still have a part remaining */
228+
__append_chain_children(root, chain, syms, i);
229+
230+
return 0;
172231
}
173232

174233
void append_chain(struct callchain_node *root, struct ip_callchain *chain,
175234
struct symbol **syms)
176235
{
177-
if (__append_chain_children(root, chain, syms) == -1)
178-
add_child(root, chain, syms);
236+
__append_chain_children(root, chain, syms, 0);
179237
}

0 commit comments

Comments
 (0)