hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/tools/perf/util/callchain.c
....@@ -16,15 +16,22 @@
1616 #include <stdbool.h>
1717 #include <errno.h>
1818 #include <math.h>
19
+#include <linux/string.h>
20
+#include <linux/zalloc.h>
1921
2022 #include "asm/bug.h"
2123
24
+#include "debug.h"
25
+#include "dso.h"
26
+#include "event.h"
2227 #include "hist.h"
23
-#include "util.h"
2428 #include "sort.h"
2529 #include "machine.h"
30
+#include "map.h"
2631 #include "callchain.h"
2732 #include "branch.h"
33
+#include "symbol.h"
34
+#include "../perf.h"
2835
2936 #define CALLCHAIN_PARAM_DEFAULT \
3037 .mode = CHAIN_GRAPH_ABS, \
....@@ -575,8 +582,8 @@
575582 return -1;
576583 }
577584 call->ip = cursor_node->ip;
578
- call->ms.sym = cursor_node->sym;
579
- call->ms.map = map__get(cursor_node->map);
585
+ call->ms = cursor_node->ms;
586
+ map__get(call->ms.map);
580587 call->srcline = cursor_node->srcline;
581588
582589 if (cursor_node->branch) {
....@@ -634,7 +641,7 @@
634641 struct callchain_list *call, *tmp;
635642
636643 list_for_each_entry_safe(call, tmp, &new->val, list) {
637
- list_del(&call->list);
644
+ list_del_init(&call->list);
638645 map__zput(call->ms.map);
639646 free(call);
640647 }
....@@ -713,21 +720,21 @@
713720 /* otherwise fall-back to symbol-based comparison below */
714721 __fallthrough;
715722 case CCKEY_FUNCTION:
716
- if (node->sym && cnode->ms.sym) {
723
+ if (node->ms.sym && cnode->ms.sym) {
717724 /*
718725 * Compare inlined frames based on their symbol name
719726 * because different inlined frames will have the same
720727 * symbol start. Otherwise do a faster comparison based
721728 * on the symbol start address.
722729 */
723
- if (cnode->ms.sym->inlined || node->sym->inlined) {
730
+ if (cnode->ms.sym->inlined || node->ms.sym->inlined) {
724731 match = match_chain_strings(cnode->ms.sym->name,
725
- node->sym->name);
732
+ node->ms.sym->name);
726733 if (match != MATCH_ERROR)
727734 break;
728735 } else {
729736 match = match_chain_dso_addresses(cnode->ms.map, cnode->ms.sym->start,
730
- node->map, node->sym->start);
737
+ node->ms.map, node->ms.sym->start);
731738 break;
732739 }
733740 }
....@@ -735,7 +742,7 @@
735742 __fallthrough;
736743 case CCKEY_ADDRESS:
737744 default:
738
- match = match_chain_dso_addresses(cnode->ms.map, cnode->ip, node->map, node->ip);
745
+ match = match_chain_dso_addresses(cnode->ms.map, cnode->ip, node->ms.map, node->ip);
739746 break;
740747 }
741748
....@@ -997,10 +1004,9 @@
9971004 int err = 0;
9981005
9991006 list_for_each_entry_safe(list, next_list, &src->val, list) {
1000
- callchain_cursor_append(cursor, list->ip,
1001
- list->ms.map, list->ms.sym,
1007
+ callchain_cursor_append(cursor, list->ip, &list->ms,
10021008 false, NULL, 0, 0, 0, list->srcline);
1003
- list_del(&list->list);
1009
+ list_del_init(&list->list);
10041010 map__zput(list->ms.map);
10051011 free(list);
10061012 }
....@@ -1037,7 +1043,7 @@
10371043 }
10381044
10391045 int callchain_cursor_append(struct callchain_cursor *cursor,
1040
- u64 ip, struct map *map, struct symbol *sym,
1046
+ u64 ip, struct map_symbol *ms,
10411047 bool branch, struct branch_flags *flags,
10421048 int nr_loop_iter, u64 iter_cycles, u64 branch_from,
10431049 const char *srcline)
....@@ -1053,9 +1059,9 @@
10531059 }
10541060
10551061 node->ip = ip;
1056
- map__zput(node->map);
1057
- node->map = map__get(map);
1058
- node->sym = sym;
1062
+ map__zput(node->ms.map);
1063
+ node->ms = *ms;
1064
+ map__get(node->ms.map);
10591065 node->branch = branch;
10601066 node->nr_loop_iter = nr_loop_iter;
10611067 node->iter_cycles = iter_cycles;
....@@ -1075,7 +1081,7 @@
10751081
10761082 int sample__resolve_callchain(struct perf_sample *sample,
10771083 struct callchain_cursor *cursor, struct symbol **parent,
1078
- struct perf_evsel *evsel, struct addr_location *al,
1084
+ struct evsel *evsel, struct addr_location *al,
10791085 int max_stack)
10801086 {
10811087 if (sample->callchain == NULL && !symbol_conf.show_branchflag_count)
....@@ -1100,8 +1106,9 @@
11001106 int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
11011107 bool hide_unresolved)
11021108 {
1103
- al->map = node->map;
1104
- al->sym = node->sym;
1109
+ al->maps = node->ms.maps;
1110
+ al->map = node->ms.map;
1111
+ al->sym = node->ms.sym;
11051112 al->srcline = node->srcline;
11061113 al->addr = node->ip;
11071114
....@@ -1112,8 +1119,8 @@
11121119 goto out;
11131120 }
11141121
1115
- if (al->map->groups == &al->machine->kmaps) {
1116
- if (machine__is_host(al->machine)) {
1122
+ if (al->maps == &al->maps->machine->kmaps) {
1123
+ if (machine__is_host(al->maps->machine)) {
11171124 al->cpumode = PERF_RECORD_MISC_KERNEL;
11181125 al->level = 'k';
11191126 } else {
....@@ -1121,7 +1128,7 @@
11211128 al->level = 'g';
11221129 }
11231130 } else {
1124
- if (machine__is_host(al->machine)) {
1131
+ if (machine__is_host(al->maps->machine)) {
11251132 al->cpumode = PERF_RECORD_MISC_USER;
11261133 al->level = '.';
11271134 } else if (perf_guest) {
....@@ -1451,13 +1458,13 @@
14511458 struct rb_node *n;
14521459
14531460 list_for_each_entry_safe(list, tmp, &node->parent_val, list) {
1454
- list_del(&list->list);
1461
+ list_del_init(&list->list);
14551462 map__zput(list->ms.map);
14561463 free(list);
14571464 }
14581465
14591466 list_for_each_entry_safe(list, tmp, &node->val, list) {
1460
- list_del(&list->list);
1467
+ list_del_init(&list->list);
14611468 map__zput(list->ms.map);
14621469 free(list);
14631470 }
....@@ -1542,7 +1549,7 @@
15421549
15431550 out:
15441551 list_for_each_entry_safe(chain, new, &head, list) {
1545
- list_del(&chain->list);
1552
+ list_del_init(&chain->list);
15461553 map__zput(chain->ms.map);
15471554 free(chain);
15481555 }
....@@ -1564,7 +1571,7 @@
15641571 if (node == NULL)
15651572 break;
15661573
1567
- rc = callchain_cursor_append(dst, node->ip, node->map, node->sym,
1574
+ rc = callchain_cursor_append(dst, node->ip, &node->ms,
15681575 node->branch, &node->branch_flags,
15691576 node->nr_loop_iter,
15701577 node->iter_cycles,
....@@ -1577,3 +1584,131 @@
15771584
15781585 return rc;
15791586 }
1587
+
1588
+/*
1589
+ * Initialize a cursor before adding entries inside, but keep
1590
+ * the previously allocated entries as a cache.
1591
+ */
1592
+void callchain_cursor_reset(struct callchain_cursor *cursor)
1593
+{
1594
+ struct callchain_cursor_node *node;
1595
+
1596
+ cursor->nr = 0;
1597
+ cursor->last = &cursor->first;
1598
+
1599
+ for (node = cursor->first; node != NULL; node = node->next)
1600
+ map__zput(node->ms.map);
1601
+}
1602
+
1603
+void callchain_param_setup(u64 sample_type)
1604
+{
1605
+ if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) {
1606
+ if ((sample_type & PERF_SAMPLE_REGS_USER) &&
1607
+ (sample_type & PERF_SAMPLE_STACK_USER)) {
1608
+ callchain_param.record_mode = CALLCHAIN_DWARF;
1609
+ dwarf_callchain_users = true;
1610
+ } else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
1611
+ callchain_param.record_mode = CALLCHAIN_LBR;
1612
+ else
1613
+ callchain_param.record_mode = CALLCHAIN_FP;
1614
+ }
1615
+}
1616
+
1617
+static bool chain_match(struct callchain_list *base_chain,
1618
+ struct callchain_list *pair_chain)
1619
+{
1620
+ enum match_result match;
1621
+
1622
+ match = match_chain_strings(base_chain->srcline,
1623
+ pair_chain->srcline);
1624
+ if (match != MATCH_ERROR)
1625
+ return match == MATCH_EQ;
1626
+
1627
+ match = match_chain_dso_addresses(base_chain->ms.map,
1628
+ base_chain->ip,
1629
+ pair_chain->ms.map,
1630
+ pair_chain->ip);
1631
+
1632
+ return match == MATCH_EQ;
1633
+}
1634
+
1635
+bool callchain_cnode_matched(struct callchain_node *base_cnode,
1636
+ struct callchain_node *pair_cnode)
1637
+{
1638
+ struct callchain_list *base_chain, *pair_chain;
1639
+ bool match = false;
1640
+
1641
+ pair_chain = list_first_entry(&pair_cnode->val,
1642
+ struct callchain_list,
1643
+ list);
1644
+
1645
+ list_for_each_entry(base_chain, &base_cnode->val, list) {
1646
+ if (&pair_chain->list == &pair_cnode->val)
1647
+ return false;
1648
+
1649
+ if (!base_chain->srcline || !pair_chain->srcline) {
1650
+ pair_chain = list_next_entry(pair_chain, list);
1651
+ continue;
1652
+ }
1653
+
1654
+ match = chain_match(base_chain, pair_chain);
1655
+ if (!match)
1656
+ return false;
1657
+
1658
+ pair_chain = list_next_entry(pair_chain, list);
1659
+ }
1660
+
1661
+ /*
1662
+ * Say chain1 is ABC, chain2 is ABCD, we consider they are
1663
+ * not fully matched.
1664
+ */
1665
+ if (pair_chain && (&pair_chain->list != &pair_cnode->val))
1666
+ return false;
1667
+
1668
+ return match;
1669
+}
1670
+
1671
+static u64 count_callchain_hits(struct hist_entry *he)
1672
+{
1673
+ struct rb_root *root = &he->sorted_chain;
1674
+ struct rb_node *rb_node = rb_first(root);
1675
+ struct callchain_node *node;
1676
+ u64 chain_hits = 0;
1677
+
1678
+ while (rb_node) {
1679
+ node = rb_entry(rb_node, struct callchain_node, rb_node);
1680
+ chain_hits += node->hit;
1681
+ rb_node = rb_next(rb_node);
1682
+ }
1683
+
1684
+ return chain_hits;
1685
+}
1686
+
1687
+u64 callchain_total_hits(struct hists *hists)
1688
+{
1689
+ struct rb_node *next = rb_first_cached(&hists->entries);
1690
+ u64 chain_hits = 0;
1691
+
1692
+ while (next) {
1693
+ struct hist_entry *he = rb_entry(next, struct hist_entry,
1694
+ rb_node);
1695
+
1696
+ chain_hits += count_callchain_hits(he);
1697
+ next = rb_next(&he->rb_node);
1698
+ }
1699
+
1700
+ return chain_hits;
1701
+}
1702
+
1703
+s64 callchain_avg_cycles(struct callchain_node *cnode)
1704
+{
1705
+ struct callchain_list *chain;
1706
+ s64 cycles = 0;
1707
+
1708
+ list_for_each_entry(chain, &cnode->val, list) {
1709
+ if (chain->srcline && chain->branch_count)
1710
+ cycles += chain->cycles_count / chain->branch_count;
1711
+ }
1712
+
1713
+ return cycles;
1714
+}