diff options
author | Namhyung Kim <namhyung@kernel.org> | 2024-08-17 02:58:38 +0300 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2024-08-19 17:50:40 +0300 |
commit | ba8833703b49451453d97bf6414a522293f7e31d (patch) | |
tree | efed0a56289a277d99026970d2e55bee06c5295e /tools/perf/util/annotate-data.c | |
parent | c663451f9239c89746b55f1a17ad62b014fa7905 (diff) | |
download | linux-ba8833703b49451453d97bf6414a522293f7e31d.tar.xz |
perf annotate-data: Check variables in every scope
Sometimes it matches a variable in the inner scope but it fails because
the actual access can be on a different type. Let's try variables in
every scope and choose the best one using is_better_type().
I have an example with update_blocked_averages(), at first it found a
variable (__mptr) but it's a void pointer. So it moved on to the upper
scope and found another variable (cfs_rq).
$ perf --debug type-profile annotate --data-type --stdio
...
-----------------------------------------------------------
find data type for 0x140(reg14) at update_blocked_averages+0x2db
CU for kernel/sched/fair.c (die:0x12dd892)
frame base: cfa=1 fbreg=7
found "__mptr" (die: 0x13022f1) in scope=4/4 (die: 0x13022e8) failed: no/void pointer
variable location: base=reg14, offset=0x140
type='void*' size=0x8 (die:0x12dd8f9)
found "cfs_rq" (die: 0x1301721) in scope=3/4 (die: 0x130171c) type_offset=0x140
variable location: reg14
type='struct cfs_rq' size=0x1c0 (die:0x12e37e5)
final type: type='struct cfs_rq' size=0x1c0 (die:0x12e37e5)
IIUC the scope is like below:
1: update_blocked_averages
2: __update_blocked_fair
3: for_each_leaf_cfs_rq_safe
4: list_entry -> (container_of)
The container_of is implemented like:
#define container_of(ptr, type, member) ({ \
void *__mptr = (void *)(ptr); \
static_assert(__same_type(*(ptr), ((type *)0)->member) || \
__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type *)(__mptr - offsetof(type, member))); })
That's why we see the __mptr variable first but it failed since it has
no type information.
Then for_each_leaf_cfs_rq_safe() is defined as
#define for_each_leaf_cfs_rq_safe(rq, cfs_rq, pos) \
list_for_each_entry_safe(cfs_rq, pos, &rq->leaf_cfs_rq_list, \
leaf_cfs_rq_list)
Note that the access was 0x140(r14). And the cfs_rq has
leaf_cfs_rq_list at the 0x140. So it converts the list_head pointer to
a pointer to struct cfs_rq here.
$ pahole --hex -C cfs_rq vmlinux | grep 140
struct cfs_rq struct list_head leaf_cfs_rq_list; /* 0x140 0x10 */
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Athira Rajeev <atrajeev@linux.vnet.ibm.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20240816235840.2754937-9-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/annotate-data.c')
-rw-r--r-- | tools/perf/util/annotate-data.c | 44 |
1 files changed, 27 insertions, 17 deletions
diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 916d26bfb9eb..e86f40fed323 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -1244,7 +1244,6 @@ again: pr_debug_dtp("found by insn track: %#x(%s) type-offset=%#x\n", dloc->op->offset, buf, dloc->type_offset); - pr_debug_type_name(type_die, TSR_KIND_TYPE); break; } @@ -1273,6 +1272,7 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) int fbreg = -1; int fb_offset = 0; bool is_fbreg = false; + bool found = false; u64 pc; char buf[64]; enum type_match_result result; @@ -1358,14 +1358,17 @@ retry: /* Search from the inner-most scope to the outer */ for (i = nr_scopes - 1; i >= 0; i--) { + Dwarf_Die mem_die; + int type_offset = offset; + if (reg == DWARF_REG_PC) { if (!die_find_variable_by_addr(&scopes[i], dloc->var_addr, - &var_die, &offset)) + &var_die, &type_offset)) continue; } else { /* Look up variables/parameters in this scope */ if (!die_find_variable_by_reg(&scopes[i], pc, reg, - &offset, is_fbreg, &var_die)) + &type_offset, is_fbreg, &var_die)) continue; } @@ -1374,43 +1377,50 @@ retry: i+1, nr_scopes, (long)dwarf_dieoffset(&scopes[i])); /* Found a variable, see if it's correct */ - result = check_variable(dloc, &var_die, type_die, reg, offset, is_fbreg); + result = check_variable(dloc, &var_die, &mem_die, reg, type_offset, is_fbreg); if (result == PERF_TMR_OK) { if (reg == DWARF_REG_PC) { pr_debug_dtp("addr=%#"PRIx64" type_offset=%#x\n", - dloc->var_addr, offset); + dloc->var_addr, type_offset); } else if (reg == DWARF_REG_FB || is_fbreg) { pr_debug_dtp("stack_offset=%#x type_offset=%#x\n", - fb_offset, offset); + fb_offset, type_offset); } else { - pr_debug_dtp("type_offset=%#x\n", offset); + pr_debug_dtp("type_offset=%#x\n", type_offset); + } + + if (!found || is_better_type(type_die, &mem_die)) { + *type_die = mem_die; + dloc->type_offset = type_offset; + found = true; } - ret = 0; } else { pr_debug_dtp("failed: %s\n", match_result_str(result)); - ret = -1; } + pr_debug_location(&var_die, pc, reg); - pr_debug_type_name(type_die, TSR_KIND_TYPE); - dloc->type_offset = offset; - goto out; + pr_debug_type_name(&mem_die, TSR_KIND_TYPE); } - if (loc->multi_regs && reg == loc->reg1 && loc->reg1 != loc->reg2) { + if (!found && loc->multi_regs && reg == loc->reg1 && loc->reg1 != loc->reg2) { reg = loc->reg2; goto retry; } - if (reg != DWARF_REG_PC) { + if (!found && reg != DWARF_REG_PC) { result = find_data_type_block(dloc, &cu_die, scopes, - nr_scopes, type_die); + nr_scopes, type_die); if (result == PERF_TMR_OK) { ann_data_stat.insn_track++; - ret = 0; + found = true; } } - if (ret < 0) { + if (found) { + pr_debug_dtp("final type:"); + pr_debug_type_name(type_die, TSR_KIND_TYPE); + ret = 0; + } else { pr_debug_dtp("no variable found\n"); ann_data_stat.no_var++; } |