mirror of
https://github.com/floor-licker/polyfill-rs.git
synced 2026-08-04 16:27:44 +00:00
243 lines
7.5 KiB
Rust
243 lines
7.5 KiB
Rust
//! Benchmark for order book updates
|
|
//!
|
|
//! This benchmark measures the performance of order book operations
|
|
//! including delta application, price updates, and book maintenance.
|
|
|
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
|
use polyfill_rs::{
|
|
book::OrderBook,
|
|
types::{OrderDelta, Side},
|
|
};
|
|
use rust_decimal::Decimal;
|
|
use rust_decimal_macros::dec;
|
|
use std::time::Instant;
|
|
|
|
fn bench_book_creation(c: &mut Criterion) {
|
|
c.bench_function("book_creation", |b| {
|
|
b.iter(|| {
|
|
let _book = OrderBook::new(black_box("test_token".to_string()), black_box(100));
|
|
});
|
|
});
|
|
}
|
|
|
|
fn bench_delta_application(c: &mut Criterion) {
|
|
let mut book = OrderBook::new("test_token".to_string(), 100);
|
|
|
|
// Pre-populate with some levels
|
|
for i in 1..=10 {
|
|
let price = Decimal::from(50 + i) / Decimal::from(100);
|
|
let delta = OrderDelta {
|
|
token_id: "test_token".to_string(),
|
|
timestamp: chrono::Utc::now(),
|
|
side: Side::BUY,
|
|
price,
|
|
size: dec!(100),
|
|
sequence: i,
|
|
};
|
|
book.apply_delta(delta).unwrap();
|
|
}
|
|
|
|
let mut sequence = 10;
|
|
|
|
c.bench_function("delta_application", |b| {
|
|
b.iter(|| {
|
|
sequence += 1;
|
|
let delta = OrderDelta {
|
|
token_id: "test_token".to_string(),
|
|
timestamp: chrono::Utc::now(),
|
|
side: black_box(Side::SELL),
|
|
price: black_box(dec!(0.52)),
|
|
size: black_box(dec!(50)),
|
|
sequence: black_box(sequence),
|
|
};
|
|
book.apply_delta(delta).unwrap();
|
|
black_box(book.sequence);
|
|
});
|
|
});
|
|
}
|
|
|
|
fn bench_best_price_lookup(c: &mut Criterion) {
|
|
let mut book = OrderBook::new("test_token".to_string(), 100);
|
|
|
|
// Pre-populate with levels
|
|
for i in 1..=20 {
|
|
let price = Decimal::from(50 + i) / Decimal::from(100);
|
|
let delta = OrderDelta {
|
|
token_id: "test_token".to_string(),
|
|
timestamp: chrono::Utc::now(),
|
|
side: if i % 2 == 0 { Side::BUY } else { Side::SELL },
|
|
price,
|
|
size: dec!(100),
|
|
sequence: i,
|
|
};
|
|
book.apply_delta(delta).unwrap();
|
|
}
|
|
|
|
c.bench_function("best_price_lookup", |b| {
|
|
b.iter(|| {
|
|
let _bid = book.best_bid();
|
|
let _ask = book.best_ask();
|
|
let _spread = book.spread();
|
|
let _mid = book.mid_price();
|
|
});
|
|
});
|
|
}
|
|
|
|
fn bench_book_snapshot(c: &mut Criterion) {
|
|
let mut book = OrderBook::new("test_token".to_string(), 100);
|
|
|
|
// Pre-populate with levels
|
|
for i in 1..=50 {
|
|
let price = Decimal::from(50 + i) / Decimal::from(100);
|
|
let delta = OrderDelta {
|
|
token_id: "test_token".to_string(),
|
|
timestamp: chrono::Utc::now(),
|
|
side: if i % 2 == 0 { Side::BUY } else { Side::SELL },
|
|
price,
|
|
size: dec!(100),
|
|
sequence: i,
|
|
};
|
|
book.apply_delta(delta).unwrap();
|
|
}
|
|
|
|
c.bench_function("book_snapshot", |b| {
|
|
b.iter(|| {
|
|
let _snapshot = book.snapshot();
|
|
});
|
|
});
|
|
}
|
|
|
|
fn bench_market_impact_calculation(c: &mut Criterion) {
|
|
let mut book = OrderBook::new("test_token".to_string(), 100);
|
|
|
|
// Pre-populate with levels
|
|
for i in 1..=30 {
|
|
let price = Decimal::from(50 + i) / Decimal::from(100);
|
|
let delta = OrderDelta {
|
|
token_id: "test_token".to_string(),
|
|
timestamp: chrono::Utc::now(),
|
|
side: if i % 2 == 0 { Side::BUY } else { Side::SELL },
|
|
price,
|
|
size: dec!(100),
|
|
sequence: i,
|
|
};
|
|
book.apply_delta(delta).unwrap();
|
|
}
|
|
|
|
c.bench_function("market_impact_calculation", |b| {
|
|
b.iter(|| {
|
|
let _impact = book.calculate_market_impact(Side::BUY, dec!(50));
|
|
});
|
|
});
|
|
}
|
|
|
|
fn bench_high_frequency_updates(c: &mut Criterion) {
|
|
c.bench_function("high_frequency_updates", |b| {
|
|
b.iter(|| {
|
|
let mut book = OrderBook::new("test_token".to_string(), 100);
|
|
let start_time = Instant::now();
|
|
|
|
// Simulate high-frequency updates
|
|
for i in 1..=1000 {
|
|
let price = Decimal::from(500 + (i % 100)) / Decimal::from(1000);
|
|
let size = Decimal::from(10 + (i % 90));
|
|
let delta = OrderDelta {
|
|
token_id: "test_token".to_string(),
|
|
timestamp: chrono::Utc::now(),
|
|
side: if i % 2 == 0 { Side::BUY } else { Side::SELL },
|
|
price,
|
|
size,
|
|
sequence: i,
|
|
};
|
|
book.apply_delta(delta).unwrap();
|
|
|
|
// Check prices every 10 updates
|
|
if i % 10 == 0 {
|
|
let _bid = book.best_bid();
|
|
let _ask = book.best_ask();
|
|
}
|
|
}
|
|
|
|
let duration = start_time.elapsed();
|
|
black_box(duration);
|
|
});
|
|
});
|
|
}
|
|
|
|
fn bench_concurrent_access(c: &mut Criterion) {
|
|
use std::sync::atomic::{AtomicU64, Ordering};
|
|
use std::sync::Arc;
|
|
use tokio::sync::RwLock;
|
|
|
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
|
let mut initial_book = OrderBook::new("test_token".to_string(), 100);
|
|
|
|
for i in 1..=20 {
|
|
let price = Decimal::from(50 + i) / Decimal::from(100);
|
|
let delta = OrderDelta {
|
|
token_id: "test_token".to_string(),
|
|
timestamp: chrono::Utc::now(),
|
|
side: if i % 2 == 0 { Side::BUY } else { Side::SELL },
|
|
price,
|
|
size: dec!(100),
|
|
sequence: i,
|
|
};
|
|
initial_book.apply_delta(delta).unwrap();
|
|
}
|
|
|
|
let book = Arc::new(RwLock::new(initial_book));
|
|
let sequence = Arc::new(AtomicU64::new(20));
|
|
|
|
c.bench_function("concurrent_access", |b| {
|
|
b.iter(|| {
|
|
rt.block_on(async {
|
|
let mut tasks = Vec::new();
|
|
|
|
for i in 1..=10 {
|
|
let book = book.clone();
|
|
let sequence = sequence.clone();
|
|
tasks.push(tokio::spawn(async move {
|
|
let mut book = book.write().await;
|
|
let sequence = sequence.fetch_add(1, Ordering::Relaxed) + 1;
|
|
let price = Decimal::from(50 + i) / Decimal::from(100);
|
|
let delta = OrderDelta {
|
|
token_id: "test_token".to_string(),
|
|
timestamp: chrono::Utc::now(),
|
|
side: if i % 2 == 0 { Side::BUY } else { Side::SELL },
|
|
price,
|
|
size: dec!(100),
|
|
sequence,
|
|
};
|
|
book.apply_delta(delta).unwrap();
|
|
black_box(book.sequence);
|
|
}));
|
|
}
|
|
|
|
for _ in 0..20 {
|
|
let book = book.clone();
|
|
tasks.push(tokio::spawn(async move {
|
|
let book = book.read().await;
|
|
black_box((book.best_bid(), book.best_ask()));
|
|
}));
|
|
}
|
|
|
|
for task in tasks {
|
|
task.await.unwrap();
|
|
}
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
criterion_group!(
|
|
benches,
|
|
bench_book_creation,
|
|
bench_delta_application,
|
|
bench_best_price_lookup,
|
|
bench_book_snapshot,
|
|
bench_market_impact_calculation,
|
|
bench_high_frequency_updates,
|
|
bench_concurrent_access,
|
|
);
|
|
criterion_main!(benches);
|