Repository navigation
Conversation
With CONFIG_PERF_OVERFLOW_CORRECTION, perf_gettime() compares the counter with one global "last" value. On SMP each CPU has its own counter (for example PMCCNTR on ARMv7-A), and these counters do not hold the same value. A read on a CPU with a lower counter than the last read on another CPU counts as an overflow. Each such read adds 2^32 cycles to all later values: on qemu-armv7a:smp a thread that runs 500 ms shows 4795 ms of CPU time. Keep "last" and "overflow" for each CPU. The state belongs to one CPU, so disabling the local interrupts is sufficient and the spinlock goes away. This also removes the wd_start() call with a spinlock held. The watchdog runs on one CPU only, so it cannot read the counter of another CPU. Use a watchdog for each CPU that sends a SMP call to the CPU of its state. A CPU that runs one thread for a long time then does not miss an overflow. With SMP off, the array has one element and the size of the code does not change: 304 bytes of text and 48 of bss on qemu-armv7a:nsh, before and after. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
|
xiaoxiang781216
approved these changes
Nov 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
With PERF_OVERFLOW_CORRECTION, perf_gettime() compares the counter with one global "last" value. On SMP each CPU has its own counter (PMCCNTR on ARMv7-A), and the counters do not hold the same value. A read on a CPU with a lower counter than the last read on another CPU counts as an overflow, and adds 2^32 cycles to all later values. On qemu-armv7a:smp a thread that runs for 500 ms shows 4795 ms of CPU time.
This PR keeps the overflow state for each CPU. The state belongs to one CPU, so perf_gettime() disables the local interrupts and needs no spinlock. The watchdog that reads the counter before it can wrap twice runs on one CPU only, so each CPU's watchdog now sends a SMP call to the CPU of its state.
Impact
SMP builds with PERF_OVERFLOW_CORRECTION only. A value from perf_gettime() compares only with a value from the same CPU, as in an SMP build without the option. With SMP off the object has the same size (304 bytes of text, 48 of bss on qemu-armv7a:nsh, before and after). The option is off by default. No API change, no documentation change (Documentation/ does not name the option).
Testing
Test program perfover.c: a thread pinned to each CPU in turn runs a busy loop (CLOCK_MONOTONIC) and reads CLOCK_THREAD_CPUTIME_ID, while a second thread on the next CPU sleeps 1 ms in a loop. qemu-armv7a:smp, 4 CPUs, QEMU TCG, SCHED_CRITMONITOR, ARCH_PERF_EVENTS, PERF_OVERFLOW_CORRECTION. CPU time in ms, CPU 0 to 3:
To check the SMP call, the same 10000 ms test with
perf_gettime()in the watchdog in place of the SMP call gives 10000, 1410, 1410, 1410: the CPUs that do not run the watchdog miss the wraps. The same test with 2 CPUs on this PR gives 10000, 10000. ostest exits with status 0 on master and with this PR.No SMP (qemu-armv7a:nsh, same options): 10000 ms before and after.
Builds with -Werror and the option on: qemu-armv7a:smp, :nsh, :knsh_smp (kernel, SMP), :knsh (kernel), mps2-an500:knsh (protected), raspberrypi-pico-2:smp (ARMv8-M, SMP), rv-virt:smp (RISC-V, SMP). arty_a7:knsh-tickless (the defconfig in the tree that sets the option) also builds. The code applies only when unsigned long is not 64 bits, as before. The RISC-V and RP2350 configurations were built only, not run.
The runs and builds are on 39a1f27. After the rebase on 3d57048, the 4-CPU run gives 500 ms on each CPU for the 500 ms test and 10000 ms on each CPU for the 10000 ms test.
The branch is now rebased on f19dbe6 (no change in the touched files).