<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Latent State // Log</title><description>Deep technical essays on machine learning, GPU compute, and Kaggle competitions.</description><link>https://latentstate.dev/</link><language>en</language><item><title>Matrix Multiplication, From Definition to Cache Lines</title><link>https://latentstate.dev/posts/matrix-multiplication/</link><guid isPermaLink="true">https://latentstate.dev/posts/matrix-multiplication/</guid><description>One multiply, three implementations, three orders of magnitude — measured on a Skylake desktop, then explained: cache lines, arithmetic intensity, and the tiling idea every BLAS and every GPU matmul kernel is built on.</description><pubDate>Tue, 28 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Every model I have shipped — every transformer layer, every value head, every
speech encoder — spends most of its FLOPs inside one operation. For
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mo&gt;∈&lt;/mo&gt;&lt;msup&gt;&lt;mi mathvariant=&quot;double-struck&quot;&gt;R&lt;/mi&gt;&lt;mrow&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A \in \R^{m \times k}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;mo&gt;∈&lt;/mo&gt;&lt;msup&gt;&lt;mi mathvariant=&quot;double-struck&quot;&gt;R&lt;/mi&gt;&lt;mrow&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;B \in \R^{k \times n}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt;, the product &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;C = AB&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; is
defined entrywise:&lt;/p&gt;
&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mrow&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;j&lt;/mi&gt;&lt;/mrow&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;munderover&gt;&lt;mo&gt;∑&lt;/mo&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/munderover&gt;&lt;msub&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mrow&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;/msub&gt;&lt;mtext&gt; &lt;/mtext&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;j&lt;/mi&gt;&lt;/mrow&gt;&lt;/msub&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mspace width=&quot;2em&quot;&gt;&lt;/mspace&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;≤&lt;/mo&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mo&gt;≤&lt;/mo&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt; &lt;/mtext&gt;&lt;mtext&gt;  &lt;/mtext&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;≤&lt;/mo&gt;&lt;mi&gt;j&lt;/mi&gt;&lt;mo&gt;≤&lt;/mo&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;c_{ij} = \sum_{p=1}^{k} a_{ip}\, b_{pj},
\qquad 1 \le i \le m,\ \; 1 \le j \le n.&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;That is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;mnk&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; multiply–adds — &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;2mnk&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; floating-point operations — and the
definition translates directly into the first matmul everyone writes. The
definition is three loops. The performance is a memory story, and this post
walks it down to the cache line.&lt;/p&gt;
&lt;h2 id=&quot;three-ways-to-spend-268-million-flops&quot;&gt;Three ways to spend 268 million FLOPs&lt;/h2&gt;
&lt;p&gt;At &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;512&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;m = n = k = 512&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; the product costs &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mo&gt;⋅&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;512&lt;/mn&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;≈&lt;/mo&gt;&lt;mn&gt;2.7&lt;/mn&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;10&lt;/mn&gt;&lt;mn&gt;8&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;2 \cdot 512^3 \approx 2.7 \times 10^8&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt;
FLOPs. Here is the definition, verbatim — this exact function is what the
&lt;a href=&quot;/code/matmul_bench.py&quot;&gt;benchmark script&lt;/a&gt; times:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#59873A;--shiki-dark:#80A665&quot;&gt; matmul_naive&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;A&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; B&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; n&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;    C &lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; [[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F798A;--shiki-dark:#4C9A91&quot;&gt;0.0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; n &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; _ &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; j &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;            acc &lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F798A;--shiki-dark:#4C9A91&quot;&gt; 0.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;            for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;n&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;                acc &lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; A&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; B&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;j&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;            C&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;j&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; acc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; C&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On my desktop this takes &lt;strong&gt;9.3 s&lt;/strong&gt; over Python lists. The obvious
“optimization” — the same three loops over NumPy arrays, indexed one scalar
at a time (&lt;code&gt;A[i, p] * B[p, j]&lt;/code&gt;) — takes &lt;strong&gt;41.9 s&lt;/strong&gt;, 4.5× as long as plain
lists. And &lt;code&gt;A @ B&lt;/code&gt;, which dispatches to OpenBLAS, takes &lt;strong&gt;5.1 ms&lt;/strong&gt; on a
single thread. Same matrices, same 268 million FLOPs, answers identical to
within &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;2.3&lt;/mn&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;10&lt;/mn&gt;&lt;mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;13&lt;/mn&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;2.3 \times 10^{-13}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;figure class=&quot;fig-light&quot;&gt;&lt;a href=&quot;https://latentstate.dev/posts/matrix-multiplication/&quot;&gt;[figure — view on the site]&lt;/a&gt;&lt;figcaption&gt;fig 1 — one multiply, three implementations; note the log scale&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;Two things in that chart deserve an explanation. The scandal — NumPy losing
to plain lists by 4.5× — is the cheap one: every &lt;code&gt;A[i, p]&lt;/code&gt; crosses the C-API
boundary and boxes a fresh Python float object, about 120 ns of overhead per
element access, 268 million times. NumPy’s contract is &lt;em&gt;whole-array&lt;/em&gt;
operations; index it like a list and you pay for the machinery without ever
engaging it.&lt;/p&gt;
&lt;p&gt;The interesting number is the other one: &lt;strong&gt;1800×&lt;/strong&gt; between the honest loops
and &lt;code&gt;A @ B&lt;/code&gt;, with OpenBLAS performing exactly the &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;2mnk&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; FLOPs the
definition demands, in the same double precision. The interpreter accounts
for maybe two orders of magnitude of that — a compiled &lt;code&gt;-O3&lt;/code&gt; version of the
same triple loop typically lands at one or two GFLOP/s on this class of
core. The rest, the factor of thirty-odd that survives compilation, is
&lt;em&gt;memory&lt;/em&gt;.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;Benchmark environment&lt;/summary&gt;
&lt;p&gt;Intel i7-6700K (Skylake, 4 cores / 8 threads, 4.0 GHz base / 4.2 GHz
single-core turbo), caches 32 KB L1d + 256 KB L2 per core, 8 MB shared L3,
dual-channel DDR4. Python 3.11.7, NumPy 2.4.2 linked against scipy-openblas,
float64 throughout. BLAS pinned to one thread with &lt;code&gt;OPENBLAS_NUM_THREADS=1&lt;/code&gt;
except in the multithreaded runs at the end. The two slow loops run once;
every other timing is best-of-5 with a fixed seed. Results cross-checked
against &lt;code&gt;A @ B&lt;/code&gt;: max abs deviation ≈ 2.3 × 10⁻¹³.&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id=&quot;the-64-byte-truth&quot;&gt;The 64-byte truth&lt;/h2&gt;
&lt;p&gt;A CPU never reads one &lt;code&gt;float64&lt;/code&gt; from memory. It reads a &lt;strong&gt;cache line&lt;/strong&gt; — 64
bytes, eight doubles — and keeps it in a hierarchy of caches: on this machine
32 KB of L1d per core, 256 KB of L2, 8 MB of L3 shared by all cores. A load
that hits L1 costs ~4 cycles; a trip to DRAM costs a couple hundred.
Everything about fast numerical code follows from one rule: &lt;em&gt;when you pull a
line, use what is on it — and reuse it before it is evicted.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;NumPy stores matrices row-major (C order): row &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;i&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; is contiguous, and element
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;j&lt;/mi&gt;&lt;/mrow&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;b_{pj}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; lives 8 bytes after &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;j&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;b_{p,j-1}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; but a full row-length after
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;j&lt;/mi&gt;&lt;/mrow&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;b_{p-1,j}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt;. Now look at the inner loop of the definition: it walks
&lt;code&gt;A[i][p]&lt;/code&gt; &lt;em&gt;along&lt;/em&gt; a row — sequential, eight useful doubles per fetched line,
a pattern the hardware prefetcher recognizes and runs ahead of — and
&lt;code&gt;B[p][j]&lt;/code&gt; &lt;em&gt;down&lt;/em&gt; a column, jumping 4 KB per step. Every step of that walk
opens a different cache line and a different memory page; one pass down a
column touches 512 lines (32 KB of traffic for 4 KB of useful data), and the
prefetcher sees nothing it can work with.&lt;/p&gt;
&lt;p&gt;The effect is easy to isolate without any matmul. Take one 8192×8192 matrix
— 537 MB, far bigger than any cache — and sum it twice, once walking rows,
once walking columns:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;M &lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; rng&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;standard_normal&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F798A;--shiki-dark:#4C9A91&quot;&gt;8192&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F798A;--shiki-dark:#4C9A91&quot;&gt; 8192&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;s &lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F798A;--shiki-dark:#4C9A91&quot;&gt; 0.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F798A;--shiki-dark:#4C9A91&quot;&gt;8192&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;):&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; s &lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; M&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; :].&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;sum&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt;   # along rows:    44 ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;s &lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F798A;--shiki-dark:#4C9A91&quot;&gt; 0.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; j &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F798A;--shiki-dark:#4C9A91&quot;&gt;8192&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;):&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; s &lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; M&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;[:,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; j&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;].&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;sum&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt;   # down columns: 597 ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Same bytes, same additions, &lt;strong&gt;13.6× apart&lt;/strong&gt;. The row pass streams whole
cache lines behind the prefetcher. The column pass uses one double per line
it opens on that pass, and its 64 KB stride touches 8192 distinct memory
pages per column — far beyond what the TLB can hold, so accesses pay for
page walks on top of cache misses. (Neighbouring columns do salvage the
other seven doubles of each line from L3 later — which is why the penalty
is 13.6× and not worse.) The row pass moves 537 MB in 44 ms — about
&lt;strong&gt;12.2 GB/s&lt;/strong&gt;, this core’s practical read bandwidth. Keep that number.&lt;/p&gt;
&lt;h2 id=&quot;arithmetic-intensity-or-why-the-naive-loop-cannot-be-fast&quot;&gt;Arithmetic intensity, or why the naive loop cannot be fast&lt;/h2&gt;
&lt;p&gt;A core is bounded by two ceilings: how fast it computes and how fast it is
fed. This one, at 4.2 GHz with two 256-bit FMA ports, peaks at&lt;/p&gt;
&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;4.2&lt;/mn&gt;&lt;mtext&gt; GHz&lt;/mtext&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mtext&gt; &lt;/mtext&gt;&lt;mstyle scriptlevel=&quot;0&quot; displaystyle=&quot;false&quot;&gt;&lt;mfrac&gt;&lt;mtext&gt;FMA&lt;/mtext&gt;&lt;mtext&gt;cycle&lt;/mtext&gt;&lt;/mfrac&gt;&lt;/mstyle&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mn&gt;4&lt;/mn&gt;&lt;mtext&gt; &lt;/mtext&gt;&lt;mstyle scriptlevel=&quot;0&quot; displaystyle=&quot;false&quot;&gt;&lt;mfrac&gt;&lt;mtext&gt;doubles&lt;/mtext&gt;&lt;mtext&gt;FMA&lt;/mtext&gt;&lt;/mfrac&gt;&lt;/mstyle&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mtext&gt; &lt;/mtext&gt;&lt;mstyle scriptlevel=&quot;0&quot; displaystyle=&quot;false&quot;&gt;&lt;mfrac&gt;&lt;mtext&gt;FLOP&lt;/mtext&gt;&lt;mtext&gt;double&lt;/mtext&gt;&lt;/mfrac&gt;&lt;/mstyle&gt;&lt;mtext&gt;  &lt;/mtext&gt;&lt;mo&gt;≈&lt;/mo&gt;&lt;mtext&gt;  &lt;/mtext&gt;&lt;mn&gt;67&lt;/mn&gt;&lt;mtext&gt; &lt;/mtext&gt;&lt;mstyle scriptlevel=&quot;0&quot; displaystyle=&quot;false&quot;&gt;&lt;mfrac&gt;&lt;mtext&gt;GFLOP&lt;/mtext&gt;&lt;mtext&gt;s&lt;/mtext&gt;&lt;/mfrac&gt;&lt;/mstyle&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;4.2\ \text{GHz} \times 2\ \tfrac{\text{FMA}}{\text{cycle}} \times 4\ \tfrac{\text{doubles}}{\text{FMA}} \times 2\ \tfrac{\text{FLOP}}{\text{double}}
\;\approx\; 67\ \tfrac{\text{GFLOP}}{\text{s}}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;in double precision — but sustains only ~12.2 GB/s of reads. Which ceiling
applies is decided by &lt;strong&gt;arithmetic intensity&lt;/strong&gt;: FLOPs performed per byte
moved.&lt;/p&gt;
&lt;p&gt;The naive loop, run at sizes where the operands have outgrown the caches,
streams both operands through the core once per use — two 8-byte reads per
multiply–add, an intensity of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;q&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mstyle scriptlevel=&quot;0&quot; displaystyle=&quot;false&quot;&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mtext&gt; FLOP&lt;/mtext&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;mn&gt;16&lt;/mn&gt;&lt;mtext&gt; B&lt;/mtext&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;/mstyle&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;0.125&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;q = \tfrac{2\ \text{FLOP}}{16\ \text{B}} =
0.125&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt;. At 12.2 GB/s that caps even a &lt;em&gt;perfectly vectorized&lt;/em&gt; loop with this
access pattern at about &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;0.125&lt;/mn&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mn&gt;12.2&lt;/mn&gt;&lt;mo&gt;≈&lt;/mo&gt;&lt;mn&gt;1.5&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;0.125 \times 12.2 \approx 1.5&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; GFLOP/s — over
forty times below the compute peak, before a single cycle of interpreter
overhead is charged. That is the ceiling compilation cannot lift: the loop
&lt;em&gt;itself&lt;/em&gt; is memory-bound by construction.&lt;/p&gt;
&lt;p&gt;To go fast we do not need fewer FLOPs. We need more FLOPs &lt;strong&gt;per byte&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;blocking-the-m-idea&quot;&gt;Blocking: the √M idea&lt;/h2&gt;
&lt;p&gt;The fix is decades old and still carries every BLAS and every GPU matmul
kernel: &lt;strong&gt;tile the problem so a small working set lives in cache and is
reused before eviction&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Cut the matrices into &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;b \times b&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; tiles and accumulate each tile of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;C&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; as a
sum of little tile products:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes vitesse-light vitesse-dark&quot; style=&quot;--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; i0 &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F798A;--shiki-dark:#4C9A91&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; n&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; b&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; j0 &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F798A;--shiki-dark:#4C9A91&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; n&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; b&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#A0ADA0;--shiki-dark:#758575DD&quot;&gt;        # this C tile is reused across the entire p-loop&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; p0 &lt;/span&gt;&lt;span style=&quot;--shiki-light:#1E754F;--shiki-dark:#4D9375&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#998418;--shiki-dark:#B8A965&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#2F798A;--shiki-dark:#4C9A91&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; n&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; b&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;            C&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;i0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;i0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; j0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;j0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt; +=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; A&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;i0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;i0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; p0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;p0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt; @&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; B&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;p0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;p0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt; j0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;j0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#AB5959;--shiki-dark:#CB7676&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--shiki-light:#393A34;--shiki-dark:#DBD7CAEE&quot;&gt;b&lt;/span&gt;&lt;span style=&quot;--shiki-light:#999999;--shiki-dark:#666666&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One step of the inner loop touches three &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;b \times b&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; tiles —
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;msup&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mn&gt;8&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;3b^2 \times 8&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; bytes — and performs &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;msup&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;2b^3&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; FLOPs on them:&lt;/p&gt;
&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;q&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mtext&gt;  &lt;/mtext&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mtext&gt;  &lt;/mtext&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;msup&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;mn&gt;24&lt;/mn&gt;&lt;mtext&gt; &lt;/mtext&gt;&lt;msup&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;mtext&gt; &lt;/mtext&gt;&lt;mstyle scriptlevel=&quot;0&quot; displaystyle=&quot;false&quot;&gt;&lt;mfrac&gt;&lt;mtext&gt;FLOP&lt;/mtext&gt;&lt;mtext&gt;B&lt;/mtext&gt;&lt;/mfrac&gt;&lt;/mstyle&gt;&lt;mtext&gt;  &lt;/mtext&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mtext&gt;  &lt;/mtext&gt;&lt;mfrac&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mn&gt;12&lt;/mn&gt;&lt;/mfrac&gt;&lt;mtext&gt; &lt;/mtext&gt;&lt;mstyle scriptlevel=&quot;0&quot; displaystyle=&quot;false&quot;&gt;&lt;mfrac&gt;&lt;mtext&gt;FLOP&lt;/mtext&gt;&lt;mtext&gt;B&lt;/mtext&gt;&lt;/mfrac&gt;&lt;/mstyle&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;q(b) \;=\; \frac{2b^3}{24\, b^2}\ \tfrac{\text{FLOP}}{\text{B}} \;=\; \frac{b}{12}\ \tfrac{\text{FLOP}}{\text{B}},&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;an intensity that &lt;em&gt;grows with the tile size&lt;/em&gt;. To lift this core from
memory-bound to compute-bound we need &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;q&lt;/mi&gt;&lt;mo&gt;≳&lt;/mo&gt;&lt;mn&gt;67&lt;/mn&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mn&gt;12.2&lt;/mn&gt;&lt;mo&gt;≈&lt;/mo&gt;&lt;mn&gt;5.5&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;q \gtrsim 67 / 12.2 \approx 5.5&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt;,
i.e. &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;b&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; of about seventy — and three 70×70 float64 tiles occupy 118 KB, a
comfortable fit in the 256 KB L2. That is the entire trick, and it is why
cache capacity &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;M&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; appears under a square root all over this literature:
tiles of side &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mo&gt;∼&lt;/mo&gt;&lt;msqrt&gt;&lt;mrow&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;/mrow&gt;&lt;/msqrt&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;b \sim \sqrt{M/3}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; cut total traffic from the naive
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;script&quot;&gt;O&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msup&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;/msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\mathcal{O}(n^3)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; words down to&lt;/p&gt;
&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;script&quot;&gt;O&lt;/mi&gt;&lt;mtext&gt; ⁣&lt;/mtext&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;(&lt;/mo&gt;&lt;mfrac&gt;&lt;msup&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;/msup&gt;&lt;msqrt&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;/msqrt&gt;&lt;/mfrac&gt;&lt;mo fence=&quot;true&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\mathcal{O}\!\left(\frac{n^3}{\sqrt{M}}\right),&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;which Hong and Kung proved in 1981 is asymptotically optimal for any
schedule of the classical algorithm. Bigger cache, less traffic — by the
square root.&lt;/p&gt;
&lt;h2 id=&quot;what-a-real-blas-adds&quot;&gt;What a real BLAS adds&lt;/h2&gt;
&lt;p&gt;OpenBLAS is this idea executed with obsession: tile sizes tuned per cache
level, operand &lt;em&gt;packing&lt;/em&gt; (each tile is copied into a contiguous aligned
buffer, so even the walk down &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;B&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; becomes sequential line-by-line streaming),
and an innermost register microkernel that pins a small block of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;C&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; in
vector registers while FMAs stream over it. The payoff fits in one chart:&lt;/p&gt;
&lt;figure class=&quot;fig-light&quot;&gt;&lt;a href=&quot;https://latentstate.dev/posts/matrix-multiplication/&quot;&gt;[figure — view on the site]&lt;/a&gt;&lt;figcaption&gt;fig 2 — single-thread A @ B across sizes; the flat line is the entire point&lt;/figcaption&gt;&lt;/figure&gt;

&lt;p&gt;&lt;strong&gt;Flat.&lt;/strong&gt; From &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;256&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;n = 256&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt;, where all three matrices fit in the L3, to
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;4096&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;n = 4096&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt;, where 268 MB of operands (400 MB counting the output) live in
DRAM, throughput holds at 51–54 GFLOP/s — 79% of the theoretical
single-core peak at the largest size — because blocking makes the
FLOP-per-byte ratio a property of the &lt;em&gt;tile&lt;/em&gt;, not of the problem size. The
definitional loop gets slower per FLOP each time the matrices outgrow
another cache level; the blocked loop does not care.&lt;/p&gt;
&lt;p&gt;Two footnotes from the same machine, both measured. First, parallelism:
pinned to the four physical cores, &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;4096&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;n = 4096&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; runs at &lt;strong&gt;179 GFLOP/s&lt;/strong&gt; — a
3.4× speedup, the shortfall from 4× being mostly all-core turbo running
below single-core turbo, plus some sharing of the L3 and DRAM channels.
Left at its default, OpenBLAS spawns eight threads on this machine — one
per &lt;em&gt;hyperthread&lt;/em&gt; — and drops to 118 GFLOP/s: two SMT siblings share one
physical core’s FMA pipes, so the extra threads add scheduling overhead and
no compute. Count physical cores. Second, 79% of peak is where a mature
BLAS lands on this microarchitecture in float64 — the missing fifth goes to
packing traffic, tile edges, and loop bookkeeping. Nobody gets 100%.&lt;/p&gt;
&lt;h2 id=&quot;the-same-idea-all-the-way-up&quot;&gt;The same idea, all the way up&lt;/h2&gt;
&lt;p&gt;Swap “L2” for “shared memory” and this becomes a CUDA lecture: a GPU matmul
kernel stages tiles of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;B&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; in each SM’s shared memory, syncs,
multiplies, advances — the identical &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msqrt&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;/msqrt&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sqrt{M}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;/span&gt; argument, executed by
thousands of threads. Tensor cores move the tile into the datapath itself: a
warp feeds fixed-size fragments and the hardware performs the small dense
product as single instructions. One level higher, an attention layer or an
MLP block is a &lt;em&gt;batch&lt;/em&gt; of these products — which is why arithmetic intensity,
usually rephrased as FLOPs per byte of weights, still decides whether a
transformer is compute-bound or bandwidth-bound on an H100.&lt;/p&gt;
&lt;p&gt;The definition is three loops, essentially unchanged since Binet wrote the
row-by-column rule down in 1812. Everything between 9.3 seconds and 5.1
milliseconds is knowing where your cache lines are.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;Reproduce it&lt;/summary&gt;
&lt;p&gt;&lt;a href=&quot;/code/matmul_bench.py&quot;&gt;&lt;code&gt;matmul_bench.py&lt;/code&gt;&lt;/a&gt; — ~130 lines of
stdlib-plus-NumPy Python: the two slow loops (single runs), the BLAS size
sweep and the traversal demo (best-of-5), and the multithreaded runs, all
with a fixed seed. It times the exact functions shown above. Absolute
numbers will differ on your machine; the ratios will not. Run it before
believing me.&lt;/p&gt;
&lt;/details&gt;</content:encoded></item></channel></rss>