nx_swarm_gpu.nx
buildroot/runtime/nx_swarm_gpu.nx
about
nx_swarm_gpu.nx -- SWARM FABRIC GPU/VRAM inventory + SPLIT-MODEL SHARD PLANNER (F792). The keystone of
split-model serve (exo/Petals-class, sovereign): given a model too big for ONE GPU, decide how to shard
its layers across the fleet's LIVE free VRAM. Its OWN small organ (NEVER bolt onto nx_swarm_beat -- the
CPU-beacon 13-token contract stays untouched); the pulse layer reports a GPU row here, the hub reads a
fresh VRAM inventory + computes a shard plan. Composes the proven nx_swarm_beat store pattern (replace-by-
node snap, flock'd log, fabric-clock freshness, path law).
nx_swarm_gpu put "<GPU row>" -- validate 5-token row -> log append + snap replace
nx_swarm_gpu show <window_sec> -- FRESH/STALE per node (the live VRAM inventory)
nx_swarm_gpu plan <snap> <window_sec> <model_mb> [util%] -- greedy shard plan across fresh nodes' free VRAM;
REFUSE if fleet usable < model (never oversubscribe)
nx_swarm_gpu now -- fabric clock (stamp rows in the freshness units)
nx_swarm_gpu [gate] -- self-gate incl the liar-killers
GPU row (positional): GPU <node> <vram_total_mb> <vram_free_mb> <ts_us>
util% = headroom margin (default 85): usable = free_vram * util%/100 -- leaves room for activations + KV-cache;
a GPU is NEVER filled to 100% VRAM (an OOM mid-decode is the never-brick analog here). Greedy snap-order fill
minimizes the shard count = fewer cross-node activation transfers (Amdahl-friendly); biggest-first = a v2 sort.
PATH LAW mirrors nx_swarm_beat: CLI paths end .log/.snap, no "..", bare-basename-in-CWD or /tmp only.
license_tier: ORIGINAL expect_exit:0
dependencies 2 imports · 0 importers
imports: nx_syscalls.nxnx_framed_append.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 23 | const SG_MAGIC_60000000: i64 = 60000000 |
| 24 | const SG_MAGIC_1000000: i64 = 1000000 |
| 25 | const SG_MAGIC_16000: i64 = 16000 |
| 26 | const SG_MAGIC_8000: i64 = 8000 |
| 27 | const SG_MAGIC_24000: i64 = 24000 |
| 28 | const SG_MAGIC_20000: i64 = 20000 |
| 29 | const SG_MAGIC_4000: i64 = 4000 |
| 30 | const SG_MAGIC_3600: i64 = 3600 |
| 31 | const SG_MAGIC_3000: i64 = 3000 |
| 32 | const SG_MAGIC_19000: i64 = 19000 |
| 33 | const SG_MAGIC_25000: i64 = 25000 |
| 34 | const SG_MAGIC_21000: i64 = 21000 |
| 36 | const SG_SNAP_CAP: i64 = 65536 |
| 37 | const SG_ROW_CAP: i64 = 256 |
| 38 | const SG_DEFAULT_UTIL: i64 = 85 |
functions
| 40 | func sg_puts(s: *u8) -> i64 { sys_write(1, s, fa_len(s)); return 0 } |
| 42 | func sg_eq(a: *u8, b: *u8) -> i64 called by 1: main |
| 50 | func sg_path_ok(p: *u8) -> i64 |
| 72 | func sg_read(path: *u8, buf: *u8, cap: i64) -> i64 |
| 85 | func sg_has(buf: *u8, n: i64, needle: *u8) -> i64 |
| 99 | func sg_pint(buf: *u8, n: i64, p: i64, vout: *i64, pend: *i64) -> i64 |
| 121 | func sg_validate(row: *u8, n: i64, nso: *i64, nlo: *i64, totout: *i64, fout: *i64, tso: *i64) -> i64 |
| 161 | func sg_fresh(ts: i64, now: i64, window_sec: i64) -> i64 |
| 169 | func sg_snap_replace(snap: *u8, row: *u8, rowlen: i64, ns: i64, nl: i64) -> i64 |
| 224 | func sg_put(log: *u8, snap: *u8, row: *u8) -> i64 |
| 243 | func sg_show(snap: *u8, window_sec: i64) -> i64 |
| 282 | func sg_plan(snap: *u8, window_sec: i64, model_mb: i64, util_pct: i64) -> i64 |
| 385 | func sg_mkrow(dst: *u8, name: *u8, total: i64, free: i64, ts: i64) -> i64 |
| 396 | func sg_gate() -> i64 |
| 501 | func main(argc: i64, argv: *i64) -> i64 |