diff --git a/docs/Dankserver System Specs.md b/docs/Dankserver System Specs.md index c944316..42c56b2 100644 --- a/docs/Dankserver System Specs.md +++ b/docs/Dankserver System Specs.md @@ -51,11 +51,11 @@ Dankserver is an NVIDIA GPU server for vLLM inference. The host runs Ubuntu 24.0 ### 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 2048, `--ctx-checkpoints 4`, `--no-mmap`. At idle ~22.2 GB VRAM used, leaving an estimated **~1.8 GiB** headroom (up from ~870 MiB at `--n-cpu-moe 32`). 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, **32 sit on CPU** (`--n-cpu-moe 32`) while the remaining **8 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 1024, `--ctx-checkpoints 4`, `--no-mmap`. At idle ~23.0 GB VRAM used, leaving an estimated **~1.0 GiB** headroom (chosen by benchmark, see [[frank-default-small-benchmark]]). Idle RAM ~32 GB of 62 GB. ## Hardware Relevance -- 24 GB VRAM is close to saturated with this config. At idle ~22.2 GB used, leaving an estimated **~1.8 GiB** headroom at `--n-cpu-moe 35` (5 layers' experts on GPU). The move from `--n-cpu-moe 32` to 35 traded a little GPU-expert speed for OOM safety after high-load sessions OOM'd at 32 and 33. If headroom proves too thin for production bursts, dial back `--n-cpu-moe` to 37 (only 3 layers on GPU, ~0.9 GiB more headroom) by editing `scripts/frank-default-small.env`. +- 24 GB VRAM is close to saturated with this config. At idle ~23.0 GB used, leaving an estimated **~1.0 GiB** headroom at `--n-cpu-moe 32` (8 layers' experts on GPU) with `ubatch 1024`. A llama-bench sweep ([[frank-default-small-benchmark]]) chose this state: it maximises decode (~48.7 t/s) while staying above the OOM boundary that `ncmoe 32 - ubatch 2048` crossed (24.4 GiB). If headroom proves too thin for production bursts, reduce `ubatch` to 768 (~1.3 GiB headroom) or dial `--n-cpu-moe` back to 34 at `ubatch 1536` (~2.0 GiB headroom) 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). - 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). diff --git a/docs/deployment.md b/docs/deployment.md index 09dba60..a9d58e6 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -143,7 +143,7 @@ The active service on Dankclaw runs llama.cpp serving the HauhauCS Qwen3.6-27B u ### 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 2048, `--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. **32 of 40 MoE expert layers** stay on CPU (`--n-cpu-moe 32`); 8 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 1024, `--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: this service replaced the retired `vllm-awq-qwen36` (AWQ 4-bit, port 34401) and the earlier `vllm-qwen36` (FP8) / `llama-server` (ROCmFPX) units. The repo tracks `main` on Dankserver at `/home/dank/vLLM`. diff --git a/docs/frank-default-small-benchmark.md b/docs/frank-default-small-benchmark.md new file mode 100644 index 0000000..45f55d2 --- /dev/null +++ b/docs/frank-default-small-benchmark.md @@ -0,0 +1,129 @@ +--- +type: reference +title: frank-default-small Benchmark — ncmoe and Batch Tuning +description: llama-bench sweep of MoE CPU offload (ncmoe) and batch/ubatch on the RTX 3090 for Qwen3.6-35B-A3B Q6_K_P. +tags: + - benchmark + - llamacpp + - ncmoe + - ubatch + - dankserver +--- + +# frank-default-small Benchmark — ncmoe and Batch/Ubatch Tuning + +This page records a llama-bench sweep on Dankserver (RTX 3090, 24 GiB) for +the HauhauCS Qwen3.6-35B-A3B Q6_K_P model. The sweep decided the final +`--n-cpu-moe` and `--ubatch-size` values for `frank-default-small`. + +Run date: 2026-08-13. Build: llama.cpp `555881ebc` (10121). CUDA, 7 threads, +`--cache-type-k q8_0 --cache-type-v f16`, `--fit-target 0` (KV auto-sized to +fill VRAM). Prompt 16384 tokens, generation 512 tokens, 2 repetitions. + +## Headline Findings + +### Generation does not depend on batch or ubatch + +For every `ncmoe` value, generation throughput stayed flat across all +`ubatch` values from 256 to 4096. The delta between the lowest and highest +was under one token per second. Generation depends only on how many MoE +expert layers stay on the GPU as `ncmoe` gets smaller. + +| `ncmoe` | Expert layers on GPU | Generation (t/s) | +| ------- | -------------------- | ---------------- | +| 40 | 0 | 40.9 | +| 38 | 2 | 42.6 | +| 36 | 4 | 44.4 | +| 35 | 5 | 45.5 | +| 34 | 6 | 46.4 | +| 32 | 8 | 48.7 | +| 30 | 10 | 51.1 | + +Each pair of expert layers moved to the GPU adds roughly 1.1-2.0 t/s of +generation. Moving from `ncmoe 35` to `ncmoe 32` adds about 3.2 t/s, or 7 +percent. + +### Prefill and graph memory scale with ubatch + +Prefill throughput climbs with `ubatch` because a prompt splits into +`prompt / ubatch` micro-batches. For `ncmoe 35` at 16384 prompt tokens: + +| `ubatch` | Prefill (t/s) | Peak graph VRAM (MiB) | +| -------- | ------------- | --------------------- | +| 256 | 245 | 6838 | +| 512 | 416 | 6852 | +| 768 | 556 | 7074 | +| 1024 | 710 | 7330 | +| 1536 | 895 | 7846 | +| 2048 | 1188 | 8574 | + +The logical `--batch-size` does not matter. At a fixed `ubatch`, `batch` +values of 2048, 4096, and 8192 gave identical prefill speed and peak VRAM. + +## Peak VRAM by ncmoe and ubatch + +Peak VRAM (llama-bench, single context) rises both when `ncmoe` drops +(more experts on GPU) and when `ubatch` rises (bigger compute graph): + +| `ncmoe` | ub 512 | ub 1024 | ub 1536 | ub 2048 | +| ------- | ------ | ------- | ------- | ------- | +| 38 | 4590 | 5068 | 5584 | 6086 | +| 36 | 6098 | 6576 | 7092 | 7594 | +| 35 | 6852 | 7330 | 7846 | 8574 | +| 34 | 7606 | 8084 | 8600 | 9102 | +| 32 | 9114 | 9592 | 10108 | 10610 | +| 30 | 10622 | 11100 | 11616 | 12118 | + +## VRAM Budget Model + +The live service holds a fixed 800000-token KV pool plus the mmproj vision +tower plus CUDA overhead. The model below fits llama-bench peak VRAM into a +24 GiB budget: + +``` +service VRAM = llama-bench peak + KV pool (11.44 GiB) + overhead (2.2 GiB) +``` + +This model reproduces the historical OOMs. Configurations whose sum exceeds +24 GiB fail. For example, `ncmoe 32 - ubatch 2048` sums to about 24.4 GiB +and fails, which matches the recorded OOMs at `ncmoe 32` and `33`. + +## Candidate Configurations + +| Configuration | Gen (t/s) | Prefill (t/s) | Headroom (MiB) | Fit | +| ------------------ | --------- | ------------- | -------------- | --- | +| ncmoe 35, ub 2048 | 45.5 | 1188 | 2035 | OK | +| ncmoe 34, ub 2048 | 46.4 | 1221 | 1507 | OK | +| ncmoe 34, ub 1536 | 46.5 | 914 | 2009 | OK | +| ncmoe 32, ub 1024 | 48.7 | 766 | 1017 | OK | +| ncmoe 32, ub 768 | 48.8 | 600 | 1273 | OK | +| ncmoe 30, ub 1536 | 51.2 | 1009 | under | OOM | + +## Chosen State + +The chosen state balances generation speed against prefill speed and OOM +headroom: + +``` +--n-cpu-moe 32 # 8 expert layers on GPU +--batch-size 8192 +--ubatch-size 1024 +``` + +This gives generation about 48.7 t/s (7 percent above the previous +`ncmoe 35`) while keeping the box above the OOM boundary. If prefill speed +matters more than generation, use `ncmoe 34 - ubatch 2048`. If stability +headroom matters most, use `ncmoe 34 - ubatch 1536`. + +## Limitations + +llama-bench measures raw decode and prefill. It does not run speculative +decoding, parallel slots, or the mmproj vision tower. The live service adds +those on top. The VRAM model uses a fixed 2.2 GiB overhead estimate; the +real overhead varies a little with load. + +## See Also + +- [[Dankserver System Specs]] +- [[deployment]] +- [[DFlash DSpark Speculative Decoding]] diff --git a/docs/index.md b/docs/index.md index 8d90728..d873046 100644 --- a/docs/index.md +++ b/docs/index.md @@ -52,6 +52,7 @@ DFlash draft, port 7770] - [[Running Qwen3.6 35B A3B FP8 on Dankserver]] — MoE model (35B total, 3B active) on RTX 3090 - [[Running Qwen3.6 27B FP8 on Dankclaw]] — Dense model (27B) on Strix Halo APU - [[frank-default-large-benchmark]] — backend/spec benchmark that drove the Dankclaw llama.cpp deployment +- [[frank-default-small-benchmark]] — ncmoe and batch/ubatch sweep that drove the Dankserver state - [[Dankclaw Improvements]] — researched enhancements: self-hosted agentic tools, runtime tuning, server/OS settings ## Speculative Decoding & Quantization diff --git a/scripts/frank-default-small.env b/scripts/frank-default-small.env index a596392..1f85d46 100644 --- a/scripts/frank-default-small.env +++ b/scripts/frank-default-small.env @@ -8,15 +8,17 @@ PORT=7770 # (Increased from 3×200k to add a 4th parallel stream.) CTX_SIZE=800000 PARALLEL=4 -# Spec: ngram-mod. n_min=48, n_max=64, n_match=24 (defaults). 5 expert -# layers back on GPU; 35 on CPU. Batch 8192 / ubatch 2048. +# Spec: ngram-mod. n_min=48, n_max=64, n_match=24 (defaults). 8 expert +# layers back on GPU; 32 on CPU. Batch 8192 / ubatch 1024. SPEC_TYPE=ngram-mod NGRAM_MOD_N_MIN=48 NGRAM_MOD_N_MAX=64 NGRAM_MOD_N_MATCH=24 -# Expert offload: 35 of 40 layers keep MoE weights on CPU; remaining -# 5 layers have their expert weights resident on GPU for faster routing. -N_CPU_MOE=35 +# Expert offload: 32 of 40 layers keep MoE weights on CPU; remaining +# 8 layers have their expert weights resident on GPU for faster routing. +# Benchmark-chosen (see frank-default-small-benchmark.md): max decode at +# the headroom that stays above the historical OOM boundary. +N_CPU_MOE=32 N_GPU_LAYERS=all # KV cache on GPU, K quantized to q8_0, V stays f16 (user-locked decision). CACHE_TYPE_K=q8_0 @@ -25,8 +27,10 @@ CACHE_TYPE_V=f16 # larger batch/ubatch (leaves headroom for ctx-checkpoints operation). CTX_CHECKPOINTS=4 # Larger batches / ubatch for big prefill workloads. +# ubatch 1024 (benchmark-chosen): decode is flat vs ubatch; 1024 frees +# compute-graph VRAM to afford ncmoe 32 while keeping prefill ~766 t/s. BATCH_SIZE=8192 -UBATCH_SIZE=2048 +UBATCH_SIZE=1024 # Load the model into RAM rather than lazy-mapping it. The MoE experts live on # CPU, so eager RAM load avoids page faults during decode (uses ~31GB RAM). NO_MMAP=1 diff --git a/scripts/serve-llama-frank-small.sh b/scripts/serve-llama-frank-small.sh index 12d51b6..1a06a81 100755 --- a/scripts/serve-llama-frank-small.sh +++ b/scripts/serve-llama-frank-small.sh @@ -32,10 +32,10 @@ fi : "${NGRAM_MOD_N_MATCH:=24}" : "${CACHE_TYPE_K:=q8_0}" : "${CACHE_TYPE_V:=f16}" -: "${N_CPU_MOE:=35}" # 35 of 40 layers: MoE expert weights stay on CPU; 5 on GPU +: "${N_CPU_MOE:=32}" # 32 of 40 layers: MoE expert weights stay on CPU; 8 on GPU : "${N_GPU_LAYERS:=all}" # every non-expert tensor goes to GPU : "${BATCH_SIZE:=2048}" -: "${UBATCH_SIZE:=512}" +: "${UBATCH_SIZE:=1024}" : "${CTX_CHECKPOINTS:=0}" : "${NO_MMAP:=0}" : "${TEMPERATURE:=1.0}"