code wiki / _hdl_build / nx_eff_lib.nx
nx_eff_lib.nx source
↩ module page · 346 lines · 15970 B
1// nx_eff_lib.nx -- THE efficiency-telemetry shared core (eff lane, 2026-07-18).
2// Operator: "know from god how we are spending energy and time and tokens ... ROI driven with
3// non-fake numbers but real estimates in time and money and energy and other savings."
4// This lib is the ONE measurement+conversion core imported by nx_eff_scan (the CLI substrate)
5// AND nx_eff_board (the ops/ROI dashboard) -- DRY (rule 15), so a spend number can never disagree
6// between the two. It MEASURES (worklog gaps=time, transcript needles=tokens) and CONVERTS via
7// DECLARED, operator-transparent coefficients (every rate emitted in the output; rule 11).
8// - cost(money): weighted-token basis-points x cents/Mtok (Anthropic pricing SHAPE: out 5x, cache-read
9// 0.1x, cache-write 1.25x vs uncached input 1x -- the multipliers are real; the base rate is declared).
10// - energy: total tokens x Wh/Mtok (ESTIMATE, flagged as a research/fetch target for real per-node RAPL).
11// - time: sum of inter-action gaps <= 300s (gap300-strict; idle beyond 5min is NOT counted as work).
12// Every number traces to a real artifact (worklog.tsv rows, transcript usage fields); fabrication is
13// structurally impossible (no artifact -> zero). license_tier: ORIGINAL No hw writes (Rule 26).
14import "nx_syscalls.nx"
15import "nx_eff_conv.nx"
16
17// ---- day-slot field layout (dayw[idx*ES_NF + f]); idx = nowday - rowday (0 = newest day) ----
18const ES_NF: i64 = 10 // fields per day slot
19const ES_F_ACT: i64 = 0 // actions
20const ES_F_MCP: i64 = 1 // mcp__ tool calls
21const ES_F_SH: i64 = 2 // shell (PowerShell/Bash)
22const ES_F_FILE: i64 = 3 // file ops (Read/Edit/Write/Grep/Glob)
23const ES_F_SEC: i64 = 4 // active seconds (gap300-strict)
24const ES_F_TIN: i64 = 5 // tokens input
25const ES_F_TOUT: i64 = 6 // tokens output
26const ES_F_TCR: i64 = 7 // cache-read tokens
27const ES_F_TCW: i64 = 8 // cache-write tokens
28const ES_F_TRF: i64 = 9 // transcript files touched this day
29// ---- envelope slots (env[]) ----
30const ES_ENV_SLOTS: i64 = 8
31const ES_E_TRUNC: i64 = 0 // transcripts that hit the per-file cap
32const ES_E_TRF: i64 = 1 // transcript files scanned
33const ES_E_TRB: i64 = 2 // transcript bytes read
34const ES_E_WLR: i64 = 3 // worklog rows parsed
35const ES_E_WLB: i64 = 4 // worklog bytes read
36// ---- window + caps ----
37const ES_WIN_MAX: i64 = 28
38const ES_WIN_DEF: i64 = 14
39const ES_CAP_WL: i64 = 33554432 // 32MiB worklog read cap
40const ES_CAP_TR: i64 = 33554432 // 32MiB per-transcript read cap
41const ES_GAP_CAP: i64 = 300 // active-time gap ceiling (s)
42const ES_DAYSEC: i64 = 86400
43const ES_TAB: i64 = 9
44const ES_NL: i64 = 10
45const ES_QUOTE: i64 = 34
46const ES_SPACE: i64 = 32
47const ES_ZERO: i64 = 48
48const ES_NINE: i64 = 57
49// money/energy coefficients + conversions now live in nx_eff_conv.nx (imported above; DRY, syscall-free).
50
51func es_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
52func es_eq(a: *u8, b: *u8) -> i64 {
53 var i: i64 = 0
54 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
55 if b[i] != (0 as u8) { return 0 }
56 return 1
57}
58func es_atoi(s: *u8) -> i64 {
59 var v: i64 = 0
60 var i: i64 = 0
61 while s[i] != (0 as u8) { let c: i64 = s[i] as i64; if c >= ES_ZERO { if c <= ES_NINE { v = v * 10 + (c - ES_ZERO) } } i = i + 1 }
62 return v
63}
64// bounded whole-file read (NOT sys_read_file: no 4GB reservation; rule-21 fork hygiene).
65// returns bytes (<=cap), -1 unopenable. Over-cap bumps env[ES_E_TRUNC].
66func es_read_bounded(path: *u8, buf: *u8, cap: i64, env: *i64) -> i64 {
67 let fd: i64 = sys_openat_rd(path)
68 if fd < 0 { return 0 - 1 }
69 var n: i64 = 0
70 var go: i64 = 1
71 while go == 1 {
72 if n >= cap { go = 0 } else {
73 let r: i64 = sys_read(fd, ((buf as i64) + n) as *u8, cap - n)
74 if r <= 0 { go = 0 } else { n = n + r }
75 }
76 }
77 if n >= cap {
78 let probe: *u8 = sys_mmap(16)
79 let r2: i64 = sys_read(fd, probe, 1)
80 if r2 > 0 { env[ES_E_TRUNC] = env[ES_E_TRUNC] + 1 }
81 }
82 sys_close(fd)
83 return n
84}
85func es_num_at(b: *u8, n: i64, pos: i64) -> i64 {
86 var v: i64 = 0
87 var i: i64 = pos
88 var go: i64 = 1
89 while go == 1 {
90 if i >= n { go = 0 } else {
91 let c: i64 = b[i] as i64
92 if c >= ES_ZERO { if c <= ES_NINE { v = v * 10 + (c - ES_ZERO); i = i + 1 } else { go = 0 } } else { go = 0 }
93 }
94 }
95 return v
96}
97func es_slice_pfx(b: *u8, a: i64, e: i64, s: *u8) -> i64 {
98 var k: i64 = 0
99 var p: i64 = a
100 while s[k] != (0 as u8) {
101 if p >= e { return 0 }
102 if b[p] != s[k] { return 0 }
103 p = p + 1
104 k = k + 1
105 }
106 return 1
107}
108func es_slice_eq(b: *u8, a: i64, e: i64, s: *u8) -> i64 {
109 if es_slice_pfx(b, a, e, s) == 0 { return 0 }
110 if es_len(s) != (e - a) { return 0 }
111 return 1
112}
113// match needle at pos; on hit skip spaces; return first value byte offset, else -1
114func es_match(b: *u8, n: i64, pos: i64, needle: *u8) -> i64 {
115 var k: i64 = 0
116 var p: i64 = pos
117 while needle[k] != (0 as u8) {
118 if p >= n { return 0 - 1 }
119 if b[p] != needle[k] { return 0 - 1 }
120 p = p + 1
121 k = k + 1
122 }
123 var go: i64 = 1
124 while go == 1 { if p >= n { go = 0 } else { if b[p] == (ES_SPACE as u8) { p = p + 1 } else { go = 0 } } }
125 return p
126}
127// newest epoch in the worklog (defines "today" deterministically from the data itself)
128func es_wl_maxepoch(b: *u8, n: i64) -> i64 {
129 var best: i64 = 0
130 var i: i64 = 0
131 while i < n {
132 var le: i64 = i
133 var s: i64 = 1
134 while s == 1 { if le >= n { s = 0 } else { if b[le] == (ES_NL as u8) { s = 0 } else { le = le + 1 } } }
135 if le > i { let e: i64 = es_num_at(b, n, i); if e > best { best = e } }
136 i = le + 1
137 }
138 return best
139}
140// accumulate per-day worklog fields (actions, mcp/shell/file classes, active-sec gap-strict)
141func es_wl_scan(b: *u8, n: i64, dayw: *i64, nowday: i64, win: i64, env: *i64) -> i64 {
142 var prev: i64 = 0
143 var i: i64 = 0
144 while i < n {
145 var le: i64 = i
146 var s: i64 = 1
147 while s == 1 { if le >= n { s = 0 } else { if b[le] == (ES_NL as u8) { s = 0 } else { le = le + 1 } } }
148 if le > i {
149 let e: i64 = es_num_at(b, n, i)
150 if e > 0 {
151 env[ES_E_WLR] = env[ES_E_WLR] + 1
152 let day: i64 = e / ES_DAYSEC
153 let idx: i64 = nowday - day
154 if idx >= 0 { if idx < win {
155 let base: i64 = idx * ES_NF
156 dayw[base] = dayw[base] + 1
157 var t1: i64 = i
158 var s1: i64 = 1
159 while s1 == 1 { if t1 >= le { s1 = 0 } else { if b[t1] == (ES_TAB as u8) { s1 = 0 } else { t1 = t1 + 1 } } }
160 var t2: i64 = t1 + 1
161 var s2: i64 = 1
162 while s2 == 1 { if t2 >= le { s2 = 0 } else { if b[t2] == (ES_TAB as u8) { s2 = 0 } else { t2 = t2 + 1 } } }
163 var t3: i64 = t2 + 1
164 var s3: i64 = 1
165 while s3 == 1 { if t3 >= le { s3 = 0 } else { if b[t3] == (ES_TAB as u8) { s3 = 0 } else { t3 = t3 + 1 } } }
166 if t2 < le {
167 let ts: i64 = t2 + 1
168 let te: i64 = t3
169 if es_slice_pfx(b, ts, te, "mcp__" as *u8) == 1 { dayw[base+1] = dayw[base+1] + 1 } else {
170 var issh: i64 = 0
171 if es_slice_eq(b, ts, te, "PowerShell" as *u8) == 1 { issh = 1 }
172 if es_slice_eq(b, ts, te, "Bash" as *u8) == 1 { issh = 1 }
173 if issh == 1 { dayw[base+2] = dayw[base+2] + 1 } else {
174 var isf: i64 = 0
175 if es_slice_eq(b, ts, te, "Read" as *u8) == 1 { isf = 1 }
176 if es_slice_eq(b, ts, te, "Edit" as *u8) == 1 { isf = 1 }
177 if es_slice_eq(b, ts, te, "Write" as *u8) == 1 { isf = 1 }
178 if es_slice_eq(b, ts, te, "Grep" as *u8) == 1 { isf = 1 }
179 if es_slice_eq(b, ts, te, "Glob" as *u8) == 1 { isf = 1 }
180 if isf == 1 { dayw[base+3] = dayw[base+3] + 1 }
181 }
182 }
183 }
184 if prev > 0 {
185 let g: i64 = e - prev
186 if g > 0 { if g <= ES_GAP_CAP { dayw[base+4] = dayw[base+4] + g } }
187 }
188 } }
189 prev = e
190 }
191 }
192 i = le + 1
193 }
194 return 0
195}
196// four usage-token needles into day fields 5..8, PER-LINE first-occurrence (dedup). A transcript line
197// records usage TWICE (message.usage + a duplicate top-level usage -- verified 611 double-lines in a real
198// transcript 2026-07-19), so a whole-buffer needle-sum DOUBLE-COUNTS. One-per-line (es_find_in) is the true
199// count and matches es_tr_tokens_bymodel. (leading-quote anchored -> cache_creation never matches "input_tokens").
200func es_tr_tokens(b: *u8, n: i64, dayw: *i64, base: i64) -> i64 {
201 var i: i64 = 0
202 while i < n {
203 var le: i64 = i
204 var s: i64 = 1
205 while s == 1 { if le >= n { s = 0 } else { if b[le] == (ES_NL as u8) { s = 0 } else { le = le + 1 } } }
206 if le > i {
207 let p1: i64 = es_find_in(b, i, le, "\x22input_tokens\x22:" as *u8)
208 if p1 >= 0 { dayw[base+5] = dayw[base+5] + es_num_at(b, le, p1) }
209 let p2: i64 = es_find_in(b, i, le, "\x22output_tokens\x22:" as *u8)
210 if p2 >= 0 { dayw[base+6] = dayw[base+6] + es_num_at(b, le, p2) }
211 let p3: i64 = es_find_in(b, i, le, "\x22cache_read_input_tokens\x22:" as *u8)
212 if p3 >= 0 { dayw[base+7] = dayw[base+7] + es_num_at(b, le, p3) }
213 let p4: i64 = es_find_in(b, i, le, "\x22cache_creation_input_tokens\x22:" as *u8)
214 if p4 >= 0 { dayw[base+8] = dayw[base+8] + es_num_at(b, le, p4) }
215 }
216 i = le + 1
217 }
218 return 0
219}
220// substring: does slice [a,e) of b contain s?
221func es_slice_has(b: *u8, a: i64, e: i64, s: *u8) -> i64 {
222 let sl: i64 = es_len(s)
223 if sl == 0 { return 0 }
224 var i: i64 = a
225 while i + sl <= e {
226 var k: i64 = 0
227 var ok: i64 = 1
228 while k < sl { if b[i+k] != s[k] { ok = 0; k = sl } else { k = k + 1 } }
229 if ok == 1 { return 1 }
230 i = i + 1
231 }
232 return 0
233}
234// classify a model-string slice [a,e) into a tier index (EFL_T_* from nx_eff_conv)
235func es_classify_model(b: *u8, a: i64, e: i64) -> i64 {
236 if es_slice_has(b, a, e, "fable" as *u8) == 1 { return EFL_T_FABLE }
237 if es_slice_has(b, a, e, "mythos" as *u8) == 1 { return EFL_T_FABLE }
238 if es_slice_has(b, a, e, "opus" as *u8) == 1 { return EFL_T_OPUS }
239 if es_slice_has(b, a, e, "sonnet" as *u8) == 1 { return EFL_T_SONNET }
240 if es_slice_has(b, a, e, "haiku" as *u8) == 1 { return EFL_T_HAIKU }
241 return EFL_T_OTHER
242}
243// find needle within [a,e); return offset AFTER the needle, or -1
244func es_find_in(b: *u8, a: i64, e: i64, needle: *u8) -> i64 {
245 let nl: i64 = es_len(needle)
246 if nl == 0 { return 0 - 1 }
247 var i: i64 = a
248 while i + nl <= e {
249 var k: i64 = 0
250 var ok: i64 = 1
251 while k < nl { if b[i+k] != needle[k] { ok = 0; k = nl } else { k = k + 1 } }
252 if ok == 1 { return i + nl }
253 i = i + 1
254 }
255 return 0 - 1
256}
257// per-LINE model+usage bucketing: modacc[tier*4 + class], class 0=in 1=out 2=cr 3=cw. A transcript message
258// carries ONE model + ONE usage on the same JSONL line, so per-line attribution is exact (leading-quote
259// anchored -> cache_creation_input_tokens never matches "input_tokens").
260func es_tr_tokens_bymodel(b: *u8, n: i64, modacc: *i64) -> i64 {
261 var i: i64 = 0
262 while i < n {
263 var le: i64 = i
264 var s: i64 = 1
265 while s == 1 { if le >= n { s = 0 } else { if b[le] == (ES_NL as u8) { s = 0 } else { le = le + 1 } } }
266 if le > i {
267 var tier: i64 = EFL_T_OTHER
268 let mp: i64 = es_find_in(b, i, le, "\x22model\x22:\x22" as *u8)
269 if mp >= 0 {
270 var qe: i64 = mp
271 var fnd: i64 = 0
272 while fnd == 0 { if qe >= le { fnd = 1 } else { if b[qe] == (ES_QUOTE as u8) { fnd = 1 } else { qe = qe + 1 } } }
273 tier = es_classify_model(b, mp, qe)
274 }
275 let base: i64 = tier * 4
276 let p1: i64 = es_find_in(b, i, le, "\x22input_tokens\x22:" as *u8)
277 if p1 >= 0 { modacc[base] = modacc[base] + es_num_at(b, le, p1) }
278 let p2: i64 = es_find_in(b, i, le, "\x22output_tokens\x22:" as *u8)
279 if p2 >= 0 { modacc[base+1] = modacc[base+1] + es_num_at(b, le, p2) }
280 let p3: i64 = es_find_in(b, i, le, "\x22cache_read_input_tokens\x22:" as *u8)
281 if p3 >= 0 { modacc[base+2] = modacc[base+2] + es_num_at(b, le, p3) }
282 let p4: i64 = es_find_in(b, i, le, "\x22cache_creation_input_tokens\x22:" as *u8)
283 if p4 >= 0 { modacc[base+3] = modacc[base+3] + es_num_at(b, le, p4) }
284 }
285 i = le + 1
286 }
287 return 0
288}
289func es_is_jsonl(name: *u8) -> i64 {
290 let n: i64 = es_len(name)
291 if n < 7 { return 0 }
292 let suf: *u8 = ".jsonl" as *u8
293 var k: i64 = 0
294 while k < 6 { if name[n - 6 + k] != suf[k] { return 0 } k = k + 1 }
295 return 1
296}
297// getdents64 walk of the transcript dir; per in-window .jsonl: bounded read + token needle scan
298func es_tr_scan(dir: *u8, tbuf: *u8, dayw: *i64, nowday: i64, win: i64, env: *i64, modacc: *i64) -> i64 {
299 let fd: i64 = sys_openat_rd(dir)
300 if fd < 0 { return 0 - 1 }
301 let gbuf: *u8 = sys_mmap(65536)
302 let stbuf: *u8 = sys_mmap(256)
303 let child: *u8 = sys_mmap(2048)
304 var nread: i64 = __syscall(217, fd, gbuf, 65536, 0, 0, 0)
305 while nread > 0 {
306 var off: i64 = 0
307 while off < nread {
308 let reclen: i64 = (gbuf[off + 16] as i64) | ((gbuf[off + 17] as i64) << 8)
309 if reclen <= 0 { off = nread } else {
310 let name: *u8 = ((gbuf as i64) + off + 19) as *u8
311 if es_is_jsonl(name) == 1 {
312 var co: i64 = 0
313 var di: i64 = 0
314 while dir[di] != (0 as u8) { child[co] = dir[di]; co = co + 1; di = di + 1 }
315 child[co] = 47 as u8
316 co = co + 1
317 var ci: i64 = 0
318 while name[ci] != (0 as u8) { child[co] = name[ci]; co = co + 1; ci = ci + 1 }
319 child[co] = 0 as u8
320 var mt: i64 = 0
321 if sys_fstatat(child, stbuf) == 0 {
322 mt = (stbuf[88] as i64) | ((stbuf[89] as i64) << 8) | ((stbuf[90] as i64) << 16) | ((stbuf[91] as i64) << 24) | ((stbuf[92] as i64) << 32) | ((stbuf[93] as i64) << 40)
323 }
324 let day: i64 = mt / ES_DAYSEC
325 let idx: i64 = nowday - day
326 if idx >= 0 { if idx < win {
327 let tn: i64 = es_read_bounded(child, tbuf, ES_CAP_TR, env)
328 if tn > 0 {
329 env[ES_E_TRF] = env[ES_E_TRF] + 1
330 env[ES_E_TRB] = env[ES_E_TRB] + tn
331 let base: i64 = idx * ES_NF
332 dayw[base+9] = dayw[base+9] + 1
333 es_tr_tokens(tbuf, tn, dayw, base)
334 es_tr_tokens_bymodel(tbuf, tn, modacc)
335 }
336 } }
337 }
338 off = off + reclen
339 }
340 }
341 nread = __syscall(217, fd, gbuf, 65536, 0, 0, 0)
342 }
343 sys_close(fd)
344 return 0
345}
346// conversions efl_* moved to nx_eff_conv.nx (imported at top; consumers get them transitively).