import CubicalTransport.Readback import CubicalTransport.FFI /-! CubicalBench.lean — Phase D.2 performance benchmarks. Measures throughput of the Rust-backed cubical evaluator. Uses an `IO.Ref` accumulator to prevent dead-code elimination (the discarded results of pure functions can otherwise be optimized away, even through `extern` boundaries). Invoke: `./.lake/build/bin/cubical-bench` -/ -- ── Helpers ──────────────────────────────────────────────────────────────── /-- Encode a CVal into a single-byte tag for accumulator accounting. Forces the full `eval` result to be observed. -/ def cvalTag : CVal → UInt8 | .vneu _ => 2 | .vlam _ _ _ => 0 | .vplam _ _ _ => 1 | .vpair _ _ => 8 | _ => 255 def dimExprTag : DimExpr → UInt8 | .zero => 0 | .one => 1 | .var _ => 2 | .inv _ => 3 | .meet _ _ => 4 | .join _ _ => 5 def faceTag : FaceFormula → UInt8 | .bot => 0 | .top => 1 | .eq0 _ => 2 | .eq1 _ => 3 | .meet _ _ => 4 | .join _ _ => 5 def ctermTag : CTerm → UInt8 | .var _ => 0 | .lam _ _ => 1 | .app _ _ => 2 | .plam _ _ => 3 | .papp _ _ => 4 | .pair _ _ => 10 | _ => 255 def timedRun (label : String) (iters : Nat) (work : IO UInt8) : IO UInt64 := do let t0 ← IO.monoNanosNow let mut acc : UInt64 := 0 for _ in [0:iters] do let x ← work acc := acc + x.toUInt64 let t1 ← IO.monoNanosNow let totalNs := (t1 - t0) let nsPerIter := if iters > 0 then totalNs / iters else totalNs let totalMs := totalNs.toFloat / 1_000_000.0 IO.println s!" {label}: {iters} iters in {totalMs}ms ({nsPerIter} ns/iter)" return acc -- ── Workloads (each returns a UInt8 derived from the result) ────────────── def work_dimexpr_normalize : IO UInt8 := do let exprs : List DimExpr := [ .inv .zero, .inv (.inv (.var ⟨"i"⟩)), .meet (.var ⟨"i"⟩) (.inv .zero), .join (.inv (.var ⟨"j"⟩)) .zero, .inv (.meet (.var ⟨"i"⟩) (.join (.var ⟨"j"⟩) .one)) ] let mut acc : UInt8 := 0 for e in exprs do acc := acc ^^^ (dimExprTag (DimExpr.normalize e)) return acc def work_face_normalize : IO UInt8 := do let faces : List FaceFormula := [ .meet .top (.eq0 ⟨"i"⟩), .meet (.eq0 ⟨"i"⟩) .bot, .join .bot (.eq1 ⟨"j"⟩), .join (.eq0 ⟨"i"⟩) .top, .meet (.meet .top (.eq0 ⟨"i"⟩)) (.meet (.eq1 ⟨"j"⟩) .top) ] let mut acc : UInt8 := 0 for φ in faces do acc := acc ^^^ (faceTag (FaceFormula.normalize φ)) return acc def work_lambda_beta : IO UInt8 := do let v1 := eval .nil (.app (.lam "x" (.var "x")) (.var "y")) let v2 := eval .nil (.app (.app (.lam "x" (.lam "y" (.var "x"))) (.var "a")) (.var "b")) let v3 := eval .nil (.app (.app (.lam "f" (.lam "x" (.app (.var "f") (.var "x")))) (.var "g")) (.var "z")) return (cvalTag v1) ^^^ (cvalTag v2) ^^^ (cvalTag v3) def work_sigma : IO UInt8 := do let v1 := eval .nil (.fst (.pair (.var "a") (.var "b"))) let v2 := eval .nil (.snd (.pair (.var "a") (.var "b"))) let v3 := eval .nil (.fst (.snd (.pair (.var "x") (.pair (.var "y") (.var "z"))))) return (cvalTag v1) ^^^ (cvalTag v2) ^^^ (cvalTag v3) def work_readback : IO UInt8 := do let t : CTerm := .lam "f" (.lam "x" (.app (.var "f") (.var "x"))) let v := eval .nil t let back := readback v return (cvalTag v) ^^^ (ctermTag back) -- ── Driver ───────────────────────────────────────────────────────────────── def main : IO Unit := do IO.println "── Topolei cubical perf benchmarks ──" IO.println "Rust-backed evaluator (native staticlib). Accumulator prevents DCE." IO.println "" let iters := 100_000 let mut tally : UInt64 := 0 tally := tally + (← timedRun "DimExpr.normalize (5 ops/iter)" iters work_dimexpr_normalize) tally := tally + (← timedRun "FaceFormula.normalize (5 ops/iter)" iters work_face_normalize) tally := tally + (← timedRun "λ β-reductions (3 ops/iter)" iters work_lambda_beta) tally := tally + (← timedRun "Σ projections (3 ops/iter)" iters work_sigma) tally := tally + (← timedRun "readback λ-form (1 op/iter)" iters work_readback) IO.println "" IO.println s!"Accumulator (forces observation): {tally}" IO.println "" IO.println "ns/iter divides total elapsed by iterations; each iter" IO.println "does N operations listed in parens, plus accumulator work."