/// DreamStack Compiler & Layout Benchmarks /// /// Measures: /// - Compiler pipeline throughput (parse → analyze → emit) /// - Signal graph construction at various scales /// - Cassowary constraint solver with varying constraint counts use criterion::{black_box, criterion_group, criterion_main, Criterion, BenchmarkId}; // ── Compiler pipeline benchmarks ──────────────────────────── fn counter_source() -> &'static str { r#" let count = 0 on click { count = count + 1 } view main = column [ text { "Count: " + count } button("Increment") { on: click } ] "# } fn todo_source() -> &'static str { r#" let todos = [] let input = "" let filter = "all" on addTodo { todos = todos + [{ text: input, done: false }] input = "" } on toggleTodo { todos = todos } view main = column [ row [ text { input } button("Add") { on: addTodo } ] column [ for todo in todos { row [ text { todo.text } ] } ] row [ button("All") { on: toggleTodo } button("Active") { on: toggleTodo } button("Done") { on: toggleTodo } ] ] "# } /// Generate a stress-test source with N signals and derived values. fn signal_chain_source(n: usize) -> String { let mut src = String::new(); src.push_str("let s0 = 0\n"); for i in 1..n { src.push_str(&format!("let s{i} = s{} + 1\n", i - 1)); } src.push_str(&format!( "view main = column [\n text {{ \"Last: \" + s{} }}\n]\n", n - 1 )); src } /// Generate a fan-out source: 1 root signal, N derived dependents. fn fan_out_source(n: usize) -> String { let mut src = String::from("let root = 0\n"); for i in 0..n { src.push_str(&format!("let d{i} = root + {i}\n")); } // View shows last derived src.push_str(&format!( "view main = column [\n text {{ \"d0: \" + d0 }}\n]\n", )); src } fn compile_source(source: &str) -> String { let program = ds_parser::parse(source).expect("parse failed"); let (graph, views) = ds_analyzer::analyze(&program); ds_codegen::JsEmitter::emit_html(&program, &graph, &views) } fn bench_compiler_pipeline(c: &mut Criterion) { let mut group = c.benchmark_group("compiler_pipeline"); group.bench_function("counter", |b| { let src = counter_source(); b.iter(|| compile_source(black_box(src))); }); group.bench_function("todo", |b| { let src = todo_source(); b.iter(|| compile_source(black_box(src))); }); group.finish(); } fn bench_signal_chain(c: &mut Criterion) { let mut group = c.benchmark_group("signal_chain"); for &n in &[10, 50, 100, 500, 1000] { let src = signal_chain_source(n); group.bench_with_input(BenchmarkId::from_parameter(n), &src, |b, src| { b.iter(|| compile_source(black_box(src))); }); } group.finish(); } fn bench_fan_out(c: &mut Criterion) { let mut group = c.benchmark_group("fan_out"); for &n in &[10, 50, 100, 500, 1000] { let src = fan_out_source(n); group.bench_with_input(BenchmarkId::from_parameter(n), &src, |b, src| { b.iter(|| compile_source(black_box(src))); }); } group.finish(); } // ── Constraint solver benchmarks ──────────────────────────── fn bench_constraint_solver(c: &mut Criterion) { use ds_layout::{LayoutSolver, Variable, Constraint, Strength}; let mut group = c.benchmark_group("constraint_solver"); for &n in &[10, 50, 100, 500] { group.bench_with_input(BenchmarkId::new("panel_chain", n), &n, |b, &n| { b.iter(|| { let mut solver = LayoutSolver::new(); // Create a chain of N panels: each starts where the previous ends let mut vars = Vec::new(); for _ in 0..n { let x = Variable::new(); let w = Variable::new(); vars.push((x, w)); } // First panel at x=0, width=100 solver.add_constraint(Constraint::eq_const(vars[0].0, 0.0, Strength::Required)); solver.add_constraint(Constraint::eq_const(vars[0].1, 100.0, Strength::Required)); // Each subsequent panel: x_i = x_{i-1} + w_{i-1} for i in 1..n { solver.add_constraint(Constraint::sum_eq( vars[i - 1].0, vars[i - 1].1, 0.0, Strength::Required, )); solver.add_constraint(Constraint::eq_const(vars[i].1, 100.0, Strength::Required)); } solver.solve(); black_box(solver.get_value(vars[n - 1].0)); }); }); } group.finish(); } criterion_group!( benches, bench_compiler_pipeline, bench_signal_chain, bench_fan_out, bench_constraint_solver, ); criterion_main!(benches);