code wiki / (root) / nx_gguf_load_block_test.nx

nx_gguf_load_block_test.nx source

↩ module page · 172 lines · 7019 B

1// nx_gguf_load_block_test.nx -- smoke for nx_gguf_load_block.nx. 2// 3// Two test classes: 4// A) Name-formatting unit checks: format "blk.{N}.{suffix}" with 5// different layer indices + suffix strings; verify byte-equal 6// to expected literal. 7// B) End-to-end integration: build a synthetic GGUF with a single 8// layer-0 attn_norm tensor (F32 shape [2]); call the loader's 9// _gbl_load_blk_tensor; verify it finds + loads correctly. 10// 11// Full 9-tensor end-to-end smoke is deferred to the `nx_llm_run` v2 12// brick where it composes with the transformer block forward pass. 13// THIS smoke validates the new code paths (name fmt + per-tensor 14// helper) under the bits-up canonical-brick discipline. 15 16import "nx_syscalls.nx" 17import "nx_tier.nx" 18import "nx_le.nx" 19import "nx_tensor.nx" 20import "nx_rope.nx" 21import "nx_gguf.nx" 22import "nx_gguf_load.nx" 23import "nx_gguf_load_block.nx" 24 25// Byte-equality helper. 26func _byte_equal(a: *u8, b: *u8, n: nx_int) -> nx_int { 27 var i: nx_int = 0 28 while i < n { 29 if a[i] != b[i] { return 0 } 30 i = i + 1 31 } 32 return 1 33} 34 35func main() -> i64 { 36 // ----- A) Name-formatting unit checks ----- 37 38 // A.1: layer 0 + "attn_q.weight" 39 let suf_q: *u8 = sys_mmap(13) 40 suf_q[0]=0x61; suf_q[1]=0x74; suf_q[2]=0x74; suf_q[3]=0x6e 41 suf_q[4]=0x5f; suf_q[5]=0x71; suf_q[6]=0x2e; suf_q[7]=0x77 42 suf_q[8]=0x65; suf_q[9]=0x69; suf_q[10]=0x67; suf_q[11]=0x68 43 suf_q[12]=0x74 44 let out_a: *u8 = sys_mmap(64) 45 let n_a: nx_int = _gbl_fmt_blk_name(0, suf_q, 13, out_a) 46 if n_a != 19 { return 10 } // "blk.0.attn_q.weight" = 19 bytes 47 let exp_a: *u8 = sys_mmap(19) 48 exp_a[0]=0x62; exp_a[1]=0x6c; exp_a[2]=0x6b; exp_a[3]=0x2e 49 exp_a[4]=0x30 // '0' 50 exp_a[5]=0x2e // '.' 51 exp_a[6]=0x61; exp_a[7]=0x74; exp_a[8]=0x74; exp_a[9]=0x6e 52 exp_a[10]=0x5f; exp_a[11]=0x71; exp_a[12]=0x2e; exp_a[13]=0x77 53 exp_a[14]=0x65; exp_a[15]=0x69; exp_a[16]=0x67; exp_a[17]=0x68 54 exp_a[18]=0x74 55 if _byte_equal(out_a, exp_a, 19) != 1 { return 11 } 56 57 // A.2: layer 5 + "attn_q.weight" -> "blk.5.attn_q.weight" (19 bytes) 58 let out_b: *u8 = sys_mmap(64) 59 let n_b: nx_int = _gbl_fmt_blk_name(5, suf_q, 13, out_b) 60 if n_b != 19 { return 20 } 61 let exp_b: *u8 = sys_mmap(19) 62 exp_b[0]=0x62; exp_b[1]=0x6c; exp_b[2]=0x6b; exp_b[3]=0x2e 63 exp_b[4]=0x35 // '5' 64 exp_b[5]=0x2e 65 exp_b[6]=0x61; exp_b[7]=0x74; exp_b[8]=0x74; exp_b[9]=0x6e 66 exp_b[10]=0x5f; exp_b[11]=0x71; exp_b[12]=0x2e; exp_b[13]=0x77 67 exp_b[14]=0x65; exp_b[15]=0x69; exp_b[16]=0x67; exp_b[17]=0x68 68 exp_b[18]=0x74 69 if _byte_equal(out_b, exp_b, 19) != 1 { return 21 } 70 71 // A.3: layer 27 + "ffn_down.weight" -> "blk.27.ffn_down.weight" (22) 72 let suf_fd: *u8 = sys_mmap(15) 73 suf_fd[0]=0x66; suf_fd[1]=0x66; suf_fd[2]=0x6e; suf_fd[3]=0x5f 74 suf_fd[4]=0x64; suf_fd[5]=0x6f; suf_fd[6]=0x77; suf_fd[7]=0x6e 75 suf_fd[8]=0x2e; suf_fd[9]=0x77; suf_fd[10]=0x65; suf_fd[11]=0x69 76 suf_fd[12]=0x67; suf_fd[13]=0x68; suf_fd[14]=0x74 77 let out_c: *u8 = sys_mmap(64) 78 let n_c: nx_int = _gbl_fmt_blk_name(27, suf_fd, 15, out_c) 79 if n_c != 22 { return 30 } 80 let exp_c: *u8 = sys_mmap(22) 81 exp_c[0]=0x62; exp_c[1]=0x6c; exp_c[2]=0x6b; exp_c[3]=0x2e 82 exp_c[4]=0x32; exp_c[5]=0x37 // "27" 83 exp_c[6]=0x2e 84 exp_c[7]=0x66; exp_c[8]=0x66; exp_c[9]=0x6e; exp_c[10]=0x5f 85 exp_c[11]=0x64; exp_c[12]=0x6f; exp_c[13]=0x77; exp_c[14]=0x6e 86 exp_c[15]=0x2e; exp_c[16]=0x77; exp_c[17]=0x65; exp_c[18]=0x69 87 exp_c[19]=0x67; exp_c[20]=0x68; exp_c[21]=0x74 88 if _byte_equal(out_c, exp_c, 22) != 1 { return 31 } 89 90 // ----- B) Verdict range gate ----- 91 var vi: nx_int = 0 92 while vi < NX_GBL_N_VERDICTS { 93 if nx_gbl_verdict_is_valid(vi) != 1 { return 40 + vi } 94 vi = vi + 1 95 } 96 97 // ----- C) Single per-layer tensor load integration ----- 98 // 99 // Build a GGUF with one tensor "blk.0.attn_norm.weight" F32 [2]. 100 let buf: *u8 = sys_mmap(512) 101 buf[0] = 0x47; buf[1] = 0x47; buf[2] = 0x55; buf[3] = 0x46 102 buf[4] = 3; buf[5] = 0; buf[6] = 0; buf[7] = 0 103 nx_le_write_u64(buf, 8, 1) // tensor_count 104 nx_le_write_u64(buf, 16, 0) // metadata_count 105 106 // Tensor: name = "blk.0.attn_norm.weight" (22 bytes) 107 nx_le_write_u64(buf, 24, 22) 108 // name bytes at 32..54 109 buf[32]=0x62; buf[33]=0x6c; buf[34]=0x6b; buf[35]=0x2e 110 buf[36]=0x30; buf[37]=0x2e 111 buf[38]=0x61; buf[39]=0x74; buf[40]=0x74; buf[41]=0x6e 112 buf[42]=0x5f; buf[43]=0x6e; buf[44]=0x6f; buf[45]=0x72 113 buf[46]=0x6d; buf[47]=0x2e; buf[48]=0x77; buf[49]=0x65 114 buf[50]=0x69; buf[51]=0x67; buf[52]=0x68; buf[53]=0x74 115 // n_dims = 1, dim_0 = 2, ggml_type = F32, offset = 0 116 nx_le_write_u32(buf, 54, 1) 117 nx_le_write_u64(buf, 58, 2) 118 nx_le_write_u32(buf, 66, NX_GGML_TYPE_F32) 119 nx_le_write_u64(buf, 70, 0) 120 // End of tensor_info at 78. data_off = align_up(78, 32) = 96. 121 122 // Data: two f32 values 1.0, 2.0 123 nx_le_write_u32(buf, 96 + 0, 0x3F800000) 124 nx_le_write_u32(buf, 96 + 4, 0x40000000) 125 126 let hdr: *NxGgufHeader = sys_mmap(NX_GGUF_HDR_BYTES) as *NxGgufHeader 127 let v_p: nx_int = nx_gguf_parse(buf, 512, hdr) 128 if v_p != NX_GGUF_OK { return 50 + v_p } 129 if hdr.n_tensors != 1 { return 60 } 130 if hdr.data_off != 96 { return 61 } 131 132 let suf_an: *u8 = sys_mmap(16) 133 suf_an[0]=0x61; suf_an[1]=0x74; suf_an[2]=0x74; suf_an[3]=0x6e 134 suf_an[4]=0x5f; suf_an[5]=0x6e; suf_an[6]=0x6f; suf_an[7]=0x72 135 suf_an[8]=0x6d; suf_an[9]=0x2e; suf_an[10]=0x77; suf_an[11]=0x65 136 suf_an[12]=0x69; suf_an[13]=0x67; suf_an[14]=0x68; suf_an[15]=0x74 137 138 let err: *i64 = sys_mmap(8) as *i64 139 err[0] = 0 140 let t_an: *NxTensor = _gbl_load_blk_tensor(buf, hdr, 0, 141 suf_an, 16, err) 142 if err[0] != NX_GL_OK { return 70 } 143 if t_an.numel != 2 { return 71 } 144 let p: *i64 = t_an.storage as *i64 145 if p[0] != 1024 { return 72 } // 1.0 -> Q10 1024 146 if p[1] != 2048 { return 73 } // 2.0 -> Q10 2048 147 148 // Negative path: ask for "blk.7.attn_norm.weight" -- not in GGUF. 149 err[0] = 0 150 let t_miss: *NxTensor = _gbl_load_blk_tensor(buf, hdr, 7, 151 suf_an, 16, err) 152 if err[0] != NX_GL_ERR_NOT_FOUND { return 80 } 153 154 // ----- D) RoPE inv_freq sanity ------------------------------ 155 // 156 // For d=4, base=10000, expect: 157 // theta_0 = 1.0 in Q10 = 1024 158 // theta_1 = 10000^(-1/2) ~ 0.01 in Q10 = 10 159 // 160 // We don't bit-check (nx_rope already has its own KAT) -- just 161 // verify the inv_freq pointer is populated and theta_0 == 1024. 162 163 // Build a fake bundle to pass to the loader -- we only check the 164 // inv_freq behavior, so we skip the 9 tensor loads and call 165 // nx_rope_compute_inv_freq directly here. 166 let inv: *i64 = sys_mmap(2 * 8) as *i64 167 let v_r: nx_int = nx_rope_compute_inv_freq(4, 10000, inv) 168 if v_r != NX_ROPE_OK { return 90 } 169 if inv[0] != 1024 { return 91 } 170 171 return 0 172}