Repository navigation
arena: pin by need (STRATA_PIN_BY_NEED=1) and a PCIe share floor (STRATA_PCIE_MIN1=1), +5-7 % prompt read on Windows - #1905
Closed
RubenTorney wants to merge 1 commit into
Closed
RubenTorney wants to merge 1 commit into
RubenTorney wants to merge 1 commit into
Conversation
…TRATA_PCIE_MIN1, opt-in) On Windows cudaHostRegister of the whole arena fails (the WDDM shared budget is about half the RAM) and the sliced fallback registers the first ~30 GiB: with Qwen3.8-Flash-Next IQ3_S layers 0-31, so layers 32-47 never get a PCIe share, while part of the registered prefix holds GPU-resident experts that DMA never reads. STRATA_PIN_BY_NEED=1 (the arena on one GPU): - every blob gets a page-aligned stride (PadMap in pinned.hpp, ArenaExpertSource::arena_off, +0.15 % RAM), so any set of blobs can be registered exactly; the loaders place each blob at its padded offset - the expert profile's pairs past the estimated GPU-resident count are merged into ranges by rank and registered before any page is touched, up to STRATA_ARENA_PIN_GIB (29 GiB by default on Windows) or the first refusal - pinned() / device_alias() / pcie_layer() work on the ranges (a blob is pinned only if wholly inside one); lock_resident_ranges() keeps the holes between them resident - one start-up line: "pin by need: N ranges, X GiB pinned, Y % of the non-resident experts" STRATA_PCIE_MIN1=1: the PCIe share (nmiss * pcie_num) >> 8 rounds to 0 at 1-2 misses per layer; with two or more misses one goes over PCIe (when its blob is pinned). RTX 3090 + Ryzen 5 5600X: 28.96 GiB registered = 92 % of the non-resident experts, all 48 layers with a PCIe share; prompt read +5-7 % at 56K-117K tokens, decode level alone and +2-3 % with --adapt-async 1 and --pcie-frac 0.6 (bench/results/2026-10-11-community-rtx3090-5600x-arena-pin-by-need, docs/DETAILS.md). Both opt-in; without them the layout, the loaders and the sliced pin are those of v0.1.42. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015oFHMEgBzk7kQSqUVWoc67
Niko1221
added a commit
that referenced
this pull request
Oct 13, 2026
…1905 pin by need, as opt-ins) into f-144-rel
Niko1221
added a commit
that referenced
this pull request
Oct 13, 2026
Owner
|
Thanks, this is a good diagnosis of the WDDM budget problem (prefix pinning that spends the budget on layers whose experts the GPU already holds). We ported it to the 0.1.44 branch with your authorship kept, as an opt-in, with a few changes of ours (separate commits):
|
fragtion
added a commit
to fragtion/StrataPool
that referenced
this pull request
Oct 13, 2026
Upstream 0.1.44: Apple Silicon (Metal), Qwen3.6 family, NVFP4 experts, K-quant pool rows (libstrata_kq), an image generation tab, prefill head alias, pin by need (Niko1221#1905) and --adapt-async in the arena (Niko1221#1904, which we carried: upstream's copy kept, ours dropped). Conflicts: - Niko1221#1822 (gate/up MMQ reading experts in place, -0.7% read time) dropped: it patched llama.cpp's mmq.cuh and does not combine with NVFP4's tails and w4a4 activations. moe_mmq.{hpp,cu} and the group gather in prefill.cpp are upstream's. - Niko1221#1368 kept: quantize_scatter for q8_1 activations, the per-row quantizer for NVFP4 w4a4. - expert_source: load_experts_gguf takes the pool range and pin by need's PadMap; pin by need only for a whole pack (a pool range keeps the packed, biased layout); generate.cpp turns it off on a pool PC. - verify.cpp: upstream's HostGraphLaunch inside our Niko1221#1120 prelaunch guard (an optional launcher: a prelaunched window has none). - iq_kernels: our IQ1_S (19) beside NVFP4 (40) and the Qwen3.6 downs. - generate.cpp: tail skip keeps from_coord and own layers beside NVFP4's default; batch graph limit is upstream's 64 for --batch-mtp and the pool worker's wide rows. - server.py / web: health has image_generation and pool_role; images and pool routes; tabs chat, images, monitor, pool, about. - the --prefill-help help text's "+~30% on" was a printf conversion (%%). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0157fjixQD2nRxvCvtXq66DD
giridhart
pushed a commit
to giridhart/Strata
that referenced
this pull request
Oct 15, 2026
…rena and Niko1221#1905 pin by need, as opt-ins) into f-144-rel
giridhart
pushed a commit
to giridhart/Strata
that referenced
this pull request
Oct 15, 2026
…-ins (Niko1221#1904 --adapt-async 1, Niko1221#1905 STRATA_PIN_BY_NEED)
giridhart
pushed a commit
to giridhart/Strata
that referenced
this pull request
Oct 15, 2026
DarthCY-K
pushed a commit
to DarthCY-K/Strata
that referenced
this pull request
Oct 20, 2026
…k (default single-GPU path unchanged) From two read-only audits of rel/0.1.44 (port-044/LOG.md, "3b"): - the PCIe share's pick under STRATA_ADAPT_FETCH takes only pinned misses: upstream's Niko1221#1905 STRATA_PIN_BY_NEED pins a PCIe layer in part, and an unpinned pick was skipped later, leaving its share slot unused (prefix pinning, the default, pins a PCIe layer whole: the same picks); - the arena keeps loading on its own thread when STRATA_PIN_BY_NEED is set without --expert-profile (pin by need turns itself off then); - upstream's --prefill-head-alias (opt-in, one GPU) turns the elastic K/V off: it lends from slot 1, so the K/V's start failed and mapped the whole window from VRAM the cache had been sized with (an exit at start on a full card); - a session file's identity names the K/V rotation the session runs (this fork rotates int8 K/V by default, STRATA_KV_ROT=0 does not); upstream's reading of STRATA_KV_ROT=1 gave both the same identity, so a disk-parked conversation could come back in the wrong basis after the variable changed; - Niko1221#2090's earlier loan start never reaches the slots the grown elastic K/V holds ([kvg.lo, kvg.top)): the chunk is halved until its loan starts at kvg.top (a small card whose auto chunk is near small_max, after a long conversation; on the 5090 the auto chunk's loan is the largest and starts at kvg.top); - the VMM stubs of the builds without CUDA VMM (HIP, SYCL, Metal) take the device argument vmm.hpp passes since 26ca4526 (an undefined reference there). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VZy1yKaDDiA8a7svdwaHio
DarthCY-K
pushed a commit
to DarthCY-K/Strata
that referenced
this pull request
Oct 20, 2026
…d allocation is refused, so the PCIe share works
FileExpertSource::pin_cache_complement with `pin`: when cudaHostAlloc of the whole copy was refused (a Q8_0 pack's
100 GiB copy on a 128 GB PC), the copy was malloc'd and only locked in the working set: pinned() was false for every
expert, pcie_layer() false, so the PCIe share (pcie_frac 0.30 logged) fetched nothing and every miss went to the CPU.
Now three paths, each logged ("page-locking path 1/2/3 ... X of Y GiB pinned"):
- path 1: the one cudaHostAlloc, as before (byte-identical).
- path 2: refused (or no device alias) -> the copy is VirtualAlloc'd (posix_memalign elsewhere) and registered with
cudaHostRegister(Portable|Mapped) slice by slice before anything writes it (the WDDM rule), slices ~ one layer of
the pack cut at expert starts (page-aligned where possible), each with its own device alias; stops at the first
refusal. pinned()/device_alias() look the slice up (an expert in no slice whole is the CPU's); pcie_layer() true.
By default only up to the GPU adapter's shared-memory budget less what the process uses there and the margin
(shared_pin_limit_for, extras/wddm-pin's per-adapter helper; STRATA_PIN_MARGIN_GIB, 4 GiB): pinned until the driver
refused (99.61 GiB + 1.3 of a 101.0 GiB budget) a 32K first prompt took 18.7 / 20.5 s against 10.9 / 10.3
unpinned; at the cap (94.63 GiB) 9.2 / 8.5 s. STRATA_COMPLEMENT_PIN_GIB: "all" until the driver refuses, N GiB,
0 = path 3.
- path 3: no slice pinned -> pageable + locked, as before. The STRATA_PARTIAL_PIN=1 budget prefix keeps its own path;
STRATA_EXCHANGE_ROTATE stays off with slices (it needs one alias).
RTX 5090, 128 GB, Q8_0 pack --low-ram (0.1.42 measurement), interleaved 3+3: decode (4 chats) 45.9 / 47.5 / 47.4 ->
56.0 / 52.4 / 53.4 tok/s, PCIe 9-12% of the routed experts, a 1238-token prompt 5.0 -> 2.55 s, start 37 -> 29 s.
Teacher-forced KL against the release equals the placement noise; the copy's checksum is the release's; with
STRATA_COMPLEMENT_PIN_GIB=0 the logits are the release's bit for bit. GPTQ pack (path 1) --low-ram: deterministic
greedy tokens identical. G2b (0.1.43.1): the slower state some path-2 runs showed is a full card (0-173 MiB free
at serve start, WDDM paging) - the next commit keeps VRAM free in the low-RAM mode.
Port to rel/0.1.44 (from fix/lowram-slice-pin-043 6a41b80d): pinned.cu / pinned.hpp are rel/0.1.44's as they are -
extras/wddm-pin already made shared_pin_limit public and added shared_pin_limit_for(dev); the slices' cap uses the
latter for the device that reads the copy, and on a layer split (the portable slices are mapped into every context,
WDDM charges every adapter) the smallest room of all devices. Upstream's STRATA_PIN_BY_NEED (Niko1221#1905) pins the expert
arena; this pins the --mmap-experts RAM copy (the low-RAM mode), whose order is already hottest first by the
profile - the two never run together (the low-RAM mode has no arena); STRATA_PIN_BY_NEED with --mmap-experts now
says it is off instead of being ignored silently.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VZy1yKaDDiA8a7svdwaHio
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Title
Issue: #1903
Summary
On Windows
cudaHostRegisterof the whole arena fails (WDDM shared budget, about half the RAM) and the sliced fallbackregisters the first ~30 GiB, layers 0-31 for Qwen3.8-Flash-Next IQ3_S: layers 32-47 never get a PCIe share, while ~10 GiB of the
registered prefix hold GPU-resident experts that DMA never reads. With
STRATA_PIN_BY_NEED=1the arena gives every blob apage-aligned stride (+0.15 % RAM) and registers the expert profile's non-GPU-resident experts by rank, up to
STRATA_ARENA_PIN_GIB(29 GiB by default on Windows, to leave the shared segment some room).STRATA_PCIE_MIN1=1sends onemiss over PCIe as soon as a layer has two (the share
(nmiss * pcie_num) >> 8rounds to 0 at 1-2 misses). Both opt-in.RTX 3090 + Ryzen 5 5600X: 28.96 GiB registered = 92 % of the non-resident experts, all 48 layers get a PCIe share.
Prompt read +5-7 % at 56K-117K tokens (2,172 → 2,313 and 2,091 → 2,208 tok/s). Decode: level on the blocking tier
(x0.999 cold, 6/12), x1.02-1.03 (10 of 12 prompts faster) on top of
--adapt-async 1(the other PR) with--pcie-frac 0.6.What changed
src/core/pinned.cu,include/strata/core/pinned.hpp: aPinnedArenaconstructor that registers a list of byte rangesin order before any page is touched, stops at the cap or the first refusal, and unregisters them in the destructor;
PadMap, the per-blob placement used by the loaders (load_experts_ranges,load_experts_gguf) when the layout is padded.STRATA_ARENA_PIN_GIB=autoapplies to this path too.src/platform/memory.cpp,.hpp:lock_resident_rangeskeeps the holes between the ranges resident (one working-set raise).src/core/expert_source.cpp,.hpp(ArenaExpertSource):arena_off()(one offset function forblob,blob_at,pinned,device_alias, the ranges);set_pin_priority;pinned()/device_alias()/pcie_layer()by ranges (a blob ispinned only if it lies wholly inside one registered range);
STRATA_PCIE_MIN1in the PCIe share.src/program/generate.cpp: before the arena is loaded, the profile's pairs past the estimated GPU-resident count (from--expert-cacheor the free VRAM, as the cache'sautocomputes it) are ranked into ranges; one log linepin by need: N ranges, X GiB pinned, Y % of the non-resident experts.docs/DETAILS.md,bench/results/2026-10-11-community-rtx3090-5600x-arena-pin-by-need/.How the default path was checked
STRATA_PIN_BY_NEEDthe layout, the loaders and the sliced pin are untouched. Bit-exact mode(
STRATA_IQ_MT_MIN=1 --pcie-frac 0 --adapt-every 0), greedy, 6 prompts: on the 5 prompts that v0.1.42 reproduces betweentwo of its own fresh engines, this branch without the variables gives the same answers byte for byte (sha256). The 6th
prompt differs between two runs of v0.1.42 itself in that mode on this machine.
pinned.cuandexpert_source.cppare shared with those builds (the new code is host code behind the variable).
Extra Notes
experts.binthrough the buffered loader (a contiguous unbuffered read cannot land strided); loadspeed was unchanged here (6.7 GiB/s).
STRATA_VERIFY_ARENA's checksum is over the padded layout when the variable is on (not comparable with the packed one).few hot ones, never correctness (
STRATA_PIN_BY_NEED_SKIP=Nsets it).🤖 Generated with Claude Code
https://claude.ai/code/session_015oFHMEgBzk7kQSqUVWoc67