blob: 80fe30d90d72ff7befefa4c0e4ca308a73f698a7 [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
John Kacur3d1d07e2009-09-28 15:32:55 +020095/*
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -030096 * histogram, sorted on item, collects periods
John Kacur3d1d07e2009-09-28 15:32:55 +020097 */
98
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -030099static struct hist_entry *hist_entry__new(struct hist_entry *template)
100{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200101 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300102 struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
103
104 if (self != NULL) {
105 *self = *template;
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300106 self->nr_events = 1;
Arnaldo Carvalho de Melo0a1eae32010-08-02 19:45:23 -0300107 if (self->ms.map)
108 self->ms.map->referenced = true;
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300109 if (symbol_conf.use_callchain)
110 callchain_init(self->callchain);
111 }
112
113 return self;
114}
115
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300116static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300117{
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300118 if (!h->filtered) {
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300119 hists__calc_col_len(hists, h);
120 ++hists->nr_entries;
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300121 hists->stats.total_period += h->period;
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300122 }
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300123}
124
Arnaldo Carvalho de Melo7a007ca2010-07-21 09:19:41 -0300125static u8 symbol__parent_filter(const struct symbol *parent)
126{
127 if (symbol_conf.exclude_other && parent == NULL)
128 return 1 << HIST_FILTER__PARENT;
129 return 0;
130}
131
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300132struct hist_entry *__hists__add_entry(struct hists *hists,
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300133 struct addr_location *al,
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300134 struct symbol *sym_parent, u64 period)
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300135{
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300136 struct rb_node **p;
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300137 struct rb_node *parent = NULL;
138 struct hist_entry *he;
139 struct hist_entry entry = {
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -0200140 .thread = al->thread,
Arnaldo Carvalho de Melo59fd5302010-03-24 16:40:17 -0300141 .ms = {
142 .map = al->map,
143 .sym = al->sym,
144 },
Arun Sharmaf60f3592010-06-04 11:27:10 -0300145 .cpu = al->cpu,
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -0200146 .ip = al->addr,
147 .level = al->level,
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300148 .period = period,
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300149 .parent = sym_parent,
Arnaldo Carvalho de Melo7a007ca2010-07-21 09:19:41 -0300150 .filtered = symbol__parent_filter(sym_parent),
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300151 };
152 int cmp;
153
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300154 pthread_mutex_lock(&hists->lock);
155
156 p = &hists->entries_in->rb_node;
157
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300158 while (*p != NULL) {
159 parent = *p;
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300160 he = rb_entry(parent, struct hist_entry, rb_node_in);
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300161
162 cmp = hist_entry__cmp(&entry, he);
163
164 if (!cmp) {
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300165 he->period += period;
166 ++he->nr_events;
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300167 goto out;
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300168 }
169
170 if (cmp < 0)
171 p = &(*p)->rb_left;
172 else
173 p = &(*p)->rb_right;
174 }
175
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300176 he = hist_entry__new(&entry);
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300177 if (!he)
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300178 goto out_unlock;
179
180 rb_link_node(&he->rb_node_in, parent, p);
181 rb_insert_color(&he->rb_node_in, hists->entries_in);
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300182out:
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300183 hist_entry__add_cpumode_period(he, al->cpumode, period);
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300184out_unlock:
185 pthread_mutex_unlock(&hists->lock);
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300186 return he;
187}
188
John Kacur3d1d07e2009-09-28 15:32:55 +0200189int64_t
190hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
191{
192 struct sort_entry *se;
193 int64_t cmp = 0;
194
195 list_for_each_entry(se, &hist_entry__sort_list, list) {
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200196 cmp = se->se_cmp(left, right);
John Kacur3d1d07e2009-09-28 15:32:55 +0200197 if (cmp)
198 break;
199 }
200
201 return cmp;
202}
203
204int64_t
205hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
206{
207 struct sort_entry *se;
208 int64_t cmp = 0;
209
210 list_for_each_entry(se, &hist_entry__sort_list, list) {
211 int64_t (*f)(struct hist_entry *, struct hist_entry *);
212
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200213 f = se->se_collapse ?: se->se_cmp;
John Kacur3d1d07e2009-09-28 15:32:55 +0200214
215 cmp = f(left, right);
216 if (cmp)
217 break;
218 }
219
220 return cmp;
221}
222
223void hist_entry__free(struct hist_entry *he)
224{
225 free(he);
226}
227
228/*
229 * collapse the histogram
230 */
231
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300232static bool hists__collapse_insert_entry(struct hists *hists,
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100233 struct rb_root *root,
234 struct hist_entry *he)
John Kacur3d1d07e2009-09-28 15:32:55 +0200235{
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200236 struct rb_node **p = &root->rb_node;
John Kacur3d1d07e2009-09-28 15:32:55 +0200237 struct rb_node *parent = NULL;
238 struct hist_entry *iter;
239 int64_t cmp;
240
241 while (*p != NULL) {
242 parent = *p;
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300243 iter = rb_entry(parent, struct hist_entry, rb_node_in);
John Kacur3d1d07e2009-09-28 15:32:55 +0200244
245 cmp = hist_entry__collapse(iter, he);
246
247 if (!cmp) {
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300248 iter->period += he->period;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100249 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300250 callchain_cursor_reset(&hists->callchain_cursor);
251 callchain_merge(&hists->callchain_cursor, iter->callchain,
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100252 he->callchain);
253 }
John Kacur3d1d07e2009-09-28 15:32:55 +0200254 hist_entry__free(he);
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300255 return false;
John Kacur3d1d07e2009-09-28 15:32:55 +0200256 }
257
258 if (cmp < 0)
259 p = &(*p)->rb_left;
260 else
261 p = &(*p)->rb_right;
262 }
263
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300264 rb_link_node(&he->rb_node_in, parent, p);
265 rb_insert_color(&he->rb_node_in, root);
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300266 return true;
John Kacur3d1d07e2009-09-28 15:32:55 +0200267}
268
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300269static struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
270{
271 struct rb_root *root;
272
273 pthread_mutex_lock(&hists->lock);
274
275 root = hists->entries_in;
276 if (++hists->entries_in > &hists->entries_in_array[1])
277 hists->entries_in = &hists->entries_in_array[0];
278
279 pthread_mutex_unlock(&hists->lock);
280
281 return root;
282}
283
284static void __hists__collapse_resort(struct hists *hists, bool threaded)
285{
286 struct rb_root *root;
287 struct rb_node *next;
288 struct hist_entry *n;
289
290 if (!sort__need_collapse && !threaded)
291 return;
292
293 root = hists__get_rotate_entries_in(hists);
294 next = rb_first(root);
295 hists->stats.total_period = 0;
296
297 while (next) {
298 n = rb_entry(next, struct hist_entry, rb_node_in);
299 next = rb_next(&n->rb_node_in);
300
301 rb_erase(&n->rb_node_in, root);
302 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n))
303 hists__inc_nr_entries(hists, n);
304 }
305}
306
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300307void hists__collapse_resort(struct hists *hists)
John Kacur3d1d07e2009-09-28 15:32:55 +0200308{
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300309 return __hists__collapse_resort(hists, false);
310}
John Kacur3d1d07e2009-09-28 15:32:55 +0200311
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300312void hists__collapse_resort_threaded(struct hists *hists)
313{
314 return __hists__collapse_resort(hists, true);
John Kacur3d1d07e2009-09-28 15:32:55 +0200315}
316
317/*
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300318 * reverse the map, sort on period.
John Kacur3d1d07e2009-09-28 15:32:55 +0200319 */
320
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300321static void __hists__insert_output_entry(struct rb_root *entries,
322 struct hist_entry *he,
323 u64 min_callchain_hits)
John Kacur3d1d07e2009-09-28 15:32:55 +0200324{
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300325 struct rb_node **p = &entries->rb_node;
John Kacur3d1d07e2009-09-28 15:32:55 +0200326 struct rb_node *parent = NULL;
327 struct hist_entry *iter;
328
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -0200329 if (symbol_conf.use_callchain)
Arnaldo Carvalho de Melob9fb9302010-04-02 09:50:42 -0300330 callchain_param.sort(&he->sorted_chain, he->callchain,
John Kacur3d1d07e2009-09-28 15:32:55 +0200331 min_callchain_hits, &callchain_param);
332
333 while (*p != NULL) {
334 parent = *p;
335 iter = rb_entry(parent, struct hist_entry, rb_node);
336
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300337 if (he->period > iter->period)
John Kacur3d1d07e2009-09-28 15:32:55 +0200338 p = &(*p)->rb_left;
339 else
340 p = &(*p)->rb_right;
341 }
342
343 rb_link_node(&he->rb_node, parent, p);
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300344 rb_insert_color(&he->rb_node, entries);
John Kacur3d1d07e2009-09-28 15:32:55 +0200345}
346
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300347static void __hists__output_resort(struct hists *hists, bool threaded)
John Kacur3d1d07e2009-09-28 15:32:55 +0200348{
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300349 struct rb_root *root;
John Kacur3d1d07e2009-09-28 15:32:55 +0200350 struct rb_node *next;
351 struct hist_entry *n;
John Kacur3d1d07e2009-09-28 15:32:55 +0200352 u64 min_callchain_hits;
353
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300354 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
John Kacur3d1d07e2009-09-28 15:32:55 +0200355
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300356 if (sort__need_collapse || threaded)
357 root = &hists->entries_collapsed;
358 else
359 root = hists->entries_in;
360
361 next = rb_first(root);
362 hists->entries = RB_ROOT;
John Kacur3d1d07e2009-09-28 15:32:55 +0200363
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300364 hists->nr_entries = 0;
365 hists__reset_col_len(hists);
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300366
John Kacur3d1d07e2009-09-28 15:32:55 +0200367 while (next) {
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300368 n = rb_entry(next, struct hist_entry, rb_node_in);
369 next = rb_next(&n->rb_node_in);
John Kacur3d1d07e2009-09-28 15:32:55 +0200370
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300371 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300372 hists__inc_nr_entries(hists, n);
John Kacur3d1d07e2009-09-28 15:32:55 +0200373 }
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300374}
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200375
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300376void hists__output_resort(struct hists *hists)
377{
378 return __hists__output_resort(hists, false);
379}
380
381void hists__output_resort_threaded(struct hists *hists)
382{
383 return __hists__output_resort(hists, true);
John Kacur3d1d07e2009-09-28 15:32:55 +0200384}
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200385
386static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
387{
388 int i;
389 int ret = fprintf(fp, " ");
390
391 for (i = 0; i < left_margin; i++)
392 ret += fprintf(fp, " ");
393
394 return ret;
395}
396
397static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
398 int left_margin)
399{
400 int i;
401 size_t ret = callchain__fprintf_left_margin(fp, left_margin);
402
403 for (i = 0; i < depth; i++)
404 if (depth_mask & (1 << i))
405 ret += fprintf(fp, "| ");
406 else
407 ret += fprintf(fp, " ");
408
409 ret += fprintf(fp, "\n");
410
411 return ret;
412}
413
414static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300415 int depth, int depth_mask, int period,
Frederic Weisbeckerd425de52011-01-03 16:13:11 +0100416 u64 total_samples, u64 hits,
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200417 int left_margin)
418{
419 int i;
420 size_t ret = 0;
421
422 ret += callchain__fprintf_left_margin(fp, left_margin);
423 for (i = 0; i < depth; i++) {
424 if (depth_mask & (1 << i))
425 ret += fprintf(fp, "|");
426 else
427 ret += fprintf(fp, " ");
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300428 if (!period && i == depth - 1) {
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200429 double percent;
430
431 percent = hits * 100.0 / total_samples;
432 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
433 } else
434 ret += fprintf(fp, "%s", " ");
435 }
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300436 if (chain->ms.sym)
437 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200438 else
439 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
440
441 return ret;
442}
443
444static struct symbol *rem_sq_bracket;
445static struct callchain_list rem_hits;
446
447static void init_rem_hits(void)
448{
449 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
450 if (!rem_sq_bracket) {
451 fprintf(stderr, "Not enough memory to display remaining hits\n");
452 return;
453 }
454
455 strcpy(rem_sq_bracket->name, "[...]");
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300456 rem_hits.ms.sym = rem_sq_bracket;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200457}
458
459static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
460 u64 total_samples, int depth,
461 int depth_mask, int left_margin)
462{
463 struct rb_node *node, *next;
464 struct callchain_node *child;
465 struct callchain_list *chain;
466 int new_depth_mask = depth_mask;
467 u64 new_total;
468 u64 remaining;
469 size_t ret = 0;
470 int i;
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300471 uint entries_printed = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200472
473 if (callchain_param.mode == CHAIN_GRAPH_REL)
474 new_total = self->children_hit;
475 else
476 new_total = total_samples;
477
478 remaining = new_total;
479
480 node = rb_first(&self->rb_root);
481 while (node) {
482 u64 cumul;
483
484 child = rb_entry(node, struct callchain_node, rb_node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100485 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200486 remaining -= cumul;
487
488 /*
489 * The depth mask manages the output of pipes that show
490 * the depth. We don't want to keep the pipes of the current
491 * level for the last child of this depth.
492 * Except if we have remaining filtered hits. They will
493 * supersede the last child
494 */
495 next = rb_next(node);
496 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
497 new_depth_mask &= ~(1 << (depth - 1));
498
499 /*
Daniel Mack3ad2f3f2010-02-03 08:01:28 +0800500 * But we keep the older depth mask for the line separator
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200501 * to keep the level link until we reach the last child
502 */
503 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
504 left_margin);
505 i = 0;
506 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200507 ret += ipchain__fprintf_graph(fp, chain, depth,
508 new_depth_mask, i++,
509 new_total,
510 cumul,
511 left_margin);
512 }
513 ret += __callchain__fprintf_graph(fp, child, new_total,
514 depth + 1,
515 new_depth_mask | (1 << depth),
516 left_margin);
517 node = next;
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300518 if (++entries_printed == callchain_param.print_limit)
519 break;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200520 }
521
522 if (callchain_param.mode == CHAIN_GRAPH_REL &&
523 remaining && remaining != new_total) {
524
525 if (!rem_sq_bracket)
526 return ret;
527
528 new_depth_mask &= ~(1 << (depth - 1));
529
530 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
531 new_depth_mask, 0, new_total,
532 remaining, left_margin);
533 }
534
535 return ret;
536}
537
538static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
539 u64 total_samples, int left_margin)
540{
541 struct callchain_list *chain;
542 bool printed = false;
543 int i = 0;
544 int ret = 0;
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300545 u32 entries_printed = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200546
547 list_for_each_entry(chain, &self->val, list) {
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200548 if (!i++ && sort__first_dimension == SORT_SYM)
549 continue;
550
551 if (!printed) {
552 ret += callchain__fprintf_left_margin(fp, left_margin);
553 ret += fprintf(fp, "|\n");
554 ret += callchain__fprintf_left_margin(fp, left_margin);
555 ret += fprintf(fp, "---");
556
557 left_margin += 3;
558 printed = true;
559 } else
560 ret += callchain__fprintf_left_margin(fp, left_margin);
561
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300562 if (chain->ms.sym)
563 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200564 else
565 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300566
567 if (++entries_printed == callchain_param.print_limit)
568 break;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200569 }
570
571 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
572
573 return ret;
574}
575
576static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
577 u64 total_samples)
578{
579 struct callchain_list *chain;
580 size_t ret = 0;
581
582 if (!self)
583 return 0;
584
585 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
586
587
588 list_for_each_entry(chain, &self->val, list) {
589 if (chain->ip >= PERF_CONTEXT_MAX)
590 continue;
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300591 if (chain->ms.sym)
592 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200593 else
594 ret += fprintf(fp, " %p\n",
595 (void *)(long)chain->ip);
596 }
597
598 return ret;
599}
600
601static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
602 u64 total_samples, int left_margin)
603{
604 struct rb_node *rb_node;
605 struct callchain_node *chain;
606 size_t ret = 0;
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300607 u32 entries_printed = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200608
609 rb_node = rb_first(&self->sorted_chain);
610 while (rb_node) {
611 double percent;
612
613 chain = rb_entry(rb_node, struct callchain_node, rb_node);
614 percent = chain->hit * 100.0 / total_samples;
615 switch (callchain_param.mode) {
616 case CHAIN_FLAT:
617 ret += percent_color_fprintf(fp, " %6.2f%%\n",
618 percent);
619 ret += callchain__fprintf_flat(fp, chain, total_samples);
620 break;
621 case CHAIN_GRAPH_ABS: /* Falldown */
622 case CHAIN_GRAPH_REL:
623 ret += callchain__fprintf_graph(fp, chain, total_samples,
624 left_margin);
625 case CHAIN_NONE:
626 default:
627 break;
628 }
629 ret += fprintf(fp, "\n");
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300630 if (++entries_printed == callchain_param.print_limit)
631 break;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200632 rb_node = rb_next(rb_node);
633 }
634
635 return ret;
636}
637
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300638int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300639 struct hists *hists, struct hists *pair_hists,
640 bool show_displacement, long displacement,
641 bool color, u64 session_total)
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200642{
643 struct sort_entry *se;
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300644 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200645 u64 nr_events;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200646 const char *sep = symbol_conf.field_sep;
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300647 int ret;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200648
649 if (symbol_conf.exclude_other && !self->parent)
650 return 0;
651
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300652 if (pair_hists) {
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300653 period = self->pair ? self->pair->period : 0;
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200654 nr_events = self->pair ? self->pair->nr_events : 0;
Arnaldo Carvalho de Melocee75ac2010-05-14 13:16:55 -0300655 total = pair_hists->stats.total_period;
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300656 period_sys = self->pair ? self->pair->period_sys : 0;
657 period_us = self->pair ? self->pair->period_us : 0;
658 period_guest_sys = self->pair ? self->pair->period_guest_sys : 0;
659 period_guest_us = self->pair ? self->pair->period_guest_us : 0;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200660 } else {
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300661 period = self->period;
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200662 nr_events = self->nr_events;
Eric B Munsoneefc4652010-03-05 12:51:08 -0300663 total = session_total;
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300664 period_sys = self->period_sys;
665 period_us = self->period_us;
666 period_guest_sys = self->period_guest_sys;
667 period_guest_us = self->period_guest_us;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200668 }
669
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300670 if (total) {
671 if (color)
672 ret = percent_color_snprintf(s, size,
673 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300674 (period * 100.0) / total);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300675 else
676 ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300677 (period * 100.0) / total);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800678 if (symbol_conf.show_cpu_utilization) {
679 ret += percent_color_snprintf(s + ret, size - ret,
680 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300681 (period_sys * 100.0) / total);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800682 ret += percent_color_snprintf(s + ret, size - ret,
683 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300684 (period_us * 100.0) / total);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800685 if (perf_guest) {
686 ret += percent_color_snprintf(s + ret,
687 size - ret,
688 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300689 (period_guest_sys * 100.0) /
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800690 total);
691 ret += percent_color_snprintf(s + ret,
692 size - ret,
693 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300694 (period_guest_us * 100.0) /
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800695 total);
696 }
697 }
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300698 } else
Arnaldo Carvalho de Melo9486aa32011-01-22 20:37:02 -0200699 ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200700
701 if (symbol_conf.show_nr_samples) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200702 if (sep)
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200703 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200704 else
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200705 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200706 }
707
Arnaldo Carvalho de Melo3f2728b2011-10-05 16:10:06 -0300708 if (symbol_conf.show_total_period) {
709 if (sep)
710 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
711 else
712 ret += snprintf(s + ret, size - ret, " %12" PRIu64, period);
713 }
714
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300715 if (pair_hists) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200716 char bf[32];
717 double old_percent = 0, new_percent = 0, diff;
718
719 if (total > 0)
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300720 old_percent = (period * 100.0) / total;
Eric B Munsoneefc4652010-03-05 12:51:08 -0300721 if (session_total > 0)
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300722 new_percent = (self->period * 100.0) / session_total;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200723
Arnaldo Carvalho de Melo9b338272009-12-16 14:31:49 -0200724 diff = new_percent - old_percent;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200725
Arnaldo Carvalho de Melo9b338272009-12-16 14:31:49 -0200726 if (fabs(diff) >= 0.01)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200727 snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
728 else
729 snprintf(bf, sizeof(bf), " ");
730
731 if (sep)
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300732 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200733 else
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300734 ret += snprintf(s + ret, size - ret, "%11.11s", bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200735
736 if (show_displacement) {
737 if (displacement)
738 snprintf(bf, sizeof(bf), "%+4ld", displacement);
739 else
740 snprintf(bf, sizeof(bf), " ");
741
742 if (sep)
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300743 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200744 else
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300745 ret += snprintf(s + ret, size - ret, "%6.6s", bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200746 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200747 }
748
749 list_for_each_entry(se, &hist_entry__sort_list, list) {
750 if (se->elide)
751 continue;
752
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300753 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200754 ret += se->se_snprintf(self, s + ret, size - ret,
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300755 hists__col_len(hists, se->se_width_idx));
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200756 }
757
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300758 return ret;
759}
760
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300761int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300762 struct hists *pair_hists, bool show_displacement,
763 long displacement, FILE *fp, u64 session_total)
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300764{
765 char bf[512];
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300766
767 if (size == 0 || size > sizeof(bf))
768 size = sizeof(bf);
769
770 hist_entry__snprintf(he, bf, size, hists, pair_hists,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300771 show_displacement, displacement,
772 true, session_total);
773 return fprintf(fp, "%s\n", bf);
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300774}
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200775
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300776static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
777 struct hists *hists, FILE *fp,
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300778 u64 session_total)
779{
780 int left_margin = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200781
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300782 if (sort__first_dimension == SORT_COMM) {
783 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
784 typeof(*se), list);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300785 left_margin = hists__col_len(hists, se->se_width_idx);
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300786 left_margin -= thread__comm_len(self->thread);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200787 }
788
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300789 return hist_entry_callchain__fprintf(fp, self, session_total,
790 left_margin);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200791}
792
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300793size_t hists__fprintf(struct hists *hists, struct hists *pair,
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300794 bool show_displacement, bool show_header, int max_rows,
795 int max_cols, FILE *fp)
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200796{
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200797 struct sort_entry *se;
798 struct rb_node *nd;
799 size_t ret = 0;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200800 unsigned long position = 1;
801 long displacement = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200802 unsigned int width;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200803 const char *sep = symbol_conf.field_sep;
Arnaldo Carvalho de Meloedb7c602010-05-17 16:22:41 -0300804 const char *col_width = symbol_conf.col_width_list_str;
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300805 int nr_rows = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200806
807 init_rem_hits();
808
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300809 if (!show_header)
810 goto print_entries;
811
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200812 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
813
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200814 if (symbol_conf.show_nr_samples) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200815 if (sep)
816 fprintf(fp, "%cSamples", *sep);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200817 else
818 fputs(" Samples ", fp);
819 }
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200820
Arnaldo Carvalho de Melo3f2728b2011-10-05 16:10:06 -0300821 if (symbol_conf.show_total_period) {
822 if (sep)
823 ret += fprintf(fp, "%cPeriod", *sep);
824 else
825 ret += fprintf(fp, " Period ");
826 }
827
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800828 if (symbol_conf.show_cpu_utilization) {
829 if (sep) {
830 ret += fprintf(fp, "%csys", *sep);
831 ret += fprintf(fp, "%cus", *sep);
832 if (perf_guest) {
833 ret += fprintf(fp, "%cguest sys", *sep);
834 ret += fprintf(fp, "%cguest us", *sep);
835 }
836 } else {
837 ret += fprintf(fp, " sys ");
838 ret += fprintf(fp, " us ");
839 if (perf_guest) {
840 ret += fprintf(fp, " guest sys ");
841 ret += fprintf(fp, " guest us ");
842 }
843 }
844 }
845
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200846 if (pair) {
847 if (sep)
848 ret += fprintf(fp, "%cDelta", *sep);
849 else
850 ret += fprintf(fp, " Delta ");
851
852 if (show_displacement) {
853 if (sep)
854 ret += fprintf(fp, "%cDisplacement", *sep);
855 else
856 ret += fprintf(fp, " Displ");
857 }
858 }
859
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200860 list_for_each_entry(se, &hist_entry__sort_list, list) {
861 if (se->elide)
862 continue;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200863 if (sep) {
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200864 fprintf(fp, "%c%s", *sep, se->se_header);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200865 continue;
866 }
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200867 width = strlen(se->se_header);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300868 if (symbol_conf.col_width_list_str) {
869 if (col_width) {
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300870 hists__set_col_len(hists, se->se_width_idx,
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300871 atoi(col_width));
872 col_width = strchr(col_width, ',');
873 if (col_width)
874 ++col_width;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200875 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200876 }
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300877 if (!hists__new_col_len(hists, se->se_width_idx, width))
878 width = hists__col_len(hists, se->se_width_idx);
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200879 fprintf(fp, " %*s", width, se->se_header);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200880 }
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300881
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200882 fprintf(fp, "\n");
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300883 if (max_rows && ++nr_rows >= max_rows)
884 goto out;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200885
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200886 if (sep)
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200887 goto print_entries;
888
889 fprintf(fp, "# ........");
890 if (symbol_conf.show_nr_samples)
891 fprintf(fp, " ..........");
Arnaldo Carvalho de Melo3f2728b2011-10-05 16:10:06 -0300892 if (symbol_conf.show_total_period)
893 fprintf(fp, " ............");
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200894 if (pair) {
895 fprintf(fp, " ..........");
896 if (show_displacement)
897 fprintf(fp, " .....");
898 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200899 list_for_each_entry(se, &hist_entry__sort_list, list) {
900 unsigned int i;
901
902 if (se->elide)
903 continue;
904
905 fprintf(fp, " ");
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300906 width = hists__col_len(hists, se->se_width_idx);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300907 if (width == 0)
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200908 width = strlen(se->se_header);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200909 for (i = 0; i < width; i++)
910 fprintf(fp, ".");
911 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200912
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300913 fprintf(fp, "\n");
914 if (max_rows && ++nr_rows >= max_rows)
915 goto out;
916
917 fprintf(fp, "#\n");
918 if (max_rows && ++nr_rows >= max_rows)
919 goto out;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200920
921print_entries:
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300922 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200923 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
924
Frederic Weisbeckere84d2122011-06-29 22:23:03 +0200925 if (h->filtered)
926 continue;
927
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200928 if (show_displacement) {
929 if (h->pair != NULL)
930 displacement = ((long)h->pair->position -
931 (long)position);
932 else
933 displacement = 0;
934 ++position;
935 }
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300936 ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement,
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300937 displacement, fp, hists->stats.total_period);
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300938
939 if (symbol_conf.use_callchain)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300940 ret += hist_entry__fprintf_callchain(h, hists, fp,
941 hists->stats.total_period);
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300942 if (max_rows && ++nr_rows >= max_rows)
943 goto out;
944
Arnaldo Carvalho de Melo59fd5302010-03-24 16:40:17 -0300945 if (h->ms.map == NULL && verbose > 1) {
Arnaldo Carvalho de Melo65f2ed22010-03-09 15:58:17 -0300946 __map_groups__fprintf_maps(&h->thread->mg,
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300947 MAP__FUNCTION, verbose, fp);
Arnaldo Carvalho de Melo65f2ed22010-03-09 15:58:17 -0300948 fprintf(fp, "%.10s end\n", graph_dotted_line);
949 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200950 }
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300951out:
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200952 free(rem_sq_bracket);
953
954 return ret;
955}
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -0300956
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -0300957/*
958 * See hists__fprintf to match the column widths
959 */
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300960unsigned int hists__sort_list_width(struct hists *hists)
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -0300961{
962 struct sort_entry *se;
963 int ret = 9; /* total % */
964
965 if (symbol_conf.show_cpu_utilization) {
966 ret += 7; /* count_sys % */
967 ret += 6; /* count_us % */
968 if (perf_guest) {
969 ret += 13; /* count_guest_sys % */
970 ret += 12; /* count_guest_us % */
971 }
972 }
973
974 if (symbol_conf.show_nr_samples)
975 ret += 11;
976
Arnaldo Carvalho de Melo3f2728b2011-10-05 16:10:06 -0300977 if (symbol_conf.show_total_period)
978 ret += 13;
979
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -0300980 list_for_each_entry(se, &hist_entry__sort_list, list)
981 if (!se->elide)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300982 ret += 2 + hists__col_len(hists, se->se_width_idx);
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -0300983
Arnaldo Carvalho de Melo903cce62010-08-05 19:15:48 -0300984 if (verbose) /* Addr + origin */
985 ret += 3 + BITS_PER_LONG / 4;
986
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -0300987 return ret;
988}
989
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300990static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
Arnaldo Carvalho de Melocc5edb02010-07-16 12:35:07 -0300991 enum hist_filter filter)
992{
993 h->filtered &= ~(1 << filter);
994 if (h->filtered)
995 return;
996
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300997 ++hists->nr_entries;
Arnaldo Carvalho de Melo0f0cbf72010-07-26 17:13:40 -0300998 if (h->ms.unfolded)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300999 hists->nr_entries += h->nr_rows;
Arnaldo Carvalho de Melo0f0cbf72010-07-26 17:13:40 -03001000 h->row_offset = 0;
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001001 hists->stats.total_period += h->period;
1002 hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
Arnaldo Carvalho de Melocc5edb02010-07-16 12:35:07 -03001003
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001004 hists__calc_col_len(hists, h);
Arnaldo Carvalho de Melocc5edb02010-07-16 12:35:07 -03001005}
1006
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001007void hists__filter_by_dso(struct hists *hists, const struct dso *dso)
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001008{
1009 struct rb_node *nd;
1010
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001011 hists->nr_entries = hists->stats.total_period = 0;
1012 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
1013 hists__reset_col_len(hists);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001014
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001015 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001016 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1017
1018 if (symbol_conf.exclude_other && !h->parent)
1019 continue;
1020
1021 if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) {
1022 h->filtered |= (1 << HIST_FILTER__DSO);
1023 continue;
1024 }
1025
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001026 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001027 }
1028}
1029
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001030void hists__filter_by_thread(struct hists *hists, const struct thread *thread)
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001031{
1032 struct rb_node *nd;
1033
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001034 hists->nr_entries = hists->stats.total_period = 0;
1035 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
1036 hists__reset_col_len(hists);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001037
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001038 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001039 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1040
1041 if (thread != NULL && h->thread != thread) {
1042 h->filtered |= (1 << HIST_FILTER__THREAD);
1043 continue;
1044 }
Arnaldo Carvalho de Melocc5edb02010-07-16 12:35:07 -03001045
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001046 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001047 }
1048}
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001049
Arnaldo Carvalho de Melo2f525d02011-02-04 13:43:24 -02001050int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001051{
Arnaldo Carvalho de Melo2f525d02011-02-04 13:43:24 -02001052 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001053}
1054
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -02001055int hist_entry__annotate(struct hist_entry *he, size_t privsize)
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001056{
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -02001057 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001058}
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001059
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001060void hists__inc_nr_events(struct hists *hists, u32 type)
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001061{
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001062 ++hists->stats.nr_events[0];
1063 ++hists->stats.nr_events[type];
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001064}
1065
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001066size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001067{
1068 int i;
1069 size_t ret = 0;
1070
1071 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
Arnaldo Carvalho de Meloe248de32011-03-05 21:40:06 -03001072 const char *name;
Thomas Gleixner3835bc02010-12-07 12:48:42 +00001073
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001074 if (hists->stats.nr_events[i] == 0)
Arnaldo Carvalho de Meloe248de32011-03-05 21:40:06 -03001075 continue;
1076
1077 name = perf_event__name(i);
Thomas Gleixner3835bc02010-12-07 12:48:42 +00001078 if (!strcmp(name, "UNKNOWN"))
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001079 continue;
Thomas Gleixner3835bc02010-12-07 12:48:42 +00001080
1081 ret += fprintf(fp, "%16s events: %10d\n", name,
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001082 hists->stats.nr_events[i]);
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001083 }
1084
1085 return ret;
1086}
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -03001087
1088void hists__init(struct hists *hists)
1089{
1090 memset(hists, 0, sizeof(*hists));
1091 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
1092 hists->entries_in = &hists->entries_in_array[0];
1093 hists->entries_collapsed = RB_ROOT;
1094 hists->entries = RB_ROOT;
1095 pthread_mutex_init(&hists->lock, NULL);
1096}