• Namhyung Kim's avatar
    perf annotate-data: Check variables in every scope · ba883370
    Namhyung Kim authored
    
    
    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: default avatarNamhyung 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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
    ba883370
annotate-data.c 42.2 KB