Fork serve scripts
WIP / fork-source. See Verification status. Knobs below are the in-tree launcher on
opengfx1030/vllm-rdna(tools/rdna/serve_rdna.sh,tools/rdna/recipes/*.env,tunableop/README.md). Same path onrdna_extras(v0.31.0 as of 11 Oct 2026). The old 0.28 line isrdna_extra/v0.28.0. Build the venv first: Host venv. First-time V620 path: Onboard. Card-count picks stay on Recipes. Flash-Next graph history stays on Serve lines.
The fork ships one serve entry point under tools/rdna/ (moved from the old
scripts/ tree). A recipe file holds only that config’s deltas. The script owns
the venv, ROCm library path, TunableOp profile, GPU selection, cache roots,
stale-worker teardown, and the vllm serve argv.
Run it from a checkout of the branch you built (rdna_extras is the v0.31.0
line). Hub v0.31.0-extras is the matching Docker bake and already includes this
launcher’s PLE / P2P knobs:
MODEL=/path/to/checkpoint VENV=/path/to/venv \
bash tools/rdna/serve_rdna.sh RECIPE=<name> [KEY=value …]
MODEL and VENV (or an already-activated $VIRTUAL_ENV) are required. Nothing
in the script or the recipes bakes in a home directory, host, or IP.
RECIPE is a script argument (RECIPE=name on the command line). MODEL
and VENV are environment variables; a trailing KEY=value can set them too.
Precedence, lowest to highest: recipe file → caller environment → trailing
KEY=value.
The launcher defaults HF_HUB_OFFLINE=1 and TRANSFORMERS_OFFLINE=1. Pass a
local checkpoint in MODEL. To pull a Hub id on this run, export
HF_HUB_OFFLINE=0 and TRANSFORMERS_OFFLINE=0 in the caller environment.
2× Flash-Next expert offload is a sibling wrapper, not a RECIPE= row:
tools/rdna/mono/serve_offload.sh after #146
(28 Oct). Same MODEL / PLE_QUANT_DIR hygiene — 2× serve.
Recipes
Files live in tools/rdna/recipes/.
Copy one and change only the deltas to add a config.
| Recipe | Model / config | Defaults worth knowing |
|---|---|---|
flashnext-mtp2 | Flash-Next AWQ-W4A16, MTP=2. Recipe note (27 Sep 2026): MTP=2 wins at 8×16k / 1k, c=8. Daily 4× path. | TP=4, port 18096, API server, MAXLEN=262144, block size 1024, KV 4026531840, COMPILE_MODE=3, FULL_AND_PIECEWISE, ATTN=fa, V2 runner. #107 (16 Oct): GPU_MAX_HW_QUEUES=4 on Flash-Next TP4 recipes (launcher default stays 2). #130 (19 Oct): HIP set on by default (not Hub). Opt-in MonoKernel: EXTRA_ARGS="--monokernel" — serve. |
flashnext-dflash2 | Flash-Next AWQ-W4A16 + DFlash2 BF16 drafter. Merged #132 (21 Oct). Not Hub. MTP-2 still faster in the PR A/B. | Same TP4 / graphs family as flashnext-mtp2. Default 3 draft tokens; DFLASH_TOKENS=2 for the measured 16k c=8 ladder. Recipe sets EXTRA_ARGS=--monokernel. — DFlash2. |
flashnext-mtp0 | Same family, MTP=0. Recipe note: MTP=0 wins at 8×1k / 512, c=8 (short prompts). | Same ports and graphs as flashnext-mtp2, with MTP=0. |
flashnext | Flash-Next production stack: tools + reasoning, six in-flight sequences. Separate from flashnext-mtp0. | Port 18094, --host 0.0.0.0, CLI entry, KV 7000000000, gpu-memory-utilization 0.90, block size 1024, ATTN=fa, V2 runner. |
flashnext-exl3 | Flash-Next EXL3 (turboderp/Qwen3.8-Flash-Next-exl3). Merged #117 (17 Oct). Not Hub. | Port 18094, TP=4, MTP=0, PLE=exl3, expert-parallel on, FULL_AND_PIECEWISE, AOT compile off. Drafts #122/#123/#124 for MTP/vision/MoE. |
flashnext-pp3 | Flash-Next AWQ-W4A16, PP=3 / TP=1, MTP=0. Merged #96 (13 Oct). Not in Hub v0.31.0-extras. | Port 18096, partition 16,16,16, MAXLEN=262144, KV=auto, GMEM=0.95, SEQS=8, MAXBAT=2048, dense INT8 ONLY, text-only. PP3. |
flashnext-pp3-mtp2 | Same layout, MTP=2. Needs a W4A16 quantized drafter (tools/rdna/quant_mtp_experts.py). | Port 18097, partition 17,17,14, SEQS=4, MAXBAT=2112, GMEM=0.975. Use up to ~4 streams. |
27b-awq | Qwen3.8-27B AWQ INT4, compressed-tensors W4A16. HEAD after #140 (26 Oct): recipe defaults W4A8=1 (VLLM_RDNA2_W4A8_SDOT4 — int8-activation prefill for M≥33; decode stays W4A16). Hub bake may still default off — check PRINT=1. | Port 18210, MTP=0, KV 8000000000, no MAXLEN (the checkpoint’s own context). language-model-only. Prefill MAXBAT derived from KV/SSM dtype on HEAD. Set W4A8=0 to force W4A16 prefill. |
27b-exl3 | Qwen3.8-27B EXL3 3.00bpw mul1. Eager bring-up (EAGER=1): no torch.compile / CUDA graphs until you turn that off. | Port 18105, MAXLEN=20480, KV 6000000000. HIP_VISIBLE_DEVICES=4,5,6,7 (second PLX on an 8-GPU chassis). On a 4-card host set HIP_VISIBLE_DEVICES=0,1,2,3. |
dsv4-flash | DeepSeek-V4-Flash (K128): fp8 dense + MXFP4 experts. Needs verify. | Port 18300, TP=4, MAXLEN=32768, KV 6000000000, ATTN=none, --kv-cache-dtype fp8. This recipe does set VLLM_USE_BREAKABLE_CUDAGRAPH=1 (piecewise needs it on that model). |
full | The old serve_gfx1030_full.sh config (FA-RDNA2 + W4A16 + HIP KV + HIP GDN, breakable FULL_AND_PIECEWISE). | TP=2, devices 0,1, MAXLEN=200000 (floor 32768), KV 7000000000. HOST is empty so vLLM binds its default address. |
PLE / n-gram on current recipes
#announcements (11 Oct 2026): three PLE modes are tested on 4× V620 (speed at
parity under coding-agent load at 1k / 16k / 32k). The launcher knob is PLE=:
PLE= | What it does | Host RAM (launcher comments) |
|---|---|---|
bf16 (default if no quant dir) | Upstream pinned BF16 n-gram table | ~95 GB class |
int4 | INT4 table from PLE_QUANT_DIR in pinned RAM | ~30 GB table; #vllm-rdna (Oct 11) corrected an inflated ~90 GB host-RAM figure — INT4 sidecar working set is closer to ~35 GB |
int4-disk | Same INT4 table mmap’d from disk via the CPU sidecar (VLLM_PLE_CPU_OFFLOAD=1) | page cache only |
exl3 | EXL3 n-gram trellis (ngram_embedding.safetensors outside the model index). flashnext-exl3 only (#117) | ~32.6 GB at ng5, page cache (CPU sidecar mmap) |
PLE_QUANT_DIR (or VLLM_PLE_QUANT_DIR) must point at a ples_int4 directory
that contains META.json, from
primitive-ai/Qwen3.8-Flash-Next-PLE-quant.
Docker: -v /path/to/ples_int4:/ples_int4 -e VLLM_PLE_QUANT_DIR=/ples_int4 and,
for disk mode, -e VLLM_PLE_CPU_OFFLOAD=1. First-time path: Onboard.
See Flash-Next serve lines.
Do not paste these onto Flash-Next
#vllm-rdna (Oct 10): agent / Unsloth / old overlay pastes still break serves.
| Knob | Flash-Next (flashnext*) | Why |
|---|---|---|
VLLM_USE_BREAKABLE_CUDAGRAPH=1 | Remove | Turns compile off / wrong path on current recipes. Only dsv4-flash sets it on purpose. |
VLLM_RDNA_FUSED_HC=0 | Do not set | Fused hyper-connection is a small win now; leave the default on. |
| Gemini / old Hub Docker as Flash-Next | No | Use v0.31.0-extras (11 Oct bake) or host venv + this launcher. Do not treat v0.27.1-extras* / leapdragon GHCR as current Flash-Next. |
Recipes that omit HIP_VISIBLE_DEVICES use the harness default 0,1,2,3
(override with GPUIDS or HIP_VISIBLE_DEVICES).
Dry-run
PRINT=1 (aliases: DRY_RUN=1, --dry-run, -n) prints the recipe path, the
TunableOp profile it would select, the export block, and the exact command,
then exits. It does not launch vLLM. Print mode still requires MODEL and
VENV, and it skips the check that $VENV/bin/python exists.
MODEL=/path/to/checkpoint VENV=/path/to/venv \
PRINT=1 bash tools/rdna/serve_rdna.sh RECIPE=27b-exl3
Examples
Flash-Next speculative decode (MTP=2). Long context is where this recipe’s own note says MTP=2 wins:
MODEL=/path/to/flash-next VENV=/path/to/venv \
bash tools/rdna/serve_rdna.sh RECIPE=flashnext-mtp2 \
PLE=int4 PLE_QUANT_DIR=/path/to/ples_int4
No PCIe P2P on the host (#vllm-rdna Oct 11): add P2P=0 (sets VLLM_RDNA_AR=0
and NCCL_P2P_DISABLE=1; RCCL uses host shared memory). Also try
VLLM_RDNA_AR=0 by itself when output is garbage on a no-P2P box.
MODEL=/path/to/flash-next VENV=/path/to/venv \
bash tools/rdna/serve_rdna.sh RECIPE=flashnext-mtp2 \
PLE=int4 PLE_QUANT_DIR=/path/to/ples_int4 P2P=0
27B AWQ at MTP=2, with port and KV overrides:
MODEL=/path/to/qwen3.8-27b-awq VENV=/path/to/venv \
bash tools/rdna/serve_rdna.sh RECIPE=27b-awq MTP=2 KV=8000000000 PORT=18210
EXL3 stays eager unless you clear that flag. CG_MODE=FULL_AND_PIECEWISE is
already the recipe default; it applies once EAGER=0:
MODEL=/path/to/qwen3.8-27b-exl3 VENV=/path/to/venv \
bash tools/rdna/serve_rdna.sh RECIPE=27b-exl3 EAGER=0 CG_MODE=FULL_AND_PIECEWISE \
HIP_VISIBLE_DEVICES=0,1,2,3
Disable TunableOp lookups for an A/B:
MODEL=/path/to/flash-next VENV=/path/to/venv \
bash tools/rdna/serve_rdna.sh RECIPE=flashnext-mtp2 TUNABLEOP=0
Option map
| Knob | Role |
|---|---|
TP | --tensor-parallel-size (harness default 4). |
PORT / HOST | Bind address. Harness defaults 18094 and 127.0.0.1. An empty HOST (the full recipe) omits --host. |
MTP | 0 skips spec decode. 1+ adds MTP with num_speculative_tokens and local-argmax reduction. Capture sizes become (MTP+1) × {1,2,4,8} unless CG_SIZES is set. |
ATTN | fa → --attention-backend RDNA_ATTN. triton → TRITON_ATTN. none omits the flag (the recipe may still set VLLM_USE_RDNA2_FA). |
MAXLEN | --max-model-len. full also enforces MIN_MAXLEN (default floor 32768). |
BLOCK_SIZE | --block-size. |
SEQS | --max-num-seqs (default 8). |
MAXBAT | --max-num-batched-tokens (default 2048). |
LPTH | --long-prefill-token-threshold (static). Merged #36 can self-tune this when VLLM_RDNA_DYNAMIC_PREFILL=1. |
PREFILL_INTERVAL | --prefill-schedule-interval (static). Same #36 controller when the dynamic flag is on. |
KV | --kv-cache-memory-bytes. Required (a recipe with no KV budget aborts). |
GMEM | --gpu-memory-utilization. |
COMPILE_MODE | Compilation mode inside --compilation-config. |
CG_MODE | cudagraph_mode (default FULL_AND_PIECEWISE). |
CG_CAPTURE_SIZES | 1 (default) writes cudagraph_capture_sizes into the compile JSON. 0 leaves capture sizes to vLLM. |
CG_SIZES | Replaces the capture-size list itself (for example [1,2,4,8]). |
EAGER | 1 passes --enforce-eager and skips --compilation-config. |
TUNED_CONFIG | 1 points VLLM_TUNED_CONFIG_FOLDER at <tree>/tuned-moe. |
W4A8 | Maps to VLLM_RDNA2_W4A8_SDOT4 (27b-awq default 0). |
RDNA_AR | Maps to VLLM_RDNA_AR. |
PLE | bf16 / int4 / int4-disk. int4* needs PLE_QUANT_DIR (a ples_int4 dir with META.json). |
PLE_QUANT_DIR | Path to INT4 PLE shards. Alias: VLLM_PLE_QUANT_DIR. |
P2P | 1 (default) leaves topology alone. 0 forces VLLM_RDNA_AR=0 and NCCL_P2P_DISABLE=1. |
HIP_VISIBLE_DEVICES | GPU set. Alias: GPUIDS. |
TUNABLEOP | 1 (default) loads a profile. 0 sets PYTORCH_TUNABLEOP_ENABLED=0. |
FEATURES | Space-separated tokens (table below). |
EXTRA_ARGS | Extra words appended to the vLLM command. #vllm-rdna (16 Oct): EXTRA_ARGS="--monokernel" turns on Flash-Next MonoKernel (#94) — same as VLLM_ROCM_MONO_DECODE=1. Off by default. MonoKernel. |
Legacy names the entry point still accepts: MODEL←MODEL_PATH,
KV←KVCAP←KV_CACHE_MEMORY, SEQS←MAX_NUM_SEQS,
MAXBAT←MAX_BATCHED_TOKENS, MAXLEN←MAX_MODEL_LEN, GMEM←GPU_MEM.
FEATURES tokens the script knows:
| Token | Flag |
|---|---|
prefix-caching | --enable-prefix-caching. Merged #97 (14 Oct): ENABLE_PREFIX_CACHING=0 now passes --no-enable-prefix-caching. Omitting the flag used to leave prefix cache on (vLLM default) — a “cache off” run still showed hits. |
language-model-only | --language-model-only |
skip-mm-profiling | --skip-mm-profiling |
mamba-align | --mamba-cache-mode align |
reasoning | --reasoning-parser qwen3 |
auto-tool | --enable-auto-tool-choice --tool-call-parser qwen3_coder |
expert-parallel | --enable-expert-parallel |
trust-remote-code | --trust-remote-code |
prompt-tokens-details | --enable-prompt-tokens-details — #vllm-rdna (Oct 7): DeepSeek / Pi harnesses that always show 0% cache hits usually lack this metadata flag, not a dead prefix cache. |
vision-cap | --limit-mm-per-prompt '{"image":1}' and --mm-processor-kwargs '{"max_pixels":1605632}' |
An unknown token aborts. vision-cap is how Flash-Next recipes keep the pixel
cap that prevents the vision-encoder startup OOM — see
Flash-Next serve lines.
TunableOp
Rows are named profiles, one folder per rocBLAS build, registered in
tunableop/profiles.json.
Solver IDs are build-specific. The helper
(tools/rdna2_028/tunableop_env.sh) selects the folder whose
lib_sha256[:12] matches the loaded librocblas.so.5.
| Profile | rocBLAS / torch | librocblas.so.5 sha256[:12] | Rows / rank |
|---|---|---|---|
rocm7.14-rocblas5.5/ | 5.5.0 / 2.12.0+rocm7.14.0 | f30bb442e9b5 | 783 (canonical). Covers Flash-Next MTP=0/2, 27B AWQ, and EXL3 27B. |
rocm10-rocblas5.6/ | 5.6.0 / 2.13.0+rocm10.0.0 | c27e2252cc7a | 70, thin. Those shapes are tuned; every other GEMM uses the rocBLAS heuristic. |
- Auto-select is the default. No recipe or launcher change is required when the venv’s
librocblas.so.5hash changes. A ROCm 7.14 start logsTunableOp profile rocm7.14-rocblas5.5 auto-selected for rocBLAS build f30bb442e9b5. TUNABLEOP_PROFILE=<name>forces a registered profile. A hash mismatch fails the launch.TUNABLEOP_ALLOW_MISMATCH=1is the experiment-only override (hard warning, then it uses the rows anyway). Solver IDs are build-specific, so a mismatched profile is never applied silently.- Lookup is read-only (
PYTORCH_TUNABLEOP_TUNING=0). The helper does not write rows to/tmpor the process CWD. If no profile matches, it uses a legacyrocblas-<hash>/folder when that folder exists, then$HOME/.cache/tunableop/tunableop_results.csv. TUNABLEOP=0turns lookups off (PYTORCH_TUNABLEOP_ENABLED=0) for an A/B against the heuristic.PRINT=1reports which profile it would pick, including “NOT registered” ifTUNABLEOP_PROFILEis unknown.
ROCm 10 and rocBLAS 5.6
A venv whose torch loads rocBLAS 5.6 (librocblas.so.5 sha256[:12] c27e2252cc7a) selects rocm10-rocblas5.6 by that hash. Same recipe, same script:
MODEL=/path/to/checkpoint VENV=/path/to/rocm10-venv \
bash tools/rdna/serve_rdna.sh RECIPE=27b-awq
MODEL=/path/to/checkpoint VENV=/path/to/rocm10-venv \
PRINT=1 bash tools/rdna/serve_rdna.sh RECIPE=27b-awq
Print mode (library present in that venv) reports:
# tunableop: rocm10-rocblas5.6 (auto-selected for librocblas.so.5 c27e2252cc7a)
A real launch logs TunableOp profile rocm10-rocblas5.6 auto-selected for rocBLAS build c27e2252cc7a.
Thin means the shipped CSV covers 70 shapes per rank. Those GEMMs use the recorded solver. Every other shape falls back to the rocBLAS heuristic: safe, and untuned. The validated serving numbers on this wiki were captured on gfx1030 + ROCm 7.14 (rocm7.14-rocblas5.5, 783 rows). Recipe knobs (TP, KV, MTP, graphs) do not depend on the ROCm version. Treat the first ROCm 10 boot as bring-up: run PRINT=1 and confirm the profile line before leaving it up.
#vllm-rdna (Oct 1): hosts not on rocBLAS 5.5 + ROCm 7.14 do not get the canonical
783-row benefit from the serve script — they need a matching profile (the thin ROCm 10 set,
a local $HOME/.cache/tunableop/ table, or a contributed CSV). The shipped 7.14 rows are the
4-card serving set; 8× shapes were not in that table yet — generate local rows on
that host rather than expecting a silent speedup.
To fill the gap on that machine, tune there and register the result. The in-tree pipeline keeps scratch under <tree>/cache/tunableop-rows (never /tmp) and does not overwrite the repo profile:
VENV=/path/to/rocm10-venv \
bash tools/rdna2_028/tunableop_rows_pipeline.sh tune
Curate with tools/rdna2_028/curate_tunableop_rows.py, freeze the CSVs into tunableop/<profile-name>/, and add that name to profiles.json with this library’s sha256. Then prove the lookup actually hits:
python tools/rdna2_028/verify_tunableop_lookup.py \
--rows tunableop/<profile-name>/tunableop_results0.csv \
--out hits.json
A hit means the solver TunableOp recorded equals the shipped row. Contributing that profile back is how the 70-row set grows. The older qualify flow is still documented under Regenerate for another rocBLAS build.
Guardrails for a ROCm 10 (or any other) library:
| Situation | What happens |
|---|---|
Loaded sha is c27e2252cc7a | Auto-selects rocm10-rocblas5.6. |
| Loaded sha matches neither profile | Legacy tunableop/rocblas-<sha12>/ if that folder exists, otherwise $HOME/.cache/tunableop/tunableop_results.csv. The 7.14 rows are not loaded. |
TUNABLEOP_PROFILE=rocm10-rocblas5.6 but the loaded library is a different sha | Launch refuses to start. |
TUNABLEOP_ALLOW_MISMATCH=1 | Proceeds with a hard warning. Experiments only. |
TUNABLEOP=0 | Lookups off. |
Mismatch symptoms and the historical ~25% prefill gap: TunableOp troubleshooting.
Foreground, aliases, stale workers
serve_rdna.sh execs in the foreground. Background it yourself and poll
readiness:
MODEL=/path/to/checkpoint VENV=/path/to/venv \
nohup bash tools/rdna/serve_rdna.sh RECIPE=27b-awq >serve.log 2>&1 &
# port follows the recipe (27b-awq is 18210)
curl -sf http://127.0.0.1:18210/v1/models
Before exec, the harness signals processes whose environment has the same
VLLM_CACHE_ROOT (API server, VLLM::Worker, VLLM::EngineCore,
PleOffloadWorker). The default cache root is <tree>/cache/vllm. A second
serve that shares that root will tear the first one down.
The old filenames are thin aliases. They forward the environment and any
trailing KEY=value:
| Old script | Calls |
|---|---|
tools/rdna/serve_gfx1030_flashnext.sh | RECIPE=flashnext |
tools/rdna/serve_gfx1030_flashnext_mtp.sh | RECIPE=flashnext-mtp2 |
tools/rdna/serve_gfx1030_27b_dense.sh | RECIPE=27b-awq |
tools/rdna/serve_gfx1030_exl3_27b.sh | RECIPE=27b-exl3 |
tools/rdna/serve_gfx1030_full.sh | RECIPE=full |
Related
- Host venv — build the tree this script expects
- Recipes — Hub image vs recipe container vs this checkout
- Flash-Next serve lines — graph modes and PLE
- Environment variables
- TunableOp mismatch