Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 on rdna_extras (v0.31.0 as of 11 Oct 2026). The old 0.28 line is rdna_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.

RecipeModel / configDefaults worth knowing
flashnext-mtp2Flash-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-dflash2Flash-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-mtp0Same 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.
flashnextFlash-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-exl3Flash-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-pp3Flash-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-mtp2Same 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-awqQwen3.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-exl3Qwen3.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-flashDeepSeek-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).
fullThe 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 doesHost RAM (launcher comments)
bf16 (default if no quant dir)Upstream pinned BF16 n-gram table~95 GB class
int4INT4 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-diskSame INT4 table mmap’d from disk via the CPU sidecar (VLLM_PLE_CPU_OFFLOAD=1)page cache only
exl3EXL3 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.

KnobFlash-Next (flashnext*)Why
VLLM_USE_BREAKABLE_CUDAGRAPH=1RemoveTurns compile off / wrong path on current recipes. Only dsv4-flash sets it on purpose.
VLLM_RDNA_FUSED_HC=0Do not setFused hyper-connection is a small win now; leave the default on.
Gemini / old Hub Docker as Flash-NextNoUse 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

KnobRole
TP--tensor-parallel-size (harness default 4).
PORT / HOSTBind address. Harness defaults 18094 and 127.0.0.1. An empty HOST (the full recipe) omits --host.
MTP0 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.
ATTNfa → --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_MODECompilation mode inside --compilation-config.
CG_MODEcudagraph_mode (default FULL_AND_PIECEWISE).
CG_CAPTURE_SIZES1 (default) writes cudagraph_capture_sizes into the compile JSON. 0 leaves capture sizes to vLLM.
CG_SIZESReplaces the capture-size list itself (for example [1,2,4,8]).
EAGER1 passes --enforce-eager and skips --compilation-config.
TUNED_CONFIG1 points VLLM_TUNED_CONFIG_FOLDER at <tree>/tuned-moe.
W4A8Maps to VLLM_RDNA2_W4A8_SDOT4 (27b-awq default 0).
RDNA_ARMaps to VLLM_RDNA_AR.
PLEbf16 / int4 / int4-disk. int4* needs PLE_QUANT_DIR (a ples_int4 dir with META.json).
PLE_QUANT_DIRPath to INT4 PLE shards. Alias: VLLM_PLE_QUANT_DIR.
P2P1 (default) leaves topology alone. 0 forces VLLM_RDNA_AR=0 and NCCL_P2P_DISABLE=1.
HIP_VISIBLE_DEVICESGPU set. Alias: GPUIDS.
TUNABLEOP1 (default) loads a profile. 0 sets PYTORCH_TUNABLEOP_ENABLED=0.
FEATURESSpace-separated tokens (table below).
EXTRA_ARGSExtra 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:

TokenFlag
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.

ProfilerocBLAS / torchlibrocblas.so.5 sha256[:12]Rows / rank
rocm7.14-rocblas5.5/5.5.0 / 2.12.0+rocm7.14.0f30bb442e9b5783 (canonical). Covers Flash-Next MTP=0/2, 27B AWQ, and EXL3 27B.
rocm10-rocblas5.6/5.6.0 / 2.13.0+rocm10.0.0c27e2252cc7a70, 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.5 hash changes. A ROCm 7.14 start logs TunableOp 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=1 is 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 /tmp or the process CWD. If no profile matches, it uses a legacy rocblas-<hash>/ folder when that folder exists, then $HOME/.cache/tunableop/tunableop_results.csv.
  • TUNABLEOP=0 turns lookups off (PYTORCH_TUNABLEOP_ENABLED=0) for an A/B against the heuristic.
  • PRINT=1 reports which profile it would pick, including “NOT registered” if TUNABLEOP_PROFILE is 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:

SituationWhat happens
Loaded sha is c27e2252cc7aAuto-selects rocm10-rocblas5.6.
Loaded sha matches neither profileLegacy 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 shaLaunch refuses to start.
TUNABLEOP_ALLOW_MISMATCH=1Proceeds with a hard warning. Experiments only.
TUNABLEOP=0Lookups 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 scriptCalls
tools/rdna/serve_gfx1030_flashnext.shRECIPE=flashnext
tools/rdna/serve_gfx1030_flashnext_mtp.shRECIPE=flashnext-mtp2
tools/rdna/serve_gfx1030_27b_dense.shRECIPE=27b-awq
tools/rdna/serve_gfx1030_exl3_27b.shRECIPE=27b-exl3
tools/rdna/serve_gfx1030_full.shRECIPE=full