code wiki / _hdl_build / nx_measure_cost_test.nx
nx_measure_cost_test.nx source
↩ module page · 85 lines · 3381 B
1// nx_measure_cost_test.nx -- the optimizer's cost model from MEASURED REALITY, not
2// a datasheet. The Seed spores onto hardware and TIMES the actual operations
3// (rdtsc cycle counter) to learn THIS machine's real costs -- so a slow/damaged/
4// asymmetric unit is reflected and the optimizer targets the hardware's true
5// limits. (A board with a crippled divider measures div as expensive and the loop
6// routes around it; a board with fast mul measures that and uses it.)
7//
8// Universal-reality invariant (true on every real CPU): integer DIV >> MUL >= ADD.
9// We MEASURE it here -- the relative costs become the optimizer's cost table.
10// Known answer (FAIL LOUD on the ordering, not exact cycles which vary): exit 0
11// iff measured div_cost > mul_cost AND mul_cost >= add_cost.
12
13import "nx_syscalls.nx"
14
15const MC_ITERS: i64 = 2000000
16
17// time a tight loop of ADDs; returns cycles. acc is fed back + consumed so the
18// op cannot be optimized away.
19func mc_time_add(seed: i64) -> i64 {
20 let t0: i64 = __rdtsc()
21 var acc: i64 = seed
22 var i: i64 = 0
23 while i < MC_ITERS { acc = acc + i; i = i + 1 }
24 let t1: i64 = __rdtsc()
25 if acc == 0 - 1 { sys_write(1, "" as *u8, 0) } // consume acc
26 return t1 - t0
27}
28func mc_time_mul(seed: i64) -> i64 {
29 let t0: i64 = __rdtsc()
30 var acc: i64 = seed | 1
31 var i: i64 = 0
32 while i < MC_ITERS { acc = acc * 3; acc = acc | 1; i = i + 1 }
33 let t1: i64 = __rdtsc()
34 if acc == 0 - 1 { sys_write(1, "" as *u8, 0) }
35 return t1 - t0
36}
37func mc_time_div(seed: i64) -> i64 {
38 let t0: i64 = __rdtsc()
39 var acc: i64 = 1000000007
40 var i: i64 = 0
41 while i < MC_ITERS { acc = acc / 3; acc = acc + 1000000007; i = i + 1 }
42 let t1: i64 = __rdtsc()
43 if acc == 0 - 1 { sys_write(1, "" as *u8, 0) }
44 return t1 - t0
45}
46
47func _emit(name: *u8, v: i64) -> i64 {
48 var n: i64 = 0; while name[n] != (0 as u8) { n = n + 1 } sys_write(1, name, n)
49 let b: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m }
50 let t: *u8 = sys_mmap(28); var k: i64 = 0
51 if m == 0 { t[0] = 48; k = 1 }
52 while m > 0 { t[k] = 48 + (m % 10); m = m / 10; k = k + 1 }
53 var i: i64 = 0; while i < k { b[i] = t[k - 1 - i]; i = i + 1 }
54 b[k] = 10; sys_write(1, b, k + 1); return 0
55}
56
57func main() -> i64 {
58 // warm up, then measure (best-of-3 to reduce scheduler noise).
59 var ca: i64 = mc_time_add(7)
60 var cm: i64 = mc_time_mul(7)
61 var cd: i64 = mc_time_div(7)
62 var r: i64 = 0
63 while r < 2 {
64 let a2: i64 = mc_time_add(7); if a2 < ca { ca = a2 }
65 let m2: i64 = mc_time_mul(7); if m2 < cm { cm = m2 }
66 let d2: i64 = mc_time_div(7); if d2 < cd { cd = d2 }
67 r = r + 1
68 }
69
70 sys_write(1, "MEASURED hardware cost (cycles for " as *u8, 35)
71 _emit(" iters):" as *u8, MC_ITERS)
72 _emit(" ADD = " as *u8, ca)
73 _emit(" MUL = " as *u8, cm)
74 _emit(" DIV = " as *u8, cd)
75 // normalized to ADD (the optimizer's measured cost table)
76 if ca > 0 {
77 _emit(" rel MUL/ADD x100 = " as *u8, (cm * 100) / ca)
78 _emit(" rel DIV/ADD x100 = " as *u8, (cd * 100) / ca)
79 }
80
81 // FAIL LOUD on the reality ordering (cycles vary; the ORDER is universal).
82 if cd <= cm { sys_exit(1); return 1 } // div must be the slowest -> route around it
83 if cm < ca { sys_exit(2); return 2 } // mul at least as costly as add
84 sys_exit(0); return 0
85}