char-fork/llama.cpp

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

Alexander Heislerggml-cuda: provide static workspace for cuBLAS handles (#26574)d9b6be07d

char/aliceai-t5-moe
11.2 KiB273 linesraw
1#include "common.cuh"
2#include "ggml.h"
3#include "solve_tri.cuh"
4
5#define MAX_N_FAST 64
6#define MAX_K_FAST 32
7
8static __global__ void get_batch_pointers(const float *  A,
9                                          float *        X,
10                                          const float ** A_ptrs,
11                                          float **       X_ptrs,
12                                          int64_t        ne02,
13                                          int64_t        total_batches,
14                                          size_t         s02,
15                                          size_t         s03,
16                                          size_t         s2,
17                                          size_t         s3) {
18    const int idx = blockIdx.x * blockDim.x + threadIdx.x;
19    if (idx >= total_batches) {
20        return;
21    }
22
23    const int64_t i3 = idx / ne02;
24    const int64_t i2 = idx % ne02;
25
26    A_ptrs[idx] = A + i3 * s03 + i2 * s02;
27    X_ptrs[idx] = X + i3 * s3 + i2 * s2;
28}
29
30static void solve_tri_f32_cublas(ggml_backend_cuda_context & ctx,
31                                 const float *               A,
32                                 const float *               B,
33                                 float *                     X,
34                                 int                         n,
35                                 int                         k,
36                                 int64_t                     ne02,
37                                 int64_t                     ne03,
38                                 size_t                      s02,
39                                 size_t                      s03,
40                                 size_t                      s12,
41                                 size_t                      s13,
42                                 size_t                      s2,
43                                 size_t                      s3,
44                                 cudaStream_t                stream) {
45    const float   alpha         = 1.0f;
46    const int64_t total_batches = ne02 * ne03;
47    if (total_batches == 0) {
48        return;
49    }
50
51    // Bulk copy B -> X (contiguous tensors)
52    if (X != B) {
53        const int64_t total_elements_BX = n * k * total_batches;
54        CUDA_CHECK(cudaMemcpyAsync(X, B, total_elements_BX * sizeof(float), cudaMemcpyDeviceToDevice, stream));
55    }
56
57    const int id = ggml_cuda_get_device();
58
59    ggml_cuda_pool_alloc<const float *> A_ptrs_alloc(ctx.pool(id), total_batches);
60    ggml_cuda_pool_alloc<float *>       X_ptrs_alloc(ctx.pool(id), total_batches);
61
62    const float ** A_ptrs_dev = A_ptrs_alloc.get();
63    float **       X_ptrs_dev = X_ptrs_alloc.get();
64
65    get_batch_pointers<<<(total_batches + 255) / 256, 256, 0, stream>>>(A, X, A_ptrs_dev, X_ptrs_dev, ne02,
66                                                                        total_batches, s02, s03, s2, s3);
67
68    // Yes, this is necessary, without this we get RMSE errors
69    CUBLAS_CHECK(cublasSetMathMode(ctx.cublas_handle(), CUBLAS_DEFAULT_MATH));
70    CUBLAS_CHECK(cublasStrsmBatched(ctx.cublas_handle(), CUBLAS_SIDE_RIGHT, CUBLAS_FILL_MODE_UPPER, CUBLAS_OP_N,
71                                    CUBLAS_DIAG_NON_UNIT, k, n, &alpha, A_ptrs_dev, n, X_ptrs_dev, k, total_batches));
72
73    // revert to standard mode from common.cuh
74    CUBLAS_CHECK(cublasSetMathMode(ctx.cublas_handle(), CUBLAS_TF32_TENSOR_OP_MATH));
75
76    GGML_UNUSED_VARS(s12, s13);
77}
78
79// ======================
80// Fast Kernel (n <= 64, k <= 32) - Warp-based parallel reduction
81// ======================
82// When ncols_template == 0 the bounds for the loops in this function are not
83// known and can't be unrolled. As we want to keep pragma unroll for all other
84// cases we suppress the clang transformation warning here.
85#ifdef __clang__
86#    pragma clang diagnostic push
87#    pragma clang diagnostic ignored "-Wpass-failed"
88#endif  // __clang__
89template <int n_template, int k_template>
90static __global__ void solve_tri_f32_fast(const float * __restrict__ A,
91                                          const float * __restrict__ B,
92                                          float * __restrict__ X,
93                                          const uint3  ne02,
94                                          const size_t nb02,
95                                          const size_t nb03,
96                                          const size_t nb12,
97                                          const size_t nb13,
98                                          const size_t nb2,
99                                          const size_t nb3,
100                                          const int    n_arg,
101                                          const int    k_arg) {
102    const int n = n_template == 0 ? n_arg : n_template;
103    const int k = k_template == 0 ? k_arg : k_template;
104
105    const int batch_idx = blockIdx.x;
106    const int lane      = threadIdx.x;
107    const int col_idx   = threadIdx.y;
108
109    if (col_idx >= k) {
110        return;
111    }
112
113    const uint2   i02_i03 = fast_div_modulo(batch_idx, ne02);
114    const int64_t i02     = i02_i03.y;
115    const int64_t i03     = i02_i03.x;
116
117    const float * const A_batch = (const float *) (A + i02 * nb02 + i03 * nb03);
118    const float * const B_batch = (const float *) (B + i02 * nb12 + i03 * nb13);
119    float *             X_batch = (float *) (X + i02 * nb2 + i03 * nb3);
120
121    __shared__ float sA[MAX_N_FAST * MAX_N_FAST];
122
123    const int offset = threadIdx.x + threadIdx.y * blockDim.x;
124
125#pragma unroll
126    for (int i = 0; i < n * n; i += k * WARP_SIZE) {
127        const int i0 = i + offset;
128        if (i0 < n * n) {
129            sA[i0] = A_batch[i0];
130        }
131    }
132
133    __syncthreads();
134
135    float x_low  = (lane < n) ? B_batch[lane * k + col_idx] : 0.0f;
136    float x_high = (WARP_SIZE + lane < n) ? B_batch[(WARP_SIZE + lane) * k + col_idx] : 0.0f;
137
138    const int half      = WARP_SIZE;
139    const int nrows_low = (n < half) ? n : half;
140
141#pragma unroll
142    for (int row = 0; row < nrows_low; ++row) {
143        float sum = 0.0f;
144        if (lane < row) {
145            sum += sA[row * n + lane] * x_low;
146        }
147        sum = warp_reduce_sum(sum);
148
149        if (lane == row) {
150            x_low = (x_low - sum) / sA[row * n + row];
151        }
152    }
153
154#pragma unroll
155    for (int row = half; row < n; ++row) {
156        float     sum = sA[row * n + lane] * x_low;
157        const int j   = half + lane;
158        if (j < row) {
159            sum += sA[row * n + j] * x_high;
160        }
161        sum = warp_reduce_sum(sum);
162
163        if (lane == row - half) {
164            x_high = (x_high - sum) / sA[row * n + row];
165        }
166    }
167
168#pragma unroll
169    for (int rr = 0; rr < 2; ++rr) {
170        const int row = rr * WARP_SIZE + lane;
171        if (row < n) {
172            const float val            = (row < half) ? x_low : x_high;
173            X_batch[row * k + col_idx] = val;
174        }
175    }
176}
177#ifdef __clang__
178#    pragma clang diagnostic pop
179#endif  // __clang__
180
181static void solve_tri_f32_cuda(const float * A,
182                               const float * B,
183                               float *       X,
184                               int           n,
185                               int           k,
186                               int64_t       ne02,
187                               int64_t       ne03,
188                               size_t        nb02,
189                               size_t        nb03,
190                               size_t        nb12,
191                               size_t        nb13,
192                               size_t        nb2,
193                               size_t        nb3,
194                               cudaStream_t  stream) {
195    const uint3 ne02_fd = init_fastdiv_values((uint32_t) ne02);
196    dim3        threads(WARP_SIZE, k);
197    dim3        grid(ne02 * ne03);
198    if (n == 64) {
199        switch (k) {
200            case 32:
201                solve_tri_f32_fast<64, 32>
202                    <<<grid, threads, 0, stream>>>(A, B, X, ne02_fd, nb02, nb03, nb12, nb13, nb2, nb3, 0, 0);
203                break;
204            case 16:
205                solve_tri_f32_fast<64, 16>
206                    <<<grid, threads, 0, stream>>>(A, B, X, ne02_fd, nb02, nb03, nb12, nb13, nb2, nb3, 0, 0);
207                break;
208            case 14:
209                solve_tri_f32_fast<64, 14>
210                    <<<grid, threads, 0, stream>>>(A, B, X, ne02_fd, nb02, nb03, nb12, nb13, nb2, nb3, 0, 0);
211                break;
212            case 12:
213                solve_tri_f32_fast<64, 12>
214                    <<<grid, threads, 0, stream>>>(A, B, X, ne02_fd, nb02, nb03, nb12, nb13, nb2, nb3, 0, 0);
215                break;
216            case 10:
217                solve_tri_f32_fast<64, 10>
218                    <<<grid, threads, 0, stream>>>(A, B, X, ne02_fd, nb02, nb03, nb12, nb13, nb2, nb3, 0, 0);
219                break;
220            case 8:
221                solve_tri_f32_fast<64, 8>
222                    <<<grid, threads, 0, stream>>>(A, B, X, ne02_fd, nb02, nb03, nb12, nb13, nb2, nb3, 0, 0);
223                break;
224            case 6:
225                solve_tri_f32_fast<64, 6>
226                    <<<grid, threads, 0, stream>>>(A, B, X, ne02_fd, nb02, nb03, nb12, nb13, nb2, nb3, 0, 0);
227                break;
228            case 4:
229                solve_tri_f32_fast<64, 4>
230                    <<<grid, threads, 0, stream>>>(A, B, X, ne02_fd, nb02, nb03, nb12, nb13, nb2, nb3, 0, 0);
231                break;
232            case 2:
233                solve_tri_f32_fast<64, 2>
234                    <<<grid, threads, 0, stream>>>(A, B, X, ne02_fd, nb02, nb03, nb12, nb13, nb2, nb3, 0, 0);
235                break;
236            case 1:
237                solve_tri_f32_fast<64, 1>
238                    <<<grid, threads, 0, stream>>>(A, B, X, ne02_fd, nb02, nb03, nb12, nb13, nb2, nb3, 0, 0);
239                break;
240            default:
241                solve_tri_f32_fast<0, 0>
242                    <<<grid, threads, 0, stream>>>(A, B, X, ne02_fd, nb02, nb03, nb12, nb13, nb2, nb3, n, k);
243        }
244    } else {  // run general case
245        solve_tri_f32_fast<0, 0>
246            <<<grid, threads, 0, stream>>>(A, B, X, ne02_fd, nb02, nb03, nb12, nb13, nb2, nb3, n, k);
247    }
248}
249
250void ggml_cuda_op_solve_tri(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
251    const ggml_tensor * src0 = dst->src[0];  // A (n×n, lower triangular)
252    const ggml_tensor * src1 = dst->src[1];  // B (n×k)
253
254    ggml_is_contiguous(src0);
255    ggml_is_contiguous(src1);
256
257    const int64_t n    = src0->ne[0];
258    const int64_t k    = src1->ne[0];
259    const int64_t ne02 = src0->ne[2];
260    const int64_t ne03 = src0->ne[3];
261
262    if (n <= MAX_N_FAST && k <= MAX_K_FAST) {
263        solve_tri_f32_cuda((const float *) src0->data, (const float *) src1->data, (float *) dst->data, n, k,
264                           src0->ne[2], src0->ne[3], src0->nb[2] / sizeof(float), src0->nb[3] / sizeof(float),
265                           src1->nb[2] / sizeof(float), src1->nb[3] / sizeof(float), dst->nb[2] / sizeof(float),
266                           dst->nb[3] / sizeof(float), ctx.stream());
267    } else {
268        solve_tri_f32_cublas(ctx, (const float *) src0->data, (const float *) src1->data, (float *) dst->data, n, k,
269                             ne02, ne03, src0->nb[2] / sizeof(float), src0->nb[3] / sizeof(float),
270                             src1->nb[2] / sizeof(float), src1->nb[3] / sizeof(float), dst->nb[2] / sizeof(float),
271                             dst->nb[3] / sizeof(float), ctx.stream());
272    }
273}