Skip to content

perf/hw_breakpoint: Optimize for thousands of tasks

Marco Elver linux-perf-users linux-sh linuxppc-dev lkml 4 versions – Applied

Status from this message: The following commit has been merged into the perf/core branch of tip:

Get series with b4
b4 am [email protected]

Versions newest first · linked by author and title

  1. v4 Latest14 patches 0 repliesApplied
  2. v314 patches 34 repliesSuperseded
  3. v213 patches 18 repliesSuperseded
Earlier versions · 1
VersionPostedPatchesRepliesStatus
v18 patches25 repliesSuperseded

Changes in v4 from the cover letter

* Fix percpu_is_read_locked(): Due to spurious read_count increments in __percpu_down_read_trylock() if sem->block != 0, check that !sem->block (reported by Peter).
* Apply Reviewed/Acked-by.

Patches in v4 Applied

#Subject and filesSizeRepliesApplied
1/14perf/hw_breakpoint: Add KUnit test for constraints accountingkernel/events/Makefile kernel/events/hw_breakpoint_test.c lib/Kconfig.debug+334 -00 replies
2/14perf/hw_breakpoint: Provide hw_breakpoint_is_used() and use in testinclude/linux/hw_breakpoint.h kernel/events/hw_breakpoint.c kernel/events/hw_breakpoint_test.c+43 -10 replies
3/14perf/hw_breakpoint: Clean up headerskernel/events/hw_breakpoint.c+9 -100 replies
4/14perf/hw_breakpoint: Optimize list of per-task breakpointsinclude/linux/perf_event.h kernel/events/hw_breakpoint.c+37 -220 replies
5/14perf/hw_breakpoint: Mark data __ro_after_initkernel/events/hw_breakpoint.c+3 -30 replies
6/14perf/hw_breakpoint: Optimize constant number of breakpoint slotsarch/sh/include/asm/hw_breakpoint.h arch/x86/include/asm/hw_breakpoint.h kernel/events/hw_breakpoint.c+63 -410 replies
7/14perf/hw_breakpoint: Make hw_breakpoint_weight() inlinableinclude/linux/hw_breakpoint.h kernel/events/hw_breakpoint.c+3 -20 replies
8/14perf/hw_breakpoint: Remove useless code related to flexible breakpointskernel/events/hw_breakpoint.c+17 -400 replies
9/14powerpc/hw_breakpoint: Avoid relying on caller synchronizationarch/powerpc/kernel/hw_breakpoint.c+40 -130 replies
10/14locking/percpu-rwsem: Add percpu_is_write_locked() and percpu_is_read_locked()include/linux/percpu-rwsem.h kernel/locking/percpu-rwsem.c+12 -00 replies
11/14perf/hw_breakpoint: Reduce contention with large number of taskskernel/events/hw_breakpoint.c+133 -280 replies
12/14perf/hw_breakpoint: Introduce bp_slots_histogramkernel/events/hw_breakpoint.c+63 -330 replies
13/14perf/hw_breakpoint: Optimize max_bp_pinned_slots() for CPU-independent task targetskernel/events/hw_breakpoint.c+53 -40 replies
14/14perf/hw_breakpoint: Optimize toggle_bp_slot() for CPU-independent task targetskernel/events/hw_breakpoint.c+124 -310 replies

Reviews trailers per patch

All 14 patches have a Reviewed-by or Acked-by.

PatchDmitry VyukovIan Rogers
1/14R-b A-b
2/14R-b A-b
3/14A-b A-b
4/14R-b A-b
5/14R-b A-b
6/14A-b A-b
7/14R-b A-b
8/14R-b A-b
9/14A-b A-b
10/14R-b A-b
11/14R-b A-b
12/14R-b A-b
13/14R-b A-b
14/14R-b A-b

Trailers given in replies are filled; those carried in the patches from earlier versions are outlined with dashes.

Read the v4 thread

Cover letter [PATCH v4 00/14] perf/hw_breakpoint: Optimize for thousands of tasks

The hw_breakpoint subsystem's code has seen little change in over 10 years. In that time, systems with >100s of CPUs have become common, along with improvements to the perf subsystem: using breakpoints on thousands of concurrent tasks should be a supported usecase.

The breakpoint constraints accounting algorithm is the major bottleneck in doing so:

