lumbda/examples/cuda-fanout/CATALOG.md
russell@unturf.com e57c4948ab
cuda-fanout: drop legacy demo_ops references — bend-cuda only
Earlier rename kept DEMO_OPS env fallback + *binary-demo-ops* var name
as transitional back-compat. With both hosts redeployed on bend-cuda
that's no longer needed.

Renamed:
  *binary-demo-ops*  ->  *binary-bend-cuda*
  DEMO_OPS env       ->  removed (only BEND_CUDA recognized now)

Also bulk-updated cuda-fanout sibling docs (DESIGN, CATALOG, plans/)
that still spelled the old name.

Slot reserved for future bend-rocm / bend-cpu via parallel env vars.
2026-06-09 15:17:04 -04:00

24 KiB
Raw Blame History

bend-form catalog

Registry of CUDA workloads we have packaged (or plan to package) as bend forms. Each form ships as a binary the worker spawns over our wire protocol & serves to any lumbda tier (Python / C / asm).

A form earns a slot here only after we have measured it: known input shape, known speedup vs CPU, known fleet host where it runs. "I think this would be fast" does not earn a slot — the form-status column says planned until numbers exist.

Status legend

  • live — binary built, worker dispatches it, numbers recorded
  • experimental — binary built but not yet worker-dispatched
  • planned — design doc only, no binary yet

Live forms

form binary hardware speedup vs CPU wire shape
cuda-shake-fanout shake256-fanout 3090 12x over host hashlib at 1M x 16 B inputs (cuda-shake-fanout (quote (hex …)) out-bytes) + BSHK binary
cuda-sim-ops-bin ecdsa/cuda/bend-cuda 3090 1.27x at 141 batches (9024 shots); crossover ~115 batches; SHAKE-RNG mode matches upstream Pareto: Σ Toffoli = 15,999,651,264 & avg Toffoli = 1,773,011.000 bit-identical to eval_circuit on same ops.bin (cuda-sim-ops-bin "path/to/ops.bin" n-batches)bend-cuda defaults --rng-mode shake (Fiat-Shamir over op stream, matches upstream); --rng-mode lfsr keeps legacy xorshift for debug parity
cuda-bignum-cgbn cgbn-batch-worker 3090 1.28 Gops/s kernel mod-mul at n=1M (256-bit, ~256x GMP CPU); 9 ops total BCGB binary: op_id + bitwidth + n + modulus + a + b
cuda-secp256k1-batched-mul secp256k1-batch-mul 3090 v1 7.86 Mkeys/s @ n=1M; v3 (windowed-G w=4) 13.83 Mkeys/s @ n=1M (1.76x v1; ~309x coincurve); Day-4 v4 (v3 ladder + Montgomery batch inv) regressed -12% vs v3 due to v2 serial-per-block walks; warp-scan Phase B/D refactor needed before v4 wins; daemon default flipped to --window-w 4 BSCP binary: scalars + base-point
cuda-sim-axis-flip ecdsa/cuda/demo_axis 3090 217 Mops/s @ K=32 M=4 (per-candidate parallel); 23.7x over per-shot N=4 at same M; LOSES to per-shot by 14% at full N=128 saturation (cuda-sim-axis (variant-paths …) n-shots)
cuda-radix-sort radix-sort 3090 5.50 Gkeys/s @ n=10M (kernel 1.82 ms); 3.77 Gkeys/s @ n=1M; CUB DeviceRadixSort u64 ascending; ~4x over published Titan baseline (1.4 Gkeys/s); byte-identity vs Python sorted() at n∈{32, 1k, 100k, 1M, 10M} BSRT binary: op_id + n + u64[n] → BSRR sorted u64[n]
cuda-blake3-tree blake3-fanout 3090 32.5 GB/s @ 1M × 64 B (kernel 1.97 ms); 20.4 GB/s @ 1k × 1 MB (kernel 51.5 ms); 2.68 GB/s @ 100k × 64 B; byte-identical vs BLAKE3 reference spec across single-chunk + multi-chunk paths at n∈{32, 1k, 10k, 100k, 1M}; one CUDA thread per input walks Merkle chunk tree on-device BSB3 binary: out_bytes + n + (u32 len + bytes) per input → BSR3 n + out_bytes + digests

