nx_gguf_load_test.nx source
↩ module page · 164 lines · 6372 B
1// nx_gguf_load_test.nx -- smoke for nx_gguf_load.nx.
2//
3// Builds a synthetic GGUF blob in memory with two tensors:
4// tensor[0] "score" : F32 shape [2,2] = {1.0, 2.0, 0.5, -1.0}
5// tensor[1] "weight" : Q8_0 shape [32] scale=0.5, qs={0,1,2,...,31}
6// => values {0, 0.5, 1.0, ..., 15.5}
7//
8// Verifies:
9// - parse + name lookup + not-found verdict
10// - format-helper bytes/values per block + total bytes
11// - f32 → Q10 unit conversions on canonical bit patterns
12// - f16 → Q10 unit conversions on canonical bit patterns
13// - end-to-end load + dequant for F32 and Q8_0
14
15import "nx_syscalls.nx"
16import "nx_tier.nx"
17import "nx_le.nx"
18import "nx_tensor.nx"
19import "nx_gguf.nx"
20import "nx_gguf_load.nx"
21
22func main() -> i64 {
23 // ----- Build synthetic GGUF -----
24 let buf: *u8 = sys_mmap(1024)
25
26 // Header magic "GGUF" LE
27 buf[0] = 0x47; buf[1] = 0x47; buf[2] = 0x55; buf[3] = 0x46
28 buf[4] = 3; buf[5] = 0; buf[6] = 0; buf[7] = 0
29 nx_le_write_u64(buf, 8, 2)
30 nx_le_write_u64(buf, 16, 0)
31
32 // tensor[0] "score" F32 [2,2]
33 nx_le_write_u64(buf, 24, 5)
34 buf[32] = 0x73; buf[33] = 0x63; buf[34] = 0x6F; buf[35] = 0x72; buf[36] = 0x65
35 nx_le_write_u32(buf, 37, 2)
36 nx_le_write_u64(buf, 41, 2)
37 nx_le_write_u64(buf, 49, 2)
38 nx_le_write_u32(buf, 57, NX_GGML_TYPE_F32)
39 nx_le_write_u64(buf, 61, 0)
40
41 // tensor[1] "weight" Q8_0 [32]
42 let t1_off: i64 = 69
43 nx_le_write_u64(buf, t1_off + 0, 6)
44 buf[t1_off + 8 + 0] = 0x77
45 buf[t1_off + 8 + 1] = 0x65
46 buf[t1_off + 8 + 2] = 0x69
47 buf[t1_off + 8 + 3] = 0x67
48 buf[t1_off + 8 + 4] = 0x68
49 buf[t1_off + 8 + 5] = 0x74
50 nx_le_write_u32(buf, t1_off + 14, 1)
51 nx_le_write_u64(buf, t1_off + 18, 32)
52 nx_le_write_u32(buf, t1_off + 26, NX_GGML_TYPE_Q8_0)
53 nx_le_write_u64(buf, t1_off + 30, 16)
54 // End of tensor_info at offset = t1_off + 38 = 107.
55 // data_off = align_up(107, 32) = 128.
56
57 // ----- Write tensor data -----
58 let data_off: i64 = 128
59 // F32 score values
60 nx_le_write_u32(buf, data_off + 0, 0x3F800000) // 1.0
61 nx_le_write_u32(buf, data_off + 4, 0x40000000) // 2.0
62 nx_le_write_u32(buf, data_off + 8, 0x3F000000) // 0.5
63 nx_le_write_u32(buf, data_off + 12, 0xBF800000) // -1.0
64
65 // Q8_0 block: f16 scale + 32 int8 values
66 let q8_off: i64 = data_off + 16
67 nx_le_write_u16(buf, q8_off + 0, 0x3800) // f16 0.5
68 var qi: nx_int = 0
69 while qi < 32 {
70 buf[q8_off + 2 + qi] = qi
71 qi = qi + 1
72 }
73
74 // ----- Parse the header -----
75 let hdr_p: *NxGgufHeader = sys_mmap(NX_GGUF_HDR_BYTES) as *NxGgufHeader
76 let v_parse: nx_int = nx_gguf_parse(buf, 1024, hdr_p)
77 if v_parse != NX_GGUF_OK { return 10 + v_parse }
78 if hdr_p.n_tensors != 2 { return 19 }
79 if hdr_p.data_off != 128 { return 18 }
80
81 // ----- Verdict-range gate -----
82 var vi: nx_int = 0
83 while vi < NX_GL_N_VERDICTS {
84 if nx_gl_verdict_is_valid(vi) != 1 { return 20 + vi }
85 vi = vi + 1
86 }
87
88 // ----- find_tensor + not-found -----
89 let score_name: *u8 = sys_mmap(5)
90 score_name[0] = 0x73; score_name[1] = 0x63; score_name[2] = 0x6F
91 score_name[3] = 0x72; score_name[4] = 0x65
92 if nx_gguf_find_tensor(hdr_p, score_name, 5) != 0 { return 30 }
93
94 let weight_name: *u8 = sys_mmap(6)
95 weight_name[0] = 0x77; weight_name[1] = 0x65; weight_name[2] = 0x69
96 weight_name[3] = 0x67; weight_name[4] = 0x68; weight_name[5] = 0x74
97 if nx_gguf_find_tensor(hdr_p, weight_name, 6) != 1 { return 31 }
98
99 let missing: *u8 = sys_mmap(3)
100 missing[0] = 0x78; missing[1] = 0x78; missing[2] = 0x78
101 if nx_gguf_find_tensor(hdr_p, missing, 3) != (0 - 1) { return 32 }
102
103 // ----- Format helpers -----
104 let ti0: *NxGgufTensorInfo = nx_gguf_tensor_at(hdr_p, 0)
105 if nx_gguf_ggml_values_per_block(ti0.ggml_type) != 1 { return 40 }
106 if nx_gguf_ggml_bytes_per_block(ti0.ggml_type) != 4 { return 41 }
107 if nx_gguf_tensor_n_values(ti0) != 4 { return 42 }
108 if nx_gguf_tensor_data_bytes(ti0) != 16 { return 43 }
109
110 let ti1: *NxGgufTensorInfo = nx_gguf_tensor_at(hdr_p, 1)
111 if nx_gguf_ggml_values_per_block(ti1.ggml_type) != 32 { return 50 }
112 if nx_gguf_ggml_bytes_per_block(ti1.ggml_type) != 34 { return 51 }
113 if nx_gguf_tensor_n_values(ti1) != 32 { return 52 }
114 if nx_gguf_tensor_data_bytes(ti1) != 34 { return 53 }
115
116 // ----- f32 → Q10 canonical bit-patterns -----
117 if _gguf_f32_to_q10(0x3F800000) != 1024 { return 60 }
118 if _gguf_f32_to_q10(0x40000000) != 2048 { return 61 }
119 if _gguf_f32_to_q10(0x3F000000) != 512 { return 62 }
120 if _gguf_f32_to_q10(0xBF800000) != (0 - 1024) { return 63 }
121 if _gguf_f32_to_q10(0) != 0 { return 64 }
122
123 // ----- f16 → Q10 canonical bit-patterns -----
124 if _gguf_f16_to_q10(0x3C00) != 1024 { return 70 }
125 if _gguf_f16_to_q10(0xBC00) != (0 - 1024) { return 71 }
126 if _gguf_f16_to_q10(0x3800) != 512 { return 72 }
127 if _gguf_f16_to_q10(0x4000) != 2048 { return 73 }
128 if _gguf_f16_to_q10(0) != 0 { return 74 }
129
130 // ----- Load "score" (F32) -----
131 let err: *i64 = sys_mmap(8) as *i64
132 err[0] = 0
133 let score_t: *NxTensor = nx_gguf_load_tensor(buf, hdr_p,
134 score_name, 5, err)
135 if err[0] != NX_GL_OK { return 80 }
136 if score_t.numel != 4 { return 81 }
137 let sp: *i64 = score_t.storage as *i64
138 if sp[0] != 1024 { return 82 }
139 if sp[1] != 2048 { return 83 }
140 if sp[2] != 512 { return 84 }
141 if sp[3] != (0 - 1024) { return 85 }
142
143 // ----- Load "weight" (Q8_0) -----
144 let weight_t: *NxTensor = nx_gguf_load_tensor(buf, hdr_p,
145 weight_name, 6, err)
146 if err[0] != NX_GL_OK { return 90 }
147 if weight_t.numel != 32 { return 91 }
148 let wp: *i64 = weight_t.storage as *i64
149 // scale_q10 = 512; qs[i] = i; dequant[i] = 512 * i.
150 var ki: nx_int = 0
151 while ki < 32 {
152 let expected: i64 = 512 * ki
153 if wp[ki] != expected { return 100 + ki }
154 ki = ki + 1
155 }
156
157 // ----- Negative path: not-found -----
158 let bad: *u8 = sys_mmap(5)
159 bad[0] = 0x78; bad[1] = 0x78; bad[2] = 0x78; bad[3] = 0x78; bad[4] = 0x78
160 let _ng: *NxTensor = nx_gguf_load_tensor(buf, hdr_p, bad, 5, err)
161 if err[0] != NX_GL_ERR_NOT_FOUND { return 140 }
162
163 return 0
164}