use criterion::{black_box, criterion_group, criterion_main, Criterion}; use calcpad_engine::context::EvalContext; use calcpad_engine::pipeline::{eval_line, eval_sheet}; use calcpad_engine::SheetContext; // --- Single-line benchmarks --- fn bench_single_line_arithmetic(c: &mut Criterion) { c.bench_function("single_line_arithmetic", |b| { b.iter(|| { let mut ctx = EvalContext::new(); eval_line(black_box("(3 + 4) * 2 ^ 3 - 1"), &mut ctx) }) }); } fn bench_single_line_unit_conversion(c: &mut Criterion) { c.bench_function("single_line_unit_conversion", |b| { b.iter(|| { let mut ctx = EvalContext::new(); eval_line(black_box("5kg in lb"), &mut ctx) }) }); } // --- Sheet benchmarks (pipeline API) --- fn bench_100_line_sheet(c: &mut Criterion) { let lines: Vec = (0..100) .map(|i| { if i == 0 { "x = 1".to_string() } else { format!("x = x + {}", i) } }) .collect(); let line_refs: Vec<&str> = lines.iter().map(|s| s.as_str()).collect(); c.bench_function("100_line_sheet_pipeline", |b| { b.iter(|| { let mut ctx = EvalContext::new(); eval_sheet(black_box(&line_refs), &mut ctx) }) }); } fn bench_variable_heavy_sheet(c: &mut Criterion) { let mut lines: Vec = Vec::with_capacity(50); for i in 0..10 { lines.push(format!("v{} = {}", i, i * 10 + 1)); } for i in 10..50 { let a = i % 10; let b = (i + 3) % 10; lines.push(format!("r{} = v{} + v{}", i, a, b)); } let line_refs: Vec<&str> = lines.iter().map(|s| s.as_str()).collect(); c.bench_function("variable_heavy_sheet_dag", |b| { b.iter(|| { let mut ctx = EvalContext::new(); eval_sheet(black_box(&line_refs), &mut ctx) }) }); } // --- SheetContext benchmarks (with dependency tracking) --- fn bench_sheet_context_500_lines(c: &mut Criterion) { let lines: Vec = (0..500) .map(|i| match i % 5 { 0 => format!("x{} = {}", i, i), 1 => format!("{} + {} * {}", i, i + 1, i + 2), 2 => format!("{}kg in g", (i as f64) * 0.1), 3 => format!("// Comment line {}", i), 4 => format!("sqrt({})", (i * i) as f64), _ => unreachable!(), }) .collect(); c.bench_function("sheet_context_500_lines_full_eval", |b| { b.iter(|| { let mut sheet = SheetContext::new(); for (i, line) in lines.iter().enumerate() { sheet.set_line(i, line); } sheet.eval() }) }); } fn bench_sheet_context_incremental_edit(c: &mut Criterion) { let lines: Vec = (0..500) .map(|i| match i % 3 { 0 => format!("x{} = {}", i, i), 1 => format!("{} + {}", i, i + 1), 2 => format!("sqrt({})", (i * i) as f64), _ => unreachable!(), }) .collect(); let mut sheet = SheetContext::new(); for (i, line) in lines.iter().enumerate() { sheet.set_line(i, line); } sheet.eval(); c.bench_function("sheet_context_incremental_single_edit", |b| { let mut s = sheet.clone(); let mut counter = 0; b.iter(|| { counter += 1; // Edit a line that doesn't affect others (no variable) s.set_line(250, &format!("{} + {}", counter, counter + 1)); s.eval() }) }); } fn bench_sheet_context_incremental_variable_change(c: &mut Criterion) { let mut sheet = SheetContext::new(); sheet.set_line(0, "base = 100"); for i in 1..500 { if i % 10 == 0 { sheet.set_line(i, "base + 1"); } else { sheet.set_line(i, &format!("{} + {}", i, i + 1)); } } sheet.eval(); c.bench_function("sheet_context_incremental_variable_change", |b| { let mut s = sheet.clone(); let mut counter = 100; b.iter(|| { counter += 1; s.set_line(0, &format!("base = {}", counter)); s.eval() }) }); } criterion_group!( benches, bench_single_line_arithmetic, bench_single_line_unit_conversion, bench_100_line_sheet, bench_variable_heavy_sheet, bench_sheet_context_500_lines, bench_sheet_context_incremental_edit, bench_sheet_context_incremental_variable_change, ); criterion_main!(benches);