char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
73ab7599b
char/aliceai-t5-moe
1#include "mmvq.cuh" 2#include "quantize.cuh" 3#include "unary.cuh" 4#include "vecdotq.cuh" 5 6#include <cstdint> 7#include <type_traits> 8 9// only enabled on DGX Spark, where it is a gain on every type below. On the higher-bandwidth parts the kernel 10// has little exposed latency left to hide and the extra requests cost more than they save. 11// For perf data, see https://github.com/ggml-org/llama.cpp/pull/26705#issuecomment-5569335031 12#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ == GGML_CUDA_CC_DGX_SPARK 13// returns true only for those quants that benefit from prefetch and false otherwise 14static constexpr __host__ __device__ bool mmvq_should_prefetch(ggml_type type) { 15 switch (type) { 16 case GGML_TYPE_Q4_0: 17 case GGML_TYPE_Q5_0: 18 case GGML_TYPE_Q8_0: 19 case GGML_TYPE_MXFP4: 20 case GGML_TYPE_Q3_K: 21 case GGML_TYPE_Q4_K: 22 case GGML_TYPE_Q5_K: 23 case GGML_TYPE_Q6_K: 24 case GGML_TYPE_IQ1_M: 25 case GGML_TYPE_IQ4_NL: 26 case GGML_TYPE_IQ4_XS: 27 return true; 28 default: 29 return false; 30 } 31} 32 33static __device__ __forceinline__ void mmvq_prefetch_l2(const void * p) { 34 asm volatile("prefetch.global.L2 [%0];" :: "l"(p)); 35} 36#endif 37 38typedef float (*vec_dot_q_cuda_t)(const void * __restrict__ vbq, const block_q8_1 * __restrict__ bq8_1, const int & kbx, const int & iqs); 39 40static constexpr __device__ vec_dot_q_cuda_t get_vec_dot_q_cuda(ggml_type type) { 41 switch (type) { 42 case GGML_TYPE_Q1_0: return vec_dot_q1_0_q8_1; 43 case GGML_TYPE_Q2_0: return vec_dot_q2_0_q8_1; 44 case GGML_TYPE_Q4_0: return vec_dot_q4_0_q8_1; 45 case GGML_TYPE_Q4_1: return vec_dot_q4_1_q8_1; 46 case GGML_TYPE_Q5_0: return vec_dot_q5_0_q8_1; 47 case GGML_TYPE_Q5_1: return vec_dot_q5_1_q8_1; 48 case GGML_TYPE_Q8_0: return vec_dot_q8_0_q8_1; 49 case GGML_TYPE_MXFP4: return vec_dot_mxfp4_q8_1; 50 case GGML_TYPE_NVFP4: return vec_dot_nvfp4_q8_1; 51 case GGML_TYPE_Q2_K: return vec_dot_q2_K_q8_1; 52 case GGML_TYPE_Q3_K: return vec_dot_q3_K_q8_1; 53 case GGML_TYPE_Q4_K: return vec_dot_q4_K_q8_1; 54 case GGML_TYPE_Q5_K: return vec_dot_q5_K_q8_1; 55 case GGML_TYPE_Q6_K: return vec_dot_q6_K_q8_1; 56 case GGML_TYPE_IQ2_XXS: return vec_dot_iq2_xxs_q8_1; 57 case GGML_TYPE_IQ2_XS: return vec_dot_iq2_xs_q8_1; 58 case GGML_TYPE_IQ2_S: return vec_dot_iq2_s_q8_1; 59 case GGML_TYPE_IQ3_XXS: return vec_dot_iq3_xxs_q8_1; 60 case GGML_TYPE_IQ1_S: return vec_dot_iq1_s_q8_1; 61 case GGML_TYPE_IQ1_M: return vec_dot_iq1_m_q8_1; 62 case GGML_TYPE_IQ4_NL: return vec_dot_iq4_nl_q8_1; 63 case GGML_TYPE_IQ4_XS: return vec_dot_iq4_xs_q8_1; 64 case GGML_TYPE_IQ3_S: return vec_dot_iq3_s_q8_1; 65 default: return nullptr; 66 } 67} 68 69static constexpr __host__ __device__ int get_vdr_mmvq(ggml_type type) { 70 switch (type) { 71 case GGML_TYPE_Q1_0: return VDR_Q1_0_Q8_1_MMVQ; 72 case GGML_TYPE_Q2_0: return VDR_Q2_0_Q8_1_MMVQ; 73 case GGML_TYPE_Q4_0: return VDR_Q4_0_Q8_1_MMVQ; 74 case GGML_TYPE_Q4_1: return VDR_Q4_1_Q8_1_MMVQ; 75 case GGML_TYPE_Q5_0: return VDR_Q5_0_Q8_1_MMVQ; 76 case GGML_TYPE_Q5_1: return VDR_Q5_1_Q8_1_MMVQ; 77 case GGML_TYPE_Q8_0: return VDR_Q8_0_Q8_1_MMVQ; 78 case GGML_TYPE_MXFP4: return VDR_MXFP4_Q8_1_MMVQ; 79 case GGML_TYPE_NVFP4: return VDR_NVFP4_Q8_1_MMVQ; 80 case GGML_TYPE_Q2_K: return VDR_Q2_K_Q8_1_MMVQ; 81 case GGML_TYPE_Q3_K: return VDR_Q3_K_Q8_1_MMVQ; 82 case GGML_TYPE_Q4_K: return VDR_Q4_K_Q8_1_MMVQ; 83 case GGML_TYPE_Q5_K: return VDR_Q5_K_Q8_1_MMVQ; 84 case GGML_TYPE_Q6_K: return VDR_Q6_K_Q8_1_MMVQ; 85 case GGML_TYPE_IQ2_XXS: return VDR_IQ2_XXS_Q8_1_MMVQ; 86 case GGML_TYPE_IQ2_XS: return VDR_IQ2_XS_Q8_1_MMVQ; 87 case GGML_TYPE_IQ2_S: return VDR_IQ2_S_Q8_1_MMVQ; 88 case GGML_TYPE_IQ3_XXS: return VDR_IQ3_XXS_Q8_1_MMVQ; 89 case GGML_TYPE_IQ3_S: return VDR_IQ3_S_Q8_1_MMVQ; 90 case GGML_TYPE_IQ4_NL: return VDR_IQ4_NL_Q8_1_MMVQ; 91 case GGML_TYPE_IQ4_XS: return VDR_IQ4_XS_Q8_1_MMVQ; 92 default: return 1; 93 } 94} 95 96enum mmvq_parameter_table_id { 97 MMVQ_PARAMETERS_GENERIC = 0, 98 MMVQ_PARAMETERS_TURING, 99 MMVQ_PARAMETERS_GCN, 100 MMVQ_PARAMETERS_RDNA2, 101 MMVQ_PARAMETERS_RDNA3_0, 102 MMVQ_PARAMETERS_RDNA4, 103 MMVQ_PARAMETERS_GB10 104}; 105 106static constexpr __device__ mmvq_parameter_table_id get_device_table_id() { 107#if defined(RDNA4) 108 return MMVQ_PARAMETERS_RDNA4; 109#elif defined(RDNA3_0) 110 return MMVQ_PARAMETERS_RDNA3_0; 111#elif defined(RDNA2) || defined(RDNA3_5) 112 return MMVQ_PARAMETERS_RDNA2; 113#elif defined(GCN) || defined(CDNA) 114 return MMVQ_PARAMETERS_GCN; 115#elif defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= GGML_CUDA_CC_TURING && __CUDA_ARCH__ < GGML_CUDA_CC_AMPERE 116 return MMVQ_PARAMETERS_TURING; 117#elif defined(__CUDA_ARCH__) && __CUDA_ARCH__ == GGML_CUDA_CC_DGX_SPARK 118 return MMVQ_PARAMETERS_GB10; 119#else 120 return MMVQ_PARAMETERS_GENERIC; 121#endif 122} 123 124static __host__ mmvq_parameter_table_id get_device_table_id(int cc) { 125 if (GGML_CUDA_CC_IS_RDNA4(cc)) { 126 return MMVQ_PARAMETERS_RDNA4; 127 } 128 if (GGML_CUDA_CC_IS_RDNA3_0(cc)) { 129 return MMVQ_PARAMETERS_RDNA3_0; 130 } 131 if (GGML_CUDA_CC_IS_RDNA2(cc) || GGML_CUDA_CC_IS_RDNA3_5(cc)) { 132 return MMVQ_PARAMETERS_RDNA2; 133 } 134 if (GGML_CUDA_CC_IS_GCN(cc) || GGML_CUDA_CC_IS_CDNA(cc)) { 135 return MMVQ_PARAMETERS_GCN; 136 } 137 if (GGML_CUDA_CC_IS_NVIDIA(cc) && ggml_cuda_highest_compiled_arch(cc) >= GGML_CUDA_CC_TURING && ggml_cuda_highest_compiled_arch(cc) < GGML_CUDA_CC_AMPERE) { 138 return MMVQ_PARAMETERS_TURING; 139 } 140 if (GGML_CUDA_CC_IS_NVIDIA(cc) && ggml_cuda_highest_compiled_arch(cc) == GGML_CUDA_CC_DGX_SPARK) { 141 return MMVQ_PARAMETERS_GB10; 142 } 143 return MMVQ_PARAMETERS_GENERIC; 144} 145 146// Per-architecture maximum batch size for which MMVQ should be used for MUL_MAT_ID. 147// Returns a value <= MMVQ_MAX_BATCH_SIZE. Default is MMVQ_MAX_BATCH_SIZE. 148// Check https://github.com/ggml-org/llama.cpp/pull/20905#issuecomment-4145835627 for details 149 150static constexpr __host__ __device__ int get_mmvq_mmid_max_batch_pascal_older(ggml_type type) { 151 switch (type) { 152 case GGML_TYPE_IQ1_S: return 6; 153 case GGML_TYPE_IQ1_M: return 6; 154 case GGML_TYPE_IQ2_S: return 4; 155 case GGML_TYPE_IQ2_XS: return 5; 156 case GGML_TYPE_IQ2_XXS: return 5; 157 case GGML_TYPE_IQ3_S: return 4; 158 case GGML_TYPE_IQ3_XXS: return 4; 159 case GGML_TYPE_IQ4_NL: return 6; 160 case GGML_TYPE_IQ4_XS: return 5; 161 case GGML_TYPE_MXFP4: return 4; 162 case GGML_TYPE_NVFP4: return 4; 163 case GGML_TYPE_Q2_K: return 4; 164 case GGML_TYPE_Q3_K: return 4; 165 case GGML_TYPE_Q4_0: return 6; 166 case GGML_TYPE_Q4_1: return 6; 167 case GGML_TYPE_Q4_K: return 5; 168 case GGML_TYPE_Q5_0: return 6; 169 case GGML_TYPE_Q5_1: return 6; 170 case GGML_TYPE_Q5_K: return 5; 171 case GGML_TYPE_Q6_K: return 4; 172 case GGML_TYPE_Q8_0: return 4; 173 default: return MMVQ_MAX_BATCH_SIZE; 174 } 175} 176 177static constexpr __host__ __device__ int get_mmvq_mmid_max_batch_turing_plus(ggml_type type) { 178 switch (type) { 179 case GGML_TYPE_IQ2_S: return 7; 180 case GGML_TYPE_IQ3_S: return 6; 181 case GGML_TYPE_IQ3_XXS: return 7; 182 case GGML_TYPE_MXFP4: return 7; 183 case GGML_TYPE_NVFP4: return 8; 184 case GGML_TYPE_Q2_K: return 7; 185 case GGML_TYPE_Q3_K: return 5; 186 default: return MMVQ_MAX_BATCH_SIZE; 187 } 188} 189 190static constexpr __host__ __device__ int get_mmvq_mmid_max_batch_gcn(ggml_type type) { 191 switch (type) { 192 case GGML_TYPE_IQ1_S: return 5; 193 case GGML_TYPE_IQ1_M: return 5; 194 case GGML_TYPE_IQ2_S: return 4; 195 case GGML_TYPE_IQ2_XS: return 4; 196 case GGML_TYPE_IQ2_XXS: return 4; 197 case GGML_TYPE_IQ3_S: return 4; 198 case GGML_TYPE_IQ3_XXS: return 4; 199 case GGML_TYPE_IQ4_NL: return 6; 200 case GGML_TYPE_IQ4_XS: return 4; 201 case GGML_TYPE_Q2_K: return 4; 202 case GGML_TYPE_Q3_K: return 4; 203 case GGML_TYPE_Q4_0: return 5; 204 case GGML_TYPE_Q4_1: return 5; 205 case GGML_TYPE_Q4_K: return 4; 206 case GGML_TYPE_Q5_K: return 4; 207 case GGML_TYPE_Q6_K: return 4; 208 case GGML_TYPE_Q8_0: return 4; 209 default: return MMVQ_MAX_BATCH_SIZE; 210 } 211} 212 213static constexpr __host__ __device__ int get_mmvq_mmid_max_batch_cdna(ggml_type type) { 214 switch (type) { 215 case GGML_TYPE_IQ2_S: return 5; 216 case GGML_TYPE_IQ2_XS: return 5; 217 case GGML_TYPE_IQ2_XXS: return 5; 218 case GGML_TYPE_IQ3_S: return 4; 219 case GGML_TYPE_IQ3_XXS: return 5; 220 default: return MMVQ_MAX_BATCH_SIZE; 221 } 222} 223 224static constexpr __host__ __device__ int get_mmvq_mmid_max_batch_rdna1_rdna2(ggml_type type) { 225 switch (type) { 226 case GGML_TYPE_IQ2_S: return 4; 227 case GGML_TYPE_IQ2_XS: return 4; 228 case GGML_TYPE_IQ2_XXS: return 4; 229 case GGML_TYPE_IQ3_S: return 4; 230 case GGML_TYPE_IQ3_XXS: return 4; 231 case GGML_TYPE_Q2_K: return 7; 232 case GGML_TYPE_Q3_K: return 4; 233 case GGML_TYPE_Q4_K: return 5; 234 case GGML_TYPE_Q5_K: return 6; 235 case GGML_TYPE_Q6_K: return 5; 236 default: return MMVQ_MAX_BATCH_SIZE; 237 } 238} 239 240static constexpr __host__ __device__ int get_mmvq_mmid_max_batch_rdna3(ggml_type type) { 241 switch (type) { 242 case GGML_TYPE_IQ1_S: return 6; 243 case GGML_TYPE_IQ1_M: return 6; 244 case GGML_TYPE_IQ2_S: return 4; 245 case GGML_TYPE_IQ2_XS: return 4; 246 case GGML_TYPE_IQ2_XXS: return 4; 247 case GGML_TYPE_IQ3_S: return 4; 248 case GGML_TYPE_IQ3_XXS: return 4; 249 case GGML_TYPE_IQ4_NL: return 6; 250 case GGML_TYPE_IQ4_XS: return 6; 251 case GGML_TYPE_Q4_K: return 4; 252 case GGML_TYPE_Q5_K: return 4; 253 case GGML_TYPE_Q6_K: return 4; 254 default: return MMVQ_MAX_BATCH_SIZE; 255 } 256} 257 258static constexpr __host__ __device__ int get_mmvq_mmid_max_batch_rdna4(ggml_type type) { 259 switch (type) { 260 case GGML_TYPE_IQ1_S: return 7; 261 case GGML_TYPE_IQ1_M: return 7; 262 case GGML_TYPE_IQ2_S: return 4; 263 case GGML_TYPE_IQ2_XS: return 4; 264 case GGML_TYPE_IQ2_XXS: return 4; 265 case GGML_TYPE_IQ3_S: return 4; 266 case GGML_TYPE_IQ3_XXS: return 4; 267 case GGML_TYPE_IQ4_NL: return 7; 268 case GGML_TYPE_IQ4_XS: return 5; 269 case GGML_TYPE_MXFP4: return 5; 270 case GGML_TYPE_NVFP4: return 5; 271 case GGML_TYPE_Q3_K: return 4; 272 case GGML_TYPE_Q4_0: return 7; 273 case GGML_TYPE_Q4_1: return 7; 274 case GGML_TYPE_Q4_K: return 4; 275 case GGML_TYPE_Q5_0: return 7; 276 case GGML_TYPE_Q5_1: return 7; 277 case GGML_TYPE_Q5_K: return 5; 278 case GGML_TYPE_Q6_K: return 5; 279 case GGML_TYPE_Q8_0: return 7; 280 default: return MMVQ_MAX_BATCH_SIZE; 281 } 282} 283 284// Host function: returns the max batch size for the current arch+type at runtime. 285int get_mmvq_mmid_max_batch(ggml_type type, int cc) { 286 // NVIDIA: Volta, Ada Lovelace, and Blackwell always use MMVQ for MUL_MAT_ID. 287 if (GGML_CUDA_CC_IS_NVIDIA(cc)) { 288 if (cc == GGML_CUDA_CC_VOLTA || cc >= GGML_CUDA_CC_ADA_LOVELACE) { 289 return MMVQ_MAX_BATCH_SIZE; 290 } 291 if (cc >= GGML_CUDA_CC_TURING) { 292 return get_mmvq_mmid_max_batch_turing_plus(type); 293 } 294 return get_mmvq_mmid_max_batch_pascal_older(type); 295 } 296 297 // AMD 298 if (GGML_CUDA_CC_IS_AMD(cc)) { 299 if (GGML_CUDA_CC_IS_RDNA4(cc)) { 300 return get_mmvq_mmid_max_batch_rdna4(type); 301 } 302 if (GGML_CUDA_CC_IS_RDNA3(cc)) { 303 return get_mmvq_mmid_max_batch_rdna3(type); 304 } 305 if (GGML_CUDA_CC_IS_RDNA1(cc) || GGML_CUDA_CC_IS_RDNA2(cc)) { 306 return get_mmvq_mmid_max_batch_rdna1_rdna2(type); 307 } 308 if (GGML_CUDA_CC_IS_CDNA(cc)) { 309 return get_mmvq_mmid_max_batch_cdna(type); 310 } 311 if (GGML_CUDA_CC_IS_GCN(cc)) { 312 return get_mmvq_mmid_max_batch_gcn(type); 313 } 314 } 315 return MMVQ_MAX_BATCH_SIZE; 316} 317 318bool ggml_cuda_should_use_mmvq(enum ggml_type type, int cc, int64_t ne11) { 319 if (!ggml_is_quantized(type)) { 320 return false; 321 } 322 // k-quants cost more to decode and mvq redoes that per column, so MMQ wins sooner. 323 // Only list quant-types MMQ supports, others would fall back to cuBLAS. 324 if (GGML_CUDA_CC_IS_NVIDIA(cc) && cc == GGML_CUDA_CC_ADA_LOVELACE) { 325 switch (type) { // tuned on RTX 4090 326 case GGML_TYPE_Q2_K: 327 return ne11 <= 4; 328 case GGML_TYPE_Q3_K: 329 return ne11 <= 6; 330 default: 331 return ne11 <= MMVQ_MAX_BATCH_SIZE; 332 } 333 } 334 if (GGML_CUDA_CC_IS_NVIDIA(cc) && cc == GGML_CUDA_CC_BLACKWELL) { 335 switch (type) { // tuned on RTX 5090 336 case GGML_TYPE_Q2_K: 337 case GGML_TYPE_Q3_K: 338 case GGML_TYPE_Q4_K: 339 return ne11 <= 5; 340 case GGML_TYPE_Q5_K: 341 return ne11 <= 6; 342 case GGML_TYPE_Q6_K: 343 return ne11 <= 7; 344 default: 345 return ne11 <= MMVQ_MAX_BATCH_SIZE; 346 } 347 } 348 if (GGML_CUDA_CC_IS_NVIDIA(cc) && cc == GGML_CUDA_CC_DGX_SPARK) { 349 switch (type) { // tuned on DGX Spark GB10 350 case GGML_TYPE_Q2_K: 351 return ne11 <= 6; 352 default: 353 return ne11 <= MMVQ_MAX_BATCH_SIZE; 354 } 355 } 356 if (GGML_CUDA_CC_IS_NVIDIA(cc) && cc == GGML_CUDA_CC_ORIN) { 357 switch (type) { // tuned for Jetson Orin 358 case GGML_TYPE_Q2_K: 359 case GGML_TYPE_Q3_K: 360 case GGML_TYPE_Q4_K: 361 case GGML_TYPE_Q5_K: 362 case GGML_TYPE_Q6_K: 363 return ne11 <= 1; 364 default: 365 return ne11 <= MMVQ_MAX_BATCH_SIZE; 366 } 367 } 368 if (GGML_CUDA_CC_IS_CDNA(cc)) { 369 if (GGML_CUDA_CC_IS_CDNA1(cc)) { 370 switch (type) { 371 case GGML_TYPE_Q4_0: 372 case GGML_TYPE_Q4_1: 373 return ne11 <= 7; 374 case GGML_TYPE_Q5_1: 375 return ne11 <= 7; 376 case GGML_TYPE_Q8_0: 377 return ne11 <= 6; 378 case GGML_TYPE_Q2_K: 379 return ne11 <= 4; 380 case GGML_TYPE_Q3_K: 381 return ne11 <= 3; 382 case GGML_TYPE_Q4_K: 383 return ne11 <= 2; 384 case GGML_TYPE_Q5_K: 385 return ne11 <= 3; 386 case GGML_TYPE_Q6_K: 387 return ne11 <= 4; 388 case GGML_TYPE_IQ1_S: 389 return ne11 <= 5; 390 case GGML_TYPE_IQ2_XXS: 391 case GGML_TYPE_IQ3_S: 392 case GGML_TYPE_IQ4_XS: 393 return ne11 <= 6; 394 default: 395 return ne11 <= MMVQ_MAX_BATCH_SIZE; 396 } 397 } 398 switch (type) { // tuned for CDNA2 399 case GGML_TYPE_Q2_K: 400 return ne11 <= 5; 401 case GGML_TYPE_Q3_K: 402 case GGML_TYPE_Q4_K: 403 case GGML_TYPE_Q5_K: 404 return ne11 <= 3; 405 case GGML_TYPE_Q6_K: 406 return ne11 <= 5; 407 default: 408 return ne11 <= MMVQ_MAX_BATCH_SIZE; 409 } 410 } 411 return ne11 <= MMVQ_MAX_BATCH_SIZE; 412} 413 414// Device constexpr: returns the max batch size for the current arch+type at compile time. 415template <ggml_type type> 416static constexpr __device__ int get_mmvq_mmid_max_batch_for_device() { 417#if defined(RDNA4) 418 return get_mmvq_mmid_max_batch_rdna4(type); 419#elif defined(RDNA3) 420 return get_mmvq_mmid_max_batch_rdna3(type); 421#elif defined(RDNA2) || defined(RDNA1) 422 return get_mmvq_mmid_max_batch_rdna1_rdna2(type); 423#elif defined(CDNA) 424 return get_mmvq_mmid_max_batch_cdna(type); 425#elif defined(GCN) 426 return get_mmvq_mmid_max_batch_gcn(type); 427#elif defined(__CUDA_ARCH__) && (__CUDA_ARCH__ == GGML_CUDA_CC_VOLTA || __CUDA_ARCH__ >= GGML_CUDA_CC_ADA_LOVELACE) 428 return MMVQ_MAX_BATCH_SIZE; 429#elif defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= GGML_CUDA_CC_TURING 430 return get_mmvq_mmid_max_batch_turing_plus(type); 431#else 432 return get_mmvq_mmid_max_batch_pascal_older(type); 433#endif 434} 435 436static constexpr __host__ __device__ int calc_nwarps(ggml_type type, int ncols_dst, mmvq_parameter_table_id table_id, bool small_k = false, bool halve_iters = false) { 437 if (table_id == MMVQ_PARAMETERS_GENERIC) { 438 switch (ncols_dst) { 439 case 1: 440 case 2: 441 case 3: 442 case 4: 443 return 4; 444 case 5: 445 case 6: 446 case 7: 447 case 8: 448 return 2; 449 default: 450 return 1; 451 } 452 } else if (table_id == MMVQ_PARAMETERS_GCN) { 453 switch (ncols_dst) { 454 case 1: 455 case 2: 456 case 3: 457 case 4: 458 return 2; 459 case 5: 460 case 6: 461 case 7: 462 case 8: 463 default: 464 return 1; 465 } 466 } 467 if (table_id == MMVQ_PARAMETERS_RDNA4) { 468 // nwarps=8 benefits types with simple vec_dot on RDNA4 (ncols_dst=1). 469 // Types with complex vec_dot (Q3_K, IQ2_*, IQ3_*) regress due to register 470 // pressure and lookup table contention at higher thread counts. 471 if (ncols_dst == 1) { 472 switch (type) { 473 case GGML_TYPE_Q4_0: 474 case GGML_TYPE_Q4_1: 475 case GGML_TYPE_Q5_0: 476 case GGML_TYPE_Q5_1: 477 case GGML_TYPE_Q8_0: 478 case GGML_TYPE_Q2_K: 479 case GGML_TYPE_Q4_K: 480 case GGML_TYPE_Q5_K: 481 case GGML_TYPE_Q6_K: 482 case GGML_TYPE_IQ4_NL: 483 case GGML_TYPE_IQ4_XS: 484 return 8; 485 default: 486 return 1; 487 } 488 } 489 return 1; 490 } 491 if (table_id == MMVQ_PARAMETERS_RDNA3_0) { 492 // RDNA3 (W7900): stricter whitelist than RDNA4. 493 // Q2_K / Q5_K / IQ4_XS regress in full quant sweeps. 494 if (ncols_dst == 1) { 495 switch (type) { 496 case GGML_TYPE_Q4_0: 497 case GGML_TYPE_Q4_1: 498 case GGML_TYPE_Q5_0: 499 case GGML_TYPE_Q5_1: 500 case GGML_TYPE_Q8_0: 501 return 8; 502 case GGML_TYPE_Q6_K: 503 return 2; 504 case GGML_TYPE_IQ4_NL: 505 return 8; 506 default: 507 return 1; 508 } 509 } 510 return 1; 511 } 512 if (table_id == MMVQ_PARAMETERS_TURING) { 513 if (ncols_dst == 1) { 514 switch (type) { 515 case GGML_TYPE_Q2_K: 516 case GGML_TYPE_Q3_K: 517 case GGML_TYPE_Q4_K: 518 case GGML_TYPE_Q5_K: 519 case GGML_TYPE_Q6_K: 520 return 2; 521 default: 522 return 4; 523 } 524 } 525 switch (ncols_dst) { 526 case 2: 527 case 3: 528 case 4: 529 return 4; 530 case 5: 531 case 6: 532 case 7: 533 case 8: 534 return 2; 535 default: 536 return 1; 537 } 538 } 539 if (table_id == MMVQ_PARAMETERS_GB10) { 540 const int generic = calc_nwarps(type, ncols_dst, MMVQ_PARAMETERS_GENERIC); 541 // Only worth the wider block when it actually retires the K loop in half the trips (Observation) 542 if (ncols_dst == 1 && !small_k && halve_iters) { 543 switch (type) { 544 case GGML_TYPE_Q4_0: 545 case GGML_TYPE_Q4_1: 546 case GGML_TYPE_Q5_0: 547 case GGML_TYPE_Q5_1: 548 case GGML_TYPE_Q8_0: 549 case GGML_TYPE_Q4_K: 550 case GGML_TYPE_Q5_K: 551 case GGML_TYPE_Q6_K: 552 case GGML_TYPE_IQ4_NL: 553 return 2 * generic; 554 default: 555 break; 556 } 557 } 558 return generic; 559 } 560 return 1; 561} 562 563static constexpr __host__ __device__ int calc_rows_per_block(int ncols_dst, int table_id, bool small_k = false, int nwarps = 1) { 564 if (table_id == MMVQ_PARAMETERS_GENERIC || table_id == MMVQ_PARAMETERS_GCN || table_id == MMVQ_PARAMETERS_TURING || table_id == MMVQ_PARAMETERS_GB10) { 565 switch (ncols_dst) { 566 case 1: 567 return small_k ? nwarps : 1; 568 case 2: 569 case 3: 570 case 4: 571 case 5: 572 case 6: 573 case 7: 574 case 8: 575 return 2; 576 default: 577 return 1; 578 } 579 } 580 return 1; 581} 582 583template <ggml_type type, int ncols_dst, bool has_fusion, bool small_k = false, bool halve_iters = false> 584__launch_bounds__(calc_nwarps(type, ncols_dst, get_device_table_id(), small_k, halve_iters)*ggml_cuda_get_physical_warp_size(), 1) 585static __global__ void mul_mat_vec_q( 586 const void * vx_ptr, const void * vy_ptr, const int32_t * ids_ptr, const ggml_cuda_mm_fusion_args_device fusion, float * dst_ptr, 587 const uint32_t ncols_x, const uint3 nchannels_y, const uint32_t stride_row_x, const uint32_t stride_col_y, 588 const uint32_t stride_col_dst, const uint3 channel_ratio, const uint32_t stride_channel_x, 589 const uint32_t stride_channel_y, const uint32_t stride_channel_dst, const uint3 sample_ratio, 590 const uint32_t stride_sample_x, const uint32_t stride_sample_y, const uint32_t stride_sample_dst, 591 const uint32_t ids_stride) { 592 const void * GGML_CUDA_RESTRICT vx = vx_ptr; 593 const void * GGML_CUDA_RESTRICT vy = vy_ptr; 594 const int32_t * GGML_CUDA_RESTRICT ids = ids_ptr; 595 float * GGML_CUDA_RESTRICT dst = dst_ptr; 596 597 constexpr int qk = ggml_cuda_type_traits<type>::qk; 598 constexpr int qi = ggml_cuda_type_traits<type>::qi; 599 constexpr int vdr = get_vdr_mmvq(type); 600 constexpr mmvq_parameter_table_id table_id = get_device_table_id(); 601 constexpr int nwarps = calc_nwarps(type, ncols_dst, table_id, small_k, halve_iters); 602 constexpr int rows_per_cuda_block = calc_rows_per_block(ncols_dst, table_id, small_k, nwarps); 603 constexpr int warp_size = ggml_cuda_get_physical_warp_size(); 604 605 constexpr vec_dot_q_cuda_t vec_dot_q_cuda = get_vec_dot_q_cuda(type); 606 607 const int tid = warp_size*threadIdx.y + threadIdx.x; 608 const int row0 = rows_per_cuda_block*blockIdx.x; 609 const int blocks_per_row_x = ncols_x / qk; 610 constexpr int blocks_per_iter = vdr * nwarps*warp_size / qi; 611 612 const uint32_t channel_dst = blockIdx.y; 613 614 uint32_t channel_x; 615 uint32_t channel_y; 616 uint32_t sample_dst; 617 618 ggml_cuda_pdl_sync(); 619 channel_x = ncols_dst == 1 && ids ? ids[channel_dst] : fastdiv(channel_dst, channel_ratio); 620 channel_y = ncols_dst == 1 && ids ? fastmodulo(channel_dst, nchannels_y) : channel_dst; 621 sample_dst = blockIdx.z; 622 623 const uint32_t sample_x = fastdiv(sample_dst, sample_ratio); 624 const uint32_t sample_y = sample_dst; 625 626 bool use_gate = false; 627 bool use_bias = false; 628 bool use_gate_bias = false; 629 bool use_scale = false; 630 bool use_gate_scale = false; 631 [[maybe_unused]] const void * vgate = nullptr; 632 const float * x_bias = nullptr; 633 const float * gate_bias = nullptr; 634 const float * x_scale = nullptr; 635 const float * gate_scale = nullptr; 636 ggml_glu_op active_glu; 637 float glu_limit = 0.0f; 638 639 if constexpr (has_fusion) { 640 use_gate = fusion.gate != nullptr; 641 use_bias = fusion.x_bias != nullptr; 642 use_gate_bias = fusion.gate_bias != nullptr && use_gate; 643 vgate = fusion.gate; 644 x_bias = (const float *) fusion.x_bias; 645 gate_bias = (const float *) fusion.gate_bias; 646 active_glu = fusion.glu_op; 647 glu_limit = fusion.glu_limit; 648 if constexpr (type == GGML_TYPE_NVFP4) { 649 use_scale = fusion.x_scale != nullptr; 650 use_gate_scale = fusion.gate_scale != nullptr && use_gate; 651 x_scale = (const float *) fusion.x_scale; 652 gate_scale = (const float *) fusion.gate_scale; 653 } 654 } 655 656 657 [[maybe_unused]] float x_biases[ncols_dst] = { 0.0f }; 658 [[maybe_unused]] float gate_biases[ncols_dst] = { 0.0f }; 659 [[maybe_unused]] float x_scales = 1.0f; 660 [[maybe_unused]] float gate_scales = 1.0f; 661 if constexpr (has_fusion) { 662 // 1. Hide latency by prefetching bias, gates and scales here 663 // 2. load only on threads that won't die after partial sum calculation 664 const uint32_t channel_bias = ids ? channel_x : channel_dst; 665 if (threadIdx.x < rows_per_cuda_block && threadIdx.y == 0 && 666 (rows_per_cuda_block == 1 || uint32_t(row0 + threadIdx.x) < stride_col_dst)) { 667 if (use_bias) { 668 x_bias = x_bias + sample_dst * stride_sample_dst + channel_bias * stride_channel_dst + row0; 669#pragma unroll 670 for (int j = 0; j < ncols_dst; ++j) { 671 x_biases[j] = x_bias[j * stride_col_dst + threadIdx.x]; 672 } 673 } 674 if (use_gate_bias) { 675 gate_bias = gate_bias + sample_dst * stride_sample_dst + channel_bias * stride_channel_dst + row0; 676#pragma unroll 677 for (int j = 0; j < ncols_dst; ++j) { 678 gate_biases[j] = gate_bias[j * stride_col_dst + threadIdx.x]; 679 } 680 } 681 if constexpr (type == GGML_TYPE_NVFP4) { 682 if (use_scale) { 683 x_scales = x_scale[ids ? channel_x : 0]; 684 } 685 if (use_gate_scale) { 686 gate_scales = gate_scale[ids ? channel_x : 0]; 687 } 688 } 689 } 690 } 691 692 // partial sum for each thread 693 float tmp[ncols_dst][rows_per_cuda_block] = {{0.0f}}; 694 float tmp_gate[ncols_dst][rows_per_cuda_block] = {{0.0f}}; 695 696 const block_q8_1 * y = ((const block_q8_1 *) vy) + sample_y*stride_sample_y + channel_y*stride_channel_y; 697 const int kbx_offset = sample_x*stride_sample_x + channel_x*stride_channel_x + row0*stride_row_x; 698 699 for (int kbx = tid / (qi/vdr); kbx < blocks_per_row_x; kbx += blocks_per_iter) { 700 const int kby = kbx * (qk/QK8_1); // y block index that aligns with kbx 701 702 // x block quant index when casting the quants to int 703 const int kqs = vdr * (tid % (qi/vdr)); 704 705#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ == GGML_CUDA_CC_DGX_SPARK 706 // start the next iterations' weight loads early 707 if constexpr (mmvq_should_prefetch(type)) { 708 constexpr int pf_dist = 2; // loop iterations, not blocks 709 const int kbx_pf = kbx + pf_dist*blocks_per_iter; 710 if (kbx_pf < blocks_per_row_x) { 711#pragma unroll 712 for (int i = 0; i < rows_per_cuda_block; ++i) { 713 const size_t off = (size_t)(kbx_offset + i*stride_row_x + kbx_pf) * ggml_cuda_type_traits<type>::bs; 714 mmvq_prefetch_l2((const char *) vx + off); 715 if constexpr (has_fusion) { 716 if (use_gate) { 717 mmvq_prefetch_l2((const char *) vgate + off); 718 } 719 } 720 } 721 } 722 } 723#endif 724 725#pragma unroll 726 for (int j = 0; j < ncols_dst; ++j) { 727#pragma unroll 728 for (int i = 0; i < rows_per_cuda_block; ++i) { 729 tmp[j][i] += vec_dot_q_cuda( 730 vx, &y[j*stride_col_y + kby], kbx_offset + i*stride_row_x + kbx, kqs); 731 if constexpr (has_fusion) { 732 if (use_gate) { 733 tmp_gate[j][i] += vec_dot_q_cuda( 734 vgate, &y[j*stride_col_y + kby], kbx_offset + i*stride_row_x + kbx, kqs); 735 } 736 } 737 } 738 } 739 } 740 741 __shared__ float tmp_shared[nwarps-1 > 0 ? nwarps-1 : 1][ncols_dst][rows_per_cuda_block][warp_size]; 742 [[maybe_unused]] __shared__ float tmp_shared_gate[(has_fusion && (nwarps-1 > 0)) ? nwarps-1 : 1][ncols_dst][rows_per_cuda_block][warp_size]; 743 744 if (threadIdx.y > 0) { 745#pragma unroll 746 for (int j = 0; j < ncols_dst; ++j) { 747#pragma unroll 748 for (int i = 0; i < rows_per_cuda_block; ++i) { 749 tmp_shared[threadIdx.y-1][j][i][threadIdx.x] = tmp[j][i]; 750 if constexpr (has_fusion) { 751 if (use_gate) { 752 tmp_shared_gate[threadIdx.y-1][j][i][threadIdx.x] = tmp_gate[j][i]; 753 } 754 } 755 } 756 } 757 } 758 __syncthreads(); 759 if (threadIdx.y > 0) { 760 return; 761 } 762 763 dst += sample_dst*stride_sample_dst + channel_dst*stride_channel_dst + row0; 764 765 // sum up partial sums and write back result 766#pragma unroll 767 for (int j = 0; j < ncols_dst; ++j) { 768#pragma unroll 769 for (int i = 0; i < rows_per_cuda_block; ++i) { 770#pragma unroll 771 for (int l = 0; l < nwarps-1; ++l) { 772 tmp[j][i] += tmp_shared[l][j][i][threadIdx.x]; 773 if constexpr (has_fusion) { 774 if (use_gate) { 775 tmp_gate[j][i] += tmp_shared_gate[l][j][i][threadIdx.x]; 776 } 777 } 778 } 779 tmp[j][i] = warp_reduce_sum<warp_size>(tmp[j][i]); 780 if constexpr (has_fusion) { 781 if (use_gate) { 782 tmp_gate[j][i] = warp_reduce_sum<warp_size>(tmp_gate[j][i]); 783 } 784 } 785 786 if (threadIdx.x == i && (rows_per_cuda_block == 1 || uint32_t(row0 + i) < stride_col_dst)) { 787 float result = tmp[j][i]; 788 if constexpr (has_fusion) { 789 if constexpr (type == GGML_TYPE_NVFP4) { 790 result *= x_scales; 791 } 792 result += x_biases[j]; 793 if (use_gate) { 794 float gate_value = tmp_gate[j][i]; 795 if constexpr (type == GGML_TYPE_NVFP4) { 796 gate_value *= gate_scales; 797 } 798 gate_value += gate_biases[j]; 799 switch (active_glu) { 800 case GGML_GLU_OP_SWIGLU: 801 result *= ggml_cuda_op_silu_single(gate_value); 802 break; 803 case GGML_GLU_OP_GEGLU: 804 result *= ggml_cuda_op_gelu_single(gate_value); 805 break; 806 case GGML_GLU_OP_SWIGLU_OAI: 807 result = ggml_cuda_op_swiglu_oai_single(gate_value, result); 808 break; 809 case GGML_GLU_OP_SWIGLU_CLAMP: 810 result = ggml_cuda_op_swiglu_clamp_single(gate_value, result, glu_limit); 811 break; 812 default: 813 result = result * gate_value; 814 break; 815 } 816 } 817 } 818 dst[j*stride_col_dst + i] = result; 819 } 820 } 821 } 822 823 if constexpr (!has_fusion) { 824 GGML_UNUSED_VARS(use_gate, use_bias, use_gate_bias, use_scale, use_gate_scale, active_glu, glu_limit, gate_bias, x_bias, x_scale, gate_scale, tmp_gate); 825 } 826 if constexpr (type != GGML_TYPE_NVFP4) { 827 GGML_UNUSED_VARS(use_scale, use_gate_scale, x_scale, gate_scale, x_scales, gate_scales); 828 } 829} 830 831// Dedicated MoE multi-token kernel. 832// Grid: (ceil(nrows_x / c_rows_per_block), nchannels_dst) 833// Block: (warp_size, ncols_dst) - each warp handles one token independently. 834// No shared memory reduction needed since each warp works alone. 835template <ggml_type type, int c_rows_per_block, bool has_fusion = false> 836__launch_bounds__(get_mmvq_mmid_max_batch_for_device<type>()*ggml_cuda_get_physical_warp_size(), 1) 837static __global__ void mul_mat_vec_q_moe( 838 const void * vx_ptr, const void * vy_ptr, const int32_t * ids_ptr, const ggml_cuda_mm_fusion_args_device fusion, 839 float * dst_ptr, 840 const uint32_t ncols_x, const uint3 nchannels_y, const uint32_t nrows_x, 841 const uint32_t stride_row_x, const uint32_t stride_col_y, const uint32_t stride_col_dst, 842 const uint32_t stride_channel_x, const uint32_t stride_channel_y, const uint32_t stride_channel_dst, 843 const uint32_t ncols_dst, const uint32_t ids_stride) { 844 const void * GGML_CUDA_RESTRICT vx = vx_ptr; 845 const void * GGML_CUDA_RESTRICT vy = vy_ptr; 846 const int32_t * GGML_CUDA_RESTRICT ids = ids_ptr; 847 float * GGML_CUDA_RESTRICT dst = dst_ptr; 848 849 constexpr int qk = ggml_cuda_type_traits<type>::qk; 850 constexpr int qi = ggml_cuda_type_traits<type>::qi; 851 constexpr int vdr = get_vdr_mmvq(type); 852 constexpr int warp_size = ggml_cuda_get_physical_warp_size(); 853 854 constexpr vec_dot_q_cuda_t vec_dot_q_cuda = get_vec_dot_q_cuda(type); 855 856 // fuse gate, bias, scales, and glu_op into the up projection 857 bool use_gate = false; 858 const void * vgate = nullptr; 859 const float * x_bias = nullptr; 860 const float * gate_bias = nullptr; 861 const float * x_scale = nullptr; 862 const float * gate_scale = nullptr; 863 ggml_glu_op active_glu = GGML_GLU_OP_SWIGLU; 864 float glu_limit = 0.0f; 865 866 if constexpr (has_fusion) { 867 use_gate = fusion.gate != nullptr; 868 vgate = fusion.gate; 869 x_bias = (const float *) fusion.x_bias; 870 gate_bias = (const float *) fusion.gate_bias; 871 active_glu = fusion.glu_op; 872 glu_limit = fusion.glu_limit; 873 if constexpr (type == GGML_TYPE_NVFP4) { 874 x_scale = (const float *) fusion.x_scale; 875 gate_scale = (const float *) fusion.gate_scale; 876 } 877 } 878 879 const uint32_t token_idx = threadIdx.y; 880 const int row0 = c_rows_per_block*blockIdx.x; 881 const int blocks_per_row_x = ncols_x / qk; 882 constexpr int blocks_per_iter = vdr * warp_size / qi; 883 884 const uint32_t channel_dst = blockIdx.y; 885 886 if (token_idx >= ncols_dst) { 887 return; 888 } 889 890 ggml_cuda_pdl_sync(); 891 const uint32_t channel_x = ids[channel_dst + token_idx * ids_stride]; 892 const uint32_t channel_y = fastmodulo(channel_dst, nchannels_y); 893 894 const block_q8_1 * y = ((const block_q8_1 *) vy) + channel_y*stride_channel_y + token_idx*stride_col_y; 895 const int kbx_offset = channel_x*stride_channel_x + row0*stride_row_x; 896 897 // partial sum for each thread 898 float tmp[c_rows_per_block] = {0.0f}; 899 float tmp_gate[c_rows_per_block] = {0.0f}; 900 901 for (int kbx = threadIdx.x / (qi/vdr); kbx < blocks_per_row_x; kbx += blocks_per_iter) { 902 const int kby = kbx * (qk/QK8_1); 903 const int kqs = vdr * (threadIdx.x % (qi/vdr)); 904 905#pragma unroll 906 for (int i = 0; i < c_rows_per_block; ++i) { 907 tmp[i] += vec_dot_q_cuda(vx, &y[kby], kbx_offset + i*stride_row_x + kbx, kqs); 908 if constexpr (has_fusion) { 909 if (use_gate) { 910 tmp_gate[i] += vec_dot_q_cuda(vgate, &y[kby], kbx_offset + i*stride_row_x + kbx, kqs); 911 } 912 } 913 } 914 } 915 916 ggml_cuda_pdl_lc(); 917 918 // Warp-level reduction only - no shared memory needed 919#pragma unroll 920 for (int i = 0; i < c_rows_per_block; ++i) { 921 tmp[i] = warp_reduce_sum<warp_size>(tmp[i]); 922 if constexpr (has_fusion) { 923 if (use_gate) { 924 tmp_gate[i] = warp_reduce_sum<warp_size>(tmp_gate[i]); 925 } 926 } 927 } 928 929 // Write results 930 if (threadIdx.x < c_rows_per_block && (c_rows_per_block == 1 || uint32_t(row0 + threadIdx.x) < nrows_x)) { 931 float result = tmp[threadIdx.x]; 932 if constexpr (has_fusion) { 933 const uint32_t bias_idx = channel_x*stride_channel_dst + row0 + threadIdx.x; 934 935 if constexpr (type == GGML_TYPE_NVFP4) { 936 if (x_scale) { 937 result *= x_scale[channel_x]; 938 } 939 } 940 if (x_bias) { 941 result += x_bias[bias_idx]; 942 } 943 if (use_gate) { 944 float gate_value = tmp_gate[threadIdx.x]; 945 if constexpr (type == GGML_TYPE_NVFP4) { 946 if (gate_scale) { 947 gate_value *= gate_scale[channel_x]; 948 } 949 } 950 if (gate_bias) { 951 gate_value += gate_bias[bias_idx]; 952 } 953 switch (active_glu) { 954 case GGML_GLU_OP_SWIGLU: 955 result *= ggml_cuda_op_silu_single(gate_value); 956 break; 957 case GGML_GLU_OP_GEGLU: 958 result *= ggml_cuda_op_gelu_single(gate_value); 959 break; 960 case GGML_GLU_OP_SWIGLU_OAI: 961 result = ggml_cuda_op_swiglu_oai_single(gate_value, result); 962 break; 963 case GGML_GLU_OP_SWIGLU_CLAMP: 964 result = ggml_cuda_op_swiglu_clamp_single(gate_value, result, glu_limit); 965 break; 966 default: 967 result = result * gate_value; 968 break; 969 } 970 } 971 } 972 dst[channel_dst*stride_channel_dst + token_idx*stride_col_dst + row0 + threadIdx.x] = result; 973 } 974 975 if constexpr (!has_fusion) { 976 GGML_UNUSED_VARS(use_gate, tmp_gate, vgate, x_bias, gate_bias, active_glu, glu_limit, x_scale, gate_scale); 977 } else if constexpr (type != GGML_TYPE_NVFP4) { 978 GGML_UNUSED_VARS(x_scale, gate_scale); 979 } 980} 981 982template<ggml_type type> 983static std::pair<dim3, dim3> calc_launch_params( 984 const int ncols_dst, const int nrows_x, const int nchannels_dst, const int nsamples_or_ntokens, 985 const int warp_size, const mmvq_parameter_table_id table_id, const bool small_k = false, const bool halve_iters = false) { 986 const int nwarps = calc_nwarps(type, ncols_dst, table_id, small_k, halve_iters); 987 const int rpb = calc_rows_per_block(ncols_dst, table_id, small_k, nwarps); 988 const int64_t nblocks = (nrows_x + rpb - 1) / rpb; 989 const dim3 block_nums(nblocks, nchannels_dst, nsamples_or_ntokens); 990 const dim3 block_dims(warp_size, nwarps, 1); 991 return {block_nums, block_dims}; 992} 993 994template<ggml_type type, int c_ncols_dst, bool small_k = false, bool halve_iters = false> 995static void mul_mat_vec_q_switch_fusion( 996 const void * vx, const void * vy, const int32_t * ids, const ggml_cuda_mm_fusion_args_device fusion, float * dst, 997 const uint32_t ncols_x, const uint3 nchannels_y, const uint32_t stride_row_x, const uint32_t stride_col_y, 998 const uint32_t stride_col_dst, const uint3 channel_ratio, const uint32_t stride_channel_x, 999 const uint32_t stride_channel_y, const uint32_t stride_channel_dst, const uint3 sample_ratio, 1000 const uint32_t stride_sample_x, const uint32_t stride_sample_y, const uint32_t stride_sample_dst, 1001 const dim3 & block_nums, const dim3 & block_dims, const int nbytes_shared, 1002 const uint32_t ids_stride, cudaStream_t stream) { 1003 1004 const bool has_fusion = fusion.gate != nullptr || fusion.x_bias != nullptr || fusion.gate_bias != nullptr || 1005 fusion.x_scale != nullptr || fusion.gate_scale != nullptr; 1006 if constexpr (c_ncols_dst == 1) { 1007 if (has_fusion) { 1008 const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(block_nums, block_dims, nbytes_shared, stream); 1009 ggml_cuda_kernel_launch(mul_mat_vec_q<type, c_ncols_dst, true, small_k, halve_iters>, launch_params, 1010 vx, vy, ids, fusion, dst, ncols_x, nchannels_y, stride_row_x, stride_col_y, stride_col_dst, 1011 channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst, 1012 sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride); 1013 return; 1014 } 1015 } 1016 1017 GGML_ASSERT(!has_fusion && "fusion only supported for ncols_dst=1"); 1018 1019 const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(block_nums, block_dims, nbytes_shared, stream); 1020 ggml_cuda_kernel_launch(mul_mat_vec_q<type, c_ncols_dst, false, small_k, halve_iters>, launch_params, 1021 vx, vy, ids, fusion, dst, ncols_x, nchannels_y, stride_row_x, stride_col_y, stride_col_dst, 1022 channel_ratio, stride_channel_x, stride_channel_y, stride_channel_dst, 1023 sample_ratio, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride); 1024} 1025 1026template <ggml_type type> 1027static void mul_mat_vec_q_moe_launch( 1028 const void * vx, const void * vy, const int32_t * ids, const ggml_cuda_mm_fusion_args_device fusion, float * dst, 1029 const uint32_t ncols_x, const uint3 nchannels_y, const uint32_t nrows_x, 1030 const uint32_t stride_row_x, const uint32_t stride_col_y, const uint32_t stride_col_dst, 1031 const uint32_t stride_channel_x, const uint32_t stride_channel_y, const uint32_t stride_channel_dst, 1032 const uint32_t ncols_dst, const uint32_t ids_stride, 1033 const int warp_size, const int nchannels_dst, cudaStream_t stream) { 1034 1035 constexpr int rows_per_block = 2; // 2 gives best perf based on tuning 1036 const int64_t nblocks_rows = (nrows_x + rows_per_block - 1) / rows_per_block; 1037 const dim3 block_nums(nblocks_rows, nchannels_dst); 1038 const dim3 block_dims(warp_size, ncols_dst); 1039 const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(block_nums, block_dims, 0, stream); 1040 1041 const bool has_fusion = fusion.gate != nullptr || fusion.x_bias != nullptr || fusion.gate_bias != nullptr || 1042 fusion.x_scale != nullptr || fusion.gate_scale != nullptr; 1043 1044 if (has_fusion) { 1045 ggml_cuda_kernel_launch(mul_mat_vec_q_moe<type, rows_per_block, true>, launch_params, 1046 vx, vy, ids, fusion, dst, ncols_x, nchannels_y, nrows_x, 1047 stride_row_x, stride_col_y, stride_col_dst, 1048 stride_channel_x, stride_channel_y, stride_channel_dst, 1049 ncols_dst, ids_stride); 1050 } else { 1051 ggml_cuda_kernel_launch(mul_mat_vec_q_moe<type, rows_per_block, false>, launch_params, 1052 vx, vy, ids, fusion, dst, ncols_x, nchannels_y, nrows_x, 1053 stride_row_x, stride_col_y, stride_col_dst, 1054 stride_channel_x, stride_channel_y, stride_channel_dst, 1055 ncols_dst, ids_stride); 1056 } 1057} 1058 1059template <ggml_type type> 1060static void mul_mat_vec_q_switch_ncols_dst( 1061 const void * vx, const void * vy, const int32_t * ids, const ggml_cuda_mm_fusion_args_device fusion, float * dst, 1062 const int ncols_x, const int nrows_x, const int ncols_dst, 1063 const int stride_row_x, const int stride_col_y, const int stride_col_dst, 1064 const int nchannels_x, const int nchannels_y, const int nchannels_dst, 1065 const int stride_channel_x, const int stride_channel_y, const int stride_channel_dst, 1066 const int nsamples_x, const int nsamples_dst, const int stride_sample_x, const int stride_sample_y, const int stride_sample_dst, 1067 const int ids_stride, cudaStream_t stream) { 1068 1069 GGML_ASSERT(ncols_x % ggml_blck_size(type) == 0); 1070 GGML_ASSERT(ncols_dst <= MMVQ_MAX_BATCH_SIZE); 1071 1072 const uint3 nchannels_y_fd = ids ? init_fastdiv_values(nchannels_y) : make_uint3(0, 0, 0); 1073 const uint3 channel_ratio_fd = ids ? make_uint3(0, 0, 0) : init_fastdiv_values(nchannels_dst / nchannels_x); 1074 const uint3 sample_ratio_fd = init_fastdiv_values(nsamples_dst / nsamples_x); 1075 1076 const int device = ggml_cuda_get_device(); 1077 const int cc = ggml_cuda_info().devices[device].cc; 1078 const int warp_size = ggml_cuda_info().devices[device].warp_size; 1079 const mmvq_parameter_table_id table_id = get_device_table_id(cc); 1080 1081 const bool has_ids = ids != nullptr; 1082 1083 // How the K loop divides up at the baseline block width, both decisions below use these. 1084 constexpr int qk = ggml_cuda_type_traits<type>::qk; 1085 constexpr int qi = ggml_cuda_type_traits<type>::qi; 1086 constexpr int vdr = get_vdr_mmvq(type); 1087 const int blocks_per_row_x = ncols_x / qk; 1088 const int blocks_per_iter_1warp = vdr * warp_size / qi; 1089 1090 const auto should_use_small_k = [&](int c_ncols_dst) { 1091 // When K is small, increase rows_per_block to match nwarps so each warp has more work to do 1092 // Trigger when the full thread block covers all K blocks in a single loop iteration and few threads remain idle. 1093 const int nwarps = calc_nwarps(type, c_ncols_dst, table_id); 1094 bool use = nwarps > 1 && blocks_per_row_x < nwarps * blocks_per_iter_1warp; 1095 1096 constexpr std::array<ggml_type, 2> iq_slow_turing = { 1097 GGML_TYPE_IQ3_XXS, 1098 GGML_TYPE_IQ3_S, 1099 }; 1100 constexpr std::array<ggml_type, 8> iq_slow_other = { 1101 GGML_TYPE_IQ1_S, GGML_TYPE_IQ1_M, GGML_TYPE_IQ2_XXS, GGML_TYPE_IQ2_XS, 1102 GGML_TYPE_IQ2_S, GGML_TYPE_IQ3_XXS, GGML_TYPE_IQ3_S, GGML_TYPE_IQ4_XS, 1103 }; 1104 constexpr std::array<ggml_type, 3> slow_pascal = { 1105 GGML_TYPE_IQ3_S, 1106 GGML_TYPE_Q2_K, 1107 GGML_TYPE_Q3_K, 1108 }; 1109 1110 const bool is_nvidia_turing_plus = GGML_CUDA_CC_IS_NVIDIA(cc) && cc >= GGML_CUDA_CC_TURING; 1111 const bool is_nvidia_pascal_older = GGML_CUDA_CC_IS_NVIDIA(cc) && cc < GGML_CUDA_CC_VOLTA; 1112 1113 if (is_nvidia_turing_plus) { 1114 if (ncols_dst == 1 && 1115 std::find(iq_slow_turing.begin(), iq_slow_turing.end(), type) != iq_slow_turing.end()) { 1116 use = false; 1117 } 1118 } else if ((ncols_dst == 1 && std::find(iq_slow_other.begin(), iq_slow_other.end(), type) != iq_slow_other.end()) || 1119 (is_nvidia_pascal_older && std::find(slow_pascal.begin(), slow_pascal.end(), type) != slow_pascal.end()) || 1120 GGML_CUDA_CC_IS_RDNA(cc)) { 1121 use = false; 1122 } 1123 1124 return use; 1125 }; 1126 1127 // Whether doubling nwarps pays off on the ncols_dst == 1 path, where K sets the K loop trip count. 1128 const auto should_halve_iters = [&] { 1129 if (table_id != MMVQ_PARAMETERS_GB10) { 1130 return false; 1131 } 1132 1133 // Expert rows are gathered per token, so a wider block adds reduction work without reuse. 1134 if (has_ids) { 1135 return false; 1136 } 1137 1138 const int blocks_per_iter = calc_nwarps(type, 1, table_id) * blocks_per_iter_1warp; 1139 const int iters = (blocks_per_row_x + blocks_per_iter - 1) / blocks_per_iter; 1140 const int iters_wide = (blocks_per_row_x + blocks_per_iter * 2 - 1) / (blocks_per_iter * 2); 1141 1142 // An odd trip count leaves half the wider block idle for its last iteration, that tail is 1143 // only affordable once the loop is long enough to dilute it to an eighth of the work (observation). 1144 const int idle = iters_wide * 2 - iters; 1145 1146 return idle * 8 <= iters_wide * 2; 1147 }; 1148 1149 if (has_ids && ncols_dst > 1) { 1150 // Multi-token MUL_MAT_ID path - dedicated MoE kernel 1151 mul_mat_vec_q_moe_launch<type>( 1152 vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, nrows_x, 1153 stride_row_x, stride_col_y, stride_col_dst, 1154 stride_channel_x, stride_channel_y, stride_channel_dst, 1155 ncols_dst, ids_stride, warp_size, nchannels_dst, stream); 1156 return; 1157 } 1158 1159 switch (ncols_dst) { 1160 case 1: { 1161 // static, else MSVC lambda capture breaks the constexpr uses below 1162 static constexpr int c_ncols_dst = 1; 1163 1164 // Tag types keep the flags compile-time, so __launch_bounds__ matches what is launched. 1165 const auto launch = [&](auto small_k_tag, auto halve_iters_tag) { 1166 constexpr bool c_small_k = decltype(small_k_tag)::value; 1167 // Types the table does not promote would compile a second, identical kernel. 1168 constexpr bool c_promoted = 1169 calc_nwarps(type, c_ncols_dst, MMVQ_PARAMETERS_GB10, false, true) != 1170 calc_nwarps(type, c_ncols_dst, MMVQ_PARAMETERS_GB10, false, false); 1171 1172 constexpr bool c_halve_iters = decltype(halve_iters_tag)::value && c_promoted; 1173 1174 const std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst, 1175 nsamples_dst, warp_size, table_id, c_small_k, c_halve_iters); 1176 mul_mat_vec_q_switch_fusion<type, c_ncols_dst, c_small_k, c_halve_iters>( 1177 vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst, 1178 channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst, sample_ratio_fd, 1179 stride_sample_x, stride_sample_y, stride_sample_dst, dims.first, dims.second, 0, ids_stride, 1180 stream); 1181 }; 1182 1183 if (should_use_small_k(c_ncols_dst)) { 1184 launch(std::true_type{}, std::false_type{}); 1185 } else if (should_halve_iters()) { 1186 launch(std::false_type{}, std::true_type{}); 1187 } else { 1188 launch(std::false_type{}, std::false_type{}); 1189 } 1190 } break; 1191 case 2: { 1192 constexpr int c_ncols_dst = 2; 1193 std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst, nsamples_dst, warp_size, table_id); 1194 mul_mat_vec_q_switch_fusion<type, c_ncols_dst>(vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst, 1195 channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst, 1196 sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst, 1197 dims.first, dims.second, 0, ids_stride, stream); 1198 } break; 1199 case 3: { 1200 constexpr int c_ncols_dst = 3; 1201 std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst, nsamples_dst, warp_size, table_id); 1202 mul_mat_vec_q_switch_fusion<type, c_ncols_dst>(vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst, 1203 channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst, 1204 sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst, 1205 dims.first, dims.second, 0, ids_stride, stream); 1206 } break; 1207 case 4: { 1208 constexpr int c_ncols_dst = 4; 1209 std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst, nsamples_dst, warp_size, table_id); 1210 mul_mat_vec_q_switch_fusion<type, c_ncols_dst>(vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst, 1211 channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst, 1212 sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst, 1213 dims.first, dims.second, 0, ids_stride, stream); 1214 } break; 1215 case 5: { 1216 constexpr int c_ncols_dst = 5; 1217 std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst, nsamples_dst, warp_size, table_id); 1218 mul_mat_vec_q_switch_fusion<type, c_ncols_dst>(vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst, 1219 channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst, 1220 sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst, 1221 dims.first, dims.second, 0, ids_stride, stream); 1222 } break; 1223 case 6: { 1224 constexpr int c_ncols_dst = 6; 1225 std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst, nsamples_dst, warp_size, table_id); 1226 mul_mat_vec_q_switch_fusion<type, c_ncols_dst>(vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst, 1227 channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst, 1228 sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst, 1229 dims.first, dims.second, 0, ids_stride, stream); 1230 } break; 1231 case 7: { 1232 constexpr int c_ncols_dst = 7; 1233 std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst, nsamples_dst, warp_size, table_id); 1234 mul_mat_vec_q_switch_fusion<type, c_ncols_dst>(vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst, 1235 channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst, 1236 sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst, 1237 dims.first, dims.second, 0, ids_stride, stream); 1238 } break; 1239 case 8: { 1240 constexpr int c_ncols_dst = 8; 1241 std::pair<dim3, dim3> dims = calc_launch_params<type>(c_ncols_dst, nrows_x, nchannels_dst, nsamples_dst, warp_size, table_id); 1242 mul_mat_vec_q_switch_fusion<type, c_ncols_dst>(vx, vy, ids, fusion, dst, ncols_x, nchannels_y_fd, stride_row_x, stride_col_y, stride_col_dst, 1243 channel_ratio_fd, stride_channel_x, stride_channel_y, stride_channel_dst, 1244 sample_ratio_fd, stride_sample_x, stride_sample_y, stride_sample_dst, 1245 dims.first, dims.second, 0, ids_stride, stream); 1246 } break; 1247 default: 1248 GGML_ABORT("fatal error"); 1249 break; 1250 } 1251} 1252static void mul_mat_vec_q_switch_type( 1253 const void * vx, const ggml_type type_x, const void * vy, const int32_t * ids, const ggml_cuda_mm_fusion_args_device fusion, float * dst, 1254 const int ncols_x, const int nrows_x, const int ncols_dst, 1255 const int stride_row_x, const int stride_col_y, const int stride_col_dst, 1256 const int nchannels_x, const int nchannels_y, const int nchannels_dst, 1257 const int stride_channel_x, const int stride_channel_y, const int stride_channel_dst, 1258 const int nsamples_x, const int nsamples_dst, const int stride_sample_x, const int stride_sample_y, const int stride_sample_dst, 1259 const int ids_stride, cudaStream_t stream) { 1260 switch (type_x) { 1261 case GGML_TYPE_Q1_0: 1262 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q1_0> 1263 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1264 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1265 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1266 break; 1267 case GGML_TYPE_Q2_0: 1268 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q2_0> 1269 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1270 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1271 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1272 break; 1273 case GGML_TYPE_Q4_0: 1274 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q4_0> 1275 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1276 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1277 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1278 break; 1279 case GGML_TYPE_Q4_1: 1280 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q4_1> 1281 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1282 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1283 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1284 break; 1285 case GGML_TYPE_Q5_0: 1286 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q5_0> 1287 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1288 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1289 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1290 break; 1291 case GGML_TYPE_Q5_1: 1292 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q5_1> 1293 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1294 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1295 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1296 break; 1297 case GGML_TYPE_Q8_0: 1298 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q8_0> 1299 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1300 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1301 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1302 break; 1303 case GGML_TYPE_MXFP4: 1304 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_MXFP4> 1305 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1306 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1307 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1308 break; 1309 case GGML_TYPE_NVFP4: 1310 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_NVFP4> 1311 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1312 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1313 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1314 break; 1315 case GGML_TYPE_Q2_K: 1316 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q2_K> 1317 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1318 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1319 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1320 break; 1321 case GGML_TYPE_Q3_K: 1322 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q3_K> 1323 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1324 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1325 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1326 break; 1327 case GGML_TYPE_Q4_K: 1328 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q4_K> 1329 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1330 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1331 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1332 break; 1333 case GGML_TYPE_Q5_K: 1334 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q5_K> 1335 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1336 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1337 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1338 break; 1339 case GGML_TYPE_Q6_K: 1340 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_Q6_K> 1341 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1342 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1343 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1344 break; 1345 case GGML_TYPE_IQ2_XXS: 1346 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ2_XXS> 1347 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1348 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1349 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1350 break; 1351 case GGML_TYPE_IQ2_XS: 1352 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ2_XS> 1353 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1354 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1355 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1356 break; 1357 case GGML_TYPE_IQ2_S: 1358 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ2_S> 1359 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1360 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1361 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1362 break; 1363 case GGML_TYPE_IQ3_XXS: 1364 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ3_XXS> 1365 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1366 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1367 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1368 break; 1369 case GGML_TYPE_IQ1_S: 1370 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ1_S> 1371 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1372 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1373 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1374 break; 1375 case GGML_TYPE_IQ1_M: 1376 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ1_M> 1377 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1378 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1379 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1380 break; 1381 case GGML_TYPE_IQ4_NL: 1382 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ4_NL> 1383 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1384 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1385 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1386 break; 1387 case GGML_TYPE_IQ4_XS: 1388 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ4_XS> 1389 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1390 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1391 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1392 break; 1393 case GGML_TYPE_IQ3_S: 1394 mul_mat_vec_q_switch_ncols_dst<GGML_TYPE_IQ3_S> 1395 (vx, vy, ids, fusion, dst, ncols_x, nrows_x, ncols_dst, stride_row_x, stride_col_y, stride_col_dst, 1396 nchannels_x, nchannels_y, nchannels_dst, stride_channel_x, stride_channel_y, stride_channel_dst, 1397 nsamples_x, nsamples_dst, stride_sample_x, stride_sample_y, stride_sample_dst, ids_stride, stream); 1398 break; 1399 default: 1400 GGML_ABORT("fatal error"); 1401 break; 1402 } 1403} 1404 1405void ggml_cuda_mul_mat_vec_q( 1406 ggml_backend_cuda_context & ctx, const ggml_tensor * src0, const ggml_tensor * src1, const ggml_tensor * ids, ggml_tensor * dst, 1407 const ggml_cuda_mm_fusion_args_host * fusion) { 1408 GGML_ASSERT( src1->type == GGML_TYPE_F32); 1409 GGML_ASSERT( dst->type == GGML_TYPE_F32); 1410 GGML_ASSERT(!ids || ids->type == GGML_TYPE_I32); // Optional, used for batched GGML_MUL_MAT_ID. 1411 1412 GGML_TENSOR_BINARY_OP_LOCALS; 1413 1414 cudaStream_t stream = ctx.stream(); 1415 1416 const size_t ts_src0 = ggml_type_size(src0->type); 1417 const size_t ts_src1 = ggml_type_size(src1->type); 1418 const size_t ts_dst = ggml_type_size(dst->type); 1419 1420 GGML_ASSERT( nb00 == ts_src0); 1421 GGML_ASSERT( nb10 == ts_src1); 1422 GGML_ASSERT( nb0 == ts_dst); 1423 GGML_ASSERT(!ids || ids->nb[0] == ggml_type_size(ids->type)); 1424 1425 GGML_ASSERT(!ids || ne12 <= MMVQ_MAX_BATCH_SIZE); 1426 1427 const float * src1_d = (const float *) src1->data; 1428 const int32_t * ids_d = ids ? (const int32_t *) ids->data : nullptr; 1429 float * dst_d = (float *) dst->data; 1430 1431 ggml_cuda_mm_fusion_args_device fusion_local{}; 1432 1433 if (fusion) { 1434 const int cc = ggml_cuda_info().devices[ggml_cuda_get_device()].cc; 1435 GGML_ASSERT( !ids || dst->ne[2] <= get_mmvq_mmid_max_batch(src0->type, cc)); 1436 GGML_ASSERT( ids || dst->ne[1] == 1); 1437 // Scale fusion is only allowed for NVFP4 currently as the cost of checking this at run-time in the prologue is 1438 // non-negligible for some models such as gpt-oss-20b 1439 GGML_ASSERT((fusion->x_scale == nullptr && fusion->gate_scale == nullptr) || src0->type == GGML_TYPE_NVFP4); 1440 1441 if (fusion->x_bias) { 1442 GGML_ASSERT(fusion->x_bias->type == GGML_TYPE_F32); 1443 GGML_ASSERT(fusion->x_bias->ne[0] == dst->ne[0]); 1444 GGML_ASSERT(!ids || fusion->x_bias->ne[1] == src0->ne[2]); 1445 fusion_local.x_bias = fusion->x_bias->data; 1446 } 1447 if (fusion->gate) { 1448 GGML_ASSERT(fusion->gate->type == src0->type && ggml_are_same_stride(fusion->gate, src0)); 1449 fusion_local.gate = fusion->gate->data; 1450 } 1451 if (fusion->gate_bias) { 1452 GGML_ASSERT(fusion->gate_bias->type == GGML_TYPE_F32); 1453 GGML_ASSERT(fusion->gate_bias->ne[0] == dst->ne[0]); 1454 GGML_ASSERT(!ids || fusion->gate_bias->ne[1] == src0->ne[2]); 1455 fusion_local.gate_bias = fusion->gate_bias->data; 1456 } 1457 if (fusion->x_scale) { 1458 GGML_ASSERT(fusion->x_scale->type == GGML_TYPE_F32); 1459 GGML_ASSERT(ggml_is_contiguous(fusion->x_scale)); 1460 GGML_ASSERT(ggml_nelements(fusion->x_scale) == (ids ? src0->ne[2] : 1)); 1461 fusion_local.x_scale = fusion->x_scale->data; 1462 } 1463 if (fusion->gate_scale) { 1464 GGML_ASSERT(fusion->gate_scale->type == GGML_TYPE_F32); 1465 GGML_ASSERT(ggml_is_contiguous(fusion->gate_scale)); 1466 GGML_ASSERT(ggml_nelements(fusion->gate_scale) == (ids ? src0->ne[2] : 1)); 1467 fusion_local.gate_scale = fusion->gate_scale->data; 1468 } 1469 fusion_local.glu_op = fusion->glu_op; 1470 fusion_local.glu_limit = fusion->glu_limit; 1471 } 1472 1473 // If src0 is a temporary compute buffer, clear any potential padding. 1474 if (ggml_backend_buffer_get_usage(src0->buffer) == GGML_BACKEND_BUFFER_USAGE_COMPUTE) { 1475 const size_t size_data = ggml_nbytes(src0); 1476 const size_t size_alloc = ggml_backend_buffer_get_alloc_size(src0->buffer, src0); 1477 if (size_alloc > size_data) { 1478 GGML_ASSERT(ggml_is_contiguously_allocated(src0)); 1479 GGML_ASSERT(!src0->view_src); 1480 CUDA_CHECK(cudaMemsetAsync((char *) src0->data + size_data, 0, size_alloc - size_data, stream)); 1481 } 1482 } 1483 1484 const int64_t ne10_padded = GGML_PAD(ne10, MATRIX_ROW_PADDING); 1485 ggml_cuda_pool_alloc<char> src1_q8_1(ctx.pool(), ne13*ne12 * ne11*ne10_padded * sizeof(block_q8_1)/QK8_1); 1486 { 1487 const int64_t s11 = src1->nb[1] / ts_src1; 1488 const int64_t s12 = src1->nb[2] / ts_src1; 1489 const int64_t s13 = src1->nb[3] / ts_src1; 1490 quantize_row_q8_1_cuda(src1_d, nullptr, src1_q8_1.get(), src0->type, ne10, s11, s12, s13, ne10_padded, ne11, ne12, ne13, stream); 1491 } 1492 1493 const int64_t s01 = src0->nb[1] / ts_src0; 1494 const int64_t s11 = ne10_padded / QK8_1; 1495 const int64_t s1 = dst->nb[1] / ts_dst; 1496 const int64_t s02 = src0->nb[2] / ts_src0; 1497 const int64_t s2 = dst->nb[2] / ts_dst; 1498 const int64_t s03 = src0->nb[3] / ts_src0; 1499 const int64_t s3 = dst->nb[3] / ts_dst; 1500 1501 const int64_t s12 = ne11*s11; 1502 const int64_t s13 = ne12*s12; 1503 1504 // For MUL_MAT_ID the memory layout is different than for MUL_MAT: 1505 const int64_t ncols_dst = ids ? ne2 : ne1; 1506 const int64_t nchannels_y = ids ? ne11 : ne12; 1507 const int64_t nchannels_dst = ids ? ne1 : ne2; 1508 const int64_t stride_col_dst = ids ? s2 : s1; 1509 const int64_t stride_col_y = ids ? s12 : s11; 1510 const int64_t stride_channel_dst = ids ? s1 : s2; 1511 const int64_t stride_channel_y = ids ? s11 : s12; 1512 1513 const int64_t ids_stride = ids ? ids->nb[1] / ggml_type_size(ids->type) : 0; 1514 1515 mul_mat_vec_q_switch_type( 1516 src0->data, src0->type, src1_q8_1.get(), ids_d, fusion_local, dst_d, ne00, 1517 ne01, ncols_dst, s01, stride_col_y, stride_col_dst, 1518 ne02, nchannels_y, nchannels_dst, s02, stride_channel_y, stride_channel_dst, 1519 ne03, ne3, s03, s13, s3, ids_stride, stream); 1520} 1521 1522void ggml_cuda_op_mul_mat_vec_q( 1523 ggml_backend_cuda_context & ctx, 1524 const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst, const char * src0_dd_i, const float * src1_ddf_i, 1525 const char * src1_ddq_i, float * dst_dd_i, const int64_t row_low, const int64_t row_high, const int64_t src1_ncols, 1526 const int64_t src1_padded_row_size, cudaStream_t stream) { 1527 1528 const int64_t ne00 = src0->ne[0]; 1529 const int64_t row_diff = row_high - row_low; 1530 1531 const int64_t ne10 = src1->ne[0]; 1532 GGML_ASSERT(ne10 % QK8_1 == 0); 1533 1534 const int64_t ne0 = dst->ne[0]; 1535 1536 int id = ggml_cuda_get_device(); 1537 1538 // the main device has a larger memory buffer to hold the results from all GPUs 1539 // nrows_dst == nrows of the matrix that the kernel writes into 1540 const int64_t nrows_dst = id == ctx.device ? ne0 : row_diff; 1541 1542 const int stride_row_x = ne00 / ggml_blck_size(src0->type); 1543 const int stride_col_y = src1_padded_row_size / QK8_1; 1544 1545 ggml_cuda_mm_fusion_args_device fusion_local{}; 1546 mul_mat_vec_q_switch_type( 1547 src0_dd_i, src0->type, src1_ddq_i, nullptr, fusion_local, dst_dd_i, ne00, row_diff, src1_ncols, stride_row_x, stride_col_y, nrows_dst, 1548 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, stream); 1549 1550 GGML_UNUSED_VARS(src1, dst, src1_ddf_i, src1_ncols, src1_padded_row_size); 1551}