~/fba-lab/lab/qwen-c/07-gemv

FBALab

Code · architecture · study mode

AboutRoadmapSpeedrun
FBALab

Study mode — no GPU required.

Interactive LLM training & inference lab.

Qwen CAboutContactTermsPrivacyCookiesCommunity

© 2026 FBA Lab

Contact · contact@bubblspace.com · +91 75061 55016

INFERENCE SIMULATION

Qwen3 Pure C — 7 · GEMV, not GEMM

running
◷run_viz.c▸matmul() is really GEMV◎learner⌁07-gemv$no GPU
weights
Load the model
The 4 GB weight file is mapped into memory in milliseconds. No copying — the OS pages in only what inference needs.
run_viz.c · stage 01–02
load
runtime
Run inference
Your prompt flows through 28 layers of attention and computation, one token at a time.
stage 03–04
forward
output
Generate text
The model scores all 151,936 possible next words and picks one. Then repeats.
stage 05–06
1/3
Blocks
Quick summary

The function is named like a general matrix multiply, but during generation it computes matrix × vector — a GEMV, not a GEMM.

Full explanation below the code →

fba-lab — run_viz.c · matmul() is really GEMVexecuting
// W (d,n) @ x (n,) -> xout (d,)$ matmul(s->q, s->xb, w->wq, n=1024, d=2048)xout[2048] = 2048 dot products of length 1024 ✓
Explanation

The comment on line 285 is not an exaggeration: by far the most amount of time is spent inside this little function. Understanding exactly what it computes is the single highest leverage idea in inference.

Read the signature on line 284: W (d,n) @ x (n,) -> xout (d,). W is a matrix with d rows and n columns. x is a vector of length n. The output is a vector of length d. Each output element is one dot product: xout[i] = W[i][0]*x[0] + W[i][1]*x[1] + ... + W[i][n-1]*x[n-1]

That is a GEMV — GEneral Matrix–Vector multiply — not a GEMM (matrix × matrix). The distinction matters enormously for how a GPU behaves, and the reason it is GEMV here is simple: during generation the model processes one token at a time, so the activation is a single vector, never a matrix of many tokens.

The #pragma omp parallel for on line 287 splits the d output rows across CPU cores — each row is an independent dot product, so the outer loop parallelizes cleanly. Same math, one row per core at a time.

Why it matters

GEMV streams the whole weight matrix through the ALUs but touches each weight only once, so it is memory-bandwidth bound — the GPU spends most of its time waiting on VRAM, not computing. This is why single-token decode is slow relative to the hardware's peak FLOPs.

Think about

W is 2048×1024 and x has length 1024. What shape is xout, and how many dot products does one call compute?

// architecture

Live diagram

100%
DECODE — one tokenWd × n@x · n=out · dGEMVmatrix × vectorbandwidth-bound7 GEMVs / layerQ · K · V · O · up · gate · down× 28 layers = 196 / tokenPREFILL / BATCH — many tokensW (d × n)@X (n × T)GEMMmatrix × matrix · compute-bound
← 6 · Generate loop8 · Every op a kernel →
Step 7 of 10Skill: Inference Systems
01Blueprint02Load weights03Buffers04Forward pass05Tokenizer06Generate loop07GEMV, not GEMM08Every op a kernel09Attention & memory10Prefill vs decode