blob: 75526d123eb2da4d2a3129681250c50947842d91 [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 Melo90cf1fb2011-10-19 13:09:10 -02009static bool hists__filter_entry_by_dso(struct hists *hists,
10 struct hist_entry *he);
11static bool hists__filter_entry_by_thread(struct hists *hists,
12 struct hist_entry *he);
13
Arnaldo Carvalho de Melo7a007ca2010-07-21 09:19:41 -030014enum hist_filter {
15 HIST_FILTER__DSO,
16 HIST_FILTER__THREAD,
17 HIST_FILTER__PARENT,
18};
19
John Kacur3d1d07e2009-09-28 15:32:55 +020020struct callchain_param callchain_param = {
21 .mode = CHAIN_GRAPH_REL,
Sam Liaod797fdc2011-06-07 23:49:46 +080022 .min_percent = 0.5,
23 .order = ORDER_CALLEE
John Kacur3d1d07e2009-09-28 15:32:55 +020024};
25
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030026u16 hists__col_len(struct hists *hists, enum hist_column col)
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030027{
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030028 return hists->col_len[col];
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030029}
30
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030031void hists__set_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 hists->col_len[col] = len;
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030034}
35
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030036bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len)
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030037{
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030038 if (len > hists__col_len(hists, col)) {
39 hists__set_col_len(hists, col, len);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030040 return true;
41 }
42 return false;
43}
44
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030045static void hists__reset_col_len(struct hists *hists)
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030046{
47 enum hist_column col;
48
49 for (col = 0; col < HISTC_NR_COLS; ++col)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030050 hists__set_col_len(hists, col, 0);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030051}
52
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030053static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030054{
55 u16 len;
56
57 if (h->ms.sym)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030058 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen);
Arnaldo Carvalho de Melod7603d52011-03-04 14:51:33 -030059 else {
60 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
61
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030062 if (hists__col_len(hists, HISTC_DSO) < unresolved_col_width &&
Arnaldo Carvalho de Melod7603d52011-03-04 14:51:33 -030063 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
64 !symbol_conf.dso_list)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030065 hists__set_col_len(hists, HISTC_DSO,
Arnaldo Carvalho de Melod7603d52011-03-04 14:51:33 -030066 unresolved_col_width);
67 }
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030068
69 len = thread__comm_len(h->thread);
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030070 if (hists__new_col_len(hists, HISTC_COMM, len))
71 hists__set_col_len(hists, HISTC_THREAD, len + 6);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030072
73 if (h->ms.map) {
74 len = dso__name_len(h->ms.map->dso);
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -030075 hists__new_col_len(hists, HISTC_DSO, len);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -030076 }
77}
78
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -030079static void hist_entry__add_cpumode_period(struct hist_entry *self,
80 unsigned int cpumode, u64 period)
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080081{
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -030082 switch (cpumode) {
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080083 case PERF_RECORD_MISC_KERNEL:
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -030084 self->period_sys += period;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080085 break;
86 case PERF_RECORD_MISC_USER:
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -030087 self->period_us += period;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080088 break;
89 case PERF_RECORD_MISC_GUEST_KERNEL:
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -030090 self->period_guest_sys += period;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080091 break;
92 case PERF_RECORD_MISC_GUEST_USER:
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -030093 self->period_guest_us += period;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080094 break;
95 default:
96 break;
97 }
98}
99
Arnaldo Carvalho de Meloab81f3f2011-10-05 19:16:15 -0300100static void hist_entry__decay(struct hist_entry *he)
101{
102 he->period = (he->period * 7) / 8;
103 he->nr_events = (he->nr_events * 7) / 8;
104}
105
106static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
107{
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -0300108 if (he->period == 0)
109 return true;
Arnaldo Carvalho de Meloab81f3f2011-10-05 19:16:15 -0300110 hists->stats.total_period -= he->period;
111 hist_entry__decay(he);
112 hists->stats.total_period += he->period;
113 return he->period == 0;
114}
115
Arnaldo Carvalho de Melob079d4e2011-10-17 09:05:04 -0200116static void __hists__decay_entries(struct hists *hists, bool zap_user,
117 bool zap_kernel, bool threaded)
Arnaldo Carvalho de Meloab81f3f2011-10-05 19:16:15 -0300118{
119 struct rb_node *next = rb_first(&hists->entries);
120 struct hist_entry *n;
121
122 while (next) {
123 n = rb_entry(next, struct hist_entry, rb_node);
124 next = rb_next(&n->rb_node);
Arnaldo Carvalho de Melodf71d952011-10-13 08:01:33 -0300125 /*
126 * We may be annotating this, for instance, so keep it here in
127 * case some it gets new samples, we'll eventually free it when
128 * the user stops browsing and it agains gets fully decayed.
129 */
Arnaldo Carvalho de Melob079d4e2011-10-17 09:05:04 -0200130 if (((zap_user && n->level == '.') ||
131 (zap_kernel && n->level != '.') ||
132 hists__decay_entry(hists, n)) &&
133 !n->used) {
Arnaldo Carvalho de Meloab81f3f2011-10-05 19:16:15 -0300134 rb_erase(&n->rb_node, &hists->entries);
135
Arnaldo Carvalho de Meloe345fa12011-10-13 09:06:54 -0300136 if (sort__need_collapse || threaded)
Arnaldo Carvalho de Meloab81f3f2011-10-05 19:16:15 -0300137 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
138
139 hist_entry__free(n);
140 --hists->nr_entries;
141 }
142 }
143}
144
Arnaldo Carvalho de Melob079d4e2011-10-17 09:05:04 -0200145void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
Arnaldo Carvalho de Meloe345fa12011-10-13 09:06:54 -0300146{
Arnaldo Carvalho de Melob079d4e2011-10-17 09:05:04 -0200147 return __hists__decay_entries(hists, zap_user, zap_kernel, false);
Arnaldo Carvalho de Meloe345fa12011-10-13 09:06:54 -0300148}
149
Arnaldo Carvalho de Melob079d4e2011-10-17 09:05:04 -0200150void hists__decay_entries_threaded(struct hists *hists,
151 bool zap_user, bool zap_kernel)
Arnaldo Carvalho de Meloe345fa12011-10-13 09:06:54 -0300152{
Arnaldo Carvalho de Melob079d4e2011-10-17 09:05:04 -0200153 return __hists__decay_entries(hists, zap_user, zap_kernel, true);
Arnaldo Carvalho de Meloe345fa12011-10-13 09:06:54 -0300154}
155
John Kacur3d1d07e2009-09-28 15:32:55 +0200156/*
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300157 * histogram, sorted on item, collects periods
John Kacur3d1d07e2009-09-28 15:32:55 +0200158 */
159
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300160static struct hist_entry *hist_entry__new(struct hist_entry *template)
161{
Frederic Weisbeckerd2009c52010-08-22 20:05:22 +0200162 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300163 struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
164
165 if (self != NULL) {
166 *self = *template;
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300167 self->nr_events = 1;
Arnaldo Carvalho de Melo0a1eae32010-08-02 19:45:23 -0300168 if (self->ms.map)
169 self->ms.map->referenced = true;
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300170 if (symbol_conf.use_callchain)
171 callchain_init(self->callchain);
172 }
173
174 return self;
175}
176
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300177static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300178{
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300179 if (!h->filtered) {
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300180 hists__calc_col_len(hists, h);
181 ++hists->nr_entries;
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300182 hists->stats.total_period += h->period;
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300183 }
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300184}
185
Arnaldo Carvalho de Melo7a007ca2010-07-21 09:19:41 -0300186static u8 symbol__parent_filter(const struct symbol *parent)
187{
188 if (symbol_conf.exclude_other && parent == NULL)
189 return 1 << HIST_FILTER__PARENT;
190 return 0;
191}
192
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300193struct hist_entry *__hists__add_entry(struct hists *hists,
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300194 struct addr_location *al,
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300195 struct symbol *sym_parent, u64 period)
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300196{
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300197 struct rb_node **p;
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300198 struct rb_node *parent = NULL;
199 struct hist_entry *he;
200 struct hist_entry entry = {
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -0200201 .thread = al->thread,
Arnaldo Carvalho de Melo59fd5302010-03-24 16:40:17 -0300202 .ms = {
203 .map = al->map,
204 .sym = al->sym,
205 },
Arun Sharmaf60f3592010-06-04 11:27:10 -0300206 .cpu = al->cpu,
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -0200207 .ip = al->addr,
208 .level = al->level,
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300209 .period = period,
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300210 .parent = sym_parent,
Arnaldo Carvalho de Melo7a007ca2010-07-21 09:19:41 -0300211 .filtered = symbol__parent_filter(sym_parent),
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300212 };
213 int cmp;
214
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300215 pthread_mutex_lock(&hists->lock);
216
217 p = &hists->entries_in->rb_node;
218
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300219 while (*p != NULL) {
220 parent = *p;
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300221 he = rb_entry(parent, struct hist_entry, rb_node_in);
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300222
223 cmp = hist_entry__cmp(&entry, he);
224
225 if (!cmp) {
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300226 he->period += period;
227 ++he->nr_events;
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300228 goto out;
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300229 }
230
231 if (cmp < 0)
232 p = &(*p)->rb_left;
233 else
234 p = &(*p)->rb_right;
235 }
236
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300237 he = hist_entry__new(&entry);
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300238 if (!he)
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300239 goto out_unlock;
240
241 rb_link_node(&he->rb_node_in, parent, p);
242 rb_insert_color(&he->rb_node_in, hists->entries_in);
Arnaldo Carvalho de Melo28e2a102010-05-09 13:02:23 -0300243out:
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300244 hist_entry__add_cpumode_period(he, al->cpumode, period);
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300245out_unlock:
246 pthread_mutex_unlock(&hists->lock);
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300247 return he;
248}
249
John Kacur3d1d07e2009-09-28 15:32:55 +0200250int64_t
251hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
252{
253 struct sort_entry *se;
254 int64_t cmp = 0;
255
256 list_for_each_entry(se, &hist_entry__sort_list, list) {
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200257 cmp = se->se_cmp(left, right);
John Kacur3d1d07e2009-09-28 15:32:55 +0200258 if (cmp)
259 break;
260 }
261
262 return cmp;
263}
264
265int64_t
266hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
267{
268 struct sort_entry *se;
269 int64_t cmp = 0;
270
271 list_for_each_entry(se, &hist_entry__sort_list, list) {
272 int64_t (*f)(struct hist_entry *, struct hist_entry *);
273
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200274 f = se->se_collapse ?: se->se_cmp;
John Kacur3d1d07e2009-09-28 15:32:55 +0200275
276 cmp = f(left, right);
277 if (cmp)
278 break;
279 }
280
281 return cmp;
282}
283
284void hist_entry__free(struct hist_entry *he)
285{
286 free(he);
287}
288
289/*
290 * collapse the histogram
291 */
292
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300293static bool hists__collapse_insert_entry(struct hists *hists,
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100294 struct rb_root *root,
295 struct hist_entry *he)
John Kacur3d1d07e2009-09-28 15:32:55 +0200296{
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200297 struct rb_node **p = &root->rb_node;
John Kacur3d1d07e2009-09-28 15:32:55 +0200298 struct rb_node *parent = NULL;
299 struct hist_entry *iter;
300 int64_t cmp;
301
302 while (*p != NULL) {
303 parent = *p;
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300304 iter = rb_entry(parent, struct hist_entry, rb_node_in);
John Kacur3d1d07e2009-09-28 15:32:55 +0200305
306 cmp = hist_entry__collapse(iter, he);
307
308 if (!cmp) {
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300309 iter->period += he->period;
Stephane Eraniane39622c2011-10-03 11:38:15 +0200310 iter->nr_events += he->nr_events;
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100311 if (symbol_conf.use_callchain) {
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300312 callchain_cursor_reset(&hists->callchain_cursor);
313 callchain_merge(&hists->callchain_cursor, iter->callchain,
Frederic Weisbecker1b3a0e92011-01-14 04:51:58 +0100314 he->callchain);
315 }
John Kacur3d1d07e2009-09-28 15:32:55 +0200316 hist_entry__free(he);
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300317 return false;
John Kacur3d1d07e2009-09-28 15:32:55 +0200318 }
319
320 if (cmp < 0)
321 p = &(*p)->rb_left;
322 else
323 p = &(*p)->rb_right;
324 }
325
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300326 rb_link_node(&he->rb_node_in, parent, p);
327 rb_insert_color(&he->rb_node_in, root);
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300328 return true;
John Kacur3d1d07e2009-09-28 15:32:55 +0200329}
330
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300331static struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
332{
333 struct rb_root *root;
334
335 pthread_mutex_lock(&hists->lock);
336
337 root = hists->entries_in;
338 if (++hists->entries_in > &hists->entries_in_array[1])
339 hists->entries_in = &hists->entries_in_array[0];
340
341 pthread_mutex_unlock(&hists->lock);
342
343 return root;
344}
345
Arnaldo Carvalho de Melo90cf1fb2011-10-19 13:09:10 -0200346static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
347{
348 hists__filter_entry_by_dso(hists, he);
349 hists__filter_entry_by_thread(hists, he);
350}
351
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300352static void __hists__collapse_resort(struct hists *hists, bool threaded)
353{
354 struct rb_root *root;
355 struct rb_node *next;
356 struct hist_entry *n;
357
358 if (!sort__need_collapse && !threaded)
359 return;
360
361 root = hists__get_rotate_entries_in(hists);
362 next = rb_first(root);
363 hists->stats.total_period = 0;
364
365 while (next) {
366 n = rb_entry(next, struct hist_entry, rb_node_in);
367 next = rb_next(&n->rb_node_in);
368
369 rb_erase(&n->rb_node_in, root);
Arnaldo Carvalho de Melo90cf1fb2011-10-19 13:09:10 -0200370 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n)) {
371 /*
372 * If it wasn't combined with one of the entries already
373 * collapsed, we need to apply the filters that may have
374 * been set by, say, the hist_browser.
375 */
376 hists__apply_filters(hists, n);
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300377 hists__inc_nr_entries(hists, n);
Arnaldo Carvalho de Melo90cf1fb2011-10-19 13:09:10 -0200378 }
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300379 }
380}
381
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300382void hists__collapse_resort(struct hists *hists)
John Kacur3d1d07e2009-09-28 15:32:55 +0200383{
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300384 return __hists__collapse_resort(hists, false);
385}
John Kacur3d1d07e2009-09-28 15:32:55 +0200386
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300387void hists__collapse_resort_threaded(struct hists *hists)
388{
389 return __hists__collapse_resort(hists, true);
John Kacur3d1d07e2009-09-28 15:32:55 +0200390}
391
392/*
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300393 * reverse the map, sort on period.
John Kacur3d1d07e2009-09-28 15:32:55 +0200394 */
395
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300396static void __hists__insert_output_entry(struct rb_root *entries,
397 struct hist_entry *he,
398 u64 min_callchain_hits)
John Kacur3d1d07e2009-09-28 15:32:55 +0200399{
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300400 struct rb_node **p = &entries->rb_node;
John Kacur3d1d07e2009-09-28 15:32:55 +0200401 struct rb_node *parent = NULL;
402 struct hist_entry *iter;
403
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -0200404 if (symbol_conf.use_callchain)
Arnaldo Carvalho de Melob9fb9302010-04-02 09:50:42 -0300405 callchain_param.sort(&he->sorted_chain, he->callchain,
John Kacur3d1d07e2009-09-28 15:32:55 +0200406 min_callchain_hits, &callchain_param);
407
408 while (*p != NULL) {
409 parent = *p;
410 iter = rb_entry(parent, struct hist_entry, rb_node);
411
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300412 if (he->period > iter->period)
John Kacur3d1d07e2009-09-28 15:32:55 +0200413 p = &(*p)->rb_left;
414 else
415 p = &(*p)->rb_right;
416 }
417
418 rb_link_node(&he->rb_node, parent, p);
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300419 rb_insert_color(&he->rb_node, entries);
John Kacur3d1d07e2009-09-28 15:32:55 +0200420}
421
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300422static void __hists__output_resort(struct hists *hists, bool threaded)
John Kacur3d1d07e2009-09-28 15:32:55 +0200423{
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300424 struct rb_root *root;
John Kacur3d1d07e2009-09-28 15:32:55 +0200425 struct rb_node *next;
426 struct hist_entry *n;
John Kacur3d1d07e2009-09-28 15:32:55 +0200427 u64 min_callchain_hits;
428
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300429 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
John Kacur3d1d07e2009-09-28 15:32:55 +0200430
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300431 if (sort__need_collapse || threaded)
432 root = &hists->entries_collapsed;
433 else
434 root = hists->entries_in;
435
436 next = rb_first(root);
437 hists->entries = RB_ROOT;
John Kacur3d1d07e2009-09-28 15:32:55 +0200438
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300439 hists->nr_entries = 0;
440 hists__reset_col_len(hists);
Arnaldo Carvalho de Melofefb0b92010-05-10 13:57:51 -0300441
John Kacur3d1d07e2009-09-28 15:32:55 +0200442 while (next) {
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300443 n = rb_entry(next, struct hist_entry, rb_node_in);
444 next = rb_next(&n->rb_node_in);
John Kacur3d1d07e2009-09-28 15:32:55 +0200445
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300446 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300447 hists__inc_nr_entries(hists, n);
John Kacur3d1d07e2009-09-28 15:32:55 +0200448 }
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300449}
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200450
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -0300451void hists__output_resort(struct hists *hists)
452{
453 return __hists__output_resort(hists, false);
454}
455
456void hists__output_resort_threaded(struct hists *hists)
457{
458 return __hists__output_resort(hists, true);
John Kacur3d1d07e2009-09-28 15:32:55 +0200459}
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200460
461static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
462{
463 int i;
464 int ret = fprintf(fp, " ");
465
466 for (i = 0; i < left_margin; i++)
467 ret += fprintf(fp, " ");
468
469 return ret;
470}
471
472static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
473 int left_margin)
474{
475 int i;
476 size_t ret = callchain__fprintf_left_margin(fp, left_margin);
477
478 for (i = 0; i < depth; i++)
479 if (depth_mask & (1 << i))
480 ret += fprintf(fp, "| ");
481 else
482 ret += fprintf(fp, " ");
483
484 ret += fprintf(fp, "\n");
485
486 return ret;
487}
488
489static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300490 int depth, int depth_mask, int period,
Frederic Weisbeckerd425de52011-01-03 16:13:11 +0100491 u64 total_samples, u64 hits,
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200492 int left_margin)
493{
494 int i;
495 size_t ret = 0;
496
497 ret += callchain__fprintf_left_margin(fp, left_margin);
498 for (i = 0; i < depth; i++) {
499 if (depth_mask & (1 << i))
500 ret += fprintf(fp, "|");
501 else
502 ret += fprintf(fp, " ");
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300503 if (!period && i == depth - 1) {
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200504 double percent;
505
506 percent = hits * 100.0 / total_samples;
507 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
508 } else
509 ret += fprintf(fp, "%s", " ");
510 }
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300511 if (chain->ms.sym)
512 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200513 else
514 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
515
516 return ret;
517}
518
519static struct symbol *rem_sq_bracket;
520static struct callchain_list rem_hits;
521
522static void init_rem_hits(void)
523{
524 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
525 if (!rem_sq_bracket) {
526 fprintf(stderr, "Not enough memory to display remaining hits\n");
527 return;
528 }
529
530 strcpy(rem_sq_bracket->name, "[...]");
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300531 rem_hits.ms.sym = rem_sq_bracket;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200532}
533
534static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
535 u64 total_samples, int depth,
536 int depth_mask, int left_margin)
537{
538 struct rb_node *node, *next;
539 struct callchain_node *child;
540 struct callchain_list *chain;
541 int new_depth_mask = depth_mask;
542 u64 new_total;
543 u64 remaining;
544 size_t ret = 0;
545 int i;
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300546 uint entries_printed = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200547
548 if (callchain_param.mode == CHAIN_GRAPH_REL)
549 new_total = self->children_hit;
550 else
551 new_total = total_samples;
552
553 remaining = new_total;
554
555 node = rb_first(&self->rb_root);
556 while (node) {
557 u64 cumul;
558
559 child = rb_entry(node, struct callchain_node, rb_node);
Frederic Weisbeckerf08c3152011-01-14 04:51:59 +0100560 cumul = callchain_cumul_hits(child);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200561 remaining -= cumul;
562
563 /*
564 * The depth mask manages the output of pipes that show
565 * the depth. We don't want to keep the pipes of the current
566 * level for the last child of this depth.
567 * Except if we have remaining filtered hits. They will
568 * supersede the last child
569 */
570 next = rb_next(node);
571 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
572 new_depth_mask &= ~(1 << (depth - 1));
573
574 /*
Daniel Mack3ad2f3f2010-02-03 08:01:28 +0800575 * But we keep the older depth mask for the line separator
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200576 * to keep the level link until we reach the last child
577 */
578 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
579 left_margin);
580 i = 0;
581 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200582 ret += ipchain__fprintf_graph(fp, chain, depth,
583 new_depth_mask, i++,
584 new_total,
585 cumul,
586 left_margin);
587 }
588 ret += __callchain__fprintf_graph(fp, child, new_total,
589 depth + 1,
590 new_depth_mask | (1 << depth),
591 left_margin);
592 node = next;
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300593 if (++entries_printed == callchain_param.print_limit)
594 break;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200595 }
596
597 if (callchain_param.mode == CHAIN_GRAPH_REL &&
598 remaining && remaining != new_total) {
599
600 if (!rem_sq_bracket)
601 return ret;
602
603 new_depth_mask &= ~(1 << (depth - 1));
604
605 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
606 new_depth_mask, 0, new_total,
607 remaining, left_margin);
608 }
609
610 return ret;
611}
612
613static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
614 u64 total_samples, int left_margin)
615{
616 struct callchain_list *chain;
617 bool printed = false;
618 int i = 0;
619 int ret = 0;
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300620 u32 entries_printed = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200621
622 list_for_each_entry(chain, &self->val, list) {
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200623 if (!i++ && sort__first_dimension == SORT_SYM)
624 continue;
625
626 if (!printed) {
627 ret += callchain__fprintf_left_margin(fp, left_margin);
628 ret += fprintf(fp, "|\n");
629 ret += callchain__fprintf_left_margin(fp, left_margin);
630 ret += fprintf(fp, "---");
631
632 left_margin += 3;
633 printed = true;
634 } else
635 ret += callchain__fprintf_left_margin(fp, left_margin);
636
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300637 if (chain->ms.sym)
638 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200639 else
640 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300641
642 if (++entries_printed == callchain_param.print_limit)
643 break;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200644 }
645
646 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
647
648 return ret;
649}
650
651static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
652 u64 total_samples)
653{
654 struct callchain_list *chain;
655 size_t ret = 0;
656
657 if (!self)
658 return 0;
659
660 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
661
662
663 list_for_each_entry(chain, &self->val, list) {
664 if (chain->ip >= PERF_CONTEXT_MAX)
665 continue;
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300666 if (chain->ms.sym)
667 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200668 else
669 ret += fprintf(fp, " %p\n",
670 (void *)(long)chain->ip);
671 }
672
673 return ret;
674}
675
676static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
677 u64 total_samples, int left_margin)
678{
679 struct rb_node *rb_node;
680 struct callchain_node *chain;
681 size_t ret = 0;
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300682 u32 entries_printed = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200683
684 rb_node = rb_first(&self->sorted_chain);
685 while (rb_node) {
686 double percent;
687
688 chain = rb_entry(rb_node, struct callchain_node, rb_node);
689 percent = chain->hit * 100.0 / total_samples;
690 switch (callchain_param.mode) {
691 case CHAIN_FLAT:
692 ret += percent_color_fprintf(fp, " %6.2f%%\n",
693 percent);
694 ret += callchain__fprintf_flat(fp, chain, total_samples);
695 break;
696 case CHAIN_GRAPH_ABS: /* Falldown */
697 case CHAIN_GRAPH_REL:
698 ret += callchain__fprintf_graph(fp, chain, total_samples,
699 left_margin);
700 case CHAIN_NONE:
701 default:
702 break;
703 }
704 ret += fprintf(fp, "\n");
Arnaldo Carvalho de Melo232a5c92010-05-09 20:28:10 -0300705 if (++entries_printed == callchain_param.print_limit)
706 break;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200707 rb_node = rb_next(rb_node);
708 }
709
710 return ret;
711}
712
Arnaldo Carvalho de Meloab81f3f2011-10-05 19:16:15 -0300713void hists__output_recalc_col_len(struct hists *hists, int max_rows)
714{
715 struct rb_node *next = rb_first(&hists->entries);
716 struct hist_entry *n;
717 int row = 0;
718
719 hists__reset_col_len(hists);
720
721 while (next && row++ < max_rows) {
722 n = rb_entry(next, struct hist_entry, rb_node);
723 hists__calc_col_len(hists, n);
724 next = rb_next(&n->rb_node);
725 }
726}
727
Arnaldo Carvalho de Melof1cf6022011-10-18 14:37:34 -0200728static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s,
729 size_t size, struct hists *pair_hists,
730 bool show_displacement, long displacement,
731 bool color, u64 session_total)
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200732{
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300733 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200734 u64 nr_events;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200735 const char *sep = symbol_conf.field_sep;
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300736 int ret;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200737
738 if (symbol_conf.exclude_other && !self->parent)
739 return 0;
740
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300741 if (pair_hists) {
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300742 period = self->pair ? self->pair->period : 0;
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200743 nr_events = self->pair ? self->pair->nr_events : 0;
Arnaldo Carvalho de Melocee75ac2010-05-14 13:16:55 -0300744 total = pair_hists->stats.total_period;
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300745 period_sys = self->pair ? self->pair->period_sys : 0;
746 period_us = self->pair ? self->pair->period_us : 0;
747 period_guest_sys = self->pair ? self->pair->period_guest_sys : 0;
748 period_guest_us = self->pair ? self->pair->period_guest_us : 0;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200749 } else {
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300750 period = self->period;
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200751 nr_events = self->nr_events;
Eric B Munsoneefc4652010-03-05 12:51:08 -0300752 total = session_total;
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300753 period_sys = self->period_sys;
754 period_us = self->period_us;
755 period_guest_sys = self->period_guest_sys;
756 period_guest_us = self->period_guest_us;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200757 }
758
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300759 if (total) {
760 if (color)
761 ret = percent_color_snprintf(s, size,
762 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300763 (period * 100.0) / total);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300764 else
765 ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300766 (period * 100.0) / total);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800767 if (symbol_conf.show_cpu_utilization) {
768 ret += percent_color_snprintf(s + ret, size - ret,
769 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300770 (period_sys * 100.0) / total);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800771 ret += percent_color_snprintf(s + ret, size - ret,
772 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300773 (period_us * 100.0) / total);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800774 if (perf_guest) {
775 ret += percent_color_snprintf(s + ret,
776 size - ret,
777 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300778 (period_guest_sys * 100.0) /
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800779 total);
780 ret += percent_color_snprintf(s + ret,
781 size - ret,
782 sep ? "%.2f" : " %6.2f%%",
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300783 (period_guest_us * 100.0) /
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800784 total);
785 }
786 }
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300787 } else
Arnaldo Carvalho de Melo9486aa32011-01-22 20:37:02 -0200788 ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200789
790 if (symbol_conf.show_nr_samples) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200791 if (sep)
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200792 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200793 else
Arnaldo Carvalho de Melofec9cbd2011-02-17 10:37:23 -0200794 ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200795 }
796
Arnaldo Carvalho de Melo3f2728b2011-10-05 16:10:06 -0300797 if (symbol_conf.show_total_period) {
798 if (sep)
799 ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
800 else
801 ret += snprintf(s + ret, size - ret, " %12" PRIu64, period);
802 }
803
Arnaldo Carvalho de Melo1c02c4d2010-05-10 13:04:11 -0300804 if (pair_hists) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200805 char bf[32];
806 double old_percent = 0, new_percent = 0, diff;
807
808 if (total > 0)
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300809 old_percent = (period * 100.0) / total;
Eric B Munsoneefc4652010-03-05 12:51:08 -0300810 if (session_total > 0)
Arnaldo Carvalho de Meloc82ee822010-05-14 14:19:35 -0300811 new_percent = (self->period * 100.0) / session_total;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200812
Arnaldo Carvalho de Melo9b338272009-12-16 14:31:49 -0200813 diff = new_percent - old_percent;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200814
Arnaldo Carvalho de Melo9b338272009-12-16 14:31:49 -0200815 if (fabs(diff) >= 0.01)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200816 snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
817 else
818 snprintf(bf, sizeof(bf), " ");
819
820 if (sep)
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300821 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200822 else
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300823 ret += snprintf(s + ret, size - ret, "%11.11s", bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200824
825 if (show_displacement) {
826 if (displacement)
827 snprintf(bf, sizeof(bf), "%+4ld", displacement);
828 else
829 snprintf(bf, sizeof(bf), " ");
830
831 if (sep)
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300832 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200833 else
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300834 ret += snprintf(s + ret, size - ret, "%6.6s", bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200835 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200836 }
837
Arnaldo Carvalho de Melof1cf6022011-10-18 14:37:34 -0200838 return ret;
839}
840
841int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size,
842 struct hists *hists)
843{
844 const char *sep = symbol_conf.field_sep;
845 struct sort_entry *se;
846 int ret = 0;
847
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200848 list_for_each_entry(se, &hist_entry__sort_list, list) {
849 if (se->elide)
850 continue;
851
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300852 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
Arnaldo Carvalho de Melof1cf6022011-10-18 14:37:34 -0200853 ret += se->se_snprintf(he, s + ret, size - ret,
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300854 hists__col_len(hists, se->se_width_idx));
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200855 }
856
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300857 return ret;
858}
859
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300860int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300861 struct hists *pair_hists, bool show_displacement,
862 long displacement, FILE *fp, u64 session_total)
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300863{
864 char bf[512];
Arnaldo Carvalho de Melof1cf6022011-10-18 14:37:34 -0200865 int ret;
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300866
867 if (size == 0 || size > sizeof(bf))
868 size = sizeof(bf);
869
Arnaldo Carvalho de Melof1cf6022011-10-18 14:37:34 -0200870 ret = hist_entry__pcnt_snprintf(he, bf, size, pair_hists,
871 show_displacement, displacement,
872 true, session_total);
873 hist_entry__snprintf(he, bf + ret, size - ret, hists);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300874 return fprintf(fp, "%s\n", bf);
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300875}
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200876
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300877static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
878 struct hists *hists, FILE *fp,
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300879 u64 session_total)
880{
881 int left_margin = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200882
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300883 if (sort__first_dimension == SORT_COMM) {
884 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
885 typeof(*se), list);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300886 left_margin = hists__col_len(hists, se->se_width_idx);
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300887 left_margin -= thread__comm_len(self->thread);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200888 }
889
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300890 return hist_entry_callchain__fprintf(fp, self, session_total,
891 left_margin);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200892}
893
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300894size_t hists__fprintf(struct hists *hists, struct hists *pair,
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300895 bool show_displacement, bool show_header, int max_rows,
896 int max_cols, FILE *fp)
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200897{
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200898 struct sort_entry *se;
899 struct rb_node *nd;
900 size_t ret = 0;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200901 unsigned long position = 1;
902 long displacement = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200903 unsigned int width;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200904 const char *sep = symbol_conf.field_sep;
Arnaldo Carvalho de Meloedb7c602010-05-17 16:22:41 -0300905 const char *col_width = symbol_conf.col_width_list_str;
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300906 int nr_rows = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200907
908 init_rem_hits();
909
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300910 if (!show_header)
911 goto print_entries;
912
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200913 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
914
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200915 if (symbol_conf.show_nr_samples) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200916 if (sep)
917 fprintf(fp, "%cSamples", *sep);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200918 else
919 fputs(" Samples ", fp);
920 }
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200921
Arnaldo Carvalho de Melo3f2728b2011-10-05 16:10:06 -0300922 if (symbol_conf.show_total_period) {
923 if (sep)
924 ret += fprintf(fp, "%cPeriod", *sep);
925 else
926 ret += fprintf(fp, " Period ");
927 }
928
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800929 if (symbol_conf.show_cpu_utilization) {
930 if (sep) {
931 ret += fprintf(fp, "%csys", *sep);
932 ret += fprintf(fp, "%cus", *sep);
933 if (perf_guest) {
934 ret += fprintf(fp, "%cguest sys", *sep);
935 ret += fprintf(fp, "%cguest us", *sep);
936 }
937 } else {
938 ret += fprintf(fp, " sys ");
939 ret += fprintf(fp, " us ");
940 if (perf_guest) {
941 ret += fprintf(fp, " guest sys ");
942 ret += fprintf(fp, " guest us ");
943 }
944 }
945 }
946
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200947 if (pair) {
948 if (sep)
949 ret += fprintf(fp, "%cDelta", *sep);
950 else
951 ret += fprintf(fp, " Delta ");
952
953 if (show_displacement) {
954 if (sep)
955 ret += fprintf(fp, "%cDisplacement", *sep);
956 else
957 ret += fprintf(fp, " Displ");
958 }
959 }
960
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200961 list_for_each_entry(se, &hist_entry__sort_list, list) {
962 if (se->elide)
963 continue;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200964 if (sep) {
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200965 fprintf(fp, "%c%s", *sep, se->se_header);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200966 continue;
967 }
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200968 width = strlen(se->se_header);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300969 if (symbol_conf.col_width_list_str) {
970 if (col_width) {
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300971 hists__set_col_len(hists, se->se_width_idx,
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -0300972 atoi(col_width));
973 col_width = strchr(col_width, ',');
974 if (col_width)
975 ++col_width;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200976 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200977 }
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -0300978 if (!hists__new_col_len(hists, se->se_width_idx, width))
979 width = hists__col_len(hists, se->se_width_idx);
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200980 fprintf(fp, " %*s", width, se->se_header);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200981 }
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300982
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200983 fprintf(fp, "\n");
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -0300984 if (max_rows && ++nr_rows >= max_rows)
985 goto out;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200986
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200987 if (sep)
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200988 goto print_entries;
989
990 fprintf(fp, "# ........");
991 if (symbol_conf.show_nr_samples)
992 fprintf(fp, " ..........");
Arnaldo Carvalho de Melo3f2728b2011-10-05 16:10:06 -0300993 if (symbol_conf.show_total_period)
994 fprintf(fp, " ............");
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200995 if (pair) {
996 fprintf(fp, " ..........");
997 if (show_displacement)
998 fprintf(fp, " .....");
999 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -02001000 list_for_each_entry(se, &hist_entry__sort_list, list) {
1001 unsigned int i;
1002
1003 if (se->elide)
1004 continue;
1005
1006 fprintf(fp, " ");
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001007 width = hists__col_len(hists, se->se_width_idx);
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -03001008 if (width == 0)
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +02001009 width = strlen(se->se_header);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -02001010 for (i = 0; i < width; i++)
1011 fprintf(fp, ".");
1012 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -02001013
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -03001014 fprintf(fp, "\n");
1015 if (max_rows && ++nr_rows >= max_rows)
1016 goto out;
1017
1018 fprintf(fp, "#\n");
1019 if (max_rows && ++nr_rows >= max_rows)
1020 goto out;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -02001021
1022print_entries:
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001023 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001024 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1025
Frederic Weisbeckere84d2122011-06-29 22:23:03 +02001026 if (h->filtered)
1027 continue;
1028
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001029 if (show_displacement) {
1030 if (h->pair != NULL)
1031 displacement = ((long)h->pair->position -
1032 (long)position);
1033 else
1034 displacement = 0;
1035 ++position;
1036 }
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -03001037 ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement,
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001038 displacement, fp, hists->stats.total_period);
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -03001039
1040 if (symbol_conf.use_callchain)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001041 ret += hist_entry__fprintf_callchain(h, hists, fp,
1042 hists->stats.total_period);
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -03001043 if (max_rows && ++nr_rows >= max_rows)
1044 goto out;
1045
Arnaldo Carvalho de Melo59fd5302010-03-24 16:40:17 -03001046 if (h->ms.map == NULL && verbose > 1) {
Arnaldo Carvalho de Melo65f2ed22010-03-09 15:58:17 -03001047 __map_groups__fprintf_maps(&h->thread->mg,
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -03001048 MAP__FUNCTION, verbose, fp);
Arnaldo Carvalho de Melo65f2ed22010-03-09 15:58:17 -03001049 fprintf(fp, "%.10s end\n", graph_dotted_line);
1050 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -02001051 }
Arnaldo Carvalho de Meloef9dfe62011-09-26 12:46:11 -03001052out:
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -02001053 free(rem_sq_bracket);
1054
1055 return ret;
1056}
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001057
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -03001058/*
1059 * See hists__fprintf to match the column widths
1060 */
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001061unsigned int hists__sort_list_width(struct hists *hists)
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -03001062{
1063 struct sort_entry *se;
1064 int ret = 9; /* total % */
1065
1066 if (symbol_conf.show_cpu_utilization) {
1067 ret += 7; /* count_sys % */
1068 ret += 6; /* count_us % */
1069 if (perf_guest) {
1070 ret += 13; /* count_guest_sys % */
1071 ret += 12; /* count_guest_us % */
1072 }
1073 }
1074
1075 if (symbol_conf.show_nr_samples)
1076 ret += 11;
1077
Arnaldo Carvalho de Melo3f2728b2011-10-05 16:10:06 -03001078 if (symbol_conf.show_total_period)
1079 ret += 13;
1080
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -03001081 list_for_each_entry(se, &hist_entry__sort_list, list)
1082 if (!se->elide)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001083 ret += 2 + hists__col_len(hists, se->se_width_idx);
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -03001084
Arnaldo Carvalho de Melo903cce62010-08-05 19:15:48 -03001085 if (verbose) /* Addr + origin */
1086 ret += 3 + BITS_PER_LONG / 4;
1087
Arnaldo Carvalho de Melo06daaab2010-07-21 17:58:25 -03001088 return ret;
1089}
1090
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001091static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
Arnaldo Carvalho de Melocc5edb02010-07-16 12:35:07 -03001092 enum hist_filter filter)
1093{
1094 h->filtered &= ~(1 << filter);
1095 if (h->filtered)
1096 return;
1097
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001098 ++hists->nr_entries;
Arnaldo Carvalho de Melo0f0cbf72010-07-26 17:13:40 -03001099 if (h->ms.unfolded)
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001100 hists->nr_entries += h->nr_rows;
Arnaldo Carvalho de Melo0f0cbf72010-07-26 17:13:40 -03001101 h->row_offset = 0;
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001102 hists->stats.total_period += h->period;
1103 hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
Arnaldo Carvalho de Melocc5edb02010-07-16 12:35:07 -03001104
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001105 hists__calc_col_len(hists, h);
Arnaldo Carvalho de Melocc5edb02010-07-16 12:35:07 -03001106}
1107
Arnaldo Carvalho de Melo90cf1fb2011-10-19 13:09:10 -02001108
1109static bool hists__filter_entry_by_dso(struct hists *hists,
1110 struct hist_entry *he)
1111{
1112 if (hists->dso_filter != NULL &&
1113 (he->ms.map == NULL || he->ms.map->dso != hists->dso_filter)) {
1114 he->filtered |= (1 << HIST_FILTER__DSO);
1115 return true;
1116 }
1117
1118 return false;
1119}
1120
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001121void hists__filter_by_dso(struct hists *hists)
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001122{
1123 struct rb_node *nd;
1124
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001125 hists->nr_entries = hists->stats.total_period = 0;
1126 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
1127 hists__reset_col_len(hists);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001128
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001129 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001130 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1131
1132 if (symbol_conf.exclude_other && !h->parent)
1133 continue;
1134
Arnaldo Carvalho de Melo90cf1fb2011-10-19 13:09:10 -02001135 if (hists__filter_entry_by_dso(hists, h))
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001136 continue;
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001137
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001138 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001139 }
1140}
1141
Arnaldo Carvalho de Melo90cf1fb2011-10-19 13:09:10 -02001142static bool hists__filter_entry_by_thread(struct hists *hists,
1143 struct hist_entry *he)
1144{
1145 if (hists->thread_filter != NULL &&
1146 he->thread != hists->thread_filter) {
1147 he->filtered |= (1 << HIST_FILTER__THREAD);
1148 return true;
1149 }
1150
1151 return false;
1152}
1153
Arnaldo Carvalho de Melod7b76f02011-10-18 19:07:34 -02001154void hists__filter_by_thread(struct hists *hists)
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001155{
1156 struct rb_node *nd;
1157
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001158 hists->nr_entries = hists->stats.total_period = 0;
1159 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
1160 hists__reset_col_len(hists);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001161
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001162 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001163 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1164
Arnaldo Carvalho de Melo90cf1fb2011-10-19 13:09:10 -02001165 if (hists__filter_entry_by_thread(hists, h))
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001166 continue;
Arnaldo Carvalho de Melocc5edb02010-07-16 12:35:07 -03001167
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001168 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
Arnaldo Carvalho de Melob09e0192010-05-11 11:10:15 -03001169 }
1170}
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001171
Arnaldo Carvalho de Melo2f525d02011-02-04 13:43:24 -02001172int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001173{
Arnaldo Carvalho de Melo2f525d02011-02-04 13:43:24 -02001174 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001175}
1176
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -02001177int hist_entry__annotate(struct hist_entry *he, size_t privsize)
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001178{
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -02001179 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
Arnaldo Carvalho de Meloef7b93a2010-05-11 23:18:06 -03001180}
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001181
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001182void hists__inc_nr_events(struct hists *hists, u32 type)
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001183{
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001184 ++hists->stats.nr_events[0];
1185 ++hists->stats.nr_events[type];
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001186}
1187
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001188size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001189{
1190 int i;
1191 size_t ret = 0;
1192
1193 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
Arnaldo Carvalho de Meloe248de32011-03-05 21:40:06 -03001194 const char *name;
Thomas Gleixner3835bc02010-12-07 12:48:42 +00001195
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001196 if (hists->stats.nr_events[i] == 0)
Arnaldo Carvalho de Meloe248de32011-03-05 21:40:06 -03001197 continue;
1198
1199 name = perf_event__name(i);
Thomas Gleixner3835bc02010-12-07 12:48:42 +00001200 if (!strcmp(name, "UNKNOWN"))
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001201 continue;
Thomas Gleixner3835bc02010-12-07 12:48:42 +00001202
1203 ret += fprintf(fp, "%16s events: %10d\n", name,
Arnaldo Carvalho de Melo42b28ac2011-09-26 12:33:28 -03001204 hists->stats.nr_events[i]);
Arnaldo Carvalho de Meloc8446b92010-05-14 10:36:42 -03001205 }
1206
1207 return ret;
1208}
Arnaldo Carvalho de Melo1980c2eb2011-10-05 17:50:23 -03001209
1210void hists__init(struct hists *hists)
1211{
1212 memset(hists, 0, sizeof(*hists));
1213 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
1214 hists->entries_in = &hists->entries_in_array[0];
1215 hists->entries_collapsed = RB_ROOT;
1216 hists->entries = RB_ROOT;
1217 pthread_mutex_init(&hists->lock, NULL);
1218}