← All posts

Is the 170 MiB of shared memory at 704K a spill? No: it matches a host-side attention mask buffer to the MiB, and the first real spill starts at 720K

Every 4B run at 704K showed 170 MiB of shared (system) GPU memory, against 146 at 512K, and I could not say whether that was the model overflowing the 10 GB card. I loaded the server at 11 context sizes and 3 ubatch sizes and read per-process memory counters. Shared memory sat at 82 MiB plus exactly context x ubatch x 2 bytes at every point up to 704K, which is the size of a half-precision attention mask held in host memory. At 720K it jumped 120 MiB past that, the first real overflow.

ExperimentE21Q
Date2026-10-29
BenchmarkMemory measurement only, no accuracy test. llama-server loaded at each setting, then per-process Dedicated and Shared Usage read from the Windows GPU Process Memory counters (max of 5 samples), plus nvidia-smi, before and after a short 2K-token prompt.
ModelQwen3.5-4B, Q4_K_M GGUF, K and V cache at q4_0, flash attention on, YaRN context extension above 256K
HardwareOne of my dedicated test rigs: RTX 3080 10 GB
VerdictBASELINE

What I tested

Context 4K, 256K, 384K, 512K, 576K, 640K, 672K, 704K, 720K at ubatch 64, plus 704K at ubatch 32 and 16, and a 704K repeat. llama.cpp built with upstream PR 29827.

Pass bar, set before the run

None (supporting measurement). Reading rule set before the run: shared flat until dedicated memory nears 10 GB and then stepping up means spill; a constant amount at every size means overhead.

Result

ContextUbatchShared (measured)82 + ctx x ub x 2 bytesDedicatednvidia-smi used
4K6482 MiB82 MiB2,969 MiB3,396 MiB
256K64114 MiB114 MiB5,315 MiB5,742 MiB
384K64130 MiB130 MiB6,484 MiB6,910 MiB
512K64146 MiB146 MiB7,652 MiB8,078 MiB
576K64154 MiB154 MiB8,236 MiB8,662 MiB
640K64162 MiB162 MiB8,820 MiB9,246 MiB
672K64166 MiB166 MiB9,112 MiB9,538 MiB
704K64170 MiB (repeat 170)170 MiB9,404 MiB9,830 MiB
704K32124 MiB126 MiB9,358 MiB9,784 MiB
704K16102 MiB104 MiB9,333 MiB9,760 MiB
720K64292 MiB172 MiB9,430 MiB9,856 MiB

The ctx x ub x 2 bytes term is the size of a half-precision attention mask for one ubatch. That attribution comes from the exact size match; I did not capture llama.cpp's buffer-size log lines in this run, so it is not yet confirmed from the allocator itself.

The 82 MiB floor at 4K is not yet attributed.

A 2K-token prompt did not change shared memory at any point.

Reading: the earlier 704K runs (E21h, E21o, E21p) had no VRAM overflow. Their 170 MiB is the fixed floor plus an 88 MiB host buffer. 720K is the first point that actually overflows.

Smaller ubatch shrinks this buffer (ubatch 16 at 704K: 102 MiB), which may let a slightly larger context stay resident. E21r tests that next.

What happened

Shared memory grew smoothly with context from the smallest size, long before the card was full, so it was not overflow in the usual sense. The extra amount over the 4K level matched context times ubatch times 2 bytes at every setting, to within 2 MiB, and it scaled with ubatch exactly as that formula says. Dedicated memory at 704K was 9,404 MiB. One step further, at 720K, shared memory jumped by 120 MiB more than the formula predicts, which is the real spill point for this build and settings. The memory saving that makes these sizes fit is upstream llama.cpp PR 29827, so credit goes to its authors.

How to rerun

powershell -ExecutionPolicy Bypass -File e21q_chain.ps1

Code

All code for E21Q: e21q_chain.ps1, results.jsonl.

Prior work

No novelty claim. This is a memory accounting measurement of standard llama.cpp behavior.

Written by Andrew Rose with help from AI tools. Every number comes from the run logs.

Questions or ideas? me@andrewroseit.com or @AndrewRoseIT.