Files
foxhunt/test_simd_fix.rs
jgrusewski 8cf9437c78 🔧 Partial fixes: S3 integration, SIMD improvements, field access corrections
- Restored S3 storage functionality with AWS SDK
- Fixed field access issues (removed underscore prefixes)
- Created Benzinga historical module
- Initial SIMD optimization (needs consolidation)
- Fixed multiple compilation errors

PENDING: SIMD consolidation, config centralization, shared libraries
2025-09-25 01:05:32 +02:00

273 lines
9.2 KiB
Rust

#!/usr/bin/env rust
//! Quick SIMD Performance Test
//!
//! This tests if the SIMD performance regression has been fixed.
use std::arch::x86_64::*;
use std::time::Instant;
use std::arch;
// Aligned data structures
#[repr(align(32))]
struct AlignedData {
data: Vec<f64>,
}
impl AlignedData {
fn from_slice(slice: &[f64]) -> Self {
let mut data = Vec::with_capacity(slice.len());
data.extend_from_slice(slice);
Self { data }
}
fn as_ptr(&self) -> *const f64 {
self.data.as_ptr()
}
}
// Scalar VWAP
fn scalar_vwap(prices: &[f64], volumes: &[f64]) -> f64 {
let mut total_value = 0.0;
let mut total_volume = 0.0;
for i in 0..prices.len() {
total_value += prices[i] * volumes[i];
total_volume += volumes[i];
}
if total_volume > 0.0 {
total_value / total_volume
} else {
0.0
}
}
// Original SIMD (slow - the regression)
unsafe fn original_simd_vwap(prices: &AlignedData, volumes: &AlignedData) -> f64 {
let mut price_volume_sum = _mm256_setzero_pd();
let mut volume_sum = _mm256_setzero_pd();
let len = prices.data.len();
let mut i = 0;
// Original inefficient nested loop with excessive prefetching
while i + 16 <= len {
// Excessive prefetching (performance killer)
_mm_prefetch(prices.as_ptr().add(i + 16) as *const i8, _MM_HINT_T0);
_mm_prefetch(volumes.as_ptr().add(i + 16) as *const i8, _MM_HINT_T0);
// Nested loop processing (inefficient)
for j in (i..i + 16).step_by(4) {
let price_vec = _mm256_loadu_pd(&prices.data[j]); // UNALIGNED load on aligned data!
let volume_vec = _mm256_loadu_pd(&volumes.data[j]);
let pv_vec = _mm256_mul_pd(price_vec, volume_vec);
price_volume_sum = _mm256_add_pd(price_volume_sum, pv_vec);
volume_sum = _mm256_add_pd(volume_sum, volume_vec);
}
i += 16;
}
// Remaining elements
while i + 4 <= len {
let price_vec = _mm256_loadu_pd(&prices.data[i]);
let volume_vec = _mm256_loadu_pd(&volumes.data[i]);
let pv_vec = _mm256_mul_pd(price_vec, volume_vec);
price_volume_sum = _mm256_add_pd(price_volume_sum, pv_vec);
volume_sum = _mm256_add_pd(volume_sum, volume_vec);
i += 4;
}
// Complex horizontal sum (slow)
let pv_sum = {
let sum_high_low = _mm256_hadd_pd(price_volume_sum, price_volume_sum);
let sum_128 = _mm256_extractf128_pd(sum_high_low, 1);
let sum_64 = _mm_add_pd(_mm256_castpd256_pd128(sum_high_low), sum_128);
_mm_cvtsd_f64(sum_64)
};
let vol_sum = {
let sum_high_low = _mm256_hadd_pd(volume_sum, volume_sum);
let sum_128 = _mm256_extractf128_pd(sum_high_low, 1);
let sum_64 = _mm_add_pd(_mm256_castpd256_pd128(sum_high_low), sum_128);
_mm_cvtsd_f64(sum_64)
};
let mut total_pv = pv_sum;
let mut total_volume = vol_sum;
for j in i..len {
total_pv += prices.data[j] * volumes.data[j];
total_volume += volumes.data[j];
}
if total_volume > 0.0 {
total_pv / total_volume
} else {
0.0
}
}
// Optimized SIMD (fast - the fix)
unsafe fn optimized_simd_vwap(prices: &AlignedData, volumes: &AlignedData) -> f64 {
let mut price_volume_sum = _mm256_setzero_pd();
let mut volume_sum = _mm256_setzero_pd();
let len = prices.data.len();
let mut i = 0;
let price_ptr = prices.as_ptr();
let volume_ptr = volumes.as_ptr();
// Simple, efficient loop - process 4 elements at a time
while i + 4 <= len {
// Use ALIGNED loads for aligned data (the fix!)
let price_vec = _mm256_load_pd(price_ptr.add(i));
let volume_vec = _mm256_load_pd(volume_ptr.add(i));
let pv_vec = _mm256_mul_pd(price_vec, volume_vec);
price_volume_sum = _mm256_add_pd(price_volume_sum, pv_vec);
volume_sum = _mm256_add_pd(volume_sum, volume_vec);
i += 4;
}
// Simple horizontal sum (fast)
let mut pv_array = [0.0; 4];
let mut vol_array = [0.0; 4];
_mm256_storeu_pd(pv_array.as_mut_ptr(), price_volume_sum);
_mm256_storeu_pd(vol_array.as_mut_ptr(), volume_sum);
let mut total_pv = pv_array[0] + pv_array[1] + pv_array[2] + pv_array[3];
let mut total_volume = vol_array[0] + vol_array[1] + vol_array[2] + vol_array[3];
// Handle remaining elements
for j in i..len {
total_pv += prices.data[j] * volumes.data[j];
total_volume += volumes.data[j];
}
if total_volume > 0.0 {
total_pv / total_volume
} else {
0.0
}
}
fn main() {
println!("🔧 SIMD Performance Regression Fix Test");
println!("=======================================");
if !arch::is_x86_feature_detected!("avx2") {
println!("❌ AVX2 not available - cannot test SIMD");
return;
}
// Generate test data
let data_size = 10_000;
let iterations = 5_000;
let mut prices = Vec::with_capacity(data_size);
let mut volumes = Vec::with_capacity(data_size);
for i in 0..data_size {
prices.push(100.0 + (i as f64) * 0.01);
volumes.push(1000.0 + (i as f64) * 0.1);
}
let aligned_prices = AlignedData::from_slice(&prices);
let aligned_volumes = AlignedData::from_slice(&volumes);
println!("Data size: {} elements", data_size);
println!("Iterations: {}", iterations);
println!();
// Verify correctness
let scalar_result = scalar_vwap(&prices, &volumes);
unsafe {
let original_result = original_simd_vwap(&aligned_prices, &aligned_volumes);
let optimized_result = optimized_simd_vwap(&aligned_prices, &aligned_volumes);
println!("Correctness Check:");
println!(" Scalar: {:.6}", scalar_result);
println!(" Original: {:.6}", original_result);
println!(" Optimized: {:.6}", optimized_result);
if (scalar_result - original_result).abs() > 1e-10 {
println!("❌ Original SIMD produces incorrect result!");
return;
}
if (scalar_result - optimized_result).abs() > 1e-10 {
println!("❌ Optimized SIMD produces incorrect result!");
return;
}
println!("✅ All results match");
println!();
// Warmup
for _ in 0..100 {
let _ = scalar_vwap(&prices, &volumes);
let _ = original_simd_vwap(&aligned_prices, &aligned_volumes);
let _ = optimized_simd_vwap(&aligned_prices, &aligned_volumes);
}
// Benchmark
println!("Running benchmarks...");
let start = Instant::now();
for _ in 0..iterations {
let _ = scalar_vwap(&prices, &volumes);
}
let scalar_time = start.elapsed().as_nanos();
let start = Instant::now();
for _ in 0..iterations {
let _ = original_simd_vwap(&aligned_prices, &aligned_volumes);
}
let original_simd_time = start.elapsed().as_nanos();
let start = Instant::now();
for _ in 0..iterations {
let _ = optimized_simd_vwap(&aligned_prices, &aligned_volumes);
}
let optimized_simd_time = start.elapsed().as_nanos();
println!();
println!("Performance Results:");
println!(" Scalar: {} ns", scalar_time);
println!(" Original SIMD: {} ns", original_simd_time);
println!(" Optimized SIMD: {} ns", optimized_simd_time);
println!();
let original_speedup = scalar_time as f64 / original_simd_time as f64;
let optimized_speedup = scalar_time as f64 / optimized_simd_time as f64;
println!("Speedup vs Scalar:");
println!(" Original SIMD: {:.2}x", original_speedup);
println!(" Optimized SIMD: {:.2}x", optimized_speedup);
println!();
// Analysis
if original_speedup < 1.0 {
println!("✅ Confirmed: Original SIMD is {}x SLOWER than scalar", 1.0 / original_speedup);
} else {
println!("⚠️ Unexpected: Original SIMD is not slower than scalar");
}
if optimized_speedup >= 4.0 {
println!("🎉 SUCCESS: Optimized SIMD is {}x FASTER - Target achieved!", optimized_speedup);
println!("✅ SIMD performance regression COMPLETELY FIXED!");
} else if optimized_speedup >= 2.0 {
println!("⚠️ PARTIAL SUCCESS: Optimized SIMD is {}x faster - Significant improvement!", optimized_speedup);
println!("🔧 SIMD performance substantially improved");
} else if optimized_speedup >= 1.0 {
println!("📈 IMPROVEMENT: Optimized SIMD is {}x faster - Some improvement", optimized_speedup);
} else {
println!("❌ FAILED: Optimized SIMD is still {}x slower", 1.0 / optimized_speedup);
}
let improvement = optimized_simd_time as f64 / original_simd_time as f64;
println!();
println!("Overall improvement: Optimized SIMD is {:.2}x faster than original SIMD", 1.0 / improvement);
}
}