blob: 87ef5c7797dec86e256115b94ace1dd779d7ace6 [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{
103 hists->stats.total_period -= he->period;
104 hist_entry__decay(he);
105 hists->stats.total_period += he->period;
106 return he->period == 0;
107}
108
109void hists__decay_entries(struct hists *hists)
110{
111 struct rb_node *next = rb_first(&hists->entries);
112 struct hist_entry *n;
113
114 while (next) {
115 n = rb_entry(next, struct hist_entry, rb_node);
116 next = rb_next(&n->rb_node);
117
118 if (hists__decay_entry(hists, n)) {
119 rb_erase(&n->rb_node, &hists->entries);
120
121 if (sort__need_collapse)
122 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
123
124 hist_entry__free(n);
125 --hists->nr_entries;
126 }
127 }
128}
129
John Kacur3d1d07e2009-09-28 15:32:55 +0200130/*
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300131 * histogram, sorted on item, collects periods
John Kacur3d1d07e2009-09-28 15:32:55 +0200132 */
133
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300134static struct hist_entry *hist_entry__new(struct hist_entry *template)
135{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200136 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300137 struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
138
139 if (self != NULL) {
140 *self = *template;
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300141 self->nr_events = 1;
Arnaldo Carvalho de Melo0a1eae32010-08-02 19:45:23 -0300142 if (self->ms.map)
143 self->ms.map->referenced = true;
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300144 if (symbol_conf.use_callchain)
145 callchain_init(self->callchain);
146 }
147
148 return self;
149}
150
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300151static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300152{
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300153 if (!h->filtered) {
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300154 hists__calc_col_len(hists, h);
155 ++hists->nr_entries;
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300156 hists->stats.total_period += h->period;
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300157 }
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300158}
159
Arnaldo Carvalho de Melo7a007ca2010-07-21 09:19:41 -0300160static u8 symbol__parent_filter(const struct symbol *parent)
161{
162 if (symbol_conf.exclude_other && parent == NULL)
163 return 1 << HIST_FILTER__PARENT;
164 return 0;
165}
166
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300167struct hist_entry *__hists__add_entry(struct hists *hists,
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300168 struct addr_location *al,
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300169 struct symbol *sym_parent, u64 period)
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300170{
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300171 struct rb_node **p;
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300172 struct rb_node *parent = NULL;
173 struct hist_entry *he;
174 struct hist_entry entry = {
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -0200175 .thread = al->thread,
Arnaldo Carvalho de Melo59fd5302010-03-24 16:40:17 -0300176 .ms = {
177 .map = al->map,
178 .sym = al->sym,
179 },
Arun Sharmaf60f3592010-06-04 11:27:10 -0300180 .cpu = al->cpu,
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -0200181 .ip = al->addr,
182 .level = al->level,
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300183 .period = period,
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300184 .parent = sym_parent,
Arnaldo Carvalho de Melo7a007ca2010-07-21 09:19:41 -0300185 .filtered = symbol__parent_filter(sym_parent),
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300186 };
187 int cmp;
188
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300189 pthread_mutex_lock(&hists->lock);
190
191 p = &hists->entries_in->rb_node;
192
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300193 while (*p != NULL) {
194 parent = *p;
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300195 he = rb_entry(parent, struct hist_entry, rb_node_in);
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300196
197 cmp = hist_entry__cmp(&entry, he);
198
199 if (!cmp) {
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300200 he->period += period;
201 ++he->nr_events;
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300202 goto out;
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300203 }
204
205 if (cmp < 0)
206 p = &(*p)->rb_left;
207 else
208 p = &(*p)->rb_right;
209 }
210
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300211 he = hist_entry__new(&entry);
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300212 if (!he)
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300213 goto out_unlock;
214
215 rb_link_node(&he->rb_node_in, parent, p);
216 rb_insert_color(&he->rb_node_in, hists->entries_in);
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300217out:
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300218 hist_entry__add_cpumode_period(he, al->cpumode, period);
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300219out_unlock:
220 pthread_mutex_unlock(&hists->lock);
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300221 return he;
222}
223
John Kacur3d1d07e2009-09-28 15:32:55 +0200224int64_t
225hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
226{
227 struct sort_entry *se;
228 int64_t cmp = 0;
229
230 list_for_each_entry(se, &hist_entry__sort_list, list) {
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200231 cmp = se->se_cmp(left, right);
John Kacur3d1d07e2009-09-28 15:32:55 +0200232 if (cmp)
233 break;
234 }
235
236 return cmp;
237}
238
239int64_t
240hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
241{
242 struct sort_entry *se;
243 int64_t cmp = 0;
244
245 list_for_each_entry(se, &hist_entry__sort_list, list) {
246 int64_t (*f)(struct hist_entry *, struct hist_entry *);
247
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200248 f = se->se_collapse ?: se->se_cmp;
John Kacur3d1d07e2009-09-28 15:32:55 +0200249
250 cmp = f(left, right);
251 if (cmp)
252 break;
253 }
254
255 return cmp;
256}
257
258void hist_entry__free(struct hist_entry *he)
259{
260 free(he);
261}
262
263/*
264 * collapse the histogram
265 */
266
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300267static bool hists__collapse_insert_entry(struct hists *hists,
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100268 struct rb_root *root,
269 struct hist_entry *he)
John Kacur3d1d07e2009-09-28 15:32:55 +0200270{
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200271 struct rb_node **p = &root->rb_node;
John Kacur3d1d07e2009-09-28 15:32:55 +0200272 struct rb_node *parent = NULL;
273 struct hist_entry *iter;
274 int64_t cmp;
275
276 while (*p != NULL) {
277 parent = *p;
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300278 iter = rb_entry(parent, struct hist_entry, rb_node_in);
John Kacur3d1d07e2009-09-28 15:32:55 +0200279
280 cmp = hist_entry__collapse(iter, he);
281
282 if (!cmp) {
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300283 iter->period += he->period;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100284 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300285 callchain_cursor_reset(&hists->callchain_cursor);
286 callchain_merge(&hists->callchain_cursor, iter->callchain,
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100287 he->callchain);
288 }
John Kacur3d1d07e2009-09-28 15:32:55 +0200289 hist_entry__free(he);
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300290 return false;
John Kacur3d1d07e2009-09-28 15:32:55 +0200291 }
292
293 if (cmp < 0)
294 p = &(*p)->rb_left;
295 else
296 p = &(*p)->rb_right;
297 }
298
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300299 rb_link_node(&he->rb_node_in, parent, p);
300 rb_insert_color(&he->rb_node_in, root);
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300301 return true;
John Kacur3d1d07e2009-09-28 15:32:55 +0200302}
303
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300304static struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
305{
306 struct rb_root *root;
307
308 pthread_mutex_lock(&hists->lock);
309
310 root = hists->entries_in;
311 if (++hists->entries_in > &hists->entries_in_array[1])
312 hists->entries_in = &hists->entries_in_array[0];
313
314 pthread_mutex_unlock(&hists->lock);
315
316 return root;
317}
318
319static void __hists__collapse_resort(struct hists *hists, bool threaded)
320{
321 struct rb_root *root;
322 struct rb_node *next;
323 struct hist_entry *n;
324
325 if (!sort__need_collapse && !threaded)
326 return;
327
328 root = hists__get_rotate_entries_in(hists);
329 next = rb_first(root);
330 hists->stats.total_period = 0;
331
332 while (next) {
333 n = rb_entry(next, struct hist_entry, rb_node_in);
334 next = rb_next(&n->rb_node_in);
335
336 rb_erase(&n->rb_node_in, root);
337 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n))
338 hists__inc_nr_entries(hists, n);
339 }
340}
341
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300342void hists__collapse_resort(struct hists *hists)
John Kacur3d1d07e2009-09-28 15:32:55 +0200343{
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300344 return __hists__collapse_resort(hists, false);
345}
John Kacur3d1d07e2009-09-28 15:32:55 +0200346
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300347void hists__collapse_resort_threaded(struct hists *hists)
348{
349 return __hists__collapse_resort(hists, true);
John Kacur3d1d07e2009-09-28 15:32:55 +0200350}
351
352/*
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300353 * reverse the map, sort on period.
John Kacur3d1d07e2009-09-28 15:32:55 +0200354 */
355
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300356static void __hists__insert_output_entry(struct rb_root *entries,
357 struct hist_entry *he,
358 u64 min_callchain_hits)
John Kacur3d1d07e2009-09-28 15:32:55 +0200359{
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300360 struct rb_node **p = &entries->rb_node;
John Kacur3d1d07e2009-09-28 15:32:55 +0200361 struct rb_node *parent = NULL;
362 struct hist_entry *iter;
363
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -0200364 if (symbol_conf.use_callchain)
Arnaldo Carvalho de Melob9fb9302010-04-02 09:50:42 -0300365 callchain_param.sort(&he->sorted_chain, he->callchain,
John Kacur3d1d07e2009-09-28 15:32:55 +0200366 min_callchain_hits, &callchain_param);
367
368 while (*p != NULL) {
369 parent = *p;
370 iter = rb_entry(parent, struct hist_entry, rb_node);
371
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300372 if (he->period > iter->period)
John Kacur3d1d07e2009-09-28 15:32:55 +0200373 p = &(*p)->rb_left;
374 else
375 p = &(*p)->rb_right;
376 }
377
378 rb_link_node(&he->rb_node, parent, p);
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300379 rb_insert_color(&he->rb_node, entries);
John Kacur3d1d07e2009-09-28 15:32:55 +0200380}
381
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300382static void __hists__output_resort(struct hists *hists, bool threaded)
John Kacur3d1d07e2009-09-28 15:32:55 +0200383{
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300384 struct rb_root *root;
John Kacur3d1d07e2009-09-28 15:32:55 +0200385 struct rb_node *next;
386 struct hist_entry *n;
John Kacur3d1d07e2009-09-28 15:32:55 +0200387 u64 min_callchain_hits;
388
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300389 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
John Kacur3d1d07e2009-09-28 15:32:55 +0200390
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300391 if (sort__need_collapse || threaded)
392 root = &hists->entries_collapsed;
393 else
394 root = hists->entries_in;
395
396 next = rb_first(root);
397 hists->entries = RB_ROOT;
John Kacur3d1d07e2009-09-28 15:32:55 +0200398
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300399 hists->nr_entries = 0;
400 hists__reset_col_len(hists);
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300401
John Kacur3d1d07e2009-09-28 15:32:55 +0200402 while (next) {
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300403 n = rb_entry(next, struct hist_entry, rb_node_in);
404 next = rb_next(&n->rb_node_in);
John Kacur3d1d07e2009-09-28 15:32:55 +0200405
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300406 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300407 hists__inc_nr_entries(hists, n);
John Kacur3d1d07e2009-09-28 15:32:55 +0200408 }
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300409}
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200410
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300411void hists__output_resort(struct hists *hists)
412{
413 return __hists__output_resort(hists, false);
414}
415
416void hists__output_resort_threaded(struct hists *hists)
417{
418 return __hists__output_resort(hists, true);
John Kacur3d1d07e2009-09-28 15:32:55 +0200419}
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200420
421static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
422{
423 int i;
424 int ret = fprintf(fp, " ");
425
426 for (i = 0; i < left_margin; i++)
427 ret += fprintf(fp, " ");
428
429 return ret;
430}
431
432static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
433 int left_margin)
434{
435 int i;
436 size_t ret = callchain__fprintf_left_margin(fp, left_margin);
437
438 for (i = 0; i < depth; i++)
439 if (depth_mask & (1 << i))
440 ret += fprintf(fp, "| ");
441 else
442 ret += fprintf(fp, " ");
443
444 ret += fprintf(fp, "\n");
445
446 return ret;
447}
448
449static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300450 int depth, int depth_mask, int period,
Frederic Weisbeckerd425de52011-01-03 16:13:11 +0100451 u64 total_samples, u64 hits,
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200452 int left_margin)
453{
454 int i;
455 size_t ret = 0;
456
457 ret += callchain__fprintf_left_margin(fp, left_margin);
458 for (i = 0; i < depth; i++) {
459 if (depth_mask & (1 << i))
460 ret += fprintf(fp, "|");
461 else
462 ret += fprintf(fp, " ");
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300463 if (!period && i == depth - 1) {
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200464 double percent;
465
466 percent = hits * 100.0 / total_samples;
467 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
468 } else
469 ret += fprintf(fp, "%s", " ");
470 }
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300471 if (chain->ms.sym)
472 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200473 else
474 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
475
476 return ret;
477}
478
479static struct symbol *rem_sq_bracket;
480static struct callchain_list rem_hits;
481
482static void init_rem_hits(void)
483{
484 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
485 if (!rem_sq_bracket) {
486 fprintf(stderr, "Not enough memory to display remaining hits\n");
487 return;
488 }
489
490 strcpy(rem_sq_bracket->name, "[...]");
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300491 rem_hits.ms.sym = rem_sq_bracket;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200492}
493
494static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
495 u64 total_samples, int depth,
496 int depth_mask, int left_margin)
497{
498 struct rb_node *node, *next;
499 struct callchain_node *child;
500 struct callchain_list *chain;
501 int new_depth_mask = depth_mask;
502 u64 new_total;
503 u64 remaining;
504 size_t ret = 0;
505 int i;
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300506 uint entries_printed = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200507
508 if (callchain_param.mode == CHAIN_GRAPH_REL)
509 new_total = self->children_hit;
510 else
511 new_total = total_samples;
512
513 remaining = new_total;
514
515 node = rb_first(&self->rb_root);
516 while (node) {
517 u64 cumul;
518
519 child = rb_entry(node, struct callchain_node, rb_node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100520 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200521 remaining -= cumul;
522
523 /*
524 * The depth mask manages the output of pipes that show
525 * the depth. We don't want to keep the pipes of the current
526 * level for the last child of this depth.
527 * Except if we have remaining filtered hits. They will
528 * supersede the last child
529 */
530 next = rb_next(node);
531 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
532 new_depth_mask &= ~(1 << (depth - 1));
533
534 /*
Daniel Mack3ad2f3f2010-02-03 08:01:28 +0800535 * But we keep the older depth mask for the line separator
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200536 * to keep the level link until we reach the last child
537 */
538 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
539 left_margin);
540 i = 0;
541 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200542 ret += ipchain__fprintf_graph(fp, chain, depth,
543 new_depth_mask, i++,
544 new_total,
545 cumul,
546 left_margin);
547 }
548 ret += __callchain__fprintf_graph(fp, child, new_total,
549 depth + 1,
550 new_depth_mask | (1 << depth),
551 left_margin);
552 node = next;
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300553 if (++entries_printed == callchain_param.print_limit)
554 break;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200555 }
556
557 if (callchain_param.mode == CHAIN_GRAPH_REL &&
558 remaining && remaining != new_total) {
559
560 if (!rem_sq_bracket)
561 return ret;
562
563 new_depth_mask &= ~(1 << (depth - 1));
564
565 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
566 new_depth_mask, 0, new_total,
567 remaining, left_margin);
568 }
569
570 return ret;
571}
572
573static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
574 u64 total_samples, int left_margin)
575{
576 struct callchain_list *chain;
577 bool printed = false;
578 int i = 0;
579 int ret = 0;
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300580 u32 entries_printed = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200581
582 list_for_each_entry(chain, &self->val, list) {
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200583 if (!i++ && sort__first_dimension == SORT_SYM)
584 continue;
585
586 if (!printed) {
587 ret += callchain__fprintf_left_margin(fp, left_margin);
588 ret += fprintf(fp, "|\n");
589 ret += callchain__fprintf_left_margin(fp, left_margin);
590 ret += fprintf(fp, "---");
591
592 left_margin += 3;
593 printed = true;
594 } else
595 ret += callchain__fprintf_left_margin(fp, left_margin);
596
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300597 if (chain->ms.sym)
598 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200599 else
600 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300601
602 if (++entries_printed == callchain_param.print_limit)
603 break;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200604 }
605
606 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
607
608 return ret;
609}
610
611static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
612 u64 total_samples)
613{
614 struct callchain_list *chain;
615 size_t ret = 0;
616
617 if (!self)
618 return 0;
619
620 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
621
622
623 list_for_each_entry(chain, &self->val, list) {
624 if (chain->ip >= PERF_CONTEXT_MAX)
625 continue;
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300626 if (chain->ms.sym)
627 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200628 else
629 ret += fprintf(fp, " %p\n",
630 (void *)(long)chain->ip);
631 }
632
633 return ret;
634}
635
636static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
637 u64 total_samples, int left_margin)
638{
639 struct rb_node *rb_node;
640 struct callchain_node *chain;
641 size_t ret = 0;
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300642 u32 entries_printed = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200643
644 rb_node = rb_first(&self->sorted_chain);
645 while (rb_node) {
646 double percent;
647
648 chain = rb_entry(rb_node, struct callchain_node, rb_node);
649 percent = chain->hit * 100.0 / total_samples;
650 switch (callchain_param.mode) {
651 case CHAIN_FLAT:
652 ret += percent_color_fprintf(fp, " %6.2f%%\n",
653 percent);
654 ret += callchain__fprintf_flat(fp, chain, total_samples);
655 break;
656 case CHAIN_GRAPH_ABS: /* Falldown */
657 case CHAIN_GRAPH_REL:
658 ret += callchain__fprintf_graph(fp, chain, total_samples,
659 left_margin);
660 case CHAIN_NONE:
661 default:
662 break;
663 }
664 ret += fprintf(fp, "\n");
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300665 if (++entries_printed == callchain_param.print_limit)
666 break;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200667 rb_node = rb_next(rb_node);
668 }
669
670 return ret;
671}
672
Arnaldo Carvalho de Meloab81f3f2011-10-05 19:16:15 -0300673void hists__output_recalc_col_len(struct hists *hists, int max_rows)
674{
675 struct rb_node *next = rb_first(&hists->entries);
676 struct hist_entry *n;
677 int row = 0;
678
679 hists__reset_col_len(hists);
680
681 while (next && row++ < max_rows) {
682 n = rb_entry(next, struct hist_entry, rb_node);
683 hists__calc_col_len(hists, n);
684 next = rb_next(&n->rb_node);
685 }
686}
687
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300688int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300689 struct hists *hists, struct hists *pair_hists,
690 bool show_displacement, long displacement,
691 bool color, u64 session_total)
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200692{
693 struct sort_entry *se;
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300694 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200695 u64 nr_events;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200696 const char *sep = symbol_conf.field_sep;
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300697 int ret;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200698
699 if (symbol_conf.exclude_other && !self->parent)
700 return 0;
701
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300702 if (pair_hists) {
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300703 period = self->pair ? self->pair->period : 0;
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200704 nr_events = self->pair ? self->pair->nr_events : 0;
Arnaldo Carvalho de Melocee75ac2010-05-14 13:16:55 -0300705 total = pair_hists->stats.total_period;
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300706 period_sys = self->pair ? self->pair->period_sys : 0;
707 period_us = self->pair ? self->pair->period_us : 0;
708 period_guest_sys = self->pair ? self->pair->period_guest_sys : 0;
709 period_guest_us = self->pair ? self->pair->period_guest_us : 0;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200710 } else {
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300711 period = self->period;
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200712 nr_events = self->nr_events;
Eric B Munsoneefc4652010-03-05 12:51:08 -0300713 total = session_total;
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300714 period_sys = self->period_sys;
715 period_us = self->period_us;
716 period_guest_sys = self->period_guest_sys;
717 period_guest_us = self->period_guest_us;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200718 }
719
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300720 if (total) {
721 if (color)
722 ret = percent_color_snprintf(s, size,
723 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300724 (period * 100.0) / total);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300725 else
726 ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300727 (period * 100.0) / total);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800728 if (symbol_conf.show_cpu_utilization) {
729 ret += percent_color_snprintf(s + ret, size - ret,
730 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300731 (period_sys * 100.0) / total);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800732 ret += percent_color_snprintf(s + ret, size - ret,
733 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300734 (period_us * 100.0) / total);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800735 if (perf_guest) {
736 ret += percent_color_snprintf(s + ret,
737 size - ret,
738 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300739 (period_guest_sys * 100.0) /
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800740 total);
741 ret += percent_color_snprintf(s + ret,
742 size - ret,
743 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300744 (period_guest_us * 100.0) /
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800745 total);
746 }
747 }
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300748 } else
Arnaldo Carvalho de Melo9486aa32011-01-22 20:37:02 -0200749 ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200750
751 if (symbol_conf.show_nr_samples) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200752 if (sep)
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200753 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200754 else
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200755 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200756 }
757
Arnaldo Carvalho de Melo3f2728b2011-10-05 16:10:06 -0300758 if (symbol_conf.show_total_period) {
759 if (sep)
760 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
761 else
762 ret += snprintf(s + ret, size - ret, " %12" PRIu64, period);
763 }
764
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300765 if (pair_hists) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200766 char bf[32];
767 double old_percent = 0, new_percent = 0, diff;
768
769 if (total > 0)
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300770 old_percent = (period * 100.0) / total;
Eric B Munsoneefc4652010-03-05 12:51:08 -0300771 if (session_total > 0)
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300772 new_percent = (self->period * 100.0) / session_total;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200773
Arnaldo Carvalho de Melo9b338272009-12-16 14:31:49 -0200774 diff = new_percent - old_percent;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200775
Arnaldo Carvalho de Melo9b338272009-12-16 14:31:49 -0200776 if (fabs(diff) >= 0.01)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200777 snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
778 else
779 snprintf(bf, sizeof(bf), " ");
780
781 if (sep)
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300782 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200783 else
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300784 ret += snprintf(s + ret, size - ret, "%11.11s", bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200785
786 if (show_displacement) {
787 if (displacement)
788 snprintf(bf, sizeof(bf), "%+4ld", displacement);
789 else
790 snprintf(bf, sizeof(bf), " ");
791
792 if (sep)
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300793 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200794 else
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300795 ret += snprintf(s + ret, size - ret, "%6.6s", bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200796 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200797 }
798
799 list_for_each_entry(se, &hist_entry__sort_list, list) {
800 if (se->elide)
801 continue;
802
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300803 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200804 ret += se->se_snprintf(self, s + ret, size - ret,
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300805 hists__col_len(hists, se->se_width_idx));
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200806 }
807
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300808 return ret;
809}
810
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300811int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300812 struct hists *pair_hists, bool show_displacement,
813 long displacement, FILE *fp, u64 session_total)
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300814{
815 char bf[512];
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300816
817 if (size == 0 || size > sizeof(bf))
818 size = sizeof(bf);
819
820 hist_entry__snprintf(he, bf, size, hists, pair_hists,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300821 show_displacement, displacement,
822 true, session_total);
823 return fprintf(fp, "%s\n", bf);
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300824}
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200825
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300826static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
827 struct hists *hists, FILE *fp,
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300828 u64 session_total)
829{
830 int left_margin = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200831
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300832 if (sort__first_dimension == SORT_COMM) {
833 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
834 typeof(*se), list);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300835 left_margin = hists__col_len(hists, se->se_width_idx);
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300836 left_margin -= thread__comm_len(self->thread);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200837 }
838
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300839 return hist_entry_callchain__fprintf(fp, self, session_total,
840 left_margin);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200841}
842
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300843size_t hists__fprintf(struct hists *hists, struct hists *pair,
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300844 bool show_displacement, bool show_header, int max_rows,
845 int max_cols, FILE *fp)
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200846{
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200847 struct sort_entry *se;
848 struct rb_node *nd;
849 size_t ret = 0;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200850 unsigned long position = 1;
851 long displacement = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200852 unsigned int width;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200853 const char *sep = symbol_conf.field_sep;
Arnaldo Carvalho de Meloedb7c602010-05-17 16:22:41 -0300854 const char *col_width = symbol_conf.col_width_list_str;
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300855 int nr_rows = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200856
857 init_rem_hits();
858
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300859 if (!show_header)
860 goto print_entries;
861
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200862 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
863
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200864 if (symbol_conf.show_nr_samples) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200865 if (sep)
866 fprintf(fp, "%cSamples", *sep);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200867 else
868 fputs(" Samples ", fp);
869 }
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200870
Arnaldo Carvalho de Melo3f2728b2011-10-05 16:10:06 -0300871 if (symbol_conf.show_total_period) {
872 if (sep)
873 ret += fprintf(fp, "%cPeriod", *sep);
874 else
875 ret += fprintf(fp, " Period ");
876 }
877
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800878 if (symbol_conf.show_cpu_utilization) {
879 if (sep) {
880 ret += fprintf(fp, "%csys", *sep);
881 ret += fprintf(fp, "%cus", *sep);
882 if (perf_guest) {
883 ret += fprintf(fp, "%cguest sys", *sep);
884 ret += fprintf(fp, "%cguest us", *sep);
885 }
886 } else {
887 ret += fprintf(fp, " sys ");
888 ret += fprintf(fp, " us ");
889 if (perf_guest) {
890 ret += fprintf(fp, " guest sys ");
891 ret += fprintf(fp, " guest us ");
892 }
893 }
894 }
895
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200896 if (pair) {
897 if (sep)
898 ret += fprintf(fp, "%cDelta", *sep);
899 else
900 ret += fprintf(fp, " Delta ");
901
902 if (show_displacement) {
903 if (sep)
904 ret += fprintf(fp, "%cDisplacement", *sep);
905 else
906 ret += fprintf(fp, " Displ");
907 }
908 }
909
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200910 list_for_each_entry(se, &hist_entry__sort_list, list) {
911 if (se->elide)
912 continue;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200913 if (sep) {
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200914 fprintf(fp, "%c%s", *sep, se->se_header);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200915 continue;
916 }
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200917 width = strlen(se->se_header);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300918 if (symbol_conf.col_width_list_str) {
919 if (col_width) {
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300920 hists__set_col_len(hists, se->se_width_idx,
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300921 atoi(col_width));
922 col_width = strchr(col_width, ',');
923 if (col_width)
924 ++col_width;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200925 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200926 }
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300927 if (!hists__new_col_len(hists, se->se_width_idx, width))
928 width = hists__col_len(hists, se->se_width_idx);
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200929 fprintf(fp, " %*s", width, se->se_header);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200930 }
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300931
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200932 fprintf(fp, "\n");
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300933 if (max_rows && ++nr_rows >= max_rows)
934 goto out;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200935
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200936 if (sep)
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200937 goto print_entries;
938
939 fprintf(fp, "# ........");
940 if (symbol_conf.show_nr_samples)
941 fprintf(fp, " ..........");
Arnaldo Carvalho de Melo3f2728b2011-10-05 16:10:06 -0300942 if (symbol_conf.show_total_period)
943 fprintf(fp, " ............");
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200944 if (pair) {
945 fprintf(fp, " ..........");
946 if (show_displacement)
947 fprintf(fp, " .....");
948 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200949 list_for_each_entry(se, &hist_entry__sort_list, list) {
950 unsigned int i;
951
952 if (se->elide)
953 continue;
954
955 fprintf(fp, " ");
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300956 width = hists__col_len(hists, se->se_width_idx);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300957 if (width == 0)
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200958 width = strlen(se->se_header);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200959 for (i = 0; i < width; i++)
960 fprintf(fp, ".");
961 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200962
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300963 fprintf(fp, "\n");
964 if (max_rows && ++nr_rows >= max_rows)
965 goto out;
966
967 fprintf(fp, "#\n");
968 if (max_rows && ++nr_rows >= max_rows)
969 goto out;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200970
971print_entries:
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300972 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200973 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
974
Frederic Weisbeckere84d2122011-06-29 22:23:03 +0200975 if (h->filtered)
976 continue;
977
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200978 if (show_displacement) {
979 if (h->pair != NULL)
980 displacement = ((long)h->pair->position -
981 (long)position);
982 else
983 displacement = 0;
984 ++position;
985 }
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300986 ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement,
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300987 displacement, fp, hists->stats.total_period);
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300988
989 if (symbol_conf.use_callchain)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300990 ret += hist_entry__fprintf_callchain(h, hists, fp,
991 hists->stats.total_period);
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300992 if (max_rows && ++nr_rows >= max_rows)
993 goto out;
994
Arnaldo Carvalho de Melo59fd5302010-03-24 16:40:17 -0300995 if (h->ms.map == NULL && verbose > 1) {
Arnaldo Carvalho de Melo65f2ed22010-03-09 15:58:17 -0300996 __map_groups__fprintf_maps(&h->thread->mg,
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300997 MAP__FUNCTION, verbose, fp);
Arnaldo Carvalho de Melo65f2ed22010-03-09 15:58:17 -0300998 fprintf(fp, "%.10s end\n", graph_dotted_line);
999 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -02001000 }
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -03001001out:
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -02001002 free(rem_sq_bracket);
1003
1004 return ret;
1005}
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001006
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -03001007/*
1008 * See hists__fprintf to match the column widths
1009 */
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001010unsigned int hists__sort_list_width(struct hists *hists)
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -03001011{
1012 struct sort_entry *se;
1013 int ret = 9; /* total % */
1014
1015 if (symbol_conf.show_cpu_utilization) {
1016 ret += 7; /* count_sys % */
1017 ret += 6; /* count_us % */
1018 if (perf_guest) {
1019 ret += 13; /* count_guest_sys % */
1020 ret += 12; /* count_guest_us % */
1021 }
1022 }
1023
1024 if (symbol_conf.show_nr_samples)
1025 ret += 11;
1026
Arnaldo Carvalho de Melo3f2728b2011-10-05 16:10:06 -03001027 if (symbol_conf.show_total_period)
1028 ret += 13;
1029
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -03001030 list_for_each_entry(se, &hist_entry__sort_list, list)
1031 if (!se->elide)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001032 ret += 2 + hists__col_len(hists, se->se_width_idx);
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -03001033
Arnaldo Carvalho de Melo903cce62010-08-05 19:15:48 -03001034 if (verbose) /* Addr + origin */
1035 ret += 3 + BITS_PER_LONG / 4;
1036
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -03001037 return ret;
1038}
1039
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001040static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
Arnaldo Carvalho de Melocc5edb02010-07-16 12:35:07 -03001041 enum hist_filter filter)
1042{
1043 h->filtered &= ~(1 << filter);
1044 if (h->filtered)
1045 return;
1046
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001047 ++hists->nr_entries;
Arnaldo Carvalho de Melo0f0cbf72010-07-26 17:13:40 -03001048 if (h->ms.unfolded)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001049 hists->nr_entries += h->nr_rows;
Arnaldo Carvalho de Melo0f0cbf72010-07-26 17:13:40 -03001050 h->row_offset = 0;
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001051 hists->stats.total_period += h->period;
1052 hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
Arnaldo Carvalho de Melocc5edb02010-07-16 12:35:07 -03001053
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001054 hists__calc_col_len(hists, h);
Arnaldo Carvalho de Melocc5edb02010-07-16 12:35:07 -03001055}
1056
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001057void hists__filter_by_dso(struct hists *hists, const struct dso *dso)
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001058{
1059 struct rb_node *nd;
1060
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001061 hists->nr_entries = hists->stats.total_period = 0;
1062 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
1063 hists__reset_col_len(hists);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001064
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001065 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001066 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1067
1068 if (symbol_conf.exclude_other && !h->parent)
1069 continue;
1070
1071 if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) {
1072 h->filtered |= (1 << HIST_FILTER__DSO);
1073 continue;
1074 }
1075
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001076 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001077 }
1078}
1079
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001080void hists__filter_by_thread(struct hists *hists, const struct thread *thread)
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001081{
1082 struct rb_node *nd;
1083
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001084 hists->nr_entries = hists->stats.total_period = 0;
1085 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
1086 hists__reset_col_len(hists);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001087
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001088 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001089 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1090
1091 if (thread != NULL && h->thread != thread) {
1092 h->filtered |= (1 << HIST_FILTER__THREAD);
1093 continue;
1094 }
Arnaldo Carvalho de Melocc5edb02010-07-16 12:35:07 -03001095
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001096 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001097 }
1098}
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001099
Arnaldo Carvalho de Melo2f525d02011-02-04 13:43:24 -02001100int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001101{
Arnaldo Carvalho de Melo2f525d02011-02-04 13:43:24 -02001102 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001103}
1104
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -02001105int hist_entry__annotate(struct hist_entry *he, size_t privsize)
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001106{
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -02001107 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001108}
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001109
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001110void hists__inc_nr_events(struct hists *hists, u32 type)
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001111{
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001112 ++hists->stats.nr_events[0];
1113 ++hists->stats.nr_events[type];
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001114}
1115
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001116size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001117{
1118 int i;
1119 size_t ret = 0;
1120
1121 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
Arnaldo Carvalho de Meloe248de32011-03-05 21:40:06 -03001122 const char *name;
Thomas Gleixner3835bc02010-12-07 12:48:42 +00001123
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001124 if (hists->stats.nr_events[i] == 0)
Arnaldo Carvalho de Meloe248de32011-03-05 21:40:06 -03001125 continue;
1126
1127 name = perf_event__name(i);
Thomas Gleixner3835bc02010-12-07 12:48:42 +00001128 if (!strcmp(name, "UNKNOWN"))
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001129 continue;
Thomas Gleixner3835bc02010-12-07 12:48:42 +00001130
1131 ret += fprintf(fp, "%16s events: %10d\n", name,
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001132 hists->stats.nr_events[i]);
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001133 }
1134
1135 return ret;
1136}
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -03001137
1138void hists__init(struct hists *hists)
1139{
1140 memset(hists, 0, sizeof(*hists));
1141 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
1142 hists->entries_in = &hists->entries_in_array[0];
1143 hists->entries_collapsed = RB_ROOT;
1144 hists->entries = RB_ROOT;
1145 pthread_mutex_init(&hists->lock, NULL);
1146}