From: Namhyung Kim <namhyung@kernel.org>
To: Yuzhuo Jing <yuzhuo@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>,
Arnaldo Carvalho de Melo <acme@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Jiri Olsa <jolsa@kernel.org>, Ian Rogers <irogers@google.com>,
Adrian Hunter <adrian.hunter@intel.com>,
Liang Kan <kan.liang@linux.intel.com>,
Yuzhuo Jing <yzj@umich.edu>,
Andrea Parri <parri.andrea@gmail.com>,
Palmer Dabbelt <palmer@rivosinc.com>,
Charlie Jenkins <charlie@rivosinc.com>,
Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
Kumar Kartikeya Dwivedi <memxor@gmail.com>,
Alexei Starovoitov <ast@kernel.org>,
Barret Rhoden <brho@google.com>,
Alexandre Ghiti <alexghiti@rivosinc.com>,
Guo Ren <guoren@kernel.org>,
linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org
Subject: Re: [PATCH v1 4/7] tools: Implement userspace per-cpu
Date: Wed, 30 Jul 2025 22:07:40 -0700 [thread overview]
Message-ID: <aIr6HEiqfYhgaec6@google.com> (raw)
In-Reply-To: <20250729022640.3134066-5-yuzhuo@google.com>
On Mon, Jul 28, 2025 at 07:26:37PM -0700, Yuzhuo Jing wrote:
> Implement userspace per-cpu for imported kernel code. Compared with
> simple thread-local definition, the kernel per-cpu provides 1) a
> guarantee of static lifetime even when thread exits, and 2) the ability
> to access other CPU's per-cpu data.
>
> This patch adds an alternative implementation and interface for
> userspace per-cpu. The kernel implementation uses special ELF sections
> and offset calculation. For simplicity, this version defines a
> PERCPU_MAX length global array for each per-cpu data, and uses a
> thread-local cpu id for indexing.
>
> Signed-off-by: Yuzhuo Jing <yuzhuo@google.com>
> ---
> tools/include/linux/compiler_types.h | 3 +
> tools/include/linux/percpu-simulate.h | 128 ++++++++++++++++++++++++++
> 2 files changed, 131 insertions(+)
> create mode 100644 tools/include/linux/percpu-simulate.h
>
> diff --git a/tools/include/linux/compiler_types.h b/tools/include/linux/compiler_types.h
> index 9a2a2f8d7b6c..46550c500b8c 100644
> --- a/tools/include/linux/compiler_types.h
> +++ b/tools/include/linux/compiler_types.h
> @@ -31,6 +31,9 @@
> # define __cond_lock(x,c) (c)
> #endif /* __CHECKER__ */
>
> +/* Per-cpu checker flag does not use address space attribute in userspace */
> +#define __percpu
> +
> /*
> * __unqual_scalar_typeof(x) - Declare an unqualified scalar type, leaving
> * non-scalar types unchanged.
> diff --git a/tools/include/linux/percpu-simulate.h b/tools/include/linux/percpu-simulate.h
> new file mode 100644
> index 000000000000..a6af2f2211eb
> --- /dev/null
> +++ b/tools/include/linux/percpu-simulate.h
> @@ -0,0 +1,128 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Userspace implementation of per_cpu_ptr for adapted kernel code.
> + *
> + * Userspace code does not have and does not need a per-cpu concept, but
> + * instead can declare variables as thread-local. However, the kernel per-cpu
> + * further provides 1) the guarantee of static lifetime when thread exits, and
> + * 2) the ability to access other CPU's per-cpu data. This file provides a
> + * simple implementation of such functionality, but with slightly different
> + * APIs and without linker script changes.
> + *
> + * 2025 Yuzhuo Jing <yuzhuo@google.com>
> + */
> +#ifndef __PERCPU_SIMULATE_H__
> +#define __PERCPU_SIMULATE_H__
> +
> +#include <assert.h>
> +
> +#include <linux/compiler.h>
> +#include <linux/types.h>
> +
> +/*
> + * The maximum supported number of CPUs. Per-cpu variables are defined as a
> + * PERCPU_MAX length array, indexed by a thread-local cpu id.
> + */
> +#define PERCPU_MAX 4096
> +
> +#ifdef ASSERT_PERCPU
> +#define __check_cpu_id(cpu) \
> +({ \
> + u32 cpuid = (cpu); \
> + assert(cpuid < PERCPU_MAX); \
> + cpuid; \
> +})
> +#else
> +#define __check_cpu_id(cpu) (cpu)
> +#endif
> +
> +/*
> + * Use weak symbol: only define __thread_per_cpu_id variable if any perf tool
> + * includes this header file.
> + */
> +_Thread_local u32 __thread_per_cpu_id __weak;
Is there any overhead (or some indirection) when using the thread local
variable?
> +
> +static inline u32 get_this_cpu_id(void)
> +{
> + return __thread_per_cpu_id;
> +}
> +
> +/*
> + * The user code must call this function inside of each thread that uses
> + * per-cpu data structures. The user code can choose an id of their choice,
> + * but must ensure each thread uses a different id.
> + *
> + * Safety: asserts CPU id smaller than PERCPU_MAX if ASSERT_PERCPU is defined.
> + */
> +static inline void set_this_cpu_id(u32 id)
> +{
> + __thread_per_cpu_id = __check_cpu_id(id);
> +}
> +
> +/*
> + * Declare a per-cpu data structure. This only declares the data type and
> + * array length. Different per-cpu data are differentiated by a key (identifer).
> + *
> + * Different from the kernel version, this API must be called before the actual
> + * definition (i.e. DEFINE_PER_CPU_ALIGNED).
> + *
> + * Note that this implementation does not support prepending static qualifier,
> + * or appending assignment expressions.
> + */
> +#define DECLARE_PER_CPU_ALIGNED(key, type, data) \
> + extern struct __percpu_type_##key { \
> + type data; \
> + } __percpu_data_##key[PERCPU_MAX]
> +
> +/*
> + * Define the per-cpu data storage for a given key. This uses a previously
> + * defined data type in DECLARE_PER_CPU_ALIGNED.
> + *
> + * Different from the kernel version, this API only accepts a key name.
> + */
> +#define DEFINE_PER_CPU_ALIGNED(key) \
> + struct __percpu_type_##key __percpu_data_##key[PERCPU_MAX]
How do these APIs guarantee the alignment?
Thanks,
Namhyung
> +
> +#define __raw_per_cpu_value(key, field, cpu) \
> + (__percpu_data_##key[cpu].field)
> +
> +/*
> + * Get a pointer of per-cpu data for a given key.
> + *
> + * Different from the kernel version, users of this API don't need to pass the
> + * address of the base variable (through `&varname').
> + *
> + * Safety: asserts CPU id smaller than PERCPU_MAX if ASSERT_PERCPU is defined.
> + */
> +#define per_cpu_ptr(key, field, cpu) (&per_cpu_value(key, field, cpu))
> +#define this_cpu_ptr(key, field) (&this_cpu_value(key, field))
> +
> +/*
> + * Additional APIs for direct value access. Effectively, `*per_cpu_ptr(...)'.
> + *
> + * Safety: asserts CPU id smaller than PERCPU_MAX if ASSERT_PERCPU is defined.
> + */
> +#define per_cpu_value(key, field, cpu) \
> + (__raw_per_cpu_value(key, field, __check_cpu_id(cpu)))
> +#define this_cpu_value(key, field) \
> + (__raw_per_cpu_value(key, field, __thread_per_cpu_id))
> +
> +/*
> + * Helper functions of simple per-cpu operations.
> + *
> + * The kernel version differentiates __this_cpu_* from this_cpu_* for
> + * preemption/interrupt-safe contexts, but the userspace version defines them
> + * as the same.
> + */
> +
> +#define __this_cpu_add(key, field, val) (this_cpu_value(key, field) += (val))
> +#define __this_cpu_sub(key, field, val) (this_cpu_value(key, field) -= (val))
> +#define __this_cpu_inc(key, field) (++this_cpu_value(key, field))
> +#define __this_cpu_dec(key, field) (--this_cpu_value(key, field))
> +
> +#define this_cpu_add __this_cpu_add
> +#define this_cpu_sub __this_cpu_sub
> +#define this_cpu_inc __this_cpu_inc
> +#define this_cpu_dec __this_cpu_dec
> +
> +#endif /* __PERCPU_SIMULATE_H__ */
> --
> 2.50.1.487.gc89ff58d15-goog
>
next prev parent reply other threads:[~2025-07-31 5:07 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-29 2:26 [PATCH v1 0/7] perf bench: Add qspinlock benchmark Yuzhuo Jing
2025-07-29 2:26 ` [PATCH v1 1/7] tools: Import cmpxchg and xchg functions Yuzhuo Jing
2025-07-31 4:52 ` Namhyung Kim
2025-08-08 6:11 ` kernel test robot
2025-07-29 2:26 ` [PATCH v1 2/7] tools: Import smp_cond_load and atomic_cond_read Yuzhuo Jing
2025-07-29 2:26 ` [PATCH v1 3/7] tools: Partial import of prefetch.h Yuzhuo Jing
2025-07-31 4:54 ` Namhyung Kim
2025-07-29 2:26 ` [PATCH v1 4/7] tools: Implement userspace per-cpu Yuzhuo Jing
2025-07-31 5:07 ` Namhyung Kim [this message]
2025-07-29 2:26 ` [PATCH v1 5/7] perf bench: Import qspinlock from kernel Yuzhuo Jing
2025-07-29 2:26 ` [PATCH v1 6/7] perf bench: Add 'bench sync qspinlock' subcommand Yuzhuo Jing
2025-07-31 5:16 ` Namhyung Kim
2025-07-31 13:19 ` Yuzhuo Jing
2025-07-29 2:26 ` [PATCH v1 7/7] perf bench sync: Add latency histogram functionality Yuzhuo Jing
2025-07-31 5:18 ` Namhyung Kim
2025-07-31 5:24 ` Namhyung Kim
2025-07-31 4:51 ` [PATCH v1 0/7] perf bench: Add qspinlock benchmark Namhyung Kim
2025-08-04 14:28 ` Mark Rutland
2025-09-16 14:18 ` Peter Zijlstra
2025-09-16 17:00 ` Ian Rogers
2025-09-16 20:38 ` Peter Zijlstra
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=aIr6HEiqfYhgaec6@google.com \
--to=namhyung@kernel.org \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=alexghiti@rivosinc.com \
--cc=ast@kernel.org \
--cc=bigeasy@linutronix.de \
--cc=brho@google.com \
--cc=charlie@rivosinc.com \
--cc=guoren@kernel.org \
--cc=irogers@google.com \
--cc=jolsa@kernel.org \
--cc=kan.liang@linux.intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=memxor@gmail.com \
--cc=mingo@redhat.com \
--cc=palmer@rivosinc.com \
--cc=parri.andrea@gmail.com \
--cc=peterz@infradead.org \
--cc=yuzhuo@google.com \
--cc=yzj@umich.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.