Module ring_buffer

Source
Expand description

Lock-free ring buffer implementation for zero-latency metric recording

This module provides a single-producer, multiple-consumer (SPMC) ring buffer optimized for high-frequency metric recording with minimal overhead.

§Architecture Overview

The ring buffer uses atomic operations to avoid locks in the hot path, ensuring minimal impact on trading system performance. It supports a single producer with multiple concurrent consumers.

Key Design Features:

  • Zero-allocation in hot paths (all memory pre-allocated)
  • Lock-free operations using compare-and-swap
  • Cache-friendly data layout with alignment
  • Overflow tracking for capacity monitoring

§Capacity Requirements and Planning

§Power of 2 Requirement

MANDATORY: Capacity must be a power of 2 (2, 4, 8, 16, 32, 64, 128, …). This enables:

  • Bitwise AND operations (& capacity_mask) instead of expensive modulo
  • ~10-20% performance improvement in hot paths
  • Optimal cache line alignment for atomic operations

§Effective Capacity

Important: Effective capacity is capacity - 1 due to full/empty distinction. The buffer reserves one slot to differentiate between full and empty states.

§Capacity Planning Formula

Required_Capacity = Peak_Throughput_Per_Second × Max_Consumer_Delay_Seconds × Safety_Factor

Where:
- Peak_Throughput_Per_Second: Maximum messages/second during bursts
- Max_Consumer_Delay_Seconds: Worst-case time between drain operations
- Safety_Factor: 2-5x buffer (3x recommended for production)

§HFT Capacity Guidelines by Use Case

Use CaseFrequencyRecommended CapacityEffective ItemsMemory (8-byte)Cache Level
Trade executionSub-μs64-12863-127~0.5-1KBL1
Order book updatesμs512-1024511-1023~4-8KBL1/L2
Risk calculationsms2048-40962047-4095~16-32KBL2
Strategy signalss8192-163848191-16383~64-128KBL2/L3
Historical loggingmin+32768+32767+~256KB+Memory

§Performance Characteristics by Capacity

  • 64-256 items: Ultra-low latency (~10-50ns), fits in L1 cache (32-64KB)
  • 512-2048 items: High performance (~50-100ns), excellent L2 utilization
  • 4096-8192 items: Balanced (~100-200ns), L3 cache friendly
  • 16384+ items: High capacity (~200ns+), may cause cache misses

§Memory Usage Calculation

Total Memory = capacity × size_of::<T>() + overhead (~64 bytes)

Examples:
- capacity=64, T=u64: ~576 bytes (fits in single cache line group)
- capacity=1024, T=u64: ~8KB (good L1 cache utilization)
- capacity=8192, T=u64: ~64KB (fits comfortably in L2 cache)

§Overflow Monitoring and Capacity Adjustment

§Overflow Implications

Each overflow represents:

  • Lost metric data that could impact trading decisions
  • Potential performance degradation due to buffer pressure
  • Need for capacity adjustment or consumer optimization

§Production Monitoring Guidelines

  • Zero overflows: Optimal capacity, consider reducing if over-provisioned
  • Rare overflows (< 0.1%): Acceptable for non-critical metrics
  • Regular overflows (> 1%): Increase capacity or optimize consumers
  • Frequent overflows (> 10%): Critical issue, system overload

§Capacity Adjustment Strategy

Based on overflow rate per minute:

  • > 100 overflows/min: Double capacity immediately
  • 10-100 overflows/min: Increase capacity by 50%
  • 1-10 overflows/min: Monitor trends, minor adjustment
  • 0 overflows/min: Current capacity sufficient

§Usage Examples

§Basic Usage

use crate::monitoring::ring_buffer::SharedRingBuffer;

// Create buffer for order book updates
let buffer = SharedRingBuffer::new(1024);

// Producer: Push metrics
if !buffer.push(metric_data) {
    eprintln!("Buffer overflow! Consider increasing capacity");
}

// Consumer: Drain in batches
let metrics = buffer.drain(64);
for metric in metrics {
    process_metric(metric);
}

§Capacity Planning Examples

use crate::monitoring::ring_buffer::SharedRingBuffer;

// Example 1: High-frequency order book (50K updates/sec, 1ms drain)
// Required: 50,000 × 0.001 = 50, Safety: 4x = 200, Next power of 2: 256
let order_book = SharedRingBuffer::new(256);

// Example 2: Strategy signals (1K signals/sec, 10ms drain)
// Required: 1,000 × 0.01 = 10, Safety: 8x = 80, Next power of 2: 128
let strategy = SharedRingBuffer::new(128);

// Example 3: Risk metrics (10K metrics/sec, 5ms drain)
// Required: 10,000 × 0.005 = 50, Safety: 5x = 250, Next power of 2: 512
let risk = SharedRingBuffer::new(512);

§Performance Optimization Guidelines

§Multi-Consumer Efficiency

  • Use drain(batch_size) instead of repeated pop() calls
  • Recommended batch sizes: 16-64 items per drain operation
  • Each consumer competes for items (no broadcasting)

§Overflow Handling Strategy

When buffer overflows:

  • Data is lost (ring buffer does not resize)
  • Monitor overflow_count() for capacity planning
  • Consider: larger capacity, faster consumers, or multiple buffers

Structs§

RingBuffer
A lock-free ring buffer for metric storage
SharedRingBuffer
A thread-safe wrapper around RingBuffer for shared access