blob: d9a5a19391dc0fa2839f0cb34cc0a67c59116bdc [file] [log] [blame]
John Kacur3d1d07e2009-09-28 15:32:55 +02001#include "hist.h"
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -02002#include "session.h"
3#include "sort.h"
John Kacur3d1d07e2009-09-28 15:32:55 +02004
5struct callchain_param callchain_param = {
6 .mode = CHAIN_GRAPH_REL,
7 .min_percent = 0.5
8};
9
John Kacur3d1d07e2009-09-28 15:32:55 +020010/*
11 * histogram, sorted on item, collects counts
12 */
13
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -020014struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
15 struct addr_location *al,
16 struct symbol *sym_parent,
17 u64 count, bool *hit)
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -030018{
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -020019 struct rb_node **p = &self->hists.rb_node;
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -030020 struct rb_node *parent = NULL;
21 struct hist_entry *he;
22 struct hist_entry entry = {
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -020023 .thread = al->thread,
24 .map = al->map,
25 .sym = al->sym,
26 .ip = al->addr,
27 .level = al->level,
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -030028 .count = count,
29 .parent = sym_parent,
30 };
31 int cmp;
32
33 while (*p != NULL) {
34 parent = *p;
35 he = rb_entry(parent, struct hist_entry, rb_node);
36
37 cmp = hist_entry__cmp(&entry, he);
38
39 if (!cmp) {
40 *hit = true;
41 return he;
42 }
43
44 if (cmp < 0)
45 p = &(*p)->rb_left;
46 else
47 p = &(*p)->rb_right;
48 }
49
50 he = malloc(sizeof(*he));
51 if (!he)
52 return NULL;
53 *he = entry;
54 rb_link_node(&he->rb_node, parent, p);
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -020055 rb_insert_color(&he->rb_node, &self->hists);
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -030056 *hit = false;
57 return he;
58}
59
John Kacur3d1d07e2009-09-28 15:32:55 +020060int64_t
61hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
62{
63 struct sort_entry *se;
64 int64_t cmp = 0;
65
66 list_for_each_entry(se, &hist_entry__sort_list, list) {
67 cmp = se->cmp(left, right);
68 if (cmp)
69 break;
70 }
71
72 return cmp;
73}
74
75int64_t
76hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
77{
78 struct sort_entry *se;
79 int64_t cmp = 0;
80
81 list_for_each_entry(se, &hist_entry__sort_list, list) {
82 int64_t (*f)(struct hist_entry *, struct hist_entry *);
83
84 f = se->collapse ?: se->cmp;
85
86 cmp = f(left, right);
87 if (cmp)
88 break;
89 }
90
91 return cmp;
92}
93
94void hist_entry__free(struct hist_entry *he)
95{
96 free(he);
97}
98
99/*
100 * collapse the histogram
101 */
102
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200103static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
John Kacur3d1d07e2009-09-28 15:32:55 +0200104{
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200105 struct rb_node **p = &root->rb_node;
John Kacur3d1d07e2009-09-28 15:32:55 +0200106 struct rb_node *parent = NULL;
107 struct hist_entry *iter;
108 int64_t cmp;
109
110 while (*p != NULL) {
111 parent = *p;
112 iter = rb_entry(parent, struct hist_entry, rb_node);
113
114 cmp = hist_entry__collapse(iter, he);
115
116 if (!cmp) {
117 iter->count += he->count;
118 hist_entry__free(he);
119 return;
120 }
121
122 if (cmp < 0)
123 p = &(*p)->rb_left;
124 else
125 p = &(*p)->rb_right;
126 }
127
128 rb_link_node(&he->rb_node, parent, p);
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200129 rb_insert_color(&he->rb_node, root);
John Kacur3d1d07e2009-09-28 15:32:55 +0200130}
131
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -0200132void perf_session__collapse_resort(struct perf_session *self)
John Kacur3d1d07e2009-09-28 15:32:55 +0200133{
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200134 struct rb_root tmp;
John Kacur3d1d07e2009-09-28 15:32:55 +0200135 struct rb_node *next;
136 struct hist_entry *n;
137
138 if (!sort__need_collapse)
139 return;
140
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200141 tmp = RB_ROOT;
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -0200142 next = rb_first(&self->hists);
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200143
John Kacur3d1d07e2009-09-28 15:32:55 +0200144 while (next) {
145 n = rb_entry(next, struct hist_entry, rb_node);
146 next = rb_next(&n->rb_node);
147
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -0200148 rb_erase(&n->rb_node, &self->hists);
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200149 collapse__insert_entry(&tmp, n);
John Kacur3d1d07e2009-09-28 15:32:55 +0200150 }
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200151
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -0200152 self->hists = tmp;
John Kacur3d1d07e2009-09-28 15:32:55 +0200153}
154
155/*
156 * reverse the map, sort on count.
157 */
158
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -0200159static void perf_session__insert_output_hist_entry(struct rb_root *root,
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -0200160 struct hist_entry *he,
161 u64 min_callchain_hits)
John Kacur3d1d07e2009-09-28 15:32:55 +0200162{
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200163 struct rb_node **p = &root->rb_node;
John Kacur3d1d07e2009-09-28 15:32:55 +0200164 struct rb_node *parent = NULL;
165 struct hist_entry *iter;
166
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -0200167 if (symbol_conf.use_callchain)
John Kacur3d1d07e2009-09-28 15:32:55 +0200168 callchain_param.sort(&he->sorted_chain, &he->callchain,
169 min_callchain_hits, &callchain_param);
170
171 while (*p != NULL) {
172 parent = *p;
173 iter = rb_entry(parent, struct hist_entry, rb_node);
174
175 if (he->count > iter->count)
176 p = &(*p)->rb_left;
177 else
178 p = &(*p)->rb_right;
179 }
180
181 rb_link_node(&he->rb_node, parent, p);
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200182 rb_insert_color(&he->rb_node, root);
John Kacur3d1d07e2009-09-28 15:32:55 +0200183}
184
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -0200185void perf_session__output_resort(struct perf_session *self, u64 total_samples)
John Kacur3d1d07e2009-09-28 15:32:55 +0200186{
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200187 struct rb_root tmp;
John Kacur3d1d07e2009-09-28 15:32:55 +0200188 struct rb_node *next;
189 struct hist_entry *n;
John Kacur3d1d07e2009-09-28 15:32:55 +0200190 u64 min_callchain_hits;
191
192 min_callchain_hits =
193 total_samples * (callchain_param.min_percent / 100);
194
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200195 tmp = RB_ROOT;
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -0200196 next = rb_first(&self->hists);
John Kacur3d1d07e2009-09-28 15:32:55 +0200197
198 while (next) {
199 n = rb_entry(next, struct hist_entry, rb_node);
200 next = rb_next(&n->rb_node);
201
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -0200202 rb_erase(&n->rb_node, &self->hists);
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -0200203 perf_session__insert_output_hist_entry(&tmp, n,
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -0200204 min_callchain_hits);
John Kacur3d1d07e2009-09-28 15:32:55 +0200205 }
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200206
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -0200207 self->hists = tmp;
John Kacur3d1d07e2009-09-28 15:32:55 +0200208}