bend.html: fleet section — cross-GPU + cluster numbers + first sweep result

Adds a new "Fleet" section between the ecdsafail workload table &
the catalog. Documents what now runs in production:

  - 2-host LAN cluster: 3090-ai:9091 + ai.foxhop.net:9092 (4090, sm_89)
  - 4090 box shares the GPU with a qwen LLM (vllm) — our bend kernels
    fit alongside because secp256k1 / CGBN workloads burn SMs only for
    milliseconds at a time, then release
  - Cross-GPU parity at small N: 0.07-0.10 ms kernel on both 3090 &
    4090 for CGBN n=100k mod-mul; both starve between calls so the
    4090's FLOPS advantage doesn't show until kernels run long enough
    to amortize wire overhead
  - Cluster aggregate: 1.6× speedup at 200 × n=1k (cap is client-side
    serialization, not workers); async fan-out unlocks the remaining 2×
  - First measured sweep through full lumbda → emit-ops-bin → bend →
    demo_ops pipeline: refined Bernstein-Yang variant cuts Σ Toffoli
    by 36.5% at p=11, within 3 pts of the p=251 reference prediction
    (-40%). Small-fixture screen confirmed faithful predictor.
  - Robustness gap fixed (handle-binary-* delete-file unconditional);
    12 guard lines across 6 sites; zero crashes since deployment.
This commit is contained in:
russell@unturf.com 2026-06-05 20:52:43 -04:00
parent 3a8c66a148
commit 7b67b727e1
No known key found for this signature in database

View file

