Files
foxhunt/testing/integration/unit/concurrency_safety_tests.rs
jgrusewski 9c3d741a08 refactor: restructure repo — crates/, bin/, testing/ layout
Move 17 library crates into crates/, CLI binary into bin/fxt,
consolidate 10 test crates into testing/, split config crate
from deployment config files.

Root directory reduced from 38+ to ~17 directories.
All Cargo.toml paths and build.rs proto refs updated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:56:00 +01:00

833 lines
30 KiB
Rust

//! Comprehensive Concurrency Safety Tests for HFT System
//!
//! This module contains critical tests for verifying the Foxhunt HFT system's
//! safety under high-throughput concurrent operations. These tests ensure
//! REAL MONEY safety in production HFT environments.
//!
//! CRITICAL: These tests prevent race conditions, data corruption, and
//! financial losses in high-frequency trading scenarios.
use std::sync::{Arc, atomic::{AtomicU64, AtomicBool, Ordering}};
use std::time::{Duration, Instant};
use std::collections::HashMap;
use tokio::sync::{RwLock, Mutex, Semaphore, Barrier};
use tokio::task::JoinSet;
use futures::future::join_all;
use proptest::prelude::*;
use criterion::black_box;
/// Concurrency test configuration for high-throughput scenarios
#[derive(Debug, Clone)]
/// ConcurrencyTestConfig component.
pub struct ConcurrencyTestConfig {
pub thread_count: usize,
pub operations_per_thread: usize,
pub order_burst_size: usize,
pub market_data_rate_per_second: usize,
pub position_update_frequency_ms: u64,
pub concurrent_symbols: usize,
pub test_duration_seconds: u64,
}
impl Default for ConcurrencyTestConfig {
fn default() -> Self {
Self {
thread_count: 16,
operations_per_thread: 10_000,
order_burst_size: 100,
market_data_rate_per_second: 100_000,
position_update_frequency_ms: 1,
concurrent_symbols: 50,
test_duration_seconds: 30,
}
}
}
/// High-throughput concurrent order processing safety test
#[tokio::test]
async fn test_concurrent_order_processing_safety() {
let config = ConcurrencyTestConfig::default();
println!("🚀 Starting Concurrent Order Processing Safety Test");
println!("📊 Config: {} threads, {} ops/thread", config.thread_count, config.operations_per_thread);
// Test concurrent order submissions
test_concurrent_order_submissions(&config).await;
// Test concurrent order modifications
test_concurrent_order_modifications(&config).await;
// Test concurrent fills processing
test_concurrent_fills_processing(&config).await;
// Test concurrent position updates
test_concurrent_position_updates(&config).await;
println!("✅ Concurrent Order Processing Safety Test Completed");
}
/// Test thousands of concurrent order submissions
async fn test_concurrent_order_submissions(config: &ConcurrencyTestConfig) {
println!("📋 Testing Concurrent Order Submissions");
let order_counter = Arc::new(AtomicU64::new(0));
let success_counter = Arc::new(AtomicU64::new(0));
let error_counter = Arc::new(AtomicU64::new(0));
let barrier = Arc::new(Barrier::new(config.thread_count));
let start_time = Instant::now();
let mut tasks = JoinSet::new();
// Spawn concurrent order submission tasks
for thread_id in 0..config.thread_count {
let order_counter = order_counter.clone();
let success_counter = success_counter.clone();
let error_counter = error_counter.clone();
let barrier = barrier.clone();
let ops_per_thread = config.operations_per_thread;
tasks.spawn(async move {
// Wait for all threads to be ready
barrier.wait().await;
for op_id in 0..ops_per_thread {
let order_id = order_counter.fetch_add(1, Ordering::Relaxed);
// Create test order with unique characteristics
let order = create_test_order(thread_id, op_id, order_id);
// Submit order concurrently
match submit_order_concurrent(order).await {
Ok(_) => {
success_counter.fetch_add(1, Ordering::Relaxed);
}
Err(_) => {
error_counter.fetch_add(1, Ordering::Relaxed);
}
}
}
});
}
// Wait for all tasks to complete
while let Some(result) = tasks.join_next().await {
result.expect("Task should complete successfully");
}
let elapsed = start_time.elapsed();
let total_orders = order_counter.load(Ordering::Relaxed);
let successes = success_counter.load(Ordering::Relaxed);
let errors = error_counter.load(Ordering::Relaxed);
// Verify results
assert_eq!(total_orders, (config.thread_count * config.operations_per_thread) as u64);
assert_eq!(successes + errors, total_orders);
// Performance validation
let orders_per_second = total_orders as f64 / elapsed.as_secs_f64();
println!("📊 Orders processed: {}, Rate: {:.0} orders/sec", total_orders, orders_per_second);
// Ensure high throughput (should exceed 50k orders/sec)
assert!(orders_per_second > 50_000.0,
"Order processing rate {:.0} should exceed 50k orders/sec", orders_per_second);
// Verify no data corruption occurred
verify_order_data_integrity().await;
println!("✅ Concurrent order submissions test passed");
}
/// Test concurrent order modifications without race conditions
async fn test_concurrent_order_modifications(config: &ConcurrencyTestConfig) {
println!("📋 Testing Concurrent Order Modifications");
// Create a shared order that will be modified concurrently
let shared_order = Arc::new(RwLock::new(create_shared_test_order()));
let modification_counter = Arc::new(AtomicU64::new(0));
let barrier = Arc::new(Barrier::new(config.thread_count));
let mut tasks = JoinSet::new();
// Spawn concurrent modification tasks
for thread_id in 0..config.thread_count {
let shared_order = shared_order.clone();
let modification_counter = modification_counter.clone();
let barrier = barrier.clone();
let modifications_per_thread = config.operations_per_thread / 10; // Fewer modifications
tasks.spawn(async move {
barrier.wait().await;
for _ in 0..modifications_per_thread {
// Read current order state
let current_price = {
let order = shared_order.read().await;
order.price.unwrap_or(Price::from_f64(100.0).expect("Valid price"))
};
// Modify order (this should be atomic)
{
let mut order = shared_order.write().await;
let new_price = Price::from_f64(current_price.to_f64().expect("Valid price") + 0.01);
order.price = Some(new_price);
order.quantity = Quantity::new(order.quantity.value() + 1);
}
modification_counter.fetch_add(1, Ordering::Relaxed);
// Small delay to increase chance of race conditions if they exist
tokio::task::yield_now().await;
}
});
}
// Wait for all modifications to complete
while let Some(result) = tasks.join_next().await {
result.expect("Modification task should complete successfully");
}
// Verify final state consistency
let final_order = shared_order.read().await;
let total_modifications = modification_counter.load(Ordering::Relaxed);
let expected_modifications = (config.thread_count * config.operations_per_thread / 10) as u64;
assert_eq!(total_modifications, expected_modifications);
// Verify order state is consistent (no race condition artifacts)
assert!(final_order.price.is_some());
assert!(final_order.quantity.value() > 0);
// Check for data corruption indicators
let price_value = final_order.price.unwrap().to_f64();
assert!(price_value > 99.0 && price_value < 200.0,
"Price should be within reasonable range, got {}", price_value);
println!("✅ Concurrent order modifications test passed");
}
/// Test concurrent fills processing for data integrity
async fn test_concurrent_fills_processing(config: &ConcurrencyTestConfig) {
println!("📋 Testing Concurrent Fills Processing");
let total_fill_volume = Arc::new(AtomicU64::new(0));
let fill_count = Arc::new(AtomicU64::new(0));
let barrier = Arc::new(Barrier::new(config.thread_count));
let mut tasks = JoinSet::new();
// Spawn concurrent fill processing tasks
for thread_id in 0..config.thread_count {
let total_fill_volume = total_fill_volume.clone();
let fill_count = fill_count.clone();
let barrier = barrier.clone();
let fills_per_thread = config.operations_per_thread / 5;
tasks.spawn(async move {
barrier.wait().await;
for fill_id in 0..fills_per_thread {
let fill = create_test_fill(thread_id, fill_id);
let fill_volume = fill.quantity.value();
// Process fill atomically
match process_fill_concurrent(fill).await {
Ok(_) => {
total_fill_volume.fetch_add(fill_volume, Ordering::Relaxed);
fill_count.fetch_add(1, Ordering::Relaxed);
}
Err(e) => {
println!("⚠️ Fill processing error: {:?}", e);
}
}
}
});
}
// Wait for all fill processing to complete
while let Some(result) = tasks.join_next().await {
result.expect("Fill processing task should complete successfully");
}
let final_volume = total_fill_volume.load(Ordering::Relaxed);
let final_count = fill_count.load(Ordering::Relaxed);
let expected_count = (config.thread_count * config.operations_per_thread / 5) as u64;
// Verify fill processing consistency
assert_eq!(final_count, expected_count);
assert!(final_volume > 0, "Total fill volume should be positive");
// Verify position consistency after fills
verify_position_consistency_after_fills().await;
println!("✅ Concurrent fills processing test passed");
}
/// Test concurrent position updates for accuracy
async fn test_concurrent_position_updates(config: &ConcurrencyTestConfig) {
println!("📋 Testing Concurrent Position Updates");
let position_map = Arc::new(RwLock::new(HashMap::<Symbol, Position>::new()));
let update_counter = Arc::new(AtomicU64::new(0));
let barrier = Arc::new(Barrier::new(config.thread_count));
// Initialize positions for test symbols
{
let mut positions = position_map.write().await;
for i in 0..config.concurrent_symbols {
let symbol = Symbol::new(&format!("TEST{:03}", i)).unwrap();
let position = Position::new(
symbol.clone(),
Side::Buy,
Quantity::new(1000),
Price::from_f64(100.0).expect("Valid price"),
Timestamp::now()
);
positions.insert(symbol, position);
}
}
let mut tasks = JoinSet::new();
// Spawn concurrent position update tasks
for thread_id in 0..config.thread_count {
let position_map = position_map.clone();
let update_counter = update_counter.clone();
let barrier = barrier.clone();
let updates_per_thread = config.operations_per_thread / 2;
let symbols_count = config.concurrent_symbols;
tasks.spawn(async move {
barrier.wait().await;
for update_id in 0..updates_per_thread {
let symbol_index = (thread_id + update_id) % symbols_count;
let symbol = Symbol::new(&format!("TEST{:03}", symbol_index)).unwrap();
// Update position atomically
{
let mut positions = position_map.write().await;
if let Some(position) = positions.get_mut(&symbol) {
// Simulate position update from trade
let quantity_change = Quantity::new(10);
position.add_quantity(quantity_change);
update_counter.fetch_add(1, Ordering::Relaxed);
}
}
// Yield to increase concurrency
tokio::task::yield_now().await;
}
});
}
// Wait for all position updates to complete
while let Some(result) = tasks.join_next().await {
result.expect("Position update task should complete successfully");
}
let total_updates = update_counter.load(Ordering::Relaxed);
let expected_updates = (config.thread_count * config.operations_per_thread / 2) as u64;
// Verify update count
assert_eq!(total_updates, expected_updates);
// Verify position consistency
let positions = position_map.read().await;
for (symbol, position) in &positions {
assert!(position.quantity.value() >= 1000,
"Position for {} should have grown from initial 1000", symbol.as_str());
// Verify position data integrity
assert!(position.average_price().to_f64() > 0.0);
assert!(position.timestamp().as_millis() > 0);
}
println!("✅ Concurrent position updates test passed");
}
/// Test lock-free data structures under high contention
#[tokio::test]
async fn test_lock_free_data_structures() {
println!("🚀 Starting Lock-Free Data Structures Test");
let config = ConcurrencyTestConfig::default();
// Test atomic operations under contention
test_atomic_operations_contention(&config).await;
// Test lock-free price updates
test_lock_free_price_updates(&config).await;
// Test concurrent order book operations
test_concurrent_order_book_operations(&config).await;
println!("✅ Lock-Free Data Structures Test Completed");
}
/// Test atomic operations under high contention
async fn test_atomic_operations_contention(config: &ConcurrencyTestConfig) {
println!("📋 Testing Atomic Operations Under Contention");
let atomic_counter = Arc::new(AtomicU64::new(0));
let atomic_price = Arc::new(AtomicU64::new(100_000_000)); // Price in microunits
let barrier = Arc::new(Barrier::new(config.thread_count));
let mut tasks = JoinSet::new();
for thread_id in 0..config.thread_count {
let atomic_counter = atomic_counter.clone();
let atomic_price = atomic_price.clone();
let barrier = barrier.clone();
let operations = config.operations_per_thread;
tasks.spawn(async move {
barrier.wait().await;
for _ in 0..operations {
// Test different atomic operations
let _old_counter = atomic_counter.fetch_add(1, Ordering::SeqCst);
// Simulate price updates with compare-and-swap
let current_price = atomic_price.load(Ordering::Acquire);
let new_price = current_price + 1;
// Attempt atomic price update
let _result = atomic_price.compare_exchange_weak(
current_price,
new_price,
Ordering::Release,
Ordering::Relaxed
);
// Yield to increase contention
tokio::task::yield_now().await;
}
});
}
// Wait for all atomic operations to complete
while let Some(result) = tasks.join_next().await {
result.expect("Atomic operations task should complete successfully");
}
let final_counter = atomic_counter.load(Ordering::SeqCst);
let final_price = atomic_price.load(Ordering::SeqCst);
// Verify atomic operations completed correctly
let expected_counter = (config.thread_count * config.operations_per_thread) as u64;
assert_eq!(final_counter, expected_counter);
assert!(final_price >= 100_000_000); // Price should have increased
println!("✅ Atomic operations under contention test passed");
}
/// Test lock-free `price` updates for market data
async fn test_lock_free_price_updates(config: &ConcurrencyTestConfig) {
println!("📋 Testing Lock-Free Price Updates");
let price_feeds = Arc::new(create_lock_free_price_feeds(config.concurrent_symbols));
let update_counter = Arc::new(AtomicU64::new(0));
let barrier = Arc::new(Barrier::new(config.thread_count));
let mut tasks = JoinSet::new();
// Spawn price update tasks
for thread_id in 0..config.thread_count {
let price_feeds = price_feeds.clone();
let update_counter = update_counter.clone();
let barrier = barrier.clone();
let updates_per_thread = config.operations_per_thread;
let symbols_count = config.concurrent_symbols;
tasks.spawn(async move {
barrier.wait().await;
for update_id in 0..updates_per_thread {
let symbol_index = (thread_id + update_id) % symbols_count;
let new_price = 100.0 + (update_id as f64 * 0.01);
// Update price in lock-free manner
if update_price_lock_free(&price_feeds, symbol_index, new_price) {
update_counter.fetch_add(1, Ordering::Relaxed);
}
// Minimal delay to test rapid updates
if update_id % 1000 == 0 {
tokio::task::yield_now().await;
}
}
});
}
// Wait for all price updates to complete
while let Some(result) = tasks.join_next().await {
result.expect("Price update task should complete successfully");
}
let total_updates = update_counter.load(Ordering::Relaxed);
// Verify price updates completed
assert!(total_updates > 0, "Some price updates should have succeeded");
// Verify price feed consistency
verify_price_feed_consistency(&price_feeds).await;
println!("✅ Lock-free price updates test passed");
}
/// Test concurrent order book operations
async fn test_concurrent_order_book_operations(config: &ConcurrencyTestConfig) {
println!("📋 Testing Concurrent Order Book Operations");
let order_book = Arc::new(create_concurrent_order_book());
let operation_counter = Arc::new(AtomicU64::new(0));
let barrier = Arc::new(Barrier::new(config.thread_count));
let mut tasks = JoinSet::new();
// Spawn order book operation tasks
for thread_id in 0..config.thread_count {
let order_book = order_book.clone();
let operation_counter = operation_counter.clone();
let barrier = barrier.clone();
let operations = config.operations_per_thread;
tasks.spawn(async move {
barrier.wait().await;
for op_id in 0..operations {
let operation_type = op_id % 4;
match operation_type {
0 => {
// Add buy order
let price = Price::from_f64(99.5 - (op_id as f64 * 0.001).expect("Valid price"));
let quantity = Quantity::new(100);
add_order_to_book(&order_book, Side::Buy, price, quantity).await;
}
1 => {
// Add sell order
let price = Price::from_f64(100.5 + (op_id as f64 * 0.001).expect("Valid price"));
let quantity = Quantity::new(100);
add_order_to_book(&order_book, Side::Sell, price, quantity).await;
}
2 => {
// Get best bid/ask
let _best_prices = get_best_prices(&order_book).await;
}
3 => {
// Cancel random order
cancel_random_order(&order_book).await;
}
_ => unreachable!(),
}
operation_counter.fetch_add(1, Ordering::Relaxed);
if op_id % 100 == 0 {
tokio::task::yield_now().await;
}
}
});
}
// Wait for all order book operations to complete
while let Some(result) = tasks.join_next().await {
result.expect("Order book operation task should complete successfully");
}
let total_operations = operation_counter.load(Ordering::Relaxed);
let expected_operations = (config.thread_count * config.operations_per_thread) as u64;
// Verify all operations completed
assert_eq!(total_operations, expected_operations);
// Verify order book integrity
verify_order_book_integrity(&order_book).await;
println!("✅ Concurrent order book operations test passed");
}
/// Property-based test for concurrent operations invariants
proptest! {
#[test]
fn test_concurrent_operations_invariants(
thread_count in 2..16usize,
operations_per_thread in 100..1000usize,
initial_quantity in 1000..10000u64,
price_range in 50.0..150.0f64
) {
tokio_test::block_on(async {
// Test that concurrent position updates maintain mathematical invariants
let total_operations = thread_count * operations_per_thread;
let position = Arc::new(RwLock::new(Position::new(
Symbol::new("PROPTEST".to_string()),
Side::Buy,
Quantity::new(initial_quantity),
Price::from_f64(price_range).expect("Valid price"),
Timestamp::now()
)));
let barrier = Arc::new(Barrier::new(thread_count));
let update_counter = Arc::new(AtomicU64::new(0));
let mut tasks = JoinSet::new();
for _ in 0..thread_count {
let position = position.clone();
let barrier = barrier.clone();
let update_counter = update_counter.clone();
tasks.spawn(async move {
barrier.wait().await;
for _ in 0..operations_per_thread {
let mut pos = position.write().await;
pos.add_quantity(Quantity::new(1));
update_counter.fetch_add(1, Ordering::Relaxed);
}
});
}
while let Some(result) = tasks.join_next().await {
result.expect("Task should complete");
}
let final_position = position.read().await;
let final_quantity = final_position.quantity.value();
let expected_quantity = initial_quantity + total_operations as u64;
prop_assert_eq!(final_quantity, expected_quantity);
prop_assert_eq!(update_counter.load(Ordering::Relaxed), total_operations as u64);
});
}
}
// ===== HELPER FUNCTIONS AND MOCKS =====
/// Create a test order with unique characteristics
fn create_test_order(thread_id: usize, op_id: usize, order_id: u64) -> Order {
Order::new(
OrderId::new(order_id),
Symbol::new(&format!("SYM{:02}", thread_id % 10)).unwrap(),
Side::Buy,
OrderType::Limit,
Quantity::new(100 + op_id as u64),
Some(Price::from_f64(100.0 + (op_id as f64 * 0.01).expect("Valid price"))),
TimeInForce::GoodTillCancel
)
}
/// Create a shared test order for modification testing
fn create_shared_test_order() -> Order {
Order::new(
OrderId::new(999999),
Symbol::new("SHARED".to_string()),
Side::Buy,
OrderType::Limit,
Quantity::new(1000),
Some(Price::from_f64(100.0).expect("Valid price")),
TimeInForce::GoodTillCancel
)
}
/// Create a test fill
fn create_test_fill(thread_id: usize, fill_id: usize) -> Fill {
Fill::new(
OrderId::new(thread_id as u64 * 1000 + fill_id as u64),
Symbol::new(&format!("SYM{:02}", thread_id % 10)).unwrap(),
Side::Buy,
Quantity::new(50 + fill_id as u64),
Price::from_f64(100.0 + (fill_id as f64 * 0.001).expect("Valid price")),
Timestamp::now(),
Some(format!("FILL_{}_{}_{}", thread_id, fill_id, Uuid::new_v4())),
None
)
}
/// Mock function to submit orders concurrently
async fn submit_order_concurrent(order: Order) -> Result<(), String> {
// Simulate order processing latency
tokio::task::yield_now().await;
// Simulate occasional failures (5% failure rate)
if rand::random::<f64>() < 0.05 {
Err("Simulated order rejection".to_string())
} else {
Ok(())
}
}
/// Mock function to process fills concurrently
async fn process_fill_concurrent(fill: Fill) -> Result<(), String> {
// Simulate fill processing
tokio::task::yield_now().await;
// Validate fill data
if fill.quantity.value() == 0 {
Err("Invalid fill quantity".to_string())
} else {
Ok(())
}
}
/// Verify order data integrity after concurrent operations
async fn verify_order_data_integrity() {
// Mock verification - in real implementation would check data consistency
tokio::task::yield_now().await;
}
/// Verify position consistency after fills
async fn verify_position_consistency_after_fills() {
// Mock verification - in real implementation would check position calculations
tokio::task::yield_now().await;
}
/// Create lock-free `price` feeds for testing
fn create_lock_free_price_feeds(symbol_count: usize) -> Vec<AtomicU64> {
(0..symbol_count)
.map(|_| AtomicU64::new(100_000_000)) // Initial price: $100
.collect()
}
/// Update `price` in lock-free manner
fn update_price_lock_free(price_feeds: &[AtomicU64], symbol_index: usize, new_price: f64) -> bool {
if symbol_index >= price_feeds.len() {
return false;
}
let price_microunits = (new_price * 1_000_000.0) as u64;
price_feeds[symbol_index].store(price_microunits, Ordering::Release);
true
}
/// Verify `price` feed consistency
async fn verify_price_feed_consistency(price_feeds: &[AtomicU64]) {
for (i, price_feed) in price_feeds.into_iter().enumerate() {
let price = price_feed.load(Ordering::Acquire);
assert!(price > 0, "Price feed {} should have positive price", i);
assert!(price < 1_000_000_000, "Price feed {} should have reasonable price", i);
}
}
/// Create concurrent order book for testing
fn create_concurrent_order_book() -> ConcurrentOrderBook {
ConcurrentOrderBook::new()
}
/// Mock concurrent order book
#[derive(Debug)]
struct ConcurrentOrderBook {
bid_count: AtomicU64,
ask_count: AtomicU64,
operation_count: AtomicU64,
}
impl ConcurrentOrderBook {
fn new() -> Self {
Self {
bid_count: AtomicU64::new(0),
ask_count: AtomicU64::new(0),
operation_count: AtomicU64::new(0),
}
}
}
/// Add order to concurrent order book
async fn add_order_to_book(
book: &ConcurrentOrderBook,
side: Side,
_price: Price,
_quantity: Quantity,
) {
match side {
Side::Buy => {
book.bid_count.fetch_add(1, Ordering::Relaxed);
}
Side::Sell => {
book.ask_count.fetch_add(1, Ordering::Relaxed);
}
}
book.operation_count.fetch_add(1, Ordering::Relaxed);
}
/// Get best prices from order book
async fn get_best_prices(book: &ConcurrentOrderBook) -> (Option<Price>, Option<Price>) {
book.operation_count.fetch_add(1, Ordering::Relaxed);
(Some(Price::from_f64(99.5).expect("Valid price")), Some(Price::from_f64(100.5).expect("Valid price")))
}
/// Cancel random order from book
async fn cancel_random_order(book: &ConcurrentOrderBook) {
book.operation_count.fetch_add(1, Ordering::Relaxed);
}
/// Verify order book integrity
async fn verify_order_book_integrity(book: &ConcurrentOrderBook) {
let bid_count = book.bid_count.load(Ordering::Relaxed);
let ask_count = book.ask_count.load(Ordering::Relaxed);
let operation_count = book.operation_count.load(Ordering::Relaxed);
assert!(bid_count >= 0);
assert!(ask_count >= 0);
assert!(operation_count > 0);
println!("📊 Order book stats - Bids: {}, Asks: {}, Total ops: {}",
bid_count, ask_count, operation_count);
}
#[cfg(test)]
mod performance_benchmarks {
use super::*;
use criterion::{criterion_group, criterion_main, Criterion, BenchmarkId};
/// Benchmark concurrent order processing performance
pub fn bench_concurrent_order_processing(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("concurrent_order_processing");
for thread_count in &[1, 2, 4, 8, 16] {
group.bench_with_input(
BenchmarkId::new("threads", thread_count),
thread_count,
|b, &thread_count| {
b.to_async(&rt).iter(|| async {
let config = ConcurrencyTestConfig {
thread_count,
operations_per_thread: 1000,
..Default::default()
};
test_concurrent_order_submissions(&config).await;
});
},
);
}
group.finish();
}
/// Benchmark atomic operations performance
pub fn bench_atomic_operations(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
c.bench_function("atomic_price_updates", |b| {
b.to_async(&rt).iter(|| async {
let atomic_price = Arc::new(AtomicU64::new(100_000_000));
for _ in 0..10000 {
let current = atomic_price.load(Ordering::Acquire);
let _result = atomic_price.compare_exchange_weak(
current,
current + 1,
Ordering::Release,
Ordering::Relaxed,
);
}
});
});
}
criterion_group!(benches, bench_concurrent_order_processing, bench_atomic_operations);
criterion_main!(benches);
}