code wiki / _hdl_build / nx_apm_collect.nx

nx_apm_collect.nx

buildroot/runtime/_hdl_build/nx_apm_collect.nx

21145 B349 linesdepth 5pulls 5 transitivereach 1 importersview sourcekind tooltopic apm
docsdependenciesstructsconstsfunctions

about

nx_apm_collect.nx -- SOVEREIGN NAS-side INTERNAL-HTTP concurrency collector (the hardware-up APM layer). WHY (the gap nx_apm_sweep cannot fill): nx_apm_sweep probes nishifamily.com over the FULL public TLS chain from the workstation. That is the right "what a browser sees" view, but each probe pays an ~800ms Nishi TLS handshake whose cost is CPU-bound on this 21-workstream-contended workstation, so conc>1 latency is handshake-noise, not server truth -> it cannot cleanly measure a daemon's CONCURRENCY health. This organ runs ON THE NAS (where the daemons live) and probes their plaintext loopback ports DIRECTLY over HTTP/1.1 with "Connection: close" -- no TLS, no contention -> the latency it measures IS the daemon. It fires `conc` SIMULTANEOUS cold probes per target (= conc browser tabs), with a per-probe SO_RCVTIMEO backstop so a truly-hung socket can never wedge the collector forever (rule #14, graceful degradation). It distinguishes GREEN / AMBER(stall>2s) / RED(timeout|err) / DOWN(connection refused) -- the last is the liar-kill: a daemon that is ABSENT must never read as healthy. Targets are DATA-DRIVEN (rule #11) from knowledge/status/apm_targets.tsv; results append to a durable time-series knowledge/status/apm_collect.tsv. Single responsibility (rule #9): HTTP latency/concurrency only. Per-daemon CPU/mem is nx_perf_sentinel's job already; the dashboard rung joins the two time-series. Proven by nx_apm_collect_gate (mock daemons). usage: nx_apm_collect (reads knowledge/status/apm_targets.tsv) license_tier: ORIGINAL

dependencies 2 imports · 1 importers

nx_syscalls.nx nx_connect.nx nx_apm_collect.nx nx_apm_collect_gate.nx

imports: nx_syscalls.nxnx_connect.nx

imported by: nx_apm_collect_gate.nx

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main sys_now_realtime_sec sys_mmap sys_clock_gettime_real ac_parse_ip sys_mmap ↻ ac_w sys_write ac_slen ac_wn sys_mmap ↻ ac_n sys_mmap ↻ sys_write ↻ ac_migrate_targets sys_openat_rd sys_close sys_mmap ↻ ac_read_small sys_openat_rd ↻ sys_read sys_close ↻ sys_mkdir ac_field ac_atoi ac_s ac_n ↻ sys_openat_wr sys_write ↻ sys_openat_append sys_mmap ↻ ac_read_small ↻ ac_s ↻ ac_kv_int ac_starts2 ac_kv_str ac_starts2 ↻ ac_burst sys_mmap_shared sys_mmap ↻

structs

none

consts

23const AC_MAGIC_65536: i64 = 65536
24const AC_MAGIC_1024: i64 = 1024
26const AC_STALL_MS: i64 = 2000
27const AC_TIMEOUT_S: i64 = 22 // > the measured ~20s :8791 wedge, so we still capture it
28const AC_TARGETS: *u8 = "knowledge/status/apm_targets.tsv"
29const AC_METRICS: *u8 = "knowledge/status/apm_collect.tsv"
32const AC_V_OK: i64 = 0
33const AC_V_SOCK: i64 = 1
34const AC_V_DOWN: i64 = 2 // connect refused -> daemon absent
35const AC_V_SEND: i64 = 3
36const AC_V_TIMEOUT: i64 = 4 // no bytes before SO_RCVTIMEO
39const AC_R_GREEN: i64 = 0
40const AC_R_AMBER: i64 = 1
41const AC_R_RED: i64 = 2
42const AC_R_DOWN: i64 = 3

functions

45func ac_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
called by 2: ac_wac_burst
46func ac_w(s: *u8) -> i64 { return sys_write(1, s, ac_slen(s)) }
called by 2: ac_burstmain calls 2: sys_writeac_slen
47func ac_atoi(s: *u8) -> i64
called by 1: ac_migrate_targets
53func ac_n(buf: *u8, off: i64, v: i64) -> i64
63func ac_s(buf: *u8, off: i64, s: *u8) -> i64 { var o: i64 = off; var i: i64 = 0; while s[i] != (0 as u8) { buf[o] = s[i]; o = o + 1; i = i + 1 } return o }
64func ac_wn(v: i64) -> i64 { let b: *u8 = sys_mmap(24); let e: i64 = ac_n(b, 0, v); return sys_write(1, b, e) }
called by 2: ac_burstmain calls 3: sys_mmapac_nsys_write
65func ac_wpad(v: i64, w: i64) -> i64
called by 1: ac_burst calls 3: sys_mmapac_nsys_write
70func ac_sort(a: *i64, n: i64) -> i64
called by 1: ac_burst
80func ac_addr(out: *u8, a: i64, b: i64, c: i64, d: i64, port: i64) -> i64
called by 1: ac_probe
88func ac_build_get(req: *u8, path: *u8) -> i64
called by 1: ac_probe calls 1: ac_s
95func ac_read_small(path: *u8, buf: *u8, cap: i64) -> i64
107func ac_field(buf: *u8, n: i64, pos: i64, out: *u8, outcap: i64, stop: *i64) -> i64
called by 1: ac_migrate_targets
126func ac_probe(port: i64, path: *u8, timeout_secs: i64, ip: i64, out: *i64) -> i64
156func ac_line_eq(buf: *u8, start: i64, end: i64, label: *u8) -> i64
called by 1: ac_seg_index
162func ac_seg_index(label: *u8) -> i64
171func ac_burst(port: i64, path: *u8, label: *u8, conc: i64, timeout_secs: i64, epoch: i64, ip: i64, out_stats: *i64) -> i64
254func ac_parse_ip(s: *u8) -> i64
called by 1: main calls 1: sys_mmap
266func ac_starts2(buf: *u8, ls: i64, end: i64, key: *u8) -> i64 { var m: i64=0; while key[m]!=(0 as u8) { if ls+m>=end { return 0 } if buf[ls+m]!=key[m] { return 0 } m=m+1 } return m }
called by 2: ac_kv_intac_kv_str
267func ac_kv_int(buf: *u8, n: i64, key: *u8) -> i64
called by 1: main calls 1: ac_starts2
274func ac_kv_str(buf: *u8, n: i64, key: *u8, out: *u8, outcap: i64) -> i64
called by 1: main calls 1: ac_starts2
282func ac_migrate_targets() -> i64
317func main(argc: i64, argv: *i64) -> i64