nx_leak_check_lib.nx
buildroot/runtime/nx_leak_check_lib.nx
about
nx_leak_check_lib.nx -- FLEET LEAK-HEALTH CERTIFIER, library half. The operator's vision: the organs are
a family/community that must be TRULY HEALTHY, health PROVEN with real math, not asserted.
★A LEAK IS NOT "MONOTONE" AND NOT "A CLEAN LINE." A real leak -- like a water leak -- is VARIABLE, bursty,
intermittent, accelerating; the invariant is that the resource TRENDS UP over time amid the variation and
never returns to baseline (consumption that disappears). So the verdict is grounded in the environmental-
science trend toolkit (the same statistics hydrologists use for streamflow/groundwater trend + leak
detection), computed over a TIME SERIES of N samples -- never 2 points, never a linear-fit R2 that a
jagged leak would fail:
QUALITATIVE = MANN-KENDALL trend test (non-parametric, SIGN-based): S = sum over i<j of sign(x_j-x_i).
Detects a significant upward trend even when the data is noisy/variable. Significance via
the exact integer variance Var(S)=n(n-1)(2n+5)/18 vs a one-sided z=1.645 (95%) bar.
QUANTITATIVE = THEIL-SEN estimator: the MEDIAN of all pairwise slopes (x_j-x_i)/(t_j-t_i). A robust leak
RATE (kB/min) immune to outlier bursts (a spike moves the mean, not the median).
LEAK iff MK says "significant upward trend" AND Theil-Sen rate >= a magnitude floor. Direction AND rate.
All INTEGER (no-float doctrine). Pure stat funcs are gate-proven on SYNTHETIC series incl a variable leak.
Reuses the portable seams (nx_os_proc pid-enum + nx_vsz_watchdog_core VmSize read) -> couplings=0, portable.
license_tier: ORIGINAL
dependencies 3 imports · 2 importers
imports: nx_syscalls.nxnx_os_proc.nxnx_vsz_watchdog_core.nx
imported by: nx_leak_check.nxnx_leak_check_gate.nx
structs
| none |
consts
| 23 | const LC_NAME_CAP: i64 = 256 // argv0 / pid-string buffer |
| 24 | const LC_DEC: i64 = 10 |
| 25 | const LC_ASCII_0: i64 = 48 |
| 26 | const LC_SLASH: i64 = 47 // '/' |
| 27 | const LC_PTR_CELL: i64 = 16 // 2-i64 timespec scratch |
| 28 | const LC_MS_PER_S: i64 = 1000 |
| 29 | const LC_NS_PER_MS: i64 = 1000000 |
| 30 | const LC_MS_PER_MIN: i64 = 60000 // Theil-Sen slope units: kB per minute |
| 32 | const LC_MKV_2: i64 = 2 // the '2' in (2n+5) and the pair/median divisor |
| 33 | const LC_MKV_5: i64 = 5 // the '5' in (2n+5) |
| 34 | const LC_MKV_DEN: i64 = 18 // the /18 in Var(S) |
| 35 | const LC_Z2_X1000: i64 = 2706 // (1.645)^2 x 1000 -- one-sided 95% significance bar for MK |
| 36 | const LC_TAU_SCALE: i64 = 1000 // Kendall tau reported in permille |
| 38 | const LC_RATE_MIN: i64 = 64 // kB/min: Theil-Sen median slope must exceed this to matter (leak floor) |
| 39 | const LC_MIN_N: i64 = 3 // minimum samples for a meaningful trend |
| 40 | const LC_WARMUP: i64 = 1 // drop the first sample (startup transient) before analysis |
| 41 | const LC_SPIKE_MAD_X1000: i64 = 4448 // Hampel 3-sigma-equiv: excursion > 4.4478*MAD (1.4826*3) = a spike |
| 42 | const LC_SPIKE_ABS_MIN: i64 = 256 // kB: a spike must ALSO be materially large (flat-series noise != spike) |
| 43 | const LC_FD_RATE_MIN: i64 = 2 // fd/min: a sustained +2 fd/min descriptor climb is a leak |
| 44 | const LC_FD_SPIKE_MIN: i64 = 16 // fds: a spike must be at least this many descriptors |
| 45 | const LC_LEVEL_OFF: i64 = 0 // level_max sentinel: sustained-high-level check DISABLED (level = baseline = R3) |
| 47 | const LC_UTIL_SCALE: i64 = 1000000 // util_permille = delta_ticks * SCALE / (HZ * dt_ms) |
| 48 | const LC_CPU_RATE_MIN: i64 = 200 // util permille/min: an ACCELERATING burn (worsening busy-loop) |
| 49 | const LC_CPU_SPIKE_MIN: i64 = 500 // util permille: a compute burst (half a core in one interval) |
| 50 | const LC_CPU_BURN_MAX: i64 = 500 // util permille: SUSTAINED median >= half a core = busy-loop (power disappearing) |
| 51 | const LC_CHURN_PERMILLE: i64 = 300 // MAD/median >= 30% (robust CV) = thrashing = CHURN (inefficient, off the racing line) |
| 52 | const LC_MAD_FLOOR: i64 = 1 // avoid divide-by-zero when the series is dead-flat |
| 54 | const LC_A_HEALTHY: i64 = 0 // on the racing line: flat baseline, bounded, no trend |
| 55 | const LC_A_LEAK: i64 = 1 // sustained/variable upward trend (resource never returned) -- CRITICAL |
| 56 | const LC_A_SPIKE: i64 = 2 // transient outlier excursion (a "reverse leak": bursts up then returns) |
| 57 | const LC_A_CHURN: i64 = 3 // high relative volatility (thrashing / inefficient design) |
| 59 | const LC_O_TAU: i64 = 0 // Kendall tau permille (trend direction/consistency) |
| 60 | const LC_O_RATE: i64 = 1 // Theil-Sen rate kB/min (leak magnitude) |
| 61 | const LC_O_MEDIAN: i64 = 2 // robust center kB |
| 62 | const LC_O_MAD: i64 = 3 // median absolute deviation kB (robust spread/volatility) |
| 63 | const LC_O_PEAK: i64 = 4 // peak upward excursion above median kB |
| 64 | const LC_O_CODE: i64 = 5 // LC_A_* |
| 65 | const LC_O_SLOTS: i64 = 6 |
| 67 | const LC_HEALTHY: i64 = 0 |
| 68 | const LC_LEAK: i64 = 1 |
| 69 | const LC_O_VERDICT: i64 = 5 // == LC_O_CODE |
functions
| 71 | func lc_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } |
| 74 | func lc_now_ms() -> i64 |
| 82 | func lc_itoa(v: i64, out: *u8) -> i64 |
| 95 | func lc_vsz(pid: i64) -> i64 |
| 103 | func lc_rss(pid: i64) -> i64 |
| 111 | func lc_ends(s: *u8, suf: *u8) -> i64 |
| 119 | func lc_is_organ(argv0: *u8) -> i64 { return lc_ends(argv0, ".elf" as *u8) } |
| 120 | func lc_basename(path: *u8, out: *u8) -> i64 |
| 133 | func lc_sign(a: i64, b: i64) -> i64 { if b > a { return 1 } if b < a { return 0 - 1 } return 0 } called by 1: lc_mk_s |
| 137 | func lc_mk_s(xs: *i64, xoff: i64, n: i64) -> i64 |
| 148 | func lc_mk_tau_permille(s: i64, n: i64) -> i64 |
| 155 | func lc_mk_sig_up(s: i64, n: i64) -> i64 |
| 163 | func lc_sort(a: *i64, m: i64) -> i64 |
| 179 | func lc_theil_sen(xs: *i64, xoff: i64, ts: *i64, toff: i64, n: i64, scratch: *i64) -> i64 |
| 196 | func lc_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } called by 1: lc_mad |
| 202 | func lc_row_valid(xs: *i64, off: i64, n: i64) -> i64 |
| 207 | func lc_max(xs: *i64, off: i64, n: i64) -> i64 called by 1: lc_classify_t |
| 213 | func lc_median(xs: *i64, off: i64, n: i64, scratch: *i64) -> i64 |
| 221 | func lc_mad(xs: *i64, off: i64, n: i64, med: i64, scratch: *i64) -> i64 |
| 234 | func lc_classify_t(xs: *i64, xoff: i64, ts: *i64, toff: i64, n_total: i64, scratch: *i64, out: *i64, rate_min: i64, spike_abs_min: i64, level_max: i64) -> i64 called by 3: mainmainlc_classify calls 7: lc_medianlc_madlc_maxlc_mk_slc_theil_senlc_mk_tau_permille+1 |
| 269 | func lc_classify(xs: *i64, xoff: i64, ts: *i64, toff: i64, n_total: i64, scratch: *i64, out: *i64) -> i64 |