Conference Presentation
System Jitter and Where to Find It: A Whack-a-Mole Experience
Benchmark Scenario & Initial Setup
- The presentation analyzes a "toy" distributed message passing system using two processes (pinger/ponger) and ring buffers on a single machine to simulate market data processing.
- The system architecture consists of two ring buffers: one for Pinger-to-Ponger and one for Ponger-to-Pinger, where the value increments with each round trip.
- The benchmark measures round-trip latency ($t_2 - t_1$) on a virtualized Intel Cascade Lake server (3.6 GHz) running OCaml, a language with a fundamentally single-threaded runtime requiring multi-process parallelism.
- Initial unoptimized virtualized measurements yielded a median latency of 637 nanoseconds with jitter as high as 16 microseconds.
Optimization Strategies & Results
1. Hardware Isolation (Bare Metal)
- Removing the virtualization layer to run on bare metal reduced median latency from 637ns to 223ns, eliminating significant "noisy neighbor" noise from other virtual machines.
- Despite this improvement, a distinct latency tail around 1 microsecond remained, indicating kernel-level interference.
2. Interrupt Isolation (isolcpus)
- Investigation via Intel Processor Trace revealed that network interrupts from the
ixgbedriver were interrupting the application cores. - Configuring the kernel parameter
isolcpusisolated specific cores (e.g., cores 1 and 2) from network interrupts. - This change required manually assigning processes to cores via
tasksetsince the scheduler would no longer migrate tasks on isolated cores. - Removing network interrupt interference reduced median latency from 223ns to 194ns.
3. Timer Tick Reduction (nohz_full)
- Profiling identified local timer interrupts (occurring ~1,000 times/second) as the cause of the remaining 1-microsecond tail, used for process scheduling and frequency scaling.
- Setting the kernel parameter
nohz_fullreduced the timer interrupt frequency from 1,000 Hz to once per second. - This optimization cut latency by an additional 24 nanoseconds (median now ~170ns) and virtually eliminated the 1-microsecond spike.
4. Turbo Boost Management
- Analysis of the frequency vs. time plot revealed a "sawtooth" pattern caused by the CPU oscillating between base frequency (3.6 GHz) and Turbo Boost frequency (4.4 GHz).
- Frequency transitions introduce variable latency and jitter.
- Disabling Turbo Boost forced the CPU to run at a constant 3.6 GHz.
- This trade-off removed jitter entirely but increased the median latency by 1 nanosecond due to the lower base clock speed.
5. Micro-architectural Optimization (Speculative Execution)
- Intel's OPCM tool attributed 8% of pipeline stalls to "bad speculation," where the CPU incorrectly assumed loop conditions would remain false and issued redundant loads.
- The root cause was the lack of a hint in the tight spin-loop, causing the CPU pipeline to stall upon correct loop exit.
- Introducing the x86
pauseinstruction via a compiler intrinsic (one line of OCaml code) reduced bad speculation from 8% to 1%. - This change reduced median latency to 163 nanoseconds and collapsed the remaining latency peaks.
6. Hardware Overclocking (Risk Assessment)
- Running on overclocked hardware with faster RAM and higher CPU clocks reduced latency by an additional 94 nanoseconds compared to the optimized baseline.
- However, testing revealed that aggressive overclocking led to memory corruption ("1 + 1 = 3") and system instability in real trading systems.
Final Metrics & Trends
- The optimization journey reduced median latency from 637ns (jitter 16µs) to 163ns (jitter near zero), an order-of-magnitude improvement.
- The final optimized system demonstrates a high correlation between median and p99 latencies, making any future performance regression immediately visible.
- Virtualization remains a primary source of jitter; bare metal or dedicated metal instances (e.g., AWS EC2 Metal) are recommended for deterministic low-latency systems.
- Running Docker on bare metal is viable provided the application does not rely on heavy system calls, as Docker's namespace isolation introduces negligible jitter compared to full virtualization.
- The "frog in boiling water" effect is a major risk: high-jitter systems can degrade performance by 10x without triggering detection, whereas deterministic systems alert developers to regressions instantly.