Phase 2, week 9retrospective

Microkernel quality

Microkernel quality shows in unroll and cleanup overhead, load reuse, and instruction mix, not only GFLOP/s.


The loop body is the review

GFLOP/s is one number about a kernel and the least diagnostic one. The K-loop body carries the rest: how many MACs sit between two loads, whether those loads are reused across rows, how many vsetvli instructions appear, and how much code exists outside the loop at all.

Separate the kernel into its own section and pull the body out:

llvm-objdump -d --no-show-raw-insn kernel.elf \
  | sed -n '/<matmul_kernel>:/,/ret/p' > kernel.s
grep -c vfmacc kernel.s
grep -c vle32 kernel.s

Read the ratio rather than the counts. A blocked kernel approaches several MACs per load; parity between vfmacc and vle32 says the tile never reached the loop, whatever the tile parameter claims.

Unroll and cleanup

Unrolling shows as a repeated body with one backward branch, and it changes the branch-per-MAC ratio rather than the load ratio. Cleanup is different: the prologue, the epilogue and the scalar tail for ragged shapes are code that runs on some shapes and not others. Count instructions outside the loop and compare with the ones inside. A kernel with 40 instructions in the loop and 400 outside is a kernel whose small-shape performance is cleanup, and a shape sweep will show it as a step rather than a slope.

Scheduling tools

llvm-mca gives a throughput and a dependency view for a straight-line block, and it is useful for the scalar core. For the vector body, check what your release ships: llvm-mca -march=riscv64 -mcpu=<cpu> --help shows the flags this build takes, and the model is only as good as the scheduling information it carries for that core. Treat the output as a hint about dependency chains, not as a cycle count for RVV code.

Things that break

The loop reloads B every K step because nothing was hoisted, and the load ratio is the only trace: the timing still improves with tile size, so it looks like a tuning problem. The second failure is measuring only shape multiples. No tile-multiple shape executes the cleanup path, so a kernel with a slow tail reports a clean curve and a chip on it.

Sources

A version records the documentation the claim was checked against, not a house pin. Confirm flags with --help on the release you installed.

Check yourself

The inner loop is half loads and half MACs. What does that tell you?

Why report instruction counts next to GFLOP/s on the emulated rig?

A kernel is fast at every tile-multiple shape and falls off just below one. What is the first thing to check?

0 / 3 correct

← back to the map