Create README.md
Browse files
README.md
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
library_name: vllm
|
| 4 |
+
pipeline_tag: text-generation
|
| 5 |
+
tags:
|
| 6 |
+
- dflash
|
| 7 |
+
- speculative-decoding
|
| 8 |
+
- block-diffusion
|
| 9 |
+
- jetson-thor
|
| 10 |
+
- sm110a
|
| 11 |
+
- nvfp4
|
| 12 |
+
- edge-inference
|
| 13 |
+
- qwen
|
| 14 |
+
---
|
| 15 |
+
|
| 16 |
+
# DFlash on NVIDIA Jetson AGX Thor (SM110a) β Proven Single-Node Deployment Guide
|
| 17 |
+
|
| 18 |
+
Block-diffusion speculative decoding (**[DFlash](https://github.com/z-lab/dflash)**) for Qwen3.5 /
|
| 19 |
+
Qwen3.6 **NVFP4** models, running on a **single NVIDIA Jetson AGX Thor** β aarch64, compute
|
| 20 |
+
**sm_110a**, ~117 GB unified LPDDR5X, CUDA 13, L4T r38. This repo is the **field guide for actually
|
| 21 |
+
getting these models stable on Thor**: the from-source vLLM image, per-model launch configs, the
|
| 22 |
+
122B Marlin-crash discovery and its fix, full k-sweeps, and conc=1 decode benchmarks for four
|
| 23 |
+
model sizes.
|
| 24 |
+
|
| 25 |
+
> This is Thor-specific. The upstream DFlash drafters and the general model cards live at
|
| 26 |
+
> [z-lab](https://huggingface.co/z-lab). Numbers here are **measured on Thor at concurrency 1**,
|
| 27 |
+
> not the B200 numbers from the paper.
|
| 28 |
+
|
| 29 |
+
---
|
| 30 |
+
|
| 31 |
+
## TL;DR β what works
|
| 32 |
+
|
| 33 |
+
| Model | Active | MoE backend | Attn backend | Optimal k | Peak DFlash tok/s (conc=1) | vs AR |
|
| 34 |
+
|---|---|---|---|---|---|---|
|
| 35 |
+
| Qwen3.5-4B-NVFP4 (GDA-hybrid) | 4B | n/a (dense) | flash_attn | 15 | **155.8** | **3.2Γ** |
|
| 36 |
+
| Qwen3.6-35B-A3B-NVFP4 (MoE) | 3B | **marlin** | flash_attn | 12 | **139.1** | β |
|
| 37 |
+
| Qwen3.6-27B-NVFP4 (dense) | 27B | n/a (dense) | flash_attn | 15 | **50.1** | β |
|
| 38 |
+
| Qwen3.5-122B-A10B-NVFP4 (MoE) | 12B | **cutlass** β οΈ | **TRITON_ATTN** β οΈ | 10 | **52.6** | **1.7Γ** |
|
| 39 |
+
|
| 40 |
+
β οΈ **The 122B is the special case.** Marlin (the backend that's *fastest* for the 35B)
|
| 41 |
+
**hard-crashes** loading the 256-expert 122B. It must run **cutlass MoE + TRITON_ATTN**. See
|
| 42 |
+
[the 122B section](#the-122b-marlin-crash-and-the-cutlass--triton_attn-fix).
|
| 43 |
+
|
| 44 |
+
---
|
| 45 |
+
|
| 46 |
+
## The image: vLLM from source + fastsafetensors
|
| 47 |
+
|
| 48 |
+
The stock `nvidia-ai-iot/vllm:latest-jetson-thor` is vLLM 0.19.0 with **no DFlash**. DFlash landed
|
| 49 |
+
after 0.19.0, so the image is built **from source for sm_110a**:
|
| 50 |
+
|
| 51 |
+
- **Source:** vLLM **PR #40898** head β `vllm @ git+https://github.com/vllm-project/vllm.git@refs/pull/40898/head`
|
| 52 |
+
(DFlash block-diffusion + interleaved SWA support). Version string: `0.20.0.dev0+dflash`.
|
| 53 |
+
- **Arch:** `TORCH_CUDA_ARCH_LIST=11.0a` β native **sm_110a SASS** in `_C.abi3.so` and `_moe_C.abi3.so`.
|
| 54 |
+
- **Flash-attn:** native **sm_110 FA2** copied from the stock Thor image. **FA3 crashes on Thor**
|
| 55 |
+
(`CUTE_ARCH_TMA_SM90_ENABLED` β `cudaErrorLaunchFailure`; FA3 needs Hopper SM90 TMA). vLLM
|
| 56 |
+
selects FA2, so this is transparent. FA2-vs-FA3 makes **no decode difference** (decode is
|
| 57 |
+
GEMM/bandwidth-bound, not attention-bound).
|
| 58 |
+
- **fastsafetensors 0.3.2** layer (`Dockerfile.fastsafe`): image tag `vllm-dflash-thor:fastsafe`
|
| 59 |
+
(identical image ID to `fa-native`, plus the fastsafetensors wheel).
|
| 60 |
+
|
| 61 |
+
**Why fastsafetensors is mandatory for the 122B.** The default safetensors loader mmaps the weight
|
| 62 |
+
file (CPU) *then* copies to GPU. On Thor's single 117 GB unified pool both copies coexist: for the
|
| 63 |
+
122B that's 72 GB(GPU) + up to 72 GB(CPU mmap) = **144 GB > 117 GB β the box crashes during load**.
|
| 64 |
+
fastsafetensors streams diskβGPU directly (no CPU staging), peaking near 72 GB. `FASTSAFETENSORS_NOGDS=1`
|
| 65 |
+
forces the no-GDS fallback (GPU Direct Storage is unsupported on Thor; it still avoids CPU staging).
|
| 66 |
+
|
| 67 |
+
Prebuilt image tarballs (aarch64 / sm_110a only) are published alongside this work:
|
| 68 |
+
```bash
|
| 69 |
+
docker load < vllm-dflash-thor-fastsafe.tar.gz # 19 GB, has fastsafetensors 0.3.2
|
| 70 |
+
# or the base (no fastsafetensors): vllm-dflash-thor-fa-native.tar.gz
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
Full build + debug narrative: **[BUILD-AND-DEBUG.md](BUILD-AND-DEBUG.md)**. All numbers + the raw
|
| 74 |
+
debug log: **[RESULTS.md](RESULTS.md)**. Per-model detail: **[benchmarks/](benchmarks/)**.
|
| 75 |
+
|
| 76 |
+
---
|
| 77 |
+
|
| 78 |
+
## How to run (proven configs)
|
| 79 |
+
|
| 80 |
+
All four use the same image, `--load-format fastsafetensors`, `--quantization compressed-tensors`
|
| 81 |
+
(the 4B is declared `modelopt` but loads fine as compressed-tensors), `--trust-remote-code`,
|
| 82 |
+
`--language-model-only` (the 4B and 122B are VLM wrappers), and these env vars:
|
| 83 |
+
```
|
| 84 |
+
-e VLLM_USE_FLASHINFER_MOE_FP4=0 # mandatory: FlashInfer FP4 MoE has no sm_110a kernel
|
| 85 |
+
-e LD_PRELOAD=/usr/lib/aarch64-linux-gnu/nvidia/libcuda.so.1 # else import vllm._C dies
|
| 86 |
+
-e FASTSAFETENSORS_NOGDS=1 -e HF_HUB_DISABLE_XET=1 -e NCCL_IGNORE_CPU_AFFINITY=1
|
| 87 |
+
-e PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True
|
| 88 |
+
-e VLLM_USE_FLASHINFER_SAMPLER=1 -e CUDA_DEVICE_MAX_CONNECTIONS=1 # free, output-safe (see Optimizations)
|
| 89 |
+
```
|
| 90 |
+
Pre-flight before every launch: `for c in $(docker ps -q); do docker kill $c; done; sudo sync;
|
| 91 |
+
sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches'`. **Never** `docker stop` (hangs, leaks page cache)
|
| 92 |
+
or `sudo fuser -k /dev/nvidia*` (kills Xorg/RustDesk, not CUDA).
|
| 93 |
+
|
| 94 |
+
Exact, copy-pasteable launch commands for all four models are in **[REVERT.md](REVERT.md)**, and the
|
| 95 |
+
wrapper scripts are `scripts/serve-{35b,27b,122b}.sh`. The key per-model differences:
|
| 96 |
+
|
| 97 |
+
```bash
|
| 98 |
+
# 35B-A3B (MoE) β marlin is fastest
|
| 99 |
+
--moe-backend marlin --attention-backend flash_attn \
|
| 100 |
+
--gpu-memory-utilization 0.78 --max-model-len 65536 --max-num-seqs 4 \
|
| 101 |
+
--speculative-config '{"method":"dflash","num_speculative_tokens":12,"model":"/draft"}'
|
| 102 |
+
|
| 103 |
+
# 27B (dense) β needs Qwen2Tokenizer overlay (ships tokenizer_class=TokenizersBackend)
|
| 104 |
+
--attention-backend flash_attn --tokenizer /tokenizer \
|
| 105 |
+
--gpu-memory-utilization 0.85 --max-model-len 65536 --max-num-seqs 4 \
|
| 106 |
+
--speculative-config '{"method":"dflash","num_speculative_tokens":15,"model":"/draft"}'
|
| 107 |
+
|
| 108 |
+
# 122B-A10B (MoE) β CUTLASS + TRITON_ATTN (NOT marlin/flashinfer), draft KV capped
|
| 109 |
+
--moe-backend cutlass --attention-backend TRITON_ATTN \
|
| 110 |
+
--gpu-memory-utilization 0.78 --max-model-len 16384 --max-num-seqs 2 \
|
| 111 |
+
--speculative-config '{"method":"dflash","num_speculative_tokens":10,"model":"/draft","max_model_len":1024}'
|
| 112 |
+
|
| 113 |
+
# 4B (dense GDA-hybrid VLM)
|
| 114 |
+
--attention-backend flash_attn \
|
| 115 |
+
--gpu-memory-utilization 0.40 --max-model-len 32768 --max-num-seqs 1 \
|
| 116 |
+
--speculative-config '{"method":"dflash","num_speculative_tokens":15,"model":"/draft"}'
|
| 117 |
+
```
|
| 118 |
+
|
| 119 |
+
---
|
| 120 |
+
|
| 121 |
+
## The 122B Marlin crash, and the cutlass + TRITON_ATTN fix
|
| 122 |
+
|
| 123 |
+
This is the central Thor discovery. The 122B-A10B (**256 experts Γ 48 layers**) crashed on every
|
| 124 |
+
launch for weeks. Root cause, established by reproduction + `cuobjdump`:
|
| 125 |
+
|
| 126 |
+
- After weights load (~60 s), the EngineCore dies with **exit 255, no Python traceback, Docker
|
| 127 |
+
OOMKilled=false, no host OOM line**, at exactly `nvfp4.py:491 Using MoEPrepareAndFinalizeNoDPEPModular`
|
| 128 |
+
β i.e. the **Marlin NVFP4 MoE weight-repack**.
|
| 129 |
+
- It is **not** DFlash / SWA / OOM / config β the identical crash reproduces with the **base model
|
| 130 |
+
alone** (no speculative config).
|
| 131 |
+
- It is **not** a missing kernel image: `_moe_C.abi3.so` *does* contain `sm_110a`, and the MoE dims
|
| 132 |
+
are 128-aligned. It is a **genuine in-kernel fault in the Marlin FP4 MoE kernel at 256-expert
|
| 133 |
+
scale** on Thor (matches open vLLM issues #35566 / #35519 / #35922). **A rebuild does not fix it.**
|
| 134 |
+
|
| 135 |
+
**The fix:**
|
| 136 |
+
1. `--moe-backend cutlass` β cutlass (VLLM_CUTLASS) processes all 256 experts cleanly (70.46 GiB
|
| 137 |
+
load, no crash). It is the **only** NVFP4 MoE backend that loads the 122B on Thor.
|
| 138 |
+
(`triton` is rejected for NVFP4; `flashinfer_*` have no sm_110a kernels.)
|
| 139 |
+
This is the **opposite** of the 35B, where marlin is ~10% *faster* than cutlass β marlin only
|
| 140 |
+
*crashes* at the large expert count.
|
| 141 |
+
2. `--attention-backend TRITON_ATTN` β cutlass + flashinfer dies in attention warmup with
|
| 142 |
+
`BatchDecodeWithPagedKVCacheWrapper.run() got an unexpected keyword 'kv_cache_sf'` (a FlashInfer
|
| 143 |
+
API mismatch in this fork). TRITON_ATTN avoids it.
|
| 144 |
+
3. `--gpu-memory-utilization 0.78` + draft `"max_model_len":1024` β the DFlash draft eats ~2 GB KV;
|
| 145 |
+
at 0.72 the 16384 KV request fails ("estimated max length 8960"); 0.90 trips the startup
|
| 146 |
+
precheck (needs 110.5 > ~108 GB free). 0.78 yields ~71k-token KV.
|
| 147 |
+
|
| 148 |
+
Result: base 122B 10.9 tok/s β DFlash **27β42 tok/s** (Ο 4.2β6.5), **1.7Γ+**, stable, coherent.
|
| 149 |
+
|
| 150 |
+
### cuobjdump arch facts (this image)
|
| 151 |
+
| extension | arches | meaning |
|
| 152 |
+
|---|---|---|
|
| 153 |
+
| `_moe_C.abi3.so` (Marlin MoE) | sm_110a, sm_80 | has Thor image, but **faults at 256 experts** |
|
| 154 |
+
| `_C.abi3.so` | sm_110a, sm_80, sm_90 | core kernels |
|
| 155 |
+
| flashinfer `fused_moe_103.so` | sm_100a, sm_103a | **no sm_110a** β `VLLM_USE_FLASHINFER_MOE_FP4=0` |
|
| 156 |
+
| `gemm_sm120.so` / `trtllm_low_latency_gemm.so` | sm_120 / sm_100a | no Thor |
|
| 157 |
+
|
| 158 |
+
---
|
| 159 |
+
|
| 160 |
+
## Benchmarks β concurrency 1, single Thor, 120W, T=0
|
| 161 |
+
|
| 162 |
+
4 coding tasks (sorting / lru / dijkstra / mixed), 3-run median, `tok/s (Ο)`. Full k-sweeps in
|
| 163 |
+
[RESULTS.md](RESULTS.md); per-model files in [benchmarks/](benchmarks/).
|
| 164 |
+
|
| 165 |
+
**Qwen3.6-35B-A3B (MoE, marlin)** β k-sweep optimal **k=12** (avg 116.5 tok/s):
|
| 166 |
+
| k | sorting | lru | dijkstra | mixed | Ο_avg |
|
| 167 |
+
|---|---|---|---|---|---|
|
| 168 |
+
| 12 | 137.1/8.56 | 100.5/6.08 | 104.0/4.76 | 124.2/5.61 | 6.25 |
|
| 169 |
+
| 15 | 139.1/8.86 | 98.7/6.27 | 98.0/4.81 | 111.1/5.35 | 6.32 |
|
| 170 |
+
MoE profile @k=12: **marlin 117.5 avg > cutlass 106.3** β marlin default.
|
| 171 |
+
|
| 172 |
+
**Qwen3.6-27B (dense)** β k-sweep optimal **k=15** (avg 42.3 tok/s):
|
| 173 |
+
| k | sorting | lru | dijkstra | mixed | Ο_avg |
|
| 174 |
+
|---|---|---|---|---|---|
|
| 175 |
+
| 15 | 50.1/7.04 | 38.4/5.33 | 39.8/5.55 | 40.9/5.68 | 5.90 |
|
| 176 |
+
|
| 177 |
+
**Qwen3.5-122B-A10B (MoE, cutlass+TRITON_ATTN)** β optimal **k=10**, base 10.9 tok/s:
|
| 178 |
+
| k | sorting | lru | dijkstra | mixed | Ο_avg |
|
| 179 |
+
|---|---|---|---|---|---|
|
| 180 |
+
| 10 | 52.6/6.36 | 45.9/5.36 | 40.0/4.49 | 40.5/4.6 | 5.20 |
|
| 181 |
+
|
| 182 |
+
**Qwen3.5-4B (dense GDA-hybrid)** β optimal **k=15** (mixed 155.8), AR baseline 47.9 (dijkstra):
|
| 183 |
+
| k | sorting | lru | dijkstra | mixed | Ο_avg |
|
| 184 |
+
|---|---|---|---|---|---|
|
| 185 |
+
| 15 | 130.6/5.75 | 141.0/4.57 | 135.5/4.37 | 155.8/5.01 | 4.92 |
|
| 186 |
+
|
| 187 |
+
### Optimal-k pattern across model classes
|
| 188 |
+
`122B k=10 Β· 35B k=12 Β· 27B k=15 Β· 4B k=15`. **Cheaper-per-token models prefer higher k.** A dense
|
| 189 |
+
27B (or overhead-bound 4B) pays an expensive full-weight forward per verify, so each accepted token
|
| 190 |
+
saves a lot and the draft overhead is small relative to it β push k to the block max. A fast MoE
|
| 191 |
+
(35B, 3B active) hits the acceptance/overhead cliff sooner β lower optimal k.
|
| 192 |
+
|
| 193 |
+
### Roofline (NVFP4, 273 GB/s)
|
| 194 |
+
| model | active | AR ceiling | best DFlash | vs ceiling |
|
| 195 |
+
|---|---|---|---|---|
|
| 196 |
+
| 4B (GDA-hybrid) | 4B | 136.5 | 155.8 | **114%** |
|
| 197 |
+
| 27B dense | 27B | 20.2 | 50.1 | **248%** |
|
| 198 |
+
| 35B-A3B MoE | 3B | 182.0 | 139.1 | 76% |
|
| 199 |
+
| 122B-A10B MoE | 12B | 45.5 | 52.6 | **116%** |
|
| 200 |
+
DFlash's Ο amortization lets three of four models **exceed** their autoregressive bandwidth ceiling
|
| 201 |
+
at conc=1 β the verify step processes k+1 tokens per weight load, so effective tok/s β ceiling Γ Ο /
|
| 202 |
+
verify-cost. The 35B sits at 76% because it's already the fastest (3B active, overhead-bound).
|
| 203 |
+
|
| 204 |
+
---
|
| 205 |
+
|
| 206 |
+
## Why this matters: conc=1 single-node decode, and DFlash vs MTP
|
| 207 |
+
|
| 208 |
+
The realistic edge / agentic deployment on a single Thor is **concurrency 1** β one user, one stream,
|
| 209 |
+
latency-bound. In that regime, *all* of these current-gen NVFP4 models are **overhead- or
|
| 210 |
+
bandwidth-starved**: at conc=1 there's no batch to amortize kernel launches, so a 4B model runs at
|
| 211 |
+
only **35% of its bandwidth ceiling** autoregressively (47.9 / 136.5 tok/s), and a 122B is a slideshow
|
| 212 |
+
at 10.9 tok/s. This is exactly where speculative decoding pays off most, and where the *choice* of
|
| 213 |
+
speculator matters.
|
| 214 |
+
|
| 215 |
+
**DFlash (block diffusion) vs MTP (multi-token prediction) at conc=1:**
|
| 216 |
+
- **MTP** appends a few extra prediction heads (typically `num_speculative_tokens=3β4`) and drafts that
|
| 217 |
+
many tokens autoregressively-cheaply. Its draft *depth* and acceptance are inherently shallow.
|
| 218 |
+
- **DFlash** denoises a whole **block** (block_size 16 β k up to 15) **in parallel**, with a
|
| 219 |
+
non-causal drafter trained for it, reaching **acceptance length Ο β 4.5β8.9** here. Each target
|
| 220 |
+
forward then verifies ~5β9 tokens instead of MTP's ~2β3.
|
| 221 |
+
- At conc=1 the per-step target cost is fixed, so throughput β Ο / verify-cost. DFlash's **deeper,
|
| 222 |
+
higher-acceptance** drafts amortize that fixed cost across far more accepted tokens than MTP's
|
| 223 |
+
shallow drafts β which is why DFlash delivers the larger conc=1 speedups (we measured **1.7Γ** on
|
| 224 |
+
the 122B and **3.2Γ** on the overhead-bound 4B; z-lab reports up to **2.9Γ** vs AR at conc=1).
|
| 225 |
+
MTP's advantage only narrows at high concurrency, where batching already hides launch overhead β
|
| 226 |
+
the opposite of the single-Thor edge case.
|
| 227 |
+
|
| 228 |
+
**The practical upshot:** DFlash is what makes a **122B-class model usable interactively on one
|
| 229 |
+
117 GB edge box** (10.9 β ~52 tok/s peak), and turns a 4B into a 150+ tok/s coding assistant β on
|
| 230 |
+
hardware with no discrete VRAM, drawing 120 W. The optimal-k tuning per model (above) is the single
|
| 231 |
+
highest-value lever; the rest of the "optimizations" are noise (next section).
|
| 232 |
+
|
| 233 |
+
---
|
| 234 |
+
|
| 235 |
+
## Optimizations that DON'T help (so you don't chase them)
|
| 236 |
+
|
| 237 |
+
Measured honestly on Thor. See [hypotheses.md](hypotheses.md) and the per-model benchmark files.
|
| 238 |
+
- **`cudagraph_mode FULL_AND_PIECEWISE`**: **already the vLLM default** in this fork (confirmed in
|
| 239 |
+
the config dump). Explicitly setting it is a no-op. A thermally-controlled 122B same-session A/B
|
| 240 |
+
of the full opt set measured **+0.2%** (neutral). Apparent 35B/27B "regressions" vs the sweep
|
| 241 |
+
baselines were **thermal drift** from ~9 h continuous load, not the opts.
|
| 242 |
+
- **`VLLM_MARLIN_USE_ATOMIC_ADD=1`**: within run-to-run noise on the 35B (marlin); a **no-op** on the
|
| 243 |
+
27B (dense β FlashInfer-Cutlass GEMM, not marlin). Kept because it's free.
|
| 244 |
+
- **`VLLM_USE_FLASHINFER_SAMPLER=1`, `CUDA_DEVICE_MAX_CONNECTIONS=1`**: output-safe, neutral β kept.
|
| 245 |
+
- **MAXN power mode**: that's removing a power/thermal ceiling (overclocking), not a software lever.
|
| 246 |
+
All benchmarks here are 120W; MAXN is a separate, reversible knob.
|
| 247 |
+
- **Restricting `cudagraph_capture_sizes` to `[1,k+1]`**: no conc=1 benefit and would force eager
|
| 248 |
+
fallback at conc>1 β **not** baked into the serve defaults.
|
| 249 |
+
- **Dead ends:** `--moe-backend triton` (rejected for NVFP4), `VLLM_USE_FLASHINFER_MOE_FP4=1`
|
| 250 |
+
(no sm_110a kernel), FA3 (Hopper TMA), prefix-caching with GDA hybrid on long context (risky).
|
| 251 |
+
|
| 252 |
+
---
|
| 253 |
+
|
| 254 |
+
## Operational rules (Thor-specific)
|
| 255 |
+
1. `LD_PRELOAD=/usr/lib/aarch64-linux-gnu/nvidia/libcuda.so.1` β or `import vllm._C` dies with
|
| 256 |
+
`undefined symbol: cuPointerGetAttribute`.
|
| 257 |
+
2. Stop with **`docker kill`** / `pkill -9`, **never `docker stop`** (hangs + page-cache leak).
|
| 258 |
+
3. **Never `sudo fuser -k /dev/nvidia*`** β it kills Xorg/gnome-shell/RustDesk (display, not CUDA);
|
| 259 |
+
`docker kill` + `drop_caches` fully releases the GPU context.
|
| 260 |
+
4. `gpu_memory_utilization` allocates **unified** memory (= system RAM). Too high starves the OS and
|
| 261 |
+
hard-crashes the box β the 122B is the danger case (0.90 trips the precheck; use 0.78).
|
| 262 |
+
5. On Thor, `nvidia-smi` reports `[N/A]` for GPU memory β track `free -h` instead.
|
| 263 |
+
6. `drop_caches` before every 122B load (the 70 GB weight file fills the unified page cache).
|
| 264 |
+
7. 27B ships `tokenizer_class=TokenizersBackend` β patch overlay to `Qwen2Tokenizer` (`--tokenizer`).
|
| 265 |
+
8. `kv-cache-dtype auto` (BF16) for the DFlash draft path; the draft can reject quantized KV.
|
| 266 |
+
|
| 267 |
+
---
|
| 268 |
+
|
| 269 |
+
## Files
|
| 270 |
+
- `scripts/serve-{35b,27b,122b}.sh`, `scripts/_common.sh` β proven launch wrappers
|
| 271 |
+
- `scripts/ksweep-{4b,35b,27b,122b}.sh`, `scripts/bench.py`, `scripts/test-atomic-add.sh` β repro
|
| 272 |
+
- `benchmarks/{4b,35b,27b,122b-a10b}-optimizations.md` β per-model detail
|
| 273 |
+
- `moe-profiles/{35b-a3b,122b-a10b}-moe-profile.json` β MoE backend selection data
|
| 274 |
+
- `REVERT.md` β exact proven launch commands + revert steps Β· `BUILD-AND-DEBUG.md` β image build +
|
| 275 |
+
122B debug journey Β· `hypotheses.md` β what was tried Β· `RESULTS.md` β everything
|
| 276 |
+
|
| 277 |
+
## Model weights
|
| 278 |
+
- Bases (NVFP4): `Qwen3.5-4B-NVFP4`, `Qwen3.6-35B-A3B-NVFP4`, `Qwen3.6-27B-NVFP4`,
|
| 279 |
+
resharded `Qwen3.5-122B-A10B-NVFP4`
|
| 280 |
+
- DFlash drafts (`hf download z-lab/<name>`): `z-lab/Qwen3.5-4B-DFlash`, `z-lab/Qwen3.6-35B-A3B-DFlash`,
|
| 281 |
+
`z-lab/Qwen3.6-27B-DFlash`, `z-lab/Qwen3.5-122B-A10B-DFlash`
|
| 282 |
+
|
| 283 |
+
## Credits
|
| 284 |
+
DFlash is by [z-lab](https://github.com/z-lab/dflash) (Chen, Liang, Liu β arXiv:2602.06036). This
|
| 285 |
+
repo is the Thor SM110a port, debugging, and benchmarking. vLLM PR #40898.
|