cuda-sim-ops-bin numbers are humbling on purpose: kickmix is conditional-op heavy & branch-divergent. This catalog exists so we DO NOT pretend 1.27x is the ceiling — we find forms with real SIMT-friendly shape & route work through them. As of 2026-06-06 our SHAKE-RNG mode anchors bend-cuda measurements directly against upstream's public Pareto scoreboard — Σ Toffoli & avg Toffoli are byte-identical to eval_circuit on the same ops.bin, no calibration constant required.

Why a form earns its slot

A form is GPU-worth-it when AT LEAST ONE of:

  1. Embarrassingly parallel. N independent items, no cross-item dependency. SHAKE fan-out, batched mod-mul, bulk point-add — each thread owns one item.
  2. Dense, branch-free inner loop. Same operation on every element. Matrix-vector, convolution, bit-twiddling sweeps.
  3. Reduction-friendly. Tree-reduce / prefix-sum / parallel-scan patterns that GPU hardware accelerates natively.
  4. Big batch amortizes fixed kernel overhead. Our cuda-sim-ops-bin shows ~5 s kernel overhead; only worth it past ~115 batches.

When none of these hold for a problem, do not force it onto GPU. Find a different decomposition: parallelize on a different axis (per-candidate instead of per-shot), or stay on CPU & fan out across fleet hosts.

Planned forms — surveyed 2026-06-05

Build order at bottom. All entries cite published precedent.

A. cuda-secp256k1-batched-mul — batched secp256k1 scalar / point ops

  • Refs: gECC https://arxiv.org/pdf/2501.03245 ; VanitySearch https://github.com/JeanLucPons/VanitySearch ; FixedPaul/VanitySearch-Bitcrack https://github.com/FixedPaul/VanitySearch-Bitcrack
  • Speedup: gECC reports 4.94× on unknown-point mul, 5.56× on ECDSA verify vs CPU. VanitySearch forks hit 6.5 Gkeys/s on RTX 4090, 8.6 Gkeys/s on RTX 5090, 2.65 Gkeys/s on RTX 3080. Endomorphism + Montgomery batch-inversion (one mod-inv per N points instead of N) carries our kernel.
  • Wire shape: (secp-mul-batch (scalars . blob<N*32B>) (base-point . blob<64B>))(points . blob<N*64B>)
  • Relevance: HIGH — our search loop's hot path. A 6.5 G/s point-mul oracle on a 4090 dwarfs any lumbda CPU tier; gives our candidate-validator a GPU-rate primitive.

B. cuda-bignum-cgbn — 256-bit modular arithmetic primitives

  • Refs: NVlabs CGBN https://github.com/NVlabs/CGBN ; midsize-int benchmarks https://arxiv.org/pdf/2405.14642
  • Speedup: 32-bit to 32K-bit ints, 4/8/16/32 threads per bignum instance. Midsize-int study hits 100×+ on dense mul vs Xeon-20c + GMP + OpenMP.
  • Wire shape: generic op-code stream — (cgbn-batch (op . mod-mul|mod-inv|mod-add) (modulus . blob<32B>) (a . blob<N*32B>) (b . blob<N*32B>))blob<N*32B>
  • Relevance: HIGH — every secp256k1 op bottoms out in a 256-bit Fp/Fq operation. CGBN gives lumbda a generic bignum batch primitive that any curve form rides on.

C. cuda-rho-pollard-walk — Pollard rho / kangaroo walks

  • Refs: atlomak/CUDA-rho-pollard https://github.com/atlomak/CUDA-rho-pollard ; oritwoen/kangaroo https://github.com/oritwoen/kangaroo
  • Speedup: 87.7 M ops/sec on RTX 2070 Super for ECCp79 (Certicom challenge solved in ~3 hours). Original CUDA Pollard paper reports > 7.2 M points/sec at 256 threads on older HW.
  • Wire shape: (rho-walk-batch (start-points . blob<W*64B>) (steps . N) (distinguished-mask . blob<32B>))(distinguished . blob<K*96B>) (point + walk-length pairs)
  • Relevance: HIGH — full secp256k1 Pollard rho stays infeasible (2^128 work), but our walk kernel maps onto any "many independent random walks feeding a central collision table" search shape, which our kickmix candidate sweep also wants.

