blob: 6568cb198ba6fe0a48199b3b55a84c8730267e78 [file] [log] [blame]
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +02001/*
2 * Copyright (C) 2009, Frederic Weisbecker <fweisbec@gmail.com>
3 *
4 * Handle the callchains from the stream in an ad-hoc radix tree and then
5 * sort them in an rbtree.
6 *
7 */
8
9#include <stdlib.h>
10#include <stdio.h>
11#include <stdbool.h>
12#include <errno.h>
13
14#include "callchain.h"
15
16
17static void rb_insert_callchain(struct rb_root *root, struct callchain_node *chain)
18{
19 struct rb_node **p = &root->rb_node;
20 struct rb_node *parent = NULL;
21 struct callchain_node *rnode;
22
23 while (*p) {
24 parent = *p;
25 rnode = rb_entry(parent, struct callchain_node, rb_node);
26
27 if (rnode->hit < chain->hit)
28 p = &(*p)->rb_left;
29 else
30 p = &(*p)->rb_right;
31 }
32
33 rb_link_node(&chain->rb_node, parent, p);
34 rb_insert_color(&chain->rb_node, root);
35}
36
37/*
38 * Once we get every callchains from the stream, we can now
39 * sort them by hit
40 */
41void sort_chain_to_rbtree(struct rb_root *rb_root, struct callchain_node *node)
42{
43 struct callchain_node *child;
44
45 list_for_each_entry(child, &node->children, brothers)
46 sort_chain_to_rbtree(rb_root, child);
47
48 if (node->hit)
49 rb_insert_callchain(rb_root, node);
50}
51
52static struct callchain_node *create_child(struct callchain_node *parent)
53{
54 struct callchain_node *new;
55
56 new = malloc(sizeof(*new));
57 if (!new) {
58 perror("not enough memory to create child for code path tree");
59 return NULL;
60 }
61 new->parent = parent;
62 INIT_LIST_HEAD(&new->children);
63 INIT_LIST_HEAD(&new->val);
64 list_add_tail(&new->brothers, &parent->children);
65
66 return new;
67}
68
69static void
Frederic Weisbecker44249612009-07-01 05:35:14 +020070fill_node(struct callchain_node *node, struct ip_callchain *chain, int start,
71 struct symbol **syms)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020072{
73 int i;
74
75 for (i = start; i < chain->nr; i++) {
76 struct callchain_list *call;
77
Frederic Weisbecker9198aa72009-07-01 05:35:13 +020078 call = malloc(sizeof(*call));
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020079 if (!call) {
80 perror("not enough memory for the code path tree");
81 return;
82 }
83 call->ip = chain->ips[i];
Frederic Weisbecker44249612009-07-01 05:35:14 +020084 call->sym = syms[i];
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020085 list_add_tail(&call->list, &node->val);
86 }
87 node->val_nr = i - start;
88}
89
Frederic Weisbecker44249612009-07-01 05:35:14 +020090static void add_child(struct callchain_node *parent, struct ip_callchain *chain,
91 struct symbol **syms)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020092{
93 struct callchain_node *new;
94
95 new = create_child(parent);
Frederic Weisbecker44249612009-07-01 05:35:14 +020096 fill_node(new, chain, parent->val_nr, syms);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +020097
98 new->hit = 1;
99}
100
101static void
102split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
Frederic Weisbecker44249612009-07-01 05:35:14 +0200103 struct callchain_list *to_split, int idx, struct symbol **syms)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200104{
105 struct callchain_node *new;
106
107 /* 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;
113
114 /* create the new one */
Frederic Weisbecker44249612009-07-01 05:35:14 +0200115 add_child(parent, chain, syms);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200116}
117
118static int
119__append_chain(struct callchain_node *root, struct ip_callchain *chain,
Frederic Weisbecker44249612009-07-01 05:35:14 +0200120 int start, struct symbol **syms);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200121
122static int
Frederic Weisbecker44249612009-07-01 05:35:14 +0200123__append_chain_children(struct callchain_node *root, struct ip_callchain *chain,
124 struct symbol **syms)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200125{
126 struct callchain_node *rnode;
127
128 /* lookup in childrens */
129 list_for_each_entry(rnode, &root->children, brothers) {
Frederic Weisbecker44249612009-07-01 05:35:14 +0200130 int ret = __append_chain(rnode, chain, root->val_nr, syms);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200131 if (!ret)
132 return 0;
133 }
134 return -1;
135}
136
137static int
138__append_chain(struct callchain_node *root, struct ip_callchain *chain,
Frederic Weisbecker44249612009-07-01 05:35:14 +0200139 int start, struct symbol **syms)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200140{
141 struct callchain_list *cnode;
142 int i = start;
143 bool found = false;
144
145 /* lookup in the current node */
146 list_for_each_entry(cnode, &root->val, list) {
147 if (cnode->ip != chain->ips[i++])
148 break;
149 if (!found)
150 found = true;
151 if (i == chain->nr)
152 break;
153 }
154
155 /* matches not, relay on the parent */
156 if (!found)
157 return -1;
158
159 /* we match only a part of the node. Split it and add the new chain */
160 if (i < root->val_nr) {
Frederic Weisbecker44249612009-07-01 05:35:14 +0200161 split_add_child(root, chain, cnode, i, syms);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200162 return 0;
163 }
164
165 /* we match 100% of the path, increment the hit */
166 if (i == root->val_nr) {
167 root->hit++;
168 return 0;
169 }
170
Frederic Weisbecker44249612009-07-01 05:35:14 +0200171 return __append_chain_children(root, chain, syms);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200172}
173
Frederic Weisbecker44249612009-07-01 05:35:14 +0200174void append_chain(struct callchain_node *root, struct ip_callchain *chain,
175 struct symbol **syms)
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200176{
Frederic Weisbecker44249612009-07-01 05:35:14 +0200177 if (__append_chain_children(root, chain, syms) == -1)
178 add_child(root, chain, syms);
Frederic Weisbecker8cb76d92009-06-26 16:28:00 +0200179}