Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

perf machine: Add inline information to frame pointer and LBR callchains

Use append_inlines() in frame pointer and LBR cases.

Update the addr2line test to also test frame pointers.

LBR is also updated but inaccuracy in the branched to IP means the
inline information is missing in the leaf.

Leave LBR callchains untested for now.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Aditya Bodkhe <aditya.b1@linux.ibm.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Albert Ou <aou@eecs.berkeley.edu>
Cc: Alexandre Ghiti <alex@ghiti.fr>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Athira Rajeev <atrajeev@linux.ibm.com>
Cc: Chun-Tse Shao <ctshao@google.com>
Cc: Dmitriy Vyukov <dvyukov@google.com>
Cc: Dr. David Alan Gilbert <linux@treblig.org>
Cc: Guo Ren <guoren@kernel.org>
Cc: Haibo Xu <haibo1.xu@intel.com>
Cc: Howard Chu <howardchu95@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.g.garry@oracle.com>
Cc: Krzysztof Łopatowski <krzysztof.m.lopatowski@gmail.com>
Cc: Leo Yan <leo.yan@linux.dev>
Cc: Mark Wielaard <mark@klomp.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Paul Walmsley <pjw@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sergei Trofimovich <slyich@gmail.com>
Cc: Shimin Guo <shimin.guo@skydio.com>
Cc: Stephen Brennan <stephen.s.brennan@oracle.com>
Cc: Thomas Falcon <thomas.falcon@intel.com>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
28cb835f 6b2658b3

