marcsun13 HF Staff commited on
Commit
99aafa6
·
1 Parent(s): d297b20

Fix q8_0 gemv: reduction-across-simdgroups convention

Browse files

q8_0's mul_mv splits the K reduction across simdgroups and combines them through
threadgroup memory, where the K-quants give each simdgroup its own rows. It
therefore needs a grid that is not divided by nsg, and it needs smem bound --
upstream branches on exactly this. Without both, q8_0 returned garbage while the
K-quants were correct.

gguf_metal/ggml_dispatch.mm CHANGED
@@ -38,14 +38,21 @@ struct TypeInfo {
38
  int block_bytes;
39
  int mv_nsg; // N_SG_* from ggml-metal-impl.h
40
  int mv_nr0; // N_R0_*
 
 
 
 
 
 
 
41
  };
42
 
43
  const std::unordered_map<int, TypeInfo> &type_table() {
44
  static const std::unordered_map<int, TypeInfo> table = {
45
- {GGML_Q8_0, {"q8_0", 32, 34, N_SG_Q8_0, N_R0_Q8_0}},
46
- {GGML_Q4_K, {"q4_K", 256, 144, N_SG_Q4_K, N_R0_Q4_K}},
47
- {GGML_Q5_K, {"q5_K", 256, 176, N_SG_Q5_K, N_R0_Q5_K}},
48
- {GGML_Q6_K, {"q6_K", 256, 210, N_SG_Q6_K, N_R0_Q6_K}},
49
  };
50
  return table;
51
  }
@@ -180,7 +187,11 @@ extern "C" int gguf_metal_mul_mat(void *blocks, size_t blocks_off, void *x, size
180
  [enc setBuffer:b_blocks offset:blocks_off atIndex:1];
181
  [enc setBuffer:b_x offset:x_off atIndex:2];
182
  [enc setBuffer:b_out offset:out_off atIndex:3];
183
- const NSUInteger gx = (N + nr0 * nsg - 1) / (nr0 * nsg);
 
 
 
 
184
  [enc dispatchThreadgroups:MTLSizeMake(gx, M, 1)
185
  threadsPerThreadgroup:MTLSizeMake(32, nsg, 1)];
186
  }
 
38
  int block_bytes;
39
  int mv_nsg; // N_SG_* from ggml-metal-impl.h
40
  int mv_nr0; // N_R0_*
41
+ // Two gemv conventions upstream. The K-quants give each simdgroup its own rows
42
+ // (first_row = (tgpig.x*NSG + sgitg)*nr0), so the grid is divided by nsg and nothing is shared.
43
+ // q8_0 instead splits the K reduction across simdgroups (r0 = tgpig.x*NR0) and combines them
44
+ // through threadgroup memory in helper_mv_reduce_and_write -- so its grid must NOT be divided by
45
+ // nsg, and it needs smem. Getting either wrong silently returns garbage.
46
+ bool mv_reduce_across_sgs;
47
+ size_t mv_smem;
48
  };
49
 
50
  const std::unordered_map<int, TypeInfo> &type_table() {
51
  static const std::unordered_map<int, TypeInfo> table = {
52
+ {GGML_Q8_0, {"q8_0", 32, 34, N_SG_Q8_0, N_R0_Q8_0, true, 32 * sizeof(float) * N_R0_Q8_0}},
53
+ {GGML_Q4_K, {"q4_K", 256, 144, N_SG_Q4_K, N_R0_Q4_K, false, 0}},
54
+ {GGML_Q5_K, {"q5_K", 256, 176, N_SG_Q5_K, N_R0_Q5_K, false, 0}},
55
+ {GGML_Q6_K, {"q6_K", 256, 210, N_SG_Q6_K, N_R0_Q6_K, false, 0}},
56
  };
57
  return table;
58
  }
 
187
  [enc setBuffer:b_blocks offset:blocks_off atIndex:1];
188
  [enc setBuffer:b_x offset:x_off atIndex:2];
189
  [enc setBuffer:b_out offset:out_off atIndex:3];
190
+ if (info->mv_smem) {
191
+ [enc setThreadgroupMemoryLength:info->mv_smem atIndex:0];
192
+ }
193
+ const NSUInteger gx = info->mv_reduce_across_sgs ? (N + nr0 - 1) / nr0
194
+ : (N + nr0 * nsg - 1) / (nr0 * nsg);
195
  [enc dispatchThreadgroups:MTLSizeMake(gx, M, 1)
196
  threadsPerThreadgroup:MTLSizeMake(32, nsg, 1)];
197
  }
result-torch212 ADDED
@@ -0,0 +1 @@
 
 
1
+ /nix/store/vsc5ambf7shc0cv3fip7zvfzaxsjk4z2-gguf-kernels-torch-ext
result-torch213 ADDED
@@ -0,0 +1 @@
 
 
1
+ /nix/store/ipmkgsrz5mzwi56m3264vhb2nm2vpgfy-gguf-kernels-torch-ext