nx_bench_stats_test.nx source
↩ module page · 157 lines · 5832 B
1// nx_bench_stats_test.nx -- smoke for the distribution-stats primitive.
2
3import "nx_syscalls.nx"
4import "nx_tier.nx"
5import "nx_bench_stats.nx"
6
7func main() -> i64 {
8 // 1: verdict enum validity
9 if nx_bst_v_is_valid(NX_BST_OK) != 1 { return 1 }
10 if nx_bst_v_is_valid(NX_BST_NULL_SAMPLES) != 1 { return 2 }
11 if nx_bst_v_is_valid(NX_BST_EMPTY) != 1 { return 3 }
12 if nx_bst_v_is_valid(NX_BST_N) != 0 { return 4 }
13 if nx_bst_v_is_valid(-1) != 0 { return 5 }
14
15 // 2: empty + null + invalid
16 let stats: *NxBenchStats = nx_bst_new()
17 let null_samples: *i64 = (0 as i64) as *i64
18 if nx_bench_stats_compute(null_samples, 10, stats) != NX_BST_NULL_SAMPLES { return 6 }
19 let buf: *u8 = sys_mmap(80)
20 let samples: *i64 = buf as *i64
21 let null_stats: *NxBenchStats = (0 as i64) as *NxBenchStats
22 if nx_bench_stats_compute(samples, 10, null_stats) != NX_BST_NULL_OUT { return 7 }
23 if nx_bench_stats_compute(samples, 0, stats) != NX_BST_EMPTY { return 8 }
24 if nx_bench_stats_compute(samples, -1, stats) != NX_BST_EMPTY { return 9 }
25
26 // 3: known distribution -- 10 samples ascending
27 // [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
28 samples[0] = 10
29 samples[1] = 20
30 samples[2] = 30
31 samples[3] = 40
32 samples[4] = 50
33 samples[5] = 60
34 samples[6] = 70
35 samples[7] = 80
36 samples[8] = 90
37 samples[9] = 100
38
39 if nx_bench_stats_compute(samples, 10, stats) != NX_BST_OK { return 10 }
40 if nx_bst_n(stats) != 10 { return 11 }
41 if nx_bst_min(stats) != 10 { return 12 }
42 if nx_bst_max(stats) != 100 { return 13 }
43 if stats.sum != 550 { return 14 }
44 if nx_bst_mean(stats) != 55 { return 15 }
45 // p50: samples[10/2] = samples[5] = 60 (post-sort, which already was sorted)
46 if nx_bst_p50(stats) != 60 { return 16 }
47 // p95: samples[(95*9)/100] = samples[8] = 90
48 if nx_bst_p95(stats) != 90 { return 17 }
49
50 // 4: unsorted input -- min/max/percentiles still correct after sort
51 let buf2: *u8 = sys_mmap(80)
52 let s2: *i64 = buf2 as *i64
53 s2[0] = 50; s2[1] = 10; s2[2] = 90; s2[3] = 30; s2[4] = 70
54 s2[5] = 20; s2[6] = 80; s2[7] = 40; s2[8] = 100; s2[9] = 60
55 let st2: *NxBenchStats = nx_bst_new()
56 if nx_bench_stats_compute(s2, 10, st2) != NX_BST_OK { return 18 }
57 if nx_bst_min(st2) != 10 { return 19 }
58 if nx_bst_max(st2) != 100 { return 20 }
59 if nx_bst_mean(st2) != 55 { return 21 }
60 if nx_bst_p50(st2) != 60 { return 22 }
61 if nx_bst_p95(st2) != 90 { return 23 }
62 // Array should now be sorted ascending
63 if s2[0] != 10 { return 24 }
64 if s2[9] != 100 { return 25 }
65 var i: nx_int = 1
66 while i < 10 {
67 if s2[i] < s2[i - 1] { return 26 }
68 i = i + 1
69 }
70
71 // 5: single-sample distribution
72 let buf3: *u8 = sys_mmap(8)
73 let s3: *i64 = buf3 as *i64
74 s3[0] = 42
75 let st3: *NxBenchStats = nx_bst_new()
76 if nx_bench_stats_compute(s3, 1, st3) != NX_BST_OK { return 27 }
77 if nx_bst_min(st3) != 42 { return 28 }
78 if nx_bst_max(st3) != 42 { return 29 }
79 if nx_bst_mean(st3) != 42 { return 30 }
80 if nx_bst_p50(st3) != 42 { return 31 }
81 if nx_bst_p95(st3) != 42 { return 32 }
82 if nx_bst_stddev(st3) != 0 { return 33 }
83
84 // 6: constant distribution -- stddev = 0
85 let buf4: *u8 = sys_mmap(40)
86 let s4: *i64 = buf4 as *i64
87 var k: nx_int = 0
88 while k < 5 { s4[k] = 100; k = k + 1 }
89 let st4: *NxBenchStats = nx_bst_new()
90 if nx_bench_stats_compute(s4, 5, st4) != NX_BST_OK { return 34 }
91 if nx_bst_stddev(st4) != 0 { return 35 }
92 if nx_bst_min(st4) != 100 { return 36 }
93 if nx_bst_max(st4) != 100 { return 37 }
94
95 // 7: stddev sanity -- [0, 100] should have stddev ~ 50
96 let buf5: *u8 = sys_mmap(16)
97 let s5: *i64 = buf5 as *i64
98 s5[0] = 0
99 s5[1] = 100
100 let st5: *NxBenchStats = nx_bst_new()
101 nx_bench_stats_compute(s5, 2, st5)
102 // mean=50; var = ((50)^2 + (50)^2)/2 = 2500; stddev = 50
103 if nx_bst_stddev(st5) != 50 { return 38 }
104
105 // 8: negative samples handled correctly
106 let buf6: *u8 = sys_mmap(40)
107 let s6: *i64 = buf6 as *i64
108 s6[0] = -50
109 s6[1] = -25
110 s6[2] = 0
111 s6[3] = 25
112 s6[4] = 50
113 let st6: *NxBenchStats = nx_bst_new()
114 nx_bench_stats_compute(s6, 5, st6)
115 if nx_bst_min(st6) != -50 { return 39 }
116 if nx_bst_max(st6) != 50 { return 40 }
117 if nx_bst_mean(st6) != 0 { return 41 }
118
119 // 9: accessor null guards
120 let null_st: *NxBenchStats = (0 as i64) as *NxBenchStats
121 if nx_bst_min(null_st) != 0 { return 42 }
122 if nx_bst_max(null_st) != 0 { return 43 }
123 if nx_bst_mean(null_st) != 0 { return 44 }
124 if nx_bst_p50(null_st) != 0 { return 45 }
125 if nx_bst_p95(null_st) != 0 { return 46 }
126 if nx_bst_stddev(null_st) != 0 { return 47 }
127 if nx_bst_n(null_st) != 0 { return 48 }
128
129 // 10: realistic wall-clock distribution -- 10 fake "elapsed_us" samples
130 // with some variance
131 let buf7: *u8 = sys_mmap(80)
132 let s7: *i64 = buf7 as *i64
133 s7[0] = 10500 // typical
134 s7[1] = 10200
135 s7[2] = 10800
136 s7[3] = 10100
137 s7[4] = 11500 // tail
138 s7[5] = 10300
139 s7[6] = 10400
140 s7[7] = 10600
141 s7[8] = 10700
142 s7[9] = 14000 // outlier
143 let st7: *NxBenchStats = nx_bst_new()
144 nx_bench_stats_compute(s7, 10, st7)
145 if nx_bst_min(st7) != 10100 { return 49 }
146 if nx_bst_max(st7) != 14000 { return 50 }
147 // sorted = [10100,10200,10300,10400,10500,10600,10700,10800,11500,14000]
148 // p50 = sorted[n/2] = sorted[5] = 10600 (simple-index median;
149 // even-n returns the upper-middle by convention here)
150 if nx_bst_p50(st7) != 10600 { return 51 }
151 // p95 = sorted[(95*9)/100] = sorted[8] = 11500
152 if nx_bst_p95(st7) != 11500 { return 52 }
153 // outlier inflates max; p95 doesn't see it (because index 8, not 9)
154 if nx_bst_max(st7) <= nx_bst_p95(st7) { return 53 }
155
156 return 0
157}