D. cuda-clifford-stabilizer — tableau stabilizer simulator (Stim-on-GPU)

  • Refs: STABSim https://arxiv.org/abs/2507.03092 ; Qimax https://arxiv.org/abs/2505.03307 ; equivalence-checking https://arxiv.org/pdf/2603.14641
  • Speedup: 186× over Stim (CPU SOTA) on equivalence-checking. STABSim a first GPU stabilizer sim that scales better than CPU on QEC workloads. Stim's own GPU experiment got very little; dedicated tableau-on-GPU broke through.
  • Wire shape: (stab-sim-batch (n-qubits . k) (circuit . blob) (n-shots . S))(samples . blob<S*ceil(k/8)>)
  • Relevance: MEDIUM-HIGH — restructures our problem along a different axis: per-candidate parallelism, not per-shot. Each GPU lane runs one full candidate circuit; divergence bounds by candidate variance, not by per-shot control flow. If our point-add circuit fits a Clifford fragment (Toffoli-decomposed), this form flips our 1.07× into double digits.

E. cuda-bernstein-yang-inv — batched modular inverse (safegcd)

  • Refs: BernsteinYang safegcd https://eprint.iacr.org/2019/266 ; "Jumping for Bernstein-Yang" https://eprint.iacr.org/2024/644
  • Speedup: Per-inversion ~3-10× over Fermat on CPU. No published dedicated CUDA implementation found — gECC uses Montgomery batched-inversion trick instead. Standalone BY-on-CUDA carries novel territory.
  • Wire shape: (modinv-batch (modulus . blob<32B>) (xs . blob<N*32B>))blob<N*32B>
  • Relevance: HIGH — modular inverse painful step in every affine point op. Even bundling Montgomery's batched trick (one inv + 3(N-1) muls) makes this our cost-floor primitive every other ECC form leans on. Low risk, high reuse.

F. cuda-ntt-poly — Number Theoretic Transform

  • Refs: NTTSuite https://arxiv.org/pdf/2405.11353 ; FHE NTT https://eprint.iacr.org/2021/124.pdf
  • Speedup: Up to 123× over CPU; 21× on RTX 3070; cuFFT-comparable kernel structure.
  • Relevance: MEDIUM — only useful once we lift our scalar arithmetic into polynomial representation (Karatsuba / Kronecker substitution for very wide muls, or FHE-style obfuscation). Park it.

G. cuda-radix-sort / cuda-prefix-scan — reduction primitives

Skipped (revisit when shape changes)

  • cuda-batched-mcts — 25-40× on Go-style rollouts. Not our search shape unless we wrap candidate construction as gate-by-gate tree search.
  • cuda-faiss-ann — 5-12× over CPU FAISS. No candidate-embedding workload today.

Wave 2 — broader surveyed forms (2026-06-05)

20 additional forms sorted by reported speedup descending. Citations in our public catalog at https://lumbda.com/bend.html. Speedup numbers from published benchmarks on the cited hardware — none have run on our fleet yet.

form speedup hardware relevance
cuda-minhash-weighted 600-1000x vs numpy+MKL Titan X vs 12-core Xeon HIGH (undefect corpus dedup)
cuda-cuckoo-filter 378x insert, 258x delete vs GQF A100 HIGH (ECDSA candidate prune)
cuda-aes-ctr-chacha20 211-400 GB/s (ChaCha8) single GPU HIGH (portal AEAD)
cuda-suffix-array-skew 30-242x vs CPU SA-IS Tesla K20 MEDIUM (source-corpus search)
cuda-kdtree-build 30-242x build, 1.6-200x kNN RTX (RT cores) MEDIUM (fleet locality index)
cuda-sat-paraFROST-elim 93x peak, 48x avg variable elim CADICAL/Kissat baseline HIGH (CNF equivalence checking)
cuda-aho-corasick-pfac ~50-100x (IDS pkt-inspect) GTX-class HIGH (OSS string scan)
cuda-dilithium-pqsig 57.7x keygen+sign+verify RTX 3090 Ti HIGH (PQ TLS migration)
cuda-mc-options-pricing 25-152x (barrier-call kernel) Tesla C1060 / modern LOW (calibration form)
cuda-cuFFT-batched-1D 8-32x vs MKL; tcFFT 1.1-3.2x over cuFFT V100 / A100 MEDIUM (punters-cc spectrograms)
cuda-blake3-tree LIVE — 32.5 GB/s @ 1M × 64 B; 20.4 GB/s @ 1k × 1 MB on 3090; see Live forms table RTX 3090 HIGH (content-addressed portals)
cuda-bloom-filter-modern ~6x CPU; 3.4B inserts/s B200 / Perlmutter HIGH (foxhop pruning, undefect known-set)
cuda-gemm-batched-FP8 4.8x FP8 over A100; 716 TFLOPS H100 H100 SXM LOW (calibration / lattice PQC)
cuda-batched-matrix-inverse 4.3-16.8x vs MAGMA P100 LOW (LA verifiers on circuits)
cuda-hash-join-radix 4B tuples/s single; 1.8T on 1024xA100 A100 cluster MEDIUM (undefect joins)
cuda-kmer-count 4-6x vs KMC2 RapidGKC, Gerbil LOW (bioinformatics adjacency)
cuda-cgraph-traversal 38B TEPS; PR half-billion nodes DGX2 MEDIUM (undefect DAG analytics)
cuda-triangle-count-TRUST ~1T TEPS (first trillion-TEPS) multi-A100 MEDIUM (twitter-x-punters community structure)
cuda-ldpc-bp-decoder 10 Gbps with early-termination GPGPU LOW (PQ-KEM noise modelling)
cuda-nvcomp-zstd 2.2x decompress; 1.4x LZ4; 1.9x snappy H100 / A100 HIGH (corpus shards, portal envelopes)

