}
trap trap_cleanup EXIT TERM INT
-test_inlinedloop() {
- echo "Inline unwinding verification test"
+test_fp() {
+ echo "Inline unwinding fp verification test"
+ # Record data. Currently only dwarf callchains support inlined functions.
+ perf record --call-graph fp -e task-clock:u -o "${perf_data}" -- perf test -w inlineloop 1
+
+ # Check output with inline (default) and srcline
+ perf script -i "${perf_data}" --fields +srcline > "${perf_script_txt}"
+
+ # Expect the leaf and middle functions to occur on lines in the 20s, with
+ # the non-inlined parent function on a line in the 30s.
+ if grep -q "inlineloop.c:2. (inlined)" "${perf_script_txt}" &&
+ grep -q "inlineloop.c:3.$" "${perf_script_txt}"
+ then
+ echo "Inline unwinding fp verification test [Success]"
+ else
+ echo "Inline unwinding fp verification test [Failed missing inlined functions]"
+ err=1
+ fi
+}
+
+test_dwarf() {
+ echo "Inline unwinding dwarf verification test"
# Record data. Currently only dwarf callchains support inlined functions.
perf record --call-graph dwarf -e task-clock:u -o "${perf_data}" -- perf test -w inlineloop 1
if grep -q "inlineloop.c:2. (inlined)" "${perf_script_txt}" &&
grep -q "inlineloop.c:3.$" "${perf_script_txt}"
then
- echo "Inline unwinding verification test [Success]"
+ echo "Inline unwinding dwarf verification test [Success]"
else
- echo "Inline unwinding verification test [Failed missing inlined functions]"
+ echo "Inline unwinding dwarf verification test [Failed missing inlined functions]"
err=1
fi
}
-test_inlinedloop
+test_fp
+test_dwarf
cleanup
exit $err
u64 cycles;
};
+static int append_inlines(struct callchain_cursor *cursor, struct map_symbol *ms, u64 ip,
+ bool branch, struct branch_flags *flags, int nr_loop_iter,
+ u64 iter_cycles, u64 branch_from)
+{
+ struct symbol *sym = ms->sym;
+ struct map *map = ms->map;
+ struct inline_node *inline_node;
+ struct inline_list *ilist;
+ struct dso *dso;
+ u64 addr;
+ int ret = 1;
+ struct map_symbol ilist_ms;
+ bool first = true;
+
+ if (!symbol_conf.inline_name || !map || !sym)
+ return ret;
+
+ addr = map__dso_map_ip(map, ip);
+ addr = map__rip_2objdump(map, addr);
+ dso = map__dso(map);
+
+ inline_node = inlines__tree_find(dso__inlined_nodes(dso), addr);
+ if (!inline_node) {
+ inline_node = dso__parse_addr_inlines(dso, addr, sym);
+ if (!inline_node)
+ return ret;
+ inlines__tree_insert(dso__inlined_nodes(dso), inline_node);
+ }
+
+ ilist_ms = (struct map_symbol) {
+ .maps = maps__get(ms->maps),
+ .map = map__get(map),
+ };
+ list_for_each_entry(ilist, &inline_node->val, list) {
+ ilist_ms.sym = ilist->symbol;
+ if (first) {
+ ret = callchain_cursor_append(cursor, ip, &ilist_ms,
+ branch, flags, nr_loop_iter,
+ iter_cycles, branch_from, ilist->srcline);
+ } else {
+ ret = callchain_cursor_append(cursor, ip, &ilist_ms, false,
+ NULL, 0, 0, 0, ilist->srcline);
+ }
+ first = false;
+
+ if (ret != 0)
+ return ret;
+ }
+ map_symbol__exit(&ilist_ms);
+
+ return ret;
+}
+
static int add_callchain_ip(struct thread *thread,
struct callchain_cursor *cursor,
struct symbol **parent,
ms.maps = maps__get(al.maps);
ms.map = map__get(al.map);
ms.sym = al.sym;
+
+ if (append_inlines(cursor, &ms, ip, branch, flags, nr_loop_iter,
+ iter_cycles, branch_from) == 0)
+ goto out;
+
srcline = callchain_srcline(&ms, al.addr);
err = callchain_cursor_append(cursor, ip, &ms,
branch, flags, nr_loop_iter,
return 0;
}
-static int append_inlines(struct callchain_cursor *cursor, struct map_symbol *ms, u64 ip)
-{
- struct symbol *sym = ms->sym;
- struct map *map = ms->map;
- struct inline_node *inline_node;
- struct inline_list *ilist;
- struct dso *dso;
- u64 addr;
- int ret = 1;
- struct map_symbol ilist_ms;
-
- if (!symbol_conf.inline_name || !map || !sym)
- return ret;
-
- addr = map__dso_map_ip(map, ip);
- addr = map__rip_2objdump(map, addr);
- dso = map__dso(map);
-
- inline_node = inlines__tree_find(dso__inlined_nodes(dso), addr);
- if (!inline_node) {
- inline_node = dso__parse_addr_inlines(dso, addr, sym);
- if (!inline_node)
- return ret;
- inlines__tree_insert(dso__inlined_nodes(dso), inline_node);
- }
-
- ilist_ms = (struct map_symbol) {
- .maps = maps__get(ms->maps),
- .map = map__get(map),
- };
- list_for_each_entry(ilist, &inline_node->val, list) {
- ilist_ms.sym = ilist->symbol;
- ret = callchain_cursor_append(cursor, ip, &ilist_ms, false,
- NULL, 0, 0, 0, ilist->srcline);
-
- if (ret != 0)
- return ret;
- }
- map_symbol__exit(&ilist_ms);
-
- return ret;
-}
-
static int unwind_entry(struct unwind_entry *entry, void *arg)
{
struct callchain_cursor *cursor = arg;
if (symbol_conf.hide_unresolved && entry->ms.sym == NULL)
return 0;
- if (append_inlines(cursor, &entry->ms, entry->ip) == 0)
+ if (append_inlines(cursor, &entry->ms, entry->ip, /*branch=*/false, /*branch_flags=*/NULL,
+ /*nr_loop_iter=*/0, /*iter_cycles=*/0, /*branch_from=*/0) == 0)
return 0;
/*