code wiki / _hdl_build / nx_uiq_perf.nx
nx_uiq_perf.nx source
↩ module page · 157 lines · 7273 B
1// nx_uiq_perf.nx -- CLI: DETERMINISTIC Core-Web-Vitals STATIC predictor (the quantitative guardrail).
2// Computes, from a page's source, the render-path costs that CWV field metrics punish -- WITHOUT a render:
3// * render-blocking external stylesheets (<link rel=stylesheet>, not preload) -> delays FCP/LCP
4// * render-blocking scripts (<script src> without async/defer) -> blocks parse, hurts INP/TBT
5// * unsized media (<img>/<video> missing width or height) -> CLS risk (>0.1 fails)
6// * page source weight (bytes) -> transfer proxy
7// Reuses the nx_uiq_* family lib (DRY: io + syscalls) -- the second consumer of nx_uiq_color, growing the family.
8// usage: nx_uiq_perf --kat | <html-file-path> -> JSON {bytes,blocking_css,blocking_js,unsized_media,issues,verdict}
9// HONEST ENVELOPE: STATIC predictors of LCP<=2.5s / INP<=200ms / CLS<=0.1 (web.dev/vitals, p75). Measured
10// LCP/INP/CLS + Speed Index need a real render + field RUM (browser-lane / CDP). This flags the source-visible
11// causes; a PASS here is necessary, not sufficient. license_tier: ORIGINAL expect_exit: 0
12import "nx_uiq_color.nx"
13const K_MAGIC_2097152: i64 = 2097152
14
15// substring present in buf[a..b)?
16func perf_has_in(buf: *u8, a: i64, b: i64, pat: *u8) -> i64 {
17 var pl: i64=0; while pat[pl]!=(0 as u8) { pl=pl+1 }
18 if pl==0 { return 0 }
19 var i: i64=a
20 while i+pl<=b {
21 var j: i64=0; var ok: i64=1
22 while j<pl { if buf[a+ (i-a) +j]!=pat[j] { ok=0; j=pl } else { j=j+1 } }
23 if ok==1 { return 1 }
24 i=i+1
25 }
26 return 0
27}
28// index of the next '>' at/after off (tag end), bounded by n.
29func perf_tagend(buf: *u8, n: i64, off: i64) -> i64 {
30 var i: i64=off; var run: i64=1
31 while run==1 { if i<n { if buf[i]==(62 as u8) { run=0 } else { i=i+1 } } else { run=0 } }
32 return i
33}
34// count <img> tags missing width= or height= (CLS risk).
35func perf_unsized_img(buf: *u8, n: i64) -> i64 {
36 var c: i64=0; var i: i64=0
37 while i+4<n {
38 var hit: i64=0
39 if buf[i]==(60 as u8) { if buf[i+1]==(105 as u8) { if buf[i+2]==(109 as u8) { if buf[i+3]==(103 as u8) { hit=1 } } } }
40 if hit==1 {
41 let e: i64 = perf_tagend(buf,n,i+4)
42 var sized: i64=1
43 if perf_has_in(buf,i+4,e,"width" as *u8)==0 { sized=0 }
44 if perf_has_in(buf,i+4,e,"height" as *u8)==0 { sized=0 }
45 if sized==0 { c=c+1 }
46 i=e
47 } else { i=i+1 }
48 }
49 return c
50}
51// count render-blocking <script src=...> (external, no async/defer).
52func perf_blocking_js(buf: *u8, n: i64) -> i64 {
53 var c: i64=0; var i: i64=0
54 while i+7<n {
55 var hit: i64=0
56 if buf[i]==(60 as u8) { if buf[i+1]==(115 as u8) { if buf[i+2]==(99 as u8) { if buf[i+3]==(114 as u8) { if buf[i+4]==(105 as u8) { if buf[i+5]==(112 as u8) { if buf[i+6]==(116 as u8) { hit=1 } } } } } } }
57 if hit==1 {
58 let e: i64 = perf_tagend(buf,n,i+7)
59 if perf_has_in(buf,i+7,e,"src" as *u8)==1 {
60 var blk: i64=1
61 if perf_has_in(buf,i+7,e,"async" as *u8)==1 { blk=0 }
62 if perf_has_in(buf,i+7,e,"defer" as *u8)==1 { blk=0 }
63 if blk==1 { c=c+1 }
64 }
65 i=e
66 } else { i=i+1 }
67 }
68 return c
69}
70// count render-blocking external stylesheets: <link ... stylesheet ...> (not preload).
71func perf_blocking_css(buf: *u8, n: i64) -> i64 {
72 var c: i64=0; var i: i64=0
73 while i+5<n {
74 var hit: i64=0
75 if buf[i]==(60 as u8) { if buf[i+1]==(108 as u8) { if buf[i+2]==(105 as u8) { if buf[i+3]==(110 as u8) { if buf[i+4]==(107 as u8) { hit=1 } } } } }
76 if hit==1 {
77 let e: i64 = perf_tagend(buf,n,i+5)
78 if perf_has_in(buf,i+5,e,"stylesheet" as *u8)==1 {
79 if perf_has_in(buf,i+5,e,"preload" as *u8)==0 { c=c+1 }
80 }
81 i=e
82 } else { i=i+1 }
83 }
84 return c
85}
86
87// audit -> emits JSON when emit=1; returns the count of CWV-critical issues (blocking_css+blocking_js+unsized).
88func perf_audit(buf: *u8, n: i64, emit: i64) -> i64 {
89 let bc: i64 = perf_blocking_css(buf,n)
90 let bj: i64 = perf_blocking_js(buf,n)
91 let um: i64 = perf_unsized_img(buf,n)
92 let issues: i64 = bc + bj + um
93 if emit==1 {
94 uiq_w("{\"bytes\":" as *u8); uiq_pn(n)
95 uiq_w(",\"blocking_css\":" as *u8); uiq_pn(bc)
96 uiq_w(",\"blocking_js\":" as *u8); uiq_pn(bj)
97 uiq_w(",\"unsized_media\":" as *u8); uiq_pn(um)
98 uiq_w(",\"issues\":" as *u8); uiq_pn(issues)
99 uiq_w(",\"verdict\":\"" as *u8)
100 if issues==0 { uiq_w("PASS" as *u8) } else { uiq_w("FLAG" as *u8) }
101 uiq_w("\"}\n" as *u8)
102 }
103 return issues
104}
105
106// self-test: proves each counter on fixtures with a KNOWN answer (non-vacuous + no false positive).
107func uiq_perf_selftest() -> i64 {
108 var f: i64=0
109 // blocking CSS: one stylesheet link + one preload -> exactly 1
110 let a: *u8 = "<link rel=\"stylesheet\" href=\"a.css\"><link rel=\"preload\" as=\"style\" href=\"b.css\">" as *u8
111 var an: i64=0; while a[an]!=(0 as u8) { an=an+1 }
112 if perf_blocking_css(a,an)!=1 { f=f+1 }
113 // blocking JS: one plain src + one deferred + one inline -> exactly 1
114 let b: *u8 = "<script src=\"x.js\"></script><script src=\"y.js\" defer></script><script>1</script>" as *u8
115 var bn: i64=0; while b[bn]!=(0 as u8) { bn=bn+1 }
116 if perf_blocking_js(b,bn)!=1 { f=f+1 }
117 // unsized img: one bare + one sized -> exactly 1
118 let c: *u8 = "<img src=\"a.png\"><img src=\"b.png\" width=\"10\" height=\"10\">" as *u8
119 var cn: i64=0; while c[cn]!=(0 as u8) { cn=cn+1 }
120 if perf_unsized_img(c,cn)!=1 { f=f+1 }
121 // NEG-CONTROL: inline-css, no ext, no img -> 0 issues (perf-optimal by construction)
122 let d: *u8 = "<style>body{color:#000}</style><p>hi</p>" as *u8
123 var dn: i64=0; while d[dn]!=(0 as u8) { dn=dn+1 }
124 if perf_audit(d,dn,0)!=0 { f=f+1 }
125 return f
126}
127
128func perf_slurp(path: *u8, buf: *u8, cap: i64) -> i64 {
129 let fd: i64 = sys_openat_rd(path)
130 if fd<0 { return 0 }
131 var total: i64=0
132 var nrd: i64=sys_read(fd, buf, cap)
133 while nrd>0 { total=total+nrd; if total>=cap { nrd=0 } else { nrd=sys_read(fd, ((buf as i64)+total) as *u8, cap-total) } }
134 sys_close(fd)
135 return total
136}
137
138func main(argc: i64, argv: *i64) -> i64 {
139 if argc>=2 {
140 let a1: *u8 = argv[1] as *u8
141 if a1[0]==(45 as u8) {
142 uiq_w("=== nx_uiq_perf --kat (static Core-Web-Vitals predictor) ===\n" as *u8)
143 let f: i64 = uiq_perf_selftest()
144 uiq_w("checks failed=" as *u8); uiq_pn(f); uiq_w(" (blocking-css + blocking-js + unsized-img + neg-control)\n" as *u8)
145 if f==0 { uiq_w("VERDICT=GREEN\n" as *u8); sys_exit(0); return 0 }
146 uiq_w("VERDICT=RED\n" as *u8); sys_exit(1); return 1
147 }
148 let cap: i64 = K_MAGIC_2097152
149 let buf: *u8 = sys_mmap(cap)
150 let n: i64 = perf_slurp(a1, buf, cap)
151 if n<=0 { uiq_w("{\"error\":\"cannot read page\"}\n" as *u8); sys_exit(2); return 2 }
152 perf_audit(buf, n, 1)
153 sys_exit(0); return 0
154 }
155 uiq_w("usage: nx_uiq_perf --kat | <html-file-path>\n" as *u8)
156 sys_exit(2); return 2
157}