model-as-a-kernel v1 source
Browse files- mak_cuda/mak_kernels.h +3 -3
- mak_cuda/megakernel.cu +322 -265
- torch-ext/model_as_a_kernel/__init__.py +30 -11
- torch-ext/torch_binding.cpp +16 -11
- torch-ext/torch_binding.h +1 -1
mak_cuda/mak_kernels.h
CHANGED
|
@@ -8,9 +8,9 @@
|
|
| 8 |
int mak_grid_blocks_impl(int smem_bytes);
|
| 9 |
|
| 10 |
cudaError_t mak_launch_mega(const long long* prog, int n_phases, int pos0,
|
| 11 |
-
int
|
| 12 |
-
int
|
| 13 |
-
int smem_bytes, cudaStream_t stream);
|
| 14 |
|
| 15 |
cudaError_t mak_launch_phase(const long long* prog, int phase, int pos,
|
| 16 |
int step_slot, int grid, int smem_bytes,
|
|
|
|
| 8 |
int mak_grid_blocks_impl(int smem_bytes);
|
| 9 |
|
| 10 |
cudaError_t mak_launch_mega(const long long* prog, int n_phases, int pos0,
|
| 11 |
+
int total, int slot0, int prompt_len,
|
| 12 |
+
int chunk_m, int* bar_cnt, int* bar_sense,
|
| 13 |
+
int grid, int smem_bytes, cudaStream_t stream);
|
| 14 |
|
| 15 |
cudaError_t mak_launch_phase(const long long* prog, int phase, int pos,
|
| 16 |
int step_slot, int grid, int smem_bytes,
|
mak_cuda/megakernel.cu
CHANGED
|
@@ -37,6 +37,7 @@ enum PhaseOp : int {
|
|
| 37 |
OP_ATTN = 3,
|
| 38 |
OP_ARGMAX_PART = 4,
|
| 39 |
OP_ARGMAX_FIN = 5,
|
|
|
|
| 40 |
};
|
| 41 |
|
| 42 |
enum InputTransform : int {
|
|
@@ -130,7 +131,7 @@ __device__ unsigned long long block_max_u64(unsigned long long v,
|
|
| 130 |
// and any block with nothing to do simply falls through to the barrier.
|
| 131 |
// ---------------------------------------------------------------------------
|
| 132 |
|
| 133 |
-
__device__ void ph_embed(const long long* P, int pos, int prompt_len) {
|
| 134 |
const bf16* tab = reinterpret_cast<const bf16*>(P[2]);
|
| 135 |
bf16* out = reinterpret_cast<bf16*>(P[3]);
|
| 136 |
const int* prompt = reinterpret_cast<const int*>(P[5]);
|
|
@@ -138,13 +139,16 @@ __device__ void ph_embed(const long long* P, int pos, int prompt_len) {
|
|
| 138 |
const long long K = P[8];
|
| 139 |
// Positions inside the prompt read from the staged prompt buffer; beyond
|
| 140 |
// it, from the feedback token written by the previous step's argmax.
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
|
|
|
|
|
|
|
|
|
| 148 |
}
|
| 149 |
|
| 150 |
__device__ __forceinline__ unsigned long long amax_key(float v, unsigned idx) {
|
|
@@ -157,10 +161,10 @@ __device__ __forceinline__ unsigned long long amax_key(float v, unsigned idx) {
|
|
| 157 |
// Finalize one element of split-S attention: combine per-chunk partials
|
| 158 |
// (max, sum, weighted V) into the bf16 attention output, matching eager's
|
| 159 |
// bf16 rounding of the attention output before the O projection.
|
| 160 |
-
__device__ __forceinline__ float attn_finalize(const float*
|
| 161 |
int d, int D, int maxch,
|
| 162 |
int nch) {
|
| 163 |
-
const float* base =
|
| 164 |
float M = -INFINITY;
|
| 165 |
for (int c = 0; c < nch; ++c)
|
| 166 |
M = fmaxf(M, base[(long long)c * (D + 2) + D]);
|
|
@@ -197,78 +201,72 @@ __device__ __forceinline__ float mk_load_x(const bf16* x, const bf16* gamma,
|
|
| 197 |
// Reduced (or plain) bf16 input element k for a consumer phase: sum the
|
| 198 |
// producer's fp32 k-slice partials in fixed order, add the residual, round
|
| 199 |
// to bf16, optionally write the materialized vector back.
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
for (int sl = 1; sl < NSLICE; ++sl) s += pp[(long long)sl * K + k];
|
| 207 |
-
const bf16* resid = reinterpret_cast<const bf16*>(P[5]);
|
| 208 |
-
if (resid != nullptr) s = bf2f(resid[k]) + s;
|
| 209 |
-
const bf16 v = f2bf(s);
|
| 210 |
-
if (itflags & ITF_WRITEBACK) reinterpret_cast<bf16*>(P[6])[k] = v;
|
| 211 |
-
return v;
|
| 212 |
-
}
|
| 213 |
-
return reinterpret_cast<const bf16*>(P[1])[k];
|
| 214 |
-
}
|
| 215 |
-
|
| 216 |
-
__device__ void ph_gemv(const long long* P, int pos) {
|
| 217 |
const bf16* W = reinterpret_cast<const bf16*>(P[2]);
|
| 218 |
const bf16* gamma = reinterpret_cast<const bf16*>(P[4]);
|
| 219 |
const bf16* resid = reinterpret_cast<const bf16*>(P[5]);
|
| 220 |
const long long N = P[7], K = P[8];
|
| 221 |
-
const int
|
| 222 |
-
const int itrans = itflags & ITF_BASE_MASK;
|
| 223 |
const int epi = (int)P[10];
|
|
|
|
| 224 |
const float eps = bits2f(P[14]);
|
| 225 |
const float* part = reinterpret_cast<const float*>(P[1]);
|
|
|
|
| 226 |
const int D = (int)P[13];
|
| 227 |
const int maxch = (int)P[15];
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
//
|
| 235 |
-
// bf16-rounded quantity by semantics, so bf16 staging is exact. This turns
|
| 236 |
-
// per-row-visit transform work (swiglu exp, attention finalize) into
|
| 237 |
-
// once-per-block work and makes the dot loop pure shared-memory reads.
|
| 238 |
-
// RMSNORM stages in two passes (raw materialized value first, then the
|
| 239 |
-
// norm applied in place) so reduce+resid+writeback consumption happens
|
| 240 |
-
// exactly once per element.
|
| 241 |
extern __shared__ bf16 xs[];
|
| 242 |
__shared__ float s_red[32];
|
| 243 |
__shared__ float s_scale;
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
|
|
|
|
|
|
|
|
|
| 263 |
const float sig = 1.f / (1.f + expf(-g));
|
| 264 |
const float sg = bf2f(f2bf(g * sig));
|
| 265 |
-
|
| 266 |
-
} else if (itrans == IT_ATTNFIN) {
|
| 267 |
-
v = attn_finalize(part, (int)(k / D), (int)(k % D), D, maxch, nch);
|
| 268 |
-
} else {
|
| 269 |
-
v = bf2f(consume_x(P, k, KR, itflags));
|
| 270 |
}
|
| 271 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 272 |
}
|
| 273 |
}
|
| 274 |
__syncthreads();
|
|
@@ -277,57 +275,61 @@ __device__ void ph_gemv(const long long* P, int pos) {
|
|
| 277 |
const long long warp =
|
| 278 |
((long long)blockIdx.x * blockDim.x + threadIdx.x) >> 5;
|
| 279 |
const long long nwarps = ((long long)gridDim.x * blockDim.x) >> 5;
|
| 280 |
-
__shared__ unsigned long long s64[32];
|
| 281 |
unsigned long long best = amax_key(-INFINITY, 0xFFFFFFFFu);
|
| 282 |
-
|
| 283 |
-
// independent warps: NSLICE times the parallelism and chains a quarter as
|
| 284 |
-
// long, with the fixed-order reduction done by the consumer's staging.
|
| 285 |
-
const bool partial = (epi == EP_PARTIAL);
|
| 286 |
-
const long long V = partial ? N * NSLICE : N;
|
| 287 |
-
const long long kslice = K / NSLICE;
|
| 288 |
-
for (long long v = warp; v < V; v += nwarps) {
|
| 289 |
-
const long long row = partial ? v / NSLICE : v;
|
| 290 |
-
const int slice = partial ? (int)(v % NSLICE) : 0;
|
| 291 |
-
const long long klo = partial ? (long long)slice * kslice : 0;
|
| 292 |
-
const long long khi = partial ? klo + kslice : K;
|
| 293 |
const bf16* wr = W + row * K;
|
| 294 |
-
float acc
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
|
|
|
|
|
|
| 299 |
int4 wv4 = *reinterpret_cast<const int4*>(wr + k);
|
| 300 |
-
for (; k + 7 <
|
| 301 |
int4 nxt;
|
| 302 |
-
const bool more = (k + 256 + 7 <
|
| 303 |
if (more) nxt = *reinterpret_cast<const int4*>(wr + k + 256);
|
| 304 |
const __nv_bfloat162* wp =
|
| 305 |
reinterpret_cast<const __nv_bfloat162*>(&wv4);
|
| 306 |
-
const __nv_bfloat162* xp =
|
| 307 |
-
reinterpret_cast<const __nv_bfloat162*>(xs + k);
|
| 308 |
#pragma unroll
|
| 309 |
-
for (int
|
| 310 |
-
|
| 311 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 312 |
}
|
| 313 |
if (more) wv4 = nxt;
|
| 314 |
}
|
| 315 |
}
|
| 316 |
-
|
| 317 |
-
|
| 318 |
-
if (
|
| 319 |
-
|
| 320 |
-
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 331 |
}
|
| 332 |
}
|
| 333 |
}
|
|
@@ -339,16 +341,58 @@ __device__ void ph_gemv(const long long* P, int pos) {
|
|
| 339 |
}
|
| 340 |
}
|
| 341 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 342 |
|
| 343 |
-
// Attention with rope fused in
|
| 344 |
-
// Slots: p1 qkv, p2 kcache, p3 vcache,
|
| 345 |
-
// [Hq
|
| 346 |
-
//
|
| 347 |
-
//
|
| 348 |
-
// copy of q (identical bits across chunks); the chunk owning `pos` also
|
| 349 |
// norms/ropes K and appends K/V for its group (duplicate identical writes
|
| 350 |
-
// across GQA members are benign)
|
| 351 |
-
|
|
|
|
|
|
|
| 352 |
const long long max_seq = P[7];
|
| 353 |
const int qk_flag = (int)P[8];
|
| 354 |
const float eps = bits2f(P[9]);
|
|
@@ -356,29 +400,11 @@ __device__ void ph_attn(const long long* P, int pos) {
|
|
| 356 |
const int Hq = (int)P[11], Hkv = (int)P[12], D = (int)P[13];
|
| 357 |
const float scale = bits2f(P[14]);
|
| 358 |
const int maxch = (int)P[15];
|
| 359 |
-
const int S = pos + 1;
|
| 360 |
-
const int nch = (S + ATTN_CHUNK - 1) / ATTN_CHUNK;
|
| 361 |
-
const int own_ch = pos / ATTN_CHUNK;
|
| 362 |
const int rep = Hq / Hkv;
|
|
|
|
| 363 |
|
| 364 |
const bf16* qnw = reinterpret_cast<const bf16*>(P[5]);
|
| 365 |
const bf16* knw = reinterpret_cast<const bf16*>(P[6]);
|
| 366 |
-
const bool red = (qk_flag & 2) != 0;
|
| 367 |
-
const long long KT = (long long)(Hq + 2 * Hkv) * D;
|
| 368 |
-
const float* qp = reinterpret_cast<const float*>(P[1]);
|
| 369 |
-
const bf16* qb = reinterpret_cast<const bf16*>(P[1]);
|
| 370 |
-
|
| 371 |
-
// qkv element: reduce the producer's fp32 k-slice partials (fixed order)
|
| 372 |
-
// and round to bf16, reproducing the monolithic store's value semantics.
|
| 373 |
-
auto qkv_at = [&](long long idx) -> float {
|
| 374 |
-
if (red) {
|
| 375 |
-
float s = qp[idx];
|
| 376 |
-
#pragma unroll
|
| 377 |
-
for (int sl = 1; sl < NSLICE; ++sl) s += qp[(long long)sl * KT + idx];
|
| 378 |
-
return bf2f(f2bf(s));
|
| 379 |
-
}
|
| 380 |
-
return bf2f(qb[idx]);
|
| 381 |
-
};
|
| 382 |
|
| 383 |
__shared__ float qs[MAX_HEAD_DIM];
|
| 384 |
__shared__ float hbuf[MAX_HEAD_DIM];
|
|
@@ -386,137 +412,150 @@ __device__ void ph_attn(const long long* P, int pos) {
|
|
| 386 |
__shared__ float s_red[32];
|
| 387 |
__shared__ float s_inv, s_m;
|
| 388 |
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
const
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 408 |
}
|
| 409 |
-
ss = block_sum(ss, s_red);
|
| 410 |
-
if (threadIdx.x == 0) s_inv = rsqrtf(ss / (float)D + eps);
|
| 411 |
__syncthreads();
|
| 412 |
-
for (int d = threadIdx.x; d < D; d += blockDim.x)
|
| 413 |
-
hbuf[d] = bf2f(f2bf(bf2f(qnw[d]) *
|
| 414 |
-
bf2f(f2bf(qkv_at(qbase + d) * s_inv))));
|
| 415 |
-
} else {
|
| 416 |
-
for (int d = threadIdx.x; d < D; d += blockDim.x)
|
| 417 |
-
hbuf[d] = qkv_at(qbase + d);
|
| 418 |
}
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
const float s = bf2f(f2bf(sinf(ang)));
|
| 425 |
-
const float x1 = hbuf[d], x2 = hbuf[d + half];
|
| 426 |
-
qs[d] = bf2f(f2bf(bf2f(f2bf(x1 * c)) + bf2f(f2bf(-x2 * s))));
|
| 427 |
-
qs[d + half] = bf2f(f2bf(bf2f(f2bf(x2 * c)) + bf2f(f2bf(x1 * s))));
|
| 428 |
}
|
| 429 |
-
__syncthreads();
|
| 430 |
-
}
|
| 431 |
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
const
|
| 435 |
-
const
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 441 |
}
|
| 442 |
-
ss = block_sum(ss, s_red);
|
| 443 |
-
if (threadIdx.x == 0) s_inv = rsqrtf(ss / (float)D + eps);
|
| 444 |
-
__syncthreads();
|
| 445 |
-
for (int d = threadIdx.x; d < D; d += blockDim.x)
|
| 446 |
-
hbuf[d] = bf2f(f2bf(bf2f(knw[d]) *
|
| 447 |
-
bf2f(f2bf(qkv_at(kbase + d) * s_inv))));
|
| 448 |
-
} else {
|
| 449 |
-
for (int d = threadIdx.x; d < D; d += blockDim.x)
|
| 450 |
-
hbuf[d] = qkv_at(kbase + d);
|
| 451 |
}
|
| 452 |
__syncthreads();
|
| 453 |
-
|
| 454 |
-
|
| 455 |
-
for (int
|
| 456 |
-
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
|
| 460 |
-
|
| 461 |
-
|
| 462 |
-
|
|
|
|
|
|
|
|
|
|
| 463 |
}
|
| 464 |
-
|
| 465 |
-
vrow[d] = f2bf(qkv_at(vbase + d));
|
| 466 |
-
__threadfence_block();
|
| 467 |
__syncthreads();
|
| 468 |
-
}
|
| 469 |
|
| 470 |
-
|
| 471 |
-
|
| 472 |
-
|
| 473 |
-
|
| 474 |
-
|
| 475 |
-
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
for (int d = lane; d < D; d += 32) acc = fmaf(qs[d], bf2f(kr[d]), acc);
|
| 481 |
-
acc = warp_sum(acc);
|
| 482 |
-
if (lane == 0) {
|
| 483 |
-
float x = bf2f(f2bf(acc));
|
| 484 |
-
sc[si] = bf2f(f2bf(x * scale));
|
| 485 |
}
|
|
|
|
| 486 |
}
|
| 487 |
-
|
|
|
|
| 488 |
|
| 489 |
-
|
| 490 |
-
|
| 491 |
-
|
| 492 |
-
|
| 493 |
-
|
| 494 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 495 |
|
| 496 |
-
|
| 497 |
-
|
| 498 |
-
|
| 499 |
-
sc[si] = p;
|
| 500 |
-
lsum += p;
|
| 501 |
-
}
|
| 502 |
-
lsum = block_sum(lsum, s_red);
|
| 503 |
-
__syncthreads();
|
| 504 |
|
| 505 |
-
|
| 506 |
-
|
| 507 |
-
|
| 508 |
-
|
| 509 |
-
|
| 510 |
-
|
| 511 |
-
|
| 512 |
-
|
| 513 |
-
|
| 514 |
-
|
| 515 |
-
}
|
| 516 |
-
__syncthreads();
|
| 517 |
}
|
| 518 |
}
|
| 519 |
-
|
| 520 |
__device__ void ph_argmax_part(const long long* P) {
|
| 521 |
const float* lg = reinterpret_cast<const float*>(P[1]);
|
| 522 |
unsigned long long* parts = reinterpret_cast<unsigned long long*>(P[3]);
|
|
@@ -555,13 +594,15 @@ __device__ void ph_argmax_fin(const long long* P, int step_slot) {
|
|
| 555 |
}
|
| 556 |
|
| 557 |
__device__ __forceinline__ void dispatch_phase(const long long* P, int pos,
|
| 558 |
-
int
|
|
|
|
| 559 |
switch ((int)P[0]) {
|
| 560 |
-
case OP_EMBED: ph_embed(P, pos, prompt_len); break;
|
| 561 |
-
case OP_GEMV: ph_gemv(P, pos); break;
|
| 562 |
-
case OP_ATTN: ph_attn(P, pos); break;
|
| 563 |
case OP_ARGMAX_PART: ph_argmax_part(P); break;
|
| 564 |
case OP_ARGMAX_FIN: ph_argmax_fin(P, step_slot); break;
|
|
|
|
| 565 |
default: break;
|
| 566 |
}
|
| 567 |
}
|
|
@@ -592,29 +633,44 @@ __device__ void grid_barrier(int* cnt, int* sense, int* local_sense) {
|
|
| 592 |
__syncthreads();
|
| 593 |
}
|
| 594 |
|
| 595 |
-
// One launch
|
| 596 |
-
//
|
| 597 |
-
//
|
|
|
|
|
|
|
|
|
|
| 598 |
__global__ void mega_kernel(const long long* __restrict__ prog, int n_phases,
|
| 599 |
-
int pos0, int
|
| 600 |
-
int* bar_cnt, int* bar_sense) {
|
| 601 |
__shared__ int s_sense;
|
| 602 |
if (threadIdx.x == 0) s_sense = atomicAdd(bar_sense, 0);
|
| 603 |
__syncthreads();
|
| 604 |
-
|
| 605 |
-
|
| 606 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 607 |
for (int p = 0; p < n_phases; ++p) {
|
| 608 |
-
|
| 609 |
-
|
|
|
|
|
|
|
| 610 |
if (!last) grid_barrier(bar_cnt, bar_sense, &s_sense);
|
| 611 |
}
|
|
|
|
| 612 |
}
|
| 613 |
}
|
| 614 |
|
| 615 |
__global__ void phase_kernel(const long long* __restrict__ prog, int p,
|
| 616 |
int pos, int step_slot, int prompt_len) {
|
| 617 |
-
|
|
|
|
|
|
|
| 618 |
}
|
| 619 |
|
| 620 |
} // namespace mak
|
|
@@ -648,11 +704,12 @@ int mak_grid_blocks_impl(int smem_bytes) {
|
|
| 648 |
}
|
| 649 |
|
| 650 |
cudaError_t mak_launch_mega(const long long* prog, int n_phases, int pos0,
|
| 651 |
-
int
|
| 652 |
-
int
|
| 653 |
-
int smem_bytes, cudaStream_t stream) {
|
| 654 |
mak::mega_kernel<<<grid, BLOCK_THREADS, smem_bytes, stream>>>(
|
| 655 |
-
prog, n_phases, pos0,
|
|
|
|
| 656 |
return cudaGetLastError();
|
| 657 |
}
|
| 658 |
|
|
|
|
| 37 |
OP_ATTN = 3,
|
| 38 |
OP_ARGMAX_PART = 4,
|
| 39 |
OP_ARGMAX_FIN = 5,
|
| 40 |
+
OP_KV_APPEND = 6, // prefill chunks only: rope+append K/V for all m
|
| 41 |
};
|
| 42 |
|
| 43 |
enum InputTransform : int {
|
|
|
|
| 131 |
// and any block with nothing to do simply falls through to the barrier.
|
| 132 |
// ---------------------------------------------------------------------------
|
| 133 |
|
| 134 |
+
__device__ void ph_embed(const long long* P, int pos, int M, int prompt_len) {
|
| 135 |
const bf16* tab = reinterpret_cast<const bf16*>(P[2]);
|
| 136 |
bf16* out = reinterpret_cast<bf16*>(P[3]);
|
| 137 |
const int* prompt = reinterpret_cast<const int*>(P[5]);
|
|
|
|
| 139 |
const long long K = P[8];
|
| 140 |
// Positions inside the prompt read from the staged prompt buffer; beyond
|
| 141 |
// it, from the feedback token written by the previous step's argmax.
|
| 142 |
+
for (long long i = (long long)blockIdx.x * blockDim.x + threadIdx.x;
|
| 143 |
+
i < (long long)M * K; i += (long long)gridDim.x * blockDim.x) {
|
| 144 |
+
const int m = (int)(i / K);
|
| 145 |
+
const long long k = i % K;
|
| 146 |
+
const int pm = pos + m;
|
| 147 |
+
const long long t = (pm < prompt_len && prompt != nullptr)
|
| 148 |
+
? (long long)prompt[pm]
|
| 149 |
+
: (long long)tok[0];
|
| 150 |
+
out[i] = tab[t * K + k];
|
| 151 |
+
}
|
| 152 |
}
|
| 153 |
|
| 154 |
__device__ __forceinline__ unsigned long long amax_key(float v, unsigned idx) {
|
|
|
|
| 161 |
// Finalize one element of split-S attention: combine per-chunk partials
|
| 162 |
// (max, sum, weighted V) into the bf16 attention output, matching eager's
|
| 163 |
// bf16 rounding of the attention output before the O projection.
|
| 164 |
+
__device__ __forceinline__ float attn_finalize(const float* mpart, int h,
|
| 165 |
int d, int D, int maxch,
|
| 166 |
int nch) {
|
| 167 |
+
const float* base = mpart + ((long long)h * maxch) * (D + 2);
|
| 168 |
float M = -INFINITY;
|
| 169 |
for (int c = 0; c < nch; ++c)
|
| 170 |
M = fmaxf(M, base[(long long)c * (D + 2) + D]);
|
|
|
|
| 201 |
// Reduced (or plain) bf16 input element k for a consumer phase: sum the
|
| 202 |
// producer's fp32 k-slice partials in fixed order, add the residual, round
|
| 203 |
// to bf16, optionally write the materialized vector back.
|
| 204 |
+
// GEMV over an M-token chunk. Weights are read once per chunk: each warp's
|
| 205 |
+
// 16-byte weight tile feeds M accumulators against M staged input rows, so
|
| 206 |
+
// prefill weight traffic is amortized by the chunk size. mmode (slot 12)
|
| 207 |
+
// restricts the phase to the chunk's last row (LM head). Buffers are laid
|
| 208 |
+
// out [M][len]; the residual stream and outputs address row m.
|
| 209 |
+
__device__ void ph_gemv(const long long* P, int pos, int M) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
const bf16* W = reinterpret_cast<const bf16*>(P[2]);
|
| 211 |
const bf16* gamma = reinterpret_cast<const bf16*>(P[4]);
|
| 212 |
const bf16* resid = reinterpret_cast<const bf16*>(P[5]);
|
| 213 |
const long long N = P[7], K = P[8];
|
| 214 |
+
const int itrans = ((int)P[9]) & ITF_BASE_MASK;
|
|
|
|
| 215 |
const int epi = (int)P[10];
|
| 216 |
+
const int mmode = (int)P[12];
|
| 217 |
const float eps = bits2f(P[14]);
|
| 218 |
const float* part = reinterpret_cast<const float*>(P[1]);
|
| 219 |
+
const bf16* xin = reinterpret_cast<const bf16*>(P[1]);
|
| 220 |
const int D = (int)P[13];
|
| 221 |
const int maxch = (int)P[15];
|
| 222 |
+
|
| 223 |
+
const int m0 = mmode ? (M - 1) : 0;
|
| 224 |
+
const int Ma = M - m0; // staged rows
|
| 225 |
+
|
| 226 |
+
// Stage transformed inputs for all chunk rows: [Ma][K] in shared, bf16
|
| 227 |
+
// (every transform value is bf16-rounded by semantics, so staging is
|
| 228 |
+
// exact). RMSNORM computes one inverse rms per row.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 229 |
extern __shared__ bf16 xs[];
|
| 230 |
__shared__ float s_red[32];
|
| 231 |
__shared__ float s_scale;
|
| 232 |
+
__shared__ unsigned long long s64[32];
|
| 233 |
+
for (int m = 0; m < Ma; ++m) {
|
| 234 |
+
const int srcm = m0 + m;
|
| 235 |
+
if (itrans == IT_RMSNORM) {
|
| 236 |
+
const bf16* xr = xin + (long long)srcm * K;
|
| 237 |
+
float ss = 0.f;
|
| 238 |
+
for (long long k = threadIdx.x; k < K; k += blockDim.x) {
|
| 239 |
+
const float v = bf2f(xr[k]);
|
| 240 |
+
ss += v * v;
|
| 241 |
+
}
|
| 242 |
+
ss = block_sum(ss, s_red);
|
| 243 |
+
if (threadIdx.x == 0) s_scale = rsqrtf(ss / (float)K + eps);
|
| 244 |
+
__syncthreads();
|
| 245 |
+
const float inv = s_scale;
|
| 246 |
+
for (long long k = threadIdx.x; k < K; k += blockDim.x)
|
| 247 |
+
xs[(long long)m * K + k] =
|
| 248 |
+
f2bf(bf2f(gamma[k]) * bf2f(f2bf(bf2f(xr[k]) * inv)));
|
| 249 |
+
__syncthreads();
|
| 250 |
+
} else if (itrans == IT_SWIGLU) {
|
| 251 |
+
const bf16* xr = xin + (long long)srcm * 2 * K;
|
| 252 |
+
for (long long k = threadIdx.x; k < K; k += blockDim.x) {
|
| 253 |
+
const float g = bf2f(xr[k]);
|
| 254 |
const float sig = 1.f / (1.f + expf(-g));
|
| 255 |
const float sg = bf2f(f2bf(g * sig));
|
| 256 |
+
xs[(long long)m * K + k] = f2bf(bf2f(f2bf(sg * bf2f(xr[K + k]))));
|
|
|
|
|
|
|
|
|
|
|
|
|
| 257 |
}
|
| 258 |
+
} else if (itrans == IT_ATTNFIN) {
|
| 259 |
+
const int pm = pos + srcm;
|
| 260 |
+
const int nch = (pm + ATTN_CHUNK) / ATTN_CHUNK;
|
| 261 |
+
const float* mpart =
|
| 262 |
+
part + (long long)srcm * ((long long)P[11] * maxch * (D + 2));
|
| 263 |
+
for (long long k = threadIdx.x; k < K; k += blockDim.x)
|
| 264 |
+
xs[(long long)m * K + k] = f2bf(attn_finalize(
|
| 265 |
+
mpart, (int)(k / D), (int)(k % D), D, maxch, nch));
|
| 266 |
+
} else {
|
| 267 |
+
const bf16* xr = xin + (long long)srcm * K;
|
| 268 |
+
for (long long k = threadIdx.x; k < K; k += blockDim.x)
|
| 269 |
+
xs[(long long)m * K + k] = xr[k];
|
| 270 |
}
|
| 271 |
}
|
| 272 |
__syncthreads();
|
|
|
|
| 275 |
const long long warp =
|
| 276 |
((long long)blockIdx.x * blockDim.x + threadIdx.x) >> 5;
|
| 277 |
const long long nwarps = ((long long)gridDim.x * blockDim.x) >> 5;
|
|
|
|
| 278 |
unsigned long long best = amax_key(-INFINITY, 0xFFFFFFFFu);
|
| 279 |
+
for (long long row = warp; row < N; row += nwarps) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 280 |
const bf16* wr = W + row * K;
|
| 281 |
+
float acc[8];
|
| 282 |
+
#pragma unroll
|
| 283 |
+
for (int m = 0; m < 8; ++m) acc[m] = 0.f;
|
| 284 |
+
// 16-byte weight loads, next tile prefetched; each tile feeds all
|
| 285 |
+
// staged rows.
|
| 286 |
+
long long k = (long long)lane * 8;
|
| 287 |
+
if (k + 7 < K) {
|
| 288 |
int4 wv4 = *reinterpret_cast<const int4*>(wr + k);
|
| 289 |
+
for (; k + 7 < K; k += 256) {
|
| 290 |
int4 nxt;
|
| 291 |
+
const bool more = (k + 256 + 7 < K);
|
| 292 |
if (more) nxt = *reinterpret_cast<const int4*>(wr + k + 256);
|
| 293 |
const __nv_bfloat162* wp =
|
| 294 |
reinterpret_cast<const __nv_bfloat162*>(&wv4);
|
|
|
|
|
|
|
| 295 |
#pragma unroll
|
| 296 |
+
for (int m = 0; m < 8; ++m) {
|
| 297 |
+
if (m < Ma) {
|
| 298 |
+
const __nv_bfloat162* xp =
|
| 299 |
+
reinterpret_cast<const __nv_bfloat162*>(xs +
|
| 300 |
+
(long long)m * K + k);
|
| 301 |
+
#pragma unroll
|
| 302 |
+
for (int j = 0; j < 4; ++j) {
|
| 303 |
+
acc[m] = fmaf(__low2float(wp[j]), __low2float(xp[j]), acc[m]);
|
| 304 |
+
acc[m] = fmaf(__high2float(wp[j]), __high2float(xp[j]),
|
| 305 |
+
acc[m]);
|
| 306 |
+
}
|
| 307 |
+
}
|
| 308 |
}
|
| 309 |
if (more) wv4 = nxt;
|
| 310 |
}
|
| 311 |
}
|
| 312 |
+
#pragma unroll
|
| 313 |
+
for (int m = 0; m < 8; ++m) {
|
| 314 |
+
if (m < Ma) {
|
| 315 |
+
const float a = warp_sum(acc[m]);
|
| 316 |
+
if (lane == 0) {
|
| 317 |
+
const int srcm = m0 + m;
|
| 318 |
+
if (epi == EP_RESID)
|
| 319 |
+
reinterpret_cast<bf16*>(P[3])[(long long)srcm * N + row] =
|
| 320 |
+
f2bf(bf2f(resid[(long long)srcm * N + row]) + a);
|
| 321 |
+
else if (epi == EP_F32)
|
| 322 |
+
reinterpret_cast<float*>(P[3])[row] = a;
|
| 323 |
+
else if (epi == EP_F32_AMAX) {
|
| 324 |
+
reinterpret_cast<float*>(P[3])[row] = a;
|
| 325 |
+
const unsigned long long kk = amax_key(bf2f(f2bf(a)),
|
| 326 |
+
(unsigned)row);
|
| 327 |
+
best = (kk > best) ? kk : best;
|
| 328 |
+
} else {
|
| 329 |
+
reinterpret_cast<bf16*>(P[3])[(long long)srcm * N + row] =
|
| 330 |
+
f2bf(a);
|
| 331 |
+
}
|
| 332 |
+
}
|
| 333 |
}
|
| 334 |
}
|
| 335 |
}
|
|
|
|
| 341 |
}
|
| 342 |
}
|
| 343 |
|
| 344 |
+
// Norm/rope K and copy V into the cache for one (kv-head, position);
|
| 345 |
+
// block-cooperative, semantics identical to the eager reference.
|
| 346 |
+
__device__ void kv_norm_rope_append(const bf16* qkv, bf16* kc, bf16* vc,
|
| 347 |
+
const bf16* knw, int qk_flag, float eps,
|
| 348 |
+
float theta, int Hq, int Hkv, int kvh,
|
| 349 |
+
int D, int pm, float* s_red,
|
| 350 |
+
float* s_inv, float* hbuf) {
|
| 351 |
+
const int half = D >> 1;
|
| 352 |
+
const bf16* ksrc = qkv + (long long)(Hq + kvh) * D;
|
| 353 |
+
const bf16* vsrc = qkv + (long long)(Hq + Hkv + kvh) * D;
|
| 354 |
+
if (qk_flag & 1) {
|
| 355 |
+
float ss = 0.f;
|
| 356 |
+
for (int d = threadIdx.x; d < D; d += blockDim.x) {
|
| 357 |
+
const float x = bf2f(ksrc[d]);
|
| 358 |
+
ss += x * x;
|
| 359 |
+
}
|
| 360 |
+
ss = block_sum(ss, s_red);
|
| 361 |
+
if (threadIdx.x == 0) *s_inv = rsqrtf(ss / (float)D + eps);
|
| 362 |
+
__syncthreads();
|
| 363 |
+
for (int d = threadIdx.x; d < D; d += blockDim.x)
|
| 364 |
+
hbuf[d] = bf2f(f2bf(bf2f(knw[d]) *
|
| 365 |
+
bf2f(f2bf(bf2f(ksrc[d]) * (*s_inv)))));
|
| 366 |
+
} else {
|
| 367 |
+
for (int d = threadIdx.x; d < D; d += blockDim.x) hbuf[d] = bf2f(ksrc[d]);
|
| 368 |
+
}
|
| 369 |
+
__syncthreads();
|
| 370 |
+
bf16* krow = kc + (long long)pm * D;
|
| 371 |
+
bf16* vrow = vc + (long long)pm * D;
|
| 372 |
+
for (int d = threadIdx.x; d < half; d += blockDim.x) {
|
| 373 |
+
const float inv_freq = 1.f / powf(theta, (float)(2 * d) / (float)D);
|
| 374 |
+
const float ang = (float)pm * inv_freq;
|
| 375 |
+
const float c = bf2f(f2bf(cosf(ang)));
|
| 376 |
+
const float s = bf2f(f2bf(sinf(ang)));
|
| 377 |
+
const float x1 = hbuf[d], x2 = hbuf[d + half];
|
| 378 |
+
krow[d] = f2bf(bf2f(f2bf(x1 * c)) + bf2f(f2bf(-x2 * s)));
|
| 379 |
+
krow[d + half] = f2bf(bf2f(f2bf(x2 * c)) + bf2f(f2bf(x1 * s)));
|
| 380 |
+
}
|
| 381 |
+
for (int d = threadIdx.x; d < D; d += blockDim.x) vrow[d] = vsrc[d];
|
| 382 |
+
__threadfence_block();
|
| 383 |
+
__syncthreads();
|
| 384 |
+
}
|
| 385 |
|
| 386 |
+
// Attention with rope fused in, cached positions split across chunks, and
|
| 387 |
+
// an M-token prefill loop. Slots: p1 qkv [M rows], p2 kcache, p3 vcache,
|
| 388 |
+
// p4 fp32 partials [M][Hq][maxch][D+2], p5 q-norm w, p6 k-norm w,
|
| 389 |
+
// 7 max_seq, 8 qk flag, 9 eps bits, 10 theta bits, 11 Hq, 12 Hkv, 13 D,
|
| 390 |
+
// 14 scale, 15 maxch. In decode (M == 1) the chunk owning `pos` also
|
|
|
|
| 391 |
// norms/ropes K and appends K/V for its group (duplicate identical writes
|
| 392 |
+
// across GQA members are benign); in prefill chunks the OP_KV_APPEND phase
|
| 393 |
+
// has already appended all M positions, so causal reads within the chunk
|
| 394 |
+
// are safe. The O-projection finalizes the partials.
|
| 395 |
+
__device__ void ph_attn(const long long* P, int pos, int M) {
|
| 396 |
const long long max_seq = P[7];
|
| 397 |
const int qk_flag = (int)P[8];
|
| 398 |
const float eps = bits2f(P[9]);
|
|
|
|
| 400 |
const int Hq = (int)P[11], Hkv = (int)P[12], D = (int)P[13];
|
| 401 |
const float scale = bits2f(P[14]);
|
| 402 |
const int maxch = (int)P[15];
|
|
|
|
|
|
|
|
|
|
| 403 |
const int rep = Hq / Hkv;
|
| 404 |
+
const long long KT = (long long)(Hq + 2 * Hkv) * D;
|
| 405 |
|
| 406 |
const bf16* qnw = reinterpret_cast<const bf16*>(P[5]);
|
| 407 |
const bf16* knw = reinterpret_cast<const bf16*>(P[6]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 408 |
|
| 409 |
__shared__ float qs[MAX_HEAD_DIM];
|
| 410 |
__shared__ float hbuf[MAX_HEAD_DIM];
|
|
|
|
| 412 |
__shared__ float s_red[32];
|
| 413 |
__shared__ float s_inv, s_m;
|
| 414 |
|
| 415 |
+
// (m, head, chunk) flattened into one block-stride space so prefill
|
| 416 |
+
// chunks use M times the parallelism; per-m chunk counts vary, so
|
| 417 |
+
// out-of-range (m, ch) pairs skip uniformly.
|
| 418 |
+
const int nch_max =
|
| 419 |
+
(pos + M - 1 + 1 + ATTN_CHUNK - 1) / ATTN_CHUNK;
|
| 420 |
+
{
|
| 421 |
+
const int total = M * Hq * nch_max;
|
| 422 |
+
for (int v = blockIdx.x; v < total; v += gridDim.x) {
|
| 423 |
+
const int m = v / (Hq * nch_max);
|
| 424 |
+
const int rem = v % (Hq * nch_max);
|
| 425 |
+
const int head = rem / nch_max;
|
| 426 |
+
const int ch = rem % nch_max;
|
| 427 |
+
const int pm = pos + m;
|
| 428 |
+
const int S = pm + 1;
|
| 429 |
+
const int nch = (S + ATTN_CHUNK - 1) / ATTN_CHUNK;
|
| 430 |
+
if (ch >= nch) continue;
|
| 431 |
+
const int own_ch = pm / ATTN_CHUNK;
|
| 432 |
+
const bf16* qkv =
|
| 433 |
+
reinterpret_cast<const bf16*>(P[1]) + (long long)m * KT;
|
| 434 |
+
float* partm = reinterpret_cast<float*>(P[4]) +
|
| 435 |
+
(long long)m * ((long long)Hq * maxch * (D + 2));
|
| 436 |
+
const int kvh = head / rep;
|
| 437 |
+
bf16* kc = reinterpret_cast<bf16*>(P[2]) + (long long)kvh * max_seq * D;
|
| 438 |
+
bf16* vc = reinterpret_cast<bf16*>(P[3]) + (long long)kvh * max_seq * D;
|
| 439 |
+
float* part = partm + ((long long)head * maxch + ch) * (D + 2);
|
| 440 |
+
const int half = D >> 1;
|
| 441 |
+
|
| 442 |
+
// stage rope'd q (bf16-rounded values) into shared
|
| 443 |
+
{
|
| 444 |
+
const bf16* q = qkv + (long long)head * D;
|
| 445 |
+
if (qk_flag & 1) {
|
| 446 |
+
float ss = 0.f;
|
| 447 |
+
for (int d = threadIdx.x; d < D; d += blockDim.x) {
|
| 448 |
+
const float x = bf2f(q[d]);
|
| 449 |
+
ss += x * x;
|
| 450 |
+
}
|
| 451 |
+
ss = block_sum(ss, s_red);
|
| 452 |
+
if (threadIdx.x == 0) s_inv = rsqrtf(ss / (float)D + eps);
|
| 453 |
+
__syncthreads();
|
| 454 |
+
for (int d = threadIdx.x; d < D; d += blockDim.x)
|
| 455 |
+
hbuf[d] =
|
| 456 |
+
bf2f(f2bf(bf2f(qnw[d]) * bf2f(f2bf(bf2f(q[d]) * s_inv))));
|
| 457 |
+
} else {
|
| 458 |
+
for (int d = threadIdx.x; d < D; d += blockDim.x)
|
| 459 |
+
hbuf[d] = bf2f(q[d]);
|
| 460 |
+
}
|
| 461 |
+
__syncthreads();
|
| 462 |
+
for (int d = threadIdx.x; d < half; d += blockDim.x) {
|
| 463 |
+
const float inv_freq = 1.f / powf(theta, (float)(2 * d) / (float)D);
|
| 464 |
+
const float ang = (float)pm * inv_freq;
|
| 465 |
+
const float c = bf2f(f2bf(cosf(ang)));
|
| 466 |
+
const float s = bf2f(f2bf(sinf(ang)));
|
| 467 |
+
const float x1 = hbuf[d], x2 = hbuf[d + half];
|
| 468 |
+
qs[d] = bf2f(f2bf(bf2f(f2bf(x1 * c)) + bf2f(f2bf(-x2 * s))));
|
| 469 |
+
qs[d + half] = bf2f(f2bf(bf2f(f2bf(x2 * c)) + bf2f(f2bf(x1 * s))));
|
| 470 |
}
|
|
|
|
|
|
|
| 471 |
__syncthreads();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 472 |
}
|
| 473 |
+
|
| 474 |
+
// decode only: the chunk owning `pos` appends K/V for its group
|
| 475 |
+
if (M == 1 && ch == own_ch) {
|
| 476 |
+
kv_norm_rope_append(qkv, kc, vc, knw, qk_flag, eps, theta, Hq, Hkv,
|
| 477 |
+
kvh, D, pm, s_red, &s_inv, hbuf);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 478 |
}
|
|
|
|
|
|
|
| 479 |
|
| 480 |
+
// score this chunk: eager rounds QK^T to bf16, scales as a bf16 op,
|
| 481 |
+
// upcasts to fp32 for the softmax
|
| 482 |
+
const int s0 = ch * ATTN_CHUNK;
|
| 483 |
+
const int s1 = (s0 + ATTN_CHUNK < S) ? s0 + ATTN_CHUNK : S;
|
| 484 |
+
const int cn = s1 - s0;
|
| 485 |
+
const int wid = threadIdx.x >> 5, lane = threadIdx.x & 31;
|
| 486 |
+
const int nw = blockDim.x >> 5;
|
| 487 |
+
for (int si = wid; si < cn; si += nw) {
|
| 488 |
+
const bf16* kr = kc + (long long)(s0 + si) * D;
|
| 489 |
+
float acc = 0.f;
|
| 490 |
+
for (int d = lane; d < D; d += 32) acc = fmaf(qs[d], bf2f(kr[d]), acc);
|
| 491 |
+
acc = warp_sum(acc);
|
| 492 |
+
if (lane == 0) {
|
| 493 |
+
float x = bf2f(f2bf(acc));
|
| 494 |
+
sc[si] = bf2f(f2bf(x * scale));
|
| 495 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 496 |
}
|
| 497 |
__syncthreads();
|
| 498 |
+
|
| 499 |
+
float mx = -INFINITY;
|
| 500 |
+
for (int si = threadIdx.x; si < cn; si += blockDim.x)
|
| 501 |
+
mx = fmaxf(mx, sc[si]);
|
| 502 |
+
mx = block_max(mx, s_red);
|
| 503 |
+
if (threadIdx.x == 0) s_m = mx;
|
| 504 |
+
__syncthreads();
|
| 505 |
+
|
| 506 |
+
float lsum = 0.f;
|
| 507 |
+
for (int si = threadIdx.x; si < cn; si += blockDim.x) {
|
| 508 |
+
const float p = expf(sc[si] - s_m);
|
| 509 |
+
sc[si] = p;
|
| 510 |
+
lsum += p;
|
| 511 |
}
|
| 512 |
+
lsum = block_sum(lsum, s_red);
|
|
|
|
|
|
|
| 513 |
__syncthreads();
|
|
|
|
| 514 |
|
| 515 |
+
if (threadIdx.x < D) {
|
| 516 |
+
const int d = threadIdx.x;
|
| 517 |
+
float acc = 0.f;
|
| 518 |
+
for (int si = 0; si < cn; ++si)
|
| 519 |
+
acc = fmaf(sc[si], bf2f(vc[(long long)(s0 + si) * D + d]), acc);
|
| 520 |
+
part[d] = acc;
|
| 521 |
+
}
|
| 522 |
+
if (threadIdx.x == 0) {
|
| 523 |
+
part[D] = s_m;
|
| 524 |
+
part[D + 1] = lsum;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 525 |
}
|
| 526 |
+
__syncthreads();
|
| 527 |
}
|
| 528 |
+
}
|
| 529 |
+
}
|
| 530 |
|
| 531 |
+
// Prefill chunks: norm/rope K and copy V into the cache for every position
|
| 532 |
+
// of the chunk, one (m, kv-head) pair per block iteration. Runs before the
|
| 533 |
+
// attention phase so causal reads inside the chunk see complete K/V.
|
| 534 |
+
__device__ void ph_kv_append(const long long* P, int pos, int M) {
|
| 535 |
+
const long long max_seq = P[7];
|
| 536 |
+
const int qk_flag = (int)P[8];
|
| 537 |
+
const float eps = bits2f(P[9]);
|
| 538 |
+
const float theta = bits2f(P[10]);
|
| 539 |
+
const int Hq = (int)P[11], Hkv = (int)P[12], D = (int)P[13];
|
| 540 |
+
const long long KT = (long long)(Hq + 2 * Hkv) * D;
|
| 541 |
+
const bf16* knw = reinterpret_cast<const bf16*>(P[6]);
|
| 542 |
|
| 543 |
+
__shared__ float s_red[32];
|
| 544 |
+
__shared__ float s_inv;
|
| 545 |
+
__shared__ float hbuf[MAX_HEAD_DIM];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 546 |
|
| 547 |
+
const int total = M * Hkv;
|
| 548 |
+
for (int v = blockIdx.x; v < total; v += gridDim.x) {
|
| 549 |
+
const int m = v / Hkv;
|
| 550 |
+
const int kvh = v % Hkv;
|
| 551 |
+
const int pm = pos + m;
|
| 552 |
+
const bf16* qkv = reinterpret_cast<const bf16*>(P[1]) + (long long)m * KT;
|
| 553 |
+
bf16* kc = reinterpret_cast<bf16*>(P[2]) + (long long)kvh * max_seq * D;
|
| 554 |
+
bf16* vc = reinterpret_cast<bf16*>(P[3]) + (long long)kvh * max_seq * D;
|
| 555 |
+
kv_norm_rope_append(qkv, kc, vc, knw, qk_flag, eps, theta, Hq, Hkv, kvh,
|
| 556 |
+
D, pm, s_red, &s_inv, hbuf);
|
|
|
|
|
|
|
| 557 |
}
|
| 558 |
}
|
|
|
|
| 559 |
__device__ void ph_argmax_part(const long long* P) {
|
| 560 |
const float* lg = reinterpret_cast<const float*>(P[1]);
|
| 561 |
unsigned long long* parts = reinterpret_cast<unsigned long long*>(P[3]);
|
|
|
|
| 594 |
}
|
| 595 |
|
| 596 |
__device__ __forceinline__ void dispatch_phase(const long long* P, int pos,
|
| 597 |
+
int M, int step_slot,
|
| 598 |
+
int prompt_len) {
|
| 599 |
switch ((int)P[0]) {
|
| 600 |
+
case OP_EMBED: ph_embed(P, pos, M, prompt_len); break;
|
| 601 |
+
case OP_GEMV: ph_gemv(P, pos, M); break;
|
| 602 |
+
case OP_ATTN: ph_attn(P, pos, M); break;
|
| 603 |
case OP_ARGMAX_PART: ph_argmax_part(P); break;
|
| 604 |
case OP_ARGMAX_FIN: ph_argmax_fin(P, step_slot); break;
|
| 605 |
+
case OP_KV_APPEND: ph_kv_append(P, pos, M); break;
|
| 606 |
default: break;
|
| 607 |
}
|
| 608 |
}
|
|
|
|
| 633 |
__syncthreads();
|
| 634 |
}
|
| 635 |
|
| 636 |
+
// One launch consumes `total` positions: prompt positions in chunks of up
|
| 637 |
+
// to `chunk_m` (weights amortized across the chunk), generated positions
|
| 638 |
+
// one at a time with the argmax of each step feeding the next embedding
|
| 639 |
+
// read. The grid barrier carries across every boundary. OP_KV_APPEND
|
| 640 |
+
// phases run only inside multi-token chunks; in decode both the dispatch
|
| 641 |
+
// and the barrier are skipped uniformly, so they cost nothing.
|
| 642 |
__global__ void mega_kernel(const long long* __restrict__ prog, int n_phases,
|
| 643 |
+
int pos0, int total, int slot0, int prompt_len,
|
| 644 |
+
int chunk_m, int* bar_cnt, int* bar_sense) {
|
| 645 |
__shared__ int s_sense;
|
| 646 |
if (threadIdx.x == 0) s_sense = atomicAdd(bar_sense, 0);
|
| 647 |
__syncthreads();
|
| 648 |
+
int pos = pos0;
|
| 649 |
+
const int pos_end = pos0 + total;
|
| 650 |
+
while (pos < pos_end) {
|
| 651 |
+
int M = 1;
|
| 652 |
+
if (pos < prompt_len) {
|
| 653 |
+
M = prompt_len - pos;
|
| 654 |
+
if (M > chunk_m) M = chunk_m;
|
| 655 |
+
if (pos + M > pos_end) M = pos_end - pos;
|
| 656 |
+
}
|
| 657 |
+
const int slot = slot0 + (pos + M - 1 - pos0);
|
| 658 |
for (int p = 0; p < n_phases; ++p) {
|
| 659 |
+
const long long* P = prog + (long long)p * 16;
|
| 660 |
+
if ((int)P[0] == OP_KV_APPEND && M == 1) continue; // uniform skip
|
| 661 |
+
dispatch_phase(P, pos, M, slot, prompt_len);
|
| 662 |
+
const bool last = (pos + M >= pos_end) && (p + 1 == n_phases);
|
| 663 |
if (!last) grid_barrier(bar_cnt, bar_sense, &s_sense);
|
| 664 |
}
|
| 665 |
+
pos += M;
|
| 666 |
}
|
| 667 |
}
|
| 668 |
|
| 669 |
__global__ void phase_kernel(const long long* __restrict__ prog, int p,
|
| 670 |
int pos, int step_slot, int prompt_len) {
|
| 671 |
+
const long long* P = prog + (long long)p * 16;
|
| 672 |
+
if ((int)P[0] == OP_KV_APPEND) return;
|
| 673 |
+
dispatch_phase(P, pos, 1, step_slot, prompt_len);
|
| 674 |
}
|
| 675 |
|
| 676 |
} // namespace mak
|
|
|
|
| 704 |
}
|
| 705 |
|
| 706 |
cudaError_t mak_launch_mega(const long long* prog, int n_phases, int pos0,
|
| 707 |
+
int total, int slot0, int prompt_len,
|
| 708 |
+
int chunk_m, int* bar_cnt, int* bar_sense,
|
| 709 |
+
int grid, int smem_bytes, cudaStream_t stream) {
|
| 710 |
mak::mega_kernel<<<grid, BLOCK_THREADS, smem_bytes, stream>>>(
|
| 711 |
+
prog, n_phases, pos0, total, slot0, prompt_len, chunk_m, bar_cnt,
|
| 712 |
+
bar_sense);
|
| 713 |
return cudaGetLastError();
|
| 714 |
}
|
| 715 |
|
torch-ext/model_as_a_kernel/__init__.py
CHANGED
|
@@ -111,14 +111,18 @@ class MegaModel:
|
|
| 111 |
|
| 112 |
# Working buffers. Pointers to these are baked into the program, so
|
| 113 |
# they (like the packed weights) live for the model's lifetime.
|
| 114 |
-
self.
|
| 115 |
-
|
| 116 |
-
self.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
self._logits = torch.empty(self.V, dtype=torch.float32, device=dev)
|
| 118 |
self._chunk = 256 # ATTN_CHUNK in the kernel
|
| 119 |
self._maxch = (self.max_seq + self._chunk - 1) // self._chunk
|
| 120 |
self._partials = torch.empty(
|
| 121 |
-
self.Hq * self._maxch * (self.D + 2), dtype=torch.float32,
|
| 122 |
device=dev)
|
| 123 |
self._kcache = torch.zeros(self.L, self.Hkv, self.max_seq, self.D,
|
| 124 |
dtype=dt, device=dev)
|
|
@@ -131,7 +135,6 @@ class MegaModel:
|
|
| 131 |
device=dev)
|
| 132 |
self._bar = torch.zeros(2, dtype=torch.int32, device=dev)
|
| 133 |
|
| 134 |
-
self._maxk = max(self.hidden, qdim, self.I)
|
| 135 |
probe = torch.zeros(1, 16, dtype=torch.int64, device=dev)
|
| 136 |
self._nblocks = int(ops.mak_num_blocks(probe, self._maxk))
|
| 137 |
self._parts = torch.zeros(self._nblocks, dtype=torch.int64, device=dev)
|
|
@@ -153,6 +156,12 @@ class MegaModel:
|
|
| 153 |
n=qdim + 2 * kvdim, k=self.hidden,
|
| 154 |
it=_IT_RMSNORM, epi=_EP_STORE, f0=self.eps))
|
| 155 |
names.append(f"L{li}.qkv")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
rows.append(_row(_OP_ATTN, p1=self._qkv.data_ptr(), p2=kc,
|
| 157 |
p3=vc, p4=self._partials.data_ptr(),
|
| 158 |
p5=lw["qn"].data_ptr() if self.qk_norm else 0,
|
|
@@ -165,7 +174,8 @@ class MegaModel:
|
|
| 165 |
rows.append(_row(_OP_GEMV, p1=self._partials.data_ptr(),
|
| 166 |
p2=lw["wo"].data_ptr(), p3=hid, p5=hid,
|
| 167 |
n=self.hidden, k=qdim, it=_IT_ATTNFIN,
|
| 168 |
-
epi=_EP_RESID,
|
|
|
|
| 169 |
names.append(f"L{li}.o")
|
| 170 |
rows.append(_row(_OP_GEMV, p1=hid, p2=lw["wgu"].data_ptr(),
|
| 171 |
p3=self._gu.data_ptr(),
|
|
@@ -182,7 +192,8 @@ class MegaModel:
|
|
| 182 |
p3=self._logits.data_ptr(),
|
| 183 |
p4=final_norm.data_ptr(),
|
| 184 |
p6=self._parts.data_ptr(), n=self.V, k=self.hidden,
|
| 185 |
-
it=_IT_RMSNORM, epi=_EP_F32_AMAX,
|
|
|
|
| 186 |
names.append("lm_head")
|
| 187 |
rows.append(_row(_OP_ARGMAX_FIN, p1=self._parts.data_ptr(),
|
| 188 |
p3=self._token.data_ptr(),
|
|
@@ -275,9 +286,17 @@ class MegaModel:
|
|
| 275 |
return self._logits, ms
|
| 276 |
|
| 277 |
def prefill(self, ids: Sequence[int], phased: bool = False):
|
| 278 |
-
"""
|
| 279 |
-
|
| 280 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 281 |
return self._logits
|
| 282 |
|
| 283 |
def generate(self, prompt_ids: Sequence[int], max_new: int,
|
|
@@ -298,7 +317,7 @@ class MegaModel:
|
|
| 298 |
self._prompt_in[:P].copy_(
|
| 299 |
torch.tensor(prompt_ids, dtype=torch.int32))
|
| 300 |
ops.mak_run_seq(self._prog, self._bar, 0, P + max_new - 1,
|
| 301 |
-
1 - P, P, self._maxk)
|
| 302 |
return self._tokens_out[:max_new].cpu().tolist()
|
| 303 |
pos = 0
|
| 304 |
for t in prompt_ids[:-1]:
|
|
|
|
| 111 |
|
| 112 |
# Working buffers. Pointers to these are baked into the program, so
|
| 113 |
# they (like the packed weights) live for the model's lifetime.
|
| 114 |
+
self._maxk = max(self.hidden, qdim, self.I)
|
| 115 |
+
# prefill chunk size, bounded by the staging shared-memory budget
|
| 116 |
+
self._chunk_m = max(1, min(8, 40960 // (2 * self._maxk)))
|
| 117 |
+
cm = 8 # buffers sized for the maximum chunk
|
| 118 |
+
self._hidden = torch.empty(cm * self.hidden, dtype=dt, device=dev)
|
| 119 |
+
self._qkv = torch.empty(cm * (qdim + 2 * kvdim), dtype=dt, device=dev)
|
| 120 |
+
self._gu = torch.empty(cm * 2 * self.I, dtype=dt, device=dev)
|
| 121 |
self._logits = torch.empty(self.V, dtype=torch.float32, device=dev)
|
| 122 |
self._chunk = 256 # ATTN_CHUNK in the kernel
|
| 123 |
self._maxch = (self.max_seq + self._chunk - 1) // self._chunk
|
| 124 |
self._partials = torch.empty(
|
| 125 |
+
cm * self.Hq * self._maxch * (self.D + 2), dtype=torch.float32,
|
| 126 |
device=dev)
|
| 127 |
self._kcache = torch.zeros(self.L, self.Hkv, self.max_seq, self.D,
|
| 128 |
dtype=dt, device=dev)
|
|
|
|
| 135 |
device=dev)
|
| 136 |
self._bar = torch.zeros(2, dtype=torch.int32, device=dev)
|
| 137 |
|
|
|
|
| 138 |
probe = torch.zeros(1, 16, dtype=torch.int64, device=dev)
|
| 139 |
self._nblocks = int(ops.mak_num_blocks(probe, self._maxk))
|
| 140 |
self._parts = torch.zeros(self._nblocks, dtype=torch.int64, device=dev)
|
|
|
|
| 156 |
n=qdim + 2 * kvdim, k=self.hidden,
|
| 157 |
it=_IT_RMSNORM, epi=_EP_STORE, f0=self.eps))
|
| 158 |
names.append(f"L{li}.qkv")
|
| 159 |
+
rows.append(_row(6, p1=self._qkv.data_ptr(), p2=kc, p3=vc,
|
| 160 |
+
p6=lw["kn"].data_ptr() if self.qk_norm else 0,
|
| 161 |
+
n=self.max_seq, k=1 if self.qk_norm else 0,
|
| 162 |
+
it=_fbits(self.eps), epi=_fbits(self.theta),
|
| 163 |
+
hq=self.Hq, hkv=self.Hkv, d=self.D))
|
| 164 |
+
names.append(f"L{li}.kvappend")
|
| 165 |
rows.append(_row(_OP_ATTN, p1=self._qkv.data_ptr(), p2=kc,
|
| 166 |
p3=vc, p4=self._partials.data_ptr(),
|
| 167 |
p5=lw["qn"].data_ptr() if self.qk_norm else 0,
|
|
|
|
| 174 |
rows.append(_row(_OP_GEMV, p1=self._partials.data_ptr(),
|
| 175 |
p2=lw["wo"].data_ptr(), p3=hid, p5=hid,
|
| 176 |
n=self.hidden, k=qdim, it=_IT_ATTNFIN,
|
| 177 |
+
epi=_EP_RESID, hq=self.Hq, d=self.D,
|
| 178 |
+
i0=self._maxch))
|
| 179 |
names.append(f"L{li}.o")
|
| 180 |
rows.append(_row(_OP_GEMV, p1=hid, p2=lw["wgu"].data_ptr(),
|
| 181 |
p3=self._gu.data_ptr(),
|
|
|
|
| 192 |
p3=self._logits.data_ptr(),
|
| 193 |
p4=final_norm.data_ptr(),
|
| 194 |
p6=self._parts.data_ptr(), n=self.V, k=self.hidden,
|
| 195 |
+
it=_IT_RMSNORM, epi=_EP_F32_AMAX, hkv=1,
|
| 196 |
+
f0=self.eps))
|
| 197 |
names.append("lm_head")
|
| 198 |
rows.append(_row(_OP_ARGMAX_FIN, p1=self._parts.data_ptr(),
|
| 199 |
p3=self._token.data_ptr(),
|
|
|
|
| 286 |
return self._logits, ms
|
| 287 |
|
| 288 |
def prefill(self, ids: Sequence[int], phased: bool = False):
|
| 289 |
+
"""Consume a prompt; returns the last position's logits. Runs in
|
| 290 |
+
chunks of up to chunk_m tokens with weight reads amortized across
|
| 291 |
+
the chunk (bitwise identical to token-by-token consumption)."""
|
| 292 |
+
P = len(ids)
|
| 293 |
+
if phased:
|
| 294 |
+
for i, t in enumerate(ids):
|
| 295 |
+
self.decode_step(int(t), i, phased=True)
|
| 296 |
+
return self._logits
|
| 297 |
+
self._prompt_in[:P].copy_(torch.tensor(ids, dtype=torch.int32))
|
| 298 |
+
ops.mak_run_seq(self._prog, self._bar, 0, P, 1 - P, P, self._maxk,
|
| 299 |
+
self._chunk_m)
|
| 300 |
return self._logits
|
| 301 |
|
| 302 |
def generate(self, prompt_ids: Sequence[int], max_new: int,
|
|
|
|
| 317 |
self._prompt_in[:P].copy_(
|
| 318 |
torch.tensor(prompt_ids, dtype=torch.int32))
|
| 319 |
ops.mak_run_seq(self._prog, self._bar, 0, P + max_new - 1,
|
| 320 |
+
1 - P, P, self._maxk, self._chunk_m)
|
| 321 |
return self._tokens_out[:max_new].cpu().tolist()
|
| 322 |
pos = 0
|
| 323 |
for t in prompt_ids[:-1]:
|
torch-ext/torch_binding.cpp
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
#include <torch/library.h>
|
| 2 |
|
| 3 |
#include <ATen/cuda/CUDAContext.h>
|
| 4 |
#include <c10/cuda/CUDAGuard.h>
|
|
@@ -24,9 +24,11 @@ void check_barrier(const at::Tensor& barrier) {
|
|
| 24 |
"barrier must be a CUDA int32 tensor with >= 2 elements");
|
| 25 |
}
|
| 26 |
|
| 27 |
-
int smem_for(int64_t
|
| 28 |
-
|
| 29 |
-
|
|
|
|
|
|
|
| 30 |
}
|
| 31 |
|
| 32 |
} // namespace
|
|
@@ -46,7 +48,7 @@ void mak_run(at::Tensor prog, at::Tensor barrier, int64_t pos,
|
|
| 46 |
const int smem = smem_for(max_k);
|
| 47 |
const cudaError_t err = mak_launch_mega(
|
| 48 |
reinterpret_cast<const long long*>(prog.data_ptr<int64_t>()),
|
| 49 |
-
(int)prog.size(0), (int)pos, 1, (int)step_slot, 0, bar, bar + 1,
|
| 50 |
mak_grid_blocks_impl(smem), smem, stream.stream());
|
| 51 |
TORCH_CHECK(err == cudaSuccess, "mak_run launch failed: ",
|
| 52 |
cudaGetErrorString(err));
|
|
@@ -66,8 +68,8 @@ void mak_run_steps(at::Tensor prog, at::Tensor barrier, int64_t pos0,
|
|
| 66 |
const int grid = mak_grid_blocks_impl(smem);
|
| 67 |
for (int64_t i = 0; i < steps; ++i) {
|
| 68 |
const cudaError_t err =
|
| 69 |
-
mak_launch_mega(pp, n, (int)(pos0 + i), 1, (int)(slot0 + i), 0,
|
| 70 |
-
bar + 1, grid, smem, stream.stream());
|
| 71 |
TORCH_CHECK(err == cudaSuccess, "mak_run_steps launch failed: ",
|
| 72 |
cudaGetErrorString(err));
|
| 73 |
}
|
|
@@ -75,18 +77,20 @@ void mak_run_steps(at::Tensor prog, at::Tensor barrier, int64_t pos0,
|
|
| 75 |
|
| 76 |
void mak_run_seq(at::Tensor prog, at::Tensor barrier, int64_t pos0,
|
| 77 |
int64_t steps, int64_t slot0, int64_t prompt_len,
|
| 78 |
-
int64_t max_k) {
|
| 79 |
check_prog(prog);
|
| 80 |
check_barrier(barrier);
|
| 81 |
TORCH_CHECK(steps >= 1, "steps must be >= 1");
|
|
|
|
| 82 |
const c10::cuda::CUDAGuard guard(prog.device());
|
| 83 |
auto stream = at::cuda::getCurrentCUDAStream();
|
| 84 |
int* bar = barrier.data_ptr<int>();
|
| 85 |
-
const int smem = smem_for(max_k);
|
| 86 |
const cudaError_t err = mak_launch_mega(
|
| 87 |
reinterpret_cast<const long long*>(prog.data_ptr<int64_t>()),
|
| 88 |
(int)prog.size(0), (int)pos0, (int)steps, (int)slot0, (int)prompt_len,
|
| 89 |
-
bar, bar + 1, mak_grid_blocks_impl(smem), smem,
|
|
|
|
| 90 |
TORCH_CHECK(err == cudaSuccess, "mak_run_seq launch failed: ",
|
| 91 |
cudaGetErrorString(err));
|
| 92 |
}
|
|
@@ -136,7 +140,7 @@ TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, ops) {
|
|
| 136 |
ops.def("mak_run_steps(Tensor prog, Tensor barrier, int pos0, int steps, "
|
| 137 |
"int slot0, int max_k) -> ()");
|
| 138 |
ops.def("mak_run_seq(Tensor prog, Tensor barrier, int pos0, int steps, "
|
| 139 |
-
"int slot0, int prompt_len, int max_k) -> ()");
|
| 140 |
ops.def("mak_run_phased(Tensor prog, int pos, int step_slot, bool timed, "
|
| 141 |
"int max_k) -> Tensor");
|
| 142 |
ops.def("mak_num_blocks(Tensor prog, int max_k) -> int");
|
|
@@ -151,3 +155,4 @@ TORCH_LIBRARY_EXPAND(TORCH_EXTENSION_NAME, ops) {
|
|
| 151 |
}
|
| 152 |
|
| 153 |
REGISTER_EXTENSION(TORCH_EXTENSION_NAME)
|
|
|
|
|
|
| 1 |
+
#include <torch/library.h>
|
| 2 |
|
| 3 |
#include <ATen/cuda/CUDAContext.h>
|
| 4 |
#include <c10/cuda/CUDAGuard.h>
|
|
|
|
| 24 |
"barrier must be a CUDA int32 tensor with >= 2 elements");
|
| 25 |
}
|
| 26 |
|
| 27 |
+
int smem_for(int64_t stage_elems) {
|
| 28 |
+
// bf16 staging must fit the default 48KB dynamic shared memory window
|
| 29 |
+
TORCH_CHECK(stage_elems > 0 && stage_elems <= 24576,
|
| 30 |
+
"staging size out of range");
|
| 31 |
+
return (int)(stage_elems * 2);
|
| 32 |
}
|
| 33 |
|
| 34 |
} // namespace
|
|
|
|
| 48 |
const int smem = smem_for(max_k);
|
| 49 |
const cudaError_t err = mak_launch_mega(
|
| 50 |
reinterpret_cast<const long long*>(prog.data_ptr<int64_t>()),
|
| 51 |
+
(int)prog.size(0), (int)pos, 1, (int)step_slot, 0, 1, bar, bar + 1,
|
| 52 |
mak_grid_blocks_impl(smem), smem, stream.stream());
|
| 53 |
TORCH_CHECK(err == cudaSuccess, "mak_run launch failed: ",
|
| 54 |
cudaGetErrorString(err));
|
|
|
|
| 68 |
const int grid = mak_grid_blocks_impl(smem);
|
| 69 |
for (int64_t i = 0; i < steps; ++i) {
|
| 70 |
const cudaError_t err =
|
| 71 |
+
mak_launch_mega(pp, n, (int)(pos0 + i), 1, (int)(slot0 + i), 0, 1,
|
| 72 |
+
bar, bar + 1, grid, smem, stream.stream());
|
| 73 |
TORCH_CHECK(err == cudaSuccess, "mak_run_steps launch failed: ",
|
| 74 |
cudaGetErrorString(err));
|
| 75 |
}
|
|
|
|
| 77 |
|
| 78 |
void mak_run_seq(at::Tensor prog, at::Tensor barrier, int64_t pos0,
|
| 79 |
int64_t steps, int64_t slot0, int64_t prompt_len,
|
| 80 |
+
int64_t max_k, int64_t chunk_m) {
|
| 81 |
check_prog(prog);
|
| 82 |
check_barrier(barrier);
|
| 83 |
TORCH_CHECK(steps >= 1, "steps must be >= 1");
|
| 84 |
+
TORCH_CHECK(chunk_m >= 1 && chunk_m <= 8, "chunk_m must be in [1, 8]");
|
| 85 |
const c10::cuda::CUDAGuard guard(prog.device());
|
| 86 |
auto stream = at::cuda::getCurrentCUDAStream();
|
| 87 |
int* bar = barrier.data_ptr<int>();
|
| 88 |
+
const int smem = smem_for(max_k * chunk_m);
|
| 89 |
const cudaError_t err = mak_launch_mega(
|
| 90 |
reinterpret_cast<const long long*>(prog.data_ptr<int64_t>()),
|
| 91 |
(int)prog.size(0), (int)pos0, (int)steps, (int)slot0, (int)prompt_len,
|
| 92 |
+
(int)chunk_m, bar, bar + 1, mak_grid_blocks_impl(smem), smem,
|
| 93 |
+
stream.stream());
|
| 94 |
TORCH_CHECK(err == cudaSuccess, "mak_run_seq launch failed: ",
|
| 95 |
cudaGetErrorString(err));
|
| 96 |
}
|
|
|
|
| 140 |
ops.def("mak_run_steps(Tensor prog, Tensor barrier, int pos0, int steps, "
|
| 141 |
"int slot0, int max_k) -> ()");
|
| 142 |
ops.def("mak_run_seq(Tensor prog, Tensor barrier, int pos0, int steps, "
|
| 143 |
+
"int slot0, int prompt_len, int max_k, int chunk_m) -> ()");
|
| 144 |
ops.def("mak_run_phased(Tensor prog, int pos, int step_slot, bool timed, "
|
| 145 |
"int max_k) -> Tensor");
|
| 146 |
ops.def("mak_num_blocks(Tensor prog, int max_k) -> int");
|
|
|
|
| 155 |
}
|
| 156 |
|
| 157 |
REGISTER_EXTENSION(TORCH_EXTENSION_NAME)
|
| 158 |
+
|
torch-ext/torch_binding.h
CHANGED
|
@@ -10,7 +10,7 @@ void mak_run_steps(at::Tensor prog, at::Tensor barrier, int64_t pos0,
|
|
| 10 |
|
| 11 |
void mak_run_seq(at::Tensor prog, at::Tensor barrier, int64_t pos0,
|
| 12 |
int64_t steps, int64_t slot0, int64_t prompt_len,
|
| 13 |
-
int64_t max_k);
|
| 14 |
|
| 15 |
at::Tensor mak_run_phased(at::Tensor prog, int64_t pos, int64_t step_slot,
|
| 16 |
bool timed, int64_t max_k);
|
|
|
|
| 10 |
|
| 11 |
void mak_run_seq(at::Tensor prog, at::Tensor barrier, int64_t pos0,
|
| 12 |
int64_t steps, int64_t slot0, int64_t prompt_len,
|
| 13 |
+
int64_t max_k, int64_t chunk_m);
|
| 14 |
|
| 15 |
at::Tensor mak_run_phased(at::Tensor prog, int64_t pos, int64_t step_slot,
|
| 16 |
bool timed, int64_t max_k);
|