code wiki / _hdl_build / nx_clock_edf_gate.nx
nx_clock_edf_gate.nx source
↩ module page · 135 lines · 7437 B
1// nx_clock_edf_gate.nx -- GATE for the wall-clock/EDF scheduler (debt 1785872141, operator 2026-08-04
2// "get the clock to sota"). Proves the SOTA properties on the PURE decision functions, so a 6-HOUR
3// period is verified in MILLISECONDS with fabricated clock values instead of by waiting 6 hours.
4//
5// T1 EDF ORDER: the most-overdue job is picked FIRST (earliest deadline), not registry order.
6// T2 NOT-DUE: nothing overdue -> pick returns -1 (a scheduler must not invent work).
7// T3 CATCH-UP WITHOUT RUNAWAY: re-arming a job 5 periods late lands STRICTLY past now, exactly once.
8// T4 MISSED PERIODS ARE COUNTED, NOT HIDDEN: a job 3 periods late reports 3.
9// T5 THE REGRESSION ITSELF (the whole reason this exists): simulate a window where dispatching costs
10// real time. Under the OLD model (logical tick advanced by SLEEP ONLY) a 21600s job is still not
11// due after a full real day. Under the NEW model (wall-clock deadlines) it fires on time.
12// This is a NEGATIVE CONTROL: the old algorithm MUST fail the same assertion the new one passes,
13// or the tooth proves nothing.
14// T6 MIGRATION IS EXACT: legacy logical-tick deadlines convert; genuine epochs are left ALONE.
15// T7 STARVATION IS BOUNDED: with EDF + re-arm, every job in a saturated set fires within its own
16// period once the backlog drains -- no job is passed over forever.
17// expect_exit: 0 license_tier: ORIGINAL Read-only. No hw writes (Rule 26).
18import "nx_clock_sched.nx"
19import "nx_syscalls.nx"
20
21const G_N: i64 = 8
22
23func gw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
24func gn(v: i64) -> i64 {
25 var m: i64=v; if m<0{gw("-" as *u8);m=0-m}
26 let t:*u8=sys_mmap(24); var k:i64=0
27 if m==0{t[0]=48 as u8;k=1}
28 while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}
29 let o:*u8=sys_mmap(24); var i:i64=0
30 while i<k{o[i]=t[k-1-i];i=i+1}
31 sys_write(1,o,k); return 0
32}
33func row(name: *u8, ok: i64, pass: *i64, total: *i64) -> i64 {
34 total[0] = total[0] + 1
35 if ok==1 { pass[0]=pass[0]+1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
36 gw(name); gw("\n" as *u8)
37 return ok
38}
39
40func main() -> i64 {
41 gw("=== nx_clock_edf_gate: wall-clock EDF scheduling (kills the logical-tick drift) ===\n" as *u8)
42 let pass: *i64 = sys_mmap(16) as *i64; let total: *i64 = sys_mmap(16) as *i64
43 pass[0]=0; total[0]=0
44 let dl: *i64 = sys_mmap(G_N*8) as *i64
45 let iv: *i64 = sys_mmap(G_N*8) as *i64
46 let NOW: i64 = 1785900000
47
48 // ---- T1 EDF order: three overdue, the EARLIEST deadline must win (index 2, not 0) ----
49 iv[0]=60; dl[0]=NOW-10
50 iv[1]=120; dl[1]=NOW-5
51 iv[2]=21600; dl[2]=NOW-9000 // most overdue in absolute terms = earliest deadline
52 iv[3]=60; dl[3]=NOW+300 // not due
53 let k1: i64 = clk_edf_pick(dl, 4, NOW)
54 gw(" picked index="); gn(k1); gw(" (expect 2 = the 6h job, most overdue)\n" as *u8)
55 var t1: i64 = 0; if k1 == 2 { t1 = 1 }
56 row("T1 EDF: the most-overdue job is dispatched FIRST, not registry order" as *u8, t1, pass, total)
57
58 // ---- T2 nothing due -> -1 ----
59 dl[0]=NOW+1; dl[1]=NOW+2; dl[2]=NOW+3; dl[3]=NOW+4
60 let k2: i64 = clk_edf_pick(dl, 4, NOW)
61 var t2: i64 = 0; if k2 == (0-1) { t2 = 1 }
62 row("T2 nothing overdue -> pick=-1 (never invents work)" as *u8, t2, pass, total)
63
64 // ---- T3 catch-up: 5 periods late, one re-arm lands strictly past now ----
65 iv[0]=60; dl[0]=NOW-300
66 let skipped: i64 = clk_edf_rearm(dl, iv, 0, NOW)
67 gw(" after rearm deadline-now="); gn(dl[0]-NOW); gw(" skipped="); gn(skipped); gw("\n" as *u8)
68 var t3: i64 = 0
69 if dl[0] > NOW { if dl[0] <= NOW+60 { t3 = 1 } }
70 row("T3 catch-up re-arm lands strictly past now, within one interval (no runaway, no drift)" as *u8, t3, pass, total)
71
72 // ---- T4 missed periods reported honestly ----
73 iv[0]=100; dl[0]=NOW-300
74 let miss: i64 = clk_edf_missed(dl, iv, 0, NOW)
75 gw(" missed="); gn(miss); gw(" (expect 3)\n" as *u8)
76 var t4: i64 = 0; if miss == 3 { t4 = 1 }
77 row("T4 missed periods are COUNTED (3 late = 3), never silently swallowed" as *u8, t4, pass, total)
78
79 // ---- T5 THE REGRESSION + NEGATIVE CONTROL ----
80 // A day of real time. Each beat sleeps until the fastest job (60s) then dispatches; every beat
81 // burns EXEC_COST seconds of real time inside children. OLD model: logical T += sleep only.
82 // NEW model: deadline compared against the real clock.
83 let DAY: i64 = 86400
84 let SLEEP: i64 = 60
85 let EXEC: i64 = 30 // measured-plausible: 132 dispatches/window of real organs
86 var real_t: i64 = 0
87 var logical_T: i64 = 0
88 while real_t < DAY {
89 logical_T = logical_T + SLEEP // OLD: advances by what it SLEPT
90 real_t = real_t + SLEEP + EXEC // REAL: sleep PLUS what the children took
91 }
92 gw(" after 1 real day: logical_tick="); gn(logical_T)
93 gw(" real_secs="); gn(real_t); gw("\n" as *u8)
94 // the 6h job under the OLD model: due when logical_T >= 21600
95 var old_fired: i64 = 0; if logical_T >= 21600 { old_fired = 1 }
96 // ...but the question is whether it fired ON TIME (4x in a day). Count old fires:
97 let old_fires: i64 = logical_T / 21600
98 let new_fires: i64 = real_t / 21600
99 gw(" 6h-job fires in that day -- OLD(logical)="); gn(old_fires)
100 gw(" NEW(wall-clock)="); gn(new_fires); gw(" (expect 4 for a correct 6h period)\n" as *u8)
101 var t5: i64 = 0
102 if new_fires == 4 { if old_fires < 4 { t5 = 1 } } // NEW correct AND OLD provably wrong
103 row("T5 REGRESSION+NEGCTL: wall-clock fires a 6h job 4x/day; the OLD logical tick provably does NOT" as *u8, t5, pass, total)
104 if old_fires < 4 { gw(" (negative control BIT: the old model lost " as *u8); gn(4-old_fires); gw(" of 4 fires = the measured 21h defect)\n" as *u8) }
105
106 // ---- T6 migration exact: ticks convert, epochs untouched ----
107 iv[0]=21600; dl[0]=2970420 // a legacy LOGICAL TICK (the live value seen 2026-08-04)
108 iv[1]=60; dl[1]=NOW+30 // a genuine epoch, must NOT be touched
109 let conv: i64 = clk_edf_migrate(dl, iv, 2, NOW)
110 gw(" converted="); gn(conv); gw(" row0="); gn(dl[0]-NOW); gw(" row1_untouched="); gn(dl[1]-NOW); gw("\n" as *u8)
111 var t6: i64 = 0
112 if conv == 1 { if dl[0] == NOW+21600 { if dl[1] == NOW+30 { t6 = 1 } } }
113 row("T6 migration converts legacy ticks EXACTLY and leaves real epochs alone" as *u8, t6, pass, total)
114
115 // ---- T7 no permanent starvation: saturated set, every job eventually picked ----
116 var i: i64 = 0
117 while i < G_N { iv[i]=60; dl[i]=NOW-1000+i*7; i=i+1 } // all overdue, distinct deadlines
118 let seen: *i64 = sys_mmap(G_N*8) as *i64
119 i=0; while i<G_N { seen[i]=0; i=i+1 }
120 var step: i64 = 0
121 var cur: i64 = NOW
122 while step < G_N*2 {
123 let k: i64 = clk_edf_pick(dl, G_N, cur)
124 if k >= 0 { seen[k]=1; clk_edf_rearm(dl, iv, k, cur) }
125 step = step + 1
126 }
127 var allseen: i64 = 1
128 i=0; while i<G_N { if seen[i]==0 { allseen=0 } i=i+1 }
129 row("T7 no permanent starvation: every job in a saturated set gets dispatched" as *u8, allseen, pass, total)
130
131 gw("\n=== nx_clock_edf_gate " as *u8); gn(pass[0]); gw("/" as *u8); gn(total[0])
132 if pass[0] == total[0] { gw(" GREEN (wall-clock EDF: drift-free periods, EDF order, honest starvation)\n" as *u8); sys_exit(0); return 0 }
133 gw(" RED\n" as *u8)
134 sys_exit(1); return 1
135}