Files
calctext/calcpad-engine/benches/eval_benchmark.rs
C. Cassel 806e2f1ec6 feat: add platform shells, CLI, formatting, plugins, tests, and benchmarks
Phase 4 — Platform shells:
- calcpad-macos/: SwiftUI two-column editor with Rust FFI bridge (16 files)
- calcpad-windows/: iced GUI with Windows 11 Fluent theme (7 files, 13 tests)
- calcpad-web/: React 18 + CodeMirror 6 + WASM Worker + PWA (20 files)
- calcpad-cli/: clap-based CLI with expression eval, pipe/stdin, JSON/CSV
  output, and interactive REPL with rustyline history

Phase 5 — Engine modules:
- formatting/: answer formatting (decimal/scientific/SI notation, thousands
  separators, currency), line type classification, clipboard values (93 tests)
- plugins/: CalcPadPlugin trait, PluginRegistry, Rhai scripting stub (43 tests)
- benches/: criterion benchmarks (single-line, 100/500-line sheets, DAG, incremental)
- tests/sheet_scenarios.rs: 20 real-world integration tests
- tests/proptest_fuzz.rs: 12 property-based fuzz tests

771 tests passing across workspace, 0 failures.
2026-03-17 09:46:40 -04:00

156 lines
4.5 KiB
Rust

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<String> = (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<String> = 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<String> = (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<String> = (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);