Tudor Brindus on Finding and Reducing System Jitter

A memory ping-pong benchmark reveals how virtualization, interrupts, CPU frequency changes and speculation can disrupt low-latency systems.

TBTudor Brindus登壇者 · Jane Street
チャンネル
Jane Street
公開日
2024年11月15日
動画
27:16
読了時間
7 分
スライド
8
原文
英語
YouTube で開く
スクロールすると動画は右下に小さくなって再生を続けます。字幕は閲覧言語に合わせて切り替わります。
閲覧言語2 言語で読めます
この記事はまだ日本語に翻訳されていないため、英語の原文を表示しています。
要約

30 秒でわかる

Jane Street software engineer Tudor Brindus investigates jitter in a simple interprocess communication benchmark. He uses measurements and processor tracing to isolate sources of latency, then adjusts the operating system and application one step at a time. The exercise illustrates the tradeoffs between speed, determinism and stability, and why low-noise measurements help teams detect regressions.

  1. 1Start with the distributionThe virtualized ping-pong benchmark had a 637 ns median and outliers reaching roughly 16 microseconds. Its latency plots show why a single average is not enough.
  2. 2Move to bare metalRunning the same code without a virtual machine reduced median latency to 223 ns and cleared much of the noise.
  3. 3Trace rare eventsMagic Trace uses Intel Processor Trace to capture control flow around a slow round trip. The traces exposed network interrupts and later timer interrupts.
  4. 4Isolate cores and timer ticksCore isolation and reduced periodic ticks brought the median down further, while requiring explicit process placement.
  5. 5Trade speed for determinismDisabling turbo boost removed frequency-transition jitter in this test, but made the median slightly slower.
  6. 6Improve the spin loopAdding an x86 pause instruction reduced bad speculation from 8% to 1% and improved the median by 8 ns.

ポイント

  1. Latency-sensitive systems need to measure the distribution and tail of processing times, not just the median.
  2. Running the benchmark on bare metal removed substantial virtualization overhead and noise in this experiment.
  3. Processor tracing can reveal rare events that ordinary sampling profilers miss, including network and timer interrupts.
  4. Core isolation, reduced timer ticks and disabling turbo boost can improve determinism, with tradeoffs.
  5. A pause instruction in the spin loop reduced bad speculation and improved the benchmark.
  6. Hardware choice affects performance, but aggressive overclocking can compromise correctness.
全文

チャプターごとに整えた全文を読む

文字起こしのみ
01

Why jitter matters

Brindus introduces latency-sensitive market data and the need for predictable processing. He sets up a small interprocess benchmark.

I work on Jane Street’s ultra-low-latency trading team, where we deal with fast software, hardware and analysis tools. One recurring problem is jitter: variation in processing time. In trading, market data can arrive at around a gigabyte per second, depending on the exchange, and even data that is 10 microseconds stale can lead to bad trades.

Jane Street uses OCaml, which in the setup I describe has a fundamentally single-threaded runtime. Its async scheduler can dispatch blocking system calls to a thread pool, but parallel code execution requires multiple processes. That makes passing data between processes on the same machine an interesting case to study.

02

A ring-buffer ping-pong benchmark

Two processes exchange incrementing integers through ring buffers. Round-trip latency is measured on a Cascade Lake server.

A ring buffer can be thought of as an array of fixed-size cells: after reaching the end, the reader or writer wraps around to the beginning. We establish two buffers between two processes, one in each direction, and use them to play an endless game of ping-pong.

The pinger writes the integer 1; the ponger reads it, adds one and sends back 2. The pinger reads that, adds one and writes 3 to the next cell. The cycle continues around the buffers. I measure the time between the pinger writing a value and receiving the corresponding response.

Measuring the ping-pong round trip
スライド 1 / 8Measuring the ping-pong round tripThe code marks the two timestamp locations used to measure communication between the processes.

The benchmark runs on a second-generation Intel Cascade Lake server at 3.6 GHz. The initial setup is virtualized. Its median round-trip latency is 637 nanoseconds, but the jitter extends to roughly 16 microseconds: a large spread for such a small amount of work.

03

Virtual machines and bare metal

The initial latency distribution has a 637 ns median and a long tail. Running the same code on bare metal reduces the median to 223 ns.

The charts show histograms on the left and samples over time on the right. The upper plots use a linear scale; the lower ones use a logarithmic scale, which becomes more useful as the noise shrinks. The orange line marks the median.

