lumbda/examples/cuda-fanout/Makefile
russell@unturf.com f11e310b24
examples: cuda-fanout reference primitive for cross-tier GPU work
Establishes the integration pattern for lumbda's future cuda primitive
across Python / C / asm tiers without dragging the CUDA toolchain into
lumbda's core build.

Shape: leaf binary that every tier spawns via its existing process-
spawn primitive & talks to through S-expression input + output
portals. Asm tier inherits via fork + execve syscalls; no libcudart
linkage; no DKMS dependency at lumbda build time.

Files:
  shake256-fanout.cu   self-contained CUDA SHAKE256 fan-out, Keccak
                       permutation derived from FIPS 202 reference
                       (tiny-sha3 lineage, CC0 → re-licensed AGPLv3)
  Makefile             nvcc build + make test + make bench
  test_roundtrip.py    validates output byte-identical to
                       hashlib.shake_256
  bench.py             device vs host throughput at N = 1k / 10k / 100k
  lumbda-call.lsp      reference Scheme wrapper showing the
                       (cuda-shake-fanout inputs out-bytes) API shape
                       lumbda's core would dispatch to per-tier
  README.md            full integration story, wire contract, the
                       three changes each tier needs (~20 LoC each),
                       generalization path for other CUDA primitives

Tested on 3090-ai (RTX 3090):
  make test  → PASS — 4 / 4 hashes byte-identical to hashlib.shake_256

Honest bench (32-byte inputs):
  N         host (Python hashlib)  device (kernel launch dominated)
  1,000              0.6 ms                  188.1 ms
  10,000             5.9 ms                  195.7 ms
  100,000           58.7 ms                  313.8 ms

Useful primitive when inputs are larger (KB+) or N reaches millions;
honest about the launch-overhead break-even point. This is the
reference, not the win — the win is locking the API shape so each
tier registers under one stable name.

Provenance: extracted as the generic pattern from
~/git/www.foxhop.net/ecdsa/cuda/sim_gpu.cu where on-device SHAKE
delivered 2.6× memory compression for batched reversible-circuit
simulation. Re-shipping the primitive back to the lumbda repo so the
ecosystem inherits the work.
2026-06-04 17:50:48 -04:00

39 lines
1.5 KiB
Makefile

# shake256-fanout — Makefile.
#
# Builds the reference cuda fan-out worker. Each lumbda tier (Python,
# C, asm) spawns this binary via its existing process-spawn primitive
# & talks to it through input + output portal files. No tier links
# against libcudart directly — the CUDA toolchain dependency stays
# isolated to this directory.
#
# Build:
# make all — compile shake256-fanout (needs nvcc)
# make test — round-trip test (host + device produce identical
# SHAKE256 outputs over a small synthetic input set)
# make bench — bench device vs host throughput at N = 100k
NVCC ?= nvcc
NVCCFLAGS ?= -O3 -arch=sm_86 -Xcompiler="-O3 -Wall -Wextra"
NVCC_PATH ?= $(shell which nvcc 2>/dev/null || echo /usr/local/cuda/bin/nvcc)
all: shake256-fanout
shake256-fanout: shake256-fanout.cu
$(NVCC) $(NVCCFLAGS) -o $@ $<
# round-trip: feed (cuda-shake-fanout (output-bytes 32) (inputs ...))
# through the binary, compare against an external SHAKE256 reference
# (Python hashlib.shake_256).
test: shake256-fanout test_roundtrip.py
@printf '(cuda-shake-fanout\n (output-bytes 32)\n (inputs\n' > /tmp/cf-in.portal
@printf ' "00"\n "01"\n "deadbeef"\n "%s"\n' \
"$$(python3 -c 'print("ab" * 100)')" >> /tmp/cf-in.portal
@printf '))\n' >> /tmp/cf-in.portal
./shake256-fanout /tmp/cf-in.portal /tmp/cf-out.portal
python3 test_roundtrip.py /tmp/cf-in.portal /tmp/cf-out.portal
bench: shake256-fanout bench.py
python3 bench.py ./shake256-fanout
clean:
rm -f shake256-fanout /tmp/cf-in.portal /tmp/cf-out.portal