lumbda/examples/cuda-fanout/Makefile
russell@unturf.com 05fa922d42
bend form G — cuda-radix-sort lands live (CUB DeviceRadixSort u64)
Thin CUDA binary wrapping cub::DeviceRadixSort::SortKeys on a 64-bit
key stream. One op wired day-1 (0x01 sort-u64-asc); 0x02/0x03/0x04
slots reserved (desc, u32, key-value) for future builds.

Wire stays distinct from existing forms:
  request:  BSRT | u32 op_id | u32 n | u64[n]
  response: BSRR | u32 status | u32 n | u64[n] sorted asc

Validated on 3090-ai.foxhop.net byte-identical to Python sorted() at
n ∈ {32, 1k, 100k, 1M, 10M}. Bench at sustained throughput:

  n           kernel_ms   Gkeys/s
  100,000     0.142       0.706
  1,000,000   0.265       3.767
  10,000,000  1.817       5.504

~4x over the published Titan baseline (1.4 Gkeys/s) at saturation,
matching CUB's expected Ampere scaling.

gpu-worker.lsp learns handle-binary-sort + BSRT magic dispatch +
maybe-register-daemon! for cuda-radix-sort (overridable via
RADIX_SORT_WORKER env). Both 3090-ai (:9091) & ai (:9092) workers
restarted; both log `ready cuda-radix-sort <- ./radix-sort`.

4090 (ai.foxhop.net) standalone --binary run OOMs on cudaMalloc when
all four daemons are co-resident (secp256k1 daemon parks ~24 GiB on
startup, leaving 47 MiB free). Pre-existing capacity constraint of
the ai host, not a form-G defect; tracked in form-G-progress.md.

CATALOG.md & www/bend.html live-forms table updated with measured
3090 numbers; Wave 1 surveyed row for G marked as promoted.
2026-06-05 21:50:05 -04:00

81 lines
3.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 cgbn-batch-worker secp256k1-batch-mul radix-sort
shake256-fanout: shake256-fanout.cu
$(NVCC) $(NVCCFLAGS) -o $@ $<
# bend form G — batched u64 radix sort via NVIDIA CUB
# (header-only, ships with CUDA Toolkit so no extra deps).
# Wire: BSRT (sort-u64-asc) request → BSRR sorted-keys response.
radix-sort: radix-sort.cu
$(NVCC) $(NVCCFLAGS) --expt-relaxed-constexpr -o $@ $<
radix-sort-test: radix-sort test_radix_sort_known_answers.py
python3 -u test_radix_sort_known_answers.py ./radix-sort
radix-sort-bench: radix-sort test_radix_sort_known_answers.py
python3 -u test_radix_sort_known_answers.py ./radix-sort --bench
# bend form A — secp256k1 batched scalar*G via VanitySearch-Bitcrack
# vendored GPUMath.h (AGPL-3.0). Per-thread Jacobian double-and-add,
# per-thread inversion to affine. See vendor/vanity-search-bitcrack/NOTICE.
NVCCFLAGS_SECP ?= -O3 -arch=sm_86 -Xcompiler="-O3 -Wall"
secp256k1-batch-mul: secp256k1-batch-mul.cu vendor/vanity-search-bitcrack/GPUMath.h
$(NVCC) $(NVCCFLAGS_SECP) -o $@ $<
secp256k1-test: secp256k1-batch-mul test_secp256k1_known_answers.py
python3 -u test_secp256k1_known_answers.py ./secp256k1-batch-mul
secp256k1-bench: secp256k1-batch-mul test_secp256k1_known_answers.py
python3 -u test_secp256k1_known_answers.py ./secp256k1-batch-mul --n 100000
# bend form B — CGBN bignum batch worker.
# CGBN_INC must point at a checkout of https://github.com/NVlabs/CGBN/include
# (header-only consumption; CGBN headers are BSD-3-Clause, our wrapper
# binary stays AGPLv3 — license noted at the top of cgbn-batch-worker.cu).
CGBN_INC ?= $(HOME)/CGBN/include
cgbn-batch-worker: cgbn-batch-worker.cu
@if [ ! -d "$(CGBN_INC)/cgbn" ]; then \
echo "ERROR: CGBN headers not found at $(CGBN_INC)/cgbn"; \
echo " Install: git clone https://github.com/NVlabs/CGBN $(HOME)/CGBN"; \
echo " Or pass: make cgbn-batch-worker CGBN_INC=/path/to/CGBN/include"; \
exit 1; \
fi
$(NVCC) $(NVCCFLAGS) --extended-lambda -I$(CGBN_INC) -o $@ $<
cgbn-test: cgbn-batch-worker test_cgbn_known_answers.py
python3 test_cgbn_known_answers.py ./cgbn-batch-worker
# 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