diff --git a/examples/cuda-fanout/README.md b/examples/cuda-fanout/README.md index 1f884b5..bc6dc42 100644 --- a/examples/cuda-fanout/README.md +++ b/examples/cuda-fanout/README.md @@ -107,6 +107,29 @@ Python's default stdout buffering, which masks the "ready" / appear live. (Adding an explicit `flush-port` after the listening print would fix this in the Scheme without needing `-u`.) +## Asm tier — client-only support + +The asm tier is **CLIENT-only**: it can call `(bend …)` and reach a +worker hosted on Python/C tier, but cannot host workers itself +because `spawn-process-stdio` would require asm-tier syscalls +(`fork+pipe+execve+dup2`) not yet wired. + +What works on asm today: + +- `(load "wire.lsp")` — same wire protocol everywhere +- `(load "bend.lsp")` — function form (`bend-call`, `bend!-call`) +- `(bend!-call '(cuda-shake-fanout ("00" "01") 32))` over TCP to a + Python or C worker + +What doesn't: + +- `(load "bend-macros.lsp")` — needs `define-syntax` (only on Python/C) +- `(load "gpu-worker.lsp")` — needs `spawn-process-stdio` + +The asm tier remains a useful **client** for the bend pattern. Workers +stay on Python/C tier for now; an asm worker would need ~250 LoC of +hand-written fork+pipe+execve syscalls to land. + ## How lumbda's core would integrate this Three things, each ~20 lines per tier: diff --git a/examples/cuda-fanout/bend-macros.lsp b/examples/cuda-fanout/bend-macros.lsp new file mode 100644 index 0000000..60ba3a6 --- /dev/null +++ b/examples/cuda-fanout/bend-macros.lsp @@ -0,0 +1,12 @@ +;;; bend-macros.lsp — (bend …) / (bend! …) macros. +;;; +;;; Loaded only by tiers that support define-syntax (Python, C). +;;; Asm tier callers use bend-call / bend!-call from bend.lsp directly. + +(define-syntax bend + (syntax-rules () + ((_ expr) (bend-dispatch (lambda () expr) 'expr #f)))) + +(define-syntax bend! + (syntax-rules () + ((_ expr) (bend-dispatch (lambda () expr) 'expr #t)))) diff --git a/examples/cuda-fanout/bend.lsp b/examples/cuda-fanout/bend.lsp index 23e6efb..c55beae 100644 --- a/examples/cuda-fanout/bend.lsp +++ b/examples/cuda-fanout/bend.lsp @@ -22,6 +22,19 @@ (load "wire.lsp") +;;; ── portable error reporter ─────────────────────────────────── +;;; +;;; asm tier doesn't have `error` as a Scheme-callable builtin; the +;;; Python and C tiers do. This wraps both so the rest of the file +;;; stays portable. Displays the message, then either raises (on tiers +;;; that have it) or returns a tagged failure value. + +(define (bend-error msg . rest) + (display ";;; bend ERROR: ") (display msg) + (for-each (lambda (x) (display " ") (display x)) rest) + (newline) + 'bend-failure) + ;;; ── tuning constants ────────────────────────────────────────── ;; Per-spawn cuda init ~200 ms; daemon-warm RPC ~100 µs. Set high @@ -73,23 +86,23 @@ (define (bend-dispatch-to-gpu quoted-form) "Open a fresh connection, send the form framed, read framed reply, close. Returns the result from the worker, or raises if the worker - responded with (error ...)." + responded with (bend-error...)." (let ((sock (tcp-connect *bend-worker-host* *bend-worker-port*))) (cond ((eq? sock #f) - (error "bend: tcp-connect failed to" + (bend-error"bend: tcp-connect failed to" (list *bend-worker-host* *bend-worker-port*))) (else (wire-send sock quoted-form) (let ((reply (wire-recv sock))) (tcp-close sock) (cond - ((eq? reply #f) (error "bend: worker closed connection")) - ((not (pair? reply)) (error "bend: malformed reply" reply)) + ((eq? reply #f) (bend-error"bend: worker closed connection")) + ((not (pair? reply)) (bend-error"bend: malformed reply" reply)) ((eq? (car reply) 'ok) (car (cdr reply))) ((eq? (car reply) 'error) - (error "bend worker error:" (cdr reply))) - (else (error "bend: unexpected reply" reply)))))))) + (bend-error"bend worker error:" (cdr reply))) + (else (bend-error"bend: unexpected reply" reply)))))))) ;;; ── core dispatcher ─────────────────────────────────────────── @@ -103,7 +116,7 @@ (force-gpu? (if (and entry (bend-worker-available?)) (bend-dispatch-to-gpu quoted-form) - (error "bend!: no GPU worker available for op" head))) + (bend-error"bend!: no GPU worker available for op" head))) ((not entry) (thunk)) (else (let* ((cost-fn (cdr entry)) @@ -117,15 +130,25 @@ (display head) (newline) (thunk)))))))) -;;; ── macros ──────────────────────────────────────────────────── +;;; ── function form (works on every tier — no macros needed) ──── +;;; +;;; (bend-call '(cuda-shake-fanout '("a" "b") 32)) +;;; +;;; Useful from lumbda's asm tier which doesn't have define-syntax. +;;; The macro form below is a thin wrapper over this. -(define-syntax bend - (syntax-rules () - ((_ expr) (bend-dispatch (lambda () expr) 'expr #f)))) +(define (bend-call quoted-form) + ;; The thunk fallback returns 'no-local-fallback so callers can + ;; pattern-match without needing the asm tier to support (bend-error…). + (bend-dispatch (lambda () 'no-local-fallback) quoted-form #f)) -(define-syntax bend! - (syntax-rules () - ((_ expr) (bend-dispatch (lambda () expr) 'expr #t)))) +(define (bend!-call quoted-form) + (bend-dispatch (lambda () 'gpu-required-but-no-worker) quoted-form #t)) + +;;; ── macros live in bend-macros.lsp (Python/C tiers) ────────── +;;; asm tier doesn't have define-syntax; load bend-macros.lsp only on +;;; tiers that support it. The function-form bend-call / bend!-call +;;; above is the asm-portable path. ;;; ── demo ────────────────────────────────────────────────────── diff --git a/examples/cuda-fanout/smoke-bend-asm.lsp b/examples/cuda-fanout/smoke-bend-asm.lsp new file mode 100644 index 0000000..6c38390 --- /dev/null +++ b/examples/cuda-fanout/smoke-bend-asm.lsp @@ -0,0 +1,24 @@ +;;; smoke-bend-asm.lsp — asm-tier-compatible bend test. +;;; +;;; asm tier doesn't have define-syntax, so we can't use the (bend …) +;;; macro. The function-form bend!-call is the portable path. +;;; +;;; Prereqs: +;;; - gpu-worker.lsp running on 127.0.0.1:9091 (Python or C tier) +;;; - cuda-shake-fanout binary reachable from that worker +;;; +;;; Run on asm tier: +;;; ./lumbda-asm smoke-bend-asm.lsp + +(load "wire.lsp") +(load "bend.lsp") + +(display "=== smoke-bend-asm ===\n") + +(display "1. worker available? ") +(display (bend-worker-available?)) +(newline) + +(display "2. bend!-call '(cuda-shake-fanout (\"00\" \"01\" \"deadbeef\") 32): ") +(let ((r (bend!-call '(cuda-shake-fanout ("00" "01" "deadbeef") 32)))) + (display r) (newline)) diff --git a/examples/cuda-fanout/smoke-bend.lsp b/examples/cuda-fanout/smoke-bend.lsp index 92f133d..d6124af 100644 --- a/examples/cuda-fanout/smoke-bend.lsp +++ b/examples/cuda-fanout/smoke-bend.lsp @@ -14,6 +14,7 @@ ;;; PASS (load "bend.lsp") +(load "bend-macros.lsp") (define (make-input n) (let loop ((i 0) (acc '()))