sketch_histogram_test.nx source
↩ module page · 145 lines · 5336 B
1// sketch_histogram_test.nx -- fixed-bin histogram + quantile + merge.
2
3import "syscalls.nx"
4import "sketch_histogram.nx"
5import "sketch_types.nx"
6
7func iabs(x: i64) -> i64 {
8 if x < 0 { return -x }
9 return x
10}
11
12func main() -> i64 {
13 // ---- alloc ----
14 let h: *Histogram = nx_hist_alloc(0, 100, 10) // [0, 100), 10 buckets
15 if h == (0 as *Histogram) { return __syscall(93, 5, 0, 0, 0, 0, 0) }
16 // Reject inverted range.
17 if nx_hist_alloc(100, 50, 10) != (0 as *Histogram) {
18 return __syscall(93, 6, 0, 0, 0, 0, 0)
19 }
20 // Reject too-few buckets.
21 if nx_hist_alloc(0, 100, 1) != (0 as *Histogram) {
22 return __syscall(93, 7, 0, 0, 0, 0, 0)
23 }
24 if h.total != 0 { return __syscall(93, 8, 0, 0, 0, 0, 0) }
25
26 // ---- in-range adds ----
27 nx_hist_add(h, 5) // bucket 0 (5*10/100=0)
28 nx_hist_add(h, 15) // bucket 1
29 nx_hist_add(h, 25) // bucket 2
30 nx_hist_add(h, 5) // bucket 0 again
31 if nx_hist_count_at(h, 0) != 2 { return __syscall(93, 10, 0, 0, 0, 0, 0) }
32 if nx_hist_count_at(h, 1) != 1 { return __syscall(93, 11, 0, 0, 0, 0, 0) }
33 if nx_hist_count_at(h, 2) != 1 { return __syscall(93, 12, 0, 0, 0, 0, 0) }
34 if nx_hist_total(h) != 4 { return __syscall(93, 13, 0, 0, 0, 0, 0) }
35 if nx_hist_count_for_value(h, 5) != 2 {
36 return __syscall(93, 14, 0, 0, 0, 0, 0)
37 }
38
39 // ---- out-of-range ----
40 nx_hist_add(h, -10) // under
41 nx_hist_add(h, 100) // over (max is exclusive)
42 nx_hist_add(h, 1000) // over
43 if h.under_count != 1 { return __syscall(93, 20, 0, 0, 0, 0, 0) }
44 if h.over_count != 2 { return __syscall(93, 21, 0, 0, 0, 0, 0) }
45 if nx_hist_total(h) != 7 { return __syscall(93, 22, 0, 0, 0, 0, 0) }
46 if nx_hist_in_range(h) != 4 { return __syscall(93, 23, 0, 0, 0, 0, 0) }
47
48 // ---- uniform fill -> uniform buckets ----
49 let h2: *Histogram = nx_hist_alloc(0, 1000, 10) // [0, 1000), 10 buckets
50 var i: i64 = 0
51 while i < 1000 {
52 nx_hist_add(h2, i)
53 i = i + 1
54 }
55 // Each bucket should have 100 items.
56 i = 0
57 while i < 10 {
58 if nx_hist_count_at(h2, i) != 100 {
59 return __syscall(93, 30, 0, 0, 0, 0, 0)
60 }
61 i = i + 1
62 }
63
64 // ---- quantile ----
65 // p10 -> bucket containing rank 100 (bucket 1). Midpoint: 150.
66 let p10: i64 = nx_hist_quantile(h2, 100)
67 if iabs(p10 - 150) > 50 {
68 return __syscall(93, 40, 0, 0, 0, 0, 0)
69 }
70 // p50 -> bucket 5. Midpoint: 550.
71 let p50: i64 = nx_hist_quantile(h2, 500)
72 if iabs(p50 - 550) > 50 {
73 return __syscall(93, 41, 0, 0, 0, 0, 0)
74 }
75 // p99 -> bucket 9. Midpoint: 950.
76 let p99: i64 = nx_hist_quantile(h2, 990)
77 if iabs(p99 - 950) > 50 {
78 return __syscall(93, 42, 0, 0, 0, 0, 0)
79 }
80
81 // ---- typed envelope ----
82 let qc: *ApproxI64 = nx_hist_query_count_for_value(h2, 250)
83 if qc.envelope_kind != NX_ENV_ABS {
84 return __syscall(93, 50, 0, 0, 0, 0, 0)
85 }
86 if qc.param_a != 0 { // exact
87 return __syscall(93, 51, 0, 0, 0, 0, 0)
88 }
89 if qc.value != 100 {
90 return __syscall(93, 52, 0, 0, 0, 0, 0)
91 }
92 if qc.maturity != NX_MATURITY_PRODUCTION {
93 return __syscall(93, 53, 0, 0, 0, 0, 0)
94 }
95
96 let qq: *ApproxI64 = nx_hist_query_quantile(h2, 500)
97 if qq.envelope_kind != NX_ENV_RANK_ERROR {
98 return __syscall(93, 60, 0, 0, 0, 0, 0)
99 }
100 // n_buckets=10 -> resolution = 100_000_000 ppb (10%).
101 if qq.param_a != 100000000 {
102 return __syscall(93, 61, 0, 0, 0, 0, 0)
103 }
104
105 // ---- merge ----
106 let ma: *Histogram = nx_hist_alloc(0, 100, 10)
107 let mb: *Histogram = nx_hist_alloc(0, 100, 10)
108 nx_hist_add(ma, 25)
109 nx_hist_add(ma, 75)
110 nx_hist_add(mb, 25)
111 nx_hist_add(mb, 50)
112 let merged: *Histogram = nx_hist_merge(ma, mb)
113 if merged == (0 as *Histogram) {
114 return __syscall(93, 70, 0, 0, 0, 0, 0)
115 }
116 if nx_hist_count_at(merged, 2) != 2 { // both put one in bucket 2
117 return __syscall(93, 71, 0, 0, 0, 0, 0)
118 }
119 if nx_hist_count_at(merged, 5) != 1 { // only mb
120 return __syscall(93, 72, 0, 0, 0, 0, 0)
121 }
122 if nx_hist_count_at(merged, 7) != 1 { // only ma
123 return __syscall(93, 73, 0, 0, 0, 0, 0)
124 }
125 if nx_hist_total(merged) != 4 {
126 return __syscall(93, 74, 0, 0, 0, 0, 0)
127 }
128 // Merge with mismatched range -> NULL.
129 let mc: *Histogram = nx_hist_alloc(0, 200, 10)
130 if nx_hist_merge(ma, mc) != (0 as *Histogram) {
131 return __syscall(93, 75, 0, 0, 0, 0, 0)
132 }
133
134 // ---- bulk add_n ----
135 let h3: *Histogram = nx_hist_alloc(0, 100, 10)
136 nx_hist_add_n(h3, 25, 50) // 50 items in bucket 2
137 nx_hist_add_n(h3, 75, 25) // 25 items in bucket 7
138 nx_hist_add_n(h3, -5, 10) // 10 under
139 if nx_hist_count_at(h3, 2) != 50 { return __syscall(93, 80, 0, 0, 0, 0, 0) }
140 if nx_hist_count_at(h3, 7) != 25 { return __syscall(93, 81, 0, 0, 0, 0, 0) }
141 if h3.under_count != 10 { return __syscall(93, 82, 0, 0, 0, 0, 0) }
142 if nx_hist_total(h3) != 85 { return __syscall(93, 83, 0, 0, 0, 0, 0) }
143
144 return 0
145}