code wiki / _hdl_build / nx_resmon.nx

nx_resmon.nx source

↩ module page · 134 lines · 7449 B

1// nx_resmon.nx -- the RESOURCE axis the health plane never had (debt seq897 / seq1005). 2// 3// WHY THIS EXISTS: on 2026-07-25 nx_health returned {overall:OK, degraded:0, down:0} while the box was 4// at 93.4% swap exhaustion with nr_vmscan_immediate_reclaim 1.33e9 -- sustained thrash. The health plane 5// probes GATEWAYS ONLY, so the single most destabilising condition on the platform was invisible to 6// every instrument we owned. 7// LAW: an instrument that reports OK during the worst outage class it could ever see is not an instrument. 8// 9// TWO AXES: 10// A. PRESSURE -- swap consumed / memory available. A LAGGING indicator: by the time it is red the 11// box is already thrashing. 12// B. LEAK CENSUS -- processes whose VmSize == VmPeak above a COMMITTED-memory floor. A LEADING 13// indicator: it fires while swap is still healthy. This is the fingerprint that 14// identified the leaking organs in the first place. 15// 16// This organ owns the /proc walk and the printing ONLY. Both policy predicates live in nx_resmon_lib.nx 17// so the gate exercises the SAME code this runs (rule 9 single responsibility, rule 15 DRY). 18// Thresholds are data-driven from knowledge/status/resmon.conf (rule 11). Read-only. 19// Exit code IS the verdict so a caller can gate on it: 0=GREEN 1=AMBER 2=RED. 20// 21// license_tier: ORIGINAL expect_exit: 0 22import "nx_resmon_lib.nx" 23import "nx_proc_ctl.nx" 24const RM_MAGIC_262144: i64 = 262144 25 26const RM_DIRBUF: i64 = 65536 27const RM_STATBUF: i64 = 4096 28 29func main() -> i64 { 30 let cbuf: *u8 = sys_mmap(RM_STATBUF) 31 let cn: i64 = rm_read("knowledge/status/resmon.conf" as *u8, cbuf, RM_STATBUF) 32 let sw_amber: i64 = rm_conf(cbuf, cn, "swap-used-permil-amber" as *u8, 700) 33 let sw_red: i64 = rm_conf(cbuf, cn, "swap-used-permil-red" as *u8, 850) 34 let av_amber: i64 = rm_conf(cbuf, cn, "mem-avail-permil-amber" as *u8, 250) 35 let av_red: i64 = rm_conf(cbuf, cn, "mem-avail-permil-red" as *u8, 100) 36 let leak_min: i64 = rm_conf(cbuf, cn, "leak-min-kb" as *u8, RM_MAGIC_262144) 37 let leak_amber: i64 = rm_conf(cbuf, cn, "leak-count-amber" as *u8, 3) 38 let leak_red: i64 = rm_conf(cbuf, cn, "leak-count-red" as *u8, 6) 39 40 // ---- AXIS A: pressure ---- 41 let mbuf: *u8 = sys_mmap(RM_STATBUF) 42 let mn: i64 = rm_read("/proc/meminfo" as *u8, mbuf, RM_STATBUF) 43 let memtotal: i64 = rm_field(mbuf, mn, "MemTotal:" as *u8) 44 let memavail: i64 = rm_field(mbuf, mn, "MemAvailable:" as *u8) 45 let swtotal: i64 = rm_field(mbuf, mn, "SwapTotal:" as *u8) 46 let swfree: i64 = rm_field(mbuf, mn, "SwapFree:" as *u8) 47 var swused_pm: i64 = 0 48 if swtotal > 0 { swused_pm = ((swtotal - swfree) * 1000) / swtotal } 49 var avail_pm: i64 = 1000 50 if memtotal > 0 { avail_pm = (memavail * 1000) / memtotal } 51 52 // ---- AXIS B: leak census ---- 53 let dbuf: *u8 = sys_mmap(RM_DIRBUF) 54 let path: *u8 = sys_mmap(256) 55 let sbuf: *u8 = sys_mmap(RM_STATBUF) 56 var leakers: i64 = 0 57 var worst_kb: i64 = 0 58 let worst_nm: *u8 = sys_mmap(64) 59 worst_nm[0] = 63 as u8 60 worst_nm[1] = 0 as u8 61 let fd: i64 = sys_openat_rd("/proc" as *u8) 62 if fd >= 0 { 63 var run: i64 = 1 64 while run == 1 { 65 let n: i64 = sys_getdents64(fd, dbuf, RM_DIRBUF) 66 if n <= 0 { run = 0 } else { 67 var off: i64 = 0 68 while off < n { 69 let rec: *u8 = ((dbuf as i64) + off) as *u8 70 let reclen: i64 = dirent_reclen(rec) 71 if reclen <= 0 { off = n } else { 72 let nm: *u8 = dirent_name(rec) 73 if nm[0] >= (48 as u8) { if nm[0] <= (57 as u8) { 74 var p: i64 = 0 75 let pre: *u8 = "/proc/" as *u8 76 var a: i64 = 0 77 while pre[a] != (0 as u8) { path[p] = pre[a]; p = p + 1; a = a + 1 } 78 a = 0 79 while nm[a] != (0 as u8) { path[p] = nm[a]; p = p + 1; a = a + 1 } 80 let suf: *u8 = "/status" as *u8 81 a = 0 82 while suf[a] != (0 as u8) { path[p] = suf[a]; p = p + 1; a = a + 1 } 83 path[p] = 0 as u8 84 let sn: i64 = rm_read(path, sbuf, RM_STATBUF) 85 if sn > 0 { 86 let vsz: i64 = rm_field(sbuf, sn, "VmSize:" as *u8) 87 let vpk: i64 = rm_field(sbuf, sn, "VmPeak:" as *u8) 88 let vrs: i64 = rm_field(sbuf, sn, "VmRSS:" as *u8) 89 let vsw: i64 = rm_field(sbuf, sn, "VmSwap:" as *u8) 90 if rm_is_leaker(vsz, vpk, vrs, vsw, leak_min) == 1 { 91 leakers = leakers + 1 92 var touched: i64 = 0 93 if vrs > 0 { touched = touched + vrs } 94 if vsw > 0 { touched = touched + vsw } 95 if touched > worst_kb { 96 worst_kb = touched 97 // /proc/<pid>/status opens with "Name:\t<comm>\n", so the comm 98 // starts at byte 6 and ends at the first newline. 99 var z: i64 = 6 100 var w: i64 = 0 101 while z < sn { if sbuf[z] == (10 as u8) { z = sn } else { if w < 62 { worst_nm[w] = sbuf[z]; w = w + 1 } z = z + 1 } } 102 worst_nm[w] = 0 as u8 103 } 104 } 105 } 106 } } 107 off = off + reclen 108 } 109 } 110 } 111 } 112 sys_close(fd) 113 } 114 115 let sev: i64 = rm_verdict(swused_pm, avail_pm, leakers, sw_amber, sw_red, av_amber, av_red, leak_amber, leak_red) 116 117 rm_puts("=== nx_resmon -- the resource axis nx_health lacks (seq897) ===\n" as *u8) 118 rm_puts("swap_used_permil=" as *u8); rm_num(swused_pm) 119 rm_puts(" (amber>=" as *u8); rm_num(sw_amber); rm_puts(" red>=" as *u8); rm_num(sw_red); rm_puts(")\n" as *u8) 120 rm_puts("mem_avail_permil=" as *u8); rm_num(avail_pm) 121 rm_puts(" (amber<=" as *u8); rm_num(av_amber); rm_puts(" red<=" as *u8); rm_num(av_red); rm_puts(")\n" as *u8) 122 rm_puts("swap_total_kb=" as *u8); rm_num(swtotal); rm_puts(" swap_free_kb=" as *u8); rm_num(swfree); rm_puts("\n" as *u8) 123 rm_puts("mem_total_kb=" as *u8); rm_num(memtotal); rm_puts(" mem_avail_kb=" as *u8); rm_num(memavail); rm_puts("\n" as *u8) 124 rm_puts("leak_suspects=" as *u8); rm_num(leakers) 125 rm_puts(" (VmSize==VmPeak and RSS+Swap>=" as *u8); rm_num(leak_min); rm_puts("kB; amber>=" as *u8); rm_num(leak_amber) 126 rm_puts(" red>=" as *u8); rm_num(leak_red); rm_puts(")\n" as *u8) 127 rm_puts("worst_committed_kb=" as *u8); rm_num(worst_kb); rm_puts(" worst=" as *u8); rm_puts(worst_nm); rm_puts("\n" as *u8) 128 rm_puts("verdict=" as *u8) 129 if sev == 0 { rm_puts("GREEN" as *u8) } 130 if sev == 1 { rm_puts("AMBER" as *u8) } 131 if sev == 2 { rm_puts("RED" as *u8) } 132 rm_puts(" sev=" as *u8); rm_num(sev); rm_puts("\n" as *u8) 133 return sev 134}