Back to the example's page

q8_matvec

The q8_matvec kernel, as the compiler built it for sm_75 at commit 5a313cd: BLK = 32, TILE_N = 64, K = 256, KB = 8, N = 128; a grid of 2 CTAs, 256 threads each.

// Q8_0 matvec: a decode-step projection that reads the weights quantized.
//
// Q8_0 stores signed bytes with one scale per block of 32 values along the
// contraction axis. Reading the bytes directly moves a quarter of the data
// an f32 copy would.
//
// The scale factors out of a block's dot product, so it is applied once per
// block and column, not once per weight.
@autotune(TILE_N in [64], BLK in [32])
@launch(256)
kernel q8_matvec(A: tensor<f32>[1, K],
W: tensor<i8>[K, N],
S: tensor<f32>[KB, N],
C: tensor<f32>[1, N]) {
let pn = ctx.block.x
var acc: tile<f32>[1, TILE_N] = 0.0
for k in range(0, K, BLK) {
let b = k / BLK
let a = A[0 :+ 1, k :+ BLK]
let w = W[k :+ BLK, pn * TILE_N :+ TILE_N]
let s = S[b :+ 1, pn * TILE_N :+ TILE_N]
var wf: tile<f32>[BLK, TILE_N] = f32(w)
var part: tile<f32>[1, TILE_N] = dot(a, wf)
acc += part * s
}
C[0 :+ 1, pn * TILE_N :+ TILE_N] = acc
}

phobos-lang/examples/q8_matvec.ph

The q8_matvec kernel, stepped through as the compiler built it for sm_75A 2 grid of CTAs with 256 threads each. The drawing shows the tensors A, W, S, C in global memory with the picked CTA's current boxes, shared memory as a byte ruler of 10880 bytes with each buffer at its planned offset, the barriers kept and elided, and how the CTA's threads and warp 0's lanes take part. The readout below describes each step.

CTA 0
  • global memory
  • shared memory
  • threads and lanes
  • extra 128-byte lines, masked elements

Keys: left and right arrows step, space plays and pauses; play runs on from the last step to the first. The address of this page keeps the step, the CTA and the zoom.