code wiki / (root) / sketch_histogram_test.nx

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}