use std::time::Instant;
use zeroproto::{MessageBuilder, MessageReader};
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("ZeroProto Performance Benchmarks");
println!("=================================");
let sizes = vec![10, 100, 1000, 10000];
for &size in &sizes {
println!("\n📊 Benchmarking message size: {} fields", size);
let test_data: Vec<u64> = (0..size).map(|i| i * 12345).collect();
let start = Instant::now();
let mut builder = MessageBuilder::new();
for (i, &value) in test_data.iter().enumerate() {
builder.set_scalar(i as u16, value)?;
}
let serialized = builder.finish();
let serialize_time = start.elapsed();
let start = Instant::now();
let reader = MessageReader::new(&serialized)?;
let deserialize_time = start.elapsed();
let start = Instant::now();
let mut sum = 0u64;
for i in 0..size {
let value: u64 = reader.get_scalar(i as u16)?;
sum += value;
}
let access_time = start.elapsed();
let expected_sum: u64 = test_data.iter().sum();
assert_eq!(sum, expected_sum, "Sum mismatch!");
println!(
" Serialization: {:>8.2} μs ({:>6.0} ns/field)",
serialize_time.as_micros(),
serialize_time.as_nanos() as f64 / size as f64
);
println!(
" Deserialization: {:>8.2} μs ({:>6.0} ns/field)",
deserialize_time.as_micros(),
deserialize_time.as_nanos() as f64 / size as f64
);
println!(
" Field access: {:>8.2} μs ({:>6.0} ns/field)",
access_time.as_micros(),
access_time.as_nanos() as f64 / size as f64
);
println!(" Total size: {} bytes", serialized.len());
println!(
" Bytes per field: {:.1}",
serialized.len() as f64 / size as f64
);
benchmark_zero_copy(&serialized, size.try_into().unwrap())?;
}
println!("\n🧵 String Handling Benchmark");
benchmark_strings()?;
println!("\n📚 Vector Handling Benchmark");
benchmark_vectors()?;
println!("\n🎯 Performance benchmarks completed!");
Ok(())
}
fn benchmark_zero_copy(data: &[u8], _field_count: usize) -> Result<(), Box<dyn std::error::Error>> {
let iterations = 1000;
let start = Instant::now();
for _ in 0..iterations {
let reader = MessageReader::new(data)?;
let _: u64 = reader.get_scalar(0)?;
}
let time = start.elapsed();
println!(
" Zero-copy readers: {:>8.2} μs ({:>6.0} ns/reader)",
time.as_micros(),
time.as_nanos() as f64 / iterations as f64
);
Ok(())
}
fn benchmark_strings() -> Result<(), Box<dyn std::error::Error>> {
let test_strings = vec![
"Hello",
"Hello, World!",
"This is a longer string with more content",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
];
for (i, test_string) in test_strings.iter().enumerate() {
let mut builder = MessageBuilder::new();
builder.set_string(0, test_string)?;
let data = builder.finish();
let iterations = 10000;
let start = Instant::now();
for _ in 0..iterations {
let reader = MessageReader::new(&data)?;
let string = reader.get_string(0)?;
assert_eq!(string, *test_string);
}
let time = start.elapsed();
println!(
" String {} ({} chars): {:>8.2} μs ({:>6.0} ns/access)",
i + 1,
test_string.len(),
time.as_micros(),
time.as_nanos() as f64 / iterations as f64
);
let reader = MessageReader::new(&data)?;
let string = reader.get_string(0)?;
let string_in_buffer = (string.as_ptr() as usize >= data.as_ptr() as usize)
&& ((string.as_ptr() as usize) < data.as_ptr() as usize + data.len());
println!(
" Zero-copy: {}",
if string_in_buffer { "✅" } else { "❌" }
);
}
Ok(())
}
fn benchmark_vectors() -> Result<(), Box<dyn std::error::Error>> {
let vector_sizes = vec![10, 100, 1000];
for &size in &vector_sizes {
let test_data: Vec<u32> = (0..size).map(|i| i as u32 * 2).collect();
let mut builder = MessageBuilder::new();
builder.set_vector(0, &test_data)?;
let data = builder.finish();
let iterations = 1000;
let start = Instant::now();
for _ in 0..iterations {
let reader = MessageReader::new(&data)?;
let vector_reader = reader.get_vector::<u32>(0)?;
let collected: Vec<u32> = vector_reader.collect()?;
assert_eq!(collected.len(), size);
}
let time = start.elapsed();
println!(
" Vector {} items: {:>8.2} μs ({:>6.0} ns/iteration)",
size,
time.as_micros(),
time.as_nanos() as f64 / iterations as f64
);
let start = Instant::now();
for _ in 0..iterations {
let reader = MessageReader::new(&data)?;
let vector_reader = reader.get_vector::<u32>(0)?;
for i in 0..std::cmp::min(5, size) {
let _: u32 = vector_reader.get(i)?;
}
}
let time = start.elapsed();
println!(
" Random access: {:>8.2} μs ({:>6.0} ns/access)",
time.as_micros(),
time.as_nanos() as f64 / (iterations * std::cmp::min(5, size)) as f64
);
}
Ok(())
}