A virtual machine might suffer from a noisy neighbor on the same physical host or other virtualization overhead. Rather than diagnose that complicated layer, I run the same code on bare metal. The median falls by 414 ns to 223 ns, and much of the noise disappears, although a concentration around one microsecond and longer tails remain.

Bare-metal latency distribution
スライド 2 / 8Bare-metal latency distributionThe histogram and time-series plots show the 223 ns median and remaining latency tails.

A sampling profiler such as perf or VTune mostly reports that the processes are spinning while waiting for one another. That is accurate but does not explain the rare slow events. Our trading systems have a similar shape: they spend much of their time waiting for market data, and the interesting activity is infrequent.

04

Tracing rare latency events

Brindus explains Intel Processor Trace and Magic Trace. Capturing slow round trips reveals network interrupts in a program that does no networking.

Intel Processor Trace records control-flow transfers such as branches, calls and returns in compressed form. For conditional branches it can record taken or not taken as a bit; with the starting instruction pointer and a disassembler, the path can be reconstructed. A fixed-size circular trace buffer can be snapshotted when an interesting event occurs.

Jane Street built Magic Trace to decode and visualize this information. Its chart places call-stack depth on the vertical axis and time on the horizontal axis, allowing us to zoom in to a few nanoseconds of resolution and inspect what happened around an event.

Knowing the median, I define an interesting event as a round trip exceeding 300 ns. The trace shows spikes amid the normal exchange of integers. Zooming in reveals network activity in the kernel, despite the fact that this application only exchanges data through memory.

Tracing a tail event
スライド 3 / 8Tracing a tail eventA Magic Trace snapshot highlights an unusual event during a slow round trip.

When a network card receives a packet, it interrupts a CPU so the kernel can dispatch it. Interrupts are normally distributed across cores for load balancing, which makes sense for heavy network traffic but can interrupt an application that has nothing to do with networking.

05

Isolating interrupts

Core isolation keeps network interrupts away from the benchmark, and reduced timer ticks remove another source of jitter. Each change is measured.

The Linux isolcpus parameter lets us set aside cores while leaving some available for network activity and remote access. The scheduler no longer places work on the isolated cores automatically, so we explicitly pin the pinger and ponger with taskset. After rebooting, network interrupts stay on other cores and the median drops another 29 ns to 194 ns.

Interrupt counts by CPU
スライド 4 / 8Interrupt counts by CPUThe /proc/interrupts listing shows network and local timer interrupts on the system.

The one-microsecond tail is now more prominent. Magic Trace reveals an APIC timer interrupt, and /proc/interrupts shows how frequently local timer interrupts occur. The kernel traditionally uses these ticks to consider scheduling, update statistics and, on older CPUs, help manage frequency.

With one runnable process per isolated core, the nohz_full parameter can reduce these timer ticks. The kernel still needs some statistics updates, so the frequency can fall to about once a second rather than literally zero. This change saves another 24 ns and largely removes the one-microsecond mode, although longer tails remain.

At this point Magic Trace no longer shows an obvious interruption: the same instructions sometimes just take longer. That suggests a microarchitectural cause. One candidate is turbo boost, which changes CPU frequency dynamically within the processor’s power constraints.

06

Turbo boost and speculation

Frequency transitions and speculative execution introduce further variation. Brindus trades turbo speed for determinism and uses a pause instruction in the spin loop.

Our Cascade Lake server has a 3.6 GHz base frequency and can boost to 4.4 GHz through 31 possible P-states. Frequency transitions take time. I suspect the sawtooth pattern in the latency time series reflects transitions between nearby states, with one direction taking longer than the other; that is a hypothesis, not a confirmed explanation.

Turbo boost and latency variation
スライド 5 / 8Turbo boost and latency variationA time-series plot illustrates the pattern Brindus associates with frequency changes.

Turning off turbo boost removes that jitter, but the benchmark becomes one nanosecond slower. We have favored determinism over speed, running at 3.6 GHz rather than near 4.4 GHz. A workload doing more than incrementing a number would likely feel the frequency difference more strongly.

Three peaks remain in the logarithmic distribution. To understand another possible source, consider the gap between CPU speed and memory latency. A processor that must wait for a dereferenced memory operand would stall badly, so designers use techniques including speculative execution to hide that delay.

In our polling loop, the ring buffer is empty most of the time. The CPU learns to predict that another load will also find no data, loops back speculatively and issues further loads. Eventually a load does contain data; the processor must discard the incorrect speculative work and restore the appropriate state.

Speculative execution in a polling loop
スライド 6 / 8Speculative execution in a polling loopThe simplified pipeline shows repeated speculative loads and loop iterations.

