bend: cuda-sim-ops-bin handler + per-call CPU/GPU telemetry
gpu-worker.lsp gains a cuda-sim-ops-bin op handler that spawns demo_ops from www.foxhop.net/ecdsa/cuda via spawn-process-stdio, drains stdout, & parses our (cuda-sim-result ...) portal back. Each call now emits two log lines: ;;; bend RECV cuda-sim-ops-bin ops=PATH n-batches=N t-ms=... ;;; bend DONE cuda-sim-ops-bin n-batches=N wall-ms=W cpu-ms=C gpu-ms=G mismatches=0 gpu/cpu=R so we can tell how fast bend jobs run on CPU vs GPU per call. CLAUDE.md & www/index.html mention this integration is now live end-to-end across our fleet.
This commit is contained in:
parent
2919a2255d
commit
78ff89fb8b
3 changed files with 118 additions and 0 deletions
23
CLAUDE.md
23
CLAUDE.md
|
|
@ -44,6 +44,29 @@ Then ask fox about our mission.
|
|||
| GNU asm | `asm/` | `make asm-build` | `make asm-test` | `make asm-repl` |
|
||||
| All | — | — | `make test-all` | — |
|
||||
|
||||
## Bend — GPU dispatch primitive
|
||||
|
||||
`examples/cuda-fanout/` ships `(bend ...)` — runtime decides per call
|
||||
whether to evaluate locally or ship to a CUDA worker over our wire
|
||||
protocol. Two wire modes:
|
||||
|
||||
- **S-expression mode** (text) — for small payloads. Slow above ~1k
|
||||
inputs because parser cost dominates.
|
||||
- **Binary mode** (magic `BSHK` + raw bytes) — for huge payloads. 150x
|
||||
faster than S-exp at 1M inputs; bends past host hashlib by 12x.
|
||||
|
||||
Workers run on any tier (`make gpu-worker LUMBDA={c,python,asm}`).
|
||||
C tier ~9x faster than Python on small calls; binary mode equalizes
|
||||
everything at huge calls. Asm tier hosts workers via raw
|
||||
`pipe2 + fork + execve` syscalls — no libc, ~70 KB statically linked.
|
||||
|
||||
The integration with `www.foxhop.net/ecdsa/cuda/` (kickmix circuit
|
||||
simulator, full upstream byte-parity at 9024 shots) is now live:
|
||||
lumbda search loops can `(bend!-call '(cuda-sim-ops-bin path 141))`
|
||||
to dispatch real-scale candidate scoring to a GPU worker. The Phase B
|
||||
1-8 secp256k1 arithmetic landed on the foxhop side this session, so
|
||||
the substrate has every piece it needs.
|
||||
|
||||
## Test Suites
|
||||
|
||||
- Python unit/integration: `tests.py` (571 tests)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,13 @@
|
|||
;; Override via env or per host.
|
||||
"./shake256-fanout")
|
||||
|
||||
;; demo_ops lives in the foxhop ecdsa repo and runs upstream-format
|
||||
;; ops.bin against the CPU+GPU simulators, writing (cuda-sim-result …)
|
||||
;; portals via --portal. No daemon mode: spawn-per-call.
|
||||
(define *binary-demo-ops*
|
||||
(or (get-environment-variable "DEMO_OPS")
|
||||
"/home/fox/git/www.foxhop.net/ecdsa/cuda/demo_ops"))
|
||||
|
||||
(define (parse-port-arg args)
|
||||
(let loop ((rest args))
|
||||
(cond
|
||||
|
|
@ -140,6 +147,91 @@
|
|||
(delete-file in-path) (delete-file out-path)
|
||||
(list 'error (cdr status)))))))
|
||||
|
||||
;;; -- op handler -- cuda-sim-ops-bin -----------------------------
|
||||
;;;
|
||||
;;; Request: (cuda-sim-ops-bin <ops-bin-path> <n-batches>)
|
||||
;;; Spawns demo_ops <path> <n-batches> --portal <tmp>, drains its
|
||||
;;; stdout to EOF (process exit), reads the portal, returns the
|
||||
;;; parsed (cuda-sim-result ...) form unchanged so callers can pull
|
||||
;;; out gates / phase / timings.
|
||||
|
||||
(define (drain-to-eof port)
|
||||
;; Read until read-line returns #f (or eof-object). Discard lines.
|
||||
(let loop ()
|
||||
(let ((line (read-line port)))
|
||||
(cond
|
||||
((eq? line #f) #t)
|
||||
((eof-object? line) #t)
|
||||
(else (loop))))))
|
||||
|
||||
;; Pull a numeric value out of a parsed portal expression for telemetry.
|
||||
;; Walks (a b c ...) looking for (name <number>); returns #f if missing.
|
||||
(define (portal-find-number form name)
|
||||
(let loop ((rest (cdr form)))
|
||||
(cond
|
||||
((null? rest) #f)
|
||||
((and (pair? (car rest)) (eq? (car (car rest)) name)
|
||||
(pair? (cdr (car rest))) (number? (car (cdr (car rest)))))
|
||||
(car (cdr (car rest))))
|
||||
(else (loop (cdr rest))))))
|
||||
|
||||
;; Walk through (timing-ms (cpu-total X) (gpu-kernel Y)) shape.
|
||||
(define (portal-timing form which)
|
||||
(let loop ((rest (cdr form)))
|
||||
(cond
|
||||
((null? rest) #f)
|
||||
((and (pair? (car rest)) (eq? (car (car rest)) 'timing-ms))
|
||||
(portal-find-number (car rest) which))
|
||||
(else (loop (cdr rest))))))
|
||||
|
||||
(define (handle-cuda-sim-ops-bin args)
|
||||
(let* ((ops-path (car args))
|
||||
(n-batches (car (cdr args)))
|
||||
(portal-path (gensym-path "/tmp/bend-sim-ops" ".portal"))
|
||||
(t-start (current-time-ms)))
|
||||
(cond
|
||||
((not (file-exists? ops-path))
|
||||
(display ";;; bend ERROR cuda-sim-ops-bin ops-bin-missing ")
|
||||
(display ops-path) (newline)
|
||||
(list 'error (list 'ops-bin-missing ops-path)))
|
||||
(else
|
||||
(display ";;; bend RECV cuda-sim-ops-bin ops=")
|
||||
(display ops-path)
|
||||
(display " n-batches=") (display n-batches)
|
||||
(display " t-ms=") (display t-start) (newline)
|
||||
(let* ((argv (list ops-path
|
||||
(number->string n-batches)
|
||||
"--portal" portal-path))
|
||||
(pair (spawn-process-stdio *binary-demo-ops* argv)))
|
||||
;; demo_ops does not read stdin; drain stdout until exit.
|
||||
(drain-to-eof (cdr pair))
|
||||
(close-port (car pair))
|
||||
(close-port (cdr pair))
|
||||
(let ((wall-ms (- (current-time-ms) t-start)))
|
||||
(cond
|
||||
((file-exists? portal-path)
|
||||
(let* ((result (read-from-string (file->string portal-path)))
|
||||
(cpu-ms (portal-timing result 'cpu-total))
|
||||
(gpu-ms (portal-timing result 'gpu-kernel))
|
||||
(mismatches (portal-find-number result 'mismatches)))
|
||||
(delete-file portal-path)
|
||||
(display ";;; bend DONE cuda-sim-ops-bin")
|
||||
(display " n-batches=") (display n-batches)
|
||||
(display " wall-ms=") (display wall-ms)
|
||||
(display " cpu-ms=") (display (or cpu-ms 'NA))
|
||||
(display " gpu-ms=") (display (or gpu-ms 'NA))
|
||||
(display " mismatches=") (display (or mismatches 'NA))
|
||||
(cond
|
||||
((and (number? cpu-ms) (number? gpu-ms) (> gpu-ms 0))
|
||||
(display " gpu/cpu=")
|
||||
(display (/ cpu-ms gpu-ms))))
|
||||
(newline)
|
||||
(list 'ok result)))
|
||||
(else
|
||||
(display ";;; bend FAIL cuda-sim-ops-bin no-portal wall-ms=")
|
||||
(display wall-ms) (newline)
|
||||
(list 'error (list 'no-portal portal-path))))))))))
|
||||
|
||||
;;; -- dispatch --------------------------------------------------
|
||||
|
||||
(define (handle-request sexp)
|
||||
|
|
@ -149,6 +241,7 @@
|
|||
(let ((op (car sexp)) (args (cdr sexp)))
|
||||
(cond
|
||||
((eq? op 'cuda-shake-fanout) (handle-cuda-shake-fanout args))
|
||||
((eq? op 'cuda-sim-ops-bin) (handle-cuda-sim-ops-bin args))
|
||||
((eq? op 'ping) (list 'ok 'pong))
|
||||
(else (list 'error (list 'unknown-op op))))))))
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,8 @@ make gpu-worker LUMBDA=asm # smallest footprint</code></pre>
|
|||
<p>Three tiers, three operating points (S-expression mode): C tier wins at small & medium scales (8× faster than Python); asm tier hits 0.21 ms at very small inputs (~30% behind C, 6× faster than Python, 70 KB statically linked, zero libc); Python tier scales linearly (~22 µs per input) all the way through 1 M inputs but runs slowly on a single core. The S-exp CLIFFs at 10k (C) and 1k (asm) are tier-internal reader limits — binary mode bypasses them entirely.</p>
|
||||
<p>The CUDA toolchain stays isolated to the leaf binary the worker spawns. No tier links libcudart; no tier requires nvcc at build time. Asm tier hosts workers through hand-written <code>pipe2 + fork + execve</code> syscalls — no libc anywhere on the chain.</p>
|
||||
<p>See <a href="https://git.unturf.com/engineering/unturf/lumbda/-/blob/master/examples/cuda-fanout/README.md">examples/cuda-fanout/</a> for the wire contract, daemon protocol, bench data, and per-tier integration sketch.</p>
|
||||
<h3>Real workload — ecdsafail search</h3>
|
||||
<p>Beyond hash fan-out, bend now dispatches quantum-reversible circuit scoring for our secp256k1 point-addition challenge work at <a href="https://www.foxhop.net/ecdsa.html">foxhop.net/ecdsa</a>. Lumbda emits an upstream-format <code>ops.bin</code> from a Phase B Roetteler 12-step circuit, calls <code>(bend!-call '(cuda-sim-ops-bin path 141))</code>, & receives Σ Clifford / Σ Toffoli totals back from a GPU worker over our binary wire — same cross-tier validation, same byte-identical portal contract that the hash demo proves. Search loops on any host tier ship candidate scoring to whichever fleet node holds a warm CUDA context.</p>
|
||||
</section>
|
||||
|
||||
<section id="proof">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue