Re: Unexplained variance in run-time of simple program (part 2)
Marc Gonzalez <[email protected]> Tue, 5 May 2026 01:17:15 +0200
| Newsgroups | org.kernel.vger.linux-rt-users |
|---|---|
| Message-ID | <[email protected]> |
Hello John, On 10/04/2026 19:16, Marc Gonzalez wrote: [snip] I have come to the conclusion that it seems IMPOSSIBLE to get reproducible run-times, even for simple programs, on "modern" systems (in quotes because Haswell, so 2013). SETUP: - System is idle, booted in single-user mode, with CPU3 isolated for benchmarks. - CPU frequency is pinned at 2.8 GHz (nominal 3.3 GHz) to avoid thermal throttling & turbo boost. - Benchmark is run as SCHED_FIFO 99, pinned to CPU3. Linux version 6.8.0-110-generic nohz_full=3 rcu_nocbs=3 isolcpus=nohz,domain,managed_irq,3 irqaffinity=0-2 nosmt mitigations=off nosoftlockup tsc=reliable log_buf_len=16M single If I benchmark an absolutely trivial program (no memory access, 1 predictable loop) then the run-time is extremely reproducible: spin: xor eax, eax mov ecx, 1000 loop: times 60 inc eax ; 120 bytes dec ecx jnz loop ; 8-bit offset ret This code is expected to run in 60,000 cycles So the TSC pulsing at 3.3 GHz would count 70715 cycles + a few cycles for rdtscp & call overhead. After measuring 12M calls to spin(), the run-time distribution is: 70725: 31 70730: 6235014 70735: 5142415 70740: 622531 70750: 1 70905: 3 70910: 4 103965: 1 (Not sure what's up with that 103965 outlier) So the run-time is within 70730-70745 with 0,999996 certainty (11999960/12M) A 15-cycle spread is 212 ppm. All is well & as expected for the trivial case. Everything breaks down when I measure my actual (simple) program. By simple, I mean: - no system calls, no library calls, no I/O, just bit twiddling - tiny code, small(ish) dataset Here, I ran the code 15 MILLION TIMES, and took the MINIMUM run-time measured. And I repeated this 20 times, expecting the various MINIMUMS to be quite similar: 66413 65707 66214 66277 67345 66640 66029 66693 67551 66771 66376 66536 66871 66177 65674 65435 66136 66223 66145 66305 The minimums of 15 MILLION runs fell somewhere between 65435 and 67551 :( That's a spread of (67551-65435) / ((65435+67551) / 2) = 3.18% = 31823 ppm 150 times larger than for the trivial case. Do I need to run the code 50M times? 100M times? to get consistent run-times? :( Running out of ideas. Maybe the memory traffic is generating a lot of "volatility" / non-determinism? (But I don't think I'm even using all of L1$) Maybe I need to disable the memory pre-fetchers? I'm stumped... Regards