From: Namhyung Kim <namhyung@kernel.org>
To: Tengda Wu <wutengda@huaweicloud.com>
Cc: james.clark@linaro.org, xueshuai@linux.alibaba.com,
Li Huafei <lihuafei1@huawei.com>,
Peter Zijlstra <peterz@infradead.org>,
leo.yan@linux.dev, Ian Rogers <irogers@google.com>,
Kim Phillips <kim.phillips@arm.com>,
Mark Rutland <mark.rutland@arm.com>,
Arnaldo Carvalho de Melo <acme@kernel.org>,
Ingo Molnar <mingo@redhat.com>, Bill Wendling <morbo@google.com>,
Nick Desaulniers <nick.desaulniers+lkml@gmail.com>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Adrian Hunter <adrian.hunter@intel.com>,
Zecheng Li <zli94@ncsu.edu>,
linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org,
llvm@lists.linux.dev
Subject: Re: [PATCH v3 20/21] perf annotate-arm64: Support per-cpu variable access tracking
Date: Thu, 9 Jul 2026 00:29:20 -0700 [thread overview]
Message-ID: <ak9N0CY1sAtGt47I@z2> (raw)
In-Reply-To: <20260701035355.752944-21-wutengda@huaweicloud.com>
On Wed, Jul 01, 2026 at 03:53:54AM +0000, Tengda Wu wrote:
> Extend update_insn_state() for arm64 to handle per-cpu variable
> addressing.
>
> On arm64, per-cpu variables are accessed by adding a per-cpu offset
> (typically from the '__per_cpu_offset' array) to the address of a global
> variable or a local variable with '__percpu' modifier(e.g.,
> 's32 __percpu *counters' in struct percpu_counter). This results in
> instruction patterns like:
>
> ldr x0, [x6, x5] // Pattern A: direct load per-cpu instance
> add x0, x6, x5 // Pattern B: compute per-cpu address
>
> where x6 holds the per-cpu offset retrieved from:
>
> adrp x4, <page>
> add x4, x4, #offset // x4 = &__per_cpu_offset
> ldr x6, [x4, w0, sxtw #3] // x6 = __per_cpu_offset[cpu]
>
> and x5 is one of the following:
>
> case 1: global variable
> adrp x5, <page>
> add x5, x5, #offset // x5 = &global_var
>
> case 2: local variable with '__percpu' modifier
> ldr x1, [x25, #32] // x1 = local_percpu_ptr
>
> To handle such cases:
>
> 1. Identify per-cpu base initialization: Detect 'adrp+add' pairs that
> resolve to the '__per_cpu_offset' symbol and mark the destination
> register as TSR_KIND_PERCPU_BASE.
> 2. Propagate type information: During subsequent 'ldr' or 'add'
> instructions, if one register is TSR_KIND_PERCPU_BASE, attempt to
> resolve the type from the other register.
>
> A real-world example is shown below:
>
> ffff8000808f2d28 <cppc_set_perf>:
> ffff8000808f2d38: adrp x2, ffff800082033000
> ffff8000808f2d3c: add x5, x2, #0x3f8 // x5 = &__per_cpu_offset
> ffff8000808f2d44: adrp x2, ffff800081f73000
> ffff8000808f2d48: add x2, x2, #0x6b8 // x2 = &cpu_pcc_subspace_idx
> ffff8000808f2d6c: ldr x5, [x5, w0, sxtw #3] // x5 = __per_cpu_offset[cpu]
> * ffff8000808f2d80: ldr w23, [x5, x2] // per_cpu(cpu_pcc_subspace_idx, cpu)
>
> Before this commit, the tracker could not link x5 back to a per-cpu
> context, resulting in an incorrect data type resolution:
>
> adrp [10] global addr=0xffff800082033000 -> reg2
> add [14] global 0x3f8(reg2) -> reg5
> adrp [1c] global addr=0xffff800081f73000 -> reg2
> add [20] global 0x6b8(reg2) -> reg2
> ldr [44] global (reg5, reg0) -> reg5 type='long unsigned int[]' size=0x1000
> chk [58] reg5 offset=0 ok=1 kind=1 (long unsigned int[]) : Good!
> found by insn track: 0(reg5, reg2) type-offset=0
> final result: type='long unsigned int' size=0x8
>
> After this commit, the tracker correctly identifies the per-cpu flow and
> resolves the actual variable type:
>
> ldr [44] global (reg5, reg0) -> reg5 percpu base
> chk [58] reg5 offset=0 ok=1 kind=2 percpu var : retry
> chk [58] reg2 offset=0 ok=1 kind=7 global addr : Good!
> found by insn track: 0(reg5, reg2) type-offset=0
> final result: type='int' size=0x4
>
> Signed-off-by: Tengda Wu <wutengda@huaweicloud.com>
> ---
> .../perf/util/annotate-arch/annotate-arm64.c | 60 ++++++++++++++++++-
> tools/perf/util/annotate-data.c | 24 +++++++-
> 2 files changed, 82 insertions(+), 2 deletions(-)
>
> diff --git a/tools/perf/util/annotate-arch/annotate-arm64.c b/tools/perf/util/annotate-arch/annotate-arm64.c
> index 6f96e75d313d..ec6fd59d51a2 100644
> --- a/tools/perf/util/annotate-arch/annotate-arm64.c
> +++ b/tools/perf/util/annotate-arch/annotate-arm64.c
> @@ -462,6 +462,15 @@ static void update_load_insn_state(struct type_state *state,
> u64 ip = dloc->ms->sym->start + dl->al.offset;
> u64 addr = src_tsr.addr + reg_offset;
> int offset;
> + u8 kind;
> + const char *var_name = NULL;
> +
> + /* it might be per-cpu offset */
> + if (get_global_var_info(dloc, addr, &var_name, &offset) &&
> + !strcmp(var_name, "__per_cpu_offset"))
> + kind = TSR_KIND_PERCPU_BASE;
It seems you need to check if the target DSO is a kernel or a module by
calling `dso__kernel(map__dso(dloc->ms->map))` first.
Thanks,
Namhyung
> + else
> + kind = TSR_KIND_TYPE;
>
> if (!get_global_var_type(cu_die, dloc, ip, addr, &offset, &type_die) ||
> !die_get_member_type(&type_die, offset, &type_die)) {
> @@ -470,7 +479,7 @@ static void update_load_insn_state(struct type_state *state,
> }
>
> tsr->type = type_die;
> - tsr->kind = TSR_KIND_TYPE;
> + tsr->kind = kind;
> tsr->offset = 0;
> tsr->addr = 0;
> tsr->ok = true;
> @@ -484,6 +493,28 @@ static void update_load_insn_state(struct type_state *state,
> }
> pr_debug_type_name(&tsr->type, tsr->kind);
> }
> + /* Or check if it's a per-cpu access */
> + else if (src_tsr.kind == TSR_KIND_PERCPU_BASE) {
> + int reg2;
> +
> + if (!src->multi_regs || src->reg1 == src->reg2 ||
> + sreg == src->reg2 /* retried */) {
> + invalidate_reg_state(tsr);
> + goto out_adjust;
> + }
> +
> + reg2 = src->reg2;
> + if (!has_reg_type(state, reg2) || !state->regs[reg2].ok ||
> + (state->regs[reg2].kind != TSR_KIND_GLOBAL_ADDR &&
> + state->regs[reg2].kind != TSR_KIND_TYPE)) {
> + invalidate_reg_state(tsr);
> + goto out_adjust;
> + } else {
> + /* Treat percpu as array: resolve type from reg2 */
> + sreg = src->reg2;
> + goto retry;
> + }
> + }
> /* Or try another register if any */
> else if (src->multi_regs && src->reg1 != src->reg2 && sreg != src->reg2) {
> sreg = src->reg2;
> @@ -693,6 +724,33 @@ static void update_add_insn_state(struct type_state *state,
> pr_debug_dtp("add [%x] global %#x(reg%d) -> reg%d\n",
> insn_offset, reg_offset, sreg, dreg);
> }
> + /* Handle per-cpu base address calculation for per-cpu variables */
> + else if (src_tsr.kind == TSR_KIND_PERCPU_BASE) {
> + /*
> + * A per-cpu base acts like an array index. Adding it to
> + * a global variable or typed register should preserve
> + * the original variable's type. Inherit the type from
> + * the typed register.
> + */
> + if (!src->multi_regs || !has_reg_type(state, src->reg2) ||
> + !state->regs[src->reg2].ok ||
> + (state->regs[src->reg2].kind != TSR_KIND_GLOBAL_ADDR &&
> + state->regs[src->reg2].kind != TSR_KIND_TYPE)) {
> + invalidate_reg_state(tsr);
> + return;
> + }
> +
> + tsr->type = state->regs[src->reg2].type;
> + tsr->kind = state->regs[src->reg2].kind;
> + tsr->offset = state->regs[src->reg2].offset;
> + tsr->addr = state->regs[src->reg2].addr;
> + tsr->ok = state->regs[src->reg2].ok;
> +
> + pr_debug_dtp("add [%x] percpu (reg%d) -> reg%d",
> + insn_offset, sreg, dreg);
> + pr_debug_type_name(&tsr->type, tsr->kind);
> + return;
> + }
> /* Or try another register if any */
> else if (src->multi_regs && src->reg1 != src->reg2 && sreg != src->reg2) {
> sreg = src->reg2;
> diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c
> index 6fa5cd373a46..b0bf0437168b 100644
> --- a/tools/perf/util/annotate-data.c
> +++ b/tools/perf/util/annotate-data.c
> @@ -1252,11 +1252,33 @@ static enum type_match_result check_matching_type(struct type_state *state,
> }
>
> if (state->regs[reg].kind == TSR_KIND_PERCPU_BASE) {
> - u64 var_addr = dloc->op->offset;
> + u64 var_addr;
> int var_offset;
>
> pr_debug_dtp("percpu var");
>
> + if (arch__is_arm64(dloc->arch)) {
> + int reg2;
> +
> + if (!dloc->op->multi_regs ||
> + dloc->op->reg1 == dloc->op->reg2 || !retry)
> + return PERF_TMR_BAIL_OUT;
> +
> + reg2 = dloc->op->reg2;
> + if (!has_reg_type(state, reg2) ||
> + !state->regs[reg2].ok ||
> + (state->regs[reg2].kind != TSR_KIND_GLOBAL_ADDR &&
> + state->regs[reg2].kind != TSR_KIND_TYPE))
> + return PERF_TMR_NO_TYPE;
> +
> + pr_debug_dtp(" : retry\n");
> + retry = false;
> + reg = reg2;
> + goto again;
> + }
> +
> + var_addr = dloc->op->offset;
> +
> if (dloc->op->multi_regs) {
> int reg2 = dloc->op->reg2;
>
> --
> 2.34.1
>
next prev parent reply other threads:[~2026-07-09 7:29 UTC|newest]
Thread overview: 69+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-01 3:53 [PATCH v3 00/21] perf arm64: Support data type profiling Tengda Wu
2026-07-01 3:53 ` [PATCH v3 01/21] perf capstone: Fix kernel map reference count leak Tengda Wu
2026-07-09 5:57 ` Namhyung Kim
2026-07-10 21:49 ` Namhyung Kim
2026-07-01 3:53 ` [PATCH v3 02/21] perf capstone: Fix arm64 jump/adrp disassembly mismatch with objdump Tengda Wu
2026-07-01 4:07 ` sashiko-bot
2026-07-01 6:44 ` Tengda Wu
2026-07-09 6:10 ` Namhyung Kim
2026-07-01 3:53 ` [PATCH v3 03/21] perf llvm: Fix arm64 adrp instruction " Tengda Wu
2026-07-01 4:05 ` sashiko-bot
2026-07-01 6:45 ` Tengda Wu
2026-07-09 6:18 ` Namhyung Kim
2026-07-09 7:49 ` Tengda Wu
2026-07-01 3:53 ` [PATCH v3 04/21] perf annotate-arm64: Generalize arm64_mov__parse to support more instructions Tengda Wu
2026-07-01 4:03 ` sashiko-bot
2026-07-01 6:57 ` Tengda Wu
2026-07-01 3:53 ` [PATCH v3 05/21] perf annotate-arm64: Handle load and store instructions Tengda Wu
2026-07-01 4:07 ` sashiko-bot
2026-07-01 7:03 ` Tengda Wu
2026-07-01 3:53 ` [PATCH v3 06/21] perf dwarf-regs: Adapt get_dwarf_regnum() for arm64 Tengda Wu
2026-07-01 4:07 ` sashiko-bot
2026-07-01 7:14 ` Tengda Wu
2026-07-01 3:53 ` [PATCH v3 07/21] perf annotate: Adapt arch__dwarf_regnum() " Tengda Wu
2026-07-01 3:53 ` [PATCH v3 08/21] perf annotate: Introduce extract_op_location callback for arch-specific parsing Tengda Wu
2026-07-01 4:06 ` sashiko-bot
2026-07-01 7:29 ` Tengda Wu
2026-07-09 6:31 ` Namhyung Kim
2026-07-01 3:53 ` [PATCH v3 09/21] perf annotate-arm64: Implement extract_op_location() callback Tengda Wu
2026-07-01 4:10 ` sashiko-bot
2026-07-01 7:36 ` Tengda Wu
2026-07-01 3:53 ` [PATCH v3 10/21] perf annotate: Deduplicate overlapping ARM SPE events for data type profiling Tengda Wu
2026-07-01 4:06 ` sashiko-bot
2026-07-09 6:47 ` Namhyung Kim
2026-07-01 3:53 ` [PATCH v3 11/21] perf auxtrace: Set default period to 1 for PERF_ITRACE_PERIOD_INSTRUCTIONS type Tengda Wu
2026-07-01 4:05 ` sashiko-bot
2026-07-01 3:53 ` [PATCH v3 12/21] perf annotate-data: Extract invalidate_reg_state() as a common helper Tengda Wu
2026-07-01 3:53 ` [PATCH v3 13/21] perf annotate-arm64: Enable instruction tracking support Tengda Wu
2026-07-01 4:12 ` sashiko-bot
2026-07-01 7:56 ` Tengda Wu
2026-07-01 3:53 ` [PATCH v3 14/21] perf annotate-arm64: Support load instruction tracking Tengda Wu
2026-07-01 4:14 ` sashiko-bot
2026-07-01 8:37 ` Tengda Wu
2026-07-09 7:05 ` Namhyung Kim
2026-07-09 7:25 ` Tengda Wu
2026-07-01 3:53 ` [PATCH v3 15/21] perf annotate-arm64: Support store " Tengda Wu
2026-07-01 3:53 ` [PATCH v3 16/21] perf annotate-arm64: Support stack variable tracking Tengda Wu
2026-07-01 4:16 ` sashiko-bot
2026-07-09 7:11 ` Namhyung Kim
2026-07-01 3:53 ` [PATCH v3 17/21] perf annotate-arm64: Support 'mov' instruction tracking Tengda Wu
2026-07-01 4:21 ` sashiko-bot
2026-07-01 8:46 ` Tengda Wu
2026-07-09 7:17 ` Namhyung Kim
2026-07-01 3:53 ` [PATCH v3 18/21] perf annotate-arm64: Support 'add' " Tengda Wu
2026-07-01 4:16 ` sashiko-bot
2026-07-01 8:47 ` Tengda Wu
2026-07-01 3:53 ` [PATCH v3 19/21] perf annotate-arm64: Support 'adrp' instruction to track global variables Tengda Wu
2026-07-01 4:15 ` sashiko-bot
2026-07-01 8:48 ` Tengda Wu
2026-07-09 7:31 ` Namhyung Kim
2026-07-09 7:42 ` Tengda Wu
2026-07-01 3:53 ` [PATCH v3 20/21] perf annotate-arm64: Support per-cpu variable access tracking Tengda Wu
2026-07-01 4:18 ` sashiko-bot
2026-07-09 7:29 ` Namhyung Kim [this message]
2026-07-01 3:53 ` [PATCH v3 21/21] perf annotate-arm64: Support 'mrs' instruction to track 'current' pointer Tengda Wu
2026-07-01 4:16 ` sashiko-bot
2026-07-01 8:56 ` Tengda Wu
2026-07-09 7:36 ` Namhyung Kim
2026-07-09 5:54 ` [PATCH v3 00/21] perf arm64: Support data type profiling Namhyung Kim
2026-07-09 8:01 ` Tengda Wu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ak9N0CY1sAtGt47I@z2 \
--to=namhyung@kernel.org \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=irogers@google.com \
--cc=james.clark@linaro.org \
--cc=kim.phillips@arm.com \
--cc=leo.yan@linux.dev \
--cc=lihuafei1@huawei.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=llvm@lists.linux.dev \
--cc=mark.rutland@arm.com \
--cc=mingo@redhat.com \
--cc=morbo@google.com \
--cc=nick.desaulniers+lkml@gmail.com \
--cc=peterz@infradead.org \
--cc=wutengda@huaweicloud.com \
--cc=xueshuai@linux.alibaba.com \
--cc=zli94@ncsu.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.