Skip to content

measure(ENG-EXPERT-STREAM-DEVICE): W0e ran, the CPU arm has a live-cache number and the CUDA arm loads without generating (#1124, #1299) - #1301

Closed
localai-bot wants to merge 3 commits into
row/ENG-EXPERT-STREAM-DEVICE-W0from
row/ENG-EXPERT-STREAM-DEVICE-W0E
Closed

measure(ENG-EXPERT-STREAM-DEVICE): W0e ran, the CPU arm has a live-cache number and the CUDA arm loads without generating (#1124, #1299)#1301
localai-bot wants to merge 3 commits into
row/ENG-EXPERT-STREAM-DEVICE-W0from
row/ENG-EXPERT-STREAM-DEVICE-W0E

Conversation

@localai-bot

Copy link
Copy Markdown
Collaborator

W0a and W0e both ran on dgx:gpu0 inside one rc hold, on the head of #1242.
Two of the three things this row wanted arrived and the third did not, so this
change records all three and claims only what was measured.

W0 works where it was aimed. --device cuda on Qwen3.8-2.4T-A95B UD-Q1_0
loads in 255-272 s instead of refusing, the [expert-stream] ON banner prints
on the device arm, and that banner is the first production evidence that W0b's
CUDA leg is reached and answers true on real hardware rather than on the fake
platform its unit gate registers.

The CUDA arm then exhausts the box inside its first forward and emits no token,
seven attempts, every one the same. That is filed as #1299 and it is not the
expert lane: a 64-slot 0.15 GiB arena dies exactly where an 8000-slot 18.55 GiB
one does, and a 1-token prompt, whose protected set fits the arena with no
in-place tower fallback at all, behaves exactly like a 5-token one. The growth
is RssAnon while RssFile stays flat, so the GPU is not pinning the mapping's
pages either, which was the first hypothesis and is refuted. Host anon plus swap
reaches ~65 GB while the system reports ~119 GiB used, and the ~42 GiB
difference is device memory this unified part does not charge to process RSS.
The non-expert weights are resident twice, and about 50 GiB of that is the bf16
expansion the GDN V-head reorder already forced on attn_qkv and ssm_out.
expert-streaming.md predicted this in prose: "Whoever takes this needs BOTH".
W0 delivered the expert half.

The CPU arm is measured, reproduced, and replaces the figure BENCHMARKS.md
carried as VOID from #912 F1: 11.05 s/token steady over 29 samples, two reps,
with steps=32 and a decode-phase exhausted delta of 0 in the same run, which
is the pairing #912 F1 lacked. Four runs across two slot counts produced
byte-identical token ids. The 8000-slot pair came out 3.6x SLOWER than the
4000-slot pair, which is the wrong direction for a bigger cache, and the swap
column says why: an 18.55 GiB arena does not fit beside 62 GiB of dense weights
on this box, so those runs swapped and one consumed all 30 GiB of swap. That is
a memory result wearing a cache result's clothes, and it is recorded as such.

G0-CORRECT has no CUDA side to compare against and says so rather than reporting
the CPU half as a pass. G0-LIVE passes on CPU and is not reached on CUDA.
G0-SPEED reports the CPU number and no ratio.

The harness lands under benchmarks/ beside marlin_moe_standalone.cpp,
unwired from CMake, because one generation had to yield three things no shipped
command gives together: the generated token ids, a per-step arrival timestamp,
and the stream counters at both ends. Its logits processor is a pure observer
that edits nothing, so the argmax is the one the sampler would have taken
anyway, and the prompt is fixed as token ids so both arms are fed identical
bytes with no tokenizer between them.

Stacked on row/ENG-EXPERT-STREAM-DEVICE-W0 (PR #1242), because every claim
here is a claim about that branch's code and none of it should land ahead of it.
agent-ready.py is green on all 28 record gates and every mutation suite; its
two commit-gate SKIPs are the stacking itself (origin/main is not an ancestor
of a branch based on #1242's head), and both gates were run explicitly over
95883dcae..HEAD and reported OK: commit trailer contract and OK: commit writing style.

Issues: #1124 (the row), #1299 (filed by this measurement).

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5-1m [claude-code]

…che number and the CUDA arm loads without generating (#1124, #1299)

W0a and W0e both ran on `dgx:gpu0` inside one `rc hold`, on the head of #1242.
Two of the three things this row wanted arrived and the third did not, so this
change records all three and claims only what was measured.

W0 works where it was aimed. `--device cuda` on `Qwen3.8-2.4T-A95B UD-Q1_0`
loads in 255-272 s instead of refusing, the `[expert-stream] ON` banner prints
on the device arm, and that banner is the first production evidence that W0b's
CUDA leg is reached and answers true on real hardware rather than on the fake
platform its unit gate registers.

The CUDA arm then exhausts the box inside its first forward and emits no token,
seven attempts, every one the same. That is filed as #1299 and it is not the
expert lane: a 64-slot 0.15 GiB arena dies exactly where an 8000-slot 18.55 GiB
one does, and a 1-token prompt, whose protected set fits the arena with no
in-place tower fallback at all, behaves exactly like a 5-token one. The growth
is `RssAnon` while `RssFile` stays flat, so the GPU is not pinning the mapping's
pages either, which was the first hypothesis and is refuted. Host anon plus swap
reaches ~65 GB while the system reports ~119 GiB used, and the ~42 GiB
difference is device memory this unified part does not charge to process RSS.
The non-expert weights are resident twice, and about 50 GiB of that is the bf16
expansion the GDN V-head reorder already forced on `attn_qkv` and `ssm_out`.
`expert-streaming.md` predicted this in prose: "Whoever takes this needs BOTH".
W0 delivered the expert half.

The CPU arm is measured, reproduced, and replaces the figure `BENCHMARKS.md`
carried as VOID from #912 F1: 11.05 s/token steady over 29 samples, two reps,
with `steps=32` and a decode-phase `exhausted` delta of 0 in the same run, which
is the pairing #912 F1 lacked. Four runs across two slot counts produced
byte-identical token ids. The 8000-slot pair came out 3.6x SLOWER than the
4000-slot pair, which is the wrong direction for a bigger cache, and the swap
column says why: an 18.55 GiB arena does not fit beside 62 GiB of dense weights
on this box, so those runs swapped and one consumed all 30 GiB of swap. That is
a memory result wearing a cache result's clothes, and it is recorded as such.

G0-CORRECT has no CUDA side to compare against and says so rather than reporting
the CPU half as a pass. G0-LIVE passes on CPU and is not reached on CUDA.
G0-SPEED reports the CPU number and no ratio.

The harness lands under `benchmarks/` beside `marlin_moe_standalone.cpp`,
unwired from CMake, because one generation had to yield three things no shipped
command gives together: the generated token ids, a per-step arrival timestamp,
and the stream counters at both ends. Its logits processor is a pure observer
that edits nothing, so the argmax is the one the sampler would have taken
anyway, and the prompt is fixed as token ids so both arms are fed identical
bytes with no tokenizer between them.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5-1m [claude-code]
mudler added 2 commits August 19, 2026 16:49
The base branch gained the architecture-term repair and eleven unrelated
benchmark sections from main; this branch carries the W0e measurement. Every
conflict is a record, and each is resolved by key rather than by an automatic
three-way merge: the benchmark log unions two disjoint section sets, the two
keyed table rows take this branch's newer state of the same key with the W0a
probe fact folded in, the spec keeps the base's architecture-term paragraph and
full W0a bullet and then this branch's W0e result, and the usage page keeps the
base's family-restriction bullet while this branch's measured bullet supersedes
its "no speed claim" placeholder.

Verified after resolution: each file differs from the base-branch version in
exactly one hunk, so no unrelated key moved.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…piled

`benchmarks/expert_stream_device_w0e.cpp` landed in no CMakeLists, so nothing
in the project built the instrument that produced this row's only numbers.
Adding the `expert-stream-device-w0e` target showed the file does not compile
under the project's flags at all: three backslash continuations inside `//`
comments, which `-Werror=comment` rejects. The recorded manual `g++ -O2` recipe
carries no `-Werror`, so that recipe was the only thing that had ever built it,
and the file would have rotted against the very C ABI it measures without
anyone noticing.

The target links `vllm::shared`, not `vllm::vllm`, so the harness stays a pure
client of `include/vllm.h`; `ldd` shows `libvllm.so.0` and nothing internal.
Build rc 0, 0 errors, 0 ENOSPC, and the binary runs and parses its own flags.
The header comment's now-false "NOT WIRED INTO CMAKE" paragraph and the spec's
harness section both record what happened rather than only the end state.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
@localai-bot

Copy link
Copy Markdown
Collaborator Author

Replaced by #1414.

#1377 landed as a squash (5f4eb356e), which destroyed this branch's merge base. Merging main into row/ENG-EXPERT-STREAM-DEVICE-W0E produces thirteen conflicts, including src/vllm/entrypoints/model_loader.cpp, src/vllm/platforms/cuda.cpp and three test files that this measurement does not touch — git sees the branch's pre-squash W0 commits and main's squashed W0 as unrelated content.

#1414 is the same eight-file delta reapplied onto main, which leaves three record conflicts instead of thirteen, each resolved by key: the benchmark log unions two disjoint sections, and the two keyed table rows take this row's newer state while keeping the keep-quant/keep-f16 mechanism #1378 corrected. Every one of main's #1378 repairs was verified to survive in the spec afterwards.

This branch is left in place rather than deleted, since it holds the original review history.

localai-bot added a commit that referenced this pull request Aug 19, 2026
…che number and the CUDA arm loads without generating (#1124, #1299) (#1414)

Replaces #1301, which cannot be merged: #1377 landed as a squash and
destroyed that branch's merge base, so merging `main` into it produced
thirteen conflicts including product files this change does not touch.
This branch is the same eight-file delta rebuilt on `main`.

W0e is the measurement W0b-W0d existed to make possible. It ran on one
`rc
hold` on `dgx:gpu0` against the real 369.97 GiB `Qwen3.8-2.4T-A95B
UD-Q1_0`,
and it split.

The CPU arm is now MEASURED and replaces the VOID #912 F1 figure:
**11.05
s/token steady at 4000 slots**, which is rep 2's median over 29 samples.
Rep 1's
median is 11.22, so the two reproduce within 1.5%. Live cache,
decode-phase
`exhausted` delta 0 over 31 decode steps in the same run.

The 8000-slot arm is slower on every pairing of the two medians, 3.56x
to 4.11x
across the four available pairings and 4.05x pairing rep 1 with rep 1,
and it is
much less steady: the steady window's max/min ratio is 3.99x and 5.87x
against
1.30x and 1.40x at 4000 slots. The cause is NOT that the arena fails to
fit.
18.55 GiB of arena beside 62 GiB of dense weights is 80.55 GiB on a
119.63 GiB
box, and peak RSS barely moves for the 9.27 GiB arena delta, 86.5 to
86.6 GiB.
What moves is `min avail`, 16,347 to 6,941 MiB, which is about the arena
delta,
and peak swap, 6,883 to 30,625 MiB, all of it. The best-supported
reading of
that pattern is page-cache displacement: the borrowed 370 GiB expert
mapping is
served out of whatever memory is free, the arena takes that memory, and
the
reclaim pressure it creates pushes anonymous pages to swap. That is a
reading of
the columns rather than a proven mechanism, because this run sampled no
page-cache size and no major-fault counter. The operational conclusion
holds
either way, and it is the one to act on: more slots is not a free knob,
and the
publishable figure is the 4000-slot one.

The CUDA arm LOADS, which it could not do before this row, and then
generates
nothing: it exhausts the box inside its first forward, 0 steps, 7
attempts. The
slot arena is measurably not the cause, because a 64-slot 0.15 GiB arena
fails
in exactly the place an 8000-slot 18.55 GiB one does. That is #1299, and
it is
the DENSE half of the model rather than the expert lane. No speed claim
is
attached to the CUDA arm and `docs/BENCHMARKS.md` says so.

The harness earns its own paragraph, because it did not build. It landed
in no
CMakeLists, so nothing in the project compiled the instrument that
produced
this row's only numbers. Wiring it as the `expert-stream-device-w0e`
target
showed the file does not compile under the project's flags at all: three
backslash continuations inside `//` comments, which `-Werror=comment`
rejects.
The recorded manual `g++ -O2` recipe carries no `-Werror`, so that
recipe was
the only thing that had ever built it, and it would have rotted against
the
very C ABI it measures with nobody noticing. It now builds, links
`vllm::shared` so it stays a pure `include/vllm.h` client, and `ldd`
shows
`libvllm.so.0` and nothing internal.

A fresh review returned FAIL on the first head, and the second commit
repairs
its six findings. The copy-paste recipe and the `--offload-config`
example in
`docs/USAGE.md` set 4000 slots rather than 8000, so an operator who
copies them
gets the arm the published number was measured on instead of the
39.98-45.40
s/token one; every place that publishes 11.05 now names 4000 beside it;
the
"does not fit" story above is restated as what the columns support; the
spec's
`forced` anchor points at `qwen3_5.cpp:5521` rather than a W4 header
comment 132
lines earlier; and the #1299 row in `.agents/issue-index.md` is appended
at the
end of that append-only file rather than inserted in its middle.

This branch is rebuilt on `main` rather than merged into it. #1377
landed as a
squash, which destroyed this branch's merge base, and merging produced
thirteen
conflicts including product files this change does not touch. Reapplying
the
eight-file delta onto `main` leaves three record conflicts, each
resolved by
key: the benchmark log unions two disjoint sections, and the two keyed
table
rows take this row's newer state while keeping the keep-quant/keep-f16
mechanism #1378 corrected. Verified afterwards that every one of main's
#1378
repairs survives in the spec and that nothing of main's is missing
beyond the
W0e status text this measurement supersedes.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]

---------

Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
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.

2 participants