code wiki / (root) / nx_perf_pathology.nx

nx_perf_pathology.nx source

↩ module page · 219 lines · 9601 B

1// nx_perf_pathology.nx -- B1 first stone of NISHI_PERFORMANCE_ 2// DOCTRINE_ROADMAP.md. 3// 4// Sealed-enum taxonomy of performance pathologies + universal 5// classifier that takes a measured value, a reference band, and 6// auxiliary signals to classify the measurement into one of the 7// pathology classes. Composes ETG (E1 attestation, E2 tournament, 8// E2.5 Byzantine) -- a pathology classification becomes an 9// NxEtgEntry's `measurement_value` so downstream tournament + 10// agreement can operate on pathology classes the same way they 11// operate on raw measurement values. 12// 13// Composes: 14// [[NISHI_PERFORMANCE_DOCTRINE_ROADMAP]] B1 (this is the first stone) 15// nx_etg.nx (E1 attestation; classifier output becomes Entry data) 16// [[feedback-hardware-agnostic-is-robustness]] (cross-arch parity 17// required before "shipped") 18// [[feedback-conductor-heterogeneous-compute-no-second-class- 19// resources]] (P10 second-class pathology is the conductor 20// cardinal's failure mode) 21// [[feedback-reclamation-doctrine-captain-moroni]] (P11 paywall 22// pathology) 23// [[feedback-physical-truth-over-published-docs-silicon-empirical- 24// gamification]] (vendor-claim references vs empirical peak) 25// [[feedback-no-strawman-perf-comparisons]] (classifier requires 26// paired reference; never aspirational) 27// [[feedback-no-false-ok-substrate-honesty-audit]] (INCONCLUSIVE 28// verdict when inputs insufficient; never silent) 29 30// nx_safety_envelope: 31// intended_use: "performance-pathology classification: 32// measured value + reference + signals -> 33// NX_PERF_PATHOLOGY_* sealed enum; composes 34// nx_etg.nx attestation" 35// sil_target: SIL2 36// evidence: [kat_taxonomy_complete, 37// kat_optimal_band_classification, 38// kat_pathology_signature_detection] 39// hazard_register: [bug-tape-pathology-aliased-bits, 40// bug-tape-band-boundary-misclassification, 41// bug-tape-signal-missing-defaults-wrong] 42// verdict: NOT_YET_EVALUATED 43 44import "nx_syscalls.nx" 45 46// ===== Pathology sealed enum ====================================== 47// 48// Numbers reserved (no renumbering); future audits replay historical 49// pathology records. 50 51const NX_PERF_PATH_NONE: i64 = 0 52const NX_PERF_PATH_OPTIMAL: i64 = 1 // P0 -- at empirical peak 53const NX_PERF_PATH_BOTTLENECK_CPU: i64 = 2 // P1 54const NX_PERF_PATH_BOTTLENECK_MEM_BW: i64 = 3 // P2 55const NX_PERF_PATH_BOTTLENECK_MEM_LAT: i64 = 4 // P3 56const NX_PERF_PATH_BOTTLENECK_IO: i64 = 5 // P4 57const NX_PERF_PATH_BLEEDING_LEAKAGE: i64 = 6 // P5 58const NX_PERF_PATH_TOO_MANY_STEPS: i64 = 7 // P6 59const NX_PERF_PATH_TOO_FEW_STEPS: i64 = 8 // P7 60const NX_PERF_PATH_LATENCY_SPIKE: i64 = 9 // P8 -- tail latency 61const NX_PERF_PATH_THROUGHPUT_CLIFF: i64 = 10 // P9 62const NX_PERF_PATH_SECOND_CLASS_RESOURCE: i64 = 11 // P10 -- CUDA pattern 63const NX_PERF_PATH_VENDOR_PAYWALL_HONORED: i64 = 12 // P11 64const NX_PERF_PATH_SINGLE_ARCH_OVERFIT: i64 = 13 // P12 65const NX_PERF_PATH_INCONCLUSIVE: i64 = 14 // insufficient signals 66const NX_PERF_PATH_N: i64 = 15 67 68func nx_perf_path_is_valid(p: i64) -> i64 { 69 if p < 0 { return 0 } 70 if p >= NX_PERF_PATH_N { return 0 } 71 return 1 72} 73 74func nx_perf_path_name(p: i64) -> *u8 { 75 if p == NX_PERF_PATH_NONE { return "NONE" } 76 if p == NX_PERF_PATH_OPTIMAL { return "OPTIMAL" } 77 if p == NX_PERF_PATH_BOTTLENECK_CPU { return "BOTTLENECK_CPU" } 78 if p == NX_PERF_PATH_BOTTLENECK_MEM_BW { return "BOTTLENECK_MEM_BW" } 79 if p == NX_PERF_PATH_BOTTLENECK_MEM_LAT { return "BOTTLENECK_MEM_LAT" } 80 if p == NX_PERF_PATH_BOTTLENECK_IO { return "BOTTLENECK_IO" } 81 if p == NX_PERF_PATH_BLEEDING_LEAKAGE { return "BLEEDING_LEAKAGE" } 82 if p == NX_PERF_PATH_TOO_MANY_STEPS { return "TOO_MANY_STEPS" } 83 if p == NX_PERF_PATH_TOO_FEW_STEPS { return "TOO_FEW_STEPS" } 84 if p == NX_PERF_PATH_LATENCY_SPIKE { return "LATENCY_SPIKE" } 85 if p == NX_PERF_PATH_THROUGHPUT_CLIFF { return "THROUGHPUT_CLIFF" } 86 if p == NX_PERF_PATH_SECOND_CLASS_RESOURCE { return "SECOND_CLASS_RESOURCE" } 87 if p == NX_PERF_PATH_VENDOR_PAYWALL_HONORED { return "VENDOR_PAYWALL_HONORED" } 88 if p == NX_PERF_PATH_SINGLE_ARCH_OVERFIT { return "SINGLE_ARCH_OVERFIT" } 89 if p == NX_PERF_PATH_INCONCLUSIVE { return "INCONCLUSIVE" } 90 return "UNKNOWN" 91} 92 93// Does this pathology indicate the substrate is leaving silicon 94// or budget on the table? Returns 1 if so, 0 otherwise. 95// OPTIMAL = 0 (peak utilization). All other named pathologies 96// imply waste of some kind. INCONCLUSIVE = 0 (no determination). 97func nx_perf_path_is_waste(p: i64) -> i64 { 98 if p == NX_PERF_PATH_OPTIMAL { return 0 } 99 if p == NX_PERF_PATH_NONE { return 0 } 100 if p == NX_PERF_PATH_INCONCLUSIVE { return 0 } 101 return 1 102} 103 104// ===== Resource signal struct ===================================== 105// 106// Per-classification snapshot of resource utilization at measurement 107// time. Used by the classifier to distinguish bottleneck classes. 108// Each field is a unitless percentage in 0..100 (or -1 = "no signal"). 109 110struct NxPerfSignals { 111 cpu_pct: i64, // 0..100; -1 if unsignaled 112 mem_bw_pct: i64, // % of empirical RAM bandwidth ceiling 113 mem_lat_pct: i64, // % of RAM latency ceiling (higher = more pointer-chase) 114 io_pct: i64, // disk+network utilization % 115 gpu_pct: i64, // GPU utilization % 116 npu_pct: i64, // NPU utilization % 117 tail_p99_over_p50: i64, // p99/p50 ratio * 100 (200 = 2x; 1000 = 10x) 118 growth_pct_per_min: i64, // resource-footprint growth rate (% per minute) 119 isa_overfit_ratio: i64, // cross-arch perf-ratio * 100 (100 = parity; 1000 = 10x worse) 120 paywall_responsive: i64, // 1 if ETG probe found PAYWALLED_BUT_RESPONSIVE 121 second_class_idle_count: i64, // count of resources < 10% util while one > 90% 122} 123 124// Initialize signals to "no determination" (all -1, counts 0). 125func nx_perf_signals_init(s: *NxPerfSignals) { 126 s.cpu_pct = -1 127 s.mem_bw_pct = -1 128 s.mem_lat_pct = -1 129 s.io_pct = -1 130 s.gpu_pct = -1 131 s.npu_pct = -1 132 s.tail_p99_over_p50 = -1 133 s.growth_pct_per_min = -1 134 s.isa_overfit_ratio = -1 135 s.paywall_responsive = 0 136 s.second_class_idle_count = 0 137} 138 139// ===== Universal classifier ======================================= 140// 141// Given a NxPerfSignals snapshot + an "is the measurement within 142// optimal-band" boolean, classify the pathology. Decision tree 143// favors the strongest signal; ties broken by listed order. 144// 145// Pathology priority (highest to lowest) on tie: 146// 1. SINGLE_ARCH_OVERFIT (cross-arch failure trumps all) 147// 2. VENDOR_PAYWALL_HONORED (reclamation cardinal) 148// 3. SECOND_CLASS_RESOURCE (conductor cardinal) 149// 4. BLEEDING_LEAKAGE (growth_pct_per_min > 0) 150// 5. LATENCY_SPIKE (tail_p99_over_p50 >= 1000 = 10x) 151// 6. THROUGHPUT_CLIFF (encoded externally; not in signals) 152// 7. BOTTLENECK_* (CPU / MEM_BW / MEM_LAT / IO) 153// 8. TOO_MANY_STEPS / TOO_FEW_STEPS (encoded via in_optimal_band) 154// 9. OPTIMAL 155// 156// in_optimal_band: caller computes whether the bench's measured 157// value sits in the (lower, upper) empirical-peak band per the ETG 158// reference. 1 = inside; 0 = outside (slower than band) -- the 159// caller is responsible for the band per workload. 160// 161// Returns one of NX_PERF_PATH_*. 162 163func nx_perf_classify(s: *NxPerfSignals, in_optimal_band: i64) -> i64 { 164 // 1. Cross-arch parity check (highest priority -- robustness gate) 165 if s.isa_overfit_ratio > 200 { 166 return NX_PERF_PATH_SINGLE_ARCH_OVERFIT 167 } 168 169 // 2. Paywall honored (reclamation cardinal) 170 if s.paywall_responsive == 1 { 171 return NX_PERF_PATH_VENDOR_PAYWALL_HONORED 172 } 173 174 // 3. Second-class resource (conductor cardinal) 175 if s.second_class_idle_count >= 2 { 176 return NX_PERF_PATH_SECOND_CLASS_RESOURCE 177 } 178 179 // 4. Bleeding leakage 180 if s.growth_pct_per_min > 0 { 181 return NX_PERF_PATH_BLEEDING_LEAKAGE 182 } 183 184 // 5. Latency spike 185 if s.tail_p99_over_p50 >= 1000 { 186 return NX_PERF_PATH_LATENCY_SPIKE 187 } 188 189 // 6. Bottleneck classification (one resource saturated >= 90% 190 // while measurement misses the optimal band) 191 if in_optimal_band == 0 { 192 if s.cpu_pct >= 90 { 193 return NX_PERF_PATH_BOTTLENECK_CPU 194 } 195 if s.mem_bw_pct >= 90 { 196 return NX_PERF_PATH_BOTTLENECK_MEM_BW 197 } 198 if s.mem_lat_pct >= 90 { 199 return NX_PERF_PATH_BOTTLENECK_MEM_LAT 200 } 201 if s.io_pct >= 90 { 202 return NX_PERF_PATH_BOTTLENECK_IO 203 } 204 // Out of optimal band with no resource saturated -- algorithmic 205 // pathology. Distinguish TOO_FEW_STEPS (slow algorithm) from 206 // TOO_MANY_STEPS (slow due to redundant work) requires a 207 // tournament comparison (B3 rung). For B1 the classifier 208 // returns TOO_FEW_STEPS as the safer default; B3 refines. 209 return NX_PERF_PATH_TOO_FEW_STEPS 210 } 211 212 // 7. In optimal band + no waste signals: OPTIMAL 213 if in_optimal_band == 1 { 214 return NX_PERF_PATH_OPTIMAL 215 } 216 217 // 8. Inputs insufficient 218 return NX_PERF_PATH_INCONCLUSIVE 219}