From: Namhyung Kim <namhyung@kernel.org>
To: Ian Rogers <irogers@google.com>
Cc: acme@kernel.org, adrian.hunter@intel.com, james.clark@linaro.org,
jolsa@kernel.org, linux-kernel@vger.kernel.org,
linux-perf-users@vger.kernel.org, mingo@redhat.com,
peterz@infradead.org, rcu@vger.kernel.org
Subject: Re: [PATCH v3 0/6] perf bpf-filter / lock contention: Add lock_held() sample filter and RCU/SRCU support
Date: Mon, 19 Oct 2026 00:00:55 -0700 [thread overview]
Message-ID: <atXAJ4FMCq21dPmn@z2> (raw)
In-Reply-To: <20261018053710.2572636-1-irogers@google.com>
Hi Ian,
On Sat, Oct 17, 2026 at 10:37:04PM -0700, Ian Rogers wrote:
> This series adds a new BPF sample filter predicate, `lock_held(<lock>)`
> (along with `lock_held_read(<lock>)` / `lock_held_shared(<lock>)`,
> `lock_held_write(<lock>)` / `lock_held_exclusive(<lock>)`, and `:R` / `:W`
> mode suffixes), to `perf record --filter`, allowing perf event samples to
> be recorded only when a specified kernel lock is held (or not held with
> `!`) by the running kernel thread or CPU. It also extends both
> `lock_held()` and `perf lock contention --use-bpf` to support RCU and
> SRCU, and fixes a pre-existing `lock_stat` filtering bug in `perf lock
> contention`.
Awesome! Looks really useful!
>
> For example:
>
> # perf record -a -g -e cycles --filter 'lock_held(&cgroup_mutex)' -- ...
> # perf record -a -g -e cycles --filter 'lock_held_read(&mmap_lock)' -- ...
> # perf record -a -g -e cycles --filter 'lock_held(&mmap_lock:W)' -- ...
> # perf record -a -g -e cycles --filter 'lock_held_read(rcu)' -- ...
> # perf lock contention -a -b -Y rcu,srcu -- sleep 1
>
> An important use-case is detecting memory allocations or direct memory
> reclaim occurring while kernel locks are held, which can stall lock
> waiters for extended periods under memory pressure:
>
> # Direct memory reclaim triggered while holding any mutex or rwsem:
> # perf record -a -g -e vmscan:mm_vmscan_direct_reclaim_begin \
> --filter 'lock_held(mutex) || lock_held(rwsem)' -- ...
>
> # Page allocations permitted to enter direct reclaim (__GFP_DIRECT_RECLAIM)
> # while holding a mutex or rwsem:
> # perf record -a -g -e kmem:mm_page_alloc \
> --filter 'gfp_flags & 0x400' \
> --filter 'lock_held(mutex) || lock_held(rwsem)' -- ...
It seems the first filter is processed by the kernel tracepoint
filtering logic and the second is passed to the BPF filter, right?
Does the ordering matter?
>
> # Major page faults occurring while holding a mutex or rwsem:
> # perf record -a -g -e major-faults \
> --filter 'lock_held(mutex) || lock_held(rwsem)' -- ...
>
> Supported `<lock>` specifications match `perf lock contention`:
> - Global/static kernel lock symbols (with or without leading `&`, e.g.
> `lock_held(&cgroup_mutex)` or `lock_held(cgroup_mutex)`)
It used to have no '&' for global locks. While having it is more
natural, I think it's better to leave it for slab locks so that we can
distinguish them easily.
> - Hexadecimal kernel lock addresses
> - Slab cache names prefixed with `&` (e.g. `lock_held(&dentry)`,
> `lock_held_read(&dentry)`)
> - Well-known per-process, semi-global, and RCU locks: `mmap_lock`,
> `siglock`, `rq_lock`, `zone_lock`, `rcu`, `rcu-trace`
> - Lock types and flags: `mutex`, `spinlock`, `rwsem`, `rwsem:R`,
> `rwsem:W`, `rwlock`, `rwlock:R`, `rwlock:W`, `rt-mutex`,
> `percpu-rwsem`, `pcpu-sem:W`, `srcu`, `srcu:R`, `srcu:W`, `rcu:R`,
> `rcu:W`, `semaphore`
>
> Limitations and weaknesses in determining whether a lock is held:
> - Inlined lock/unlock operations:
> - When the kernel is configured to inline spinlock or rwlock operations
> (`CONFIG_INLINE_SPIN_LOCK`, `CONFIG_INLINE_READ_LOCK`,
> `CONFIG_INLINE_WRITE_LOCK`, `!CONFIG_UNINLINE_SPIN_UNLOCK`,
> `CONFIG_INLINE_*_UNLOCK*`, etc.), `_raw_spin_lock*` /
> `_raw_spin_unlock*` and `_raw_read_lock*` / `_raw_write_lock*` are
> inlined into callers and have no BTF function entry points for
> `fentry`/`fexit` to attach to. `configure_lock_progs()` verifies that
> both acquire and release entry points exist in BTF before enabling a
> lock family.
> - Fast-path `percpu_down_read()` / `percpu_up_read()` and
> `srcu_read_lock_fast()` / `srcu_read_unlock_fast()` are inlined
> per-CPU counter increments without function calls, so only
> `percpu_down_write()` / `percpu_up_write()` and out-of-line
> `__srcu_read_lock*()` / `__srcu_read_unlock*()` can be hooked.
> - On `!CONFIG_PREEMPT_RCU` kernels, `rcu_read_lock()` compiles to
> `preempt_disable()` and does not maintain
> `current->rcu_read_lock_nesting` in `task_struct`, so `lock_held(rcu)`
> read-side inspection requires `CONFIG_PREEMPT_RCU`.
Looks ok. What happens if user specified unsupported locks - e.g. rcu:R
on !CONFIG_PREEMPT_RCU.
> - Lack of an inspectable owner field on non-exclusive / spinning locks:
> - While `struct mutex`, `struct rt_mutex`, and write-locked
> `struct rw_semaphore` store the owning `task_struct *` in `lock->owner`
> (allowing `perf_sample_filter` to inspect kernel memory directly on
> sample overflow when filtering by lock address), spinlocks, rwlocks,
> semaphores, SRCU, and reader-locked `rw_semaphore`s (where
> `__up_read()` does not clear `sem->owner` when `!CONFIG_DEBUG_RWSEMS`)
> do not maintain an authoritative per-task owner pointer.
So do you use the owner field for the supported locks? Then maybe it
can skip tracing mutex_lock() and mutex_unlock(). Does it already do?
> - Tracking these locks (as well as slab-cache and lock-type filters)
> relies on `fexit` (acquire) and `fentry` (release) BPF hooks
> maintaining the `held_locks` BPF hash map:
> - Any such lock already held before `perf record` attaches its BPF
> programs will not be present in `held_locks` until it is released
> and re-acquired.
Right, but this can be mitigated when it runs for long.
> - The attached `fentry`/`fexit` hooks execute on every kernel lock
> acquire and release for the hooked lock family across the system,
> adding tracing overhead outside of perf sample handling.
This is a real problem. As it touches the fastpath it can cause a lot
of overhead if locking is frequent. But having this capability would be
very useful anyway!
Thanks,
Namhyung
>
> Patch overview:
> 1. "perf lock contention: Share common BPF and lock type definitions in
> lock_data.h": Moves `lock_type_table` to `util/lock-contention.c` and
> `LCB_F_*` flags, CO-RE structs, and common BPF lock helpers
> (`get_lock_owner`, `get_current_mmap_lock`, `get_current_siglock`,
> `get_lock_addr`, `check_lock_type`, `do_collect_lock_syms`,
> `do_slab_cache_iter`) into `tools/perf/util/bpf_skel/lock_data.h`.
> 2. "perf bpf-filter: Add lock_held() sample filter": Implements
> `lock_held()`, `lock_held_read()`/`lock_held_shared()`,
> `lock_held_write()`/`lock_held_exclusive()`, and `:R`/`:W` mode
> suffixes using direct lock owner inspection where possible (`mutex`,
> `rt_mutex`, write-locked `rw_semaphore`) and a `held_locks` BPF map
> updated by selectively attached `fentry`/`fexit` hooks, supporting
> both PMU/software events (`SEC("perf_event")`) and tracepoint events
> (`SEC("tracepoint")`).
> 3. "perf test: Add tests for lock_held() BPF sample filter": Adds unit
> tests in `tests/parse-events.c` and shell tests in
> `tests/shell/record_bpf_filter.sh`.
> 4. "perf bpf-filter: Extend lock_held() to support RCU, Tasks Trace RCU,
> and SRCU": Supports `rcu` (`rcu:R` via direct
> `current->rcu_read_lock_nesting` inspection with zero tracing hooks;
> `rcu:W` via `synchronize_rcu*()` / `rcu_barrier()` hooks),
> `rcu-trace` (via `current->trc_reader_nesting`), and `srcu`
> (`srcu:R` via `__srcu_read_lock*` / `__srcu_read_unlock*`; `srcu:W`
> via `synchronize_srcu*()` / `srcu_barrier()`).
> 5. "perf lock contention: Extend BPF lock contention to RCU and SRCU":
> Extends `perf lock contention --use-bpf` to track RCU and SRCU
> grace-period and barrier waits (`-Y rcu`, `-Y srcu`, `-L rcu`).
> 6. "perf lock contention: Filter events before creating lock_stat":
> Fixes `report_lock_contention_begin_event()` in `builtin-lock.c` to
> apply `-Y`, `-L`, and `-S` filters before calling
> `lock_stat_findnew()`.
>
> Changes in v3:
> - Move the writer-only `rw_semaphore` check out of `get_lock_owner()` in
> `lock_data.h` into `is_rwsem_writer_owner()` in `sample_filter.bpf.c`
> so `perf lock contention -b -o` still reports reader owners when a
> writer contends on a reader-owned `rw_semaphore`, and scope
> `is_direct_lock_owner()` by lock type (`PBF_LOCK_DIRECT_MUTEX`,
> `PBF_LOCK_DIRECT_RWSEM`, `PBF_LOCK_DIRECT_RTMUTEX`).
> - Add `SEC("tracepoint") int perf_tp_sample_filter(void *ctx)` so BPF
> sample filters (`lock_held()`, `uid`, `gid`, etc.) can attach to
> `PERF_TYPE_TRACEPOINT` events (such as `kmem:mm_page_alloc` and
> `vmscan:mm_vmscan_direct_reclaim_begin`), check `libbpf_get_error()`
> when attaching, and document memory allocation / direct reclaim
> filtering with `lock_held()`.
> - Return early in `init_numa_data()` in `bpf-filter.c` when `node_data`
> cannot be resolved and check `node_data_addr != 0` in
> `do_collect_zone_lock()`.
> - Avoid double-counting `_raw_read_lock_irq` / `_raw_read_lock_bh` in
> `sample_filter.bpf.c` on `CONFIG_GENERIC_LOCKBREAK=y &&
> !CONFIG_DEBUG_LOCK_ALLOC` kernels where they call
> `_raw_read_lock_irqsave()`.
> - Offset `rcu_state_addr` by 1 byte so it is distinct from
> `&rcu_state.node[0].lock` at offset 0 of `rcu_state`, and pass `bool
> is_rcu` to `do_contention_end()` in `lock_contention.bpf.c` so
> `tp_btf/contention_end` and RCU/SRCU `fexit` hooks never cross-match
> timestamp maps.
>
> Changes in v2:
> - Guard `BPF_CORE_READ(mutex, owner.counter)` with `bpf_core_field_exists`
> and fall back to `struct rt_mutex_base` in `get_lock_owner()` so CO-RE
> relocation succeeds on `CONFIG_PREEMPT_RT=y` kernels.
> - Add `CONFIG_DEBUG_LOCK_ALLOC=y` lock entry points
> (`_mutex_lock_nest_lock`, `_mutex_lock_killable`,
> `_mutex_trylock_nest_lock`, `_down_write_nest_lock`,
> `_raw_spin_lock_nest_lock`, `_rt_mutex_lock_nest_lock`) to
> `sample_filter.bpf.c` and `lock_progs[]`.
> - Verify in `supported_lock_prog_groups()` that both acquire and all
> unlock BTF entry points exist for a lock family before enabling its
> tracing hooks, preventing acquire-only attachment when spinlock/rwlock
> unlock functions are inlined.
> - Enable `LOCK_PROG_PERCPU_RWSEM` alongside `LOCK_PROG_RWSEM_WRITE` when
> a symbol name ends in `rwsem` (such as `cgroup_threadgroup_rwsem`).
> - Gate `record_lock_acquired(ctx, LCB_F_READ)` in `fexit_downgrade_write`
> on `track_rwsem_read` and verify non-zero read/write counts in
> `record_lock_released_addr()` before decrementing aggregate slab/type
> counts.
> - Adjust stack skip depth by 2 for `fentry` RCU/SRCU programs in
> `lock_contention.bpf.c` and recognize `synchronize_rcu*`,
> `synchronize_srcu*`, `rcu_barrier`, and `srcu_barrier` in
> `machine__is_lock_function()`.
> - Add patch 6 fixing `report_lock_contention_begin_event()` to check
> type, address, and callstack filters before creating `lock_stat`
> entries.
>
> Assisted-by: Antigravity:gemini-3.1-pro
>
> Ian Rogers (6):
> perf lock contention: Share common BPF and lock type definitions in
> lock_data.h
> perf bpf-filter: Add lock_held() sample filter
> perf test: Add tests for lock_held() BPF sample filter
> perf bpf-filter: Extend lock_held() to support RCU, Tasks Trace RCU,
> and SRCU
> perf lock contention: Extend BPF lock contention to RCU and SRCU
> perf lock contention: Filter events before creating lock_stat
>
> tools/perf/Documentation/perf-lock.txt | 7 +-
> tools/perf/Documentation/perf-record.txt | 64 +-
> tools/perf/builtin-lock.c | 88 +-
> tools/perf/tests/parse-events.c | 121 ++
> tools/perf/tests/shell/lock_contention.sh | 14 +
> tools/perf/tests/shell/record_bpf_filter.sh | 134 ++
> tools/perf/util/bpf-filter.c | 1271 ++++++++++++++++-
> tools/perf/util/bpf-filter.h | 13 +
> tools/perf/util/bpf-filter.l | 31 +-
> tools/perf/util/bpf-filter.y | 46 +-
> tools/perf/util/bpf_lock_contention.c | 171 ++-
> .../perf/util/bpf_skel/lock_contention.bpf.c | 448 +++---
> tools/perf/util/bpf_skel/lock_data.h | 360 ++++-
> tools/perf/util/bpf_skel/sample-filter.h | 77 +
> tools/perf/util/bpf_skel/sample_filter.bpf.c | 1225 ++++++++++++++++
> tools/perf/util/bpf_skel/vmlinux/vmlinux.h | 7 +
> tools/perf/util/lock-contention.c | 22 +
> tools/perf/util/lock-contention.h | 15 +
> tools/perf/util/machine.c | 11 +
> tools/perf/util/parse-events.c | 3 +-
> 20 files changed, 3741 insertions(+), 387 deletions(-)
>
> --
> 2.56.0.212.g129ede20d9-goog
>
next prev parent reply other threads:[~2026-10-19 7:00 UTC|newest]
Thread overview: 77+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-17 5:45 [PATCH v1 0/5] perf bpf-filter / lock contention: Add lock_held() sample filter and RCU/SRCU support Ian Rogers
2026-10-17 5:45 ` [PATCH v1 1/5] perf lock contention: Share common BPF and lock type definitions in lock_data.h Ian Rogers
2026-10-17 5:52 ` sashiko-bot
2026-10-17 5:45 ` [PATCH v1 2/5] perf bpf-filter: Add lock_held() sample filter Ian Rogers
2026-10-17 6:09 ` sashiko-bot
2026-10-17 5:45 ` [PATCH v1 3/5] perf test: Add tests for lock_held() BPF " Ian Rogers
2026-10-17 5:49 ` sashiko-bot
2026-10-17 5:45 ` [PATCH v1 4/5] perf bpf-filter: Extend lock_held() to support RCU, Tasks Trace RCU, and SRCU Ian Rogers
2026-10-17 5:56 ` sashiko-bot
2026-10-17 5:45 ` [PATCH v1 5/5] perf lock contention: Extend BPF lock contention to RCU " Ian Rogers
2026-10-17 6:08 ` sashiko-bot
2026-10-17 17:14 ` [PATCH v2 0/6] perf bpf-filter / lock contention: Add lock_held() sample filter and RCU/SRCU support Ian Rogers
2026-10-17 17:14 ` [PATCH v2 1/6] perf lock contention: Share common BPF and lock type definitions in lock_data.h Ian Rogers
2026-10-17 17:31 ` sashiko-bot
2026-10-17 17:14 ` [PATCH v2 2/6] perf bpf-filter: Add lock_held() sample filter Ian Rogers
2026-10-17 17:35 ` sashiko-bot
2026-10-17 17:14 ` [PATCH v2 3/6] perf test: Add tests for lock_held() BPF " Ian Rogers
2026-10-17 17:17 ` sashiko-bot
2026-10-17 17:14 ` [PATCH v2 4/6] perf bpf-filter: Extend lock_held() to support RCU, Tasks Trace RCU, and SRCU Ian Rogers
2026-10-17 17:25 ` sashiko-bot
2026-10-17 17:14 ` [PATCH v2 5/6] perf lock contention: Extend BPF lock contention to RCU " Ian Rogers
2026-10-17 17:30 ` sashiko-bot
2026-10-17 17:14 ` [PATCH v2 6/6] perf lock contention: Filter events before creating lock_stat Ian Rogers
2026-10-17 17:17 ` sashiko-bot
2026-10-18 5:37 ` [PATCH v3 0/6] perf bpf-filter / lock contention: Add lock_held() sample filter and RCU/SRCU support Ian Rogers
2026-10-18 5:37 ` [PATCH v3 1/6] perf lock contention: Share common BPF and lock type definitions in lock_data.h Ian Rogers
2026-10-18 5:50 ` sashiko-bot
2026-10-18 5:37 ` [PATCH v3 2/6] perf bpf-filter: Add lock_held() sample filter Ian Rogers
2026-10-18 6:12 ` sashiko-bot
2026-10-18 5:37 ` [PATCH v3 3/6] perf test: Add tests for lock_held() BPF " Ian Rogers
2026-10-18 5:41 ` sashiko-bot
2026-10-18 5:37 ` [PATCH v3 4/6] perf bpf-filter: Extend lock_held() to support RCU, Tasks Trace RCU, and SRCU Ian Rogers
2026-10-18 5:51 ` sashiko-bot
2026-10-18 5:37 ` [PATCH v3 5/6] perf lock contention: Extend BPF lock contention to RCU " Ian Rogers
2026-10-18 5:48 ` sashiko-bot
2026-10-18 5:37 ` [PATCH v3 6/6] perf lock contention: Filter events before creating lock_stat Ian Rogers
2026-10-18 5:40 ` sashiko-bot
2026-10-19 7:00 ` Namhyung Kim [this message]
2026-10-19 19:08 ` [PATCH v3 0/6] perf bpf-filter / lock contention: Add lock_held() sample filter and RCU/SRCU support Ian Rogers
2026-10-19 22:09 ` [PATCH v4 0/7] " Ian Rogers
2026-10-19 22:09 ` [PATCH v4 1/7] perf lock contention: Filter events before creating lock_stat Ian Rogers
2026-10-19 22:14 ` sashiko-bot
2026-10-20 4:34 ` Namhyung Kim
2026-10-19 22:09 ` [PATCH v4 2/7] perf bpf-filter: Support BPF sample filters on tracepoint events Ian Rogers
2026-10-19 22:26 ` sashiko-bot
2026-10-20 5:41 ` Namhyung Kim
2026-10-20 15:30 ` Ian Rogers
2026-10-20 22:29 ` Namhyung Kim
2026-10-19 22:09 ` [PATCH v4 3/7] perf lock contention: Share common BPF and lock type definitions in lock_data.h Ian Rogers
2026-10-19 22:17 ` sashiko-bot
2026-10-19 22:09 ` [PATCH v4 4/7] perf bpf-filter: Add lock_held() sample filter Ian Rogers
2026-10-19 22:28 ` sashiko-bot
2026-10-19 22:09 ` [PATCH v4 5/7] perf test: Add tests for lock_held() BPF " Ian Rogers
2026-10-19 22:12 ` sashiko-bot
2026-10-19 22:09 ` [PATCH v4 6/7] perf bpf-filter: Extend lock_held() to support RCU, Tasks Trace RCU, and SRCU Ian Rogers
2026-10-19 22:19 ` sashiko-bot
2026-10-19 22:09 ` [PATCH v4 7/7] perf lock contention: Extend BPF lock contention to RCU " Ian Rogers
2026-10-19 22:19 ` sashiko-bot
2026-10-20 20:58 ` [PATCH v5 0/8] perf bpf-filter / lock contention: Add lock_held() sample filter and RCU/SRCU support Ian Rogers
2026-10-20 20:58 ` [PATCH v5 1/8] perf lock contention: Filter events before creating lock_stat Ian Rogers
2026-10-20 22:38 ` sashiko-bot
2026-10-20 20:58 ` [PATCH v5 2/8] perf bpf-filter: Fix bpf_link leak by using PERF_EVENT_IOC_SET_BPF Ian Rogers
2026-10-20 22:41 ` sashiko-bot
2026-10-20 20:58 ` [PATCH v5 3/8] perf bpf-filter: Support BPF sample filters on tracepoint events Ian Rogers
2026-10-20 22:57 ` sashiko-bot
2026-10-20 20:58 ` [PATCH v5 4/8] perf lock contention: Share common BPF and lock type definitions in lock_data.h Ian Rogers
2026-10-20 22:42 ` Namhyung Kim
2026-10-20 23:02 ` sashiko-bot
2026-10-20 20:58 ` [PATCH v5 5/8] perf bpf-filter: Add lock_held() sample filter Ian Rogers
2026-10-20 22:49 ` Namhyung Kim
2026-10-20 23:17 ` sashiko-bot
2026-10-20 20:58 ` [PATCH v5 6/8] perf test: Add tests for lock_held() BPF " Ian Rogers
2026-10-20 23:20 ` sashiko-bot
2026-10-20 20:58 ` [PATCH v5 7/8] perf bpf-filter: Extend lock_held() to support RCU, Tasks Trace RCU, and SRCU Ian Rogers
2026-10-20 23:29 ` sashiko-bot
2026-10-20 20:58 ` [PATCH v5 8/8] perf lock contention: Extend BPF lock contention to RCU " Ian Rogers
2026-10-20 23:37 ` sashiko-bot
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=atXAJ4FMCq21dPmn@z2 \
--to=namhyung@kernel.org \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=irogers@google.com \
--cc=james.clark@linaro.org \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=rcu@vger.kernel.org \
/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.