Skipped (revisit when shape changes)

  • Argon2 / scrypt — ~1000 H/s on K20X is the whole point of memory-hard KDFs; not a speedup story
  • cuRAND alone — bundled inside Monte Carlo + ChaCha20; not a standalone wire form
  • GP regression / variational inference — current GPU wins 2-4x, below threshold
  • Generic ML inference — out of scope, covered by upstream frameworks
  • cuda-batched-mcts — 25-40x on Go-style rollouts; wrong shape for our search
  • cuda-faiss-ann — 5-12x; no embedding workload today

Wave 3 — surveyed 2026-06-05

15 additional forms covering ZK/SNARK provers, pairing crypto, tensor network contraction, sparse LA, CV primitives, numerical solvers, generic BP, MD/CFD, convex opt, DSP beyond cuFFT, DB aggregations, graph theory beyond triangle/PageRank.

form speedup / throughput hardware relevance
cuda-fluidx3d-lbm 100-200x vs ANSYS Fluent; 8799 MLUPS A100 A100 unsandbox MEDIUM (HPC reproducibility)
cuda-mfcc-spectral ~97x CPU MFCC; STFT ~75x via cuSignal GTX 580+ unsandbox HIGH (punters-cc, BT-DISC forensics)
cuda-batched-lp-simplex 95x over CPLEX; 5x over GLPK on 100K LPs GTX 980-class unsandbox HIGH (resource scheduling, Prime Mission)
cuda-betweenness-centrality-weighted 30-150x warp-centric weighted BC GTX+ undefect HIGH (workaholic-node detection, MOAD-0001)
cuda-cudasift-orb-ransac ~60x SIFT; 1.2ms on GTX 1060; ORB 11.3x GTX 1060+ unsandbox MEDIUM (visual evidence)
cuda-cudasw-gasal2 CUDASW++4.0 16.2x; 5.71 TCUPS H100; GASAL2 750x H100 undefect MEDIUM (binary-diff patch-similarity)
cuda-loopy-bp-mrf 45x over CPU LBP for stereo MRF GTX 280+ undefect HIGH (FuzzingBrain probabilistic analysis)
cuda-sgm-stereo 42 fps @ 640x480, 128 disparities Tegra X1 Tegra X1+ unsandbox MEDIUM (edge node profile)
cuda-hungarian-lap 400M-var LAP in ~13s; 10-50x class NVIDIA unsandbox HIGH (workstation-to-queue balancing); undefect MEDIUM
cuda-msm-bls12-381 27.86x over Pippenger RELIC AVX; 60% of Groth16 A100 / 4090 ECDSA HIGH (Pippenger shares branchless modmul shape)
cuda-pdwt-lifting 15.9x over best CPU DWT GTX / Tesla unsandbox MEDIUM (audio-IPC analysis)
cuda-tensornet-contract 8-20x vs CuPy; tensor QR ~100x vs Xeon 8480+ A100 ECDSA HIGH (alt to stabilizer/kickmix)
cuda-ega-gpu-aggregation 6.45-29.12x multi-pass; group-by hash 19.4x NVIDIA undefect HIGH (corpus aggregation); unsandbox HIGH (telemetry)
cuda-bicgstab-ilu-spmv SpTRSV 10.7x; ILU0 BiCGSTAB 3.2x; GMRES 6.9x V100 / MI210 ECDSA MEDIUM (sparse LA over GF(p)); undefect MEDIUM
cuda-icicle-snark-groth16 Fastest Groth16 today; Mina 3x libsnark RTX 4090 / A100 ECDSA MEDIUM; undefect MEDIUM (zk-prover defect scanning)

