From ff132f7ec7a942a7eac4fd29e47aae9478af424b Mon Sep 17 00:00:00 2001 From: BDaws04 Date: Mon, 12 Jan 2026 23:32:13 +0000 Subject: [PATCH 1/2] add sonic-rs benchmarks for ticker, trade and l2 updates using safe and unsafe implementations --- sje/Cargo.toml | 1 + sje/benches/l2_update.rs | 63 ++++++++++++++++++++++++++++++++++++++-- sje/benches/ticker.rs | 45 +++++++++++++++++++++++++++- sje/benches/trade.rs | 47 +++++++++++++++++++++++++++++- 4 files changed, 152 insertions(+), 4 deletions(-) diff --git a/sje/Cargo.toml b/sje/Cargo.toml index b6c6453..c6f7a0a 100644 --- a/sje/Cargo.toml +++ b/sje/Cargo.toml @@ -21,6 +21,7 @@ sje_derive = { path = "../sje_derive" } criterion = "0.5.1" serde = { version = "1.0.217", features = ["derive"] } serde_json = "1.0.138" +sonic-rs = "0.3" [features] default = [] diff --git a/sje/benches/l2_update.rs b/sje/benches/l2_update.rs index 51a8360..d4c7418 100644 --- a/sje/benches/l2_update.rs +++ b/sje/benches/l2_update.rs @@ -2,7 +2,7 @@ use criterion::{Criterion, Throughput, criterion_group, criterion_main}; use serde::{Deserialize, Deserializer}; use sje_derive::Decoder; use std::str::FromStr; - +use sonic_rs::{from_slice, from_slice_unchecked}; const JSON: &[u8] = br#"{"e":"depthUpdate","E":1739836781765,"T":1739836781757,"s":"XRPUSDT","U":6780157664288,"u":6780157666166,"pu":6780157664112,"b":[["2.6461","6404.9"],["2.6468","22540.8"]],"a":[["2.6582","12708.6"],["2.6588","10898.1"],["2.6611","16595.4"]]}"#; #[derive(Debug, Copy, Clone, PartialEq)] @@ -140,5 +140,64 @@ fn serde_l2_update_benchmark(c: &mut Criterion) { }); } -criterion_group!(benches, sje_l2_update_benchmark, serde_l2_update_benchmark); +fn sonic_l2_update_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("sonic_safe"); + group.throughput(Throughput::Elements(1)); + group.throughput(Throughput::Bytes(JSON.len() as u64)); + + group.bench_function("sonic_l2_update", |b| { + b.iter(|| { + let l2_update: L2Update = from_slice(JSON).unwrap(); + + assert_eq!("depthUpdate", l2_update.event_type); + assert_eq!(1739836781765, l2_update.event_time); + assert_eq!(1739836781757, l2_update.transaction_time); + assert_eq!("XRPUSDT", l2_update.symbol); + assert_eq!(6780157664288, l2_update.first_update_id); + assert_eq!(6780157666166, l2_update.final_update_id); + assert_eq!(6780157664112, l2_update.previous_final_update_id); + + let mut bids = l2_update.bids.into_iter(); + assert_eq!((Price(2.6461), Quantity(6404.9)), bids.next().unwrap()); + assert_eq!((Price(2.6468), Quantity(22540.8)), bids.next().unwrap()); + + let mut asks = l2_update.asks.into_iter(); + assert_eq!((Price(2.6582), Quantity(12708.6)), asks.next().unwrap()); + assert_eq!((Price(2.6588), Quantity(10898.1)), asks.next().unwrap()); + assert_eq!((Price(2.6611), Quantity(16595.4)), asks.next().unwrap()); + }) + }); +} + +fn sonic_unchecked_l2_update_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("sonic_unsafe"); + group.throughput(Throughput::Elements(1)); + group.throughput(Throughput::Bytes(JSON.len() as u64)); + + group.bench_function("sonic_l2_update", |b| { + b.iter(|| { + let l2_update: L2Update = unsafe {from_slice_unchecked(JSON).unwrap()}; + + assert_eq!("depthUpdate", l2_update.event_type); + assert_eq!(1739836781765, l2_update.event_time); + assert_eq!(1739836781757, l2_update.transaction_time); + assert_eq!("XRPUSDT", l2_update.symbol); + assert_eq!(6780157664288, l2_update.first_update_id); + assert_eq!(6780157666166, l2_update.final_update_id); + assert_eq!(6780157664112, l2_update.previous_final_update_id); + + let mut bids = l2_update.bids.into_iter(); + assert_eq!((Price(2.6461), Quantity(6404.9)), bids.next().unwrap()); + assert_eq!((Price(2.6468), Quantity(22540.8)), bids.next().unwrap()); + + let mut asks = l2_update.asks.into_iter(); + assert_eq!((Price(2.6582), Quantity(12708.6)), asks.next().unwrap()); + assert_eq!((Price(2.6588), Quantity(10898.1)), asks.next().unwrap()); + assert_eq!((Price(2.6611), Quantity(16595.4)), asks.next().unwrap()); + }) + }); +} + + +criterion_group!(benches, sje_l2_update_benchmark, serde_l2_update_benchmark, sonic_l2_update_benchmark, sonic_unchecked_l2_update_benchmark); criterion_main!(benches); diff --git a/sje/benches/ticker.rs b/sje/benches/ticker.rs index adcf7a2..d43492d 100644 --- a/sje/benches/ticker.rs +++ b/sje/benches/ticker.rs @@ -1,6 +1,7 @@ use criterion::{Criterion, Throughput, criterion_group, criterion_main}; use serde::Deserialize; use sje_derive::Decoder; +use sonic_rs::{from_slice, from_slice_unchecked}; const JSON: &[u8] = br#"{"e":"bookTicker","u":6780157666962,"s":"BTCUSDT","b":"95732.60","B":"2.073","a":"95732.70","A":"23.383","T":1739836781773,"E":1739836781774}"#; @@ -79,5 +80,47 @@ fn serde_ticker_benchmark(c: &mut Criterion) { }); } -criterion_group!(benches, sje_ticker_benchmark, serde_ticker_benchmark); +fn sonic_ticker_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("sonic_safe"); + group.throughput(Throughput::Elements(1)); + group.throughput(Throughput::Bytes(JSON.len() as u64)); + + group.bench_function("sonic_ticker", |b| { + b.iter(|| { + let ticker: Ticker = from_slice(JSON).unwrap(); + assert_eq!("bookTicker", ticker.event_type); + assert_eq!(6780157666962, ticker.update_id); + assert_eq!("BTCUSDT", ticker.symbol); + assert_eq!("95732.60", ticker.bid_price); + assert_eq!("2.073", ticker.bid_qty); + assert_eq!("95732.70", ticker.ask_price); + assert_eq!("23.383", ticker.ask_qty); + assert_eq!(1739836781773, ticker.transaction_time); + assert_eq!(1739836781774, ticker.event_time); + }) + }); +} + +fn sonic_unchecked_ticker_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("sonic_unsafe"); + group.throughput(Throughput::Elements(1)); + group.throughput(Throughput::Bytes(JSON.len() as u64)); + + group.bench_function("sonic_ticker", |b| { + b.iter(|| { + let ticker: Ticker = unsafe {from_slice_unchecked(JSON).unwrap()}; + assert_eq!("bookTicker", ticker.event_type); + assert_eq!(6780157666962, ticker.update_id); + assert_eq!("BTCUSDT", ticker.symbol); + assert_eq!("95732.60", ticker.bid_price); + assert_eq!("2.073", ticker.bid_qty); + assert_eq!("95732.70", ticker.ask_price); + assert_eq!("23.383", ticker.ask_qty); + assert_eq!(1739836781773, ticker.transaction_time); + assert_eq!(1739836781774, ticker.event_time); + }) + }); +} + +criterion_group!(benches, sje_ticker_benchmark, serde_ticker_benchmark, sonic_ticker_benchmark, sonic_unchecked_ticker_benchmark); criterion_main!(benches); diff --git a/sje/benches/trade.rs b/sje/benches/trade.rs index f6f9349..67ab42b 100644 --- a/sje/benches/trade.rs +++ b/sje/benches/trade.rs @@ -1,6 +1,7 @@ use criterion::{Criterion, Throughput, criterion_group, criterion_main}; use serde::Deserialize; use sje_derive::Decoder; +use sonic_rs::{from_slice, from_slice_unchecked}; const JSON: &[u8] = br#"{"e":"trade","E":1705085312569,"s":"BTCUSDT","t":3370034463,"p":"43520.00000000","q":"0.00022000","b":24269765071,"a":24269767699,"T":1705085312568,"m":true,"M":true}"#; @@ -84,5 +85,49 @@ fn serde_trade_benchmark(c: &mut Criterion) { }); } -criterion_group!(benches, sje_trade_benchmark, serde_trade_benchmark); +fn sonic_trade_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("sonic_safe"); + group.throughput(Throughput::Elements(1)); + group.throughput(Throughput::Bytes(JSON.len() as u64)); + + group.bench_function("sonic_trade", |b| { + b.iter(|| { + let trade: Trade = from_slice(JSON).unwrap(); + assert_eq!("trade", trade.event_type); + assert_eq!(1705085312569, trade.event_time); + assert_eq!("BTCUSDT", trade.symbol); + assert_eq!(3370034463, trade.trade_id); + assert_eq!("43520.00000000", trade.price); + assert_eq!("0.00022000", trade.quantity); + assert_eq!(24269765071, trade.buyer_order_id); + assert_eq!(24269767699, trade.seller_order_id); + assert_eq!(1705085312568, trade.transaction_time); + assert!(trade.is_buyer_maker); + }) + }); +} + +fn sonic_unchecked_trade_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("sonic_unsafe"); + group.throughput(Throughput::Elements(1)); + group.throughput(Throughput::Bytes(JSON.len() as u64)); + + group.bench_function("sonic_trade", |b| { + b.iter(|| { + let trade: Trade = unsafe {from_slice_unchecked(JSON).unwrap()}; + assert_eq!("trade", trade.event_type); + assert_eq!(1705085312569, trade.event_time); + assert_eq!("BTCUSDT", trade.symbol); + assert_eq!(3370034463, trade.trade_id); + assert_eq!("43520.00000000", trade.price); + assert_eq!("0.00022000", trade.quantity); + assert_eq!(24269765071, trade.buyer_order_id); + assert_eq!(24269767699, trade.seller_order_id); + assert_eq!(1705085312568, trade.transaction_time); + assert!(trade.is_buyer_maker); + }) + }); +} + +criterion_group!(benches, sje_trade_benchmark, serde_trade_benchmark, sonic_trade_benchmark, sonic_unchecked_trade_benchmark); criterion_main!(benches); From c9cfd0df96f3a49d29915d7e19dfad1db5dd1518 Mon Sep 17 00:00:00 2001 From: BDaws04 Date: Wed, 14 Jan 2026 15:48:26 +0000 Subject: [PATCH 2/2] use cargo fmt --- sje/benches/l2_update.rs | 13 +++++++++---- sje/benches/ticker.rs | 10 ++++++++-- sje/benches/trade.rs | 10 ++++++++-- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/sje/benches/l2_update.rs b/sje/benches/l2_update.rs index d4c7418..065792d 100644 --- a/sje/benches/l2_update.rs +++ b/sje/benches/l2_update.rs @@ -1,8 +1,8 @@ use criterion::{Criterion, Throughput, criterion_group, criterion_main}; use serde::{Deserialize, Deserializer}; use sje_derive::Decoder; -use std::str::FromStr; use sonic_rs::{from_slice, from_slice_unchecked}; +use std::str::FromStr; const JSON: &[u8] = br#"{"e":"depthUpdate","E":1739836781765,"T":1739836781757,"s":"XRPUSDT","U":6780157664288,"u":6780157666166,"pu":6780157664112,"b":[["2.6461","6404.9"],["2.6468","22540.8"]],"a":[["2.6582","12708.6"],["2.6588","10898.1"],["2.6611","16595.4"]]}"#; #[derive(Debug, Copy, Clone, PartialEq)] @@ -176,7 +176,7 @@ fn sonic_unchecked_l2_update_benchmark(c: &mut Criterion) { group.bench_function("sonic_l2_update", |b| { b.iter(|| { - let l2_update: L2Update = unsafe {from_slice_unchecked(JSON).unwrap()}; + let l2_update: L2Update = unsafe { from_slice_unchecked(JSON).unwrap() }; assert_eq!("depthUpdate", l2_update.event_type); assert_eq!(1739836781765, l2_update.event_time); @@ -198,6 +198,11 @@ fn sonic_unchecked_l2_update_benchmark(c: &mut Criterion) { }); } - -criterion_group!(benches, sje_l2_update_benchmark, serde_l2_update_benchmark, sonic_l2_update_benchmark, sonic_unchecked_l2_update_benchmark); +criterion_group!( + benches, + sje_l2_update_benchmark, + serde_l2_update_benchmark, + sonic_l2_update_benchmark, + sonic_unchecked_l2_update_benchmark +); criterion_main!(benches); diff --git a/sje/benches/ticker.rs b/sje/benches/ticker.rs index d43492d..745729c 100644 --- a/sje/benches/ticker.rs +++ b/sje/benches/ticker.rs @@ -108,7 +108,7 @@ fn sonic_unchecked_ticker_benchmark(c: &mut Criterion) { group.bench_function("sonic_ticker", |b| { b.iter(|| { - let ticker: Ticker = unsafe {from_slice_unchecked(JSON).unwrap()}; + let ticker: Ticker = unsafe { from_slice_unchecked(JSON).unwrap() }; assert_eq!("bookTicker", ticker.event_type); assert_eq!(6780157666962, ticker.update_id); assert_eq!("BTCUSDT", ticker.symbol); @@ -122,5 +122,11 @@ fn sonic_unchecked_ticker_benchmark(c: &mut Criterion) { }); } -criterion_group!(benches, sje_ticker_benchmark, serde_ticker_benchmark, sonic_ticker_benchmark, sonic_unchecked_ticker_benchmark); +criterion_group!( + benches, + sje_ticker_benchmark, + serde_ticker_benchmark, + sonic_ticker_benchmark, + sonic_unchecked_ticker_benchmark +); criterion_main!(benches); diff --git a/sje/benches/trade.rs b/sje/benches/trade.rs index 67ab42b..a038490 100644 --- a/sje/benches/trade.rs +++ b/sje/benches/trade.rs @@ -114,7 +114,7 @@ fn sonic_unchecked_trade_benchmark(c: &mut Criterion) { group.bench_function("sonic_trade", |b| { b.iter(|| { - let trade: Trade = unsafe {from_slice_unchecked(JSON).unwrap()}; + let trade: Trade = unsafe { from_slice_unchecked(JSON).unwrap() }; assert_eq!("trade", trade.event_type); assert_eq!(1705085312569, trade.event_time); assert_eq!("BTCUSDT", trade.symbol); @@ -129,5 +129,11 @@ fn sonic_unchecked_trade_benchmark(c: &mut Criterion) { }); } -criterion_group!(benches, sje_trade_benchmark, serde_trade_benchmark, sonic_trade_benchmark, sonic_unchecked_trade_benchmark); +criterion_group!( + benches, + sje_trade_benchmark, + serde_trade_benchmark, + sonic_trade_benchmark, + sonic_unchecked_trade_benchmark +); criterion_main!(benches);