You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
TierPlanner.Plan prices GPU KV uniformly: 2 × gpuLayers × NumKvHeads × HeadDim × sizeof(float) × ctx for every layer (TierPlanner.cs:97-126). The Gemma 4 runtime allocates nothing like that:
SWA layers get window-sized rings, not full-context buffers: CudaForwardPass.cs:809,833-834 — layerCtx = SwaRingSize(_maxSeqLen, swaWindow) when hp.IsSwaLayer[i]. Gemma 4 is ~5:1 SWA:global with a window far smaller than typical contexts.
KV-share layers allocate no KV at all — they alias the source layer's K/V (CudaForwardPass.cs:802-803: "KV-share layers (KvSourceLayer[L] >= 0) alias the…").
Net effect: for Gemma 4 the planner overestimates per-token KV cost by roughly 4–6× (more with narrowed KV). On a 12 GB card with -g -1, that means fewer GPU layers and/or a much smaller RecommendedCtxSize than what actually fits — the loader's ClampGemma4KvShareBoundary (InferenceEngineLoader.cs:216) already patches one Gemma-4 blind spot in the planner, and this is the rest of the family.
This matters most for the hybrid configs (Gemma 4 12B-class on 12 GB, where every reclaimed GB is another GPU layer) and for auto-context on E4B long-context runs.
Proposed work
Teach TierPlanner the per-layer KV shape: when hp.IsSwaLayer is populated, price SWA layers at SwaRingSize(ctx, hp.SlidingWindowSize) positions; skip KV-share layers (hp.KvSourceLayer[L] >= 0); use per-layer head_dim where the hyperparams carry it. Reuse the same helpers CudaForwardPass uses so the two can't drift (single source of truth for ring sizing).
Problem
TierPlanner.Planprices GPU KV uniformly:2 × gpuLayers × NumKvHeads × HeadDim × sizeof(float) × ctxfor every layer (TierPlanner.cs:97-126). The Gemma 4 runtime allocates nothing like that:CudaForwardPass.cs:809,833-834—layerCtx = SwaRingSize(_maxSeqLen, swaWindow)whenhp.IsSwaLayer[i]. Gemma 4 is ~5:1 SWA:global with a window far smaller than typical contexts.CudaForwardPass.cs:802-803: "KV-share layers (KvSourceLayer[L] >= 0) alias the…").hp.HeadDim.SHARPI_KV_DTYPE=bf16/q8_0narrows it 2–4× (also noted in perf(cuda,engine): CPU-MoE mode + expert-aware TierPlanner for CudaHybridForwardPass — auto placement is structurally wrong for pure-attention MoE on 12 GB #215; perf(cuda): decode throughput degrades at long context with q8_0 KV (12 vs 65 tok/s) #213's live config runs q8_0 KV).Net effect: for Gemma 4 the planner overestimates per-token KV cost by roughly 4–6× (more with narrowed KV). On a 12 GB card with
-g -1, that means fewer GPU layers and/or a much smallerRecommendedCtxSizethan what actually fits — the loader'sClampGemma4KvShareBoundary(InferenceEngineLoader.cs:216) already patches one Gemma-4 blind spot in the planner, and this is the rest of the family.This matters most for the hybrid configs (Gemma 4 12B-class on 12 GB, where every reclaimed GB is another GPU layer) and for auto-context on E4B long-context runs.
Proposed work
TierPlannerthe per-layer KV shape: whenhp.IsSwaLayeris populated, price SWA layers atSwaRingSize(ctx, hp.SlidingWindowSize)positions; skip KV-share layers (hp.KvSourceLayer[L] >= 0); use per-layer head_dim where the hyperparams carry it. Reuse the same helpersCudaForwardPassuses so the two can't drift (single source of truth for ring sizing).RecommendedCtxSizefrom the corrected per-token cost.Acceptance
ModelHyperparams(SWA pattern + KV-share + per-layer head_dim) asserting plannedGpuKvBytesmatches the runtime allocator's arithmetic.-g -1gains GPU layers and/or context vs today's plan; no change for uniform-attention models.References