code wiki / (root) / nx_batch_scheduler_test.nx

nx_batch_scheduler_test.nx source

↩ module page · 164 lines · 7615 B

1// nx_batch_scheduler_test.nx -- smoke for H2 continuous batching. 2 3import "nx_syscalls.nx" 4import "nx_batch_scheduler.nx" 5 6func main() -> i64 { 7 // 4-slot scheduler with 8-slot pending queue. 8 let sch: *NxBatchScheduler = nx_batch_scheduler_new(4, 8) 9 if nx_batch_scheduler_is_valid(sch) != 1 { return 1 } 10 if nx_batch_scheduler_n_running(sch) != 0 { return 2 } 11 if nx_batch_scheduler_n_pending(sch) != 0 { return 3 } 12 if nx_batch_scheduler_n_done(sch) != 0 { return 4 } 13 14 // ----- 1. Admit 3 requests directly into slots ----- 15 let s0: i64 = nx_batch_scheduler_admit(sch, 1001, 16) 16 if s0 < 0 { return 5 } 17 if nx_batch_scheduler_slot_state(sch, s0) != NX_SLOT_RUNNING { return 6 } 18 if nx_batch_scheduler_slot_request_id(sch, s0) != 1001 { return 7 } 19 if nx_batch_scheduler_slot_tokens_remaining(sch, s0) != 16 { return 8 } 20 21 let s1: i64 = nx_batch_scheduler_admit(sch, 1002, 8) 22 if s1 < 0 { return 9 } 23 if s1 == s0 { return 10 } 24 25 let s2: i64 = nx_batch_scheduler_admit(sch, 1003, 4) 26 if s2 < 0 { return 11 } 27 if nx_batch_scheduler_n_running(sch) != 3 { return 12 } 28 29 // ----- 2. step() reports the 3 running slots ----- 30 let active: *i64 = (sys_mmap(64)) as *i64 31 let n_active: i64 = nx_batch_scheduler_step(sch, active, 8) 32 if n_active != 3 { return 13 } 33 34 // ----- 3. Fill the 4th slot directly ----- 35 let s3: i64 = nx_batch_scheduler_admit(sch, 1004, 32) 36 if s3 < 0 { return 14 } 37 if nx_batch_scheduler_n_running(sch) != 4 { return 15 } 38 39 // ----- 4. 5th admission goes to QUEUE ----- 40 let q_v: i64 = nx_batch_scheduler_admit(sch, 1005, 2) 41 if q_v != (0 - NX_BATCH_QUEUED) { return 16 } 42 if nx_batch_scheduler_n_pending(sch) != 1 { return 17 } 43 if nx_batch_scheduler_n_running(sch) != 4 { return 18 } 44 45 // ----- 5. Add more to queue ----- 46 let q2: i64 = nx_batch_scheduler_admit(sch, 1006, 5) 47 if q2 != (0 - NX_BATCH_QUEUED) { return 19 } 48 let q3: i64 = nx_batch_scheduler_admit(sch, 1007, 5) 49 if q3 != (0 - NX_BATCH_QUEUED) { return 20 } 50 if nx_batch_scheduler_n_pending(sch) != 3 { return 21 } 51 52 // ----- 6. tick() decrements token count ----- 53 let rem: i64 = nx_batch_scheduler_tick(sch, s0, 1) 54 if rem != 15 { return 22 } 55 if nx_batch_scheduler_slot_state(sch, s0) != NX_SLOT_RUNNING { return 23 } 56 57 // ----- 7. tick() through to DONE ----- 58 let rem2: i64 = nx_batch_scheduler_tick(sch, s2, 4) 59 if rem2 != 0 { return 24 } 60 if nx_batch_scheduler_slot_state(sch, s2) != NX_SLOT_DONE { return 25 } 61 if nx_batch_scheduler_n_running(sch) != 3 { return 26 } 62 if nx_batch_scheduler_n_done(sch) != 1 { return 27 } 63 64 // ----- 8. recycle drains queue into freed slot ----- 65 let admitted: i64 = nx_batch_scheduler_recycle(sch) 66 if admitted != 1 { return 28 } // only 1 slot freed; 1 queued admitted 67 if nx_batch_scheduler_n_running(sch) != 4 { return 29 } // back to 4 68 if nx_batch_scheduler_n_pending(sch) != 2 { return 30 } // 3 - 1 69 if nx_batch_scheduler_n_done(sch) != 0 { return 31 } 70 71 // The newly-admitted slot is request 1005 (FCFS order). 72 // It must be in some slot in RUNNING state with that request_id. 73 var found_1005: i64 = 0 74 var i: i64 = 0 75 while i < sch.max_slots { 76 if nx_batch_scheduler_slot_request_id(sch, i) == 1005 { 77 if nx_batch_scheduler_slot_state(sch, i) == NX_SLOT_RUNNING { 78 found_1005 = 1 79 } 80 } 81 i = i + 1 82 } 83 if found_1005 != 1 { return 32 } 84 85 // ----- 9. complete() forces slot DONE ----- 86 if nx_batch_scheduler_complete(sch, s1) != NX_BATCH_OK { return 33 } 87 if nx_batch_scheduler_slot_state(sch, s1) != NX_SLOT_DONE { return 34 } 88 if nx_batch_scheduler_n_running(sch) != 3 { return 35 } 89 if nx_batch_scheduler_n_done(sch) != 1 { return 36 } 90 91 // Complete a non-running slot -> SLOT_NOT_RUNNING 92 if nx_batch_scheduler_complete(sch, s1) != NX_BATCH_SLOT_NOT_RUNNING { return 37 } 93 94 // ----- 10. Recycle drains the rest ----- 95 let admitted_2: i64 = nx_batch_scheduler_recycle(sch) 96 if admitted_2 != 1 { return 38 } 97 if nx_batch_scheduler_n_pending(sch) != 1 { return 39 } 98 99 // ----- 11. Empty the rest by completing all ----- 100 var j: i64 = 0 101 while j < sch.max_slots { 102 let st: i64 = nx_batch_scheduler_slot_state(sch, j) 103 if st == NX_SLOT_RUNNING { 104 nx_batch_scheduler_complete(sch, j) 105 } 106 j = j + 1 107 } 108 if nx_batch_scheduler_n_running(sch) != 0 { return 40 } 109 // Recycle drains the last queued -> 1 admitted, 0 pending. 110 let admitted_3: i64 = nx_batch_scheduler_recycle(sch) 111 if admitted_3 != 1 { return 41 } 112 if nx_batch_scheduler_n_pending(sch) != 0 { return 42 } 113 114 // ----- 12. Queue-FULL rejection ----- 115 // Fresh 1-slot scheduler with 2-slot queue. 116 let sch2: *NxBatchScheduler = nx_batch_scheduler_new(1, 2) 117 let a0: i64 = nx_batch_scheduler_admit(sch2, 200, 5) 118 if a0 < 0 { return 43 } // direct admit 119 let a1: i64 = nx_batch_scheduler_admit(sch2, 201, 5) 120 if a1 != (0 - NX_BATCH_QUEUED) { return 44 } // queued 121 let a2: i64 = nx_batch_scheduler_admit(sch2, 202, 5) 122 if a2 != (0 - NX_BATCH_QUEUED) { return 45 } // queued 123 let a3: i64 = nx_batch_scheduler_admit(sch2, 203, 5) 124 if a3 != (0 - NX_BATCH_FULL) { return 46 } // REJECTED 125 126 // ----- 13. Bad-input gates ----- 127 if nx_batch_scheduler_admit(sch, 999, 0) != (0 - NX_BATCH_BAD_INPUT) { return 47 } 128 if nx_batch_scheduler_admit(sch, 999, -5) != (0 - NX_BATCH_BAD_INPUT) { return 48 } 129 if nx_batch_scheduler_tick(sch, -1, 1) != (0 - NX_BATCH_BAD_SLOT) { return 49 } 130 if nx_batch_scheduler_tick(sch, 999, 1) != (0 - NX_BATCH_BAD_SLOT) { return 50 } 131 if nx_batch_scheduler_complete(sch, -1) != NX_BATCH_BAD_SLOT { return 51 } 132 if nx_batch_scheduler_complete(sch, 999) != NX_BATCH_BAD_SLOT { return 52 } 133 let null_buf: *i64 = (0 as i64) as *i64 134 if nx_batch_scheduler_step(sch, null_buf, 8) != (0 - NX_BATCH_BAD_INPUT) { return 53 } 135 if nx_batch_scheduler_step(sch, active, 0) != (0 - NX_BATCH_BAD_INPUT) { return 54 } 136 137 // ----- 14. Tamper ----- 138 let tamper_sch: *NxBatchScheduler = nx_batch_scheduler_new(2, 4) 139 tamper_sch.canary_post = 0xDEADBEEF 140 if nx_batch_scheduler_is_valid(tamper_sch) != 0 { return 55 } 141 if nx_batch_scheduler_admit(tamper_sch, 1, 1) != (0 - NX_BATCH_TAMPER) { return 56 } 142 if nx_batch_scheduler_recycle(tamper_sch) != (0 - NX_BATCH_TAMPER) { return 57 } 143 if nx_batch_scheduler_n_running(tamper_sch) != -1 { return 58 } 144 145 // ----- 15. Sealed-enum gates ----- 146 if nx_slot_state_is_valid(NX_SLOT_FREE) != 1 { return 59 } 147 if nx_slot_state_is_valid(NX_SLOT_RUNNING) != 1 { return 60 } 148 if nx_slot_state_is_valid(NX_SLOT_DONE) != 1 { return 61 } 149 if nx_slot_state_is_valid(-1) != 0 { return 62 } 150 if nx_slot_state_is_valid(NX_SLOT_N_STATES) != 0 { return 63 } 151 if nx_batch_verdict_is_valid(NX_BATCH_OK) != 1 { return 64 } 152 if nx_batch_verdict_is_valid(NX_BATCH_QUEUED) != 1 { return 65 } 153 if nx_batch_verdict_is_valid(-1) != 0 { return 66 } 154 if nx_batch_verdict_is_valid(NX_BATCH_N_VERDICTS) != 0 { return 67 } 155 156 // ----- 16. Bad new() inputs ----- 157 if (nx_batch_scheduler_new(0, 4) as i64) != 0 { return 68 } 158 if (nx_batch_scheduler_new(-1, 4) as i64) != 0 { return 69 } 159 if (nx_batch_scheduler_new(NX_BATCH_MAX_SLOTS + 1, 4) as i64) != 0 { return 70 } 160 if (nx_batch_scheduler_new(4, -1) as i64) != 0 { return 71 } 161 if (nx_batch_scheduler_new(4, NX_BATCH_MAX_PENDING + 1) as i64) != 0 { return 72 } 162 163 return 0 164}