@ -92,6 +92,57 @@ make gpu-worker LUMBDA=asm # smallest footprint</code></pre>
<p>Crossover at ~115 batches. GPU kernel carries ~5,070 ms of fixed overhead (init + alloc + upload) plus ~12 ms per batch; CPU runs ~55 ms per batch. The kickmix circuit's conditional ops cause branch divergence &mdash; this is one form where GPU does not dominate. Honest numbers go in the catalog below.</p>
</section>
<section id="fleet">
<h2>Fleet &mdash; cross-GPU & cluster numbers</h2>
<p>bend runs on a 2-host LAN cluster today. The worker on each box is a lumbda C-tier process; daemons stay warm across requests. Round-robin selection lives in <code>bend.lsp</code> via <code>*bend-workers*</code> &amp; the <code>BEND_WORKERS</code> environment variable.</p>
<table>
<thead><tr><th>host</th><th>GPU</th><th>arch</th><th>port</th><th>daemons live</th><th>coexists with</th></tr></thead>
<tbody>
<tr><td><code>3090-ai.foxhop.net</code></td><td>RTX 3090 (24 GB)</td><td>sm_86</td><td>9091</td><td>shake / cgbn / secp / sim-ops-bin / sim-axis-flip</td><td>idle</td></tr>
<tr><td><code>ai.foxhop.net</code></td><td>RTX 4090 (24 GB)</td><td>sm_89</td><td>9092</td><td>shake / cgbn / secp</td><td>qwen LLM serving on ports 9090 + 9091 (Erlang Cowboy, uid 992)</td></tr>
</tbody>
</table>
<p>The 4090 box shares the GPU with a qwen LLM (vllm) serving on the same machine. Our bend kernels fit alongside qwen comfortably because the secp256k1 / CGBN workloads burn the SMs only for milliseconds at a time, then release. The qwen server keeps its model weights resident; our kernels allocate transient VRAM for the per-call batch, run, free, return. 24 GB VRAM is enough for both.</p>
<h3>Cross-GPU parity at small batches</h3>
<p>Single-call kernel time at <code>n=100k</code> CGBN 256-bit mod-mul:</p>
<table>
<thead><tr><th>host</th><th>kernel ms</th><th>wall ms (incl. PCIe + wire)</th><th>Mops/s (wall)</th></tr></thead>
<tbody>
<tr><td>3090-ai</td><td>0.07&ndash;0.10</td><td>336 (median)</td><td>0.30</td></tr>
<tr><td>ai (4090)</td><td>0.07&ndash;0.10</td><td>362 (median)</td><td>0.28</td></tr>
</tbody>
</table>
<p>At <code>n=100k</code>, kernels finish faster than the per-call PCIe transfer (6.4 MB tx) + LAN wire round trip. Both GPUs run the same workload in the same kernel time because neither saturates &mdash; both starve between calls. The 4090's raw FLOPS advantage shows up only when the kernel runs long enough to amortize wire overhead.</p>
<h3>Cluster aggregate &mdash; round-robin fan-out</h3>
<table>
<thead><tr><th>workload</th><th>solo (1 host)</th><th>cluster (2 hosts)</th><th>speedup</th></tr></thead>
<tbody>
<tr><td>200 × <code>n=1k</code> CGBN mod-mul</td><td>0.052 Mops/s</td><td>0.084 Mops/s</td><td><strong>1.6&times;</strong></td></tr>
<tr><td>6 × <code>n=100k</code> CGBN mod-mul</td><td>0.15 Mops/s</td><td>0.18 Mops/s</td><td>1.2&times;</td></tr>
</tbody>
</table>
<p>Speedup caps at 1.6&times; instead of 2&times; because the dispatching client serializes one call at a time. An async fan-out client unlocks the remaining 2&times; headroom. Workers themselves never block each other.</p>
<h3>First measured ECDSA-mission sweep</h3>
<p>The first end-to-end run through the full lumbda &rarr; emit-ops-bin walker &rarr; bend &rarr; demo_ops pipeline landed today at <code>runs/lumbda-sweep-001/</code>. Two of six lever variants emitted &amp; scored at <code>p=11</code> point-add width:</p>
<table>
<thead><tr><th>variant</th><th>n_ops</th><th>Σ Clifford</th><th>Σ Toffoli</th></tr></thead>
<tbody>
<tr><td>Solinas + Fermat textbook B-Y</td><td>48,763</td><td>1,687,232</td><td>749,056</td></tr>
<tr><td><strong>Solinas + refined B-Y</strong> (Phase B step 10)</td><td><strong>32,333</strong></td><td><strong>1,237,440</strong></td><td><strong>475,648</strong></td></tr>
</tbody>
</table>
<p><strong>Refined Bernstein-Yang cuts Σ Toffoli by 36.5% at production-relevant width.</strong> Our small-fixture lever screen predicted &minus;56% at <code>p=5</code>, &amp; the <code>p=251</code> ground-truth reference predicted &minus;40%. Measured &minus;36.5% sits within 3 percentage points of the larger-width prediction. The small-fixture lever screen earns its keep as a faithful predictor: sweep cheap at <code>p=11</code>, filter to winners, promote only winners to <code>p=251</code> production cost.</p>
<p>Four remaining variants still emitting (the lumbda walker is CPU-bound on the local box at full Phase B width); <code>dispatch-sweep.py</code> auto-resumes against new <code>.bin</code> files as they land.</p>
<h3>Robustness</h3>
<p>The binary handlers (<code>handle-binary-shake</code>, <code>handle-binary-cgbn</code>, <code>handle-binary-secp</code>) used to call <code>delete-file</code> unconditionally after daemon failure &mdash; if the daemon errored before writing the output portal, the missing-file raise crashed the entire listener. 12 guard lines across 6 sites (<code>(if (file-exists? PATH) (delete-file PATH))</code>) closed the gap. Fix held under sustained sweep traffic with zero crashes since deployment.</p>
</section>
<section id="catalog">
<h2>Form catalog</h2>
<p>A form earns a slot here only after we have published a benchmark or measured one on our hardware. "I think this would be fast" does not earn a slot &mdash; the form-status column says <code>planned</code> until numbers exist.</p>