speckl/bench-rust.mjs
Scott Scoble 8b520284cb TS generator: fix #12 (5 expression patterns) + #11 (opaque record types)
#12: All 5 untranslated SpeckDL patterns now emit valid JS:
  - notIn → !.has(), old() → drop, union → Set spread,
    set diff → filter, append() → [...X, Y], length() → .length
  - ==/!= operator replacement fixed (word-boundary regression)
  - Postcondition object comparisons get @ts-expect-error TS2839

#11: Generator auto-detects opaque identifier types used in state
  variables and action params, emits 'type X = any' before class.
  - State properties use ! (non-null assertion) for strict mode

TigerBeetleLedger → tsc --noEmit = 0 errors. 37/37 tests pass.
2026-05-11 10:16:15 -07:00

120 lines
3.4 KiB
JavaScript

import fs from 'fs';
import { execSync } from 'child_process';
const specs = [
{ name: 'KafkaKRaft', construct: 'KafkaKRaftMachine::new()', ops: [
'm.request_vote(2, 1, 0)',
'm.append_entries(2)',
'm.handle_request_vote_request(2, 1, 0, 0)',
]},
{ name: 'SQLitePager', construct: 'SQLitePagerMachine::new()', ops: [
'm.begin_read_transaction()',
'm.begin_write_transaction()',
'm.write_page(1, 100)',
'm.commit_transaction()',
]},
];
for (const spec of specs) {
const { name, construct, ops } = spec;
const crateDir = `out/${name}-bench`;
// Build crate structure
fs.mkdirSync(`${crateDir}/src`, { recursive: true });
fs.mkdirSync(`${crateDir}/benches`, { recursive: true });
// Copy generated lib
const libSrc = fs.readFileSync(`out/${name}/src/lib.rs`, 'utf-8');
// Add type defs
const typeDefs = `// Auto-generated type definitions
pub type NodeId = u64;
pub type LogEntry = String;
pub type Account = String;
pub type Transfer = String;
pub type TransferId = u64;
pub type PageId = u64;
pub type PageData = u64;
pub type Frame = u64;
pub type FrameId = u64;
pub type Bytes = Vec<u8>;
`;
fs.writeFileSync(`${crateDir}/src/lib.rs`, typeDefs + libSrc);
// Cargo.toml
fs.writeFileSync(`${crateDir}/Cargo.toml`, `[package]
name = "${name.toLowerCase()}-bench"
version = "0.1.0"
edition = "2021"
[[bench]]
name = "bench"
harness = false
[profile.bench]
debug = 0
lto = "fat"
codegen-units = 1
`);
// Benchmark code
const opBody = ops.map((op, i) => ` let _ = ${op};`).join('\n');
const totalOps = ops.length;
fs.writeFileSync(`${crateDir}/benches/bench.rs`, `use std::time::Instant;
#[path = "../src/lib.rs"]
mod generated;
use generated::*;
fn main() {
let iterations = 100_000;
println!("\\n=== ${name} Benchmark ===");
println!("Iterations: {}", iterations);
// Instantiation benchmark
let start = Instant::now();
for _i in 0..iterations {
let _m = ${construct};
}
let elapsed = start.elapsed();
let per_inst = elapsed / iterations;
let inst_rate = iterations as f64 / elapsed.as_secs_f64();
println!(" Instantiate:");
println!(" Total: {:?}", elapsed);
println!(" Per op: {:?}", per_inst);
if inst_rate > 1_000_000.0 {
println!(" Rate: {:.1} M/sec", inst_rate / 1_000_000.0);
} else if inst_rate > 1_000.0 {
println!(" Rate: {:.1} K/sec", inst_rate / 1_000.0);
} else {
println!(" Rate: {:.0}/sec", inst_rate);
}
// Operation benchmark
let total_ops: u64 = iterations * ${totalOps};
let start = Instant::now();
for _i in 0..iterations {
let mut m = ${construct};
${opBody}
}
let elapsed = start.elapsed();
let per_op = elapsed / total_ops;
let rate = total_ops as f64 / elapsed.as_secs_f64();
println!(" Operations ({} ops per cycle):", ${totalOps});
println!(" Total: {:?}", elapsed);
println!(" Per op: {:?}", per_op);
if rate > 1_000_000.0 {
println!(" Rate: {:.1} M ops/sec", rate / 1_000_000.0);
} else if rate > 1_000.0 {
println!(" Rate: {:.1} K ops/sec", rate / 1_000.0);
} else {
println!(" Rate: {:.0} ops/sec", rate);
}
}
`);
}
console.log('Bench crates created. Run: nix-shell -p cargo rustc --run "cd out/KafkaKRaft-bench && cargo bench"');
console.log('And: nix-shell -p cargo rustc --run "cd out/SQLitePager-bench && cargo bench"');