+86 -49
+26 -5
tools/perf/tests/shell/addr2line_inlines.sh
··· 21 21 } 22 22 trap trap_cleanup EXIT TERM INT 23 23 24 - test_inlinedloop() { 25 - echo "Inline unwinding verification test" 24 + test_fp() { 25 + echo "Inline unwinding fp verification test" 26 + # Record data. Currently only dwarf callchains support inlined functions. 27 + perf record --call-graph fp -e task-clock:u -o "${perf_data}" -- perf test -w inlineloop 1 28 + 29 + # Check output with inline (default) and srcline 30 + perf script -i "${perf_data}" --fields +srcline > "${perf_script_txt}" 31 + 32 + # Expect the leaf and middle functions to occur on lines in the 20s, with 33 + # the non-inlined parent function on a line in the 30s. 34 + if grep -q "inlineloop.c:2. (inlined)" "${perf_script_txt}" && 35 + grep -q "inlineloop.c:3.$" "${perf_script_txt}" 36 + then 37 + echo "Inline unwinding fp verification test [Success]" 38 + else 39 + echo "Inline unwinding fp verification test [Failed missing inlined functions]" 40 + err=1 41 + fi 42 + } 43 + 44 + test_dwarf() { 45 + echo "Inline unwinding dwarf verification test" 26 46 # Record data. Currently only dwarf callchains support inlined functions. 27 47 perf record --call-graph dwarf -e task-clock:u -o "${perf_data}" -- perf test -w inlineloop 1 28 48 ··· 54 34 if grep -q "inlineloop.c:2. (inlined)" "${perf_script_txt}" && 55 35 grep -q "inlineloop.c:3.$" "${perf_script_txt}" 56 36 then 57 - echo "Inline unwinding verification test [Success]" 37 + echo "Inline unwinding dwarf verification test [Success]" 58 38 else 59 - echo "Inline unwinding verification test [Failed missing inlined functions]" 39 + echo "Inline unwinding dwarf verification test [Failed missing inlined functions]" 60 40 err=1 61 41 fi 62 42 } 63 43 64 - test_inlinedloop 44 + test_fp 45 + test_dwarf 65 46 66 47 cleanup 67 48 exit $err
+60 -44
tools/perf/util/machine.c
··· 2090 2090 u64 cycles; 2091 2091 }; 2092 2092 2093 + static int append_inlines(struct callchain_cursor *cursor, struct map_symbol *ms, u64 ip, 2094 + bool branch, struct branch_flags *flags, int nr_loop_iter, 2095 + u64 iter_cycles, u64 branch_from) 2096 + { 2097 + struct symbol *sym = ms->sym; 2098 + struct map *map = ms->map; 2099 + struct inline_node *inline_node; 2100 + struct inline_list *ilist; 2101 + struct dso *dso; 2102 + u64 addr; 2103 + int ret = 1; 2104 + struct map_symbol ilist_ms; 2105 + bool first = true; 2106 + 2107 + if (!symbol_conf.inline_name || !map || !sym) 2108 + return ret; 2109 + 2110 + addr = map__dso_map_ip(map, ip); 2111 + addr = map__rip_2objdump(map, addr); 2112 + dso = map__dso(map); 2113 + 2114 + inline_node = inlines__tree_find(dso__inlined_nodes(dso), addr); 2115 + if (!inline_node) { 2116 + inline_node = dso__parse_addr_inlines(dso, addr, sym); 2117 + if (!inline_node) 2118 + return ret; 2119 + inlines__tree_insert(dso__inlined_nodes(dso), inline_node); 2120 + } 2121 + 2122 + ilist_ms = (struct map_symbol) { 2123 + .maps = maps__get(ms->maps), 2124 + .map = map__get(map), 2125 + }; 2126 + list_for_each_entry(ilist, &inline_node->val, list) { 2127 + ilist_ms.sym = ilist->symbol; 2128 + if (first) { 2129 + ret = callchain_cursor_append(cursor, ip, &ilist_ms, 2130 + branch, flags, nr_loop_iter, 2131 + iter_cycles, branch_from, ilist->srcline); 2132 + } else { 2133 + ret = callchain_cursor_append(cursor, ip, &ilist_ms, false, 2134 + NULL, 0, 0, 0, ilist->srcline); 2135 + } 2136 + first = false; 2137 + 2138 + if (ret != 0) 2139 + return ret; 2140 + } 2141 + map_symbol__exit(&ilist_ms); 2142 + 2143 + return ret; 2144 + } 2145 + 2093 2146 static int add_callchain_ip(struct thread *thread, 2094 2147 struct callchain_cursor *cursor, 2095 2148 struct symbol **parent, ··· 2223 2170 ms.maps = maps__get(al.maps); 2224 2171 ms.map = map__get(al.map); 2225 2172 ms.sym = al.sym; 2173 + 2174 + if (append_inlines(cursor, &ms, ip, branch, flags, nr_loop_iter, 2175 + iter_cycles, branch_from) == 0) 2176 + goto out; 2177 + 2226 2178 srcline = callchain_srcline(&ms, al.addr); 2227 2179 err = callchain_cursor_append(cursor, ip, &ms, 2228 2180 branch, flags, nr_loop_iter, ··· 2946 2888 return 0; 2947 2889 } 2948 2890 2949 - static int append_inlines(struct callchain_cursor *cursor, struct map_symbol *ms, u64 ip) 2950 - { 2951 - struct symbol *sym = ms->sym; 2952 - struct map *map = ms->map; 2953 - struct inline_node *inline_node; 2954 - struct inline_list *ilist; 2955 - struct dso *dso; 2956 - u64 addr; 2957 - int ret = 1; 2958 - struct map_symbol ilist_ms; 2959 - 2960 - if (!symbol_conf.inline_name || !map || !sym) 2961 - return ret; 2962 - 2963 - addr = map__dso_map_ip(map, ip); 2964 - addr = map__rip_2objdump(map, addr); 2965 - dso = map__dso(map); 2966 - 2967 - inline_node = inlines__tree_find(dso__inlined_nodes(dso), addr); 2968 - if (!inline_node) { 2969 - inline_node = dso__parse_addr_inlines(dso, addr, sym); 2970 - if (!inline_node) 2971 - return ret; 2972 - inlines__tree_insert(dso__inlined_nodes(dso), inline_node); 2973 - } 2974 - 2975 - ilist_ms = (struct map_symbol) { 2976 - .maps = maps__get(ms->maps), 2977 - .map = map__get(map), 2978 - }; 2979 - list_for_each_entry(ilist, &inline_node->val, list) { 2980 - ilist_ms.sym = ilist->symbol; 2981 - ret = callchain_cursor_append(cursor, ip, &ilist_ms, false, 2982 - NULL, 0, 0, 0, ilist->srcline); 2983 - 2984 - if (ret != 0) 2985 - return ret; 2986 - } 2987 - map_symbol__exit(&ilist_ms); 2988 - 2989 - return ret; 2990 - } 2991 - 2992 2891 static int unwind_entry(struct unwind_entry *entry, void *arg) 2993 2892 { 2994 2893 struct callchain_cursor *cursor = arg; ··· 2955 2940 if (symbol_conf.hide_unresolved && entry->ms.sym == NULL) 2956 2941 return 0; 2957 2942 2958 - if (append_inlines(cursor, &entry->ms, entry->ip) == 0) 2943 + if (append_inlines(cursor, &entry->ms, entry->ip, /*branch=*/false, /*branch_flags=*/NULL, 2944 + /*nr_loop_iter=*/0, /*iter_cycles=*/0, /*branch_from=*/0) == 0) 2959 2945 return 0; 2960 2946 2961 2947 /*