aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/callchain.h
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2011-01-13 22:51:58 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-01-22 16:56:31 -0500
commit1b3a0e9592ebf174af934b3908a2bf6a6fa86169 (patch)
tree22de930ec03920ea7a4d602d9a582f5125595916 /tools/perf/util/callchain.h
parentde5fa3a8a05cd60f59622e88cfeb90416760d78e (diff)
perf callchain: Feed callchains into a cursor
The callchains are fed with an array of a fixed size. As a result we iterate over each callchains three times: - 1st to resolve symbols - 2nd to filter out context boundaries - 3rd for the insertion into the tree This also involves some pairs of memory allocation/deallocation everytime we insert a callchain, for the filtered out array of addresses and for the array of symbols that comes along. Instead, feed the callchains through a linked list with persistent allocations. It brings several pros like: - Merge the 1st and 2nd iterations in one. That was possible before but in a way that would involve allocating an array slightly taller than necessary because we don't know in advance the number of context boundaries to filter out. - Much lesser allocations/deallocations. The linked list keeps persistent empty entries for the next usages and is extendable at will. - Makes it easier for multiple sources of callchains to feed a stacktrace together. This is deemed to pave the way for cfi based callchains wherein traditional frame pointer based kernel stacktraces will precede cfi based user ones, producing an overall callchain which size is hardly predictable. This requirement makes the static array obsolete and makes a linked list based iterator a much more flexible fit. Basic testing on a big perf file containing callchains (~ 176 MB) has shown a throughput gain of about 11% with perf report. Cc: Ingo Molnar <mingo@elte.hu> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <1294977121-5700-2-git-send-email-fweisbec@gmail.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/callchain.h')
-rw-r--r--tools/perf/util/callchain.h66
1 files changed, 63 insertions, 3 deletions
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index c15fb8c24ad2..d74a19af4a44 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -49,6 +49,27 @@ struct callchain_list {
49 struct list_head list; 49 struct list_head list;
50}; 50};
51 51
52/*
53 * A callchain cursor is a single linked list that
54 * let one feed a callchain progressively.
55 * It keeps persitent allocated entries to minimize
56 * allocations.
57 */
58struct callchain_cursor_node {
59 u64 ip;
60 struct map *map;
61 struct symbol *sym;
62 struct callchain_cursor_node *next;
63};
64
65struct callchain_cursor {
66 u64 nr;
67 struct callchain_cursor_node *first;
68 struct callchain_cursor_node **last;
69 u64 pos;
70 struct callchain_cursor_node *curr;
71};
72
52static inline void callchain_init(struct callchain_root *root) 73static inline void callchain_init(struct callchain_root *root)
53{ 74{
54 INIT_LIST_HEAD(&root->node.brothers); 75 INIT_LIST_HEAD(&root->node.brothers);
@@ -67,9 +88,48 @@ static inline u64 cumul_hits(struct callchain_node *node)
67} 88}
68 89
69int register_callchain_param(struct callchain_param *param); 90int register_callchain_param(struct callchain_param *param);
70int callchain_append(struct callchain_root *root, struct ip_callchain *chain, 91int callchain_append(struct callchain_root *root,
71 struct map_symbol *syms, u64 period); 92 struct callchain_cursor *cursor,
72int callchain_merge(struct callchain_root *dst, struct callchain_root *src); 93 u64 period);
94
95int callchain_merge(struct callchain_cursor *cursor,
96 struct callchain_root *dst, struct callchain_root *src);
73 97
74bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event); 98bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event);
99
100/*
101 * Initialize a cursor before adding entries inside, but keep
102 * the previously allocated entries as a cache.
103 */
104static inline void callchain_cursor_reset(struct callchain_cursor *cursor)
105{
106 cursor->nr = 0;
107 cursor->last = &cursor->first;
108}
109
110int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip,
111 struct map *map, struct symbol *sym);
112
113/* Close a cursor writing session. Initialize for the reader */
114static inline void callchain_cursor_commit(struct callchain_cursor *cursor)
115{
116 cursor->curr = cursor->first;
117 cursor->pos = 0;
118}
119
120/* Cursor reading iteration helpers */
121static inline struct callchain_cursor_node *
122callchain_cursor_current(struct callchain_cursor *cursor)
123{
124 if (cursor->pos == cursor->nr)
125 return NULL;
126
127 return cursor->curr;
128}
129
130static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
131{
132 cursor->curr = cursor->curr->next;
133 cursor->pos++;
134}
75#endif /* __PERF_CALLCHAIN_H */ 135#endif /* __PERF_CALLCHAIN_H */