Intel’s PCM tool attributes 8% of the observed pipeline breakdown to bad speculation. Other categories have larger percentages, but I cite Intel’s optimization guidance that bad speculation above 1% deserves attention. The polling loop resembles a spin lock, a case the x86 pause instruction is designed to help.

The pause instruction hints that the processor is in a spin-wait loop and helps avoid the penalty associated with exiting it. We ask our compiler developers for an OCaml intrinsic that emits it. With that one-line change, bad speculation falls from 8% to 1%, and median latency improves by another 8 ns.

Bad speculation after adding pause
スライド 7 / 8Bad speculation after adding pauseThe processor metrics show bad speculation reduced to 1%.

The three peaks largely collapse into one, though some samples remain in slower bands that I cannot explain. On the original hardware, we have gone from 637 ns with substantial jitter to 163 ns with much less jitter. That is a substantial improvement for a very small code change.

07

Hardware, tradeoffs and measurement

An overclocked server improves the benchmark but proves unstable under real workloads. Brindus discusses virtual machines, containers and the value of continuously monitoring tails.

What if we use faster memory and an overclocked CPU? The benchmark improves by another 94 ns, to a 69 ns median. But there is an important qualification: when we tried real trading systems on this machine, it died halfway through a test with memory corruption. Aggressive overclocking can make the result fast and wrong.

The overclocked-server result
スライド 8 / 8The overclocked-server resultThe benchmark improves to a 69 ns median, though the machine later proved unstable.

If performance and determinism matter, consider the cost of virtualization and understand the environment you are using. In response to a question, I note that AWS is a reputable provider but virtual machines can still have jitter; it also offers bare-metal instances. Lower-end providers may oversubscribe their hardware.

Asked about Docker, I distinguish containers on bare metal from a hypervisor-based virtual machine. Docker uses kernel namespaces, and cgroup accounting can make kernel interactions moderately slower. For code that avoids system calls, I would not expect the same kind of additional virtualization jitter.

Understanding the architecture can unlock considerable performance, and hardware choice matters. Most of all, keep measuring. When a system already has noisy tails, a regression can hide in the noise and become much worse before anyone notices.

When median and p99 latency are close, a new regression that sends p99 sharply upward is much easier to detect during testing. That is a more stable position from which to maintain a system when determinism matters.

同じチャンネルの記事

1:48:29EN
JSJane Street· 2026年10月16日How AI Is Changing Programming: John Krazit and Ron MinskyRon Minsky, John Krazit · Jane StreetJane Street’s AI tooling lead and the Signals and Threads host examine agent infrastructure, security, code review and the changing experience of writing software.コーディングエージェントDeveloper productivity評価(Evals)+2
1:36:37EN
JSJane Street· 2026年9月23日Aaron Bauer on Teaching Software Engineering in the Age of AIRon Minsky, Aaron Bauer · Jane StreetHow learning goals, active practice and editor design shape engineering education when models can generate the code.AI in EducationSoftware engineeringEducation+2
スライド 9 枚1:05:45EN
JSJane Street· 2026年9月11日Cyrus Omar on Live Programming and a Computational Commons for Humans and AICyrus OmarA demonstration of Hazel shows how immediate feedback, structured collaboration and carefully scoped permissions could support people and AI agents working together.Programming LanguagesHuman-AI Collaboration開発ワークフローとテスト+2
1:25:00EN
JSJane Street· 2026年9月2日Eric Mannes on Turning Messy External Data Into Trading ResearchRon, Eric Mannes · Jane StreetFrom commodity futures and an Excel risk system to point-in-time datasets and AI, Eric Mannes explains the domain knowledge behind data engineering at Jane Street.Data quality & curation開発ワークフローとテストInvesting+2
スライド 7 枚1:16:29EN
JSJane Street· 2026年8月26日Grant Sanderson and Alok Puranik: Positional Encodings Through Group TheoryGrant Sanderson, Alok Puranik · 3Blue1BrownStarting with assumptions about attention, they derive matrix exponentials and connect rotations, decay and Jordan blocks to RoPE and ALiBi.Transformers & attentionMathematics機械学習の基礎+1
27:39EN
JSJane Street· 2026年8月21日3Blue1Brown and Jane Street on Trading, Machine Learning and CultureGrant Sanderson, Nitya, In Young, Craig, Alok · 3Blue1BrownGrant Sanderson talks with Jane Street colleagues about market making, shared compute, research and the paths that brought them to the firm.Machine LearningFintechCompany Culture+2