code wiki / (root) / nx_qplan_gate.nx

nx_qplan_gate.nx source

↩ module page · 62 lines · 4095 B

1// nx_qplan_gate.nx -- proves the cost-based planner CHOOSES CORRECTLY, matching the reality the parexec 2// bench measured: small data -> sequential (fork not worth it); large bandwidth-bound scan -> sequential 3// (parallel loses, measured 0.66x); large compute-bound -> parallel (measured 3.10x). Also proves the 4// estimates are internally ordered and monotone. Known cost profiles, deterministic. D001 via nx_gate_verdict. 5import "nx_gate_verdict.nx" 6import "nx_qplan.nx" 7 8func qg_eq(a: i64, b: i64) -> i64 { if a == b { return 1 } return 0 } 9 10func main() -> i64 { 11 let ctr: *i64 = gv_ctr() 12 gv_head("nx_qplan_gate -- does the cost-based planner choose what the bench actually measured?" as *u8) 13 14 // ---- the three decisions the bench established ----------------------------------------------- 15 // 1) tiny job (10k rows = 0.01 Mrows... use 1 Mrow with cw=0): bandwidth-bound + small -> SEQUENTIAL 16 gv_check("T1 1M-row pure SCAN -> SEQUENTIAL (fork cost + bus contention beat the saving)" as *u8, qg_eq(qp_choose(1, 0, 4), QP_SEQ), ctr) 17 // 2) large bandwidth-bound scan (40 Mrows, cw=0): parallel measured SLOWER -> SEQUENTIAL 18 gv_check("T2 40M-row pure SCAN -> SEQUENTIAL (matches the measured 0.66x -- parallel loses on bandwidth)" as *u8, qg_eq(qp_choose(40, 0, 4), QP_SEQ), ctr) 19 // 3) large compute-bound (40 Mrows, cw=32 like the hashsum): parallel measured 3.10x -> PARALLEL 20 gv_check("T3 40M-row COMPUTE-bound (cw=32) -> PARALLEL (matches the measured 3.10x)" as *u8, qg_eq(qp_choose(40, 32, 4), QP_PAR), ctr) 21 22 // ---- the cost estimates are sane and ordered ------------------------------------------------ 23 // for a pure scan, parallel must be estimated MORE expensive than sequential (it is, by the model) 24 var t4: i64 = 0 25 if qp_cost_par(40, 0, 4) > qp_cost_seq(40, 0) { t4 = 1 } 26 gv_check("T4 pure-scan parallel estimate > sequential estimate (the model encodes the bus-contention penalty)" as *u8, t4, ctr) 27 // for heavy compute, parallel estimate must be LESS than sequential 28 var t5: i64 = 0 29 if qp_cost_par(40, 32, 4) < qp_cost_seq(40, 32) { t5 = 1 } 30 gv_check("T5 heavy-compute parallel estimate < sequential estimate" as *u8, t5, ctr) 31 // more cores -> lower parallel estimate for compute-bound (monotone in ncores) 32 var t6: i64 = 0 33 if qp_cost_par(40, 32, 8) < qp_cost_par(40, 32, 4) { t6 = 1 } 34 gv_check("T6 more cores lowers the compute-bound parallel estimate (scales with ncores)" as *u8, t6, ctr) 35 36 // ---- THE CROSSOVER is real: there is a compute-weight where the choice flips ------------------ 37 // at cw=0 sequential; at cw=32 parallel; so some threshold in between flips it -> find it by scan 38 var flip: i64 = 0 - 1 39 var w: i64 = 0 40 while w <= 32 { 41 if flip < 0 { if qp_choose(40, w, 4) == QP_PAR { flip = w } } 42 w = w + 1 43 } 44 var t7: i64 = 0 45 if flip > 0 { if flip <= 32 { t7 = 1 } } 46 gv_check("T7 a real compute-weight CROSSOVER exists (below it sequential, at/above it parallel)" as *u8, t7, ctr) 47 // and below the crossover it is sequential, at it parallel -- the decision is a clean step, not noise 48 var t8: i64 = 1 49 if flip > 0 { if qp_choose(40, flip - 1, 4) != QP_SEQ { t8 = 0 } if qp_choose(40, flip, 4) != QP_PAR { t8 = 0 } } else { t8 = 0 } 50 gv_check("T8 the crossover is a clean step: cw=flip-1 sequential, cw=flip parallel" as *u8, t8, ctr) 51 52 // ---- the constants are DATA (conf-driven), not baked ----------------------------------------- 53 // conf-driven: seed a sentinel default; if the conf is present the read must differ from the sentinel 54 var t9: i64 = 0 55 let probe: i64 = qp_conf("scan_us_per_mrow" as *u8, 0 - 999) 56 if probe != (0 - 999) { if probe > 0 { t9 = 1 } } 57 gv_check("T9 the scan-cost constant is READ from analyst_qplan.conf (not a code literal)" as *u8, t9, ctr) 58 59 let rc: i64 = gv_verdict("QPLAN-GATE" as *u8, ctr, "cost-based planner picks sequential vs parallel matching the measured bench, with a real crossover, from data-driven constants" as *u8) 60 sys_exit(rc) 61 return rc 62}