nx_actor_test.nx source
↩ module page · 176 lines · 7910 B
1// nx_actor_test.nx -- smoke for nx_actor.
2
3import "nx_syscalls.nx"
4import "nx_actor.nx"
5
6func main() -> i64 {
7 let now: nx_size = 1000000
8
9 // 1: enum validity
10 if nx_ac_state_is_valid(NX_AC_STATE_READY) != 1 { return 1 }
11 if nx_ac_state_is_valid(NX_AC_STATE_PAUSED) != 1 { return 2 }
12 if nx_ac_state_is_valid(-1) != 0 { return 3 }
13 if nx_ac_state_is_valid(6) != 0 { return 4 }
14 if NX_AC_STATE_N != 6 { return 5 }
15
16 if nx_ac_wait_is_valid(NX_AC_WAIT_NONE) != 1 { return 6 }
17 if nx_ac_wait_is_valid(NX_AC_WAIT_OPERATOR) != 1 { return 7 }
18 if nx_ac_wait_is_valid(-1) != 0 { return 8 }
19 if nx_ac_wait_is_valid(6) != 0 { return 9 }
20
21 if nx_ac_v_is_valid(NX_AC_V_STEPPED) != 1 { return 10 }
22 if nx_ac_v_is_valid(NX_AC_V_FAILED) != 1 { return 11 }
23
24 // 2: runnable + terminal predicates
25 if nx_ac_state_is_runnable(NX_AC_STATE_READY) != 1 { return 12 }
26 if nx_ac_state_is_runnable(NX_AC_STATE_RUNNING) != 1 { return 13 }
27 if nx_ac_state_is_runnable(NX_AC_STATE_WAITING) != 0 { return 14 }
28 if nx_ac_state_is_runnable(NX_AC_STATE_COMPLETED) != 0 { return 15 }
29
30 if nx_ac_state_is_terminal(NX_AC_STATE_COMPLETED) != 1 { return 16 }
31 if nx_ac_state_is_terminal(NX_AC_STATE_FAILED) != 1 { return 17 }
32 if nx_ac_state_is_terminal(NX_AC_STATE_READY) != 0 { return 18 }
33
34 // 3: scheduler construction
35 let s: *NxActorScheduler = nx_ac_sched_new(16, 1000000, 4, now)
36 if s.capacity != 16 { return 19 }
37 if s.n_actors != 0 { return 20 }
38 if s.quantum_per_actor != 4 { return 21 }
39
40 if nx_ac_sched_new(0, 1000000, 4, now) != (0 as *NxActorScheduler) { return 22 }
41 if nx_ac_sched_new(16, 1000000, 0, now) != (0 as *NxActorScheduler) { return 23 }
42
43 // 4: spawn actors
44 if nx_ac_spawn(s, 1001, 1, 90, 0, now) != NX_AC_V_STEPPED { return 24 } // LLM
45 if nx_ac_spawn(s, 1002, 2, 50, 0, now) != NX_AC_V_STEPPED { return 25 } // IMAGE
46 if nx_ac_spawn(s, 1003, 3, 30, 0, now) != NX_AC_V_STEPPED { return 26 } // VIDEO
47 if nx_ac_actor_count(s) != 3 { return 27 }
48
49 if nx_ac_spawn(s, 0, 1, 50, 0, now) != NX_AC_V_INVALID { return 28 }
50
51 // 5: find
52 let a1: *NxActor = nx_ac_find(s, 1001)
53 if a1.actor_id != 1001 { return 29 }
54 if a1.role != 1 { return 30 }
55 if a1.priority != 90 { return 31 }
56 if a1.state != NX_AC_STATE_READY { return 32 }
57
58 if (nx_ac_find(s, 9999) as i64) != 0 { return 33 }
59
60 // 6: pick_next -- highest priority wins (LLM = 90)
61 let pick1: *NxActor = nx_ac_pick_next(s)
62 if pick1.actor_id != 1001 { return 34 }
63
64 // 7: step LLM actor, accumulate runtime, increments quanta
65 if nx_ac_step(s, 1001, 5000, now + 100) != NX_AC_V_STEPPED { return 35 }
66 if a1.current_step != 1 { return 36 }
67 if a1.cumulative_runtime_us != 5000 { return 37 }
68 if a1.quanta_used_this_epoch != 1 { return 38 }
69 if a1.state != NX_AC_STATE_RUNNING { return 39 }
70
71 // 8: step until quantum exhausted (quantum_per_actor=4)
72 nx_ac_step(s, 1001, 5000, now + 200)
73 nx_ac_step(s, 1001, 5000, now + 300)
74 let v_exhaust: nx_int = nx_ac_step(s, 1001, 5000, now + 400)
75 if v_exhaust != NX_AC_V_YIELDED { return 40 }
76 if a1.state != NX_AC_STATE_READY { return 41 }
77 if a1.quanta_used_this_epoch != 4 { return 42 }
78
79 // 9: after quantum exhaustion, pick_next prefers IMAGE because LLM has used 4 quanta
80 // (score = 90*1000 - 4 = 89996 vs IMAGE 50*1000 - 0 = 50000).
81 // LLM still wins on priority alone; verify pick logic:
82 let pick2: *NxActor = nx_ac_pick_next(s)
83 if pick2.actor_id != 1001 { return 43 } // LLM still wins by priority
84
85 // 10: set_waiting takes LLM out of contention; now IMAGE wins
86 if nx_ac_set_waiting(s, 1001, NX_AC_WAIT_MESSAGE) != NX_AC_V_BLOCKED { return 44 }
87 let a1w: *NxActor = nx_ac_find(s, 1001)
88 if a1w.state != NX_AC_STATE_WAITING { return 45 }
89 if a1w.wait_reason != NX_AC_WAIT_MESSAGE { return 46 }
90 let pick3: *NxActor = nx_ac_pick_next(s)
91 if pick3.actor_id != 1002 { return 47 }
92
93 // 11: invalid set_waiting / wake
94 if nx_ac_set_waiting(s, 9999, NX_AC_WAIT_MESSAGE) != NX_AC_V_INVALID { return 48 }
95 if nx_ac_set_waiting(s, 1001, 99) != NX_AC_V_INVALID { return 49 }
96 if nx_ac_wake(s, 9999) != NX_AC_V_INVALID { return 50 }
97 if nx_ac_wake(s, 1002) != NX_AC_V_INVALID { return 51 } // not waiting
98
99 // 12: wake LLM back to READY
100 if nx_ac_wake(s, 1001) != NX_AC_V_STEPPED { return 52 }
101 if a1w.state != NX_AC_STATE_READY { return 53 }
102 if a1w.wait_reason != NX_AC_WAIT_NONE { return 54 }
103
104 // 13: epoch_tick resets quanta
105 if nx_ac_epoch_tick(s, now + 1000) != NX_AC_V_STEPPED { return 55 }
106 if a1.quanta_used_this_epoch != 0 { return 56 }
107 if s.epoch_count != 1 { return 57 }
108
109 // 14: pause + resume
110 if nx_ac_pause(s, 1002) != NX_AC_V_BLOCKED { return 58 }
111 let a2p: *NxActor = nx_ac_find(s, 1002)
112 if a2p.state != NX_AC_STATE_PAUSED { return 59 }
113 // PAUSED actors are not runnable, won't be picked
114 let pick4: *NxActor = nx_ac_pick_next(s)
115 if pick4.actor_id != 1001 { return 60 }
116 if nx_ac_resume(s, 1002) != NX_AC_V_STEPPED { return 61 }
117 if a2p.state != NX_AC_STATE_READY { return 62 }
118
119 // 15: cannot resume non-paused
120 if nx_ac_resume(s, 1001) != NX_AC_V_INVALID { return 63 }
121
122 // 16: complete
123 if nx_ac_complete(s, 1003) != NX_AC_V_COMPLETED { return 64 }
124 let a3c: *NxActor = nx_ac_find(s, 1003)
125 if a3c.state != NX_AC_STATE_COMPLETED { return 65 }
126 // Stepping a completed actor -> BLOCKED
127 if nx_ac_step(s, 1003, 1000, now) != NX_AC_V_BLOCKED { return 66 }
128
129 // 17: fail
130 let s2: *NxActorScheduler = nx_ac_sched_new(4, 1000000, 4, now)
131 nx_ac_spawn(s2, 2001, 1, 50, 0, now)
132 if nx_ac_fail(s2, 2001) != NX_AC_V_FAILED { return 67 }
133 let af: *NxActor = nx_ac_find(s2, 2001)
134 if af.state != NX_AC_STATE_FAILED { return 68 }
135
136 // 18: deadline failure -- spawn with tight deadline, step past it
137 let s3: *NxActorScheduler = nx_ac_sched_new(4, 1000000, 4, now)
138 nx_ac_spawn(s3, 3001, 1, 50, now + 1000, now)
139 // Step at now + 2000 -> past deadline -> FAILED
140 if nx_ac_step(s3, 3001, 100, now + 2000) != NX_AC_V_FAILED { return 69 }
141 let a3001: *NxActor = nx_ac_find(s3, 3001)
142 if a3001.state != NX_AC_STATE_FAILED { return 70 }
143
144 // 19: count_by_state
145 let n_ready: nx_int = nx_ac_count_by_state(s, NX_AC_STATE_READY)
146 if n_ready != 2 { return 71 } // 1001 + 1002 both READY
147 if nx_ac_count_by_state(s, NX_AC_STATE_COMPLETED) != 1 { return 72 }
148
149 // 20: total_runtime accumulates
150 if nx_ac_total_runtime_us(s) < 20000 { return 73 } // 4 steps * 5000us = 20000
151
152 // 21: capacity exceeded
153 let s_full: *NxActorScheduler = nx_ac_sched_new(2, 1000000, 4, now)
154 nx_ac_spawn(s_full, 1, 1, 50, 0, now)
155 nx_ac_spawn(s_full, 2, 1, 50, 0, now)
156 if nx_ac_spawn(s_full, 3, 1, 50, 0, now) != NX_AC_V_INVALID { return 74 }
157
158 // 22: null handling
159 let null_s: *NxActorScheduler = (0 as i64) as *NxActorScheduler
160 if nx_ac_spawn(null_s, 1, 1, 50, 0, now) != NX_AC_V_NULL { return 75 }
161 if (nx_ac_find(null_s, 1) as i64) != 0 { return 76 }
162 if nx_ac_step(null_s, 1, 100, now) != NX_AC_V_NULL { return 77 }
163 if nx_ac_set_waiting(null_s, 1, NX_AC_WAIT_MESSAGE) != NX_AC_V_NULL { return 78 }
164 if nx_ac_wake(null_s, 1) != NX_AC_V_NULL { return 79 }
165 if nx_ac_pause(null_s, 1) != NX_AC_V_NULL { return 80 }
166 if nx_ac_resume(null_s, 1) != NX_AC_V_NULL { return 81 }
167 if nx_ac_complete(null_s, 1) != NX_AC_V_NULL { return 82 }
168 if nx_ac_fail(null_s, 1) != NX_AC_V_NULL { return 83 }
169 if nx_ac_epoch_tick(null_s, now) != NX_AC_V_NULL { return 84 }
170 if (nx_ac_pick_next(null_s) as i64) != 0 { return 85 }
171 if nx_ac_count_by_state(null_s, NX_AC_STATE_READY) != 0 { return 86 }
172 if nx_ac_total_runtime_us(null_s) != 0 { return 87 }
173 if nx_ac_actor_count(null_s) != 0 { return 88 }
174
175 return 0
176}