1 // SPDX-License-Identifier: GPL-2.0
2 #include "callchain.h"
3 #include "debug.h"
4 #include "dso.h"
5 #include "build-id.h"
6 #include "hist.h"
7 #include "kvm-stat.h"
8 #include "map.h"
9 #include "map_symbol.h"
10 #include "branch.h"
11 #include "mem-events.h"
12 #include "mem-info.h"
13 #include "session.h"
14 #include "namespaces.h"
15 #include "cgroup.h"
16 #include "sort.h"
17 #include "units.h"
18 #include "evlist.h"
19 #include "evsel.h"
20 #include "annotate.h"
21 #include "srcline.h"
22 #include "symbol.h"
23 #include "thread.h"
24 #include "block-info.h"
25 #include "ui/progress.h"
26 #include <errno.h>
27 #include <math.h>
28 #include <inttypes.h>
29 #include <sys/param.h>
30 #include <linux/rbtree.h>
31 #include <linux/string.h>
32 #include <linux/time64.h>
33 #include <linux/zalloc.h>
34
35 static int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
36 static int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
37
38 static bool hists__filter_entry_by_dso(struct hists *hists,
39 struct hist_entry *he);
40 static bool hists__filter_entry_by_thread(struct hists *hists,
41 struct hist_entry *he);
42 static bool hists__filter_entry_by_symbol(struct hists *hists,
43 struct hist_entry *he);
44 static bool hists__filter_entry_by_socket(struct hists *hists,
45 struct hist_entry *he);
46 static bool hists__filter_entry_by_parallelism(struct hists *hists,
47 struct hist_entry *he);
48
hists__col_len(struct hists * hists,enum hist_column col)49 u16 hists__col_len(struct hists *hists, enum hist_column col)
50 {
51 return hists->col_len[col];
52 }
53
hists__set_col_len(struct hists * hists,enum hist_column col,u16 len)54 void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len)
55 {
56 hists->col_len[col] = len;
57 }
58
hists__new_col_len(struct hists * hists,enum hist_column col,u16 len)59 bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len)
60 {
61 if (len > hists__col_len(hists, col)) {
62 hists__set_col_len(hists, col, len);
63 return true;
64 }
65 return false;
66 }
67
hists__reset_col_len(struct hists * hists)68 void hists__reset_col_len(struct hists *hists)
69 {
70 enum hist_column col;
71
72 for (col = 0; col < HISTC_NR_COLS; ++col)
73 hists__set_col_len(hists, col, 0);
74 }
75
hists__set_unres_dso_col_len(struct hists * hists,int dso)76 static void hists__set_unres_dso_col_len(struct hists *hists, int dso)
77 {
78 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
79
80 if (hists__col_len(hists, dso) < unresolved_col_width &&
81 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
82 !symbol_conf.dso_list)
83 hists__set_col_len(hists, dso, unresolved_col_width);
84 }
85
hists__calc_col_len(struct hists * hists,struct hist_entry * h)86 void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
87 {
88 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
89 int symlen;
90 u16 len;
91
92 if (h->block_info)
93 return;
94 /*
95 * +4 accounts for '[x] ' priv level info
96 * +2 accounts for 0x prefix on raw addresses
97 * +3 accounts for ' y ' symtab origin info
98 */
99 if (h->ms.sym) {
100 symlen = h->ms.sym->namelen + 4;
101 if (verbose > 0)
102 symlen += BITS_PER_LONG / 4 + 2 + 3;
103 hists__new_col_len(hists, HISTC_SYMBOL, symlen);
104 } else {
105 symlen = unresolved_col_width + 4 + 2;
106 hists__new_col_len(hists, HISTC_SYMBOL, symlen);
107 hists__set_unres_dso_col_len(hists, HISTC_DSO);
108 }
109
110 len = thread__comm_len(h->thread);
111 if (hists__new_col_len(hists, HISTC_COMM, len))
112 hists__set_col_len(hists, HISTC_THREAD, len + 8);
113
114 if (h->ms.map) {
115 len = dso__name_len(map__dso(h->ms.map));
116 hists__new_col_len(hists, HISTC_DSO, len);
117 }
118
119 if (h->parent)
120 hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
121
122 if (h->branch_info) {
123 if (h->branch_info->from.ms.sym) {
124 symlen = (int)h->branch_info->from.ms.sym->namelen + 4;
125 if (verbose > 0)
126 symlen += BITS_PER_LONG / 4 + 2 + 3;
127 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
128
129 symlen = dso__name_len(map__dso(h->branch_info->from.ms.map));
130 hists__new_col_len(hists, HISTC_DSO_FROM, symlen);
131 } else {
132 symlen = unresolved_col_width + 4 + 2;
133 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
134 hists__new_col_len(hists, HISTC_ADDR_FROM, symlen);
135 hists__set_unres_dso_col_len(hists, HISTC_DSO_FROM);
136 }
137
138 if (h->branch_info->to.ms.sym) {
139 symlen = (int)h->branch_info->to.ms.sym->namelen + 4;
140 if (verbose > 0)
141 symlen += BITS_PER_LONG / 4 + 2 + 3;
142 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
143
144 symlen = dso__name_len(map__dso(h->branch_info->to.ms.map));
145 hists__new_col_len(hists, HISTC_DSO_TO, symlen);
146 } else {
147 symlen = unresolved_col_width + 4 + 2;
148 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
149 hists__new_col_len(hists, HISTC_ADDR_TO, symlen);
150 hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
151 }
152
153 if (h->branch_info->srcline_from)
154 hists__new_col_len(hists, HISTC_SRCLINE_FROM,
155 strlen(h->branch_info->srcline_from));
156 if (h->branch_info->srcline_to)
157 hists__new_col_len(hists, HISTC_SRCLINE_TO,
158 strlen(h->branch_info->srcline_to));
159 }
160
161 if (h->mem_info) {
162 if (mem_info__daddr(h->mem_info)->ms.sym) {
163 symlen = (int)mem_info__daddr(h->mem_info)->ms.sym->namelen + 4
164 + unresolved_col_width + 2;
165 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
166 symlen);
167 hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
168 symlen + 1);
169 } else {
170 symlen = unresolved_col_width + 4 + 2;
171 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
172 symlen);
173 hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
174 symlen);
175 }
176
177 if (mem_info__iaddr(h->mem_info)->ms.sym) {
178 symlen = (int)mem_info__iaddr(h->mem_info)->ms.sym->namelen + 4
179 + unresolved_col_width + 2;
180 hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL,
181 symlen);
182 } else {
183 symlen = unresolved_col_width + 4 + 2;
184 hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL,
185 symlen);
186 }
187
188 if (mem_info__daddr(h->mem_info)->ms.map) {
189 symlen = dso__name_len(map__dso(mem_info__daddr(h->mem_info)->ms.map));
190 hists__new_col_len(hists, HISTC_MEM_DADDR_DSO,
191 symlen);
192 } else {
193 symlen = unresolved_col_width + 4 + 2;
194 hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
195 }
196
197 hists__new_col_len(hists, HISTC_MEM_PHYS_DADDR,
198 unresolved_col_width + 4 + 2);
199
200 hists__new_col_len(hists, HISTC_MEM_DATA_PAGE_SIZE,
201 unresolved_col_width + 4 + 2);
202
203 } else {
204 symlen = unresolved_col_width + 4 + 2;
205 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen);
206 hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL, symlen);
207 hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
208 }
209
210 hists__new_col_len(hists, HISTC_CGROUP, 6);
211 hists__new_col_len(hists, HISTC_CGROUP_ID, 20);
212 hists__new_col_len(hists, HISTC_PARALLELISM, 11);
213 hists__new_col_len(hists, HISTC_CPU, 3);
214 hists__new_col_len(hists, HISTC_SOCKET, 6);
215 hists__new_col_len(hists, HISTC_MEM_LOCKED, 6);
216 hists__new_col_len(hists, HISTC_MEM_TLB, 22);
217 hists__new_col_len(hists, HISTC_MEM_SNOOP, 12);
218 hists__new_col_len(hists, HISTC_MEM_LVL, 36 + 3);
219 hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12);
220 hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12);
221 hists__new_col_len(hists, HISTC_MEM_BLOCKED, 10);
222 hists__new_col_len(hists, HISTC_LOCAL_INS_LAT, 13);
223 hists__new_col_len(hists, HISTC_GLOBAL_INS_LAT, 13);
224 hists__new_col_len(hists, HISTC_LOCAL_P_STAGE_CYC, 13);
225 hists__new_col_len(hists, HISTC_GLOBAL_P_STAGE_CYC, 13);
226 hists__new_col_len(hists, HISTC_ADDR, BITS_PER_LONG / 4 + 2);
227 hists__new_col_len(hists, HISTC_CALLCHAIN_BRANCH_PREDICTED, 9);
228 hists__new_col_len(hists, HISTC_CALLCHAIN_BRANCH_ABORT, 5);
229 hists__new_col_len(hists, HISTC_CALLCHAIN_BRANCH_CYCLES, 6);
230
231 if (symbol_conf.nanosecs)
232 hists__new_col_len(hists, HISTC_TIME, 16);
233 else
234 hists__new_col_len(hists, HISTC_TIME, 12);
235 hists__new_col_len(hists, HISTC_CODE_PAGE_SIZE, 6);
236
237 if (h->srcline) {
238 len = MAX(strlen(h->srcline), strlen(sort_srcline.se_header));
239 hists__new_col_len(hists, HISTC_SRCLINE, len);
240 }
241
242 if (h->srcfile)
243 hists__new_col_len(hists, HISTC_SRCFILE, strlen(h->srcfile));
244
245 if (h->transaction)
246 hists__new_col_len(hists, HISTC_TRANSACTION,
247 hist_entry__transaction_len());
248
249 if (h->trace_output)
250 hists__new_col_len(hists, HISTC_TRACE, strlen(h->trace_output));
251
252 if (h->cgroup) {
253 const char *cgrp_name = "unknown";
254 struct cgroup *cgrp = cgroup__find(maps__machine(h->ms.maps)->env,
255 h->cgroup);
256 if (cgrp != NULL)
257 cgrp_name = cgrp->name;
258
259 hists__new_col_len(hists, HISTC_CGROUP, strlen(cgrp_name));
260 }
261 }
262
hists__output_recalc_col_len(struct hists * hists,int max_rows)263 void hists__output_recalc_col_len(struct hists *hists, int max_rows)
264 {
265 struct rb_node *next = rb_first_cached(&hists->entries);
266 struct hist_entry *n;
267 int row = 0;
268
269 hists__reset_col_len(hists);
270
271 while (next && row++ < max_rows) {
272 n = rb_entry(next, struct hist_entry, rb_node);
273 if (!n->filtered)
274 hists__calc_col_len(hists, n);
275 next = rb_next(&n->rb_node);
276 }
277 }
278
he_stat__add_cpumode_period(struct he_stat * he_stat,unsigned int cpumode,u64 period)279 static void he_stat__add_cpumode_period(struct he_stat *he_stat,
280 unsigned int cpumode, u64 period)
281 {
282 switch (cpumode) {
283 case PERF_RECORD_MISC_KERNEL:
284 he_stat->period_sys += period;
285 break;
286 case PERF_RECORD_MISC_USER:
287 he_stat->period_us += period;
288 break;
289 case PERF_RECORD_MISC_GUEST_KERNEL:
290 he_stat->period_guest_sys += period;
291 break;
292 case PERF_RECORD_MISC_GUEST_USER:
293 he_stat->period_guest_us += period;
294 break;
295 default:
296 break;
297 }
298 }
299
hist_time(unsigned long htime)300 static long hist_time(unsigned long htime)
301 {
302 unsigned long time_quantum = symbol_conf.time_quantum;
303 if (time_quantum)
304 return (htime / time_quantum) * time_quantum;
305 return htime;
306 }
307
he_stat__add_period(struct he_stat * he_stat,u64 period,u64 latency)308 static void he_stat__add_period(struct he_stat *he_stat, u64 period, u64 latency)
309 {
310 he_stat->period += period;
311 he_stat->latency += latency;
312 he_stat->nr_events += 1;
313 }
314
he_stat__add_stat(struct he_stat * dest,struct he_stat * src)315 static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
316 {
317 dest->period += src->period;
318 dest->period_sys += src->period_sys;
319 dest->period_us += src->period_us;
320 dest->period_guest_sys += src->period_guest_sys;
321 dest->period_guest_us += src->period_guest_us;
322 dest->weight1 += src->weight1;
323 dest->weight2 += src->weight2;
324 dest->weight3 += src->weight3;
325 dest->nr_events += src->nr_events;
326 dest->latency += src->latency;
327 }
328
he_stat__decay(struct he_stat * he_stat)329 static void he_stat__decay(struct he_stat *he_stat)
330 {
331 he_stat->period = (he_stat->period * 7) / 8;
332 he_stat->nr_events = (he_stat->nr_events * 7) / 8;
333 he_stat->weight1 = (he_stat->weight1 * 7) / 8;
334 he_stat->weight2 = (he_stat->weight2 * 7) / 8;
335 he_stat->weight3 = (he_stat->weight3 * 7) / 8;
336 he_stat->latency = (he_stat->latency * 7) / 8;
337 }
338
339 static void hists__delete_entry(struct hists *hists, struct hist_entry *he);
340
hists__decay_entry(struct hists * hists,struct hist_entry * he)341 static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
342 {
343 u64 prev_period = he->stat.period;
344 u64 prev_latency = he->stat.latency;
345
346 if (prev_period == 0)
347 return true;
348
349 he_stat__decay(&he->stat);
350 if (symbol_conf.cumulate_callchain)
351 he_stat__decay(he->stat_acc);
352 decay_callchain(he->callchain);
353
354 if (!he->depth) {
355 u64 period_diff = prev_period - he->stat.period;
356 u64 latency_diff = prev_latency - he->stat.latency;
357
358 hists->stats.total_period -= period_diff;
359 hists->stats.total_latency -= latency_diff;
360 if (!he->filtered) {
361 hists->stats.total_non_filtered_period -= period_diff;
362 hists->stats.total_non_filtered_latency -= latency_diff;
363 }
364 }
365
366 if (!he->leaf) {
367 struct hist_entry *child;
368 struct rb_node *node = rb_first_cached(&he->hroot_out);
369 while (node) {
370 child = rb_entry(node, struct hist_entry, rb_node);
371 node = rb_next(node);
372
373 if (hists__decay_entry(hists, child))
374 hists__delete_entry(hists, child);
375 }
376 }
377
378 return he->stat.period == 0 && he->stat.latency == 0;
379 }
380
hists__delete_entry(struct hists * hists,struct hist_entry * he)381 static void hists__delete_entry(struct hists *hists, struct hist_entry *he)
382 {
383 struct rb_root_cached *root_in;
384 struct rb_root_cached *root_out;
385
386 if (he->parent_he) {
387 root_in = &he->parent_he->hroot_in;
388 root_out = &he->parent_he->hroot_out;
389 } else {
390 if (hists__has(hists, need_collapse))
391 root_in = &hists->entries_collapsed;
392 else
393 root_in = hists->entries_in;
394 root_out = &hists->entries;
395 }
396
397 rb_erase_cached(&he->rb_node_in, root_in);
398 rb_erase_cached(&he->rb_node, root_out);
399
400 --hists->nr_entries;
401 if (!he->filtered)
402 --hists->nr_non_filtered_entries;
403
404 hist_entry__delete(he);
405 }
406
hists__decay_entries(struct hists * hists,bool zap_user,bool zap_kernel)407 void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
408 {
409 struct rb_node *next = rb_first_cached(&hists->entries);
410 struct hist_entry *n;
411
412 while (next) {
413 n = rb_entry(next, struct hist_entry, rb_node);
414 next = rb_next(&n->rb_node);
415 if (((zap_user && n->level == '.') ||
416 (zap_kernel && n->level != '.') ||
417 hists__decay_entry(hists, n))) {
418 hists__delete_entry(hists, n);
419 }
420 }
421 }
422
hists__delete_entries(struct hists * hists)423 void hists__delete_entries(struct hists *hists)
424 {
425 struct rb_node *next = rb_first_cached(&hists->entries);
426 struct hist_entry *n;
427
428 while (next) {
429 n = rb_entry(next, struct hist_entry, rb_node);
430 next = rb_next(&n->rb_node);
431
432 hists__delete_entry(hists, n);
433 }
434 }
435
hists__get_entry(struct hists * hists,int idx)436 struct hist_entry *hists__get_entry(struct hists *hists, int idx)
437 {
438 struct rb_node *next = rb_first_cached(&hists->entries);
439 struct hist_entry *n;
440 int i = 0;
441
442 while (next) {
443 n = rb_entry(next, struct hist_entry, rb_node);
444 if (i == idx)
445 return n;
446
447 next = rb_next(&n->rb_node);
448 i++;
449 }
450
451 return NULL;
452 }
453
454 /*
455 * histogram, sorted on item, collects periods
456 */
457
hist_entry__init(struct hist_entry * he,struct hist_entry * template,bool sample_self,size_t callchain_size)458 static int hist_entry__init(struct hist_entry *he,
459 struct hist_entry *template,
460 bool sample_self,
461 size_t callchain_size)
462 {
463 *he = *template;
464 he->callchain_size = callchain_size;
465
466 if (symbol_conf.cumulate_callchain) {
467 he->stat_acc = malloc(sizeof(he->stat));
468 if (he->stat_acc == NULL)
469 return -ENOMEM;
470 memcpy(he->stat_acc, &he->stat, sizeof(he->stat));
471 if (!sample_self)
472 memset(&he->stat, 0, sizeof(he->stat));
473 }
474
475 he->ms.maps = maps__get(he->ms.maps);
476 he->ms.map = map__get(he->ms.map);
477
478 if (he->branch_info) {
479 /*
480 * This branch info is (a part of) allocated from
481 * sample__resolve_bstack() and will be freed after
482 * adding new entries. So we need to save a copy.
483 */
484 he->branch_info = malloc(sizeof(*he->branch_info));
485 if (he->branch_info == NULL)
486 goto err;
487
488 memcpy(he->branch_info, template->branch_info,
489 sizeof(*he->branch_info));
490
491 he->branch_info->from.ms.maps = maps__get(he->branch_info->from.ms.maps);
492 he->branch_info->from.ms.map = map__get(he->branch_info->from.ms.map);
493 he->branch_info->to.ms.maps = maps__get(he->branch_info->to.ms.maps);
494 he->branch_info->to.ms.map = map__get(he->branch_info->to.ms.map);
495 }
496
497 if (he->mem_info) {
498 he->mem_info = mem_info__clone(template->mem_info);
499 if (he->mem_info == NULL)
500 goto err_infos;
501 }
502
503 if (hist_entry__has_callchains(he) && symbol_conf.use_callchain)
504 callchain_init(he->callchain);
505
506 if (he->raw_data) {
507 he->raw_data = memdup(he->raw_data, he->raw_size);
508 if (he->raw_data == NULL)
509 goto err_infos;
510 }
511
512 if (he->srcline && he->srcline != SRCLINE_UNKNOWN) {
513 he->srcline = strdup(he->srcline);
514 if (he->srcline == NULL)
515 goto err_rawdata;
516 }
517
518 if (symbol_conf.res_sample) {
519 he->res_samples = calloc(symbol_conf.res_sample,
520 sizeof(struct res_sample));
521 if (!he->res_samples)
522 goto err_srcline;
523 }
524
525 INIT_LIST_HEAD(&he->pairs.node);
526 he->thread = thread__get(he->thread);
527 he->hroot_in = RB_ROOT_CACHED;
528 he->hroot_out = RB_ROOT_CACHED;
529
530 if (!symbol_conf.report_hierarchy)
531 he->leaf = true;
532
533 return 0;
534
535 err_srcline:
536 zfree(&he->srcline);
537
538 err_rawdata:
539 zfree(&he->raw_data);
540
541 err_infos:
542 if (he->branch_info) {
543 map_symbol__exit(&he->branch_info->from.ms);
544 map_symbol__exit(&he->branch_info->to.ms);
545 zfree(&he->branch_info);
546 }
547 if (he->mem_info) {
548 map_symbol__exit(&mem_info__iaddr(he->mem_info)->ms);
549 map_symbol__exit(&mem_info__daddr(he->mem_info)->ms);
550 }
551 err:
552 map_symbol__exit(&he->ms);
553 zfree(&he->stat_acc);
554 return -ENOMEM;
555 }
556
hist_entry__zalloc(size_t size)557 static void *hist_entry__zalloc(size_t size)
558 {
559 return zalloc(size + sizeof(struct hist_entry));
560 }
561
hist_entry__free(void * ptr)562 static void hist_entry__free(void *ptr)
563 {
564 free(ptr);
565 }
566
567 static struct hist_entry_ops default_ops = {
568 .new = hist_entry__zalloc,
569 .free = hist_entry__free,
570 };
571
hist_entry__new(struct hist_entry * template,bool sample_self)572 static struct hist_entry *hist_entry__new(struct hist_entry *template,
573 bool sample_self)
574 {
575 struct hist_entry_ops *ops = template->ops;
576 size_t callchain_size = 0;
577 struct hist_entry *he;
578 int err = 0;
579
580 if (!ops)
581 ops = template->ops = &default_ops;
582
583 if (symbol_conf.use_callchain)
584 callchain_size = sizeof(struct callchain_root);
585
586 he = ops->new(callchain_size);
587 if (he) {
588 err = hist_entry__init(he, template, sample_self, callchain_size);
589 if (err) {
590 ops->free(he);
591 he = NULL;
592 }
593 }
594 return he;
595 }
596
symbol__parent_filter(const struct symbol * parent)597 static filter_mask_t symbol__parent_filter(const struct symbol *parent)
598 {
599 if (symbol_conf.exclude_other && parent == NULL)
600 return 1 << HIST_FILTER__PARENT;
601 return 0;
602 }
603
hist_entry__add_callchain_period(struct hist_entry * he,u64 period,u64 latency)604 static void hist_entry__add_callchain_period(struct hist_entry *he, u64 period, u64 latency)
605 {
606 if (!hist_entry__has_callchains(he) || !symbol_conf.use_callchain)
607 return;
608
609 he->hists->callchain_period += period;
610 he->hists->callchain_latency += latency;
611 if (!he->filtered) {
612 he->hists->callchain_non_filtered_period += period;
613 he->hists->callchain_non_filtered_latency += latency;
614 }
615 }
616
hists__findnew_entry(struct hists * hists,struct hist_entry * entry,const struct addr_location * al,bool sample_self)617 static struct hist_entry *hists__findnew_entry(struct hists *hists,
618 struct hist_entry *entry,
619 const struct addr_location *al,
620 bool sample_self)
621 {
622 struct rb_node **p;
623 struct rb_node *parent = NULL;
624 struct hist_entry *he;
625 int64_t cmp;
626 u64 period = entry->stat.period;
627 u64 latency = entry->stat.latency;
628 bool leftmost = true;
629
630 p = &hists->entries_in->rb_root.rb_node;
631
632 while (*p != NULL) {
633 parent = *p;
634 he = rb_entry(parent, struct hist_entry, rb_node_in);
635
636 /*
637 * Make sure that it receives arguments in a same order as
638 * hist_entry__collapse() so that we can use an appropriate
639 * function when searching an entry regardless which sort
640 * keys were used.
641 */
642 cmp = hist_entry__cmp(he, entry);
643 if (!cmp) {
644 if (sample_self) {
645 he_stat__add_stat(&he->stat, &entry->stat);
646 hist_entry__add_callchain_period(he, period, latency);
647 }
648 if (symbol_conf.cumulate_callchain)
649 he_stat__add_period(he->stat_acc, period, latency);
650
651 block_info__delete(entry->block_info);
652
653 kvm_info__zput(entry->kvm_info);
654
655 /* If the map of an existing hist_entry has
656 * become out-of-date due to an exec() or
657 * similar, update it. Otherwise we will
658 * mis-adjust symbol addresses when computing
659 * the history counter to increment.
660 */
661 if (hists__has(hists, sym) && he->ms.map != entry->ms.map) {
662 if (he->ms.sym) {
663 u64 addr = he->ms.sym->start;
664 he->ms.sym = map__find_symbol(entry->ms.map, addr);
665 }
666
667 map__put(he->ms.map);
668 he->ms.map = map__get(entry->ms.map);
669 }
670 goto out;
671 }
672
673 if (cmp < 0)
674 p = &(*p)->rb_left;
675 else {
676 p = &(*p)->rb_right;
677 leftmost = false;
678 }
679 }
680
681 he = hist_entry__new(entry, sample_self);
682 if (!he)
683 return NULL;
684
685 if (sample_self)
686 hist_entry__add_callchain_period(he, period, latency);
687 hists->nr_entries++;
688
689 rb_link_node(&he->rb_node_in, parent, p);
690 rb_insert_color_cached(&he->rb_node_in, hists->entries_in, leftmost);
691 out:
692 if (sample_self)
693 he_stat__add_cpumode_period(&he->stat, al->cpumode, period);
694 if (symbol_conf.cumulate_callchain)
695 he_stat__add_cpumode_period(he->stat_acc, al->cpumode, period);
696 return he;
697 }
698
random_max(unsigned high)699 static unsigned random_max(unsigned high)
700 {
701 unsigned thresh = -high % high;
702 for (;;) {
703 unsigned r = random();
704 if (r >= thresh)
705 return r % high;
706 }
707 }
708
hists__res_sample(struct hist_entry * he,struct perf_sample * sample)709 static void hists__res_sample(struct hist_entry *he, struct perf_sample *sample)
710 {
711 struct res_sample *r;
712 int j;
713
714 if (he->num_res < symbol_conf.res_sample) {
715 j = he->num_res++;
716 } else {
717 j = random_max(symbol_conf.res_sample);
718 }
719 r = &he->res_samples[j];
720 r->time = sample->time;
721 r->cpu = sample->cpu;
722 r->tid = sample->tid;
723 }
724
725 static struct hist_entry*
__hists__add_entry(struct hists * hists,struct addr_location * al,struct symbol * sym_parent,struct branch_info * bi,struct mem_info * mi,struct kvm_info * ki,struct block_info * block_info,struct perf_sample * sample,bool sample_self,struct hist_entry_ops * ops)726 __hists__add_entry(struct hists *hists,
727 struct addr_location *al,
728 struct symbol *sym_parent,
729 struct branch_info *bi,
730 struct mem_info *mi,
731 struct kvm_info *ki,
732 struct block_info *block_info,
733 struct perf_sample *sample,
734 bool sample_self,
735 struct hist_entry_ops *ops)
736 {
737 struct namespaces *ns = thread__namespaces(al->thread);
738 struct hist_entry entry = {
739 .thread = al->thread,
740 .comm = thread__comm(al->thread),
741 .cgroup_id = {
742 .dev = ns ? ns->link_info[CGROUP_NS_INDEX].dev : 0,
743 .ino = ns ? ns->link_info[CGROUP_NS_INDEX].ino : 0,
744 },
745 .cgroup = sample->cgroup,
746 .ms = {
747 .maps = al->maps,
748 .map = al->map,
749 .sym = al->sym,
750 },
751 .srcline = (char *) al->srcline,
752 .socket = al->socket,
753 .cpu = al->cpu,
754 .cpumode = al->cpumode,
755 .ip = al->addr,
756 .level = al->level,
757 .code_page_size = sample->code_page_size,
758 .parallelism = al->parallelism,
759 .stat = {
760 .nr_events = 1,
761 .period = sample->period,
762 .weight1 = sample->weight,
763 .weight2 = sample->ins_lat,
764 .weight3 = sample->p_stage_cyc,
765 .latency = al->latency,
766 },
767 .parent = sym_parent,
768 .filtered = symbol__parent_filter(sym_parent) | al->filtered,
769 .hists = hists,
770 .branch_info = bi,
771 .mem_info = mi,
772 .kvm_info = ki,
773 .block_info = block_info,
774 .transaction = sample->transaction,
775 .raw_data = sample->raw_data,
776 .raw_size = sample->raw_size,
777 .ops = ops,
778 .time = hist_time(sample->time),
779 .weight = sample->weight,
780 .ins_lat = sample->ins_lat,
781 .p_stage_cyc = sample->p_stage_cyc,
782 .simd_flags = sample->simd_flags,
783 }, *he = hists__findnew_entry(hists, &entry, al, sample_self);
784
785 if (!hists->has_callchains && he && he->callchain_size != 0)
786 hists->has_callchains = true;
787 if (he && symbol_conf.res_sample)
788 hists__res_sample(he, sample);
789 return he;
790 }
791
hists__add_entry(struct hists * hists,struct addr_location * al,struct symbol * sym_parent,struct branch_info * bi,struct mem_info * mi,struct kvm_info * ki,struct perf_sample * sample,bool sample_self)792 struct hist_entry *hists__add_entry(struct hists *hists,
793 struct addr_location *al,
794 struct symbol *sym_parent,
795 struct branch_info *bi,
796 struct mem_info *mi,
797 struct kvm_info *ki,
798 struct perf_sample *sample,
799 bool sample_self)
800 {
801 return __hists__add_entry(hists, al, sym_parent, bi, mi, ki, NULL,
802 sample, sample_self, NULL);
803 }
804
hists__add_entry_ops(struct hists * hists,struct hist_entry_ops * ops,struct addr_location * al,struct symbol * sym_parent,struct branch_info * bi,struct mem_info * mi,struct kvm_info * ki,struct perf_sample * sample,bool sample_self)805 struct hist_entry *hists__add_entry_ops(struct hists *hists,
806 struct hist_entry_ops *ops,
807 struct addr_location *al,
808 struct symbol *sym_parent,
809 struct branch_info *bi,
810 struct mem_info *mi,
811 struct kvm_info *ki,
812 struct perf_sample *sample,
813 bool sample_self)
814 {
815 return __hists__add_entry(hists, al, sym_parent, bi, mi, ki, NULL,
816 sample, sample_self, ops);
817 }
818
hists__add_entry_block(struct hists * hists,struct addr_location * al,struct block_info * block_info)819 struct hist_entry *hists__add_entry_block(struct hists *hists,
820 struct addr_location *al,
821 struct block_info *block_info)
822 {
823 struct hist_entry entry = {
824 .block_info = block_info,
825 .hists = hists,
826 .ms = {
827 .maps = al->maps,
828 .map = al->map,
829 .sym = al->sym,
830 },
831 }, *he = hists__findnew_entry(hists, &entry, al, false);
832
833 return he;
834 }
835
836 static int
iter_next_nop_entry(struct hist_entry_iter * iter __maybe_unused,struct addr_location * al __maybe_unused)837 iter_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
838 struct addr_location *al __maybe_unused)
839 {
840 return 0;
841 }
842
843 static int
iter_add_next_nop_entry(struct hist_entry_iter * iter __maybe_unused,struct addr_location * al __maybe_unused)844 iter_add_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
845 struct addr_location *al __maybe_unused)
846 {
847 return 0;
848 }
849
850 static int
iter_prepare_mem_entry(struct hist_entry_iter * iter,struct addr_location * al)851 iter_prepare_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
852 {
853 struct perf_sample *sample = iter->sample;
854 struct mem_info *mi;
855
856 mi = sample__resolve_mem(sample, al);
857 if (mi == NULL)
858 return -ENOMEM;
859
860 iter->mi = mi;
861 return 0;
862 }
863
864 static int
iter_add_single_mem_entry(struct hist_entry_iter * iter,struct addr_location * al)865 iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
866 {
867 u64 cost;
868 struct mem_info *mi = iter->mi;
869 struct hists *hists = evsel__hists(iter->evsel);
870 struct perf_sample *sample = iter->sample;
871 struct hist_entry *he;
872
873 if (mi == NULL)
874 return -EINVAL;
875
876 cost = sample->weight;
877 if (!cost)
878 cost = 1;
879
880 /*
881 * must pass period=weight in order to get the correct
882 * sorting from hists__collapse_resort() which is solely
883 * based on periods. We want sorting be done on nr_events * weight
884 * and this is indirectly achieved by passing period=weight here
885 * and the he_stat__add_period() function.
886 */
887 sample->period = cost;
888
889 he = hists__add_entry(hists, al, iter->parent, NULL, mi, NULL,
890 sample, true);
891 if (!he)
892 return -ENOMEM;
893
894 iter->he = he;
895 return 0;
896 }
897
898 static int
iter_finish_mem_entry(struct hist_entry_iter * iter,struct addr_location * al __maybe_unused)899 iter_finish_mem_entry(struct hist_entry_iter *iter,
900 struct addr_location *al __maybe_unused)
901 {
902 struct evsel *evsel = iter->evsel;
903 struct hists *hists = evsel__hists(evsel);
904 struct hist_entry *he = iter->he;
905 int err = -EINVAL;
906
907 if (he == NULL)
908 goto out;
909
910 hists__inc_nr_samples(hists, he->filtered);
911
912 err = hist_entry__append_callchain(he, iter->sample);
913
914 out:
915 mem_info__zput(iter->mi);
916
917 iter->he = NULL;
918 return err;
919 }
920
921 static int
iter_prepare_branch_entry(struct hist_entry_iter * iter,struct addr_location * al)922 iter_prepare_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
923 {
924 struct branch_info *bi;
925 struct perf_sample *sample = iter->sample;
926
927 bi = sample__resolve_bstack(sample, al);
928 if (!bi)
929 return -ENOMEM;
930
931 iter->curr = 0;
932 iter->total = sample->branch_stack->nr;
933
934 iter->bi = bi;
935 return 0;
936 }
937
938 static int
iter_add_single_branch_entry(struct hist_entry_iter * iter __maybe_unused,struct addr_location * al __maybe_unused)939 iter_add_single_branch_entry(struct hist_entry_iter *iter __maybe_unused,
940 struct addr_location *al __maybe_unused)
941 {
942 return 0;
943 }
944
945 static int
iter_next_branch_entry(struct hist_entry_iter * iter,struct addr_location * al)946 iter_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
947 {
948 struct branch_info *bi = iter->bi;
949 int i = iter->curr;
950
951 if (bi == NULL)
952 return 0;
953
954 if (iter->curr >= iter->total)
955 return 0;
956
957 maps__put(al->maps);
958 al->maps = maps__get(bi[i].to.ms.maps);
959 map__put(al->map);
960 al->map = map__get(bi[i].to.ms.map);
961 al->sym = bi[i].to.ms.sym;
962 al->addr = bi[i].to.addr;
963 return 1;
964 }
965
966 static int
iter_add_next_branch_entry(struct hist_entry_iter * iter,struct addr_location * al)967 iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
968 {
969 struct branch_info *bi;
970 struct evsel *evsel = iter->evsel;
971 struct hists *hists = evsel__hists(evsel);
972 struct perf_sample *sample = iter->sample;
973 struct hist_entry *he = NULL;
974 int i = iter->curr;
975 int err = 0;
976
977 bi = iter->bi;
978
979 if (iter->hide_unresolved && !(bi[i].from.ms.sym && bi[i].to.ms.sym))
980 goto out;
981
982 /*
983 * The report shows the percentage of total branches captured
984 * and not events sampled. Thus we use a pseudo period of 1.
985 */
986 sample->period = 1;
987 sample->weight = bi->flags.cycles ? bi->flags.cycles : 1;
988
989 he = hists__add_entry(hists, al, iter->parent, &bi[i], NULL, NULL,
990 sample, true);
991 if (he == NULL)
992 return -ENOMEM;
993
994 out:
995 iter->he = he;
996 iter->curr++;
997 return err;
998 }
999
branch_info__exit(struct branch_info * bi)1000 static void branch_info__exit(struct branch_info *bi)
1001 {
1002 map_symbol__exit(&bi->from.ms);
1003 map_symbol__exit(&bi->to.ms);
1004 zfree_srcline(&bi->srcline_from);
1005 zfree_srcline(&bi->srcline_to);
1006 }
1007
1008 static int
iter_finish_branch_entry(struct hist_entry_iter * iter,struct addr_location * al __maybe_unused)1009 iter_finish_branch_entry(struct hist_entry_iter *iter,
1010 struct addr_location *al __maybe_unused)
1011 {
1012 struct evsel *evsel = iter->evsel;
1013 struct hists *hists = evsel__hists(evsel);
1014
1015 for (int i = 0; i < iter->total; i++)
1016 branch_info__exit(&iter->bi[i]);
1017
1018 if (iter->he)
1019 hists__inc_nr_samples(hists, iter->he->filtered);
1020
1021 zfree(&iter->bi);
1022 iter->he = NULL;
1023
1024 return iter->curr >= iter->total ? 0 : -1;
1025 }
1026
1027 static int
iter_prepare_normal_entry(struct hist_entry_iter * iter __maybe_unused,struct addr_location * al __maybe_unused)1028 iter_prepare_normal_entry(struct hist_entry_iter *iter __maybe_unused,
1029 struct addr_location *al __maybe_unused)
1030 {
1031 return 0;
1032 }
1033
1034 static int
iter_add_single_normal_entry(struct hist_entry_iter * iter,struct addr_location * al)1035 iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location *al)
1036 {
1037 struct evsel *evsel = iter->evsel;
1038 struct perf_sample *sample = iter->sample;
1039 struct hist_entry *he;
1040
1041 he = hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
1042 NULL, sample, true);
1043 if (he == NULL)
1044 return -ENOMEM;
1045
1046 iter->he = he;
1047 return 0;
1048 }
1049
1050 static int
iter_finish_normal_entry(struct hist_entry_iter * iter,struct addr_location * al __maybe_unused)1051 iter_finish_normal_entry(struct hist_entry_iter *iter,
1052 struct addr_location *al __maybe_unused)
1053 {
1054 struct hist_entry *he = iter->he;
1055 struct evsel *evsel = iter->evsel;
1056 struct perf_sample *sample = iter->sample;
1057
1058 if (he == NULL)
1059 return 0;
1060
1061 iter->he = NULL;
1062
1063 hists__inc_nr_samples(evsel__hists(evsel), he->filtered);
1064
1065 return hist_entry__append_callchain(he, sample);
1066 }
1067
1068 static int
iter_prepare_cumulative_entry(struct hist_entry_iter * iter,struct addr_location * al __maybe_unused)1069 iter_prepare_cumulative_entry(struct hist_entry_iter *iter,
1070 struct addr_location *al __maybe_unused)
1071 {
1072 struct hist_entry **he_cache;
1073 struct callchain_cursor *cursor = get_tls_callchain_cursor();
1074
1075 if (cursor == NULL)
1076 return -ENOMEM;
1077
1078 callchain_cursor_commit(cursor);
1079
1080 /*
1081 * This is for detecting cycles or recursions so that they're
1082 * cumulated only one time to prevent entries more than 100%
1083 * overhead.
1084 */
1085 he_cache = malloc(sizeof(*he_cache) * (cursor->nr + 1));
1086 if (he_cache == NULL)
1087 return -ENOMEM;
1088
1089 iter->he_cache = he_cache;
1090 iter->curr = 0;
1091
1092 return 0;
1093 }
1094
1095 static int
iter_add_single_cumulative_entry(struct hist_entry_iter * iter,struct addr_location * al)1096 iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
1097 struct addr_location *al)
1098 {
1099 struct evsel *evsel = iter->evsel;
1100 struct hists *hists = evsel__hists(evsel);
1101 struct perf_sample *sample = iter->sample;
1102 struct hist_entry **he_cache = iter->he_cache;
1103 struct hist_entry *he;
1104 int err = 0;
1105
1106 he = hists__add_entry(hists, al, iter->parent, NULL, NULL, NULL,
1107 sample, true);
1108 if (he == NULL)
1109 return -ENOMEM;
1110
1111 iter->he = he;
1112 he_cache[iter->curr++] = he;
1113
1114 hist_entry__append_callchain(he, sample);
1115
1116 /*
1117 * We need to re-initialize the cursor since callchain_append()
1118 * advanced the cursor to the end.
1119 */
1120 callchain_cursor_commit(get_tls_callchain_cursor());
1121
1122 hists__inc_nr_samples(hists, he->filtered);
1123
1124 return err;
1125 }
1126
1127 static int
iter_next_cumulative_entry(struct hist_entry_iter * iter,struct addr_location * al)1128 iter_next_cumulative_entry(struct hist_entry_iter *iter,
1129 struct addr_location *al)
1130 {
1131 struct callchain_cursor_node *node;
1132
1133 node = callchain_cursor_current(get_tls_callchain_cursor());
1134 if (node == NULL)
1135 return 0;
1136
1137 return fill_callchain_info(al, node, iter->hide_unresolved);
1138 }
1139
1140 static bool
hist_entry__fast__sym_diff(struct hist_entry * left,struct hist_entry * right)1141 hist_entry__fast__sym_diff(struct hist_entry *left,
1142 struct hist_entry *right)
1143 {
1144 struct symbol *sym_l = left->ms.sym;
1145 struct symbol *sym_r = right->ms.sym;
1146
1147 if (!sym_l && !sym_r)
1148 return left->ip != right->ip;
1149
1150 return !!_sort__sym_cmp(sym_l, sym_r);
1151 }
1152
1153
1154 static int
iter_add_next_cumulative_entry(struct hist_entry_iter * iter,struct addr_location * al)1155 iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
1156 struct addr_location *al)
1157 {
1158 struct evsel *evsel = iter->evsel;
1159 struct perf_sample *sample = iter->sample;
1160 struct hist_entry **he_cache = iter->he_cache;
1161 struct hist_entry *he;
1162 struct hist_entry he_tmp = {
1163 .hists = evsel__hists(evsel),
1164 .cpu = al->cpu,
1165 .thread = al->thread,
1166 .comm = thread__comm(al->thread),
1167 .ip = al->addr,
1168 .ms = {
1169 .maps = al->maps,
1170 .map = al->map,
1171 .sym = al->sym,
1172 },
1173 .srcline = (char *) al->srcline,
1174 .parent = iter->parent,
1175 .raw_data = sample->raw_data,
1176 .raw_size = sample->raw_size,
1177 };
1178 int i;
1179 struct callchain_cursor cursor, *tls_cursor = get_tls_callchain_cursor();
1180 bool fast = hists__has(he_tmp.hists, sym);
1181
1182 if (tls_cursor == NULL)
1183 return -ENOMEM;
1184
1185 callchain_cursor_snapshot(&cursor, tls_cursor);
1186
1187 callchain_cursor_advance(tls_cursor);
1188
1189 /*
1190 * Check if there's duplicate entries in the callchain.
1191 * It's possible that it has cycles or recursive calls.
1192 */
1193 for (i = 0; i < iter->curr; i++) {
1194 /*
1195 * For most cases, there are no duplicate entries in callchain.
1196 * The symbols are usually different. Do a quick check for
1197 * symbols first.
1198 */
1199 if (fast && hist_entry__fast__sym_diff(he_cache[i], &he_tmp))
1200 continue;
1201
1202 if (hist_entry__cmp(he_cache[i], &he_tmp) == 0) {
1203 /* to avoid calling callback function */
1204 iter->he = NULL;
1205 return 0;
1206 }
1207 }
1208
1209 he = hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
1210 NULL, sample, false);
1211 if (he == NULL)
1212 return -ENOMEM;
1213
1214 iter->he = he;
1215 he_cache[iter->curr++] = he;
1216
1217 if (hist_entry__has_callchains(he) && symbol_conf.use_callchain)
1218 callchain_append(he->callchain, &cursor, sample->period);
1219 return 0;
1220 }
1221
1222 static int
iter_finish_cumulative_entry(struct hist_entry_iter * iter,struct addr_location * al __maybe_unused)1223 iter_finish_cumulative_entry(struct hist_entry_iter *iter,
1224 struct addr_location *al __maybe_unused)
1225 {
1226 mem_info__zput(iter->mi);
1227 zfree(&iter->bi);
1228 zfree(&iter->he_cache);
1229 iter->he = NULL;
1230
1231 return 0;
1232 }
1233
1234 const struct hist_iter_ops hist_iter_mem = {
1235 .prepare_entry = iter_prepare_mem_entry,
1236 .add_single_entry = iter_add_single_mem_entry,
1237 .next_entry = iter_next_nop_entry,
1238 .add_next_entry = iter_add_next_nop_entry,
1239 .finish_entry = iter_finish_mem_entry,
1240 };
1241
1242 const struct hist_iter_ops hist_iter_branch = {
1243 .prepare_entry = iter_prepare_branch_entry,
1244 .add_single_entry = iter_add_single_branch_entry,
1245 .next_entry = iter_next_branch_entry,
1246 .add_next_entry = iter_add_next_branch_entry,
1247 .finish_entry = iter_finish_branch_entry,
1248 };
1249
1250 const struct hist_iter_ops hist_iter_normal = {
1251 .prepare_entry = iter_prepare_normal_entry,
1252 .add_single_entry = iter_add_single_normal_entry,
1253 .next_entry = iter_next_nop_entry,
1254 .add_next_entry = iter_add_next_nop_entry,
1255 .finish_entry = iter_finish_normal_entry,
1256 };
1257
1258 const struct hist_iter_ops hist_iter_cumulative = {
1259 .prepare_entry = iter_prepare_cumulative_entry,
1260 .add_single_entry = iter_add_single_cumulative_entry,
1261 .next_entry = iter_next_cumulative_entry,
1262 .add_next_entry = iter_add_next_cumulative_entry,
1263 .finish_entry = iter_finish_cumulative_entry,
1264 };
1265
hist_entry_iter__add(struct hist_entry_iter * iter,struct addr_location * al,int max_stack_depth,void * arg)1266 int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
1267 int max_stack_depth, void *arg)
1268 {
1269 int err, err2;
1270 struct map *alm = NULL;
1271
1272 if (al)
1273 alm = map__get(al->map);
1274
1275 err = sample__resolve_callchain(iter->sample, get_tls_callchain_cursor(), &iter->parent,
1276 iter->evsel, al, max_stack_depth);
1277 if (err) {
1278 map__put(alm);
1279 return err;
1280 }
1281
1282 err = iter->ops->prepare_entry(iter, al);
1283 if (err)
1284 goto out;
1285
1286 err = iter->ops->add_single_entry(iter, al);
1287 if (err)
1288 goto out;
1289
1290 if (iter->he && iter->add_entry_cb) {
1291 err = iter->add_entry_cb(iter, al, true, arg);
1292 if (err)
1293 goto out;
1294 }
1295
1296 while (iter->ops->next_entry(iter, al)) {
1297 err = iter->ops->add_next_entry(iter, al);
1298 if (err)
1299 break;
1300
1301 if (iter->he && iter->add_entry_cb) {
1302 err = iter->add_entry_cb(iter, al, false, arg);
1303 if (err)
1304 goto out;
1305 }
1306 }
1307
1308 out:
1309 err2 = iter->ops->finish_entry(iter, al);
1310 if (!err)
1311 err = err2;
1312
1313 map__put(alm);
1314
1315 return err;
1316 }
1317
1318 static int64_t
hist_entry__cmp_impl(struct perf_hpp_list * hpp_list,struct hist_entry * left,struct hist_entry * right,unsigned long fn_offset,bool ignore_dynamic,bool ignore_skipped)1319 hist_entry__cmp_impl(struct perf_hpp_list *hpp_list, struct hist_entry *left,
1320 struct hist_entry *right, unsigned long fn_offset,
1321 bool ignore_dynamic, bool ignore_skipped)
1322 {
1323 struct hists *hists = left->hists;
1324 struct perf_hpp_fmt *fmt;
1325 perf_hpp_fmt_cmp_t *fn;
1326 int64_t cmp;
1327
1328 /*
1329 * Never collapse filtered and non-filtered entries.
1330 * Note this is not the same as having an extra (invisible) fmt
1331 * that corresponds to the filtered status.
1332 */
1333 cmp = (int64_t)!!left->filtered - (int64_t)!!right->filtered;
1334 if (cmp)
1335 return cmp;
1336
1337 perf_hpp_list__for_each_sort_list(hpp_list, fmt) {
1338 if (ignore_dynamic && perf_hpp__is_dynamic_entry(fmt) &&
1339 !perf_hpp__defined_dynamic_entry(fmt, hists))
1340 continue;
1341
1342 if (ignore_skipped && perf_hpp__should_skip(fmt, hists))
1343 continue;
1344
1345 fn = (void *)fmt + fn_offset;
1346 cmp = (*fn)(fmt, left, right);
1347 if (cmp)
1348 break;
1349 }
1350
1351 return cmp;
1352 }
1353
1354 int64_t
hist_entry__cmp(struct hist_entry * left,struct hist_entry * right)1355 hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
1356 {
1357 return hist_entry__cmp_impl(left->hists->hpp_list, left, right,
1358 offsetof(struct perf_hpp_fmt, cmp), true, false);
1359 }
1360
1361 static int64_t
hist_entry__sort(struct hist_entry * left,struct hist_entry * right)1362 hist_entry__sort(struct hist_entry *left, struct hist_entry *right)
1363 {
1364 return hist_entry__cmp_impl(left->hists->hpp_list, left, right,
1365 offsetof(struct perf_hpp_fmt, sort), false, true);
1366 }
1367
1368 int64_t
hist_entry__collapse(struct hist_entry * left,struct hist_entry * right)1369 hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
1370 {
1371 return hist_entry__cmp_impl(left->hists->hpp_list, left, right,
1372 offsetof(struct perf_hpp_fmt, collapse), true, false);
1373 }
1374
1375 static int64_t
hist_entry__collapse_hierarchy(struct perf_hpp_list * hpp_list,struct hist_entry * left,struct hist_entry * right)1376 hist_entry__collapse_hierarchy(struct perf_hpp_list *hpp_list,
1377 struct hist_entry *left,
1378 struct hist_entry *right)
1379 {
1380 return hist_entry__cmp_impl(hpp_list, left, right,
1381 offsetof(struct perf_hpp_fmt, collapse), false, false);
1382 }
1383
hist_entry__delete(struct hist_entry * he)1384 void hist_entry__delete(struct hist_entry *he)
1385 {
1386 struct hist_entry_ops *ops = he->ops;
1387
1388 if (symbol_conf.report_hierarchy) {
1389 struct rb_root *root = &he->hroot_out.rb_root;
1390 struct hist_entry *child, *tmp;
1391
1392 rbtree_postorder_for_each_entry_safe(child, tmp, root, rb_node)
1393 hist_entry__delete(child);
1394
1395 *root = RB_ROOT;
1396 }
1397
1398 thread__zput(he->thread);
1399 map_symbol__exit(&he->ms);
1400
1401 if (he->branch_info) {
1402 branch_info__exit(he->branch_info);
1403 zfree(&he->branch_info);
1404 }
1405
1406 if (he->mem_info) {
1407 map_symbol__exit(&mem_info__iaddr(he->mem_info)->ms);
1408 map_symbol__exit(&mem_info__daddr(he->mem_info)->ms);
1409 mem_info__zput(he->mem_info);
1410 }
1411
1412 if (he->block_info)
1413 block_info__delete(he->block_info);
1414
1415 if (he->kvm_info)
1416 kvm_info__zput(he->kvm_info);
1417
1418 zfree(&he->res_samples);
1419 zfree(&he->stat_acc);
1420 zfree_srcline(&he->srcline);
1421 if (he->srcfile && he->srcfile[0])
1422 zfree(&he->srcfile);
1423 free_callchain(he->callchain);
1424 zfree(&he->trace_output);
1425 zfree(&he->raw_data);
1426 ops->free(he);
1427 }
1428
1429 /*
1430 * If this is not the last column, then we need to pad it according to the
1431 * pre-calculated max length for this column, otherwise don't bother adding
1432 * spaces because that would break viewing this with, for instance, 'less',
1433 * that would show tons of trailing spaces when a long C++ demangled method
1434 * names is sampled.
1435 */
hist_entry__snprintf_alignment(struct hist_entry * he,struct perf_hpp * hpp,struct perf_hpp_fmt * fmt,int printed)1436 int hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp,
1437 struct perf_hpp_fmt *fmt, int printed)
1438 {
1439 if (!list_is_last(&fmt->list, &he->hists->hpp_list->fields)) {
1440 const int width = fmt->width(fmt, hpp, he->hists);
1441 if (printed < width) {
1442 advance_hpp(hpp, printed);
1443 printed = scnprintf(hpp->buf, hpp->size, "%-*s", width - printed, " ");
1444 }
1445 }
1446
1447 return printed;
1448 }
1449
1450 /*
1451 * collapse the histogram
1452 */
1453
1454 static void hists__apply_filters(struct hists *hists, struct hist_entry *he);
1455 static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *he,
1456 enum hist_filter type);
1457
1458 typedef bool (*fmt_chk_fn)(struct perf_hpp_fmt *fmt);
1459
check_thread_entry(struct perf_hpp_fmt * fmt)1460 static bool check_thread_entry(struct perf_hpp_fmt *fmt)
1461 {
1462 return perf_hpp__is_thread_entry(fmt) || perf_hpp__is_comm_entry(fmt);
1463 }
1464
hist_entry__check_and_remove_filter(struct hist_entry * he,enum hist_filter type,fmt_chk_fn check)1465 static void hist_entry__check_and_remove_filter(struct hist_entry *he,
1466 enum hist_filter type,
1467 fmt_chk_fn check)
1468 {
1469 struct perf_hpp_fmt *fmt;
1470 bool type_match = false;
1471 struct hist_entry *parent = he->parent_he;
1472
1473 switch (type) {
1474 case HIST_FILTER__THREAD:
1475 if (symbol_conf.comm_list == NULL &&
1476 symbol_conf.pid_list == NULL &&
1477 symbol_conf.tid_list == NULL)
1478 return;
1479 break;
1480 case HIST_FILTER__DSO:
1481 if (symbol_conf.dso_list == NULL)
1482 return;
1483 break;
1484 case HIST_FILTER__SYMBOL:
1485 if (symbol_conf.sym_list == NULL)
1486 return;
1487 break;
1488 case HIST_FILTER__PARALLELISM:
1489 if (__bitmap_weight(symbol_conf.parallelism_filter, MAX_NR_CPUS + 1) == 0)
1490 return;
1491 break;
1492 case HIST_FILTER__PARENT:
1493 case HIST_FILTER__GUEST:
1494 case HIST_FILTER__HOST:
1495 case HIST_FILTER__SOCKET:
1496 case HIST_FILTER__C2C:
1497 default:
1498 return;
1499 }
1500
1501 /* if it's filtered by own fmt, it has to have filter bits */
1502 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1503 if (check(fmt)) {
1504 type_match = true;
1505 break;
1506 }
1507 }
1508
1509 if (type_match) {
1510 /*
1511 * If the filter is for current level entry, propagate
1512 * filter marker to parents. The marker bit was
1513 * already set by default so it only needs to clear
1514 * non-filtered entries.
1515 */
1516 if (!(he->filtered & (1 << type))) {
1517 while (parent) {
1518 parent->filtered &= ~(1 << type);
1519 parent = parent->parent_he;
1520 }
1521 }
1522 } else {
1523 /*
1524 * If current entry doesn't have matching formats, set
1525 * filter marker for upper level entries. it will be
1526 * cleared if its lower level entries is not filtered.
1527 *
1528 * For lower-level entries, it inherits parent's
1529 * filter bit so that lower level entries of a
1530 * non-filtered entry won't set the filter marker.
1531 */
1532 if (parent == NULL)
1533 he->filtered |= (1 << type);
1534 else
1535 he->filtered |= (parent->filtered & (1 << type));
1536 }
1537 }
1538
hist_entry__apply_hierarchy_filters(struct hist_entry * he)1539 static void hist_entry__apply_hierarchy_filters(struct hist_entry *he)
1540 {
1541 hist_entry__check_and_remove_filter(he, HIST_FILTER__THREAD,
1542 check_thread_entry);
1543
1544 hist_entry__check_and_remove_filter(he, HIST_FILTER__DSO,
1545 perf_hpp__is_dso_entry);
1546
1547 hist_entry__check_and_remove_filter(he, HIST_FILTER__SYMBOL,
1548 perf_hpp__is_sym_entry);
1549
1550 hist_entry__check_and_remove_filter(he, HIST_FILTER__PARALLELISM,
1551 perf_hpp__is_parallelism_entry);
1552
1553 hists__apply_filters(he->hists, he);
1554 }
1555
hierarchy_insert_entry(struct hists * hists,struct rb_root_cached * root,struct hist_entry * he,struct hist_entry * parent_he,struct perf_hpp_list * hpp_list)1556 static struct hist_entry *hierarchy_insert_entry(struct hists *hists,
1557 struct rb_root_cached *root,
1558 struct hist_entry *he,
1559 struct hist_entry *parent_he,
1560 struct perf_hpp_list *hpp_list)
1561 {
1562 struct rb_node **p = &root->rb_root.rb_node;
1563 struct rb_node *parent = NULL;
1564 struct hist_entry *iter, *new;
1565 struct perf_hpp_fmt *fmt;
1566 int64_t cmp;
1567 bool leftmost = true;
1568
1569 while (*p != NULL) {
1570 parent = *p;
1571 iter = rb_entry(parent, struct hist_entry, rb_node_in);
1572 cmp = hist_entry__collapse_hierarchy(hpp_list, iter, he);
1573 if (!cmp) {
1574 he_stat__add_stat(&iter->stat, &he->stat);
1575 return iter;
1576 }
1577
1578 if (cmp < 0)
1579 p = &parent->rb_left;
1580 else {
1581 p = &parent->rb_right;
1582 leftmost = false;
1583 }
1584 }
1585
1586 new = hist_entry__new(he, true);
1587 if (new == NULL)
1588 return NULL;
1589
1590 hists->nr_entries++;
1591
1592 /* save related format list for output */
1593 new->hpp_list = hpp_list;
1594 new->parent_he = parent_he;
1595
1596 hist_entry__apply_hierarchy_filters(new);
1597
1598 /* some fields are now passed to 'new' */
1599 perf_hpp_list__for_each_sort_list(hpp_list, fmt) {
1600 if (perf_hpp__is_trace_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
1601 he->trace_output = NULL;
1602 else
1603 new->trace_output = NULL;
1604
1605 if (perf_hpp__is_srcline_entry(fmt))
1606 he->srcline = NULL;
1607 else
1608 new->srcline = NULL;
1609
1610 if (perf_hpp__is_srcfile_entry(fmt))
1611 he->srcfile = NULL;
1612 else
1613 new->srcfile = NULL;
1614 }
1615
1616 rb_link_node(&new->rb_node_in, parent, p);
1617 rb_insert_color_cached(&new->rb_node_in, root, leftmost);
1618 return new;
1619 }
1620
hists__hierarchy_insert_entry(struct hists * hists,struct rb_root_cached * root,struct hist_entry * he)1621 static int hists__hierarchy_insert_entry(struct hists *hists,
1622 struct rb_root_cached *root,
1623 struct hist_entry *he)
1624 {
1625 struct perf_hpp_list_node *node;
1626 struct hist_entry *new_he = NULL;
1627 struct hist_entry *parent = NULL;
1628 int depth = 0;
1629 int ret = 0;
1630
1631 list_for_each_entry(node, &hists->hpp_formats, list) {
1632 /* skip period (overhead) and elided columns */
1633 if (node->level == 0 || node->skip)
1634 continue;
1635
1636 /* insert copy of 'he' for each fmt into the hierarchy */
1637 new_he = hierarchy_insert_entry(hists, root, he, parent, &node->hpp);
1638 if (new_he == NULL) {
1639 ret = -1;
1640 break;
1641 }
1642
1643 root = &new_he->hroot_in;
1644 new_he->depth = depth++;
1645 parent = new_he;
1646 }
1647
1648 if (new_he) {
1649 new_he->leaf = true;
1650
1651 if (hist_entry__has_callchains(new_he) &&
1652 symbol_conf.use_callchain) {
1653 struct callchain_cursor *cursor = get_tls_callchain_cursor();
1654
1655 if (cursor == NULL)
1656 return -1;
1657
1658 callchain_cursor_reset(cursor);
1659 if (callchain_merge(cursor,
1660 new_he->callchain,
1661 he->callchain) < 0)
1662 ret = -1;
1663 }
1664 }
1665
1666 /* 'he' is no longer used */
1667 hist_entry__delete(he);
1668
1669 /* return 0 (or -1) since it already applied filters */
1670 return ret;
1671 }
1672
hists__collapse_insert_entry(struct hists * hists,struct rb_root_cached * root,struct hist_entry * he)1673 static int hists__collapse_insert_entry(struct hists *hists,
1674 struct rb_root_cached *root,
1675 struct hist_entry *he)
1676 {
1677 struct rb_node **p = &root->rb_root.rb_node;
1678 struct rb_node *parent = NULL;
1679 struct hist_entry *iter;
1680 int64_t cmp;
1681 bool leftmost = true;
1682
1683 if (symbol_conf.report_hierarchy)
1684 return hists__hierarchy_insert_entry(hists, root, he);
1685
1686 while (*p != NULL) {
1687 parent = *p;
1688 iter = rb_entry(parent, struct hist_entry, rb_node_in);
1689
1690 cmp = hist_entry__collapse(iter, he);
1691
1692 if (!cmp) {
1693 int ret = 0;
1694
1695 he_stat__add_stat(&iter->stat, &he->stat);
1696 if (symbol_conf.cumulate_callchain)
1697 he_stat__add_stat(iter->stat_acc, he->stat_acc);
1698
1699 if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
1700 struct callchain_cursor *cursor = get_tls_callchain_cursor();
1701
1702 if (cursor != NULL) {
1703 callchain_cursor_reset(cursor);
1704 if (callchain_merge(cursor, iter->callchain, he->callchain) < 0)
1705 ret = -1;
1706 } else {
1707 ret = 0;
1708 }
1709 }
1710 hist_entry__delete(he);
1711 return ret;
1712 }
1713
1714 if (cmp < 0)
1715 p = &(*p)->rb_left;
1716 else {
1717 p = &(*p)->rb_right;
1718 leftmost = false;
1719 }
1720 }
1721 hists->nr_entries++;
1722
1723 rb_link_node(&he->rb_node_in, parent, p);
1724 rb_insert_color_cached(&he->rb_node_in, root, leftmost);
1725 return 1;
1726 }
1727
hists__get_rotate_entries_in(struct hists * hists)1728 struct rb_root_cached *hists__get_rotate_entries_in(struct hists *hists)
1729 {
1730 struct rb_root_cached *root;
1731
1732 mutex_lock(&hists->lock);
1733
1734 root = hists->entries_in;
1735 if (++hists->entries_in > &hists->entries_in_array[1])
1736 hists->entries_in = &hists->entries_in_array[0];
1737
1738 mutex_unlock(&hists->lock);
1739
1740 return root;
1741 }
1742
hists__apply_filters(struct hists * hists,struct hist_entry * he)1743 static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
1744 {
1745 hists__filter_entry_by_dso(hists, he);
1746 hists__filter_entry_by_thread(hists, he);
1747 hists__filter_entry_by_symbol(hists, he);
1748 hists__filter_entry_by_socket(hists, he);
1749 hists__filter_entry_by_parallelism(hists, he);
1750 }
1751
hists__collapse_resort(struct hists * hists,struct ui_progress * prog)1752 int hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
1753 {
1754 struct rb_root_cached *root;
1755 struct rb_node *next;
1756 struct hist_entry *n;
1757 int ret;
1758
1759 if (!hists__has(hists, need_collapse))
1760 return 0;
1761
1762 hists->nr_entries = 0;
1763
1764 root = hists__get_rotate_entries_in(hists);
1765
1766 next = rb_first_cached(root);
1767
1768 while (next) {
1769 if (session_done())
1770 break;
1771 n = rb_entry(next, struct hist_entry, rb_node_in);
1772 next = rb_next(&n->rb_node_in);
1773
1774 rb_erase_cached(&n->rb_node_in, root);
1775 ret = hists__collapse_insert_entry(hists, &hists->entries_collapsed, n);
1776 if (ret < 0)
1777 return -1;
1778
1779 if (ret) {
1780 /*
1781 * If it wasn't combined with one of the entries already
1782 * collapsed, we need to apply the filters that may have
1783 * been set by, say, the hist_browser.
1784 */
1785 hists__apply_filters(hists, n);
1786 }
1787 if (prog)
1788 ui_progress__update(prog, 1);
1789 }
1790 return 0;
1791 }
1792
hists__reset_filter_stats(struct hists * hists)1793 static void hists__reset_filter_stats(struct hists *hists)
1794 {
1795 hists->nr_non_filtered_entries = 0;
1796 hists->stats.total_non_filtered_period = 0;
1797 hists->stats.total_non_filtered_latency = 0;
1798 }
1799
hists__reset_stats(struct hists * hists)1800 void hists__reset_stats(struct hists *hists)
1801 {
1802 hists->nr_entries = 0;
1803 hists->stats.total_period = 0;
1804 hists->stats.total_latency = 0;
1805
1806 hists__reset_filter_stats(hists);
1807 }
1808
hists__inc_filter_stats(struct hists * hists,struct hist_entry * h)1809 static void hists__inc_filter_stats(struct hists *hists, struct hist_entry *h)
1810 {
1811 hists->nr_non_filtered_entries++;
1812 hists->stats.total_non_filtered_period += h->stat.period;
1813 hists->stats.total_non_filtered_latency += h->stat.latency;
1814 }
1815
hists__inc_stats(struct hists * hists,struct hist_entry * h)1816 void hists__inc_stats(struct hists *hists, struct hist_entry *h)
1817 {
1818 if (!h->filtered)
1819 hists__inc_filter_stats(hists, h);
1820
1821 hists->nr_entries++;
1822 hists->stats.total_period += h->stat.period;
1823 hists->stats.total_latency += h->stat.latency;
1824 }
1825
hierarchy_recalc_total_periods(struct hists * hists)1826 static void hierarchy_recalc_total_periods(struct hists *hists)
1827 {
1828 struct rb_node *node;
1829 struct hist_entry *he;
1830
1831 node = rb_first_cached(&hists->entries);
1832
1833 hists->stats.total_period = 0;
1834 hists->stats.total_non_filtered_period = 0;
1835 hists->stats.total_latency = 0;
1836 hists->stats.total_non_filtered_latency = 0;
1837
1838 /*
1839 * recalculate total period using top-level entries only
1840 * since lower level entries only see non-filtered entries
1841 * but upper level entries have sum of both entries.
1842 */
1843 while (node) {
1844 he = rb_entry(node, struct hist_entry, rb_node);
1845 node = rb_next(node);
1846
1847 hists->stats.total_period += he->stat.period;
1848 hists->stats.total_latency += he->stat.latency;
1849 if (!he->filtered) {
1850 hists->stats.total_non_filtered_period += he->stat.period;
1851 hists->stats.total_non_filtered_latency += he->stat.latency;
1852 }
1853 }
1854 }
1855
hierarchy_insert_output_entry(struct rb_root_cached * root,struct hist_entry * he)1856 static void hierarchy_insert_output_entry(struct rb_root_cached *root,
1857 struct hist_entry *he)
1858 {
1859 struct rb_node **p = &root->rb_root.rb_node;
1860 struct rb_node *parent = NULL;
1861 struct hist_entry *iter;
1862 struct perf_hpp_fmt *fmt;
1863 bool leftmost = true;
1864
1865 while (*p != NULL) {
1866 parent = *p;
1867 iter = rb_entry(parent, struct hist_entry, rb_node);
1868
1869 if (hist_entry__sort(he, iter) > 0)
1870 p = &parent->rb_left;
1871 else {
1872 p = &parent->rb_right;
1873 leftmost = false;
1874 }
1875 }
1876
1877 rb_link_node(&he->rb_node, parent, p);
1878 rb_insert_color_cached(&he->rb_node, root, leftmost);
1879
1880 /* update column width of dynamic entry */
1881 perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) {
1882 if (fmt->init)
1883 fmt->init(fmt, he);
1884 }
1885 }
1886
hists__hierarchy_output_resort(struct hists * hists,struct ui_progress * prog,struct rb_root_cached * root_in,struct rb_root_cached * root_out,u64 min_callchain_hits,bool use_callchain)1887 static void hists__hierarchy_output_resort(struct hists *hists,
1888 struct ui_progress *prog,
1889 struct rb_root_cached *root_in,
1890 struct rb_root_cached *root_out,
1891 u64 min_callchain_hits,
1892 bool use_callchain)
1893 {
1894 struct rb_node *node;
1895 struct hist_entry *he;
1896
1897 *root_out = RB_ROOT_CACHED;
1898 node = rb_first_cached(root_in);
1899
1900 while (node) {
1901 he = rb_entry(node, struct hist_entry, rb_node_in);
1902 node = rb_next(node);
1903
1904 hierarchy_insert_output_entry(root_out, he);
1905
1906 if (prog)
1907 ui_progress__update(prog, 1);
1908
1909 hists->nr_entries++;
1910 if (!he->filtered) {
1911 hists->nr_non_filtered_entries++;
1912 hists__calc_col_len(hists, he);
1913 }
1914
1915 if (!he->leaf) {
1916 hists__hierarchy_output_resort(hists, prog,
1917 &he->hroot_in,
1918 &he->hroot_out,
1919 min_callchain_hits,
1920 use_callchain);
1921 continue;
1922 }
1923
1924 if (!use_callchain)
1925 continue;
1926
1927 if (callchain_param.mode == CHAIN_GRAPH_REL) {
1928 u64 total = he->stat.period;
1929
1930 if (symbol_conf.cumulate_callchain)
1931 total = he->stat_acc->period;
1932
1933 min_callchain_hits = total * (callchain_param.min_percent / 100);
1934 }
1935
1936 callchain_param.sort(&he->sorted_chain, he->callchain,
1937 min_callchain_hits, &callchain_param);
1938 }
1939 }
1940
__hists__insert_output_entry(struct rb_root_cached * entries,struct hist_entry * he,u64 min_callchain_hits,bool use_callchain)1941 static void __hists__insert_output_entry(struct rb_root_cached *entries,
1942 struct hist_entry *he,
1943 u64 min_callchain_hits,
1944 bool use_callchain)
1945 {
1946 struct rb_node **p = &entries->rb_root.rb_node;
1947 struct rb_node *parent = NULL;
1948 struct hist_entry *iter;
1949 struct perf_hpp_fmt *fmt;
1950 bool leftmost = true;
1951
1952 if (use_callchain) {
1953 if (callchain_param.mode == CHAIN_GRAPH_REL) {
1954 u64 total = he->stat.period;
1955
1956 if (symbol_conf.cumulate_callchain)
1957 total = he->stat_acc->period;
1958
1959 min_callchain_hits = total * (callchain_param.min_percent / 100);
1960 }
1961 callchain_param.sort(&he->sorted_chain, he->callchain,
1962 min_callchain_hits, &callchain_param);
1963 }
1964
1965 while (*p != NULL) {
1966 parent = *p;
1967 iter = rb_entry(parent, struct hist_entry, rb_node);
1968
1969 if (hist_entry__sort(he, iter) > 0)
1970 p = &(*p)->rb_left;
1971 else {
1972 p = &(*p)->rb_right;
1973 leftmost = false;
1974 }
1975 }
1976
1977 rb_link_node(&he->rb_node, parent, p);
1978 rb_insert_color_cached(&he->rb_node, entries, leftmost);
1979
1980 /* update column width of dynamic entries */
1981 perf_hpp_list__for_each_sort_list(&perf_hpp_list, fmt) {
1982 if (fmt->init)
1983 fmt->init(fmt, he);
1984 }
1985 }
1986
output_resort(struct hists * hists,struct ui_progress * prog,bool use_callchain,hists__resort_cb_t cb,void * cb_arg)1987 static void output_resort(struct hists *hists, struct ui_progress *prog,
1988 bool use_callchain, hists__resort_cb_t cb,
1989 void *cb_arg)
1990 {
1991 struct rb_root_cached *root;
1992 struct rb_node *next;
1993 struct hist_entry *n;
1994 u64 callchain_total;
1995 u64 min_callchain_hits;
1996
1997 callchain_total = hists->callchain_period;
1998 if (symbol_conf.filter_relative)
1999 callchain_total = hists->callchain_non_filtered_period;
2000
2001 min_callchain_hits = callchain_total * (callchain_param.min_percent / 100);
2002
2003 hists__reset_stats(hists);
2004 hists__reset_col_len(hists);
2005
2006 if (symbol_conf.report_hierarchy) {
2007 hists__hierarchy_output_resort(hists, prog,
2008 &hists->entries_collapsed,
2009 &hists->entries,
2010 min_callchain_hits,
2011 use_callchain);
2012 hierarchy_recalc_total_periods(hists);
2013 return;
2014 }
2015
2016 if (hists__has(hists, need_collapse))
2017 root = &hists->entries_collapsed;
2018 else
2019 root = hists->entries_in;
2020
2021 next = rb_first_cached(root);
2022 hists->entries = RB_ROOT_CACHED;
2023
2024 while (next) {
2025 n = rb_entry(next, struct hist_entry, rb_node_in);
2026 next = rb_next(&n->rb_node_in);
2027
2028 if (cb && cb(n, cb_arg))
2029 continue;
2030
2031 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits, use_callchain);
2032 hists__inc_stats(hists, n);
2033
2034 if (!n->filtered)
2035 hists__calc_col_len(hists, n);
2036
2037 if (prog)
2038 ui_progress__update(prog, 1);
2039 }
2040 }
2041
evsel__output_resort_cb(struct evsel * evsel,struct ui_progress * prog,hists__resort_cb_t cb,void * cb_arg)2042 void evsel__output_resort_cb(struct evsel *evsel, struct ui_progress *prog,
2043 hists__resort_cb_t cb, void *cb_arg)
2044 {
2045 bool use_callchain;
2046
2047 if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph)
2048 use_callchain = evsel__has_callchain(evsel);
2049 else
2050 use_callchain = symbol_conf.use_callchain;
2051
2052 use_callchain |= symbol_conf.show_branchflag_count;
2053
2054 output_resort(evsel__hists(evsel), prog, use_callchain, cb, cb_arg);
2055 }
2056
evsel__output_resort(struct evsel * evsel,struct ui_progress * prog)2057 void evsel__output_resort(struct evsel *evsel, struct ui_progress *prog)
2058 {
2059 return evsel__output_resort_cb(evsel, prog, NULL, NULL);
2060 }
2061
hists__output_resort(struct hists * hists,struct ui_progress * prog)2062 void hists__output_resort(struct hists *hists, struct ui_progress *prog)
2063 {
2064 output_resort(hists, prog, symbol_conf.use_callchain, NULL, NULL);
2065 }
2066
hists__output_resort_cb(struct hists * hists,struct ui_progress * prog,hists__resort_cb_t cb)2067 void hists__output_resort_cb(struct hists *hists, struct ui_progress *prog,
2068 hists__resort_cb_t cb)
2069 {
2070 output_resort(hists, prog, symbol_conf.use_callchain, cb, NULL);
2071 }
2072
can_goto_child(struct hist_entry * he,enum hierarchy_move_dir hmd)2073 static bool can_goto_child(struct hist_entry *he, enum hierarchy_move_dir hmd)
2074 {
2075 if (he->leaf || hmd == HMD_FORCE_SIBLING)
2076 return false;
2077
2078 if (he->unfolded || hmd == HMD_FORCE_CHILD)
2079 return true;
2080
2081 return false;
2082 }
2083
rb_hierarchy_last(struct rb_node * node)2084 struct rb_node *rb_hierarchy_last(struct rb_node *node)
2085 {
2086 struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
2087
2088 while (can_goto_child(he, HMD_NORMAL)) {
2089 node = rb_last(&he->hroot_out.rb_root);
2090 he = rb_entry(node, struct hist_entry, rb_node);
2091 }
2092 return node;
2093 }
2094
__rb_hierarchy_next(struct rb_node * node,enum hierarchy_move_dir hmd)2095 struct rb_node *__rb_hierarchy_next(struct rb_node *node, enum hierarchy_move_dir hmd)
2096 {
2097 struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
2098
2099 if (can_goto_child(he, hmd))
2100 node = rb_first_cached(&he->hroot_out);
2101 else
2102 node = rb_next(node);
2103
2104 while (node == NULL) {
2105 he = he->parent_he;
2106 if (he == NULL)
2107 break;
2108
2109 node = rb_next(&he->rb_node);
2110 }
2111 return node;
2112 }
2113
rb_hierarchy_prev(struct rb_node * node)2114 struct rb_node *rb_hierarchy_prev(struct rb_node *node)
2115 {
2116 struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
2117
2118 node = rb_prev(node);
2119 if (node)
2120 return rb_hierarchy_last(node);
2121
2122 he = he->parent_he;
2123 if (he == NULL)
2124 return NULL;
2125
2126 return &he->rb_node;
2127 }
2128
hist_entry__has_hierarchy_children(struct hist_entry * he,float limit)2129 bool hist_entry__has_hierarchy_children(struct hist_entry *he, float limit)
2130 {
2131 struct rb_node *node;
2132 struct hist_entry *child;
2133 float percent;
2134
2135 if (he->leaf)
2136 return false;
2137
2138 node = rb_first_cached(&he->hroot_out);
2139 child = rb_entry(node, struct hist_entry, rb_node);
2140
2141 while (node && child->filtered) {
2142 node = rb_next(node);
2143 child = rb_entry(node, struct hist_entry, rb_node);
2144 }
2145
2146 if (node)
2147 percent = hist_entry__get_percent_limit(child);
2148 else
2149 percent = 0;
2150
2151 return node && percent >= limit;
2152 }
2153
hists__remove_entry_filter(struct hists * hists,struct hist_entry * h,enum hist_filter filter)2154 static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
2155 enum hist_filter filter)
2156 {
2157 h->filtered &= ~(1 << filter);
2158
2159 if (symbol_conf.report_hierarchy) {
2160 struct hist_entry *parent = h->parent_he;
2161
2162 while (parent) {
2163 he_stat__add_stat(&parent->stat, &h->stat);
2164
2165 parent->filtered &= ~(1 << filter);
2166
2167 if (parent->filtered)
2168 goto next;
2169
2170 /* force fold unfiltered entry for simplicity */
2171 parent->unfolded = false;
2172 parent->has_no_entry = false;
2173 parent->row_offset = 0;
2174 parent->nr_rows = 0;
2175 next:
2176 parent = parent->parent_he;
2177 }
2178 }
2179
2180 if (h->filtered)
2181 return;
2182
2183 /* force fold unfiltered entry for simplicity */
2184 h->unfolded = false;
2185 h->has_no_entry = false;
2186 h->row_offset = 0;
2187 h->nr_rows = 0;
2188
2189 hists->stats.nr_non_filtered_samples += h->stat.nr_events;
2190
2191 hists__inc_filter_stats(hists, h);
2192 hists__calc_col_len(hists, h);
2193 }
2194
2195
hists__filter_entry_by_dso(struct hists * hists,struct hist_entry * he)2196 static bool hists__filter_entry_by_dso(struct hists *hists,
2197 struct hist_entry *he)
2198 {
2199 if (hists->dso_filter != NULL &&
2200 (he->ms.map == NULL || !RC_CHK_EQUAL(map__dso(he->ms.map), hists->dso_filter))) {
2201 he->filtered |= (1 << HIST_FILTER__DSO);
2202 return true;
2203 }
2204
2205 return false;
2206 }
2207
hists__filter_entry_by_thread(struct hists * hists,struct hist_entry * he)2208 static bool hists__filter_entry_by_thread(struct hists *hists,
2209 struct hist_entry *he)
2210 {
2211 if (hists->thread_filter != NULL &&
2212 !RC_CHK_EQUAL(he->thread, hists->thread_filter)) {
2213 he->filtered |= (1 << HIST_FILTER__THREAD);
2214 return true;
2215 }
2216
2217 return false;
2218 }
2219
hists__filter_entry_by_symbol(struct hists * hists,struct hist_entry * he)2220 static bool hists__filter_entry_by_symbol(struct hists *hists,
2221 struct hist_entry *he)
2222 {
2223 if (hists->symbol_filter_str != NULL &&
2224 (!he->ms.sym || strstr(he->ms.sym->name,
2225 hists->symbol_filter_str) == NULL)) {
2226 he->filtered |= (1 << HIST_FILTER__SYMBOL);
2227 return true;
2228 }
2229
2230 return false;
2231 }
2232
hists__filter_entry_by_socket(struct hists * hists,struct hist_entry * he)2233 static bool hists__filter_entry_by_socket(struct hists *hists,
2234 struct hist_entry *he)
2235 {
2236 if ((hists->socket_filter > -1) &&
2237 (he->socket != hists->socket_filter)) {
2238 he->filtered |= (1 << HIST_FILTER__SOCKET);
2239 return true;
2240 }
2241
2242 return false;
2243 }
2244
hists__filter_entry_by_parallelism(struct hists * hists,struct hist_entry * he)2245 static bool hists__filter_entry_by_parallelism(struct hists *hists,
2246 struct hist_entry *he)
2247 {
2248 if (test_bit(he->parallelism, hists->parallelism_filter)) {
2249 he->filtered |= (1 << HIST_FILTER__PARALLELISM);
2250 return true;
2251 }
2252 return false;
2253 }
2254
2255 typedef bool (*filter_fn_t)(struct hists *hists, struct hist_entry *he);
2256
hists__filter_by_type(struct hists * hists,int type,filter_fn_t filter)2257 static void hists__filter_by_type(struct hists *hists, int type, filter_fn_t filter)
2258 {
2259 struct rb_node *nd;
2260
2261 hists->stats.nr_non_filtered_samples = 0;
2262
2263 hists__reset_filter_stats(hists);
2264 hists__reset_col_len(hists);
2265
2266 for (nd = rb_first_cached(&hists->entries); nd; nd = rb_next(nd)) {
2267 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2268
2269 if (filter(hists, h))
2270 continue;
2271
2272 hists__remove_entry_filter(hists, h, type);
2273 }
2274 }
2275
resort_filtered_entry(struct rb_root_cached * root,struct hist_entry * he)2276 static void resort_filtered_entry(struct rb_root_cached *root,
2277 struct hist_entry *he)
2278 {
2279 struct rb_node **p = &root->rb_root.rb_node;
2280 struct rb_node *parent = NULL;
2281 struct hist_entry *iter;
2282 struct rb_root_cached new_root = RB_ROOT_CACHED;
2283 struct rb_node *nd;
2284 bool leftmost = true;
2285
2286 while (*p != NULL) {
2287 parent = *p;
2288 iter = rb_entry(parent, struct hist_entry, rb_node);
2289
2290 if (hist_entry__sort(he, iter) > 0)
2291 p = &(*p)->rb_left;
2292 else {
2293 p = &(*p)->rb_right;
2294 leftmost = false;
2295 }
2296 }
2297
2298 rb_link_node(&he->rb_node, parent, p);
2299 rb_insert_color_cached(&he->rb_node, root, leftmost);
2300
2301 if (he->leaf || he->filtered)
2302 return;
2303
2304 nd = rb_first_cached(&he->hroot_out);
2305 while (nd) {
2306 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2307
2308 nd = rb_next(nd);
2309 rb_erase_cached(&h->rb_node, &he->hroot_out);
2310
2311 resort_filtered_entry(&new_root, h);
2312 }
2313
2314 he->hroot_out = new_root;
2315 }
2316
hists__filter_hierarchy(struct hists * hists,int type,const void * arg)2317 static void hists__filter_hierarchy(struct hists *hists, int type, const void *arg)
2318 {
2319 struct rb_node *nd;
2320 struct rb_root_cached new_root = RB_ROOT_CACHED;
2321
2322 hists->stats.nr_non_filtered_samples = 0;
2323
2324 hists__reset_filter_stats(hists);
2325 hists__reset_col_len(hists);
2326
2327 nd = rb_first_cached(&hists->entries);
2328 while (nd) {
2329 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2330 int ret;
2331
2332 ret = hist_entry__filter(h, type, arg);
2333
2334 /*
2335 * case 1. non-matching type
2336 * zero out the period, set filter marker and move to child
2337 */
2338 if (ret < 0) {
2339 memset(&h->stat, 0, sizeof(h->stat));
2340 h->filtered |= (1 << type);
2341
2342 nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_CHILD);
2343 }
2344 /*
2345 * case 2. matched type (filter out)
2346 * set filter marker and move to next
2347 */
2348 else if (ret == 1) {
2349 h->filtered |= (1 << type);
2350
2351 nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_SIBLING);
2352 }
2353 /*
2354 * case 3. ok (not filtered)
2355 * add period to hists and parents, erase the filter marker
2356 * and move to next sibling
2357 */
2358 else {
2359 hists__remove_entry_filter(hists, h, type);
2360
2361 nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_SIBLING);
2362 }
2363 }
2364
2365 hierarchy_recalc_total_periods(hists);
2366
2367 /*
2368 * resort output after applying a new filter since filter in a lower
2369 * hierarchy can change periods in a upper hierarchy.
2370 */
2371 nd = rb_first_cached(&hists->entries);
2372 while (nd) {
2373 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
2374
2375 nd = rb_next(nd);
2376 rb_erase_cached(&h->rb_node, &hists->entries);
2377
2378 resort_filtered_entry(&new_root, h);
2379 }
2380
2381 hists->entries = new_root;
2382 }
2383
hists__filter_by_thread(struct hists * hists)2384 void hists__filter_by_thread(struct hists *hists)
2385 {
2386 if (symbol_conf.report_hierarchy)
2387 hists__filter_hierarchy(hists, HIST_FILTER__THREAD,
2388 hists->thread_filter);
2389 else
2390 hists__filter_by_type(hists, HIST_FILTER__THREAD,
2391 hists__filter_entry_by_thread);
2392 }
2393
hists__filter_by_dso(struct hists * hists)2394 void hists__filter_by_dso(struct hists *hists)
2395 {
2396 if (symbol_conf.report_hierarchy)
2397 hists__filter_hierarchy(hists, HIST_FILTER__DSO,
2398 hists->dso_filter);
2399 else
2400 hists__filter_by_type(hists, HIST_FILTER__DSO,
2401 hists__filter_entry_by_dso);
2402 }
2403
hists__filter_by_symbol(struct hists * hists)2404 void hists__filter_by_symbol(struct hists *hists)
2405 {
2406 if (symbol_conf.report_hierarchy)
2407 hists__filter_hierarchy(hists, HIST_FILTER__SYMBOL,
2408 hists->symbol_filter_str);
2409 else
2410 hists__filter_by_type(hists, HIST_FILTER__SYMBOL,
2411 hists__filter_entry_by_symbol);
2412 }
2413
hists__filter_by_socket(struct hists * hists)2414 void hists__filter_by_socket(struct hists *hists)
2415 {
2416 if (symbol_conf.report_hierarchy)
2417 hists__filter_hierarchy(hists, HIST_FILTER__SOCKET,
2418 &hists->socket_filter);
2419 else
2420 hists__filter_by_type(hists, HIST_FILTER__SOCKET,
2421 hists__filter_entry_by_socket);
2422 }
2423
hists__filter_by_parallelism(struct hists * hists)2424 void hists__filter_by_parallelism(struct hists *hists)
2425 {
2426 if (symbol_conf.report_hierarchy)
2427 hists__filter_hierarchy(hists, HIST_FILTER__PARALLELISM,
2428 hists->parallelism_filter);
2429 else
2430 hists__filter_by_type(hists, HIST_FILTER__PARALLELISM,
2431 hists__filter_entry_by_parallelism);
2432 }
2433
events_stats__inc(struct events_stats * stats,u32 type)2434 void events_stats__inc(struct events_stats *stats, u32 type)
2435 {
2436 ++stats->nr_events[0];
2437 ++stats->nr_events[type];
2438 }
2439
hists_stats__inc(struct hists_stats * stats)2440 static void hists_stats__inc(struct hists_stats *stats)
2441 {
2442 ++stats->nr_samples;
2443 }
2444
hists__inc_nr_events(struct hists * hists)2445 void hists__inc_nr_events(struct hists *hists)
2446 {
2447 hists_stats__inc(&hists->stats);
2448 }
2449
hists__inc_nr_samples(struct hists * hists,bool filtered)2450 void hists__inc_nr_samples(struct hists *hists, bool filtered)
2451 {
2452 hists_stats__inc(&hists->stats);
2453 if (!filtered)
2454 hists->stats.nr_non_filtered_samples++;
2455 }
2456
hists__inc_nr_lost_samples(struct hists * hists,u32 lost)2457 void hists__inc_nr_lost_samples(struct hists *hists, u32 lost)
2458 {
2459 hists->stats.nr_lost_samples += lost;
2460 }
2461
hists__inc_nr_dropped_samples(struct hists * hists,u32 lost)2462 void hists__inc_nr_dropped_samples(struct hists *hists, u32 lost)
2463 {
2464 hists->stats.nr_dropped_samples += lost;
2465 }
2466
hists__add_dummy_entry(struct hists * hists,struct hist_entry * pair)2467 static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
2468 struct hist_entry *pair)
2469 {
2470 struct rb_root_cached *root;
2471 struct rb_node **p;
2472 struct rb_node *parent = NULL;
2473 struct hist_entry *he;
2474 int64_t cmp;
2475 bool leftmost = true;
2476
2477 if (hists__has(hists, need_collapse))
2478 root = &hists->entries_collapsed;
2479 else
2480 root = hists->entries_in;
2481
2482 p = &root->rb_root.rb_node;
2483
2484 while (*p != NULL) {
2485 parent = *p;
2486 he = rb_entry(parent, struct hist_entry, rb_node_in);
2487
2488 cmp = hist_entry__collapse(he, pair);
2489
2490 if (!cmp)
2491 goto out;
2492
2493 if (cmp < 0)
2494 p = &(*p)->rb_left;
2495 else {
2496 p = &(*p)->rb_right;
2497 leftmost = false;
2498 }
2499 }
2500
2501 he = hist_entry__new(pair, true);
2502 if (he) {
2503 memset(&he->stat, 0, sizeof(he->stat));
2504 he->hists = hists;
2505 if (symbol_conf.cumulate_callchain)
2506 memset(he->stat_acc, 0, sizeof(he->stat));
2507 rb_link_node(&he->rb_node_in, parent, p);
2508 rb_insert_color_cached(&he->rb_node_in, root, leftmost);
2509 hists__inc_stats(hists, he);
2510 he->dummy = true;
2511 }
2512 out:
2513 return he;
2514 }
2515
add_dummy_hierarchy_entry(struct hists * hists,struct rb_root_cached * root,struct hist_entry * pair)2516 static struct hist_entry *add_dummy_hierarchy_entry(struct hists *hists,
2517 struct rb_root_cached *root,
2518 struct hist_entry *pair)
2519 {
2520 struct rb_node **p;
2521 struct rb_node *parent = NULL;
2522 struct hist_entry *he;
2523 bool leftmost = true;
2524
2525 p = &root->rb_root.rb_node;
2526 while (*p != NULL) {
2527 int64_t cmp;
2528
2529 parent = *p;
2530 he = rb_entry(parent, struct hist_entry, rb_node_in);
2531 cmp = hist_entry__collapse_hierarchy(he->hpp_list, he, pair);
2532 if (!cmp)
2533 goto out;
2534
2535 if (cmp < 0)
2536 p = &parent->rb_left;
2537 else {
2538 p = &parent->rb_right;
2539 leftmost = false;
2540 }
2541 }
2542
2543 he = hist_entry__new(pair, true);
2544 if (he) {
2545 rb_link_node(&he->rb_node_in, parent, p);
2546 rb_insert_color_cached(&he->rb_node_in, root, leftmost);
2547
2548 he->dummy = true;
2549 he->hists = hists;
2550 memset(&he->stat, 0, sizeof(he->stat));
2551 hists__inc_stats(hists, he);
2552 }
2553 out:
2554 return he;
2555 }
2556
hists__find_entry(struct hists * hists,struct hist_entry * he)2557 static struct hist_entry *hists__find_entry(struct hists *hists,
2558 struct hist_entry *he)
2559 {
2560 struct rb_node *n;
2561
2562 if (hists__has(hists, need_collapse))
2563 n = hists->entries_collapsed.rb_root.rb_node;
2564 else
2565 n = hists->entries_in->rb_root.rb_node;
2566
2567 while (n) {
2568 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node_in);
2569 int64_t cmp = hist_entry__collapse(iter, he);
2570
2571 if (cmp < 0)
2572 n = n->rb_left;
2573 else if (cmp > 0)
2574 n = n->rb_right;
2575 else
2576 return iter;
2577 }
2578
2579 return NULL;
2580 }
2581
hists__find_hierarchy_entry(struct rb_root_cached * root,struct hist_entry * he)2582 static struct hist_entry *hists__find_hierarchy_entry(struct rb_root_cached *root,
2583 struct hist_entry *he)
2584 {
2585 struct rb_node *n = root->rb_root.rb_node;
2586
2587 while (n) {
2588 struct hist_entry *iter;
2589 int64_t cmp;
2590
2591 iter = rb_entry(n, struct hist_entry, rb_node_in);
2592 cmp = hist_entry__collapse_hierarchy(he->hpp_list, iter, he);
2593 if (cmp < 0)
2594 n = n->rb_left;
2595 else if (cmp > 0)
2596 n = n->rb_right;
2597 else
2598 return iter;
2599 }
2600
2601 return NULL;
2602 }
2603
hists__match_hierarchy(struct rb_root_cached * leader_root,struct rb_root_cached * other_root)2604 static void hists__match_hierarchy(struct rb_root_cached *leader_root,
2605 struct rb_root_cached *other_root)
2606 {
2607 struct rb_node *nd;
2608 struct hist_entry *pos, *pair;
2609
2610 for (nd = rb_first_cached(leader_root); nd; nd = rb_next(nd)) {
2611 pos = rb_entry(nd, struct hist_entry, rb_node_in);
2612 pair = hists__find_hierarchy_entry(other_root, pos);
2613
2614 if (pair) {
2615 hist_entry__add_pair(pair, pos);
2616 hists__match_hierarchy(&pos->hroot_in, &pair->hroot_in);
2617 }
2618 }
2619 }
2620
2621 /*
2622 * Look for pairs to link to the leader buckets (hist_entries):
2623 */
hists__match(struct hists * leader,struct hists * other)2624 void hists__match(struct hists *leader, struct hists *other)
2625 {
2626 struct rb_root_cached *root;
2627 struct rb_node *nd;
2628 struct hist_entry *pos, *pair;
2629
2630 if (symbol_conf.report_hierarchy) {
2631 /* hierarchy report always collapses entries */
2632 return hists__match_hierarchy(&leader->entries_collapsed,
2633 &other->entries_collapsed);
2634 }
2635
2636 if (hists__has(leader, need_collapse))
2637 root = &leader->entries_collapsed;
2638 else
2639 root = leader->entries_in;
2640
2641 for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) {
2642 pos = rb_entry(nd, struct hist_entry, rb_node_in);
2643 pair = hists__find_entry(other, pos);
2644
2645 if (pair)
2646 hist_entry__add_pair(pair, pos);
2647 }
2648 }
2649
hists__link_hierarchy(struct hists * leader_hists,struct hist_entry * parent,struct rb_root_cached * leader_root,struct rb_root_cached * other_root)2650 static int hists__link_hierarchy(struct hists *leader_hists,
2651 struct hist_entry *parent,
2652 struct rb_root_cached *leader_root,
2653 struct rb_root_cached *other_root)
2654 {
2655 struct rb_node *nd;
2656 struct hist_entry *pos, *leader;
2657
2658 for (nd = rb_first_cached(other_root); nd; nd = rb_next(nd)) {
2659 pos = rb_entry(nd, struct hist_entry, rb_node_in);
2660
2661 if (hist_entry__has_pairs(pos)) {
2662 bool found = false;
2663
2664 list_for_each_entry(leader, &pos->pairs.head, pairs.node) {
2665 if (leader->hists == leader_hists) {
2666 found = true;
2667 break;
2668 }
2669 }
2670 if (!found)
2671 return -1;
2672 } else {
2673 leader = add_dummy_hierarchy_entry(leader_hists,
2674 leader_root, pos);
2675 if (leader == NULL)
2676 return -1;
2677
2678 /* do not point parent in the pos */
2679 leader->parent_he = parent;
2680
2681 hist_entry__add_pair(pos, leader);
2682 }
2683
2684 if (!pos->leaf) {
2685 if (hists__link_hierarchy(leader_hists, leader,
2686 &leader->hroot_in,
2687 &pos->hroot_in) < 0)
2688 return -1;
2689 }
2690 }
2691 return 0;
2692 }
2693
2694 /*
2695 * Look for entries in the other hists that are not present in the leader, if
2696 * we find them, just add a dummy entry on the leader hists, with period=0,
2697 * nr_events=0, to serve as the list header.
2698 */
hists__link(struct hists * leader,struct hists * other)2699 int hists__link(struct hists *leader, struct hists *other)
2700 {
2701 struct rb_root_cached *root;
2702 struct rb_node *nd;
2703 struct hist_entry *pos, *pair;
2704
2705 if (symbol_conf.report_hierarchy) {
2706 /* hierarchy report always collapses entries */
2707 return hists__link_hierarchy(leader, NULL,
2708 &leader->entries_collapsed,
2709 &other->entries_collapsed);
2710 }
2711
2712 if (hists__has(other, need_collapse))
2713 root = &other->entries_collapsed;
2714 else
2715 root = other->entries_in;
2716
2717 for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) {
2718 pos = rb_entry(nd, struct hist_entry, rb_node_in);
2719
2720 if (!hist_entry__has_pairs(pos)) {
2721 pair = hists__add_dummy_entry(leader, pos);
2722 if (pair == NULL)
2723 return -1;
2724 hist_entry__add_pair(pos, pair);
2725 }
2726 }
2727
2728 return 0;
2729 }
2730
hists__unlink(struct hists * hists)2731 int hists__unlink(struct hists *hists)
2732 {
2733 struct rb_root_cached *root;
2734 struct rb_node *nd;
2735 struct hist_entry *pos;
2736
2737 if (hists__has(hists, need_collapse))
2738 root = &hists->entries_collapsed;
2739 else
2740 root = hists->entries_in;
2741
2742 for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) {
2743 pos = rb_entry(nd, struct hist_entry, rb_node_in);
2744 list_del_init(&pos->pairs.node);
2745 }
2746
2747 return 0;
2748 }
2749
hist__account_cycles(struct branch_stack * bs,struct addr_location * al,struct perf_sample * sample,bool nonany_branch_mode,u64 * total_cycles,struct evsel * evsel)2750 void hist__account_cycles(struct branch_stack *bs, struct addr_location *al,
2751 struct perf_sample *sample, bool nonany_branch_mode,
2752 u64 *total_cycles, struct evsel *evsel)
2753 {
2754 struct branch_info *bi;
2755 struct branch_entry *entries = perf_sample__branch_entries(sample);
2756
2757 /* If we have branch cycles always annotate them. */
2758 if (bs && bs->nr && entries[0].flags.cycles) {
2759 bi = sample__resolve_bstack(sample, al);
2760 if (bi) {
2761 struct addr_map_symbol *prev = NULL;
2762
2763 /*
2764 * Ignore errors, still want to process the
2765 * other entries.
2766 *
2767 * For non standard branch modes always
2768 * force no IPC (prev == NULL)
2769 *
2770 * Note that perf stores branches reversed from
2771 * program order!
2772 */
2773 for (int i = bs->nr - 1; i >= 0; i--) {
2774 addr_map_symbol__account_cycles(&bi[i].from,
2775 nonany_branch_mode ? NULL : prev,
2776 bi[i].flags.cycles, evsel,
2777 bi[i].branch_stack_cntr);
2778 prev = &bi[i].to;
2779
2780 if (total_cycles)
2781 *total_cycles += bi[i].flags.cycles;
2782 }
2783 for (unsigned int i = 0; i < bs->nr; i++) {
2784 map_symbol__exit(&bi[i].to.ms);
2785 map_symbol__exit(&bi[i].from.ms);
2786 }
2787 free(bi);
2788 }
2789 }
2790 }
2791
evlist__fprintf_nr_events(struct evlist * evlist,FILE * fp)2792 size_t evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp)
2793 {
2794 struct evsel *pos;
2795 size_t ret = 0;
2796
2797 evlist__for_each_entry(evlist, pos) {
2798 struct hists *hists = evsel__hists(pos);
2799 u64 total_samples = hists->stats.nr_samples;
2800
2801 total_samples += hists->stats.nr_lost_samples;
2802 total_samples += hists->stats.nr_dropped_samples;
2803
2804 if (symbol_conf.skip_empty && total_samples == 0)
2805 continue;
2806
2807 ret += fprintf(fp, "%s stats:\n", evsel__name(pos));
2808 if (hists->stats.nr_samples)
2809 ret += fprintf(fp, "%20s events: %10d\n",
2810 "SAMPLE", hists->stats.nr_samples);
2811 if (hists->stats.nr_lost_samples)
2812 ret += fprintf(fp, "%20s events: %10d\n",
2813 "LOST_SAMPLES", hists->stats.nr_lost_samples);
2814 if (hists->stats.nr_dropped_samples)
2815 ret += fprintf(fp, "%20s events: %10d\n",
2816 "LOST_SAMPLES (BPF)", hists->stats.nr_dropped_samples);
2817 }
2818
2819 return ret;
2820 }
2821
2822
hists__total_period(struct hists * hists)2823 u64 hists__total_period(struct hists *hists)
2824 {
2825 return symbol_conf.filter_relative ? hists->stats.total_non_filtered_period :
2826 hists->stats.total_period;
2827 }
2828
hists__total_latency(struct hists * hists)2829 u64 hists__total_latency(struct hists *hists)
2830 {
2831 return symbol_conf.filter_relative ? hists->stats.total_non_filtered_latency :
2832 hists->stats.total_latency;
2833 }
2834
__hists__scnprintf_title(struct hists * hists,char * bf,size_t size,bool show_freq)2835 int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool show_freq)
2836 {
2837 char unit;
2838 int printed;
2839 const struct dso *dso = hists->dso_filter;
2840 struct thread *thread = hists->thread_filter;
2841 int socket_id = hists->socket_filter;
2842 unsigned long nr_samples = hists->stats.nr_samples;
2843 u64 nr_events = hists->stats.total_period;
2844 struct evsel *evsel = hists_to_evsel(hists);
2845 const char *ev_name = evsel__name(evsel);
2846 char buf[512], sample_freq_str[64] = "";
2847 size_t buflen = sizeof(buf);
2848 char ref[30] = " show reference callgraph, ";
2849 bool enable_ref = false;
2850
2851 if (symbol_conf.filter_relative) {
2852 nr_samples = hists->stats.nr_non_filtered_samples;
2853 nr_events = hists->stats.total_non_filtered_period;
2854 }
2855
2856 if (evsel__is_group_event(evsel)) {
2857 struct evsel *pos;
2858
2859 evsel__group_desc(evsel, buf, buflen);
2860 ev_name = buf;
2861
2862 for_each_group_member(pos, evsel) {
2863 struct hists *pos_hists = evsel__hists(pos);
2864
2865 if (symbol_conf.filter_relative) {
2866 nr_samples += pos_hists->stats.nr_non_filtered_samples;
2867 nr_events += pos_hists->stats.total_non_filtered_period;
2868 } else {
2869 nr_samples += pos_hists->stats.nr_samples;
2870 nr_events += pos_hists->stats.total_period;
2871 }
2872 }
2873 }
2874
2875 if (symbol_conf.show_ref_callgraph &&
2876 strstr(ev_name, "call-graph=no"))
2877 enable_ref = true;
2878
2879 if (show_freq)
2880 scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->core.attr.sample_freq);
2881
2882 nr_samples = convert_unit(nr_samples, &unit);
2883 printed = scnprintf(bf, size,
2884 "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64,
2885 nr_samples, unit, evsel->core.nr_members > 1 ? "s" : "",
2886 ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events);
2887
2888
2889 if (hists->uid_filter_str)
2890 printed += snprintf(bf + printed, size - printed,
2891 ", UID: %s", hists->uid_filter_str);
2892 if (thread) {
2893 if (hists__has(hists, thread)) {
2894 printed += scnprintf(bf + printed, size - printed,
2895 ", Thread: %s(%d)",
2896 (thread__comm_set(thread) ? thread__comm_str(thread) : ""),
2897 thread__tid(thread));
2898 } else {
2899 printed += scnprintf(bf + printed, size - printed,
2900 ", Thread: %s",
2901 (thread__comm_set(thread) ? thread__comm_str(thread) : ""));
2902 }
2903 }
2904 if (dso)
2905 printed += scnprintf(bf + printed, size - printed,
2906 ", DSO: %s", dso__short_name(dso));
2907 if (socket_id > -1)
2908 printed += scnprintf(bf + printed, size - printed,
2909 ", Processor Socket: %d", socket_id);
2910
2911 return printed;
2912 }
2913
parse_filter_percentage(const struct option * opt __maybe_unused,const char * arg,int unset __maybe_unused)2914 int parse_filter_percentage(const struct option *opt __maybe_unused,
2915 const char *arg, int unset __maybe_unused)
2916 {
2917 if (!strcmp(arg, "relative"))
2918 symbol_conf.filter_relative = true;
2919 else if (!strcmp(arg, "absolute"))
2920 symbol_conf.filter_relative = false;
2921 else {
2922 pr_debug("Invalid percentage: %s\n", arg);
2923 return -1;
2924 }
2925
2926 return 0;
2927 }
2928
perf_hist_config(const char * var,const char * value)2929 int perf_hist_config(const char *var, const char *value)
2930 {
2931 if (!strcmp(var, "hist.percentage"))
2932 return parse_filter_percentage(NULL, value, 0);
2933
2934 return 0;
2935 }
2936
__hists__init(struct hists * hists,struct perf_hpp_list * hpp_list)2937 int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list)
2938 {
2939 memset(hists, 0, sizeof(*hists));
2940 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT_CACHED;
2941 hists->entries_in = &hists->entries_in_array[0];
2942 hists->entries_collapsed = RB_ROOT_CACHED;
2943 hists->entries = RB_ROOT_CACHED;
2944 mutex_init(&hists->lock);
2945 hists->socket_filter = -1;
2946 hists->parallelism_filter = symbol_conf.parallelism_filter;
2947 hists->hpp_list = hpp_list;
2948 INIT_LIST_HEAD(&hists->hpp_formats);
2949 return 0;
2950 }
2951
hists__delete_remaining_entries(struct rb_root_cached * root)2952 static void hists__delete_remaining_entries(struct rb_root_cached *root)
2953 {
2954 struct rb_node *node;
2955 struct hist_entry *he;
2956
2957 while (!RB_EMPTY_ROOT(&root->rb_root)) {
2958 node = rb_first_cached(root);
2959 rb_erase_cached(node, root);
2960
2961 he = rb_entry(node, struct hist_entry, rb_node_in);
2962 hist_entry__delete(he);
2963 }
2964 }
2965
hists__delete_all_entries(struct hists * hists)2966 static void hists__delete_all_entries(struct hists *hists)
2967 {
2968 hists__delete_entries(hists);
2969 hists__delete_remaining_entries(&hists->entries_in_array[0]);
2970 hists__delete_remaining_entries(&hists->entries_in_array[1]);
2971 hists__delete_remaining_entries(&hists->entries_collapsed);
2972 }
2973
hists_evsel__exit(struct evsel * evsel)2974 static void hists_evsel__exit(struct evsel *evsel)
2975 {
2976 struct hists *hists = evsel__hists(evsel);
2977 struct perf_hpp_fmt *fmt, *pos;
2978 struct perf_hpp_list_node *node, *tmp;
2979
2980 hists__delete_all_entries(hists);
2981
2982 list_for_each_entry_safe(node, tmp, &hists->hpp_formats, list) {
2983 perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
2984 list_del_init(&fmt->list);
2985 free(fmt);
2986 }
2987 list_del_init(&node->list);
2988 free(node);
2989 }
2990 }
2991
hists_evsel__init(struct evsel * evsel)2992 static int hists_evsel__init(struct evsel *evsel)
2993 {
2994 struct hists *hists = evsel__hists(evsel);
2995
2996 __hists__init(hists, &perf_hpp_list);
2997 return 0;
2998 }
2999
3000 /*
3001 * XXX We probably need a hists_evsel__exit() to free the hist_entries
3002 * stored in the rbtree...
3003 */
3004
hists__init(void)3005 int hists__init(void)
3006 {
3007 int err = evsel__object_config(sizeof(struct hists_evsel),
3008 hists_evsel__init, hists_evsel__exit);
3009 if (err)
3010 fputs("FATAL ERROR: Couldn't setup hists class\n", stderr);
3011
3012 return err;
3013 }
3014
perf_hpp_list__init(struct perf_hpp_list * list)3015 void perf_hpp_list__init(struct perf_hpp_list *list)
3016 {
3017 INIT_LIST_HEAD(&list->fields);
3018 INIT_LIST_HEAD(&list->sorts);
3019 }
3020