Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1#include "annotate.h"
2#include "util.h"
3#include "build-id.h"
4#include "hist.h"
5#include "session.h"
6#include "sort.h"
7#include "evsel.h"
8#include <math.h>
9
10static bool hists__filter_entry_by_dso(struct hists *hists,
11 struct hist_entry *he);
12static bool hists__filter_entry_by_thread(struct hists *hists,
13 struct hist_entry *he);
14static bool hists__filter_entry_by_symbol(struct hists *hists,
15 struct hist_entry *he);
16
17enum hist_filter {
18 HIST_FILTER__DSO,
19 HIST_FILTER__THREAD,
20 HIST_FILTER__PARENT,
21 HIST_FILTER__SYMBOL,
22};
23
24struct callchain_param callchain_param = {
25 .mode = CHAIN_GRAPH_REL,
26 .min_percent = 0.5,
27 .order = ORDER_CALLEE
28};
29
30u16 hists__col_len(struct hists *hists, enum hist_column col)
31{
32 return hists->col_len[col];
33}
34
35void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len)
36{
37 hists->col_len[col] = len;
38}
39
40bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len)
41{
42 if (len > hists__col_len(hists, col)) {
43 hists__set_col_len(hists, col, len);
44 return true;
45 }
46 return false;
47}
48
49void hists__reset_col_len(struct hists *hists)
50{
51 enum hist_column col;
52
53 for (col = 0; col < HISTC_NR_COLS; ++col)
54 hists__set_col_len(hists, col, 0);
55}
56
57static void hists__set_unres_dso_col_len(struct hists *hists, int dso)
58{
59 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
60
61 if (hists__col_len(hists, dso) < unresolved_col_width &&
62 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
63 !symbol_conf.dso_list)
64 hists__set_col_len(hists, dso, unresolved_col_width);
65}
66
67void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
68{
69 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
70 int symlen;
71 u16 len;
72
73 /*
74 * +4 accounts for '[x] ' priv level info
75 * +2 accounts for 0x prefix on raw addresses
76 * +3 accounts for ' y ' symtab origin info
77 */
78 if (h->ms.sym) {
79 symlen = h->ms.sym->namelen + 4;
80 if (verbose)
81 symlen += BITS_PER_LONG / 4 + 2 + 3;
82 hists__new_col_len(hists, HISTC_SYMBOL, symlen);
83 } else {
84 symlen = unresolved_col_width + 4 + 2;
85 hists__new_col_len(hists, HISTC_SYMBOL, symlen);
86 hists__set_unres_dso_col_len(hists, HISTC_DSO);
87 }
88
89 len = thread__comm_len(h->thread);
90 if (hists__new_col_len(hists, HISTC_COMM, len))
91 hists__set_col_len(hists, HISTC_THREAD, len + 6);
92
93 if (h->ms.map) {
94 len = dso__name_len(h->ms.map->dso);
95 hists__new_col_len(hists, HISTC_DSO, len);
96 }
97
98 if (h->parent)
99 hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
100
101 if (h->branch_info) {
102 if (h->branch_info->from.sym) {
103 symlen = (int)h->branch_info->from.sym->namelen + 4;
104 if (verbose)
105 symlen += BITS_PER_LONG / 4 + 2 + 3;
106 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
107
108 symlen = dso__name_len(h->branch_info->from.map->dso);
109 hists__new_col_len(hists, HISTC_DSO_FROM, symlen);
110 } else {
111 symlen = unresolved_col_width + 4 + 2;
112 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
113 hists__set_unres_dso_col_len(hists, HISTC_DSO_FROM);
114 }
115
116 if (h->branch_info->to.sym) {
117 symlen = (int)h->branch_info->to.sym->namelen + 4;
118 if (verbose)
119 symlen += BITS_PER_LONG / 4 + 2 + 3;
120 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
121
122 symlen = dso__name_len(h->branch_info->to.map->dso);
123 hists__new_col_len(hists, HISTC_DSO_TO, symlen);
124 } else {
125 symlen = unresolved_col_width + 4 + 2;
126 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
127 hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
128 }
129 }
130
131 if (h->mem_info) {
132 if (h->mem_info->daddr.sym) {
133 symlen = (int)h->mem_info->daddr.sym->namelen + 4
134 + unresolved_col_width + 2;
135 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
136 symlen);
137 } else {
138 symlen = unresolved_col_width + 4 + 2;
139 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
140 symlen);
141 }
142 if (h->mem_info->daddr.map) {
143 symlen = dso__name_len(h->mem_info->daddr.map->dso);
144 hists__new_col_len(hists, HISTC_MEM_DADDR_DSO,
145 symlen);
146 } else {
147 symlen = unresolved_col_width + 4 + 2;
148 hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
149 }
150 } else {
151 symlen = unresolved_col_width + 4 + 2;
152 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen);
153 hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
154 }
155
156 hists__new_col_len(hists, HISTC_MEM_LOCKED, 6);
157 hists__new_col_len(hists, HISTC_MEM_TLB, 22);
158 hists__new_col_len(hists, HISTC_MEM_SNOOP, 12);
159 hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3);
160 hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12);
161 hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12);
162}
163
164void hists__output_recalc_col_len(struct hists *hists, int max_rows)
165{
166 struct rb_node *next = rb_first(&hists->entries);
167 struct hist_entry *n;
168 int row = 0;
169
170 hists__reset_col_len(hists);
171
172 while (next && row++ < max_rows) {
173 n = rb_entry(next, struct hist_entry, rb_node);
174 if (!n->filtered)
175 hists__calc_col_len(hists, n);
176 next = rb_next(&n->rb_node);
177 }
178}
179
180static void hist_entry__add_cpumode_period(struct hist_entry *he,
181 unsigned int cpumode, u64 period)
182{
183 switch (cpumode) {
184 case PERF_RECORD_MISC_KERNEL:
185 he->stat.period_sys += period;
186 break;
187 case PERF_RECORD_MISC_USER:
188 he->stat.period_us += period;
189 break;
190 case PERF_RECORD_MISC_GUEST_KERNEL:
191 he->stat.period_guest_sys += period;
192 break;
193 case PERF_RECORD_MISC_GUEST_USER:
194 he->stat.period_guest_us += period;
195 break;
196 default:
197 break;
198 }
199}
200
201static void he_stat__add_period(struct he_stat *he_stat, u64 period,
202 u64 weight)
203{
204
205 he_stat->period += period;
206 he_stat->weight += weight;
207 he_stat->nr_events += 1;
208}
209
210static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
211{
212 dest->period += src->period;
213 dest->period_sys += src->period_sys;
214 dest->period_us += src->period_us;
215 dest->period_guest_sys += src->period_guest_sys;
216 dest->period_guest_us += src->period_guest_us;
217 dest->nr_events += src->nr_events;
218 dest->weight += src->weight;
219}
220
221static void hist_entry__decay(struct hist_entry *he)
222{
223 he->stat.period = (he->stat.period * 7) / 8;
224 he->stat.nr_events = (he->stat.nr_events * 7) / 8;
225 /* XXX need decay for weight too? */
226}
227
228static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
229{
230 u64 prev_period = he->stat.period;
231
232 if (prev_period == 0)
233 return true;
234
235 hist_entry__decay(he);
236
237 if (!he->filtered)
238 hists->stats.total_period -= prev_period - he->stat.period;
239
240 return he->stat.period == 0;
241}
242
243void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
244{
245 struct rb_node *next = rb_first(&hists->entries);
246 struct hist_entry *n;
247
248 while (next) {
249 n = rb_entry(next, struct hist_entry, rb_node);
250 next = rb_next(&n->rb_node);
251 /*
252 * We may be annotating this, for instance, so keep it here in
253 * case some it gets new samples, we'll eventually free it when
254 * the user stops browsing and it agains gets fully decayed.
255 */
256 if (((zap_user && n->level == '.') ||
257 (zap_kernel && n->level != '.') ||
258 hists__decay_entry(hists, n)) &&
259 !n->used) {
260 rb_erase(&n->rb_node, &hists->entries);
261
262 if (sort__need_collapse)
263 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
264
265 hist_entry__free(n);
266 --hists->nr_entries;
267 }
268 }
269}
270
271/*
272 * histogram, sorted on item, collects periods
273 */
274
275static struct hist_entry *hist_entry__new(struct hist_entry *template)
276{
277 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
278 struct hist_entry *he = zalloc(sizeof(*he) + callchain_size);
279
280 if (he != NULL) {
281 *he = *template;
282
283 if (he->ms.map)
284 he->ms.map->referenced = true;
285
286 if (he->branch_info) {
287 /*
288 * This branch info is (a part of) allocated from
289 * machine__resolve_bstack() and will be freed after
290 * adding new entries. So we need to save a copy.
291 */
292 he->branch_info = malloc(sizeof(*he->branch_info));
293 if (he->branch_info == NULL) {
294 free(he);
295 return NULL;
296 }
297
298 memcpy(he->branch_info, template->branch_info,
299 sizeof(*he->branch_info));
300
301 if (he->branch_info->from.map)
302 he->branch_info->from.map->referenced = true;
303 if (he->branch_info->to.map)
304 he->branch_info->to.map->referenced = true;
305 }
306
307 if (he->mem_info) {
308 if (he->mem_info->iaddr.map)
309 he->mem_info->iaddr.map->referenced = true;
310 if (he->mem_info->daddr.map)
311 he->mem_info->daddr.map->referenced = true;
312 }
313
314 if (symbol_conf.use_callchain)
315 callchain_init(he->callchain);
316
317 INIT_LIST_HEAD(&he->pairs.node);
318 }
319
320 return he;
321}
322
323void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
324{
325 if (!h->filtered) {
326 hists__calc_col_len(hists, h);
327 ++hists->nr_entries;
328 hists->stats.total_period += h->stat.period;
329 }
330}
331
332static u8 symbol__parent_filter(const struct symbol *parent)
333{
334 if (symbol_conf.exclude_other && parent == NULL)
335 return 1 << HIST_FILTER__PARENT;
336 return 0;
337}
338
339static struct hist_entry *add_hist_entry(struct hists *hists,
340 struct hist_entry *entry,
341 struct addr_location *al,
342 u64 period,
343 u64 weight)
344{
345 struct rb_node **p;
346 struct rb_node *parent = NULL;
347 struct hist_entry *he;
348 int cmp;
349
350 p = &hists->entries_in->rb_node;
351
352 while (*p != NULL) {
353 parent = *p;
354 he = rb_entry(parent, struct hist_entry, rb_node_in);
355
356 /*
357 * Make sure that it receives arguments in a same order as
358 * hist_entry__collapse() so that we can use an appropriate
359 * function when searching an entry regardless which sort
360 * keys were used.
361 */
362 cmp = hist_entry__cmp(he, entry);
363
364 if (!cmp) {
365 he_stat__add_period(&he->stat, period, weight);
366
367 /*
368 * This mem info was allocated from machine__resolve_mem
369 * and will not be used anymore.
370 */
371 free(entry->mem_info);
372
373 /* If the map of an existing hist_entry has
374 * become out-of-date due to an exec() or
375 * similar, update it. Otherwise we will
376 * mis-adjust symbol addresses when computing
377 * the history counter to increment.
378 */
379 if (he->ms.map != entry->ms.map) {
380 he->ms.map = entry->ms.map;
381 if (he->ms.map)
382 he->ms.map->referenced = true;
383 }
384 goto out;
385 }
386
387 if (cmp < 0)
388 p = &(*p)->rb_left;
389 else
390 p = &(*p)->rb_right;
391 }
392
393 he = hist_entry__new(entry);
394 if (!he)
395 return NULL;
396
397 rb_link_node(&he->rb_node_in, parent, p);
398 rb_insert_color(&he->rb_node_in, hists->entries_in);
399out:
400 hist_entry__add_cpumode_period(he, al->cpumode, period);
401 return he;
402}
403
404struct hist_entry *__hists__add_mem_entry(struct hists *self,
405 struct addr_location *al,
406 struct symbol *sym_parent,
407 struct mem_info *mi,
408 u64 period,
409 u64 weight)
410{
411 struct hist_entry entry = {
412 .thread = al->thread,
413 .ms = {
414 .map = al->map,
415 .sym = al->sym,
416 },
417 .stat = {
418 .period = period,
419 .weight = weight,
420 .nr_events = 1,
421 },
422 .cpu = al->cpu,
423 .ip = al->addr,
424 .level = al->level,
425 .parent = sym_parent,
426 .filtered = symbol__parent_filter(sym_parent),
427 .hists = self,
428 .mem_info = mi,
429 .branch_info = NULL,
430 };
431 return add_hist_entry(self, &entry, al, period, weight);
432}
433
434struct hist_entry *__hists__add_branch_entry(struct hists *self,
435 struct addr_location *al,
436 struct symbol *sym_parent,
437 struct branch_info *bi,
438 u64 period,
439 u64 weight)
440{
441 struct hist_entry entry = {
442 .thread = al->thread,
443 .ms = {
444 .map = bi->to.map,
445 .sym = bi->to.sym,
446 },
447 .cpu = al->cpu,
448 .ip = bi->to.addr,
449 .level = al->level,
450 .stat = {
451 .period = period,
452 .nr_events = 1,
453 .weight = weight,
454 },
455 .parent = sym_parent,
456 .filtered = symbol__parent_filter(sym_parent),
457 .branch_info = bi,
458 .hists = self,
459 .mem_info = NULL,
460 };
461
462 return add_hist_entry(self, &entry, al, period, weight);
463}
464
465struct hist_entry *__hists__add_entry(struct hists *self,
466 struct addr_location *al,
467 struct symbol *sym_parent, u64 period,
468 u64 weight)
469{
470 struct hist_entry entry = {
471 .thread = al->thread,
472 .ms = {
473 .map = al->map,
474 .sym = al->sym,
475 },
476 .cpu = al->cpu,
477 .ip = al->addr,
478 .level = al->level,
479 .stat = {
480 .period = period,
481 .nr_events = 1,
482 .weight = weight,
483 },
484 .parent = sym_parent,
485 .filtered = symbol__parent_filter(sym_parent),
486 .hists = self,
487 .branch_info = NULL,
488 .mem_info = NULL,
489 };
490
491 return add_hist_entry(self, &entry, al, period, weight);
492}
493
494int64_t
495hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
496{
497 struct sort_entry *se;
498 int64_t cmp = 0;
499
500 list_for_each_entry(se, &hist_entry__sort_list, list) {
501 cmp = se->se_cmp(left, right);
502 if (cmp)
503 break;
504 }
505
506 return cmp;
507}
508
509int64_t
510hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
511{
512 struct sort_entry *se;
513 int64_t cmp = 0;
514
515 list_for_each_entry(se, &hist_entry__sort_list, list) {
516 int64_t (*f)(struct hist_entry *, struct hist_entry *);
517
518 f = se->se_collapse ?: se->se_cmp;
519
520 cmp = f(left, right);
521 if (cmp)
522 break;
523 }
524
525 return cmp;
526}
527
528void hist_entry__free(struct hist_entry *he)
529{
530 free(he->branch_info);
531 free(he->mem_info);
532 free(he);
533}
534
535/*
536 * collapse the histogram
537 */
538
539static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
540 struct rb_root *root,
541 struct hist_entry *he)
542{
543 struct rb_node **p = &root->rb_node;
544 struct rb_node *parent = NULL;
545 struct hist_entry *iter;
546 int64_t cmp;
547
548 while (*p != NULL) {
549 parent = *p;
550 iter = rb_entry(parent, struct hist_entry, rb_node_in);
551
552 cmp = hist_entry__collapse(iter, he);
553
554 if (!cmp) {
555 he_stat__add_stat(&iter->stat, &he->stat);
556
557 if (symbol_conf.use_callchain) {
558 callchain_cursor_reset(&callchain_cursor);
559 callchain_merge(&callchain_cursor,
560 iter->callchain,
561 he->callchain);
562 }
563 hist_entry__free(he);
564 return false;
565 }
566
567 if (cmp < 0)
568 p = &(*p)->rb_left;
569 else
570 p = &(*p)->rb_right;
571 }
572
573 rb_link_node(&he->rb_node_in, parent, p);
574 rb_insert_color(&he->rb_node_in, root);
575 return true;
576}
577
578static struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
579{
580 struct rb_root *root;
581
582 pthread_mutex_lock(&hists->lock);
583
584 root = hists->entries_in;
585 if (++hists->entries_in > &hists->entries_in_array[1])
586 hists->entries_in = &hists->entries_in_array[0];
587
588 pthread_mutex_unlock(&hists->lock);
589
590 return root;
591}
592
593static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
594{
595 hists__filter_entry_by_dso(hists, he);
596 hists__filter_entry_by_thread(hists, he);
597 hists__filter_entry_by_symbol(hists, he);
598}
599
600void hists__collapse_resort(struct hists *hists)
601{
602 struct rb_root *root;
603 struct rb_node *next;
604 struct hist_entry *n;
605
606 if (!sort__need_collapse)
607 return;
608
609 root = hists__get_rotate_entries_in(hists);
610 next = rb_first(root);
611
612 while (next) {
613 n = rb_entry(next, struct hist_entry, rb_node_in);
614 next = rb_next(&n->rb_node_in);
615
616 rb_erase(&n->rb_node_in, root);
617 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n)) {
618 /*
619 * If it wasn't combined with one of the entries already
620 * collapsed, we need to apply the filters that may have
621 * been set by, say, the hist_browser.
622 */
623 hists__apply_filters(hists, n);
624 }
625 }
626}
627
628/*
629 * reverse the map, sort on period.
630 */
631
632static int period_cmp(u64 period_a, u64 period_b)
633{
634 if (period_a > period_b)
635 return 1;
636 if (period_a < period_b)
637 return -1;
638 return 0;
639}
640
641static int hist_entry__sort_on_period(struct hist_entry *a,
642 struct hist_entry *b)
643{
644 int ret;
645 int i, nr_members;
646 struct perf_evsel *evsel;
647 struct hist_entry *pair;
648 u64 *periods_a, *periods_b;
649
650 ret = period_cmp(a->stat.period, b->stat.period);
651 if (ret || !symbol_conf.event_group)
652 return ret;
653
654 evsel = hists_to_evsel(a->hists);
655 nr_members = evsel->nr_members;
656 if (nr_members <= 1)
657 return ret;
658
659 periods_a = zalloc(sizeof(periods_a) * nr_members);
660 periods_b = zalloc(sizeof(periods_b) * nr_members);
661
662 if (!periods_a || !periods_b)
663 goto out;
664
665 list_for_each_entry(pair, &a->pairs.head, pairs.node) {
666 evsel = hists_to_evsel(pair->hists);
667 periods_a[perf_evsel__group_idx(evsel)] = pair->stat.period;
668 }
669
670 list_for_each_entry(pair, &b->pairs.head, pairs.node) {
671 evsel = hists_to_evsel(pair->hists);
672 periods_b[perf_evsel__group_idx(evsel)] = pair->stat.period;
673 }
674
675 for (i = 1; i < nr_members; i++) {
676 ret = period_cmp(periods_a[i], periods_b[i]);
677 if (ret)
678 break;
679 }
680
681out:
682 free(periods_a);
683 free(periods_b);
684
685 return ret;
686}
687
688static void __hists__insert_output_entry(struct rb_root *entries,
689 struct hist_entry *he,
690 u64 min_callchain_hits)
691{
692 struct rb_node **p = &entries->rb_node;
693 struct rb_node *parent = NULL;
694 struct hist_entry *iter;
695
696 if (symbol_conf.use_callchain)
697 callchain_param.sort(&he->sorted_chain, he->callchain,
698 min_callchain_hits, &callchain_param);
699
700 while (*p != NULL) {
701 parent = *p;
702 iter = rb_entry(parent, struct hist_entry, rb_node);
703
704 if (hist_entry__sort_on_period(he, iter) > 0)
705 p = &(*p)->rb_left;
706 else
707 p = &(*p)->rb_right;
708 }
709
710 rb_link_node(&he->rb_node, parent, p);
711 rb_insert_color(&he->rb_node, entries);
712}
713
714void hists__output_resort(struct hists *hists)
715{
716 struct rb_root *root;
717 struct rb_node *next;
718 struct hist_entry *n;
719 u64 min_callchain_hits;
720
721 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
722
723 if (sort__need_collapse)
724 root = &hists->entries_collapsed;
725 else
726 root = hists->entries_in;
727
728 next = rb_first(root);
729 hists->entries = RB_ROOT;
730
731 hists->nr_entries = 0;
732 hists->stats.total_period = 0;
733 hists__reset_col_len(hists);
734
735 while (next) {
736 n = rb_entry(next, struct hist_entry, rb_node_in);
737 next = rb_next(&n->rb_node_in);
738
739 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
740 hists__inc_nr_entries(hists, n);
741 }
742}
743
744static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
745 enum hist_filter filter)
746{
747 h->filtered &= ~(1 << filter);
748 if (h->filtered)
749 return;
750
751 ++hists->nr_entries;
752 if (h->ms.unfolded)
753 hists->nr_entries += h->nr_rows;
754 h->row_offset = 0;
755 hists->stats.total_period += h->stat.period;
756 hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->stat.nr_events;
757
758 hists__calc_col_len(hists, h);
759}
760
761
762static bool hists__filter_entry_by_dso(struct hists *hists,
763 struct hist_entry *he)
764{
765 if (hists->dso_filter != NULL &&
766 (he->ms.map == NULL || he->ms.map->dso != hists->dso_filter)) {
767 he->filtered |= (1 << HIST_FILTER__DSO);
768 return true;
769 }
770
771 return false;
772}
773
774void hists__filter_by_dso(struct hists *hists)
775{
776 struct rb_node *nd;
777
778 hists->nr_entries = hists->stats.total_period = 0;
779 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
780 hists__reset_col_len(hists);
781
782 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
783 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
784
785 if (symbol_conf.exclude_other && !h->parent)
786 continue;
787
788 if (hists__filter_entry_by_dso(hists, h))
789 continue;
790
791 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
792 }
793}
794
795static bool hists__filter_entry_by_thread(struct hists *hists,
796 struct hist_entry *he)
797{
798 if (hists->thread_filter != NULL &&
799 he->thread != hists->thread_filter) {
800 he->filtered |= (1 << HIST_FILTER__THREAD);
801 return true;
802 }
803
804 return false;
805}
806
807void hists__filter_by_thread(struct hists *hists)
808{
809 struct rb_node *nd;
810
811 hists->nr_entries = hists->stats.total_period = 0;
812 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
813 hists__reset_col_len(hists);
814
815 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
816 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
817
818 if (hists__filter_entry_by_thread(hists, h))
819 continue;
820
821 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
822 }
823}
824
825static bool hists__filter_entry_by_symbol(struct hists *hists,
826 struct hist_entry *he)
827{
828 if (hists->symbol_filter_str != NULL &&
829 (!he->ms.sym || strstr(he->ms.sym->name,
830 hists->symbol_filter_str) == NULL)) {
831 he->filtered |= (1 << HIST_FILTER__SYMBOL);
832 return true;
833 }
834
835 return false;
836}
837
838void hists__filter_by_symbol(struct hists *hists)
839{
840 struct rb_node *nd;
841
842 hists->nr_entries = hists->stats.total_period = 0;
843 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
844 hists__reset_col_len(hists);
845
846 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
847 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
848
849 if (hists__filter_entry_by_symbol(hists, h))
850 continue;
851
852 hists__remove_entry_filter(hists, h, HIST_FILTER__SYMBOL);
853 }
854}
855
856int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
857{
858 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
859}
860
861int hist_entry__annotate(struct hist_entry *he, size_t privsize)
862{
863 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
864}
865
866void events_stats__inc(struct events_stats *stats, u32 type)
867{
868 ++stats->nr_events[0];
869 ++stats->nr_events[type];
870}
871
872void hists__inc_nr_events(struct hists *hists, u32 type)
873{
874 events_stats__inc(&hists->stats, type);
875}
876
877static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
878 struct hist_entry *pair)
879{
880 struct rb_root *root;
881 struct rb_node **p;
882 struct rb_node *parent = NULL;
883 struct hist_entry *he;
884 int cmp;
885
886 if (sort__need_collapse)
887 root = &hists->entries_collapsed;
888 else
889 root = hists->entries_in;
890
891 p = &root->rb_node;
892
893 while (*p != NULL) {
894 parent = *p;
895 he = rb_entry(parent, struct hist_entry, rb_node_in);
896
897 cmp = hist_entry__collapse(he, pair);
898
899 if (!cmp)
900 goto out;
901
902 if (cmp < 0)
903 p = &(*p)->rb_left;
904 else
905 p = &(*p)->rb_right;
906 }
907
908 he = hist_entry__new(pair);
909 if (he) {
910 memset(&he->stat, 0, sizeof(he->stat));
911 he->hists = hists;
912 rb_link_node(&he->rb_node_in, parent, p);
913 rb_insert_color(&he->rb_node_in, root);
914 hists__inc_nr_entries(hists, he);
915 }
916out:
917 return he;
918}
919
920static struct hist_entry *hists__find_entry(struct hists *hists,
921 struct hist_entry *he)
922{
923 struct rb_node *n;
924
925 if (sort__need_collapse)
926 n = hists->entries_collapsed.rb_node;
927 else
928 n = hists->entries_in->rb_node;
929
930 while (n) {
931 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node_in);
932 int64_t cmp = hist_entry__collapse(iter, he);
933
934 if (cmp < 0)
935 n = n->rb_left;
936 else if (cmp > 0)
937 n = n->rb_right;
938 else
939 return iter;
940 }
941
942 return NULL;
943}
944
945/*
946 * Look for pairs to link to the leader buckets (hist_entries):
947 */
948void hists__match(struct hists *leader, struct hists *other)
949{
950 struct rb_root *root;
951 struct rb_node *nd;
952 struct hist_entry *pos, *pair;
953
954 if (sort__need_collapse)
955 root = &leader->entries_collapsed;
956 else
957 root = leader->entries_in;
958
959 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
960 pos = rb_entry(nd, struct hist_entry, rb_node_in);
961 pair = hists__find_entry(other, pos);
962
963 if (pair)
964 hist_entry__add_pair(pair, pos);
965 }
966}
967
968/*
969 * Look for entries in the other hists that are not present in the leader, if
970 * we find them, just add a dummy entry on the leader hists, with period=0,
971 * nr_events=0, to serve as the list header.
972 */
973int hists__link(struct hists *leader, struct hists *other)
974{
975 struct rb_root *root;
976 struct rb_node *nd;
977 struct hist_entry *pos, *pair;
978
979 if (sort__need_collapse)
980 root = &other->entries_collapsed;
981 else
982 root = other->entries_in;
983
984 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
985 pos = rb_entry(nd, struct hist_entry, rb_node_in);
986
987 if (!hist_entry__has_pairs(pos)) {
988 pair = hists__add_dummy_entry(leader, pos);
989 if (pair == NULL)
990 return -1;
991 hist_entry__add_pair(pos, pair);
992 }
993 }
994
995 return 0;
996}