Wave 3 filtered out (below threshold)

  • AMGX algebraic multigrid: 2-5x — below 10x cutoff
  • GROMACS GPU: 2-3x speedup vs CPU — below threshold
  • NVIDIA Optical Flow SDK: 7-10x borderline, dedicated hardware unit
  • Junction-tree BP per-message: 0.68-9.18x — below threshold
  • Batched L-BFGS: 134x reported but single mesh-size case, not generalized

Form D structural finding — 2026-06-05

cuda-clifford-stabilizer does NOT apply to our point-add circuit. Build agent measured Toffoli fraction 13.87% (well under 40% threshold), THEN noticed the circuit contains no H or S gates — only X/CX/CCX/CZ/CCZ/SWAP/R/HMR/Z/NEG. State never leaves the computational basis. Stabilizer tableau compression buys nothing when there's no superposition; AG reduces to exactly what sim_gpu.cu already does, at one bit per qubit per shot.

The 1.07x cuda-sim-ops-bin ceiling traces to memory-bandwidth on per-shot striped state, not algorithm. Both pivots landed 2026-06-05; bandwidth-bound diagnosis confirmed FALSE on the kickmix circuit. Empirical results below; see RESULTS docs for detail.

  • axis-flip refactor of sim_gpu.cu — DONE (Form D option 1, commit foxhop 1f7ac9d). 217 Mops/s @ K=32 M=4; 23.7x over per-shot N=4 at same M. Both kernels saturate at ~220-250 Mops/s. Axis flip's win is occupancy-amortization at small M, not bandwidth redistribution. Right tool for many-candidates × few-shots search-loop early-screen pattern.

  • ops.bin packing (QECCOPS2) — DONE (Form D option 3, commit foxhop 90484ca). 1.07x kernel speedup, 2.33x on-disk shrink (716 MB → 307 MB). The 3.5x projection was WRONG because ops_loader.c already narrowed u64 → u32 on load, so in-VRAM Op was already 28 B not 56 B; max realistic VRAM reduction 28→24 B = 1.17x best case. Per-shot state traffic (qubits + bits per thread) is ~85x larger than the op stream and dominates kernel bandwidth. Storage win still useful for fleet rsync; compute win small.

