lkml.org 
[lkml]   [2024]   [Feb]   [2]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 12/14] perf annotate-data: Handle this-cpu variables in kernel
    Date
    On x86, the kernel gets the current task using the current macro like
    below:

    #define current get_current()

    static __always_inline struct task_struct *get_current(void)
    {
    return this_cpu_read_stable(pcpu_hot.current_task);
    }

    So it returns the current_task field of struct pcpu_hot which is the
    first member. On my build, it's located at 0x32940.

    $ nm vmlinux | grep pcpu_hot
    0000000000032940 D pcpu_hot

    And the current macro generates the instructions like below:

    mov %gs:0x32940, %rcx

    So the %gs segment register points to the beginning of the per-cpu
    region of this cpu and it points the variable with a constant.

    Let's update the instruction location info to have a segment register
    and handle %gs in kernel to look up a global variable. The new
    get_percpu_var_info() helper is to get information about the variable.
    Pretend it as a global variable by changing the register number to
    DWARF_REG_PC.

    Signed-off-by: Namhyung Kim <namhyung@kernel.org>
    ---
    tools/perf/util/annotate.c | 31 +++++++++++++++++++++++++++++++
    tools/perf/util/annotate.h | 4 ++++
    2 files changed, 35 insertions(+)

    diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
    index 86ac44c476bf..5f3136f57c62 100644
    --- a/tools/perf/util/annotate.c
    +++ b/tools/perf/util/annotate.c
    @@ -3810,6 +3810,27 @@ void get_global_var_info(struct thread *thread, struct map_symbol *ms, u64 ip,
    addr_location__exit(&al);
    }

    +void get_percpu_var_info(struct thread *thread, struct map_symbol *ms,
    + u8 cpumode, u64 var_addr, const char **var_name,
    + int *poffset)
    +{
    + struct addr_location al;
    + struct symbol *var;
    + u64 map_addr;
    +
    + /* Kernel symbols might be relocated */
    + map_addr = var_addr + map__reloc(ms->map);
    +
    + addr_location__init(&al);
    + var = thread__find_symbol_fb(thread, cpumode, map_addr, &al);
    + if (var) {
    + *var_name = var->name;
    + /* Calculate type offset from the start of variable */
    + *poffset = map_addr - map__unmap_ip(al.map, var->start);
    + }
    + addr_location__exit(&al);
    +}
    +
    /**
    * hist_entry__get_data_type - find data type for given hist entry
    * @he: hist entry
    @@ -3906,6 +3927,16 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
    &dloc.type_offset);
    }

    + /* This CPU access in kernel - pretend PC-relative addressing */
    + if (op_loc->reg1 < 0 && map__dso(ms->map)->kernel &&
    + arch__is(arch, "x86") && op_loc->segment == INSN_SEG_X86_GS) {
    + dloc.var_addr = op_loc->offset;
    + get_percpu_var_info(he->thread, ms, he->cpumode,
    + dloc.var_addr, &dloc.var_name,
    + &dloc.type_offset);
    + op_loc->reg1 = DWARF_REG_PC;
    + }
    +
    mem_type = find_data_type(&dloc);
    if (mem_type)
    istat->good++;
    diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
    index 2bd654620de3..490134d19c9d 100644
    --- a/tools/perf/util/annotate.h
    +++ b/tools/perf/util/annotate.h
    @@ -513,6 +513,10 @@ void get_global_var_info(struct thread *thread, struct map_symbol *ms, u64 ip,
    struct disasm_line *dl, u8 cpumode, u64 *var_addr,
    const char **var_name, int *poffset);

    +void get_percpu_var_info(struct thread *thread, struct map_symbol *ms,
    + u8 cpumode, u64 var_addr, const char **var_name,
    + int *poffset);
    +
    /**
    * struct annotated_basic_block - Basic block of instructions
    * @list: List node
    --
    2.43.0.594.gd9cf4e227d-goog

    \
     
     \ /
      Last update: 2024-05-27 14:46    [W:4.024 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site