1. toggle_bp_slot() and fetch_bp_busy_slots() are O(#cpus * #tasks):
Both iterate through all CPUs and call task_bp_pinned(), which is O(#tasks).

2. Everything is serialized on a global mutex, 'nr_bp_mutex'.

The series progresses with the simpler optimizations and finishes with the more complex optimizations:

1. We first optimize task_bp_pinned() to only take O(1) on average.

2. Rework synchronization to allow concurrency when checking and updating breakpoint constraints for tasks.

3. Eliminate the O(#cpus) loops in the CPU-independent case.

Along the way, smaller micro-optimizations and cleanups are done as they seemed obvious when staring at the code (but likely insignificant).

The result is (on a system with 256 CPUs) that we go from:

| $> perf bench -r 30 breakpoint thread -b 4 -p 64 -t 64
[ ^ more aggressive benchmark parameters took too long ]

 | # Running 'breakpoint/thread' benchmark:
 | # Created/joined 30 threads with 4 breakpoints and 64 parallelism
 |      Total time: 236.418 [sec]
 |
 |   123134.794271 usecs/op
 |  7880626.833333 usecs/op/cpu

... to the following with all optimizations:

 | $> perf bench -r 30 breakpoint thread -b 4 -p 64 -t 64
 | # Running 'breakpoint/thread' benchmark:
 | # Created/joined 30 threads with 4 breakpoints and 64 parallelism
 |      Total time: 0.067 [sec]
 |
 |       35.292187 usecs/op
 |     2258.700000 usecs/op/cpu

On the used test system, that's an effective speedup of ~3490x per op.

Which is on par with the theoretical ideal performance through optimizations in hw_breakpoint.c (constraints accounting disabled), and only 12% slower than no breakpoints at all.

Changelog
---------

v4:
* Fix percpu_is_read_locked(): Due to spurious read_count increments in __percpu_down_read_trylock() if sem->block != 0, check that !sem->block (reported by Peter).
* Apply Reviewed/Acked-by.

v3: https://lkml.kernel.org/r/[email protected]
* Fix typos.
* Introduce hw_breakpoint_is_used() for the test.
* Add WARN_ON in bp_blots_histogram_add().
* Don't use raw_smp_processor_id() in test.
* Apply Acked-by/Reviewed-by given in v2 for mostly unchanged patches.

v2: https://lkml.kernel.org/r/[email protected]
* Add KUnit test suite.
* Remove struct bp_busy_slots and simplify functions.
* Add "powerpc/hw_breakpoint: Avoid relying on caller synchronization".
* Add "locking/percpu-rwsem: Add percpu_is_write_locked() and percpu_is_read_locked()".
* Use percpu-rwsem instead of rwlock.
* Use task_struct::perf_event_mutex instead of sharded mutex.
* Drop v1 "perf/hw_breakpoint: Optimize task_bp_pinned() if CPU-independent".
* Add "perf/hw_breakpoint: Introduce bp_slots_histogram".
* Add "perf/hw_breakpoint: Optimize max_bp_pinned_slots() for CPU-independent task targets".
* Add "perf/hw_breakpoint: Optimize toggle_bp_slot() for CPU-independent task targets".
* Apply Acked-by/Reviewed-by given in v1 for unchanged patches.
==> Speedup of ~3490x (vs. ~3315x in v1).

v1: https://lore.kernel.org/all/[email protected]/

Marco Elver (14):
perf/hw_breakpoint: Add KUnit test for constraints accounting perf/hw_breakpoint: Provide hw_breakpoint_is_used() and use in test perf/hw_breakpoint: Clean up headers
perf/hw_breakpoint: Optimize list of per-task breakpoints perf/hw_breakpoint: Mark data __ro_after_init perf/hw_breakpoint: Optimize constant number of breakpoint slots perf/hw_breakpoint: Make hw_breakpoint_weight() inlinable perf/hw_breakpoint: Remove useless code related to flexible
breakpoints
powerpc/hw_breakpoint: Avoid relying on caller synchronization locking/percpu-rwsem: Add percpu_is_write_locked() and
percpu_is_read_locked()
perf/hw_breakpoint: Reduce contention with large number of tasks perf/hw_breakpoint: Introduce bp_slots_histogram perf/hw_breakpoint: Optimize max_bp_pinned_slots() for CPU-independent
task targets
perf/hw_breakpoint: Optimize toggle_bp_slot() for CPU-independent task
targets

 arch/powerpc/kernel/hw_breakpoint.c  |  53 ++-
 arch/sh/include/asm/hw_breakpoint.h  |   5 +-
 arch/x86/include/asm/hw_breakpoint.h |   5 +-
 include/linux/hw_breakpoint.h        |   4 +-
 include/linux/percpu-rwsem.h         |   6 +
 include/linux/perf_event.h           |   3 +-
 kernel/events/Makefile               |   1 +
 kernel/events/hw_breakpoint.c        | 638 ++++++++++++++++++++-------
 kernel/events/hw_breakpoint_test.c   | 333 ++++++++++++++
 kernel/locking/percpu-rwsem.c        |   6 +
 lib/Kconfig.debug                    |  10 +
 11 files changed, 885 insertions(+), 179 deletions(-)
 create mode 100644 kernel/events/hw_breakpoint_test.c
Signature · 1 line
2.37.2.672.g94769d06f0-goog