Both pivots converged on the same diagnosis: the 3090 is compute-saturated at ~250 Mops/s on the kickmix circuit, not bandwidth-saturated. Real next macro-lever: multi-GPU fan-out (3090-ai + ai.foxhop.net 4090, each hitting its own ceiling in parallel — see task #30).

Form D as originally scoped (AG tableau for our circuit) is parked. STABSim-class wins remain valid for QEC / surface-code work where H + S exist; that's a future workload.

Progress doc: examples/cuda-fanout/plans/form-D-build-progress.md

Wave 4 — surveyed 2026-06-05

20 additional forms covering lattice cryptography, lattice reduction (LLL/BKZ/sieve), privacy/MPC primitives, ZK prover internals beyond MSM/NTT, sparse direct solvers, real-time DSP, computational biology beyond pairwise alignment, erasure coding, computational geometry, ODE/PDE, time series, quantum chemistry.

form speedup / throughput hardware relevance
cuda-kalman-batched 1386x for 5000-component measurements various unsandbox HIGH (RSSI tracking, punters surface)
cuda-g6k-tensor-sieve 1230x vs G6K CPU at dim 120; SVP record dim 180 4 Turing ECDSA HIGH (lattice attacks on biased nonces)
cuda-zkspeed-sumcheck-hyperplonk 801x geomean; sumcheck 8.4s → 9.5ms accelerator undefect HIGH (verifiable-defect-scan provenance)
cuda-kyber-batched-ntt ~451x batched (B=65k); HI-Kyber 6.47x prior SOTA RTX 3080 undefect HIGH (PQ migration); unsandbox HIGH (proxy TLS)
cuda-ironman-ote 237x OT throughput vs full-thread CPU near-memory unsandbox HIGH (cross-fleet PSI/MPC)
cuda-cudss-cholesky >100x vs QDLDL; 20x vs CHOLMOD factor NVIDIA undefect HIGH (defect-graph eigenproblems)
cuda-particle-filter ~150x absolute (5000 particles @ 170 Hz) GPGPU unsandbox MEDIUM
cuda-rk-stiff-chemkin 126x single-core; 25x 6-core hydrogen RKCK 524k ODEs GPGPU ECDSA MEDIUM (batched ODE maps to candidate sweep)
cuda-fem-assembly-jit 87x assembly serial CPU; 126x peak num integration GPGPU LOW
cuda-cufalcon-sign 201k sig/s Falcon-512 A100; verify 2.72M sig/s, 29.5x AVX2 A100 undefect HIGH; unsandbox HIGH (PQ disclosure signing)
cuda-cudahull-3d 30-40x over Qhull CPU NVIDIA LOW
cuda-fastplay-garbled 35-40x over serial garbling GPU cluster unsandbox MEDIUM
cuda-air-fri ~22.8x avg end-to-end ZK speedup GPGPU undefect HIGH
cuda-rabin-fingerprint 16x over single-thread CPU; 40 Gbps absolute GTX 780 unsandbox HIGH (CDN/proxy cache dedup)
cuda-gdel3d 10x over CGAL 3D Delaunay; 70x Voronoi 10M NVIDIA LOW
cuda-perasure-crs 10x vs Jerasure; 10 GB/s GTX780 absolute GTX 780 unsandbox HIGH (object-storage erasure)
cuda-piranha-mpc 4x vs CryptGPU VGG16 private inference single GPU unsandbox HIGH (MPC layer for untrusted containers)
cuda-scamp-matrix-profile quintillion pairwise comparisons / day GPGPU undefect HIGH; unsandbox HIGH (journald intrusion detection)
cuda-cudtw-subseq 2-3 orders of magnitude vs UCR-Suite CPU Volta unsandbox HIGH (audio diff for bluetooth/sbc forensics)
cuda-terachem-dft 1-2 orders of magnitude over CPU 4x Tesla LOW (catalog completeness)

Wave 4 filtered out (below threshold)

  • MAFFT MSA — 11-20x peak on old NVIDIA hardware; largely surpassed
  • RAxML likelihood — 32x kernel only, ~3-10x end-to-end
  • AmgX CG — 3-4x on solve-time when AmgX is the baseline
  • BVH Karras LBVH — 2-3x over prior GPU LBVH; fails strict 10x
  • LDPC decode — 40-160 Mbps; not >=10x over modern SIMD CPU
  • Mesh decimation — application-dependent, borderline
  • Discrete Gaussian sampler — single-digit %; fold into cuda-kyber-batched-ntt
  1. A: cuda-secp256k1-batched-mul — biggest immediate win. Drop VanitySearch's CUDA secp256k1 kernel as a BSHK worker; lumbda gets a 6.5 Gkeys/s point-mul oracle. Every candidate validation rides this form. Hardware already owned (3090 + 4090).
  2. D: cuda-clifford-stabilizer — right axis fix for our 1.07× kickmix speedup. Reshape circuit-sim per-candidate-parallel (one lane = one full candidate), target Clifford fragment via STABSim-style tableau. Directly answers our divergence diagnosis.
  3. B: cuda-bignum-cgbn — foundational layer. Even after A ships using VanitySearch's bespoke field, CGBN becomes our generic 256-bit vocabulary, lets lumbda call mod-mul / mod-add / mod-inv batches not tied to secp256k1.

Forms E, C, G follow once A-D give us measured numbers on our hardware.

Process — adding a new form

  1. Cite the science. Paper, library, or benchmark URL. No form ships without a published precedent.
  2. Prototype the binary outside the worker first. CLI tool, one input file, one output file. Measure speedup vs CPU on our hardware before wiring bend.
  3. Add a handler to gpu-worker.lsp matching the existing handle-cuda-sim-ops-bin pattern: spawn-process-stdio, drain stdout, parse portal, return (ok …).
  4. Add telemetry lines so we log per-call wall-ms, cpu-ms, gpu-ms, gpu/cpu ratio.
  5. Update this table. form name, binary, hardware, measured speedup, wire shape.
  6. Push.