Skip to content

Dynamic host-RAM tiering for large MoE models (Rust experiment) #54

Description

@meronrudy

What problem would this solve?

What problem would this solve?

ToshLLM already does unusually good work on the GPU side for AMD Macs: persistent host↔GPU staging, CPU-offloaded MoE, custom Metal attention/GEMM paths, wave64 support, and multi-GPU transfers.

The remaining limitation I’m interested in is placement policy for machines with far more host RAM than VRAM.

A 2019 Mac Pro can have an extreme memory hierarchy — potentially ~1.5 TB host RAM against tens of GB of VRAM per GPU. For large sparse MoE models, most expert weights could remain resident in host RAM indefinitely while only a smaller hot expert set lives in VRAM.

Today, --n-cpu-moe is effectively a static decision made at launch. It cannot respond to which experts are actually hot for the current session, and it cannot use observed router locality to prefetch likely experts.

The question is whether ToshLLM could use host RAM as a managed second-tier model cache instead of treating CPU offload as a fixed split.

Proposed behavior

I’d like to experiment with an optional host-memory tiering runtime that sits above ToshLLM’s existing Metal implementation.

Conceptually:

GGUF / disk

large host-RAM model tier

hot expert / KV working set

GPU VRAM

existing ToshLLM Metal kernels

The runtime would decide what should be resident and what should move next. ToshLLM’s existing Metal code would continue deciding how the copy and computation happen.

I scaffolded a Rust implementation because the host side eventually becomes mostly a residency/state-management problem:

HostOnly
→ PromotionQueued
→ Uploading
→ VramReady
→ InUse
→ Evictable

The proposed sequence is deliberately measurement-first:

  1. Read-only MoE tracing
    • record selected expert IDs by layer/token;
    • record VRAM pressure and existing transfer activity;
    • do not move anything.
  2. Offline policy simulation
    • compare static placement against LRU/LFU/windowed policies;
    • measure realistic cache hit rates and bytes moved.
  3. Single-GPU expert cache
    • only if the traces show useful locality;
    • reuse the existing ggml_metal_*_async staging functions.
  4. Predictive prefetch
    • only if expert transitions are actually predictable;
    • initially use simple per-layer transition statistics rather than another ML model.
  5. Multi-GPU placement
    • reuse ToshLLM’s existing event-vs-peer-copy behavior rather than implementing another transfer backend.
  6. Potential KV host tier
    • keep recent KV in VRAM and colder blocks in host RAM;
    • integrate with the existing KV/prompt-cache work instead of replacing it.

The static path would remain the fallback throughout.

I would consider the experiment worth continuing only if real traces show something roughly like:

  • ≥70% expert-cache hit rate at a realistic VRAM budget, or
  • ≥25% reduction in host/device bytes on a useful workload.

Otherwise the right outcome is simply to stop.

Alternatives considered

Rewrite more of ToshLLM in Rust: I don’t think this makes sense. Rewriting SwiftUI or the existing Metal backend would touch a lot of working code without addressing the actual bottleneck.

Replace the Metal transfer layer: also unnecessary. ToshLLM already has persistent staging, async host/device copies, multi-GPU event hand-off, peer copies, etc. The proposed runtime should call those existing primitives.

Just increase --n-cpu-moe: this remains the simplest solution, but it is static. It cannot exploit session-level expert locality or dynamically trade expert residency against growing KV requirements.

Immediately implement predictive prefetch: too speculative. I think routing traces should establish whether locality exists first.

Additional context

I’ve scaffolded the experiment in a fork here:

https://github.com/meronrudy/toshllm/tree/rust-tiering-rfc

The scaffold includes:

tosh-tier/
├── tier-core
├── expert-cache
├── trace
├── transfer-sched
├── host-tier
├── kv-tier
├── policy-sim
├── ggml-shim
└── ggml-sys

It also includes an optional Rust↔llama.cpp link shim, deterministic baseline-vs-linked A/B scripts, and a proposed hardware test matrix.

Nothing currently replaces the AMD Metal kernels or performs live expert/KV movement.

I don’t currently have the target Mac Pro hardware, so the main thing I’m asking for before taking the implementation further is help validating the architecture on ToshLLM’s existing AMD test hardware.

The two questions I’d especially appreciate guidance on are:

  1. Where is the cleanest point in the current engine to observe top-k MoE expert selections without forcing a GPU synchronization?
  2. Would someone with an AMD Mac Pro / large-MoE setup be willing to run the build and baseline A/B scripts before I implement live placement?

If the instrumentation shows no useful expert locality, I’m happy for that to be the end of the experiment.

Before submitting

  • I searched the existing issues and did not find the same request.

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: needs triageNew report awaiting maintainer classificationtype: featureA new capability or user-facing improvement

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions