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}