nx_select_test.nx source
↩ module page · 189 lines · 8445 B
1// nx_select_test.nx -- smoke for nx_select SA-4 MVP.
2//
3// Exercises six scenarios across the selection pipeline:
4// 1. Empty input -> NX_SEL_BAD_INPUT
5// 2. Single candidate that fits -> returns that index
6// 3. Two candidates, one's ISA mask excludes the host -> picks the fit
7// 4. Two candidates both fit, different cost -> picks lower cost
8// 5. Policy weight swap (throughput vs energy) flips selection
9// 6. Tier filter (variant requires HPC, host is LAPTOP) -> filtered out
10//
11// SA-4 verification gate per NISHI_SELF_ASSEMBLY_ROADMAP.md ยง8:
12// "picks variants A on hardware H_A and B on H_B with both smokes
13// passing on their respective hosts" -- demonstrated in code by
14// synthesizing probes for both hosts and asserting different
15// selections.
16
17import "nx_syscalls.nx"
18import "nx_probe.nx"
19import "nx_calibrate.nx"
20import "nx_select.nx"
21
22// Helper: build a probe record stamped with a given ISA + endianness.
23// Bypasses nx_probe_run (which would witness the actual host); the
24// test treats the probe as a SYNTHETIC INPUT to the selector.
25
26func _make_probe(isa: i64) -> *NxProbeRecord {
27 let p: *NxProbeRecord = nx_probe_new()
28 p.actual_isa_family = isa
29 p.actual_endianness = NX_ENDIAN_LITTLE
30 p.actual_pointer_width_bits = 64
31 p.actual_page_size_bytes = 4096
32 p.actual_mmap_works = 1
33 p.actual_write_works = 1
34 p.actual_mono_clock_works = 1
35 p.actual_mono_clock_resolution_ns = 100
36 return p
37}
38
39func main() -> i64 {
40 // ----- 1. Empty input -----
41 let probe_rv64: *NxProbeRecord = _make_probe(NX_ISA_RV64)
42 let policy_t: *NxPolicy = nx_policy_throughput_default()
43 let empty_ptrs: *i64 = (sys_mmap(8)) as *i64
44 let rc_empty: i64 = nx_select(empty_ptrs, 0, probe_rv64,
45 NX_TIER_INF_LAPTOP, 1048576, 0, policy_t)
46 if rc_empty != NX_SEL_BAD_INPUT { return 1 }
47
48 // ----- 2. Single candidate that fits -----
49 let m_rv64_only: *NxManifest = nx_manifest_new(
50 100, // variant_class
51 1001, // variant_id
52 nx_isa_bit(NX_ISA_RV64), // requires_isa_mask
53 0, // requires_isa_ext_mask
54 4096, // requires_ram_min_b
55 NX_TIER_INF_MOBILE, // tier_floor
56 NX_TIER_INF_HPC, // tier_ceiling
57 1024, 1024, 1024, 1024) // cost coefs (all 1.0 Q10)
58 let one_ptrs: *i64 = (sys_mmap(8)) as *i64
59 one_ptrs[0] = m_rv64_only as i64
60 let rc_one: i64 = nx_select(one_ptrs, 1, probe_rv64,
61 NX_TIER_INF_LAPTOP, 1048576, 0, policy_t)
62 if rc_one != 0 { return 2 }
63
64 // ----- 3. Two candidates, ISA-mismatch one excluded -----
65 let m_x86_only: *NxManifest = nx_manifest_new(
66 100, 1002,
67 nx_isa_bit(NX_ISA_X86_64), // ONLY x86_64 -- excluded on RV64 host
68 0, 4096,
69 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
70 512, 512, 512, 512) // cheaper than rv64_only, but blocked
71 let two_ptrs: *i64 = (sys_mmap(16)) as *i64
72 two_ptrs[0] = m_x86_only as i64
73 two_ptrs[1] = m_rv64_only as i64
74 let rc_isa: i64 = nx_select(two_ptrs, 2, probe_rv64,
75 NX_TIER_INF_LAPTOP, 1048576, 0, policy_t)
76 if rc_isa != 1 { return 3 } // index 1 = rv64_only
77
78 // Cross-host gate: same two candidates on an x86_64 probe should
79 // select index 0 (x86_only) because RV64-only is excluded there.
80 let probe_x86: *NxProbeRecord = _make_probe(NX_ISA_X86_64)
81 let rc_cross: i64 = nx_select(two_ptrs, 2, probe_x86,
82 NX_TIER_INF_LAPTOP, 1048576, 0, policy_t)
83 if rc_cross != 0 { return 4 } // host-dependent selection
84
85 // ----- 4. Two compatible variants, lower cost wins -----
86 let m_both_cheap: *NxManifest = nx_manifest_new(
87 100, 2001,
88 nx_isa_bit(NX_ISA_RV64) | nx_isa_bit(NX_ISA_X86_64),
89 0, 4096,
90 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
91 100, 100, 100, 100) // cheap across all axes
92 let m_both_expensive: *NxManifest = nx_manifest_new(
93 100, 2002,
94 nx_isa_bit(NX_ISA_RV64) | nx_isa_bit(NX_ISA_X86_64),
95 0, 4096,
96 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
97 10000, 10000, 10000, 10000)
98 let cost_ptrs: *i64 = (sys_mmap(16)) as *i64
99 cost_ptrs[0] = m_both_expensive as i64
100 cost_ptrs[1] = m_both_cheap as i64
101 let rc_cost: i64 = nx_select(cost_ptrs, 2, probe_rv64,
102 NX_TIER_INF_LAPTOP, 1048576, 0, policy_t)
103 if rc_cost != 1 { return 5 } // cheap variant wins regardless of order
104
105 // ----- 5. Policy axis swap flips selection -----
106 // m_fast_high_energy: low compute cost, high energy cost
107 // m_slow_low_energy: high compute cost, low energy cost
108 // throughput-policy picks fast; energy-policy picks low-energy.
109 let m_fast_high_energy: *NxManifest = nx_manifest_new(
110 100, 3001,
111 nx_isa_bit(NX_ISA_RV64) | nx_isa_bit(NX_ISA_X86_64),
112 0, 4096,
113 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
114 100, // cheap flops
115 500, 500,
116 10000) // expensive energy
117 let m_slow_low_energy: *NxManifest = nx_manifest_new(
118 100, 3002,
119 nx_isa_bit(NX_ISA_RV64) | nx_isa_bit(NX_ISA_X86_64),
120 0, 4096,
121 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
122 5000, // expensive flops
123 500, 500,
124 100) // cheap energy
125 let pol_ptrs: *i64 = (sys_mmap(16)) as *i64
126 pol_ptrs[0] = m_fast_high_energy as i64
127 pol_ptrs[1] = m_slow_low_energy as i64
128 let rc_throughput: i64 = nx_select(pol_ptrs, 2, probe_rv64,
129 NX_TIER_INF_LAPTOP, 1048576, 0,
130 nx_policy_throughput_default())
131 if rc_throughput != 0 { return 6 } // throughput-weighted picks fast
132
133 let rc_energy: i64 = nx_select(pol_ptrs, 2, probe_rv64,
134 NX_TIER_INF_LAPTOP, 1048576, 0,
135 nx_policy_energy_default())
136 if rc_energy != 1 { return 7 } // energy-weighted picks low-energy
137
138 // ----- 6. Tier filter excludes too-rich variant -----
139 let m_hpc_only: *NxManifest = nx_manifest_new(
140 100, 4001,
141 nx_isa_bit(NX_ISA_RV64) | nx_isa_bit(NX_ISA_X86_64),
142 0, 4096,
143 NX_TIER_INF_HPC, NX_TIER_INF_HPC, // HPC only
144 50, 50, 50, 50)
145 let m_anywhere: *NxManifest = nx_manifest_new(
146 100, 4002,
147 nx_isa_bit(NX_ISA_RV64) | nx_isa_bit(NX_ISA_X86_64),
148 0, 4096,
149 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
150 500, 500, 500, 500)
151 let tier_ptrs: *i64 = (sys_mmap(16)) as *i64
152 tier_ptrs[0] = m_hpc_only as i64
153 tier_ptrs[1] = m_anywhere as i64
154 // Host inferred as LAPTOP -- hpc_only excluded; anywhere wins.
155 let rc_tier_laptop: i64 = nx_select(tier_ptrs, 2, probe_rv64,
156 NX_TIER_INF_LAPTOP, 1048576, 0,
157 policy_t)
158 if rc_tier_laptop != 1 { return 8 }
159 // Host inferred as HPC -- hpc_only fits (and is cheaper); wins.
160 let rc_tier_hpc: i64 = nx_select(tier_ptrs, 2, probe_rv64,
161 NX_TIER_INF_HPC, 1048576, 0,
162 policy_t)
163 if rc_tier_hpc != 0 { return 9 }
164
165 // ----- 7. No candidates fit -> NONE_MATCH -----
166 let only_hpc_ptrs: *i64 = (sys_mmap(8)) as *i64
167 only_hpc_ptrs[0] = m_hpc_only as i64
168 let rc_none: i64 = nx_select(only_hpc_ptrs, 1, probe_rv64,
169 NX_TIER_INF_LAPTOP, 1048576, 0, policy_t)
170 if rc_none != NX_SEL_NONE_MATCH { return 10 }
171
172 // ----- 8. RAM filter -----
173 let m_big_ram: *NxManifest = nx_manifest_new(
174 100, 5001,
175 nx_isa_bit(NX_ISA_RV64),
176 0,
177 16777216, // 16 MiB required
178 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
179 50, 50, 50, 50)
180 let big_ptrs: *i64 = (sys_mmap(8)) as *i64
181 big_ptrs[0] = m_big_ram as i64
182 let rc_ram_short: i64 = nx_select(big_ptrs, 1, probe_rv64,
183 NX_TIER_INF_LAPTOP,
184 4096, // only 4 KiB available
185 0, policy_t)
186 if rc_ram_short != NX_SEL_NONE_MATCH { return 11 }
187
188 return 0
189}