Skip to content

Correct the memory hierarchy: the earlier table measured the thread count, not the part - #32

Merged
AndreSlavescu merged 1 commit into
mainfrom
correct-hierarchy-occupancy
Jul 30, 2026
Merged

Correct the memory hierarchy: the earlier table measured the thread count, not the part#32
AndreSlavescu merged 1 commit into
mainfrom
correct-hierarchy-occupancy

Conversation

@AndreSlavescu

Copy link
Copy Markdown
Owner

The hierarchy constants I added a few commits ago were wrong, and an occupancy probe written to explain
something else is what showed it. That table put the fast level's capacity at 2 MB with a fourfold cliff
past it. There is no cliff at 2 MB.

Every size in it was measured at 64 threadgroups — enough to saturate DRAM at 128 MB, and starving an
8 MB working set by a factor of twelve
:

working set 64 groups 512 groups
8 MB 196 2403
16 MB 160 1910
32 MB 131 447

So the "levels" between 4 and 32 MB were the thread count, not the memory system.

Corrected, sweeping occupancy per size and keeping the best

working set best groups GB/s thread-count effect
4 MB 256 2435 13.1x
8 MB 512 2431 15.7x
16 MB 1024 2453 19.7x
32 MB 1024 1795 15.3x
64 MB 1024 448 3.8x
256 MB 1024 156 1.4x

Capacity moves from 2 MB to at least 16 MB, and the far side becomes a ramp rather than a cliff.

The DRAM constant survives, and that needed checking

The corrected sweep reads 156 GB/s at 256 MB against a recorded STREAMING_READ_GBPS = 120.6. A
constant that low would have reopened every decode conclusion built on it — MLX at ~120 would be at 77% of
the limit, not 100%.

At a 1 GB working set bandwidth converges to 125–131 GB/s whatever the occupancy (256 → 2048
groups). So 120.6 is right for true streaming, and the 156 was partial residency. The constant stands and
the decode roofline conclusions hold.

Residency is necessary, not sufficient

Also recorded: threadgroups needed before a resident set reads at resident speed — 256 at 4 MB rising to
1024 at 16 MB.

With a caveat that matters more than the numbers: not yet shown to be actionable for real kernels. The
affine decode matmul launches N / block_n groups — 35 to 280 at N=8960, an eightfold range straddling
those thresholds — and its configs measure within 3% of each other. Whatever binds that kernel, it isn't
this.

One test changed rather than made to pass

It asserted the drop past resident capacity was at least threefold, which encoded the cliff the corrected
measurement removed — it was testing an artefact of the harness. It now asserts the span and the ordering,
which is what survives. A second test pins that residency alone doesn't deliver resident bandwidth.

687 pass. Lint and vulture clean.

🤖 Generated with Claude Code

…ount, not the part

The hierarchy constants I added a few commits ago were wrong, and an occupancy probe written to explain
something else is what showed it. That table put the fast level's capacity at 2 MB with a fourfold cliff
past it. There is no cliff at 2 MB. Every size in it was measured at 64 threadgroups, which saturates DRAM
at 128 MB and starves an 8 MB working set by a factor of twelve:

    working set    64 groups    512 groups
         8 MB            196          2403
        16 MB            160          1910
        32 MB            131           447

So the "levels" between 4 and 32 MB were the thread count. Measuring each size at several threadgroup
counts and keeping the best moves the capacity from 2 MB to at least 16 MB and turns the far side from a
cliff into a ramp: 2453, 1795, 448, 175, 156 GB/s at 16, 32, 64, 128 and 256 MB. The thread count alone
moves 16 MB by 19.7x, which is why one count cannot serve the sweep.

The DRAM constant survives, and that was worth checking rather than assuming, because the corrected sweep
reads 156 GB/s at 256 MB against a recorded 120.6 and a constant that low would have reopened every decode
conclusion built on it. At a one-gigabyte working set bandwidth converges to 125 to 131 GB/s whatever the
occupancy, so 120.6 is right for true streaming and the 156 was partial residency. STREAMING_READ_GBPS
stands.

Also recorded, with a caveat that matters more than the numbers: how many threadgroups a resident working
set needs before it reads at resident speed, 256 at 4 MB rising to 1024 at 16 MB. Residency is necessary
and not sufficient. It is not yet shown to be actionable for real kernels -- the affine decode matmul
launches 35 to 280 groups depending on block_n, an eightfold range straddling those thresholds, and its
configs measure within 3% of each other, so whatever binds that kernel it is not this.

One test changed rather than being made to pass. It asserted the drop past the resident capacity was at
least threefold, which encoded the cliff the corrected measurement removed, so it was testing an artefact
of the harness. It now asserts the span and the ordering, which is what survives. A second test pins that
residency alone does not deliver resident bandwidth.

687 pass. Lint and vulture clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@AndreSlavescu
AndreSlavescu merged commit 5fc3e07 into main Jul 30, 2026
2 checks passed
@AndreSlavescu
AndreSlavescu deleted the correct-hierarchy-occupancy branch July 30, 2026 20:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant