char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

fairydreamingcuda : CUDA GGML_OP_LIGHTNING_INDEXER implementation (generic vector kernel + wmma kernel) (#25545)3b5321936

char/aliceai-t5-moe
23.6 KiB588 linesraw
1#include "common.cuh"
2#include "lightning-indexer.cuh"
3#include "fattn-common.cuh"
4#include "convert.cuh"
5
6#if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
7#if defined(TURING_MMA_AVAILABLE)
8
9typedef union {
10    int2 i2;
11    half2 h2[2];
12} half4;
13
14// TODO add support for AMD cards via rocWMMA
15#include <mma.h>
16namespace wmma = nvcuda::wmma;
17
18template <int WARPS_PER_BLOCK, int K_VECS_PER_BLOCK, int64_t N_EMBD, int64_t N_HEAD, ggml_type TYPE_K>
19static __global__ void lightning_indexer_kernel_wmma(
20        const float * Q, const char * K, const float * W, const half * M, float * dst,
21        int64_t n_stream, int64_t n_batch, int64_t n_kv,
22        size_t nb1, size_t nb2, size_t nb3,
23        size_t nbq1, size_t nbq2, size_t nbq3,
24        size_t nbk1, size_t nbk2, size_t nbk3,
25        size_t nbw1, size_t nbw2, size_t nbw3,
26        size_t nbm1, size_t nbm2, size_t nbm3,
27        int64_t nem3
28    ) {
29
30    constexpr int THREADS_PER_BLOCK = WARPS_PER_BLOCK * WARP_SIZE;
31    constexpr int HEADS_PER_INNER_LOOP = 8;
32    constexpr int K_EMBD_PER_INNER_LOOP = 16;
33    constexpr int N_EMBD_PADDED = N_EMBD + 8;
34
35    const int i_batch  = blockIdx.y;
36    const int i_stream = blockIdx.z;
37    const int i_warp   = threadIdx.y;
38    const int i_lane   = threadIdx.x;
39    const int tid      = i_warp * WARP_SIZE + i_lane;
40
41    // each block processes K_VECS_PER_BLOCK K vectors
42    const int start_kv = blockIdx.x * K_VECS_PER_BLOCK;
43
44    const char  * q_base = (const char  *)                 Q + i_batch*nbq2 + i_stream*nbq3;
45    const float * w_base = (const float *) ((const char *) W + i_batch*nbw1 + i_stream*nbw3);
46
47    // phase 1 - load weights and first Q tile to shared memory
48
49    __shared__ float w_shared[N_HEAD];
50    __shared__ int2  q_shared_h[HEADS_PER_INNER_LOOP][N_EMBD_PADDED / 4];
51
52    if (tid < N_HEAD) {
53        w_shared[tid] = w_base[tid];
54    }
55
56    // total number of half4 elements in HEADS_PER_INNER_LOOP x N_EMBD Q tile
57    constexpr int N_Q_TILE = HEADS_PER_INNER_LOOP * (N_EMBD / 4);
58    // number of registers needed in each thread to store Q tile in thread block
59    constexpr int N_Q_NEXT = (N_Q_TILE + THREADS_PER_BLOCK - 1) / THREADS_PER_BLOCK;
60
61#pragma unroll
62    for (int i_q = tid; i_q < N_Q_TILE; i_q += THREADS_PER_BLOCK) {
63        const int i_head = i_q / (N_EMBD / 4);
64        const int i_embd = i_q % (N_EMBD / 4);
65        const float4 q = *(const float4 *) (q_base + i_head*nbq1 + i_embd*sizeof(float4));
66        half4 q_packed;
67        q_packed.h2[0] = __float22half2_rn(make_float2(q.x, q.y));
68        q_packed.h2[1] = __float22half2_rn(make_float2(q.z, q.w));
69        q_shared_h[i_head][i_embd] = q_packed.i2;
70    }
71
72    // phase 2 - load (and dequantize if needed) K to shared mem
73
74    __shared__ half2 k_shared_h[K_VECS_PER_BLOCK][N_EMBD_PADDED / 4][2];
75
76    constexpr int n_k = K_VECS_PER_BLOCK * (N_EMBD / 4);
77
78    if constexpr (TYPE_K == GGML_TYPE_F16) {
79#pragma unroll
80        for (int i_k = tid; i_k < n_k; i_k += THREADS_PER_BLOCK) {
81            const int i_k_vec = i_k / (N_EMBD / 4);
82            const int i_embd = i_k % (N_EMBD / 4);
83            const int i_kv = start_kv + i_k_vec;
84            if (i_kv < n_kv) {
85                const int2 * k_base = (const int2 *) ((const char *) K + i_kv*nbk2 + i_stream*nbk3);
86                *(int2*) &k_shared_h[i_k_vec][i_embd] = k_base[i_embd];
87            } else {
88                *(int2*) &k_shared_h[i_k_vec][i_embd] = make_int2(0, 0);
89            }
90        }
91    } else {
92        constexpr dequantize_V_t dequantize_k = get_dequantize_V<TYPE_K, half, 4>();
93#pragma unroll
94        for (int i_k = tid; i_k < n_k; i_k += THREADS_PER_BLOCK) {
95            const int i_k_vec = i_k / (N_EMBD / 4);
96            const int i_embd = i_k % (N_EMBD / 4);
97            const int i_kv = start_kv + i_k_vec;
98            if (i_kv < n_kv) {
99                const void * k_base = (const void *) ((const char *) K + i_kv*nbk2 + i_stream*nbk3);
100                dequantize_k(k_base, &k_shared_h[i_k_vec][i_embd][0], i_embd * 4);
101            } else {
102                *(int2*) &k_shared_h[i_k_vec][i_embd] = make_int2(0, 0);
103            }
104        }
105    }
106
107    __syncthreads();
108
109    // phase 3 - calculate lightning indexer scores
110
111    __shared__ float qk_shared[WARPS_PER_BLOCK][HEADS_PER_INNER_LOOP][K_VECS_PER_BLOCK];
112
113    // load K fragment
114    wmma::fragment<wmma::matrix_b, HEADS_PER_INNER_LOOP, K_VECS_PER_BLOCK, K_EMBD_PER_INNER_LOOP, half, wmma::col_major> frag_k;
115    wmma::load_matrix_sync(frag_k, (half*) &k_shared_h[0][i_warp * K_EMBD_PER_INNER_LOOP / 4], N_EMBD_PADDED);
116
117    float score_k = 0.0f;
118
119    for (int i_head_0 = 0; i_head_0 < N_HEAD; i_head_0 += HEADS_PER_INNER_LOOP) {
120        const int i_head_next = i_head_0 + HEADS_PER_INNER_LOOP;
121
122        // we don't use accumulator for anything, fill it with zeros
123        wmma::fragment<wmma::accumulator, HEADS_PER_INNER_LOOP, K_VECS_PER_BLOCK, K_EMBD_PER_INNER_LOOP, float> frag_acc;
124        wmma::fill_fragment(frag_acc, 0.0f);
125
126        // load Q fragment
127        wmma::fragment<wmma::matrix_a, HEADS_PER_INNER_LOOP, K_VECS_PER_BLOCK, K_EMBD_PER_INNER_LOOP, half, wmma::row_major> frag_q;
128        wmma::load_matrix_sync(frag_q, (half*) &q_shared_h[0][i_warp * K_EMBD_PER_INNER_LOOP / 4], N_EMBD_PADDED);
129
130        // preload next Q tile to registers during matrix multiplication
131        float4 q_next[N_Q_NEXT];
132
133        if (i_head_next < N_HEAD) {
134#pragma unroll
135            for (int i_q = tid, i_q_next = 0; i_q < N_Q_TILE; i_q += THREADS_PER_BLOCK) {
136                const int i_head = i_head_next + i_q / (N_EMBD / 4);
137                const int i_embd =               i_q % (N_EMBD / 4);
138                q_next[i_q_next++] = *(const float4 *) (q_base + i_head*nbq1 + i_embd*sizeof(float4));
139            }
140        }
141
142        // perform matrix multiplication
143        wmma::mma_sync(frag_acc, frag_q, frag_k, frag_acc);
144        wmma::store_matrix_sync((float*) &qk_shared[i_warp][0][0], frag_acc, K_VECS_PER_BLOCK, wmma::mem_row_major);
145
146        // make sure all threads finished using q_shared_h so we can store next tile
147        __syncthreads();
148
149        // write preloaded Q tile to shared memory
150        if (i_head_next < N_HEAD) {
151#pragma unroll
152            for (int i_q = tid, i_q_next = 0; i_q < N_Q_TILE; i_q += THREADS_PER_BLOCK) {
153                const int i_head = i_q / (N_EMBD / 4);
154                const int i_embd = i_q % (N_EMBD / 4);
155                half4 q_packed;
156                q_packed.h2[0] = __float22half2_rn(make_float2(q_next[i_q_next].x, q_next[i_q_next].y));
157                q_packed.h2[1] = __float22half2_rn(make_float2(q_next[i_q_next].z, q_next[i_q_next].w));
158                q_shared_h[i_head][i_embd] = q_packed.i2;
159                ++i_q_next;
160            }
161        }
162
163        // accumulate QK multiplication results from all block warps
164        // (there are 256 threads in block and 256 matmul outputs)
165        // TODO it will break if WARP_SIZE is not 32
166        const int h = tid / K_VECS_PER_BLOCK;
167        const int k = tid % K_VECS_PER_BLOCK;
168        const float w_val = w_shared[i_head_0 + h];
169
170        float sum = 0.0f;
171#pragma unroll
172        for (int w = 0; w < WARPS_PER_BLOCK; ++w) {
173            sum += qk_shared[w][h][k];
174        }
175
176        // ReLU, weight
177        sum = sum > 0.0f ? sum : 0.0f;
178        sum *= w_val;
179
180        // wait until qk_shared[0] is no longer used
181        __syncthreads();
182
183        // reuse qk_shared[0] for storing partial results
184        qk_shared[0][h][k] = sum;
185
186        // wait until all threads write their results
187        __syncthreads();
188
189        // accumulate result over heads
190        if (tid < K_VECS_PER_BLOCK) {
191#pragma unroll
192            for (int i_head = 0; i_head < HEADS_PER_INNER_LOOP; ++i_head) {
193                score_k += qk_shared[0][i_head][tid];
194            }
195        }
196
197        // make sure all threads finished using qk_shared
198        __syncthreads();
199    }
200
201    // phase 4 - store output to VRAM
202
203    if (tid < K_VECS_PER_BLOCK) {
204        const int i_kv = start_kv + tid;
205        if (i_kv < n_kv) {
206            const half * m_base = (const half *) ((const char *) M + i_batch*nbm1 + (i_stream%nem3)*nbm3);
207            float * dst_base = (float *) ((char *) dst + i_batch*nb1 + i_stream*nb3);
208            dst_base[i_kv] = score_k + __half2float(m_base[i_kv]);
209        }
210    }
211}
212
213#else // defined(TURING_MMA_AVAILABLE)
214
215template <int WARPS_PER_BLOCK, int K_VECS_PER_BLOCK, int64_t N_EMBD, int64_t N_HEAD, ggml_type TYPE_K>
216static __global__ void lightning_indexer_kernel_wmma(
217        const float * Q, const char * K, const float * W, const half * M, float * dst,
218        int64_t n_stream, int64_t n_batch, int64_t n_kv,
219        size_t nb1, size_t nb2, size_t nb3,
220        size_t nbq1, size_t nbq2, size_t nbq3,
221        size_t nbk1, size_t nbk2, size_t nbk3,
222        size_t nbw1, size_t nbw2, size_t nbw3,
223        size_t nbm1, size_t nbm2, size_t nbm3,
224        int64_t nem3
225    ) {
226    GGML_UNUSED_VARS(Q, K, W, M, dst,
227        n_stream, n_batch, n_kv,
228        nb1, nb2, nb3,
229        nbq1, nbq2, nbq3,
230        nbk1, nbk2, nbk3,
231        nbw1, nbw2, nbw3,
232        nem3);
233    NO_DEVICE_CODE;
234}
235
236#endif // defined(TURING_MMA_AVAILABLE)
237#endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
238
239// TODO there is one ugly assumption used in this kernel - that WARP_SIZE is equal to 32
240// thanks to that one warp operating on float4 processes whole indexer K/Q vectors
241// 32 * 4 = 128 (N_EMBD)
242
243template <int WARPS_PER_BLOCK, int K_VECS_PER_BLOCK, int64_t N_EMBD, int64_t N_HEAD, ggml_type TYPE_K>
244static __global__ void lightning_indexer_kernel_vec(
245        const float * Q, const char * K, const float * W, const half * M, float * dst,
246        int64_t n_stream, int64_t n_batch, int64_t n_kv,
247        size_t nb1, size_t nb2, size_t nb3,
248        size_t nbq1, size_t nbq2, size_t nbq3,
249        size_t nbk1, size_t nbk2, size_t nbk3,
250        size_t nbw1, size_t nbw2, size_t nbw3,
251        size_t nbm1, size_t nbm2, size_t nbm3,
252        int64_t nem3
253    ) {
254
255    constexpr int K_VECS_PER_WARP = K_VECS_PER_BLOCK / WARPS_PER_BLOCK;
256    constexpr int THREADS_PER_BLOCK = WARPS_PER_BLOCK * WARP_SIZE;
257
258    const int i_batch  = blockIdx.y;
259    const int i_stream = blockIdx.z;
260    const int i_warp   = threadIdx.y;
261    const int i_lane   = threadIdx.x;
262    const int tid      = i_warp * WARP_SIZE + i_lane;
263
264    // each warp processes K_VECS_PER_WARP K vectors
265    const int start_kv_block = blockIdx.x * K_VECS_PER_BLOCK;
266    const int start_kv = start_kv_block + i_warp * K_VECS_PER_WARP;
267
268    const char  * q_base = (const char  *)                 Q + i_batch*nbq2 + i_stream*nbq3;
269    const float * w_base = (const float *) ((const char *) W + i_batch*nbw1 + i_stream*nbw3);
270
271    // phase 1 - load (and dequantize if needed) K to registers
272
273    float4 k_reg_f[K_VECS_PER_WARP];
274
275    if constexpr (TYPE_K == GGML_TYPE_F32) {
276        // direct copy of float4
277#pragma unroll
278        for (int k = 0; k < K_VECS_PER_WARP; ++k) {
279            int i_kv = start_kv + k;
280            if (i_kv < n_kv) {
281                const float4 * k_base = (const float4 *) ((const char *) K + i_kv*nbk2 + i_stream*nbk3);
282                k_reg_f[k] = k_base[i_lane];
283            } else {
284                k_reg_f[k] = make_float4(0, 0, 0, 0);
285            }
286        }
287    } else {
288        // dequantize remaining types to float
289        constexpr dequantize_V_t dequantize_k = get_dequantize_V<TYPE_K, float, 4>();
290#pragma unroll
291        for (int k = 0; k < K_VECS_PER_WARP; ++k) {
292            int i_kv = start_kv + k;
293            if (i_kv < n_kv) {
294                const void * k_base = (const void *) ((const char *) K + i_kv*nbk2 + i_stream*nbk3);
295                dequantize_k(k_base, &k_reg_f[k], i_lane * 4);
296            } else {
297                k_reg_f[k] = make_float4(0, 0, 0, 0);
298            }
299        }
300    }
301
302    float score_k[K_VECS_PER_WARP] = { 0.0f };
303
304    // load weights and Q only for N_HEAD_INNER heads at once to reduce shared memory usage
305    constexpr int N_HEAD_INNER = N_HEAD / 4;
306
307    for (int i_head_0 = 0; i_head_0 < N_HEAD; i_head_0 += N_HEAD_INNER) {
308        // phase 2 - load weights and Q to shared memory
309
310        __shared__ float  w_shared[N_HEAD_INNER];
311        __shared__ float4 q_shared_f[N_HEAD_INNER][N_EMBD / 4];
312
313        if (tid < N_HEAD_INNER) {
314            w_shared[tid] = w_base[i_head_0 + tid];
315        }
316
317        constexpr int n_q = N_HEAD_INNER * (N_EMBD / 4);
318#pragma unroll
319        for (int i_q = tid; i_q < n_q; i_q += THREADS_PER_BLOCK) {
320            const int i_head_inner = i_q / (N_EMBD / 4);
321            const int i_head = i_head_0 + i_head_inner;
322            const int i_embd = i_q % (N_EMBD / 4);
323            q_shared_f[i_head_inner][i_embd] = *(const float4 *) (q_base + i_head*nbq1 + i_embd*sizeof(float4));
324        }
325
326        __syncthreads();
327
328        // phase 3 - calculate lightning indexer scores
329
330        for (int i_head_inner = 0; i_head_inner < N_HEAD_INNER; ++i_head_inner) {
331            const float w_val = w_shared[i_head_inner];
332            float qk[K_VECS_PER_WARP] = { 0.0f };
333
334            // dot product of floats
335            const float4 q_vec = q_shared_f[i_head_inner][i_lane];
336
337#pragma unroll
338            for (int k = 0; k < K_VECS_PER_WARP; ++k) {
339                ggml_cuda_mad(qk[k], q_vec.x, k_reg_f[k].x);
340                ggml_cuda_mad(qk[k], q_vec.y, k_reg_f[k].y);
341                ggml_cuda_mad(qk[k], q_vec.z, k_reg_f[k].z);
342                ggml_cuda_mad(qk[k], q_vec.w, k_reg_f[k].w);
343            }
344
345#pragma unroll
346            for (int k = 0; k < K_VECS_PER_WARP; ++k) {
347                float sum = warp_reduce_sum(qk[k]);
348
349                // ReLU, weight
350                if (i_lane == 0) {
351                    sum = (sum > 0.0f) ? sum : 0.0f;
352                    score_k[k] += sum * w_val;
353                }
354            }
355        }
356
357        __syncthreads();
358    }
359
360    // phase 4 - store outputs to shared memory
361
362    __shared__ float dst_shared[K_VECS_PER_BLOCK];
363
364    if (i_lane == 0) {
365#pragma unroll
366        for (int k = 0; k < K_VECS_PER_WARP; ++k) {
367            dst_shared[i_warp * K_VECS_PER_WARP + k] = score_k[k];
368        }
369    }
370
371    __syncthreads();
372
373    // phase 5 - write from shared memory to VRAM in coalesced manner
374
375    if (tid < K_VECS_PER_BLOCK) {
376        int i_kv = start_kv_block + tid;
377        if (i_kv < n_kv) {
378            const half * m_base = (const half *) ((const char *) M + i_batch*nbm1 + (i_stream%nem3)*nbm3);
379            float * dst_base = (float *) ((char *) dst + i_batch*nb1 + i_stream*nb3);
380            dst_base[i_kv] = dst_shared[tid] + __half2float(m_base[i_kv]);
381        }
382    }
383}
384
385#define LIGHTNING_INDEXER_CASE(lightning_indexer_kernel, n_embd, n_head, K, type_K)         \
386    if (K->type == (type_K)) {                                                              \
387        lightning_indexer_kernel<WARPS_PER_BLOCK, K_VECS_PER_BLOCK, n_embd, n_head, type_K> \
388            <<<grid, block, 0, ctx.stream()>>>(                                             \
389            q_d, k_d, w_d, m_d, dst_d,                                                      \
390            n_stream, n_batch, n_kv,                                                        \
391            nb1, nb2, nb3,                                                                  \
392            nbq1, nbq2, nbq3,                                                               \
393            nbk1, nbk2, nbk3,                                                               \
394            nbw1, nbw2, nbw3,                                                               \
395            nbm1, nbm2, nbm3,                                                               \
396            nem3                                                                            \
397        );                                                                                  \
398    } else
399
400void ggml_cuda_lightning_indexer(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
401    const ggml_tensor * q = dst->src[0];
402    const ggml_tensor * k = dst->src[1];
403    const ggml_tensor * w = dst->src[2]; // weights
404    const ggml_tensor * m = dst->src[3]; // mask
405
406    GGML_ASSERT(dst->type == GGML_TYPE_F32);
407    GGML_ASSERT(  q->type == GGML_TYPE_F32);
408    GGML_ASSERT(  w->type == GGML_TYPE_F32);
409    GGML_ASSERT(  m->type == GGML_TYPE_F16);
410
411    GGML_TENSOR_LOCALS(int64_t, neq,  q, ne)
412    GGML_TENSOR_LOCALS(size_t,  nbq,  q, nb)
413    GGML_TENSOR_LOCALS(int64_t, nek,  k, ne)
414    GGML_TENSOR_LOCALS(size_t,  nbk,  k, nb)
415    GGML_TENSOR_LOCALS(int64_t, new,  w, ne)
416    GGML_TENSOR_LOCALS(size_t,  nbw,  w, nb)
417    GGML_TENSOR_LOCALS(int64_t, nem,  m, ne)
418    GGML_TENSOR_LOCALS(size_t,  nbm,  m, nb)
419    GGML_TENSOR_LOCALS(int64_t, ne, dst, ne)
420    GGML_TENSOR_LOCALS(size_t,  nb, dst, nb)
421
422    // input tensor rows must be contiguous
423    GGML_ASSERT(nbq0 == ggml_type_size(q->type));
424    GGML_ASSERT(nbk0 == ggml_type_size(k->type));
425    GGML_ASSERT(nbw0 == ggml_type_size(w->type));
426    GGML_ASSERT(nbm0 == ggml_type_size(m->type));
427
428    // dst cannot be transposed or permuted
429    GGML_ASSERT(nb0 == sizeof(float));
430    GGML_ASSERT(nb0 <= nb1);
431    GGML_ASSERT(nb1 <= nb2);
432    GGML_ASSERT(nb2 <= nb3);
433
434    const int n_embd   = q->ne[0];
435    const int n_head   = q->ne[1];
436    const int n_batch  = q->ne[2];
437    const int n_stream = q->ne[3];
438    const int n_kv     = k->ne[2];
439
440    const float *   q_d = (const float *)   q->data;
441    const char  *   k_d = (const char  *)   k->data;
442    const float *   w_d = (const float *)   w->data;
443    const half  *   m_d = (const half  *)   m->data;
444    float       * dst_d = (      float *) dst->data;
445
446    const int device = ggml_cuda_get_device();
447    const int cc     = ggml_cuda_info().devices[device].cc;
448
449    if (n_embd == 128 && n_head == 64) {
450#if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
451        if (GGML_CUDA_CC_IS_NVIDIA(cc) && turing_mma_available(cc) && k->type != GGML_TYPE_F32 && k->type != GGML_TYPE_BF16) {
452            // use wmma kernel
453            constexpr int K_VECS_PER_BLOCK = 32;
454            constexpr int WARPS_PER_BLOCK = 8;
455
456            dim3 block(32, WARPS_PER_BLOCK);
457            int num_kv_blocks = (n_kv + (K_VECS_PER_BLOCK) - 1) / (K_VECS_PER_BLOCK);
458            dim3 grid(num_kv_blocks, n_batch, n_stream);
459
460            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_wmma, 128, 64, k, GGML_TYPE_F16)
461            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_wmma, 128, 64, k, GGML_TYPE_Q4_0)
462            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_wmma, 128, 64, k, GGML_TYPE_Q4_1)
463            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_wmma, 128, 64, k, GGML_TYPE_Q5_0)
464            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_wmma, 128, 64, k, GGML_TYPE_Q5_1)
465            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_wmma, 128, 64, k, GGML_TYPE_Q8_0)
466            GGML_ABORT("fatal error");
467        } else {
468#else // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
469        {
470#endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
471            // use vector kernel
472            constexpr int K_VECS_PER_WARP = 8;
473            constexpr int WARPS_PER_BLOCK = 8;
474            constexpr int K_VECS_PER_BLOCK = K_VECS_PER_WARP * WARPS_PER_BLOCK;
475
476            dim3 block(32, WARPS_PER_BLOCK);
477            int num_kv_blocks = (n_kv + (K_VECS_PER_BLOCK) - 1) / (K_VECS_PER_BLOCK);
478            dim3 grid(num_kv_blocks, n_batch, n_stream);
479
480            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_vec, 128, 64, k, GGML_TYPE_F16)
481            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_vec, 128, 64, k, GGML_TYPE_Q4_0)
482            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_vec, 128, 64, k, GGML_TYPE_Q4_1)
483            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_vec, 128, 64, k, GGML_TYPE_Q5_0)
484            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_vec, 128, 64, k, GGML_TYPE_Q5_1)
485            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_vec, 128, 64, k, GGML_TYPE_Q8_0)
486            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_vec, 128, 64, k, GGML_TYPE_BF16)
487            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_vec, 128, 64, k, GGML_TYPE_F32)
488            GGML_ABORT("fatal error");
489        }
490    } else if (n_embd == 128 && n_head == 32) {
491#if !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
492        if (GGML_CUDA_CC_IS_NVIDIA(cc) && turing_mma_available(cc) && k->type != GGML_TYPE_F32 && k->type != GGML_TYPE_BF16) {
493            // use wmma kernel
494            constexpr int K_VECS_PER_BLOCK = 32;
495            constexpr int WARPS_PER_BLOCK = 8;
496
497            dim3 block(32, WARPS_PER_BLOCK);
498            int num_kv_blocks = (n_kv + (K_VECS_PER_BLOCK) - 1) / (K_VECS_PER_BLOCK);
499            dim3 grid(num_kv_blocks, n_batch, n_stream);
500
501            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_wmma, 128, 32, k, GGML_TYPE_F16)
502            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_wmma, 128, 32, k, GGML_TYPE_Q4_0)
503            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_wmma, 128, 32, k, GGML_TYPE_Q4_1)
504            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_wmma, 128, 32, k, GGML_TYPE_Q5_0)
505            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_wmma, 128, 32, k, GGML_TYPE_Q5_1)
506            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_wmma, 128, 32, k, GGML_TYPE_Q8_0)
507            GGML_ABORT("fatal error");
508        } else {
509#else // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
510        {
511#endif // !defined(GGML_USE_HIP) && !defined(GGML_USE_MUSA)
512            // use vector kernel
513            constexpr int K_VECS_PER_WARP = 8;
514            constexpr int WARPS_PER_BLOCK = 8;
515            constexpr int K_VECS_PER_BLOCK = K_VECS_PER_WARP * WARPS_PER_BLOCK;
516
517            dim3 block(32, WARPS_PER_BLOCK);
518            int num_kv_blocks = (n_kv + (K_VECS_PER_BLOCK) - 1) / (K_VECS_PER_BLOCK);
519            dim3 grid(num_kv_blocks, n_batch, n_stream);
520
521            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_vec, 128, 32, k, GGML_TYPE_F16)
522            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_vec, 128, 32, k, GGML_TYPE_Q4_0)
523            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_vec, 128, 32, k, GGML_TYPE_Q4_1)
524            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_vec, 128, 32, k, GGML_TYPE_Q5_0)
525            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_vec, 128, 32, k, GGML_TYPE_Q5_1)
526            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_vec, 128, 32, k, GGML_TYPE_Q8_0)
527            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_vec, 128, 32, k, GGML_TYPE_BF16)
528            LIGHTNING_INDEXER_CASE(lightning_indexer_kernel_vec, 128, 32, k, GGML_TYPE_F32)
529            GGML_ABORT("fatal error");
530        }
531    } else {
532        GGML_ABORT("fatal error");
533    }
534}
535
536bool ggml_cuda_lightning_indexer_supported(int device, const ggml_tensor * dst) {
537    GGML_UNUSED(device);
538
539    const ggml_tensor * q = dst->src[0];
540    const ggml_tensor * k = dst->src[1];
541    const ggml_tensor * w = dst->src[2]; // weights
542    const ggml_tensor * m = dst->src[3]; // mask
543
544    GGML_TENSOR_LOCALS(int64_t, neq,  q, ne)
545    GGML_TENSOR_LOCALS(size_t,  nbq,  q, nb)
546    GGML_TENSOR_LOCALS(int64_t, nek,  k, ne)
547    GGML_TENSOR_LOCALS(size_t,  nbk,  k, nb)
548    GGML_TENSOR_LOCALS(int64_t, new,  w, ne)
549    GGML_TENSOR_LOCALS(size_t,  nbw,  w, nb)
550    GGML_TENSOR_LOCALS(int64_t, nem,  m, ne)
551    GGML_TENSOR_LOCALS(size_t,  nbm,  m, nb)
552    GGML_TENSOR_LOCALS(int64_t, ne, dst, ne)
553    GGML_TENSOR_LOCALS(size_t,  nb, dst, nb)
554
555    if (neq0 != 128) {
556        return false;
557    }
558
559    if (neq1 != 64 && neq1 != 32) {
560        return false;
561    }
562
563    // alignment checks
564    for (const ggml_tensor * t : {q, k}) {
565        if (ggml_is_quantized(t->type)) {
566            continue;
567        }
568        for (size_t i = 1; i < GGML_MAX_DIMS; ++i) {
569            if (t->nb[i] % 16 != 0) {
570                return false;
571            }
572        }
573    }
574
575    switch(k->type) {
576        case GGML_TYPE_F32:
577        case GGML_TYPE_BF16:
578        case GGML_TYPE_F16:
579        case GGML_TYPE_Q8_0:
580        case GGML_TYPE_Q5_1:
581        case GGML_TYPE_Q5_0:
582        case GGML_TYPE_Q4_1:
583        case GGML_TYPE_Q4_0:
584            return true;
585        default:
586            return false;
587    }
588}