code wiki / (root) / nx_stream_multiplexer_test.nx

nx_stream_multiplexer_test.nx source

↩ module page · 152 lines · 7980 B

1// nx_stream_multiplexer_test.nx -- smoke for nx_stream_multiplexer. 2 3import "nx_syscalls.nx" 4import "nx_stream_multiplexer.nx" 5 6func main() -> i64 { 7 let now: nx_size = 1000000 8 9 // Out-params for nx_sm_next 10 let out_class_buf: *u8 = sys_mmap(24) 11 let out_class: *i64 = out_class_buf as *i64 12 let out_seq: *i64 = (out_class_buf + 8) as *i64 13 let out_stream: *i64 = (out_class_buf + 16) as *i64 14 15 // 1: enum validity 16 if nx_sm_class_is_valid(NX_SM_CLASS_LLM_TEXT) != 1 { return 1 } 17 if nx_sm_class_is_valid(NX_SM_CLASS_SYSTEM_EVENT) != 1 { return 2 } 18 if nx_sm_class_is_valid(-1) != 0 { return 3 } 19 if nx_sm_class_is_valid(7) != 0 { return 4 } 20 if NX_SM_CLASS_N != 7 { return 5 } 21 22 if nx_sm_v_is_valid(NX_SM_V_DELIVERED) != 1 { return 6 } 23 if nx_sm_v_is_valid(NX_SM_V_STARVED) != 1 { return 7 } 24 25 // 2: priority ordering: SYSTEM > GAME_ACTION > LLM > AUDIO > TOOL > IMAGE > VIDEO 26 if nx_sm_class_priority(NX_SM_CLASS_SYSTEM_EVENT) <= nx_sm_class_priority(NX_SM_CLASS_GAME_ACTION) { return 8 } 27 if nx_sm_class_priority(NX_SM_CLASS_GAME_ACTION) <= nx_sm_class_priority(NX_SM_CLASS_LLM_TEXT) { return 9 } 28 if nx_sm_class_priority(NX_SM_CLASS_LLM_TEXT) <= nx_sm_class_priority(NX_SM_CLASS_AUDIO_TTS) { return 10 } 29 if nx_sm_class_priority(NX_SM_CLASS_AUDIO_TTS) <= nx_sm_class_priority(NX_SM_CLASS_TOOL_RESULT) { return 11 } 30 if nx_sm_class_priority(NX_SM_CLASS_TOOL_RESULT) <= nx_sm_class_priority(NX_SM_CLASS_IMAGE_TILE) { return 12 } 31 if nx_sm_class_priority(NX_SM_CLASS_IMAGE_TILE) <= nx_sm_class_priority(NX_SM_CLASS_VIDEO_FRAME) { return 13 } 32 33 // 3: construction 34 let m: *NxStreamMultiplexer = nx_sm_new(32, 50000) // 50ms starvation threshold 35 if m.capacity != 32 { return 14 } 36 if m.n_pending != 0 { return 15 } 37 if m.starvation_threshold_us != 50000 { return 16 } 38 39 if nx_sm_new(0, 50000) != (0 as *NxStreamMultiplexer) { return 17 } 40 41 // 4: empty next returns EMPTY 42 if nx_sm_next(m, out_class, out_seq, out_stream, now) != NX_SM_V_EMPTY { return 18 } 43 44 // 5: push chunks of varying priority then verify the highest-priority 45 // one comes out first (no starvation/budget effects yet) 46 nx_sm_push(m, 1, NX_SM_CLASS_VIDEO_FRAME, 100, 1024, 0xCA01, now) 47 nx_sm_push(m, 2, NX_SM_CLASS_IMAGE_TILE, 200, 1024, 0xCA02, now) 48 nx_sm_push(m, 3, NX_SM_CLASS_LLM_TEXT, 300, 64, 0xCA03, now) 49 nx_sm_push(m, 4, NX_SM_CLASS_AUDIO_TTS, 400, 32, 0xCA04, now) 50 nx_sm_push(m, 5, NX_SM_CLASS_GAME_ACTION, 500, 16, 0xCA05, now) 51 nx_sm_push(m, 6, NX_SM_CLASS_SYSTEM_EVENT, 600, 8, 0xCA06, now) 52 if m.n_pending != 6 { return 19 } 53 if nx_sm_pending_count(m) != 6 { return 20 } 54 55 // 6: first next should be SYSTEM_EVENT 56 if nx_sm_next(m, out_class, out_seq, out_stream, now) != NX_SM_V_DELIVERED { return 21 } 57 if out_class[0] != (NX_SM_CLASS_SYSTEM_EVENT as i64) { return 22 } 58 if out_seq[0] != 600 { return 23 } 59 if m.n_pending != 5 { return 24 } 60 61 // 7: second next should be GAME_ACTION 62 nx_sm_next(m, out_class, out_seq, out_stream, now) 63 if out_class[0] != (NX_SM_CLASS_GAME_ACTION as i64) { return 25 } 64 if out_seq[0] != 500 { return 26 } 65 66 // 8: third = LLM_TEXT 67 nx_sm_next(m, out_class, out_seq, out_stream, now) 68 if out_class[0] != (NX_SM_CLASS_LLM_TEXT as i64) { return 27 } 69 70 // 9: fourth = AUDIO_TTS 71 nx_sm_next(m, out_class, out_seq, out_stream, now) 72 if out_class[0] != (NX_SM_CLASS_AUDIO_TTS as i64) { return 28 } 73 74 // 10: fifth = IMAGE_TILE 75 nx_sm_next(m, out_class, out_seq, out_stream, now) 76 if out_class[0] != (NX_SM_CLASS_IMAGE_TILE as i64) { return 29 } 77 78 // 11: sixth = VIDEO_FRAME 79 nx_sm_next(m, out_class, out_seq, out_stream, now) 80 if out_class[0] != (NX_SM_CLASS_VIDEO_FRAME as i64) { return 30 } 81 82 // 12: empty again 83 if m.n_pending != 0 { return 31 } 84 if nx_sm_next(m, out_class, out_seq, out_stream, now) != NX_SM_V_EMPTY { return 32 } 85 86 // 13: starvation boost -- push a VIDEO_FRAME at t=0, then LLM_TEXT at t=100ms. 87 // LLM normally wins by priority. But if VIDEO has waited > 50ms (threshold), 88 // it gets +30 score boost, may now beat LLM (30 priority + 30 boost = 60 < 80). 89 // LLM (80) still wins. Let me design a scenario where boost matters: 90 // image_tile (40) + 30 boost = 70 > audio_tts (70 base) -- ties happen. 91 // Cleanest: push 5x AUDIO chunks so AUDIO hits its budget of 16... no, budget is 16. 92 // Test: push old IMAGE_TILE (40) + recent VIDEO_FRAME (30); IMAGE has +30 boost 93 // becomes 70 > VIDEO 30 -> IMAGE wins. Need to verify that without boost 94 // IMAGE still wins anyway (40 > 30). So the boost test is invariant. 95 // Force test: old VIDEO (30+30=60) vs recent IMAGE (40+0=40) -> VIDEO wins. 96 let m2: *NxStreamMultiplexer = nx_sm_new(8, 50000) 97 nx_sm_push(m2, 1, NX_SM_CLASS_VIDEO_FRAME, 100, 1024, 0, now) 98 nx_sm_push(m2, 2, NX_SM_CLASS_IMAGE_TILE, 200, 1024, 0, now + 60000) 99 // Read at t = now + 60000 -- video has waited 60ms > 50ms threshold 100 nx_sm_next(m2, out_class, out_seq, out_stream, now + 60000) 101 if out_class[0] != (NX_SM_CLASS_VIDEO_FRAME as i64) { return 33 } 102 103 // 14: budget exhaustion -- IMAGE_TILE budget is 2 per epoch. Push 3 IMAGEs 104 // before any LLM. IMAGE serves twice then backoff kicks in (priority 40 - 50 = -10). 105 // If we now push 1 LLM_TEXT, LLM should win even though IMAGE is older. 106 let m3: *NxStreamMultiplexer = nx_sm_new(8, 1000000) // huge starvation threshold so no boost 107 nx_sm_push(m3, 1, NX_SM_CLASS_IMAGE_TILE, 101, 1024, 0, now) 108 nx_sm_push(m3, 2, NX_SM_CLASS_IMAGE_TILE, 102, 1024, 0, now) 109 nx_sm_next(m3, out_class, out_seq, out_stream, now) // IMAGE 1 110 nx_sm_next(m3, out_class, out_seq, out_stream, now) // IMAGE 2 111 if nx_sm_served_count(m3, NX_SM_CLASS_IMAGE_TILE) != 2 { return 34 } 112 // Now push another image + an LLM 113 nx_sm_push(m3, 3, NX_SM_CLASS_IMAGE_TILE, 103, 1024, 0, now) 114 nx_sm_push(m3, 4, NX_SM_CLASS_LLM_TEXT, 104, 64, 0, now) 115 // Image budget=2 already used, so IMAGE score = 40-50 = -10. LLM = 80. LLM wins. 116 nx_sm_next(m3, out_class, out_seq, out_stream, now) 117 if out_class[0] != (NX_SM_CLASS_LLM_TEXT as i64) { return 35 } 118 119 // 15: epoch_tick resets served counts 120 if nx_sm_epoch_tick(m3) != NX_SM_V_DELIVERED { return 36 } 121 if nx_sm_served_count(m3, NX_SM_CLASS_IMAGE_TILE) != 0 { return 37 } 122 123 // 16: after reset, IMAGE_TILE wins again over... wait, IMAGE has priority 40 and 124 // remaining queue has IMAGE seq=103. Push nothing else -- IMAGE wins by default. 125 nx_sm_next(m3, out_class, out_seq, out_stream, now) 126 if out_class[0] != (NX_SM_CLASS_IMAGE_TILE as i64) { return 38 } 127 128 // 17: capacity exceeded 129 let m_full: *NxStreamMultiplexer = nx_sm_new(2, 50000) 130 nx_sm_push(m_full, 1, NX_SM_CLASS_LLM_TEXT, 1, 64, 0, now) 131 nx_sm_push(m_full, 2, NX_SM_CLASS_LLM_TEXT, 2, 64, 0, now) 132 if nx_sm_push(m_full, 3, NX_SM_CLASS_LLM_TEXT, 3, 64, 0, now) != NX_SM_V_INVALID { return 39 } 133 134 // 18: invalid class refused 135 let m_v: *NxStreamMultiplexer = nx_sm_new(4, 50000) 136 if nx_sm_push(m_v, 1, 99, 1, 64, 0, now) != NX_SM_V_INVALID { return 40 } 137 if nx_sm_push(m_v, 1, -1, 1, 64, 0, now) != NX_SM_V_INVALID { return 41 } 138 139 // 19: served_count for invalid class returns 0 140 if nx_sm_served_count(m_v, 99) != 0 { return 42 } 141 142 // 20: null handling 143 let null_m: *NxStreamMultiplexer = (0 as i64) as *NxStreamMultiplexer 144 if nx_sm_push(null_m, 1, NX_SM_CLASS_LLM_TEXT, 1, 64, 0, now) != NX_SM_V_NULL { return 43 } 145 if nx_sm_next(null_m, out_class, out_seq, out_stream, now) != NX_SM_V_NULL { return 44 } 146 if nx_sm_epoch_tick(null_m) != NX_SM_V_NULL { return 45 } 147 if nx_sm_pending_count(null_m) != 0 { return 46 } 148 if nx_sm_served_count(null_m, NX_SM_CLASS_LLM_TEXT) != 0 { return 47 } 149 if (nx_sm_peek_next(null_m, now) as i64) != 0 { return 48 } 150 151 return 0 152}