code wiki / (root) / nx_swarm_pack.nx

nx_swarm_pack.nx source

↩ module page · 451 lines · 21863 B

1// nx_swarm_pack.nx -- SWARM FABRIC heterogeneous MAX-UTILIZATION scheduler (SF-R-PACK): get the MOST out 2// of EVERY participant by exploiting ALL of its resources at once -- RAM, CPU cores, GPU, VRAM -- not routing 3// a job to one class (operator 2026-07-15: "gpu was just an example ... use the ram cpu gpu whatever is 4// available to get the most out of what participates in the supercomputer", the NIST/heterogeneous-compute 5// model). A single participant can host MANY demands using DIFFERENT resources concurrently; work spreads to 6// fill every participant's spare capacity. 7// 8// RESOURCE VECTOR (aligned to the beacon telemetry = the FEED): per participant 9// pcpu = spare CPU milli-cores (beacon: (1000-lpc)*ncpu) · pram = free RAM MB (beacon mem_avail_mb) 10// pgpu = GPU present 0/1 · pvram = free VRAM MB (the axis to wire from a GPU collector) 11// DEMAND VECTOR: per chunk dcpu (milli-cores) · dram (MB) · dgpu (needs GPU 0/1) · dvram (MB) 12// 13// COMPOSES (check-before-build 2026-07-15): nx_resource_arbiter ALREADY models VRAM/RAM/CPU/GPU/net/disk as 14// first-class allocatable kinds with fairness+preempt -- but is "fed by nothing". This packer IS that feed + 15// the placement loop; the fairness/preempt/treaty LAYER wires to nx_resource_arbiter (nx_ra_request/grant) 16// as the allocation policy SSOT. Hard-constraint classify = nx_swarm_coord. Telemetry = nx_node_beacon. 17// 18// ★★THE LIAR-KILLERS (the operator's principle, mechanized): (1) NO participant is ever over-allocated on ANY 19// resource (sum assigned <= supply, per axis). (2) a demand is NEVER placed on a participant that lacks its 20// REQUIRED resource -- a needs-GPU chunk never lands on a GPU-less node (GPU generalized to "whatever it 21// requires"). (3) packing beats naive round-robin on placed-count (measured). (4) HETEROGENEOUS EXPLOITATION 22// proven: one participant hosts DIFFERENT resource-type demands at once; no participant sits idle while a 23// demand it could serve is queued. 24// 25// pack <poolfile> <jobsfile> -- pool line "name cpu_milli ram_mb gpu vram_mb"; job line "id cpu ram gpu vram" 26// [gate] -- self-gate: the heterogeneous scenario + all four liar-killers 27// license_tier: ORIGINAL expect_exit:0 28import "nx_swarm_lib.nx" 29const SK_MAGIC_8000: i64 = 8000 30const SK_MAGIC_16000: i64 = 16000 31const SK_MAGIC_12000: i64 = 12000 32const SK_MAGIC_3000: i64 = 3000 33const SK_MAGIC_32000: i64 = 32000 34const SK_MAGIC_4000: i64 = 4000 35const SK_MAGIC_5000: i64 = 5000 36const SK_MAGIC_20000: i64 = 20000 37const SK_MAGIC_2000: i64 = 2000 38const SK_MAGIC_65536: i64 = 65536 39const SK_MAGIC_8192: i64 = 8192 40const SK_MAGIC_1000000: i64 = 1000000 41 42const SK_MAXP: i64 = 256 43const SK_MAXD: i64 = 4096 44 45func sk_puts(s: *u8) -> i64 { sys_write(1, s, fa_len(s)); return 0 } 46 47// best-fit assign of demand j onto the participants; decrements the winner's vector. returns participant idx or -1. 48// FIT = supplies ALL of the demand's resources (hard constraint per axis). BEST = tightest CPU slack among fitting 49// (packs tightly, leaving big/flexible participants free for constrained demands) -- a participant with the 50// resource the demand needs is preferred to leave headroom elsewhere. 51func sk_place_one(pcpu: *i64, pram: *i64, pgpu: *i64, pvram: *i64, n: i64, dcpu: i64, dram: i64, dgpu: i64, dvram: i64) -> i64 { 52 var best: i64 = 0 - 1 53 var best_slack: i64 = 0 54 var i: i64 = 0 55 while i < n { 56 var fits: i64 = 1 57 if pcpu[i] < dcpu { fits = 0 } 58 if pram[i] < dram { fits = 0 } 59 if dgpu == 1 { if pgpu[i] == 0 { fits = 0 } } // ★ needs-GPU never fits a GPU-less node 60 if pvram[i] < dvram { fits = 0 } 61 if fits == 1 { 62 let slack: i64 = (pcpu[i] - dcpu) + (pram[i] - dram) // tightest combined slack = best fit 63 if best < 0 { best = i; best_slack = slack } else { if slack < best_slack { best = i; best_slack = slack } } 64 } 65 i = i + 1 66 } 67 if best >= 0 { 68 pcpu[best] = pcpu[best] - dcpu 69 pram[best] = pram[best] - dram 70 pvram[best] = pvram[best] - dvram 71 // GPU is a boolean CAPABILITY here (shareable across demands via time-slice); vram is the metered axis 72 } 73 return best 74} 75 76// pack all m demands onto n participants. Fills assign[j] = participant idx or -1 (queued). 77// Processes GPU-demands FIRST (scarcest hard constraint), then by descending RAM (big chunks first) -- 78// best-fit-decreasing, the standard bin-packing heuristic for high utilization. 79func sk_pack(pcpu: *i64, pram: *i64, pgpu: *i64, pvram: *i64, n: i64, 80 dcpu: *i64, dram: *i64, dgpu: *i64, dvram: *i64, m: i64, assign: *i64) -> i64 { 81 var j: i64 = 0 82 while j < m { assign[j] = 0 - 1; j = j + 1 } 83 var placed: i64 = 0 84 // pass 1: GPU demands (hard-constrained -> place while GPU capacity exists) 85 j = 0 86 while j < m { 87 if dgpu[j] == 1 { 88 let w: i64 = sk_place_one(pcpu, pram, pgpu, pvram, n, dcpu[j], dram[j], 1, dvram[j]) 89 if w >= 0 { assign[j] = w; placed = placed + 1 } 90 } 91 j = j + 1 92 } 93 // pass 2: non-GPU demands, biggest-RAM first (approximate BFD; a full sort is overkill for the demo) 94 var done: i64 = 0 95 while done == 0 { 96 var pick: i64 = 0 - 1 97 var pickram: i64 = 0 - 1 98 j = 0 99 while j < m { 100 if dgpu[j] == 0 { if assign[j] < 0 { 101 if dram[j] > pickram { pick = j; pickram = dram[j] } 102 } } 103 j = j + 1 104 } 105 if pick < 0 { done = 1 } else { 106 let w: i64 = sk_place_one(pcpu, pram, pgpu, pvram, n, dcpu[pick], dram[pick], 0, dvram[pick]) 107 if w >= 0 { assign[pick] = w; placed = placed + 1; } else { assign[pick] = 0 - 2 } // -2 = tried, unplaceable 108 } 109 } 110 // normalize -2 back to -1 (queued) 111 j = 0 112 while j < m { if assign[j] == (0 - 2) { assign[j] = 0 - 1 } j = j + 1 } 113 return placed 114} 115 116// naive ROUND-ROBIN comparator: assign demand j to participant (j % n) iff it happens to fit; else queue. 117// (models the "spread evenly, ignore the resource vector" scheduler -- the anti-pattern.) returns placed count. 118func sk_naive(pcpu: *i64, pram: *i64, pgpu: *i64, pvram: *i64, n: i64, 119 dcpu: *i64, dram: *i64, dgpu: *i64, dvram: *i64, m: i64) -> i64 { 120 let c2: *i64 = sys_mmap(8 * n + 16) as *i64 121 let r2: *i64 = sys_mmap(8 * n + 16) as *i64 122 let v2: *i64 = sys_mmap(8 * n + 16) as *i64 123 var i: i64 = 0 124 while i < n { c2[i] = pcpu[i]; r2[i] = pram[i]; v2[i] = pvram[i]; i = i + 1 } 125 var placed: i64 = 0 126 var j: i64 = 0 127 while j < m { 128 let t: i64 = j - (j / n) * n // j % n 129 var fits: i64 = 1 130 if c2[t] < dcpu[j] { fits = 0 } 131 if r2[t] < dram[j] { fits = 0 } 132 if dgpu[j] == 1 { if pgpu[t] == 0 { fits = 0 } } 133 if v2[t] < dvram[j] { fits = 0 } 134 if fits == 1 { c2[t] = c2[t] - dcpu[j]; r2[t] = r2[t] - dram[j]; v2[t] = v2[t] - dvram[j]; placed = placed + 1 } 135 j = j + 1 136 } 137 return placed 138} 139 140func sk_report(names: *i64, pcpu0: *i64, pram0: *i64, pgpu: *i64, pcpu: *i64, pram: *i64, n: i64, 141 dcpu: *i64, dram: *i64, dgpu: *i64, m: i64, assign: *i64) -> i64 { 142 let t: *u8 = sys_mmap(512) 143 var i: i64 = 0 144 while i < n { 145 var o: i64 = 0 146 o = fa_cat(t, o, " participant " as *u8); o = fa_cat(t, o, names[i] as *u8) 147 o = fa_cat(t, o, ": cpu " as *u8); o = fa_catn(t, o, pcpu0[i] - pcpu[i]); o = fa_cat(t, o, "/" as *u8); o = fa_catn(t, o, pcpu0[i]) 148 o = fa_cat(t, o, " mc, ram " as *u8); o = fa_catn(t, o, pram0[i] - pram[i]); o = fa_cat(t, o, "/" as *u8); o = fa_catn(t, o, pram0[i]) 149 o = fa_cat(t, o, " mb, gpu=" as *u8); o = fa_catn(t, o, pgpu[i]) 150 o = fa_cat(t, o, " hosts:" as *u8) 151 var j: i64 = 0 152 var cnt: i64 = 0 153 while j < m { 154 if assign[j] == i { 155 o = fa_cat(t, o, " d" as *u8); o = fa_catn(t, o, j) 156 if dgpu[j] == 1 { o = fa_cat(t, o, "[gpu]" as *u8) } else { if dram[j] >= SK_MAGIC_8000 { o = fa_cat(t, o, "[ram]" as *u8) } else { o = fa_cat(t, o, "[cpu]" as *u8) } } 157 cnt = cnt + 1 158 } 159 j = j + 1 160 } 161 if cnt == 0 { o = fa_cat(t, o, " (idle)" as *u8) } 162 o = fa_cat(t, o, "\n" as *u8) 163 sys_write(1, t, o) 164 i = i + 1 165 } 166 return 0 167} 168 169// count distinct resource-TYPE tags a participant hosts (cpu/ram/gpu) -> heterogeneity proof. 170func sk_types_on(part: i64, dram: *i64, dgpu: *i64, m: i64, assign: *i64) -> i64 { 171 var has_cpu: i64 = 0 172 var has_ram: i64 = 0 173 var has_gpu: i64 = 0 174 var j: i64 = 0 175 while j < m { 176 if assign[j] == part { 177 if dgpu[j] == 1 { has_gpu = 1 } else { if dram[j] >= SK_MAGIC_8000 { has_ram = 1 } else { has_cpu = 1 } } 178 } 179 j = j + 1 180 } 181 return has_cpu + has_ram + has_gpu 182} 183 184func sk_gate() -> i64 { 185 var pass: i64 = 0 186 var total: i64 = 0 187 let n: i64 = 3 188 let names: *i64 = sys_mmap(64) as *i64 189 names[0] = "laptop" as i64 190 names[1] = "nas" as i64 191 names[2] = "pi" as i64 192 // supply vectors (spare cpu milli-cores, free ram mb, gpu, free vram mb) 193 let pcpu0: *i64 = sys_mmap(64) as *i64 194 let pram0: *i64 = sys_mmap(64) as *i64 195 let pgpu: *i64 = sys_mmap(64) as *i64 196 let pvram0: *i64 = sys_mmap(64) as *i64 197 pcpu0[0] = SK_MAGIC_8000; pram0[0] = SK_MAGIC_16000; pgpu[0] = 1; pvram0[0] = SK_MAGIC_12000 // laptop: 8 cores, 16GB, RTX GPU 12GB 198 pcpu0[1] = SK_MAGIC_3000; pram0[1] = SK_MAGIC_32000; pgpu[1] = 0; pvram0[1] = 0 // nas: 3 cores, 32GB, no GPU 199 pcpu0[2] = SK_MAGIC_4000; pram0[2] = SK_MAGIC_4000; pgpu[2] = 0; pvram0[2] = 0 // pi: 4 cores, 4GB, no GPU 200 // working copies (decremented) 201 let pcpu: *i64 = sys_mmap(64) as *i64 202 let pram: *i64 = sys_mmap(64) as *i64 203 let pvram: *i64 = sys_mmap(64) as *i64 204 var i: i64 = 0 205 while i < n { pcpu[i] = pcpu0[i]; pram[i] = pram0[i]; pvram[i] = pvram0[i]; i = i + 1 } 206 // demands: 2 GPU gen, 1 big-RAM index, 4 CPU tiles 207 let m: i64 = 7 208 let dcpu: *i64 = sys_mmap(128) as *i64 209 let dram: *i64 = sys_mmap(128) as *i64 210 let dgpu: *i64 = sys_mmap(128) as *i64 211 let dvram: *i64 = sys_mmap(128) as *i64 212 dcpu[0]=500; dram[0]=1000; dgpu[0]=1; dvram[0]=SK_MAGIC_5000 // gen A (GPU) 213 dcpu[1]=500; dram[1]=1000; dgpu[1]=1; dvram[1]=SK_MAGIC_5000 // gen B (GPU) 214 dcpu[2]=1000; dram[2]=SK_MAGIC_20000; dgpu[2]=0; dvram[2]=0 // ram-index (big RAM -> only nas fits) 215 dcpu[3]=SK_MAGIC_2000; dram[3]=500; dgpu[3]=0; dvram[3]=0 // cpu tile 216 dcpu[4]=SK_MAGIC_2000; dram[4]=500; dgpu[4]=0; dvram[4]=0 // cpu tile 217 dcpu[5]=SK_MAGIC_2000; dram[5]=500; dgpu[5]=0; dvram[5]=0 // cpu tile 218 dcpu[6]=SK_MAGIC_2000; dram[6]=500; dgpu[6]=0; dvram[6]=0 // cpu tile 219 let assign: *i64 = sys_mmap(128) as *i64 220 let placed: i64 = sk_pack(pcpu, pram, pgpu, pvram, n, dcpu, dram, dgpu, dvram, m, assign) 221 222 sk_puts("--- heterogeneous pack (2 GPU gen, 1 RAM index, 4 CPU tiles over laptop/nas/pi) ---\n" as *u8) 223 sk_report(names, pcpu0, pram0, pgpu, pcpu, pram, n, dcpu, dram, dgpu, m, assign) 224 225 // T1 supply never exceeded (no participant over-allocated on any axis) 226 total = total + 1 227 var okcap: i64 = 1 228 i = 0 229 while i < n { if pcpu[i] < 0 { okcap = 0 } if pram[i] < 0 { okcap = 0 } if pvram[i] < 0 { okcap = 0 } i = i + 1 } 230 if okcap == 1 { pass = pass + 1; sk_puts("T1 no-overallocation OK\n" as *u8) } 231 232 // T2 ★ never-ignore-required-resource: every GPU demand landed on a gpu=1 participant (or queued), NEVER gpu=0 233 total = total + 1 234 var okgpu: i64 = 1 235 var j: i64 = 0 236 while j < m { if dgpu[j] == 1 { if assign[j] >= 0 { if pgpu[assign[j]] == 0 { okgpu = 0 } } } j = j + 1 } 237 if okgpu == 1 { pass = pass + 1; sk_puts("T2 gpu-demand-never-on-cpu-node OK\n" as *u8) } 238 239 // T3 the big-RAM index landed on nas (the only 32GB participant), never pi/laptop 240 total = total + 1 241 if assign[2] == 1 { pass = pass + 1; sk_puts("T3 ram-index->big-ram-node OK\n" as *u8) } 242 243 // T4 ★★HETEROGENEOUS EXPLOITATION: the laptop hosts >1 resource TYPE at once (GPU gen AND a CPU tile) 244 total = total + 1 245 if sk_types_on(0, dram, dgpu, m, assign) >= 2 { pass = pass + 1; sk_puts("T4 one-node-multi-resource-type OK\n" as *u8) } 246 247 // T5 NO idle participant while placeable demands exist (every participant does SOME work here) 248 total = total + 1 249 var idle: i64 = 0 250 i = 0 251 while i < n { 252 var hosts: i64 = 0 253 j = 0 254 while j < m { if assign[j] == i { hosts = 1 } j = j + 1 } 255 if hosts == 0 { idle = idle + 1 } 256 i = i + 1 257 } 258 if idle == 0 { pass = pass + 1; sk_puts("T5 every-participant-utilized OK\n" as *u8) } 259 260 // T6 MAX-UTILIZATION beats naive round-robin on placed-count (vector-aware > blind spread) 261 total = total + 1 262 // reset copies for naive 263 i = 0 264 while i < n { pcpu[i] = pcpu0[i]; pram[i] = pram0[i]; pvram[i] = pvram0[i]; i = i + 1 } 265 let naive: i64 = sk_naive(pcpu0, pram0, pgpu, pvram0, n, dcpu, dram, dgpu, dvram, m) 266 sk_puts(" packed=" as *u8); let tb: *u8 = sys_mmap(64); var to: i64 = fa_catn(tb, 0, placed); tb[to]=32 as u8; to=to+1; to=fa_cat(tb,to,"naive=" as *u8); to=fa_catn(tb,to,naive); tb[to]=10 as u8; sys_write(1,tb,to+1) 267 if placed >= naive { if placed >= 6 { pass = pass + 1; sk_puts("T6 max-utilization>=naive OK\n" as *u8) } } 268 269 // T7 queue-honest: any unplaced demand is assign=-1 (never misplaced) -- and here all 7 fit 270 total = total + 1 271 var okq: i64 = 1 272 j = 0 273 while j < m { if assign[j] < (0 - 1) { okq = 0 } j = j + 1 } 274 if okq == 1 { pass = pass + 1; sk_puts("T7 queue-honest OK\n" as *u8) } 275 276 // T8 DETERMINISM: repack -> identical placed count + assignment 277 total = total + 1 278 i = 0 279 while i < n { pcpu[i] = pcpu0[i]; pram[i] = pram0[i]; pvram[i] = pvram0[i]; i = i + 1 } 280 let assign2: *i64 = sys_mmap(128) as *i64 281 let placed2: i64 = sk_pack(pcpu, pram, pgpu, pvram, n, dcpu, dram, dgpu, dvram, m, assign2) 282 var okdet: i64 = 1 283 if placed2 != placed { okdet = 0 } 284 j = 0 285 while j < m { if assign2[j] != assign[j] { okdet = 0 } j = j + 1 } 286 if okdet == 1 { pass = pass + 1; sk_puts("T8 deterministic OK\n" as *u8) } 287 288 let t: *u8 = sys_mmap(128) 289 var to2: i64 = 0 290 to2 = fa_cat(t, to2, "SWARMPACKGATE " as *u8) 291 to2 = fa_catn(t, to2, pass) 292 to2 = fa_cat(t, to2, "/" as *u8) 293 to2 = fa_catn(t, to2, total) 294 if pass == total { to2 = fa_cat(t, to2, " verdict=GREEN\n" as *u8) } else { to2 = fa_cat(t, to2, " verdict=RED\n" as *u8) } 295 sys_write(1, t, to2) 296 if pass == total { return 0 } 297 return 1 298} 299 300// ---- LIVE pack: consume the beat-store snapshot (real beacon telemetry) + a jobs file ---- 301func sk_skipsp(buf: *u8, n: i64, p: i64) -> i64 { 302 var i: i64 = p 303 var go: i64 = 1 304 while go == 1 { if i >= n { go = 0 } else { if (buf[i] as i64) == 32 { i = i + 1 } else { go = 0 } } } 305 return i 306} 307 308// is name[0..nl) a comma-field of the roster csv? 309func sk_roster_has(roster: *u8, name: *u8, nl: i64) -> i64 { 310 let rl: i64 = fa_len(roster) 311 if rl == 0 { return 0 } 312 var p: i64 = 0 313 while p < rl { 314 var q: i64 = p 315 var fend: i64 = rl 316 var scan: i64 = 1 317 while scan == 1 { if q >= rl { scan = 0 } else { if (roster[q] as i64) == 44 { fend = q; scan = 0 } else { q = q + 1 } } } 318 if fend - p == nl { 319 var k: i64 = 0 320 var same: i64 = 1 321 while k < nl { if roster[p+k] != name[k] { same = 0; k = nl } else { k = k + 1 } } 322 if same == 1 { return 1 } 323 } 324 p = fend + 1 325 } 326 return 0 327} 328 329// load participant vectors from a beat-store snapshot. names[i]=ptr; vector from live beacon fields. 330// pcpu = spare milli-cores = (1000-lpc)*ncpu ; pram = mem_avail_mb ; pgpu = name in roster ; pvram = 0 (wire). 331func sk_load_pool(snap: *u8, roster: *u8, names: *i64, pcpu: *i64, pram: *i64, pgpu: *i64, pvram: *i64, maxn: i64) -> i64 { 332 let buf: *u8 = sys_mmap(SK_MAGIC_65536) 333 let n: i64 = sb_read(snap, buf, SK_MAGIC_65536) 334 let namebuf: *u8 = sys_mmap(SK_MAGIC_8192) 335 var noff: i64 = 0 336 let f: *i64 = sys_mmap(128) as *i64 337 let nso: *i64 = sys_mmap(16) as *i64 338 let nlo: *i64 = sys_mmap(16) as *i64 339 let tso: *i64 = sys_mmap(16) as *i64 340 var cnt: i64 = 0 341 var i: i64 = 0 342 while i < n { 343 var e: i64 = i 344 var g: i64 = 1 345 while g == 1 { if e >= n { g = 0 } else { if (buf[e] as i64) == 10 { g = 0 } else { e = e + 1 } } } 346 if e > i { if cnt < maxn { 347 let line: *u8 = (buf as i64 + i) as *u8 348 let ln: i64 = e - i 349 if sb_fields(line, ln, f) == 1 { 350 sb_validate(line, ln, nso, nlo, tso) 351 let ns: i64 = nso[0] 352 let nl: i64 = nlo[0] 353 let np: i64 = noff 354 var k: i64 = 0 355 while k < nl { namebuf[noff] = line[ns+k]; noff = noff + 1; k = k + 1 } 356 namebuf[noff] = 0 as u8; noff = noff + 1 357 names[cnt] = namebuf as i64 + np 358 var spare: i64 = (1000 - f[3]) * f[2] 359 if spare < 0 { spare = 0 } 360 pcpu[cnt] = spare 361 pram[cnt] = f[5] 362 pgpu[cnt] = sk_roster_has(roster, (namebuf as i64 + np) as *u8, nl) 363 // VRAM not in the beacon yet (beacon-v3 wire): a GPU node advertises VRAM present-but- 364 // UNMETERED (large sentinel) so GPU demands fit; a non-GPU node stays 0 so they never do. 365 if pgpu[cnt] == 1 { pvram[cnt] = SK_MAGIC_1000000 } else { pvram[cnt] = 0 } 366 cnt = cnt + 1 367 } 368 } } 369 i = e + 1 370 } 371 return cnt 372} 373 374// load job demands: each line "cpu_milli ram_mb needs_gpu vram_mb" ('#' comment/blank skipped). returns m. 375func sk_load_jobs(jobs: *u8, dcpu: *i64, dram: *i64, dgpu: *i64, dvram: *i64, maxm: i64) -> i64 { 376 let buf: *u8 = sys_mmap(SK_MAGIC_65536) 377 let n: i64 = sb_read(jobs, buf, SK_MAGIC_65536) 378 let vout: *i64 = sys_mmap(16) as *i64 379 let pend: *i64 = sys_mmap(16) as *i64 380 var cnt: i64 = 0 381 var i: i64 = 0 382 while i < n { 383 var e: i64 = i 384 var g: i64 = 1 385 while g == 1 { if e >= n { g = 0 } else { if (buf[e] as i64) == 10 { g = 0 } else { e = e + 1 } } } 386 if e > i { if (buf[i] as i64) != 35 { if cnt < maxm { 387 var p: i64 = sk_skipsp(buf, e, i) 388 var vals: i64 = 0 389 if sb_pint(buf, e, p, vout, pend) == 1 { dcpu[cnt] = vout[0]; p = sk_skipsp(buf, e, pend[0]); vals = vals + 1 } 390 if sb_pint(buf, e, p, vout, pend) == 1 { dram[cnt] = vout[0]; p = sk_skipsp(buf, e, pend[0]); vals = vals + 1 } 391 if sb_pint(buf, e, p, vout, pend) == 1 { dgpu[cnt] = vout[0]; p = sk_skipsp(buf, e, pend[0]); vals = vals + 1 } 392 if sb_pint(buf, e, p, vout, pend) == 1 { dvram[cnt] = vout[0]; vals = vals + 1 } 393 if vals == 4 { cnt = cnt + 1 } 394 } } } 395 i = e + 1 396 } 397 return cnt 398} 399 400func sk_live(snap: *u8, jobs: *u8, roster: *u8) -> i64 { 401 let names: *i64 = sys_mmap(8 * SK_MAXP) as *i64 402 let pcpu0: *i64 = sys_mmap(8 * SK_MAXP) as *i64 403 let pram0: *i64 = sys_mmap(8 * SK_MAXP) as *i64 404 let pgpu: *i64 = sys_mmap(8 * SK_MAXP) as *i64 405 let pvram0: *i64 = sys_mmap(8 * SK_MAXP) as *i64 406 let n: i64 = sk_load_pool(snap, roster, names, pcpu0, pram0, pgpu, pvram0, SK_MAXP) 407 if n < 1 { sk_puts("SWARMPACK live: no participants in snapshot\n" as *u8); return 3 } 408 let dcpu: *i64 = sys_mmap(8 * SK_MAXD) as *i64 409 let dram: *i64 = sys_mmap(8 * SK_MAXD) as *i64 410 let dgpu: *i64 = sys_mmap(8 * SK_MAXD) as *i64 411 let dvram: *i64 = sys_mmap(8 * SK_MAXD) as *i64 412 let m: i64 = sk_load_jobs(jobs, dcpu, dram, dgpu, dvram, SK_MAXD) 413 if m < 1 { sk_puts("SWARMPACK live: no job demands\n" as *u8); return 3 } 414 let pcpu: *i64 = sys_mmap(8 * SK_MAXP) as *i64 415 let pram: *i64 = sys_mmap(8 * SK_MAXP) as *i64 416 let pvram: *i64 = sys_mmap(8 * SK_MAXP) as *i64 417 var i: i64 = 0 418 while i < n { pcpu[i] = pcpu0[i]; pram[i] = pram0[i]; pvram[i] = pvram0[i]; i = i + 1 } 419 let assign: *i64 = sys_mmap(8 * SK_MAXD) as *i64 420 let placed: i64 = sk_pack(pcpu, pram, pgpu, pvram, n, dcpu, dram, dgpu, dvram, m, assign) 421 sk_puts("--- LIVE heterogeneous pack over the fleet snapshot ---\n" as *u8) 422 sk_report(names, pcpu0, pram0, pgpu, pcpu, pram, n, dcpu, dram, dgpu, m, assign) 423 let t: *u8 = sys_mmap(128) 424 var o: i64 = fa_cat(t, 0, "SWARMPACK live placed=" as *u8) 425 o = fa_catn(t, o, placed); o = fa_cat(t, o, "/" as *u8); o = fa_catn(t, o, m) 426 o = fa_cat(t, o, " participants=" as *u8); o = fa_catn(t, o, n); o = fa_cat(t, o, "\n" as *u8) 427 sys_write(1, t, o) 428 // liar-killer even on live data: no GPU demand on a GPU-less participant 429 var okgpu: i64 = 1 430 var j: i64 = 0 431 while j < m { if dgpu[j] == 1 { if assign[j] >= 0 { if pgpu[assign[j]] == 0 { okgpu = 0 } } } j = j + 1 } 432 if okgpu == 0 { sk_puts("SWARMPACK LIVE VIOLATION: gpu demand on gpu-less node\n" as *u8); return 1 } 433 if placed == m { return 0 } 434 return 3 435} 436 437func main(argc: i64, argv: *i64) -> i64 { 438 if argc >= 2 { 439 let verb: *u8 = argv[1] as *u8 440 var isp: i64 = 1 441 if verb[0] != (112 as u8) { isp = 0 } // 'p' 442 if isp == 1 { 443 if argc < 4 { sk_puts("usage: nx_swarm_pack pack <snap> <jobs> [gpu_roster_csv]\n" as *u8); return 2 } 444 if sb_path_ok(argv[2] as *u8) == 0 { sk_puts("SWARMPACK REFUSED (snap path law)\n" as *u8); return 3 } 445 var roster: *u8 = "" as *u8 446 if argc >= 5 { roster = argv[4] as *u8 } 447 return sk_live(argv[2] as *u8, argv[3] as *u8, roster) 448 } 449 } 450 return sk_gate() 451}