blob: 7393a02fd8d470fe9ac50340b41e61fe7564b804 [file] [log] [blame]
John Kacur3d1d07e2009-09-28 15:32:55 +02001#include "hist.h"
2
3struct rb_root hist;
4struct rb_root collapse_hists;
5struct rb_root output_hists;
6int callchain;
7
8struct callchain_param callchain_param = {
9 .mode = CHAIN_GRAPH_REL,
10 .min_percent = 0.5
11};
12
13unsigned long total;
14unsigned long total_mmap;
15unsigned long total_comm;
16unsigned long total_fork;
17unsigned long total_unknown;
18unsigned long total_lost;
19
20/*
21 * histogram, sorted on item, collects counts
22 */
23
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -030024struct hist_entry *__hist_entry__add(struct thread *thread, struct map *map,
25 struct symbol *sym,
26 struct symbol *sym_parent,
27 u64 ip, u64 count, char level, bool *hit)
28{
29 struct rb_node **p = &hist.rb_node;
30 struct rb_node *parent = NULL;
31 struct hist_entry *he;
32 struct hist_entry entry = {
33 .thread = thread,
34 .map = map,
35 .sym = sym,
36 .ip = ip,
37 .level = level,
38 .count = count,
39 .parent = sym_parent,
40 };
41 int cmp;
42
43 while (*p != NULL) {
44 parent = *p;
45 he = rb_entry(parent, struct hist_entry, rb_node);
46
47 cmp = hist_entry__cmp(&entry, he);
48
49 if (!cmp) {
50 *hit = true;
51 return he;
52 }
53
54 if (cmp < 0)
55 p = &(*p)->rb_left;
56 else
57 p = &(*p)->rb_right;
58 }
59
60 he = malloc(sizeof(*he));
61 if (!he)
62 return NULL;
63 *he = entry;
64 rb_link_node(&he->rb_node, parent, p);
65 rb_insert_color(&he->rb_node, &hist);
66 *hit = false;
67 return he;
68}
69
John Kacur3d1d07e2009-09-28 15:32:55 +020070int64_t
71hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
72{
73 struct sort_entry *se;
74 int64_t cmp = 0;
75
76 list_for_each_entry(se, &hist_entry__sort_list, list) {
77 cmp = se->cmp(left, right);
78 if (cmp)
79 break;
80 }
81
82 return cmp;
83}
84
85int64_t
86hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
87{
88 struct sort_entry *se;
89 int64_t cmp = 0;
90
91 list_for_each_entry(se, &hist_entry__sort_list, list) {
92 int64_t (*f)(struct hist_entry *, struct hist_entry *);
93
94 f = se->collapse ?: se->cmp;
95
96 cmp = f(left, right);
97 if (cmp)
98 break;
99 }
100
101 return cmp;
102}
103
104void hist_entry__free(struct hist_entry *he)
105{
106 free(he);
107}
108
109/*
110 * collapse the histogram
111 */
112
113void collapse__insert_entry(struct hist_entry *he)
114{
115 struct rb_node **p = &collapse_hists.rb_node;
116 struct rb_node *parent = NULL;
117 struct hist_entry *iter;
118 int64_t cmp;
119
120 while (*p != NULL) {
121 parent = *p;
122 iter = rb_entry(parent, struct hist_entry, rb_node);
123
124 cmp = hist_entry__collapse(iter, he);
125
126 if (!cmp) {
127 iter->count += he->count;
128 hist_entry__free(he);
129 return;
130 }
131
132 if (cmp < 0)
133 p = &(*p)->rb_left;
134 else
135 p = &(*p)->rb_right;
136 }
137
138 rb_link_node(&he->rb_node, parent, p);
139 rb_insert_color(&he->rb_node, &collapse_hists);
140}
141
142void collapse__resort(void)
143{
144 struct rb_node *next;
145 struct hist_entry *n;
146
147 if (!sort__need_collapse)
148 return;
149
150 next = rb_first(&hist);
151 while (next) {
152 n = rb_entry(next, struct hist_entry, rb_node);
153 next = rb_next(&n->rb_node);
154
155 rb_erase(&n->rb_node, &hist);
156 collapse__insert_entry(n);
157 }
158}
159
160/*
161 * reverse the map, sort on count.
162 */
163
164void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
165{
166 struct rb_node **p = &output_hists.rb_node;
167 struct rb_node *parent = NULL;
168 struct hist_entry *iter;
169
170 if (callchain)
171 callchain_param.sort(&he->sorted_chain, &he->callchain,
172 min_callchain_hits, &callchain_param);
173
174 while (*p != NULL) {
175 parent = *p;
176 iter = rb_entry(parent, struct hist_entry, rb_node);
177
178 if (he->count > iter->count)
179 p = &(*p)->rb_left;
180 else
181 p = &(*p)->rb_right;
182 }
183
184 rb_link_node(&he->rb_node, parent, p);
185 rb_insert_color(&he->rb_node, &output_hists);
186}
187
188void output__resort(u64 total_samples)
189{
190 struct rb_node *next;
191 struct hist_entry *n;
192 struct rb_root *tree = &hist;
193 u64 min_callchain_hits;
194
195 min_callchain_hits =
196 total_samples * (callchain_param.min_percent / 100);
197
198 if (sort__need_collapse)
199 tree = &collapse_hists;
200
201 next = rb_first(tree);
202
203 while (next) {
204 n = rb_entry(next, struct hist_entry, rb_node);
205 next = rb_next(&n->rb_node);
206
207 rb_erase(&n->rb_node, tree);
208 output__insert_entry(n, min_callchain_hits);
209 }
210}