Chronicle Ring vs LMAX Disruptor
October 7th, 2021
Benchmarks have a natural lifespan that can be improved with more modern hardware. This benchmark was performed on October 7, 2021. Please don’t hesitate to contact us if you have questions about how Chronicle Ring will perform today. The same methodology can easily be re-run on today’s CPUs to demonstrate how advances in cache lines, CPU cache hierarchies and memory barriers further benefit Chronicle’s data structures.
Introduction
Chronicle RingZero is a specialised lightweight, high-performance ring buffer specifically for the common use case of a single writer and single reader. This single producer, single consumer pattern removes contention and virtually eliminates lock overhead, delivering thread safe inter thread communication with ultra-low latency that suits real time frequency trading workflows. Chronicle RingZero is available in both Java and C++, enabling full interoperability between applications in either language. Because the code base is tuned for performance Java developers as well as native C++ engineers, teams can adopt a deterministic data structure that behaves identically across the whole stack and across main memory boundaries.
Chronicle RingZero is one part of the Chronicle suite of low-latency Java and C++ libraries and software products, which also includes Chronicle Queue, Chronicle Map and other fault tolerant components designed with mechanical sympathy in mind. These libraries share the same philosophy of minimising false sharing, keeping objects pre-allocated and fixed size where appropriate, and pinning critical threads to specific cores to maximise CPU cache residency.
The RingZero features are as follows:
A fixed number of slots (which must be a power of 2) to allow simple masking instead of expensive modulo arithmetic and to keep the event sequence predictable for the producer consumer pair
A maximum fixed message size per slot, ensuring every cache line is used efficiently and avoiding heap allocations
Single writer, single reader (concurrent), giving a classic producer consumer model that avoids costly memory fences when compared with multiple producers
All writes must be from the same thread, guaranteeing that no additional memory barriers are required on the publishing side
All reads must be from the same thread, ensuring that the consumer observes events in order without extra synchronisation
The LMAX Ring Buffer is part of the Java Disruptor library, and this document provides a comparison between this implementation and Java Chronicle RingZero. In Disruptor terms, our benchmark configures disruptor.start(), a ringbuffer publish from the single producer and the typical disruptor.handleEventsWith consumer chain.
Test Methodology
The test measured the write-to-read latency between two threads sharing data using either a Chronicle RingZero or LMAX Disruptor ring buffer. Fifteen million (15 M) messages were sent—yes, literally millions messages—at varying message rates from 250 k to 2 M msgs/s. The messages were intentionally kept to just 12 bytes (1 int for indexing, 1 long for the nanosecond timestamp) in order to minimise fixed overheads from copying data and so better highlight the differences between the underlying ring implementations. The first 100 k messages were discarded from the test to remove effects from JVM warm-up and JIT compilation.
All tests were run on a 2 × 12-core Xeon E5-2650 v4 @ 2.20 GHz, with cores 2-11 isolated. The test process was assigned isolated cores, and no other processes were running in the isolated set. The Chronicle RingZero test used the Chronicle Affinity library to manage thread pinning, whereas the LMAX Disruptor test used external taskset (in the absence of equivalent controls exposed by the LMAX library itself). By pinning the producer and consumer to dedicated cores and aligning the ring buffer in memory to avoid false sharing, both frameworks were given every opportunity to keep hot data inside the L1/L2 caches and away from slower main memory.
Results
The write-to-read latency results (in nanoseconds) are shown below for Chronicle RingZero (first plot) and LMAX Disruptor Ring Buffer (second plot). Note the RingZero plot uses a linear latency axis, whereas a logarithmic scale is used for the LMAX Disruptor results.
The results show lower latencies across all percentiles with Chronicle RingZero compared to LMAX Disruptor. In addition, the outliers are better controlled and the sensitivity to message rate is much less with Chronicle RingZero. In short, Chronicle RingZero consistently delivers sub-microsecond, sometimes sub-100 ns, end-to-end latency while remaining highly predictable—exactly what modern trading systems and other real time event driven services require.


For more details on the tests, the queue disruptor configuration, or the code used, please contact [email protected]. You can also refer to the original message Java GoogleGroups discussion where Disruptor achieves its design goals by combating cache contention—search for the root parent thread that covers “false sharing” and “cache lines” if you would like a deeper dive.