use reputation_core::{Calculator, BatchOptions};
use reputation_types::AgentDataBuilder;
use std::time::Instant;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Reputation Engine Performance Guide ===\n");
let agents = generate_test_agents(10_000);
println!("1. SINGLE vs BATCH PROCESSING");
println!("-----------------------------");
compare_single_vs_batch(&agents)?;
println!("\n2. OPTIMAL CHUNK SIZES");
println!("----------------------");
test_chunk_sizes(&agents)?;
println!("\n3. CALCULATOR REUSE");
println!("-------------------");
demonstrate_calculator_reuse(&agents)?;
println!("\n4. MEMORY EFFICIENCY");
println!("--------------------");
demonstrate_memory_efficiency()?;
println!("\n5. PERFORMANCE TIPS");
println!("-------------------");
print_performance_tips();
Ok(())
}
fn generate_test_agents(count: usize) -> Vec<reputation_types::AgentData> {
(0..count)
.map(|i| {
let reviews = (i % 100) as u32;
let mut builder = AgentDataBuilder::new(&format!("did:perf:agent{}", i))
.total_interactions(reviews + (i % 50) as u32);
if reviews > 0 {
builder = builder.with_reviews(reviews, 3.0 + (i % 20) as f64 * 0.1);
}
if i % 10 == 0 {
builder = builder.mcp_level((i % 4) as u8);
}
builder.build().unwrap()
})
.collect()
}
fn compare_single_vs_batch(agents: &[reputation_types::AgentData]) -> Result<(), Box<dyn std::error::Error>> {
let calc = Calculator::default();
let test_size = 1000;
let test_agents = &agents[..test_size.min(agents.len())];
let start = Instant::now();
for agent in test_agents {
let _ = calc.calculate(agent)?;
}
let single_duration = start.elapsed();
let start = Instant::now();
let _ = calc.calculate_batch(test_agents);
let batch_duration = start.elapsed();
println!("Processing {} agents:", test_size);
println!(" Single (sequential): {:?}", single_duration);
println!(" Batch (parallel): {:?}", batch_duration);
println!(" Speedup: {:.2}x",
single_duration.as_secs_f64() / batch_duration.as_secs_f64());
println!("\nPer-agent timing:");
println!(" Single: {:?}/agent", single_duration / test_size as u32);
println!(" Batch: {:?}/agent", batch_duration / test_size as u32);
Ok(())
}
fn test_chunk_sizes(agents: &[reputation_types::AgentData]) -> Result<(), Box<dyn std::error::Error>> {
let calc = Calculator::default();
let test_size = 5000;
let test_agents = &agents[..test_size.min(agents.len())];
let chunk_sizes = vec![10, 50, 100, 200, 500, 1000];
let cpu_count = 8;
println!("Testing chunk sizes (CPUs: {}):", cpu_count);
println!("Chunk Size | Duration | Per Agent | Efficiency");
println!("-----------|-----------|-----------|------------");
for chunk_size in chunk_sizes {
let options = BatchOptions {
chunk_size: Some(chunk_size),
fail_fast: false,
progress_callback: None,
};
let start = Instant::now();
let result = calc.calculate_batch_with_options(test_agents, options);
let duration = start.elapsed();
let per_agent = duration.as_micros() as f64 / test_size as f64;
let efficiency = result.successful_count as f64 / test_size as f64 * 100.0;
println!("{:10} | {:9.2?} | {:7.1}μs | {:6.1}%",
chunk_size, duration, per_agent, efficiency);
}
println!("\nRecommendation: Use chunk_size = {} (CPUs * 10-20)",
cpu_count * 10);
Ok(())
}
fn demonstrate_calculator_reuse(agents: &[reputation_types::AgentData]) -> Result<(), Box<dyn std::error::Error>> {
let test_size = 1000;
let test_agents = &agents[..test_size.min(agents.len())];
let start = Instant::now();
for agent in test_agents {
let calc = Calculator::default(); let _ = calc.calculate(agent)?;
}
let new_calc_duration = start.elapsed();
let calc = Calculator::default();
let start = Instant::now();
for agent in test_agents {
let _ = calc.calculate(agent)?;
}
let reuse_duration = start.elapsed();
println!("Calculator instantiation overhead:");
println!(" New calculator each time: {:?}", new_calc_duration);
println!(" Reused calculator: {:?}", reuse_duration);
println!(" Overhead: {:?}", new_calc_duration - reuse_duration);
println!(" Overhead per agent: {:.1}μs",
(new_calc_duration - reuse_duration).as_micros() as f64 / test_size as f64);
Ok(())
}
fn demonstrate_memory_efficiency() -> Result<(), Box<dyn std::error::Error>> {
println!("Memory characteristics:");
println!(" Calculator size: {} bytes", std::mem::size_of::<Calculator>());
println!(" AgentData size: {} bytes", std::mem::size_of::<reputation_types::AgentData>());
println!(" ReputationScore size: {} bytes", std::mem::size_of::<reputation_types::ReputationScore>());
let calc = Calculator::default();
let agent = AgentDataBuilder::new("did:test:memory")
.with_reviews(100, 4.0)
.total_interactions(150)
.build()?;
let _score = calc.calculate(&agent)?;
println!("\nMemory efficiency features:");
println!(" ✓ Zero heap allocations during calculation");
println!(" ✓ Stack-based computation");
println!(" ✓ Efficient for embedded systems");
println!(" ✓ Cache-friendly data layout");
Ok(())
}
fn print_performance_tips() {
println!("Key Performance Tips:");
println!();
println!("1. **Use Batch Processing**");
println!(" - Up to 10x faster for multiple agents");
println!(" - Automatically uses all CPU cores");
println!();
println!("2. **Optimal Chunk Size**");
println!(" - Set chunk_size to CPU_COUNT * 10-20");
println!(" - Balances parallelism and overhead");
println!();
println!("3. **Reuse Calculator Instances**");
println!(" - Create once, use many times");
println!(" - Thread-safe with Arc for sharing");
println!();
println!("4. **Progress Callbacks**");
println!(" - Use sparingly - adds overhead");
println!(" - Update UI every N agents, not every agent");
println!();
println!("5. **Data Preparation**");
println!(" - Validate data before batch processing");
println!(" - Use fail_fast: true if data quality is uncertain");
println!();
println!("Example optimal configuration:");
println!("```rust");
println!("let options = BatchOptions {{");
println!(" chunk_size: Some(num_cpus::get() * 10),");
println!(" fail_fast: false,");
println!(" progress_callback: Some(Box::new(|completed, total| {{");
println!(" if completed % 100 == 0 {{ // Update every 100");
println!(" update_progress_bar(completed, total);");
println!(" }}");
println!(" }})),");
println!("}};");
println!("```");
}