code wiki / (root) / sketch_lc_vs_hll_small_n_bench.nx

sketch_lc_vs_hll_small_n_bench.nx source

↩ module page · 90 lines · 2789 B

1// sketch_lc_vs_hll_small_n_bench.nx -- LC sweet-spot paired bench. 2// 3// CLAIM TO VALIDATE: 4// Linear Counter (Whang-Vander Zanden 1990) is exact-bit per insert 5// with collision-driven variance. At small N where bit-collisions 6// are rare (N << m), LC's estimator is tighter than HLL's, which 7// pays a constant overhead for the rho-based ranks even when the 8// counts are small. 9// 10// The substrate ships both; LC's documented sweet spot is "small-N". 11// Bench verifies the cross-over: at N <= m/4, LC should win on 12// accuracy at matched memory. 13// 14// WORKLOAD: 15// N = 200 distinct keys. 16// LC m_bits = 1024 (128 bytes regs) 17// HLL lg_k = 7 (m = 128 regs * 8 bits = 1024 bits = 128 bytes total) 18// Both at ~128 byte register footprint. 19// 20// MEASUREMENT: 21// ACCURACY: closer to truth=200 wins. 22 23import "syscalls.nx" 24import "sketch_linear_counter.nx" 25import "sketch_hll.nx" 26import "sketch_comparator.nx" 27import "sketch_types.nx" 28 29func iabs_lc(x: i64) -> i64 { 30 if x < 0 { return -x } 31 return x 32} 33 34func write_blc(buf: *u8, value: i64) -> i64 { 35 var i: i64 = 0 36 var v: i64 = value 37 while i < 8 { 38 buf[i] = (v & 0xFF) as u8 39 v = v >> 8 40 i = i + 1 41 } 42 return 0 43} 44 45func main() -> i64 { 46 let n: i64 = 200 47 let seed: i64 = 42 48 let lc_m_bits: i64 = 1024 // 128 bytes 49 let hll_lg_k: i64 = 7 // m=128 regs * 8 bits = 1024 bits 50 51 let lc: *LinearCounter = nx_lc_alloc(lc_m_bits, seed) 52 let hll: *Hll = nx_hll_alloc(hll_lg_k, seed) 53 if lc == (0 as *LinearCounter) { return __syscall(93, 1, 0, 0, 0, 0, 0) } 54 if hll == (0 as *Hll) { return __syscall(93, 2, 0, 0, 0, 0, 0) } 55 56 let key_raw: *u8 = sys_mmap(8) 57 let key: *u8 = key_raw 58 59 var i: i64 = 0 60 while i < n { 61 write_blc(key, i + 7000000) 62 nx_lc_add(lc, key, 8) 63 nx_hll_add(hll, key, 8) 64 i = i + 1 65 } 66 67 let lc_est: i64 = nx_lc_estimate(lc) 68 let hll_est: i64 = nx_hll_estimate(hll) 69 70 // ---- Sanity: both produce non-zero estimates ---- 71 if lc_est <= 0 { return __syscall(93, 5, 0, 0, 0, 0, 0) } 72 if hll_est <= 0 { return __syscall(93, 6, 0, 0, 0, 0, 0) } 73 74 // ---- ACCURACY at truth=200: closer wins ---- 75 let acc: *ComparisonResult = nx_cmp_accuracy(lc_est, hll_est, n, 30000) 76 77 // Expected: LC wins at this small-N regime. 78 if acc.verdict != NX_CMP_VERDICT_BEATS { 79 // If LC doesn't beat HLL, the substrate doc claim of 80 // "small-N sweet spot" is false -- honest failure. 81 if acc.verdict == NX_CMP_VERDICT_EQUIVALENT { 82 // Equivalent is acceptable -- LC's edge may be marginal 83 // at this exact N. Don't fail. 84 return 0 85 } 86 return __syscall(93, 10, 0, 0, 0, 0, 0) 87 } 88 89 return 0 90}