Skip to content

Feature request: run MoE expert weights from host RAM via PCIe DMA (no H2D copy) — 23GB MoE on 1.6GB VRAM, 81GB Qwen3-235B on 8GB cards #26448

Description

@yalun753

TL;DR

For MoE models, keep expert weights in host memory (pinned buffer) and let cuBLAS read them directly over PCIe DMA — never copy experts into VRAM. Non-expert layers stay in VRAM as usual. Result (RTX 4090, real measurements):

Model Standard (all-in-VRAM) This approach VRAM saved Speed
DeepSeek-V2-Lite Q2_K (23.3GB) 23.3GB VRAM, 65 t/s 1.6GB VRAM, 37.5 t/s −93% 58% retained
Qwen3.6-35B-A3B (11GB) OOM on 8GB cards 2.1GB VRAM, 46.8 t/s ≈ parity
Qwen3-235B-A22B Q2_K (81.7GB) impossible on consumer GPUs 8GB VRAM (verification in progress) TBD

Motivation

The biggest real-world MoE use case is running a large model on a small GPU. With all experts in VRAM, an 8GB card tops out around a 7-8B dense or a ~11GB MoE. But MoE experts are only activated sparsely (2-8 of 256 per token) — the full weight set doesn't need to live on the GPU. The bottleneck is that llama.cpp's offload path copies expert weights H2D per layer (see #25859), and the --n-cpu-moe path computes experts on CPU (slow).

Proposed approach (high level)

  1. Load expert weights into a host pinned buffer (not GPU VRAM, not anonymous mmap that gets evicted).
  2. Run the expert matmuls on GPU via cuBLAS operating directly on host pointers — the CUDA driver DMA-reads the expert weights from host RAM over PCIe on demand, per activated expert. No H2D staging copy, no per-layer streaming.
  3. VRAM holds only non-expert layers + KV cache. For DS-V2-Lite that's ~1.6GB total.
  4. Optional: a small expert cache (a few slots, LRU) that D2D-copies the hot experts into VRAM once and reuses them — helps when the same experts fire repeatedly (e.g. long prompts / codegen patterns).

Measured results (RTX 4090, 2026-08-02)

  • DeepSeek-V2-Lite Q2_K: VRAM 23.3GB → 1.6GB; speed 37.5 t/s (vs 65 t/s fully offloaded — reasonable PCIe price for −93% VRAM). Expert cache at 0.25: prompt throughput 99 → 308 t/s (+211%), gen +5%.
  • Qwen3.6-35B-A3B: VRAM 2.1GB, 46.8 t/s — an 11GB MoE that OOMs an 8GB card normally, now runs on ~2GB with near-full speed.
  • Qwen3-235B-A22B Q2_K (81.7GB): download in progress; target: run on 8GB VRAM (experts ~80GB in host RAM + PCIe DMA).

Why this is different from existing work

This also composes with existing features: --n-cpu-moe-style flag to select the expert storage mode, GGML_OP_OFFLOAD_MIN_BATCH to control when offload kicks in, and the expert cache as an optional accelerator.

Ask

  • Would the maintainers accept a host-pinned expert buffer + DMA-direct expert matmul path as an official load mode (e.g. --expert-mode host-dma)?
  • Happy to open a PR with the CUDA backend changes (it's a focused patch: model loader + CUDA expert matmul path + optional small expert cache).
  • Open to discussion on trade-offs: PCIe bandwidth vs VRAM, multi-GPU, pageable vs pinned, and whether a --host-ram-budget knob makes sense.

Context

  • All numbers above are from a single RTX 4090 box, measured with llama.cpp-based server (this is a custom fork, patch described at high level above).
  • Env: Linux x86_64, CUDA 12, PCIe 4.0 (gen4 single-GPU).
  • Happy to provide full benchmark methodology / logs on request.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions