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}