- Phase 1: Component parser + codegen (emit_component_decl, emit_component_use, emit_match) - Phase 2: 6 registry components (button, input, card, badge, dialog, toast) - Phase 3: dreamstack add CLI with dependency resolution and --list/--all - Phase 4: dreamstack convert TSX→DS transpiler with --shadcn GitHub fetch - Phase 5: 120+ lines variant CSS (buttons, badges, cards, dialog, toast, input) - New example: showcase.ds demonstrating all component styles
181 lines
5 KiB
Rust
181 lines
5 KiB
Rust
/// 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);
|