nx_bench_stress_autoreg_test.nx source
↩ module page · 145 lines · 6004 B
1// nx_bench_stress_autoreg_test.nx -- 10-iteration REAL transformer
2// stress test with wall-clock measurement.
3//
4// Where nx_actor_role_llm_v2_real_autoreg_test does 3 iterations
5// for correctness, this smoke does 10 to exercise the substrate
6// under load + capture honest wall-clock numbers.
7//
8// Each iteration drives the v2 LLM actor through INIT -> RUN (full
9// Llama-class transformer forward via nx_llm_generate_one_v2) ->
10// EMIT. Real embedding lookup + RMSNorm + multi-head attention +
11// SwiGLU FFN + output projection + sample. Listener mailbox
12// receives 10 LLM_TOKEN messages.
13//
14// Substrate invariants verified under load:
15// * All 10 iterations succeed (every runner_result >= 0)
16// * All 10 tokens are in [0, vocab)
17// * Listener mailbox correctly handles 10 messages
18// * Scheduler counters scale linearly (30 actor steps, 30000us
19// cumulative runtime)
20// * Wall-clock elapsed > 0 (substrate actually ran wall-time work)
21//
22// HONEST SCOPE: wall-clock under qemu-riscv64 isn't physical-hardware
23// time. When Phase E + a physical-board arc land, this same smoke
24// will produce defensible numbers without code changes.
25
26import "nx_syscalls.nx"
27import "nx_tier.nx"
28import "nx_clock.nx"
29import "nx_actor.nx"
30import "nx_message.nx"
31import "nx_session.nx"
32import "nx_bench_companion.nx"
33import "nx_bench_companion_timed.nx"
34import "nx_gguf_fixture_tiny.nx"
35import "nx_actor_role_llm_v2.nx"
36
37func main() -> i64 {
38 let now: nx_size = 1000000
39 let N_ITERS: nx_int = 10
40
41 // ===== Fixture + session =====
42 let fix: *NxGgufFixtureBundle = nx_gft_build_tiny_llama(0xfeed)
43 if nx_gft_is_built(fix) != 1 { return 1 }
44 let s: *NxSession = nx_session_new_default(now)
45 if nx_session_is_ready(s) != 1 { return 2 }
46 let LLM: nx_int = 8001
47 let LIS: nx_int = 8099
48 nx_session_spawn_actor(s, LLM, 1, 80, 0, now)
49 nx_session_spawn_actor(s, LIS, 5, 50, 0, now)
50 nx_session_subscribe(s, LIS, NX_MS_KIND_LLM_TOKEN)
51
52 let prompt: *u8 = sys_mmap(1)
53 prompt[0] = 0x61 // 'a'
54 let ctx: *NxLlmV2ActorCtx = nx_lv_actor_new(
55 fix.spec, fix.gguf_buf, fix.hdr, fix.bpe,
56 prompt, 1,
57 1024, 4, fix.prng_state, 10000, 724)
58 if (ctx as i64) == 0 { return 3 }
59
60 // ===== Pre-capture for paired-delta =====
61 let r_before: *NxBenchReport = nx_bc_report_new()
62 nx_bc_capture(s, r_before, 11, now)
63
64 // ===== Start wall-clock timer =====
65 let base: *NxBenchReport = nx_bc_report_new()
66 let timed: *NxBenchTimedReport = nx_bctm_new(base)
67 timed.wallclock_start_ns = nx_clock_monotonic_ns()
68
69 // ===== Drive 10 autoregressive iterations =====
70 let history: *u8 = sys_mmap(N_ITERS * 8)
71 let hist: *i64 = history as *i64
72 var iter: nx_int = 0
73 var tick: nx_size = now + 100
74 while iter < N_ITERS {
75 if nx_lv_actor_step(ctx, s.scheduler, s.bus, LLM, tick) != NX_LV_V_STEPPED { return 10 + iter }
76 tick = tick + 50
77 let v_run: nx_int = nx_lv_actor_step(ctx, s.scheduler, s.bus, LLM, tick)
78 if ctx.runner_result < 0 { return 20 + iter }
79 if ctx.runner_result >= fix.vocab_size { return 30 + iter }
80 if ctx.runner_verdict != NX_LR2_OK { return 40 + iter }
81 if v_run != NX_LV_V_STEPPED { return 50 + iter }
82 tick = tick + 50
83 let v_emit: nx_int = nx_lv_actor_step(ctx, s.scheduler, s.bus, LLM, tick)
84 if v_emit != NX_LV_V_COMPLETED { return 60 + iter }
85 if ctx.current_phase != NX_LV_PHASE_DONE { return 70 + iter }
86 let tok: nx_int = ctx.runner_result
87 hist[iter] = tok as i64
88 tick = tick + 50
89
90 if iter < (N_ITERS - 1) {
91 let new_byte: nx_int = nx_gft_vocab_byte(fix, tok)
92 if new_byte < 0 { return 80 + iter }
93 prompt[0] = new_byte as u8
94 if nx_lv_actor_reset_for_next_token(ctx, s.scheduler, LLM, prompt, 1) != NX_LV_V_STEPPED { return 90 + iter }
95 }
96 iter = iter + 1
97 }
98
99 // ===== Stop wall-clock timer + capture substrate counters =====
100 if nx_bctm_capture_finish(timed, s, 11) != NX_BCTM_OK { return 100 }
101
102 // ===== Substrate invariants under load =====
103 //
104 // Per iteration: 3 actor steps (INIT, RUN, EMIT). 10 iterations
105 // = 30 cooperative steps for the LLM actor.
106 if base.total_actor_steps != 30 { return 101 }
107 // Each step accumulates 1000us substrate runtime.
108 if base.cumulative_runtime_us != 30000 { return 102 }
109 // LLM actor reached COMPLETED on the FINAL iteration (no reset).
110 if base.actors_completed != 1 { return 103 }
111 if base.actors_failed != 0 { return 104 }
112 // Listener (still READY) + LLM (COMPLETED) = 2 actors
113 if base.n_actors != 2 { return 105 }
114
115 // ===== Wall-clock invariants =====
116 if timed.wallclock_elapsed_us < 0 { return 106 }
117 if timed.wallclock_end_ns < timed.wallclock_start_ns { return 107 }
118 if nx_bctm_verdict(timed) != NX_BCTM_OK { return 108 }
119
120 // ===== Listener received exactly N_ITERS LLM_TOKEN messages =====
121 if nx_ms_pending(s.bus, LIS) != N_ITERS { return 109 }
122
123 // ===== Drain + verify each token matches history =====
124 var drained: nx_int = 0
125 while drained < N_ITERS {
126 let m: *NxMessage = nx_ms_receive(s.bus, LIS)
127 if (m as i64) == 0 { return 200 + drained }
128 if m.kind != NX_MS_KIND_LLM_TOKEN { return 210 + drained }
129 if m.sender_actor_id != LLM { return 220 + drained }
130 let recv_tok: nx_int = m.payload_handle as nx_int
131 if recv_tok != (hist[drained] as nx_int) { return 230 + drained }
132 if recv_tok < 0 { return 240 + drained }
133 if recv_tok >= fix.vocab_size { return 250 + drained }
134 drained = drained + 1
135 }
136
137 // ===== Paired delta with pre-capture =====
138 let delta: *NxBenchReport = nx_bc_report_new()
139 nx_bc_diff(r_before, base, delta)
140 if delta.total_actor_steps != 30 { return 300 }
141 if delta.cumulative_runtime_us != 30000 { return 301 }
142 if delta.actors_completed != 1 { return 302 }
143
144 return 0
145}