code wiki / (root) / nx_arena_reset_probe.nx

nx_arena_reset_probe.nx source

↩ module page · 84 lines · 4219 B

1// nx_arena_reset_probe.nx -- bite-proof that sys_arena_mark/sys_arena_reset ACTUALLY RECLAIM memory 2// (not merely run). MEASURED, not asserted: read this process's own VmRSS from /proc/self/status at 3// three points -- after warmup+mark, after allocating many small chunks (RSS must RISE), and after 4// reset+re-churn (RSS must NOT double). A reset that returns 1 but frees nothing is the exact failure 5// this catches. license_tier: ORIGINAL No hw writes (Rule 26). 6import "nx_syscalls.nx" 7import "nx_gate_verdict.nx" 8const K_MAGIC_8192: i64 = 8192 9const K_MAGIC_8191: i64 = 8191 10const K_MAGIC_1024: i64 = 1024 11const K_MAGIC_16000: i64 = 16000 12const K_MAGIC_48000: i64 = 48000 13 14func ap_vmrss() -> i64 { 15 let fd: i64 = sys_openat_rd("/proc/self/status" as *u8) 16 if fd < 0 { return 0 - 1 } 17 let buf: *u8 = sys_mmap(K_MAGIC_8192) 18 var t: i64 = 0 19 var r: i64 = 1 20 while r > 0 { r = sys_read(fd, ((buf as i64) + t) as *u8, K_MAGIC_8191 - t); if r > 0 { t = t + r } } 21 sys_close(fd) 22 let key: *u8 = "VmRSS:" as *u8 23 let kl: i64 = 6 24 var i: i64 = 0 25 var at: i64 = 0 - 1 26 while i + kl <= t { 27 var j: i64 = 0; var hit: i64 = 1 28 while j < kl { if buf[i+j] != key[j] { hit = 0; j = kl } else { j = j + 1 } } 29 if hit == 1 { at = i + kl; i = t } else { i = i + 1 } 30 } 31 if at < 0 { return 0 - 1 } 32 var sp: i64 = 1 33 while sp == 1 { if at >= t { sp = 0 } else { let w: i64 = buf[at] as i64; if w == 32 { at = at + 1 } else { if w == 9 { at = at + 1 } else { sp = 0 } } } } // skip TAB and space (/proc uses a tab after the colon) 34 var v: i64 = 0; var d: i64 = 0 35 var pr: i64 = 1 36 while pr == 1 { if at >= t { pr = 0 } else { let c: i64 = buf[at] as i64; if c < 48 { pr = 0 } else { if c > 57 { pr = 0 } else { v = v*10 + (c-48); d = d+1; at = at+1 } } } } 37 if d == 0 { return 0 - 1 } 38 return v 39} 40 41func ap_churn(nbytes_total: i64) -> i64 { 42 var done: i64 = 0 43 var acc: i64 = 0 44 while done < nbytes_total { 45 let p: *u8 = sys_mmap(128) 46 p[0] = 1 as u8; p[64] = 1 as u8; p[127] = 1 as u8 47 acc = acc + (p[0] as i64) 48 done = done + 128 49 } 50 return acc 51} 52 53// simulate the daemon accept-loop: mark once, then N iterations of (reset; churn WITHIN the chunk-cap). 54// A reclaiming arena bounds RSS to ONE iteration's footprint; a leaking one grows by ~churn every 55// iteration. Churn 24MB/iter = 96 chunks, safely under NXA_CHUNKMAX(192) so no untracked overflow. 56func main() -> i64 { 57 let ctr: *i64 = gv_ctr() 58 gv_head("=== nx_arena_reset_probe -- daemon loop: mark, then N x (reset; churn); RSS must stay bounded ===" as *u8) 59 let iter_bytes: i64 = 24 * K_MAGIC_1024 * K_MAGIC_1024 60 // BASELINE-LEAK measurement: churn once WITHOUT reset to show the per-iteration cost is real. 61 sys_arena_mark() 62 let rss0: i64 = ap_vmrss() 63 ap_churn(iter_bytes) 64 let rss1: i64 = ap_vmrss() 65 let reset_rc: i64 = sys_arena_reset() 66 // Now the daemon pattern: 50 iterations of reset+churn. A leak would add 50*24MB = 1.2GB. 67 var it: i64 = 0 68 while it < 50 { sys_arena_reset(); ap_churn(iter_bytes); it = it + 1 } 69 let rssN: i64 = ap_vmrss() 70 sys_arena_reset() 71 72 gv_puts(" rss_after_mark_kb=" as *u8); gv_num(rss0); gv_puts(" rss_after_1churn_kb=" as *u8); gv_num(rss1); gv_puts(" rss_after_50_reset_churn_kb=" as *u8); gv_num(rssN); gv_puts(" (a LEAK would be ~1.2GB here)\n" as *u8) 73 74 gv_check("reset returned 1 (mark existed)" as *u8, reset_rc, ctr) 75 var grew: i64 = 0; if rss1 - rss0 > K_MAGIC_16000 { grew = 1 } 76 gv_check("one churn cost >16MB RSS (per-iteration allocation is real, not a no-op)" as *u8, grew, ctr) 77 // THE LOAD-BEARING TOOTH: 50 reset+churn iterations stayed within ~48MB of a SINGLE churn -- 78 // i.e. footprint is bounded by ~2 iterations, not 50. A non-reclaiming arena fails here by ~1.15GB. 79 var bounded: i64 = 0; if rssN - rss1 < K_MAGIC_48000 { bounded = 1 } 80 gv_check("50 reset+churn iterations stayed bounded (<48MB over one churn, not +1.2GB)" as *u8, bounded, ctr) 81 let rc: i64 = gv_verdict("ARENA-RESET-PROBE" as *u8, ctr, "mark/reset bounds a daemon accept-loop's resident footprint" as *u8) 82 sys_exit(rc) 83 return rc 84}