One Core, 85.3 GFLOPS: How Software Optimization Squeezes Zen 3 Dry

A single-core FP32 matrix multiplication on a modest AMD Zen 3 CPU hit 85.3 GFLOPS — nearly 57 times faster than the naive implementation, and within striking distance of theoretical limits. This wasn't achieved by buying better hardware. It was achieved by 28 rounds of surgical software optimization.

I found this result in a GitHub repo by Lucas Lima Freitag, a developer who systematically pushed an AMD Ryzen 5 5500 to its absolute mathematical ceiling. The benchmark trended on Hacker News, and for good reason: it exposes something quietly dramatic about modern computing. There is an enormous amount of untapped performance sitting idle in the silicon already on your desk.

The Battlefield: Matrix Multiplication

Matrix multiplication is the workhorse operation of modern computing. It's the engine inside neural network training, the calculation behind real-time ray tracing denoisers, the physics simulation in every AAA game, and the recommendation algorithm deciding which product you'll buy next.

In academic terms, it's called GEMM — General Matrix Multiply. In practical terms, it's the single operation you optimize when you want to dominate an entire industry.

The math is deceptively simple: multiply two matrices, store the result in a third. An NxN matrix multiply requires N³ multiply-add operations. The hardware to do it fits in the palm of your hand. The challenge is that the hardware is full of moving parts, and most of them are fighting against each other.

The Hardware: AMD Zen 3

The CPU in question is an AMD Ryzen 5 5500 — a six-core Zen 3 chip clocked at 4.2 GHz. It's not exotic. It's not a server processor. You can buy one on Amazon for roughly $120.

Here's what matters about its microarchitecture:

  • Two FMA (fused multiply-add) execution ports per core
  • AVX2 support with 256-bit wide vector registers (YMM0–YMM15)
  • Each AVX2 register holds eight 32-bit floating-point values
  • Each FMA instruction performs two operations per float (multiply and add)

The math works out like this: 2 ports × 8 floats × 2 ops × 4.2 GHz = 134.4 GFLOPS theoretical peak for a single core. That number is the absolute ceiling — the speed of light for this chip.

Most code doesn't come close. A textbook triple-nested-loop implementation on this hardware manages roughly 1.5 to 3 GFLOPS. The gap between naive and optimal isn't a small inefficiency. It's an order of magnitude.

The Optimization Chain

Freitag didn't tweak one thing and call it a day. He ran 28 distinct models (labeled MX01 through MX28), each layering additional optimization techniques on top of the last. The progression reads like a video game difficulty curve — each step demanding deeper understanding of how the CPU actually works.

Cache Blocking (Tiling)

Modern CPUs have a memory hierarchy: fast but tiny L1 cache (32 KB per core), medium L2 cache (512 KB), and larger L3 cache (16 MB shared). If your working data doesn't fit in L1, you pay a steep latency penalty. If it spills beyond L3, you're waiting for DRAM — which is roughly 200 times slower than L1.

The fix is cache blocking — also called tiling. You break the large matrix into smaller chunks that fit neatly into each level of cache. The Zen 3 L1 data cache holds 32 KB, so block sizes need to be carefully calculated to keep the active tiles resident.

Freitag tested block sizes for all three cache levels. The sweet spot for the BK dimension (inner blocking factor) was 256, which maximized data reuse without overflowing L2.

Register Blocking

Beyond cache, there's the register file. Zen 3 has 16 YMM registers available for AVX2 operations. You can think of registers as the CPU's immediate workspace — faster than any cache, but extremely limited in size.

Register blocking means keeping accumulator rows of the result matrix in registers across multiple iterations of the inner loop, rather than writing them to memory and reloading them. The best configuration used four accumulator rows, which filled 32 YMM registers total and required register spilling — but the reuse of matrix A more than compensated for the cost.

FMA Chaining

Each FMA instruction on Zen 3 has 4 cycles of latency. That means the result isn't available for 4 clock cycles. If you chain dependent instructions, your execution ports sit idle, waiting.

FMA chaining solves this by maintaining multiple independent accumulator chains. With chain4 (the optimal configuration), four independent streams of computation run in parallel, perfectly hiding the 4-cycle latency.

Memory Packing

Matrix B in a GEMM operation is typically accessed with strided memory patterns — jumping across rows rather than reading sequentially. CPUs hate this. Freitag tested several strategies and found B-pack on-the-fly (copying blocks of B into a contiguous buffer) won — it converted strided access into sequential reads without polluting the L3 cache like a full transposition would.

The Mistakes

The optimization journey wasn't just about successes. The failures are equally instructive:

  • Non-temporal stores (_mm256_stream_ps) dropped performance to 1.24 GFLOPS
  • Eight-row register blocking required 64 YMM registers and spilled 48, collapsing to 12.24 GFLOPS
  • Six-chain FMA chaining overextended the register budget and hit 14.26 GFLOPS

The Result: 85.3 GFLOPS

The winning configuration, MX24, combined 4-line register blocking, chain4 FMA chaining, and B-packing with BK=256. It hit 85.3 GFLOPS63.5% of the theoretical peak of 134.4 GFLOPS.

That's over half the speed of light. On a $120 processor.

PixelOracle Analysis

The real story isn't just the 85.3 GFLOPS number — it's the 28-model systematic approach. This wasn't a lucky discovery. It was methodical experimentation across a design space of real techniques, with measurable results at each step. That methodology — test, measure, iterate — is as applicable to software engineering as it is to hardware design. The optimization gap is wider than the hardware gap. A Zen 3 core from 2022, properly fed, competes with significantly newer architectures running unoptimized code.

Why This Matters Beyond Benchmarks

Every neural network layer is a matrix multiply followed by an activation function. When you train a large language model with billions of parameters, you're performing trillions of GEMM operations. The difference between 35 GFLOPS and 85 GFLOPS per core compounds dramatically at scale. Most applications don't use hand-tuned GEMM kernels. They use library defaults, compiler auto-vectorization, or plain Python loops. The gap between what your CPU can do and what your software actually achieves could be 10x.

What I Think

I think we're living through a quiet revolution in how we measure "performance." The conventional wisdom says you buy a faster CPU or upgrade to a GPU. But Freitag's results suggest a different priority: the optimization gap is wider than the hardware gap.

The hardware doesn't care about your intentions. It only responds to your precision.