Skip to content

CUDA + discrete GPU: page-cache residency when RAM ≥ model — measured before/after (decode +52%) #477

Description

@fioruccione

Ciao Salvatore,

ho fatto girare ds4 con DeepSeek V4 Flash (Q2 IQ2XXS, ~80GB) su hardware
consumer "improbabile": dual-socket X99, 2× RTX 4060 Ti 16GB (no NVLink,
PCIe3 x8), 128GB DDR4. Prima cosa: gira e la qualità delle risposte è alta.
Grazie per il progetto.

Una segnalazione sul path CUDA, con numeri riproducibili col tuo ds4-bench.

Il punto

Su GPU discrete (non unified-memory) il path CUDA usa O_DIRECT di default e
scarta le pagine dopo l'uso (madvise/fadvise DONTNEED). Sensato quando la RAM
non basta. Ma quando la RAM è >= modello, questo resta inchiodato alla
velocità dell'SSD mentre la RAM (spesso abbondante su chi ha una scheda seria)
resta inutilizzata.

Ho provato le due env var che hai già previsto:
DS4_CUDA_NO_DIRECT_IO=1
DS4_CUDA_KEEP_MODEL_PAGES=1

  • modello pre-scaldato in page cache.

Misure (ds4-bench, GPU singola isolata 16GB, cache esperti 11GB)

Comando (identico before/after, cambia solo le 2 env var):

CUDA_VISIBLE_DEVICES=1 ./ds4-bench -m <model.gguf>
--prompt-file speed-bench/promessi_sposi.txt --cuda --ssd-streaming
--ssd-streaming-cache-experts 11GB --ctx-start 2048 --ctx-max 8192
--step-incr 2048 --gen-tokens 64 --csv out.csv

ctx | prefill_tps O_DIRECT -> page-cache | gen_tps O_DIRECT -> page-cache
2048 | 44.0 -> 24.0 (primo chunk, freddo) | 0.87 -> 1.34
4096 | 42.6 -> 56.4 | 0.88 -> 1.36
6144 | 41.6 -> 57.9 | 0.87 -> 1.32
8192 | 41.4 -> 57.5 | 0.88 -> 1.33

  • Decode: +52% costante a ogni contesto (esperti caldi serviti dalla RAM).
  • Prefill: penalità solo sul primo chunk freddo (warm-up della cache),
    poi +37% sostenuto. I/O disco nel decode passa da ~1.6 GB/s a ~0.

La regola

Il vincolo su GPU discreta non è la VRAM, è la RAM totale >= modello. Combacia
con la tua raccomandazione 96/128GB. E scala verso l'alto: una scheda con
piu' VRAM prenderebbe questo + una cache esperti piu' grande -> piu' veloce
ancora.

Proposta

Attivare automaticamente la residenza in page-cache sul path CUDA quando la
RAM libera >= modello, invece di lasciarlo alle env var manuali. Beneficia
ogni box a GPU discreta con RAM sufficiente (3090/4090/5090 + DDR abbondante),
che è la maggioranza degli utenti CUDA. Costo: un warm-up una tantum sul primo
chunk di prefill, trascurabile su sessioni reali.

Nota: ho visto che O_DIRECT e keep-pages-off sono scelte deliberate per
tenere la RAM libera ad altri processi. Su una macchina dedicata
all'inferenza è un non-problema; per questo proporrei un auto-rilevamento del
regime RAM>=modello, non un cambio secco del default.

PS - multi-GPU

Per curiosità ho provato il distributed (pipeline) sulle due schede: funziona
ma per un singolo stream è piu' lento (~0.23 t/s) per la staffetta
coordinator<->worker a ogni token. Guardando il codice, la cucitura per un
Expert Parallelism sembra esserci (slot-cache per-esperto,
ds4_gpu_stream_expert_cache_begin_selected_load con gli ID selezionati);
l'ostacolo è il backend CUDA single-device (un solo cudaSetDevice, stato
globale singleton). Lo lascio al tuo giudizio.

Macchina: dual Xeon X99, 2× RTX 4060 Ti 16GB, CUDA 12.6, Pop!_OS.
Backend: CUDA, ssd-streaming. Modello: DeepSeek-V4-Flash IQ2XXS (~80GB).
Grazie ancora.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions