nx_placement_test.nx source
↩ module page · 143 lines · 5075 B
1// nx_placement_test.nx -- smoke for nx_placement.nx.
2//
3// Two test classes:
4// A) Lazy lifecycle: build a synthetic Q8_0 block in a buffer;
5// create lazy NxPlacedTensor; verify storage_bytes==0 + is_live==0;
6// materialize; verify is_live==1, storage_bytes>0, values match;
7// demote; verify is_live==0; re-materialize; verify values match.
8// B) Owned: wrap a pre-built NxTensor; verify is_live==1 + storage
9// reflects it; demote refuses (NX_PT_ERR_BAD_PLACEMENT).
10
11import "nx_syscalls.nx"
12import "nx_tier.nx"
13import "nx_le.nx"
14import "nx_tensor.nx"
15import "nx_gguf.nx"
16import "nx_placement.nx"
17
18func main() -> i64 {
19 // ----- Verdict gate -----
20 var vi: nx_int = 0
21 while vi < NX_PT_N_VERDICTS {
22 if nx_pt_verdict_is_valid(vi) != 1 { return 5 + vi }
23 vi = vi + 1
24 }
25 var vp: nx_int = 0
26 while vp < NX_PLACE_N {
27 if nx_place_is_valid(vp) != 1 { return 10 + vp }
28 vp = vp + 1
29 }
30
31 // ----- A) Lazy lifecycle with Q8_0 source -----
32 //
33 // Build a 34-byte Q8_0 block at buffer offset 0:
34 // f16 scale at byte 0: 0.5 (0x3800) -> scale_q10 = 512
35 // int8 values at byte 2: qs[i] = i
36 // Dequant expected: out[i] = 512 * i.
37 let buf: *u8 = sys_mmap(64)
38 nx_le_write_u16(buf, 0, 0x3800)
39 var qi: nx_int = 0
40 while qi < 32 {
41 buf[2 + qi] = qi
42 qi = qi + 1
43 }
44
45 let shape: *i64 = sys_mmap(1 * 8) as *i64
46 shape[0] = 32
47 let lazy_p: *NxPlacedTensor = nx_placed_tensor_new_lazy(
48 buf, 0, NX_GGML_TYPE_Q8_0, 32, shape, 1)
49
50 if lazy_p.placement != NX_PLACE_MMAP { return 30 }
51 if nx_placed_tensor_is_live(lazy_p) != 0 { return 31 }
52 if nx_placed_tensor_storage_bytes(lazy_p) != 0 { return 32 }
53 if lazy_p.src_n_values != 32 { return 33 }
54 if lazy_p.src_ggml_type != NX_GGML_TYPE_Q8_0 { return 34 }
55 if lazy_p.shape_0 != 32 { return 35 }
56
57 // Materialize.
58 let v_m: nx_int = nx_placed_tensor_materialize(lazy_p)
59 if v_m != NX_PT_OK { return 40 + v_m }
60 if nx_placed_tensor_is_live(lazy_p) != 1 { return 50 }
61 if nx_placed_tensor_storage_bytes(lazy_p) != 32 * 8 { return 51 }
62
63 // Verify values.
64 let p1: *i64 = lazy_p.t.storage as *i64
65 var ki: nx_int = 0
66 while ki < 32 {
67 if p1[ki] != 512 * ki { return 60 + ki }
68 ki = ki + 1
69 }
70
71 // Materializing again is rejected (already live).
72 let v_m2: nx_int = nx_placed_tensor_materialize(lazy_p)
73 if v_m2 != NX_PT_ERR_ALREADY_LIVE { return 100 }
74
75 // Demote.
76 let v_d: nx_int = nx_placed_tensor_demote(lazy_p)
77 if v_d != NX_PT_OK { return 110 + v_d }
78 if nx_placed_tensor_is_live(lazy_p) != 0 { return 120 }
79 if nx_placed_tensor_storage_bytes(lazy_p) != 0 { return 121 }
80
81 // Demoting again is rejected (already lazy).
82 let v_d2: nx_int = nx_placed_tensor_demote(lazy_p)
83 if v_d2 != NX_PT_ERR_NOT_LIVE { return 130 }
84
85 // Re-materialize (idempotent contract).
86 let v_m3: nx_int = nx_placed_tensor_materialize(lazy_p)
87 if v_m3 != NX_PT_OK { return 140 + v_m3 }
88 let p2: *i64 = lazy_p.t.storage as *i64
89 var kj: nx_int = 0
90 while kj < 32 {
91 if p2[kj] != 512 * kj { return 150 + kj }
92 kj = kj + 1
93 }
94
95 // ----- B) Owned wrapper -----
96 //
97 // Build a real NxTensor; wrap it as OWNED; verify lifecycle
98 // semantics differ (demote refused).
99 let sh: *i64 = sys_mmap(1 * 8) as *i64
100 sh[0] = 4
101 let err: *i64 = sys_mmap(8) as *i64
102 err[0] = 0
103 let raw_t: *NxTensor = nx_t_alloc(NX_DT_I64, sh, 1, err)
104 if err[0] != 0 { return 200 }
105 let pt: *i64 = raw_t.storage as *i64
106 pt[0] = 11; pt[1] = 22; pt[2] = 33; pt[3] = 44
107
108 let owned_p: *NxPlacedTensor = nx_placed_tensor_new_owned(raw_t)
109 if owned_p.placement != NX_PLACE_OWNED { return 210 }
110 if nx_placed_tensor_is_live(owned_p) != 1 { return 211 }
111 if nx_placed_tensor_storage_bytes(owned_p) != 4 * 8 { return 212 }
112 if owned_p.shape_0 != 4 { return 213 }
113
114 let v_dem_owned: nx_int = nx_placed_tensor_demote(owned_p)
115 if v_dem_owned != NX_PT_ERR_BAD_PLACEMENT { return 220 }
116
117 // On-demand get returns the live tensor without re-materializing.
118 let got: *NxTensor = nx_placed_tensor_get(owned_p)
119 if got != raw_t { return 230 }
120
121 // For lazy: nx_placed_tensor_get works even on a fresh lazy --
122 // it triggers materialization automatically. Build a fresh
123 // lazy + call get + verify.
124 let buf2: *u8 = sys_mmap(64)
125 nx_le_write_u16(buf2, 0, 0x3800)
126 var qi2: nx_int = 0
127 while qi2 < 32 {
128 buf2[2 + qi2] = qi2
129 qi2 = qi2 + 1
130 }
131 let shape2: *i64 = sys_mmap(8) as *i64
132 shape2[0] = 32
133 let lazy2: *NxPlacedTensor = nx_placed_tensor_new_lazy(
134 buf2, 0, NX_GGML_TYPE_Q8_0, 32, shape2, 1)
135 if nx_placed_tensor_is_live(lazy2) != 0 { return 240 }
136 let auto_t: *NxTensor = nx_placed_tensor_get(lazy2)
137 if auto_t == (0 as *NxTensor) { return 241 }
138 if nx_placed_tensor_is_live(lazy2) != 1 { return 242 }
139 let pa: *i64 = auto_t.storage as *i64
140 if pa[5] != 512 * 5 { return 243 }
141
142 return 0
143}