From a88cebced06cc7c1a6cf8b9d79aeef32d7ed1dfa Mon Sep 17 00:00:00 2001 From: "russell@unturf.com" Date: Sun, 14 Jun 2026 19:58:57 -0400 Subject: [PATCH] =?UTF-8?q?bend=20demo:=20100M=20secp256k1=20=E2=80=94=20e?= =?UTF-8?q?pic=20160x=20GPU=20win,=20~33=20minutes=20of=20CPU=20work?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the small cuda-shake-fanout step and the modest kickmix 4x demo with a single dispatch you can feel: 100,000,000 secp256k1 scalar*G batched multiplications. Numbers measured end-to-end through https://bend.unturf.com/ on 3090-ai: HTTP request size ~32 bytes (just '(cuda-secp256k1-bench 100000000)') worker scalar gen 5.2 s (/dev/urandom into 3.2 GB BSCP) GPU kernel 12.5 s (7.99 Mkeys/s on 3090) total wall-clock 18.3 s CPU equivalent ~2000 s = ~33 minutes (libsecp256k1 ref) speedup-est ~160x The 3.2 GB of random scalars never crosses the wire — the worker synthesizes them from os.urandom and dispatches into the existing cuda-secp256k1-batched-mul daemon. Response is a tiny S-expression with the timing summary; no 6.4 GB result blob comes back. Ping + health stay at the top so a visitor sees the chain warm up before committing to the 18 s heavy run. --- wasm/app/demos/bend-gpu.lsp | 49 ++++++++++++------------------- www/playground/demos/bend-gpu.lsp | 49 ++++++++++++------------------- 2 files changed, 36 insertions(+), 62 deletions(-) diff --git a/wasm/app/demos/bend-gpu.lsp b/wasm/app/demos/bend-gpu.lsp index 0d1a681..318142d 100644 --- a/wasm/app/demos/bend-gpu.lsp +++ b/wasm/app/demos/bend-gpu.lsp @@ -4,19 +4,18 @@ ; above first. The playground guards the Run button so a customer ; machine never burns minutes on the local tiers. ; -; What you can call today (S-expression mode over HTTP): -; (ping) → (ok pong) — round-trip probe -; (health) → (ok (load-avg ...)) — worker telemetry -; (cuda-shake-fanout INPUTS OUT-BYTES) -; → (ok (HEX0 HEX1 ...)) — N SHAKE256 outputs -; (cuda-sim-ops-bin PATH N-BATCHES) -; → (ok (cuda-sim-result … (timing-ms …))) -; — kickmix circuit on the worker's bin +; Today's headline payload: 100,000,000 secp256k1 scalar*G operations +; in one HTTP POST. On a 3090 the daemon finishes in ~13 seconds; +; on a single CPU core (libsecp256k1 ~50K keys/s) the same workload +; would take ~33 minutes. That's a ~160× speedup — the kind of math +; only a GPU can do in a reasonable amount of time. ; -; Binary modes (BSHK / BCGB / BSCP / BSRT / BSB3) stream raw bytes via -; the wire-TCP path and stay native-only until Phase 2 lands server-side -; factory recipes (gated on auth — today an open recipe endpoint would -; let anyone occupy our GPU). +; The request is ~32 bytes of S-expression. The 3.2 GB of random +; scalars never crosses the wire — the worker generates them locally +; from /dev/urandom via examples/cuda-fanout/generate-bscp.py, calls +; into the existing cuda-secp256k1-batched-mul daemon, and returns +; just the timing summary. You see the GPU work happen in your +; output panel; your laptop never does the math. (display ";; 1. probe round-trip ...") (newline) (define r1 (bend!-call "(ping)")) @@ -28,25 +27,13 @@ (display " (health) → ") (display r2) (newline) (newline) -(display ";; 3. small CUDA fan-out (3 inputs, 32-byte outputs) ...") (newline) -(define payload - (string-append - "(cuda-shake-fanout " - "(\"00\" \"01\" \"deadbeef\") " - "32)")) -(display " payload: ") (display payload) (newline) -(define r3 (bend!-call payload)) +(display ";; 3. 100,000,000 secp256k1 scalar*G batch on the GPU") (newline) +(display ";; ~13 s on 3090 vs ~33 min on a CPU core (~160x)") (newline) +(display ";; sit tight — this is real compute, not a mock") (newline) +(define heavy "(cuda-secp256k1-bench 100000000)") +(display " payload: ") (display heavy) (newline) +(define r3 (bend!-call heavy)) (display " result : ") (display r3) (newline) (newline) -(display ";; 4. feel the GPU win — kickmix circuit simulation") (newline) -(display ";; 14,848 ops / 58 qubits / 9024 shots / 141 batches") (newline) -(display ";; tiny HTTP payload (~70 bytes), heavy GPU work") (newline) -(display ";; CPU baseline ~1450 ms, GPU kernel ~360 ms (~4x)") (newline) -(define heavy "(cuda-sim-ops-bin \"/tmp/ecdsa-queue/out.bin\" 141)") -(display " payload: ") (display heavy) (newline) -(define r4 (bend!-call heavy)) -(display " result : ") (display r4) (newline) -(newline) - -(print "done") +(print "done — that math would have taken ~33 minutes on this CPU.") diff --git a/www/playground/demos/bend-gpu.lsp b/www/playground/demos/bend-gpu.lsp index 0d1a681..318142d 100644 --- a/www/playground/demos/bend-gpu.lsp +++ b/www/playground/demos/bend-gpu.lsp @@ -4,19 +4,18 @@ ; above first. The playground guards the Run button so a customer ; machine never burns minutes on the local tiers. ; -; What you can call today (S-expression mode over HTTP): -; (ping) → (ok pong) — round-trip probe -; (health) → (ok (load-avg ...)) — worker telemetry -; (cuda-shake-fanout INPUTS OUT-BYTES) -; → (ok (HEX0 HEX1 ...)) — N SHAKE256 outputs -; (cuda-sim-ops-bin PATH N-BATCHES) -; → (ok (cuda-sim-result … (timing-ms …))) -; — kickmix circuit on the worker's bin +; Today's headline payload: 100,000,000 secp256k1 scalar*G operations +; in one HTTP POST. On a 3090 the daemon finishes in ~13 seconds; +; on a single CPU core (libsecp256k1 ~50K keys/s) the same workload +; would take ~33 minutes. That's a ~160× speedup — the kind of math +; only a GPU can do in a reasonable amount of time. ; -; Binary modes (BSHK / BCGB / BSCP / BSRT / BSB3) stream raw bytes via -; the wire-TCP path and stay native-only until Phase 2 lands server-side -; factory recipes (gated on auth — today an open recipe endpoint would -; let anyone occupy our GPU). +; The request is ~32 bytes of S-expression. The 3.2 GB of random +; scalars never crosses the wire — the worker generates them locally +; from /dev/urandom via examples/cuda-fanout/generate-bscp.py, calls +; into the existing cuda-secp256k1-batched-mul daemon, and returns +; just the timing summary. You see the GPU work happen in your +; output panel; your laptop never does the math. (display ";; 1. probe round-trip ...") (newline) (define r1 (bend!-call "(ping)")) @@ -28,25 +27,13 @@ (display " (health) → ") (display r2) (newline) (newline) -(display ";; 3. small CUDA fan-out (3 inputs, 32-byte outputs) ...") (newline) -(define payload - (string-append - "(cuda-shake-fanout " - "(\"00\" \"01\" \"deadbeef\") " - "32)")) -(display " payload: ") (display payload) (newline) -(define r3 (bend!-call payload)) +(display ";; 3. 100,000,000 secp256k1 scalar*G batch on the GPU") (newline) +(display ";; ~13 s on 3090 vs ~33 min on a CPU core (~160x)") (newline) +(display ";; sit tight — this is real compute, not a mock") (newline) +(define heavy "(cuda-secp256k1-bench 100000000)") +(display " payload: ") (display heavy) (newline) +(define r3 (bend!-call heavy)) (display " result : ") (display r3) (newline) (newline) -(display ";; 4. feel the GPU win — kickmix circuit simulation") (newline) -(display ";; 14,848 ops / 58 qubits / 9024 shots / 141 batches") (newline) -(display ";; tiny HTTP payload (~70 bytes), heavy GPU work") (newline) -(display ";; CPU baseline ~1450 ms, GPU kernel ~360 ms (~4x)") (newline) -(define heavy "(cuda-sim-ops-bin \"/tmp/ecdsa-queue/out.bin\" 141)") -(display " payload: ") (display heavy) (newline) -(define r4 (bend!-call heavy)) -(display " result : ") (display r4) (newline) -(newline) - -(print "done") +(print "done — that math would have taken ~33 minutes on this CPU.")