blob: 48da373afa3dc6a5263601b0a02e96e33bc1c403 [file] [log] [blame]
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001#include "annotate.h"
Frederic Weisbecker8a0ecfb2010-05-13 19:47:16 +02002#include "util.h"
Frederic Weisbecker598357e2010-05-21 12:48:39 +02003#include "build-id.h"
John Kacur3d1d07e2009-09-28 15:32:55 +02004#include "hist.h"
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -02005#include "session.h"
6#include "sort.h"
Arnaldo Carvalho de Melo9b338272009-12-16 14:31:49 -02007#include <math.h>
John Kacur3d1d07e2009-09-28 15:32:55 +02008
Arnaldo Carvalho de Melo7a007ca2010-07-21 09:19:41 -03009enum hist_filter {
10 HIST_FILTER__DSO,
11 HIST_FILTER__THREAD,
12 HIST_FILTER__PARENT,
13};
14
John Kacur3d1d07e2009-09-28 15:32:55 +020015struct callchain_param callchain_param = {
16 .mode = CHAIN_GRAPH_REL,
Sam Liaod797fdc2011-06-07 23:49:46 +080017 .min_percent = 0.5,
18 .order = ORDER_CALLEE
John Kacur3d1d07e2009-09-28 15:32:55 +020019};
20
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030021u16 hists__col_len(struct hists *hists, enum hist_column col)
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030022{
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030023 return hists->col_len[col];
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030024}
25
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030026void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len)
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030027{
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030028 hists->col_len[col] = len;
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030029}
30
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030031bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len)
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030032{
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030033 if (len > hists__col_len(hists, col)) {
34 hists__set_col_len(hists, col, len);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030035 return true;
36 }
37 return false;
38}
39
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030040static void hists__reset_col_len(struct hists *hists)
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030041{
42 enum hist_column col;
43
44 for (col = 0; col < HISTC_NR_COLS; ++col)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030045 hists__set_col_len(hists, col, 0);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030046}
47
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030048static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030049{
50 u16 len;
51
52 if (h->ms.sym)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030053 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen);
Arnaldo Carvalho de Melod7603d52011-03-04 14:51:33 -030054 else {
55 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
56
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030057 if (hists__col_len(hists, HISTC_DSO) < unresolved_col_width &&
Arnaldo Carvalho de Melod7603d52011-03-04 14:51:33 -030058 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
59 !symbol_conf.dso_list)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030060 hists__set_col_len(hists, HISTC_DSO,
Arnaldo Carvalho de Melod7603d52011-03-04 14:51:33 -030061 unresolved_col_width);
62 }
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030063
64 len = thread__comm_len(h->thread);
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030065 if (hists__new_col_len(hists, HISTC_COMM, len))
66 hists__set_col_len(hists, HISTC_THREAD, len + 6);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030067
68 if (h->ms.map) {
69 len = dso__name_len(h->ms.map->dso);
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030070 hists__new_col_len(hists, HISTC_DSO, len);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030071 }
72}
73
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -030074static void hist_entry__add_cpumode_period(struct hist_entry *self,
75 unsigned int cpumode, u64 period)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080076{
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -030077 switch (cpumode) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080078 case PERF_RECORD_MISC_KERNEL:
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -030079 self->period_sys += period;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080080 break;
81 case PERF_RECORD_MISC_USER:
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -030082 self->period_us += period;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080083 break;
84 case PERF_RECORD_MISC_GUEST_KERNEL:
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -030085 self->period_guest_sys += period;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080086 break;
87 case PERF_RECORD_MISC_GUEST_USER:
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -030088 self->period_guest_us += period;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080089 break;
90 default:
91 break;
92 }
93}
94
Arnaldo Carvalho de Meloab81f3f2011-10-05 19:16:15 -030095static void hist_entry__decay(struct hist_entry *he)
96{
97 he->period = (he->period * 7) / 8;
98 he->nr_events = (he->nr_events * 7) / 8;
99}
100
101static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
102{
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -0300103 if (he->period == 0)
104 return true;
Arnaldo Carvalho de Meloab81f3f2011-10-05 19:16:15 -0300105 hists->stats.total_period -= he->period;
106 hist_entry__decay(he);
107 hists->stats.total_period += he->period;
108 return he->period == 0;
109}
110
Arnaldo Carvalho de Melob079d4e2011-10-17 09:05:04 -0200111static void __hists__decay_entries(struct hists *hists, bool zap_user,
112 bool zap_kernel, bool threaded)
Arnaldo Carvalho de Meloab81f3f2011-10-05 19:16:15 -0300113{
114 struct rb_node *next = rb_first(&hists->entries);
115 struct hist_entry *n;
116
117 while (next) {
118 n = rb_entry(next, struct hist_entry, rb_node);
119 next = rb_next(&n->rb_node);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -0300120 /*
121 * We may be annotating this, for instance, so keep it here in
122 * case some it gets new samples, we'll eventually free it when
123 * the user stops browsing and it agains gets fully decayed.
124 */
Arnaldo Carvalho de Melob079d4e2011-10-17 09:05:04 -0200125 if (((zap_user && n->level == '.') ||
126 (zap_kernel && n->level != '.') ||
127 hists__decay_entry(hists, n)) &&
128 !n->used) {
Arnaldo Carvalho de Meloab81f3f2011-10-05 19:16:15 -0300129 rb_erase(&n->rb_node, &hists->entries);
130
Arnaldo Carvalho de Meloe345fa12011-10-13 09:06:54 -0300131 if (sort__need_collapse || threaded)
Arnaldo Carvalho de Meloab81f3f2011-10-05 19:16:15 -0300132 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
133
134 hist_entry__free(n);
135 --hists->nr_entries;
136 }
137 }
138}
139
Arnaldo Carvalho de Melob079d4e2011-10-17 09:05:04 -0200140void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
Arnaldo Carvalho de Meloe345fa12011-10-13 09:06:54 -0300141{
Arnaldo Carvalho de Melob079d4e2011-10-17 09:05:04 -0200142 return __hists__decay_entries(hists, zap_user, zap_kernel, false);
Arnaldo Carvalho de Meloe345fa12011-10-13 09:06:54 -0300143}
144
Arnaldo Carvalho de Melob079d4e2011-10-17 09:05:04 -0200145void hists__decay_entries_threaded(struct hists *hists,
146 bool zap_user, bool zap_kernel)
Arnaldo Carvalho de Meloe345fa12011-10-13 09:06:54 -0300147{
Arnaldo Carvalho de Melob079d4e2011-10-17 09:05:04 -0200148 return __hists__decay_entries(hists, zap_user, zap_kernel, true);
Arnaldo Carvalho de Meloe345fa12011-10-13 09:06:54 -0300149}
150
John Kacur3d1d07e2009-09-28 15:32:55 +0200151/*
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300152 * histogram, sorted on item, collects periods
John Kacur3d1d07e2009-09-28 15:32:55 +0200153 */
154
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300155static struct hist_entry *hist_entry__new(struct hist_entry *template)
156{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200157 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300158 struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
159
160 if (self != NULL) {
161 *self = *template;
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300162 self->nr_events = 1;
Arnaldo Carvalho de Melo0a1eae32010-08-02 19:45:23 -0300163 if (self->ms.map)
164 self->ms.map->referenced = true;
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300165 if (symbol_conf.use_callchain)
166 callchain_init(self->callchain);
167 }
168
169 return self;
170}
171
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300172static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300173{
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300174 if (!h->filtered) {
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300175 hists__calc_col_len(hists, h);
176 ++hists->nr_entries;
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300177 hists->stats.total_period += h->period;
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300178 }
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300179}
180
Arnaldo Carvalho de Melo7a007ca2010-07-21 09:19:41 -0300181static u8 symbol__parent_filter(const struct symbol *parent)
182{
183 if (symbol_conf.exclude_other && parent == NULL)
184 return 1 << HIST_FILTER__PARENT;
185 return 0;
186}
187
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300188struct hist_entry *__hists__add_entry(struct hists *hists,
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300189 struct addr_location *al,
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300190 struct symbol *sym_parent, u64 period)
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300191{
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300192 struct rb_node **p;
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300193 struct rb_node *parent = NULL;
194 struct hist_entry *he;
195 struct hist_entry entry = {
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -0200196 .thread = al->thread,
Arnaldo Carvalho de Melo59fd5302010-03-24 16:40:17 -0300197 .ms = {
198 .map = al->map,
199 .sym = al->sym,
200 },
Arun Sharmaf60f3592010-06-04 11:27:10 -0300201 .cpu = al->cpu,
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -0200202 .ip = al->addr,
203 .level = al->level,
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300204 .period = period,
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300205 .parent = sym_parent,
Arnaldo Carvalho de Melo7a007ca2010-07-21 09:19:41 -0300206 .filtered = symbol__parent_filter(sym_parent),
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300207 };
208 int cmp;
209
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300210 pthread_mutex_lock(&hists->lock);
211
212 p = &hists->entries_in->rb_node;
213
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300214 while (*p != NULL) {
215 parent = *p;
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300216 he = rb_entry(parent, struct hist_entry, rb_node_in);
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300217
218 cmp = hist_entry__cmp(&entry, he);
219
220 if (!cmp) {
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300221 he->period += period;
222 ++he->nr_events;
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300223 goto out;
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300224 }
225
226 if (cmp < 0)
227 p = &(*p)->rb_left;
228 else
229 p = &(*p)->rb_right;
230 }
231
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300232 he = hist_entry__new(&entry);
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300233 if (!he)
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300234 goto out_unlock;
235
236 rb_link_node(&he->rb_node_in, parent, p);
237 rb_insert_color(&he->rb_node_in, hists->entries_in);
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300238out:
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300239 hist_entry__add_cpumode_period(he, al->cpumode, period);
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300240out_unlock:
241 pthread_mutex_unlock(&hists->lock);
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300242 return he;
243}
244
John Kacur3d1d07e2009-09-28 15:32:55 +0200245int64_t
246hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
247{
248 struct sort_entry *se;
249 int64_t cmp = 0;
250
251 list_for_each_entry(se, &hist_entry__sort_list, list) {
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200252 cmp = se->se_cmp(left, right);
John Kacur3d1d07e2009-09-28 15:32:55 +0200253 if (cmp)
254 break;
255 }
256
257 return cmp;
258}
259
260int64_t
261hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
262{
263 struct sort_entry *se;
264 int64_t cmp = 0;
265
266 list_for_each_entry(se, &hist_entry__sort_list, list) {
267 int64_t (*f)(struct hist_entry *, struct hist_entry *);
268
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200269 f = se->se_collapse ?: se->se_cmp;
John Kacur3d1d07e2009-09-28 15:32:55 +0200270
271 cmp = f(left, right);
272 if (cmp)
273 break;
274 }
275
276 return cmp;
277}
278
279void hist_entry__free(struct hist_entry *he)
280{
281 free(he);
282}
283
284/*
285 * collapse the histogram
286 */
287
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300288static bool hists__collapse_insert_entry(struct hists *hists,
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100289 struct rb_root *root,
290 struct hist_entry *he)
John Kacur3d1d07e2009-09-28 15:32:55 +0200291{
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200292 struct rb_node **p = &root->rb_node;
John Kacur3d1d07e2009-09-28 15:32:55 +0200293 struct rb_node *parent = NULL;
294 struct hist_entry *iter;
295 int64_t cmp;
296
297 while (*p != NULL) {
298 parent = *p;
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300299 iter = rb_entry(parent, struct hist_entry, rb_node_in);
John Kacur3d1d07e2009-09-28 15:32:55 +0200300
301 cmp = hist_entry__collapse(iter, he);
302
303 if (!cmp) {
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300304 iter->period += he->period;
Stephane Eraniane39622c2011-10-03 11:38:15 +0200305 iter->nr_events += he->nr_events;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100306 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300307 callchain_cursor_reset(&hists->callchain_cursor);
308 callchain_merge(&hists->callchain_cursor, iter->callchain,
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100309 he->callchain);
310 }
John Kacur3d1d07e2009-09-28 15:32:55 +0200311 hist_entry__free(he);
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300312 return false;
John Kacur3d1d07e2009-09-28 15:32:55 +0200313 }
314
315 if (cmp < 0)
316 p = &(*p)->rb_left;
317 else
318 p = &(*p)->rb_right;
319 }
320
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300321 rb_link_node(&he->rb_node_in, parent, p);
322 rb_insert_color(&he->rb_node_in, root);
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300323 return true;
John Kacur3d1d07e2009-09-28 15:32:55 +0200324}
325
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300326static struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
327{
328 struct rb_root *root;
329
330 pthread_mutex_lock(&hists->lock);
331
332 root = hists->entries_in;
333 if (++hists->entries_in > &hists->entries_in_array[1])
334 hists->entries_in = &hists->entries_in_array[0];
335
336 pthread_mutex_unlock(&hists->lock);
337
338 return root;
339}
340
341static void __hists__collapse_resort(struct hists *hists, bool threaded)
342{
343 struct rb_root *root;
344 struct rb_node *next;
345 struct hist_entry *n;
346
347 if (!sort__need_collapse && !threaded)
348 return;
349
350 root = hists__get_rotate_entries_in(hists);
351 next = rb_first(root);
352 hists->stats.total_period = 0;
353
354 while (next) {
355 n = rb_entry(next, struct hist_entry, rb_node_in);
356 next = rb_next(&n->rb_node_in);
357
358 rb_erase(&n->rb_node_in, root);
359 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n))
360 hists__inc_nr_entries(hists, n);
361 }
362}
363
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300364void hists__collapse_resort(struct hists *hists)
John Kacur3d1d07e2009-09-28 15:32:55 +0200365{
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300366 return __hists__collapse_resort(hists, false);
367}
John Kacur3d1d07e2009-09-28 15:32:55 +0200368
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300369void hists__collapse_resort_threaded(struct hists *hists)
370{
371 return __hists__collapse_resort(hists, true);
John Kacur3d1d07e2009-09-28 15:32:55 +0200372}
373
374/*
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300375 * reverse the map, sort on period.
John Kacur3d1d07e2009-09-28 15:32:55 +0200376 */
377
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300378static void __hists__insert_output_entry(struct rb_root *entries,
379 struct hist_entry *he,
380 u64 min_callchain_hits)
John Kacur3d1d07e2009-09-28 15:32:55 +0200381{
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300382 struct rb_node **p = &entries->rb_node;
John Kacur3d1d07e2009-09-28 15:32:55 +0200383 struct rb_node *parent = NULL;
384 struct hist_entry *iter;
385
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -0200386 if (symbol_conf.use_callchain)
Arnaldo Carvalho de Melob9fb9302010-04-02 09:50:42 -0300387 callchain_param.sort(&he->sorted_chain, he->callchain,
John Kacur3d1d07e2009-09-28 15:32:55 +0200388 min_callchain_hits, &callchain_param);
389
390 while (*p != NULL) {
391 parent = *p;
392 iter = rb_entry(parent, struct hist_entry, rb_node);
393
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300394 if (he->period > iter->period)
John Kacur3d1d07e2009-09-28 15:32:55 +0200395 p = &(*p)->rb_left;
396 else
397 p = &(*p)->rb_right;
398 }
399
400 rb_link_node(&he->rb_node, parent, p);
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300401 rb_insert_color(&he->rb_node, entries);
John Kacur3d1d07e2009-09-28 15:32:55 +0200402}
403
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300404static void __hists__output_resort(struct hists *hists, bool threaded)
John Kacur3d1d07e2009-09-28 15:32:55 +0200405{
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300406 struct rb_root *root;
John Kacur3d1d07e2009-09-28 15:32:55 +0200407 struct rb_node *next;
408 struct hist_entry *n;
John Kacur3d1d07e2009-09-28 15:32:55 +0200409 u64 min_callchain_hits;
410
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300411 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
John Kacur3d1d07e2009-09-28 15:32:55 +0200412
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300413 if (sort__need_collapse || threaded)
414 root = &hists->entries_collapsed;
415 else
416 root = hists->entries_in;
417
418 next = rb_first(root);
419 hists->entries = RB_ROOT;
John Kacur3d1d07e2009-09-28 15:32:55 +0200420
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300421 hists->nr_entries = 0;
422 hists__reset_col_len(hists);
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300423
John Kacur3d1d07e2009-09-28 15:32:55 +0200424 while (next) {
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300425 n = rb_entry(next, struct hist_entry, rb_node_in);
426 next = rb_next(&n->rb_node_in);
John Kacur3d1d07e2009-09-28 15:32:55 +0200427
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300428 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300429 hists__inc_nr_entries(hists, n);
John Kacur3d1d07e2009-09-28 15:32:55 +0200430 }
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300431}
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200432
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300433void hists__output_resort(struct hists *hists)
434{
435 return __hists__output_resort(hists, false);
436}
437
438void hists__output_resort_threaded(struct hists *hists)
439{
440 return __hists__output_resort(hists, true);
John Kacur3d1d07e2009-09-28 15:32:55 +0200441}
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200442
443static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
444{
445 int i;
446 int ret = fprintf(fp, " ");
447
448 for (i = 0; i < left_margin; i++)
449 ret += fprintf(fp, " ");
450
451 return ret;
452}
453
454static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
455 int left_margin)
456{
457 int i;
458 size_t ret = callchain__fprintf_left_margin(fp, left_margin);
459
460 for (i = 0; i < depth; i++)
461 if (depth_mask & (1 << i))
462 ret += fprintf(fp, "| ");
463 else
464 ret += fprintf(fp, " ");
465
466 ret += fprintf(fp, "\n");
467
468 return ret;
469}
470
471static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300472 int depth, int depth_mask, int period,
Frederic Weisbeckerd425de52011-01-03 16:13:11 +0100473 u64 total_samples, u64 hits,
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200474 int left_margin)
475{
476 int i;
477 size_t ret = 0;
478
479 ret += callchain__fprintf_left_margin(fp, left_margin);
480 for (i = 0; i < depth; i++) {
481 if (depth_mask & (1 << i))
482 ret += fprintf(fp, "|");
483 else
484 ret += fprintf(fp, " ");
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300485 if (!period && i == depth - 1) {
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200486 double percent;
487
488 percent = hits * 100.0 / total_samples;
489 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
490 } else
491 ret += fprintf(fp, "%s", " ");
492 }
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300493 if (chain->ms.sym)
494 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200495 else
496 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
497
498 return ret;
499}
500
501static struct symbol *rem_sq_bracket;
502static struct callchain_list rem_hits;
503
504static void init_rem_hits(void)
505{
506 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
507 if (!rem_sq_bracket) {
508 fprintf(stderr, "Not enough memory to display remaining hits\n");
509 return;
510 }
511
512 strcpy(rem_sq_bracket->name, "[...]");
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300513 rem_hits.ms.sym = rem_sq_bracket;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200514}
515
516static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
517 u64 total_samples, int depth,
518 int depth_mask, int left_margin)
519{
520 struct rb_node *node, *next;
521 struct callchain_node *child;
522 struct callchain_list *chain;
523 int new_depth_mask = depth_mask;
524 u64 new_total;
525 u64 remaining;
526 size_t ret = 0;
527 int i;
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300528 uint entries_printed = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200529
530 if (callchain_param.mode == CHAIN_GRAPH_REL)
531 new_total = self->children_hit;
532 else
533 new_total = total_samples;
534
535 remaining = new_total;
536
537 node = rb_first(&self->rb_root);
538 while (node) {
539 u64 cumul;
540
541 child = rb_entry(node, struct callchain_node, rb_node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100542 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200543 remaining -= cumul;
544
545 /*
546 * The depth mask manages the output of pipes that show
547 * the depth. We don't want to keep the pipes of the current
548 * level for the last child of this depth.
549 * Except if we have remaining filtered hits. They will
550 * supersede the last child
551 */
552 next = rb_next(node);
553 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
554 new_depth_mask &= ~(1 << (depth - 1));
555
556 /*
Daniel Mack3ad2f3f2010-02-03 08:01:28 +0800557 * But we keep the older depth mask for the line separator
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200558 * to keep the level link until we reach the last child
559 */
560 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
561 left_margin);
562 i = 0;
563 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200564 ret += ipchain__fprintf_graph(fp, chain, depth,
565 new_depth_mask, i++,
566 new_total,
567 cumul,
568 left_margin);
569 }
570 ret += __callchain__fprintf_graph(fp, child, new_total,
571 depth + 1,
572 new_depth_mask | (1 << depth),
573 left_margin);
574 node = next;
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300575 if (++entries_printed == callchain_param.print_limit)
576 break;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200577 }
578
579 if (callchain_param.mode == CHAIN_GRAPH_REL &&
580 remaining && remaining != new_total) {
581
582 if (!rem_sq_bracket)
583 return ret;
584
585 new_depth_mask &= ~(1 << (depth - 1));
586
587 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
588 new_depth_mask, 0, new_total,
589 remaining, left_margin);
590 }
591
592 return ret;
593}
594
595static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
596 u64 total_samples, int left_margin)
597{
598 struct callchain_list *chain;
599 bool printed = false;
600 int i = 0;
601 int ret = 0;
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300602 u32 entries_printed = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200603
604 list_for_each_entry(chain, &self->val, list) {
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200605 if (!i++ && sort__first_dimension == SORT_SYM)
606 continue;
607
608 if (!printed) {
609 ret += callchain__fprintf_left_margin(fp, left_margin);
610 ret += fprintf(fp, "|\n");
611 ret += callchain__fprintf_left_margin(fp, left_margin);
612 ret += fprintf(fp, "---");
613
614 left_margin += 3;
615 printed = true;
616 } else
617 ret += callchain__fprintf_left_margin(fp, left_margin);
618
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300619 if (chain->ms.sym)
620 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200621 else
622 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300623
624 if (++entries_printed == callchain_param.print_limit)
625 break;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200626 }
627
628 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
629
630 return ret;
631}
632
633static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
634 u64 total_samples)
635{
636 struct callchain_list *chain;
637 size_t ret = 0;
638
639 if (!self)
640 return 0;
641
642 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
643
644
645 list_for_each_entry(chain, &self->val, list) {
646 if (chain->ip >= PERF_CONTEXT_MAX)
647 continue;
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300648 if (chain->ms.sym)
649 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200650 else
651 ret += fprintf(fp, " %p\n",
652 (void *)(long)chain->ip);
653 }
654
655 return ret;
656}
657
658static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
659 u64 total_samples, int left_margin)
660{
661 struct rb_node *rb_node;
662 struct callchain_node *chain;
663 size_t ret = 0;
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300664 u32 entries_printed = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200665
666 rb_node = rb_first(&self->sorted_chain);
667 while (rb_node) {
668 double percent;
669
670 chain = rb_entry(rb_node, struct callchain_node, rb_node);
671 percent = chain->hit * 100.0 / total_samples;
672 switch (callchain_param.mode) {
673 case CHAIN_FLAT:
674 ret += percent_color_fprintf(fp, " %6.2f%%\n",
675 percent);
676 ret += callchain__fprintf_flat(fp, chain, total_samples);
677 break;
678 case CHAIN_GRAPH_ABS: /* Falldown */
679 case CHAIN_GRAPH_REL:
680 ret += callchain__fprintf_graph(fp, chain, total_samples,
681 left_margin);
682 case CHAIN_NONE:
683 default:
684 break;
685 }
686 ret += fprintf(fp, "\n");
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300687 if (++entries_printed == callchain_param.print_limit)
688 break;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200689 rb_node = rb_next(rb_node);
690 }
691
692 return ret;
693}
694
Arnaldo Carvalho de Meloab81f3f2011-10-05 19:16:15 -0300695void hists__output_recalc_col_len(struct hists *hists, int max_rows)
696{
697 struct rb_node *next = rb_first(&hists->entries);
698 struct hist_entry *n;
699 int row = 0;
700
701 hists__reset_col_len(hists);
702
703 while (next && row++ < max_rows) {
704 n = rb_entry(next, struct hist_entry, rb_node);
705 hists__calc_col_len(hists, n);
706 next = rb_next(&n->rb_node);
707 }
708}
709
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300710int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300711 struct hists *hists, struct hists *pair_hists,
712 bool show_displacement, long displacement,
713 bool color, u64 session_total)
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200714{
715 struct sort_entry *se;
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300716 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200717 u64 nr_events;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200718 const char *sep = symbol_conf.field_sep;
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300719 int ret;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200720
721 if (symbol_conf.exclude_other && !self->parent)
722 return 0;
723
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300724 if (pair_hists) {
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300725 period = self->pair ? self->pair->period : 0;
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200726 nr_events = self->pair ? self->pair->nr_events : 0;
Arnaldo Carvalho de Melocee75ac2010-05-14 13:16:55 -0300727 total = pair_hists->stats.total_period;
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300728 period_sys = self->pair ? self->pair->period_sys : 0;
729 period_us = self->pair ? self->pair->period_us : 0;
730 period_guest_sys = self->pair ? self->pair->period_guest_sys : 0;
731 period_guest_us = self->pair ? self->pair->period_guest_us : 0;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200732 } else {
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300733 period = self->period;
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200734 nr_events = self->nr_events;
Eric B Munsoneefc4652010-03-05 12:51:08 -0300735 total = session_total;
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300736 period_sys = self->period_sys;
737 period_us = self->period_us;
738 period_guest_sys = self->period_guest_sys;
739 period_guest_us = self->period_guest_us;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200740 }
741
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300742 if (total) {
743 if (color)
744 ret = percent_color_snprintf(s, size,
745 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300746 (period * 100.0) / total);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300747 else
748 ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300749 (period * 100.0) / total);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800750 if (symbol_conf.show_cpu_utilization) {
751 ret += percent_color_snprintf(s + ret, size - ret,
752 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300753 (period_sys * 100.0) / total);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800754 ret += percent_color_snprintf(s + ret, size - ret,
755 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300756 (period_us * 100.0) / total);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800757 if (perf_guest) {
758 ret += percent_color_snprintf(s + ret,
759 size - ret,
760 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300761 (period_guest_sys * 100.0) /
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800762 total);
763 ret += percent_color_snprintf(s + ret,
764 size - ret,
765 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300766 (period_guest_us * 100.0) /
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800767 total);
768 }
769 }
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300770 } else
Arnaldo Carvalho de Melo9486aa32011-01-22 20:37:02 -0200771 ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200772
773 if (symbol_conf.show_nr_samples) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200774 if (sep)
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200775 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200776 else
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200777 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200778 }
779
Arnaldo Carvalho de Melo3f2728b2011-10-05 16:10:06 -0300780 if (symbol_conf.show_total_period) {
781 if (sep)
782 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
783 else
784 ret += snprintf(s + ret, size - ret, " %12" PRIu64, period);
785 }
786
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300787 if (pair_hists) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200788 char bf[32];
789 double old_percent = 0, new_percent = 0, diff;
790
791 if (total > 0)
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300792 old_percent = (period * 100.0) / total;
Eric B Munsoneefc4652010-03-05 12:51:08 -0300793 if (session_total > 0)
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300794 new_percent = (self->period * 100.0) / session_total;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200795
Arnaldo Carvalho de Melo9b338272009-12-16 14:31:49 -0200796 diff = new_percent - old_percent;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200797
Arnaldo Carvalho de Melo9b338272009-12-16 14:31:49 -0200798 if (fabs(diff) >= 0.01)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200799 snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
800 else
801 snprintf(bf, sizeof(bf), " ");
802
803 if (sep)
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300804 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200805 else
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300806 ret += snprintf(s + ret, size - ret, "%11.11s", bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200807
808 if (show_displacement) {
809 if (displacement)
810 snprintf(bf, sizeof(bf), "%+4ld", displacement);
811 else
812 snprintf(bf, sizeof(bf), " ");
813
814 if (sep)
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300815 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200816 else
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300817 ret += snprintf(s + ret, size - ret, "%6.6s", bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200818 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200819 }
820
821 list_for_each_entry(se, &hist_entry__sort_list, list) {
822 if (se->elide)
823 continue;
824
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300825 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200826 ret += se->se_snprintf(self, s + ret, size - ret,
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300827 hists__col_len(hists, se->se_width_idx));
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200828 }
829
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300830 return ret;
831}
832
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300833int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300834 struct hists *pair_hists, bool show_displacement,
835 long displacement, FILE *fp, u64 session_total)
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300836{
837 char bf[512];
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300838
839 if (size == 0 || size > sizeof(bf))
840 size = sizeof(bf);
841
842 hist_entry__snprintf(he, bf, size, hists, pair_hists,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300843 show_displacement, displacement,
844 true, session_total);
845 return fprintf(fp, "%s\n", bf);
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300846}
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200847
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300848static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
849 struct hists *hists, FILE *fp,
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300850 u64 session_total)
851{
852 int left_margin = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200853
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300854 if (sort__first_dimension == SORT_COMM) {
855 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
856 typeof(*se), list);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300857 left_margin = hists__col_len(hists, se->se_width_idx);
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300858 left_margin -= thread__comm_len(self->thread);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200859 }
860
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300861 return hist_entry_callchain__fprintf(fp, self, session_total,
862 left_margin);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200863}
864
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300865size_t hists__fprintf(struct hists *hists, struct hists *pair,
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300866 bool show_displacement, bool show_header, int max_rows,
867 int max_cols, FILE *fp)
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200868{
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200869 struct sort_entry *se;
870 struct rb_node *nd;
871 size_t ret = 0;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200872 unsigned long position = 1;
873 long displacement = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200874 unsigned int width;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200875 const char *sep = symbol_conf.field_sep;
Arnaldo Carvalho de Meloedb7c602010-05-17 16:22:41 -0300876 const char *col_width = symbol_conf.col_width_list_str;
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300877 int nr_rows = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200878
879 init_rem_hits();
880
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300881 if (!show_header)
882 goto print_entries;
883
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200884 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
885
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200886 if (symbol_conf.show_nr_samples) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200887 if (sep)
888 fprintf(fp, "%cSamples", *sep);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200889 else
890 fputs(" Samples ", fp);
891 }
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200892
Arnaldo Carvalho de Melo3f2728b2011-10-05 16:10:06 -0300893 if (symbol_conf.show_total_period) {
894 if (sep)
895 ret += fprintf(fp, "%cPeriod", *sep);
896 else
897 ret += fprintf(fp, " Period ");
898 }
899
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800900 if (symbol_conf.show_cpu_utilization) {
901 if (sep) {
902 ret += fprintf(fp, "%csys", *sep);
903 ret += fprintf(fp, "%cus", *sep);
904 if (perf_guest) {
905 ret += fprintf(fp, "%cguest sys", *sep);
906 ret += fprintf(fp, "%cguest us", *sep);
907 }
908 } else {
909 ret += fprintf(fp, " sys ");
910 ret += fprintf(fp, " us ");
911 if (perf_guest) {
912 ret += fprintf(fp, " guest sys ");
913 ret += fprintf(fp, " guest us ");
914 }
915 }
916 }
917
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200918 if (pair) {
919 if (sep)
920 ret += fprintf(fp, "%cDelta", *sep);
921 else
922 ret += fprintf(fp, " Delta ");
923
924 if (show_displacement) {
925 if (sep)
926 ret += fprintf(fp, "%cDisplacement", *sep);
927 else
928 ret += fprintf(fp, " Displ");
929 }
930 }
931
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200932 list_for_each_entry(se, &hist_entry__sort_list, list) {
933 if (se->elide)
934 continue;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200935 if (sep) {
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200936 fprintf(fp, "%c%s", *sep, se->se_header);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200937 continue;
938 }
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200939 width = strlen(se->se_header);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300940 if (symbol_conf.col_width_list_str) {
941 if (col_width) {
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300942 hists__set_col_len(hists, se->se_width_idx,
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300943 atoi(col_width));
944 col_width = strchr(col_width, ',');
945 if (col_width)
946 ++col_width;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200947 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200948 }
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300949 if (!hists__new_col_len(hists, se->se_width_idx, width))
950 width = hists__col_len(hists, se->se_width_idx);
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200951 fprintf(fp, " %*s", width, se->se_header);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200952 }
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300953
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200954 fprintf(fp, "\n");
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300955 if (max_rows && ++nr_rows >= max_rows)
956 goto out;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200957
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200958 if (sep)
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200959 goto print_entries;
960
961 fprintf(fp, "# ........");
962 if (symbol_conf.show_nr_samples)
963 fprintf(fp, " ..........");
Arnaldo Carvalho de Melo3f2728b2011-10-05 16:10:06 -0300964 if (symbol_conf.show_total_period)
965 fprintf(fp, " ............");
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200966 if (pair) {
967 fprintf(fp, " ..........");
968 if (show_displacement)
969 fprintf(fp, " .....");
970 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200971 list_for_each_entry(se, &hist_entry__sort_list, list) {
972 unsigned int i;
973
974 if (se->elide)
975 continue;
976
977 fprintf(fp, " ");
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300978 width = hists__col_len(hists, se->se_width_idx);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300979 if (width == 0)
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200980 width = strlen(se->se_header);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200981 for (i = 0; i < width; i++)
982 fprintf(fp, ".");
983 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200984
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300985 fprintf(fp, "\n");
986 if (max_rows && ++nr_rows >= max_rows)
987 goto out;
988
989 fprintf(fp, "#\n");
990 if (max_rows && ++nr_rows >= max_rows)
991 goto out;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200992
993print_entries:
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300994 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200995 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
996
Frederic Weisbeckere84d2122011-06-29 22:23:03 +0200997 if (h->filtered)
998 continue;
999
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001000 if (show_displacement) {
1001 if (h->pair != NULL)
1002 displacement = ((long)h->pair->position -
1003 (long)position);
1004 else
1005 displacement = 0;
1006 ++position;
1007 }
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -03001008 ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement,
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001009 displacement, fp, hists->stats.total_period);
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -03001010
1011 if (symbol_conf.use_callchain)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001012 ret += hist_entry__fprintf_callchain(h, hists, fp,
1013 hists->stats.total_period);
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -03001014 if (max_rows && ++nr_rows >= max_rows)
1015 goto out;
1016
Arnaldo Carvalho de Melo59fd5302010-03-24 16:40:17 -03001017 if (h->ms.map == NULL && verbose > 1) {
Arnaldo Carvalho de Melo65f2ed22010-03-09 15:58:17 -03001018 __map_groups__fprintf_maps(&h->thread->mg,
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -03001019 MAP__FUNCTION, verbose, fp);
Arnaldo Carvalho de Melo65f2ed22010-03-09 15:58:17 -03001020 fprintf(fp, "%.10s end\n", graph_dotted_line);
1021 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -02001022 }
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -03001023out:
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -02001024 free(rem_sq_bracket);
1025
1026 return ret;
1027}
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001028
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -03001029/*
1030 * See hists__fprintf to match the column widths
1031 */
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001032unsigned int hists__sort_list_width(struct hists *hists)
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -03001033{
1034 struct sort_entry *se;
1035 int ret = 9; /* total % */
1036
1037 if (symbol_conf.show_cpu_utilization) {
1038 ret += 7; /* count_sys % */
1039 ret += 6; /* count_us % */
1040 if (perf_guest) {
1041 ret += 13; /* count_guest_sys % */
1042 ret += 12; /* count_guest_us % */
1043 }
1044 }
1045
1046 if (symbol_conf.show_nr_samples)
1047 ret += 11;
1048
Arnaldo Carvalho de Melo3f2728b2011-10-05 16:10:06 -03001049 if (symbol_conf.show_total_period)
1050 ret += 13;
1051
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -03001052 list_for_each_entry(se, &hist_entry__sort_list, list)
1053 if (!se->elide)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001054 ret += 2 + hists__col_len(hists, se->se_width_idx);
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -03001055
Arnaldo Carvalho de Melo903cce62010-08-05 19:15:48 -03001056 if (verbose) /* Addr + origin */
1057 ret += 3 + BITS_PER_LONG / 4;
1058
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -03001059 return ret;
1060}
1061
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001062static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
Arnaldo Carvalho de Melocc5edb02010-07-16 12:35:07 -03001063 enum hist_filter filter)
1064{
1065 h->filtered &= ~(1 << filter);
1066 if (h->filtered)
1067 return;
1068
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001069 ++hists->nr_entries;
Arnaldo Carvalho de Melo0f0cbf72010-07-26 17:13:40 -03001070 if (h->ms.unfolded)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001071 hists->nr_entries += h->nr_rows;
Arnaldo Carvalho de Melo0f0cbf72010-07-26 17:13:40 -03001072 h->row_offset = 0;
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001073 hists->stats.total_period += h->period;
1074 hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
Arnaldo Carvalho de Melocc5edb02010-07-16 12:35:07 -03001075
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001076 hists__calc_col_len(hists, h);
Arnaldo Carvalho de Melocc5edb02010-07-16 12:35:07 -03001077}
1078
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001079void hists__filter_by_dso(struct hists *hists, const struct dso *dso)
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001080{
1081 struct rb_node *nd;
1082
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001083 hists->nr_entries = hists->stats.total_period = 0;
1084 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
1085 hists__reset_col_len(hists);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001086
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001087 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001088 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1089
1090 if (symbol_conf.exclude_other && !h->parent)
1091 continue;
1092
1093 if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) {
1094 h->filtered |= (1 << HIST_FILTER__DSO);
1095 continue;
1096 }
1097
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001098 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001099 }
1100}
1101
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001102void hists__filter_by_thread(struct hists *hists, const struct thread *thread)
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001103{
1104 struct rb_node *nd;
1105
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001106 hists->nr_entries = hists->stats.total_period = 0;
1107 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
1108 hists__reset_col_len(hists);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001109
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001110 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001111 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1112
1113 if (thread != NULL && h->thread != thread) {
1114 h->filtered |= (1 << HIST_FILTER__THREAD);
1115 continue;
1116 }
Arnaldo Carvalho de Melocc5edb02010-07-16 12:35:07 -03001117
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001118 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001119 }
1120}
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001121
Arnaldo Carvalho de Melo2f525d02011-02-04 13:43:24 -02001122int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001123{
Arnaldo Carvalho de Melo2f525d02011-02-04 13:43:24 -02001124 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001125}
1126
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -02001127int hist_entry__annotate(struct hist_entry *he, size_t privsize)
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001128{
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -02001129 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001130}
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001131
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001132void hists__inc_nr_events(struct hists *hists, u32 type)
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001133{
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001134 ++hists->stats.nr_events[0];
1135 ++hists->stats.nr_events[type];
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001136}
1137
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001138size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001139{
1140 int i;
1141 size_t ret = 0;
1142
1143 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
Arnaldo Carvalho de Meloe248de32011-03-05 21:40:06 -03001144 const char *name;
Thomas Gleixner3835bc02010-12-07 12:48:42 +00001145
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001146 if (hists->stats.nr_events[i] == 0)
Arnaldo Carvalho de Meloe248de32011-03-05 21:40:06 -03001147 continue;
1148
1149 name = perf_event__name(i);
Thomas Gleixner3835bc02010-12-07 12:48:42 +00001150 if (!strcmp(name, "UNKNOWN"))
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001151 continue;
Thomas Gleixner3835bc02010-12-07 12:48:42 +00001152
1153 ret += fprintf(fp, "%16s events: %10d\n", name,
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001154 hists->stats.nr_events[i]);
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001155 }
1156
1157 return ret;
1158}
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -03001159
1160void hists__init(struct hists *hists)
1161{
1162 memset(hists, 0, sizeof(*hists));
1163 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
1164 hists->entries_in = &hists->entries_in_array[0];
1165 hists->entries_collapsed = RB_ROOT;
1166 hists->entries = RB_ROOT;
1167 pthread_mutex_init(&hists->lock, NULL);
1168}