frank-default-small: ncmoe 35->36 for prefill stability

Fix a live crash: cuBLAS cudaErrorInvalidValue in ggml_cuda_mul_mat_cublas
killed the service during a 145k-token prefill burst at ncmoe35/ub3072.

ncmoe 36 moves one more expert layer to CPU: frees ~0.75 GiB peak VRAM
(grid: peak 8606 vs 9360 MiB at ub3072) for -2% prefill / -2% decode.
Keeps prefill priority (top ubatch tier). Docs synced; noted fallback
GGML_CUDA_FORCE_MMQ=1 if pressure persists.
This commit is contained in:
Frank committed 2026-08-14 10:56:40 -07:00
1 parent 7daf9896e5
commit 9d7643ec5d
5 files changed
+28 -20

No files matched your search

+2 -2
View File
@@ -51,11 +51,11 @@ Dankserver is an NVIDIA GPU server for vLLM inference. The host runs Ubuntu 24.0
### Active Services ### Active Services
The active `frank-default-small` service (llama.cpp, `b10108+`) serves the HauhauCS Qwen3.6-35B-A3B uncensored `Q6_K_P` model on port 7770 with **ngram-mod** speculative decoding. It runs **4 parallel slots** at 200000 context each (pool 800000). Of the 40 layers' MoE expert weights, **35 sit on CPU** (`--n-cpu-moe 35`) while the remaining **5 layers' expert weights** are resident on GPU along with all non-expert tensors (`--gpu-layers all`). KV stays on GPU with K=`q8_0`, V=`f16`. Batch 8192 / ubatch 3072, `--ctx-checkpoints 4`, `--no-mmap`. At idle ~22.8 GB VRAM used, leaving an estimated **~1.2 GiB** headroom (chosen by benchmark for prefill speed, see [[frank-default-small-benchmark]]). Idle RAM ~32 GB of 62 GB. The active `frank-default-small` service (llama.cpp, `b10108+`) serves the HauhauCS Qwen3.6-35B-A3B uncensored `Q6_K_P` model on port 7770 with **ngram-mod** speculative decoding. It runs **4 parallel slots** at 200000 context each (pool 800000). Of the 40 layers' MoE expert weights, **36 sit on CPU** (`--n-cpu-moe 36`) while the remaining **4 layers' expert weights** are resident on GPU along with all non-expert tensors (`--gpu-layers all`). KV stays on GPU with K=`q8_0`, V=`f16`. Batch 8192 / ubatch 3072, `--ctx-checkpoints 4`, `--no-mmap`. At idle ~21.05 GB VRAM used, leaving an estimated **~3.0 GiB** headroom (chosen for prefill stability, see [[frank-default-small-benchmark]]). Idle RAM ~32 GB of 62 GB.
## Hardware Relevance ## Hardware Relevance
- 24 GB VRAM is close to saturated with this config. At idle ~22.8 GB used, leaving an estimated **~1.2 GiB** headroom at `--n-cpu-moe 35` (5 layers' experts on GPU) with `ubatch 3072`. A llama-bench sweep ([[frank-default-small-benchmark]]) chose this state because prefill is the priority: `ubatch 3072` reaches ~1458 t/s prefill, the top tier, and generation is independent of ubatch. If decode speed matters more, use `ncmoe 32 - ubatch 1024` (gen ~48.7 t/s). By editing `scripts/frank-default-small.env`. - 24 GB VRAM is close to saturated with this config. At idle ~21.05 GB used, leaving an estimated **~3.0 GiB** headroom at `--n-cpu-moe 36` (4 layers' experts on GPU) with `ubatch 3072`. A llama-bench sweep ([[frank-default-small-benchmark]]) guided this state: prefill is the priority, so `ubatch 3072` stays (top prefill tier), and `ncmoe 36` was raised from 35 to fix a cuBLAS OOM-class crash during big prefills by freeing ~0.75 GiB peak VRAM at only -2% prefill. If it still crashes under load, add `GGML_CUDA_FORCE_MMQ=1`. If decode speed matters more, use `ncmoe 32 - ubatch 1024` (gen ~48.7 t/s). By editing `scripts/frank-default-small.env`.
- 62 GB system RAM holds the ~29 GB of MoE expert weights with room to spare (~57 GB available after load). - 62 GB system RAM holds the ~29 GB of MoE expert weights with room to spare (~57 GB available after load).
- 127 GB swap is available for CPU KV cache paging if GPU KV offload is disabled. - 127 GB swap is available for CPU KV cache paging if GPU KV offload is disabled.
- Root disk has approximately 140 GB free. Store the GGUF models under `/home/dank/models` (about 32 GB total). - Root disk has approximately 140 GB free. Store the GGUF models under `/home/dank/models` (about 32 GB total).
+1 -1
View File
@@ -143,7 +143,7 @@ The active service on Dankclaw runs llama.cpp serving the HauhauCS Qwen3.6-27B u
### Dankserver — frank-default-small ### Dankserver — frank-default-small
The active service on Dankserver runs llama.cpp (upstream, `b10108+`) and serves the HauhauCS Qwen3.6-35B-A3B uncensored `Q6_K_P` model under the alias `frank-default-small` on port 7770. It uses **ngram-mod** speculative decoding (`--spec-ngram-mod-n-min 48 / n_max 64 / n_match 24`), **4 parallel slots** at 200000 context each (pool 800000), and mmproj vision. **35 of 40 MoE expert layers** stay on CPU (`--n-cpu-moe 35`); 5 expert layers' weights are back on GPU alongside all non-expert tensors (`--gpu-layers all`). KV stays on GPU (K=`q8_0`, V=`f16`). Batch 8192 / ubatch 3072, `--ctx-checkpoints 4`, `--no-mmap`. The unit file is `scripts/frank-default-small.service`, symlinked to `/etc/systemd/system/`. It launches through `scripts/serve-llama-frank-small.sh`, which reads tunables from `scripts/frank-default-small.env`. The active service on Dankserver runs llama.cpp (upstream, `b10108+`) and serves the HauhauCS Qwen3.6-35B-A3B uncensored `Q6_K_P` model under the alias `frank-default-small` on port 7770. It uses **ngram-mod** speculative decoding (`--spec-ngram-mod-n-min 48 / n_max 64 / n_match 24`), **4 parallel slots** at 200000 context each (pool 800000), and mmproj vision. **36 of 40 MoE expert layers** stay on CPU (`--n-cpu-moe 36`); 4 expert layers' weights are back on GPU alongside all non-expert tensors (`--gpu-layers all`). KV stays on GPU (K=`q8_0`, V=`f16`). Batch 8192 / ubatch 3072, `--ctx-checkpoints 4`, `--no-mmap`. The unit file is `scripts/frank-default-small.service`, symlinked to `/etc/systemd/system/`. It launches through `scripts/serve-llama-frank-small.sh`, which reads tunables from `scripts/frank-default-small.env`.
> Note: the Dankserver process currently observed runs `--spec-type ngram-mod` with `--parallel 4`, batch 8192 / ubatch 2048, and `--n-cpu-moe 34` (this is being bench-tuned by the operator; reconcile against `scripts/frank-default-small.env`). > Note: the Dankserver process currently observed runs `--spec-type ngram-mod` with `--parallel 4`, batch 8192 / ubatch 2048, and `--n-cpu-moe 34` (this is being bench-tuned by the operator; reconcile against `scripts/frank-default-small.env`).
+16 -9
View File
@@ -101,24 +101,31 @@ and fails, which matches the recorded OOMs at `ncmoe 32` and `33`.
## Chosen State ## Chosen State
Prefill speed is the priority for this workload, so the final state takes Prefill speed is the priority, so the state keeps the top prefill tier and
the top prefill tier while keeping a safe headroom margin: moves one expert layer to CPU for stability:
``` ```
--n-cpu-moe 35 # 5 expert layers on GPU --n-cpu-moe 36 # 4 expert layers on GPU
--batch-size 8192 --batch-size 8192
--ubatch-size 3072 --ubatch-size 3072
``` ```
This gives prefill about 1458 t/s at 16384 prompt tokens, generation about This gives prefill about 1427 t/s at 16384 prompt tokens, generation about
45.4 t/s, and about 1.2 GiB of headroom at the 800000-token pool. Both are 44.4 t/s, and about 3.0 GiB of headroom at the 800000-token pool.
chosen because generation does not depend on `ubatch`: `ubatch 3072` reaches
the best prefill speed with no cost to decode. `ncmoe 36` came from a live crash rather than this sweep. At `ncmoe 35` with
`ubatch 3072`, a big prefill burst failed a cuBLAS call under memory
pressure (a `cudaErrorInvalidValue` in `ggml_cuda_mul_mat_cublas`), which
killed the service. Raising `ncmoe` one step frees about 0.75 GiB of peak
VRAM (the grid shows `ncmoe 36 - ubatch 3072` peak 8606 MiB versus 9360 MiB
at `ncmoe 35`) for about 2 percent less prefill and 2 percent less decode.
If a crash still occurs under load, set `GGML_CUDA_FORCE_MMQ=1` to bypass
the cuBLAS path for quantized matmuls, or drop `ubatch`, or shrink the
context pool.
If decode speed matters more than prefill, swap to `ncmoe 32 - ubatch 1024` If decode speed matters more than prefill, swap to `ncmoe 32 - ubatch 1024`
(generation about 48.7 t/s, prefill about 766 t/s, about 1.0 GiB headroom). (generation about 48.7 t/s, prefill about 766 t/s, about 1.0 GiB headroom).
If stability headroom matters most, use `ncmoe 34 - ubatch 1536` (about 2.0
GiB headroom).
## Limitations ## Limitations
+8 -7
View File
@@ -8,17 +8,18 @@ PORT=7770
# (Increased from 3×200k to add a 4th parallel stream.) # (Increased from 3×200k to add a 4th parallel stream.)
CTX_SIZE=800000 CTX_SIZE=800000
PARALLEL=4 PARALLEL=4
# Spec: ngram-mod. n_min=48, n_max=64, n_match=24 (defaults). 5 expert # Spec: ngram-mod. n_min=48, n_max=64, n_match=24 (defaults). 4 expert
# layers back on GPU; 35 on CPU. Batch 8192 / ubatch 3072. # layers back on GPU; 36 on CPU. Batch 8192 / ubatch 3072.
SPEC_TYPE=ngram-mod SPEC_TYPE=ngram-mod
NGRAM_MOD_N_MIN=48 NGRAM_MOD_N_MIN=48
NGRAM_MOD_N_MAX=64 NGRAM_MOD_N_MAX=64
NGRAM_MOD_N_MATCH=24 NGRAM_MOD_N_MATCH=24
# Expert offload: 35 of 40 layers keep MoE weights on CPU; remaining # Expert offload: 36 of 40 layers keep MoE weights on CPU; remaining
# 5 layers have their expert weights resident on GPU for faster routing. # 4 layers have their expert weights resident on GPU for faster routing.
# Benchmark-chosen (see frank-default-small-benchmark.md): prefill-max. # Chosen for prefill-max stability at ubatch 3072: frees ~0.75 GiB peak
# gen ~45.4 t/s, pp ~1458 t/s, ~1.2 GiB headroom. # VRAM vs ncmoe 35 (grid: peak 8606 vs 9360 MiB) for -2% prefill, -2%
N_CPU_MOE=35 # decode. Fixes the cuBLAS OOM crash class during big prefills.
N_CPU_MOE=36
N_GPU_LAYERS=all N_GPU_LAYERS=all
# KV cache on GPU, K quantized to q8_0, V stays f16 (user-locked decision). # KV cache on GPU, K quantized to q8_0, V stays f16 (user-locked decision).
CACHE_TYPE_K=q8_0 CACHE_TYPE_K=q8_0
+1 -1
View File
@@ -32,7 +32,7 @@ fi
: "${NGRAM_MOD_N_MATCH:=24}" : "${NGRAM_MOD_N_MATCH:=24}"
: "${CACHE_TYPE_K:=q8_0}" : "${CACHE_TYPE_K:=q8_0}"
: "${CACHE_TYPE_V:=f16}" : "${CACHE_TYPE_V:=f16}"
: "${N_CPU_MOE:=35}" # 35 of 40 layers: MoE expert weights stay on CPU; 5 on GPU : "${N_CPU_MOE:=36}" # 36 of 40 layers: MoE expert weights stay on CPU; 4 on GPU
: "${N_GPU_LAYERS:=all}" # every non-expert tensor goes to GPU : "${N_GPU_LAYERS:=all}" # every non-expert tensor goes to GPU
: "${BATCH_SIZE:=2048}" : "${BATCH_SIZE:=2048}"
: "${UBATCH_SIZE:=3072}" : "${UBATCH_SIZE:=3072}"