上下文推理延遲實(shí)測(cè):hipBLASLt 與 HIP 編譯器配置怎么調(diào))
1. 長(zhǎng)上下文推理延遲為什么你調(diào)了參數(shù)卻沒(méi)變化ROCm 7.x 在 GPU 長(zhǎng)上下文推理場(chǎng)景下的延遲表現(xiàn)是最近不少做本地部署的團(tuán)隊(duì)都在盯的事。長(zhǎng)上下文推理指的是輸入序列超過(guò) 32k tokens 之后Prefill 階段的計(jì)算量和顯存帶寬壓力會(huì)急劇上升首字延遲TTFT和每 token 生成延遲TPOT都會(huì)明顯劣化。適合關(guān)注這個(gè)話題的人包括手里有 AMD Instinct 系列或 Radeon Pro 系列 GPU、正在跑 vLLM 或 PyTorch 原生推理、并且發(fā)現(xiàn)升級(jí) ROCm 之后延遲沒(méi)有預(yù)期下降的開(kāi)發(fā)者。我試過(guò)在同一臺(tái)機(jī)器上只改環(huán)境變量和編譯參數(shù)不改模型代碼觀察 TTFT 的變化。結(jié)論是延遲變化往往不是版本本身帶來(lái)的而是 hipBLASLt 的算子選擇路徑和 HIP 編譯器的調(diào)度策略有沒(méi)有被正確激活。很多人升級(jí)完 ROCm 7.x 就直接跑結(jié)果發(fā)現(xiàn)和舊版差不多原因就在這里——默認(rèn)配置下hipBLASLt 可能仍然走了稠密路徑HIP 編譯器也沒(méi)有開(kāi)啟針對(duì)長(zhǎng)序列的指令重排優(yōu)化。這篇文章從兩個(gè)可調(diào)項(xiàng)切入hipBLASLt 的運(yùn)行時(shí)環(huán)境變量以及 HIP 編譯器的編譯參數(shù)骨架。我會(huì)給出可復(fù)制的配置、對(duì)照驗(yàn)證動(dòng)作以及怎么判斷延遲變化到底來(lái)自版本特性還是配置差異。全程不涉及任何網(wǎng)絡(luò)層操作只聚焦在軟件棧本身的調(diào)優(yōu)。2. TaoToken 前置先把模型服務(wù)和 API 入口理清楚在開(kāi)始調(diào) ROCm 之前建議先把推理服務(wù)的調(diào)用鏈路固定下來(lái)。如果你是用 vLLM 起本地服務(wù)再通過(guò) OpenAI 兼容接口調(diào)用那么模型對(duì)話入口可以用 TaoToken 的模型對(duì)話頁(yè)面來(lái)做快速驗(yàn)證確認(rèn)你的請(qǐng)求格式和返回結(jié)構(gòu)沒(méi)問(wèn)題。這一步的意義在于把「模型服務(wù)本身是否正?!购汀窻OCm 配置是否生效」兩個(gè)變量分開(kāi)否則你很難判斷延遲變化到底來(lái)自哪一層。TaoToken 的 API 入口是 https://taotoken.net/api 接入文檔在 https://taotoken.net/doc 。如果你要長(zhǎng)期跑編碼類(lèi)或 Agent 類(lèi)任務(wù)可以看 Coding Plan 頁(yè)面如果只是驗(yàn)證模型輸出是否符合預(yù)期直接用模型對(duì)話即可。API Keys 管理在 https://taotoken.net/api-keys 控制臺(tái)在 https://taotoken.net/console 。需要強(qiáng)調(diào)的是TaoToken 在這里的角色是模型調(diào)用入口和驗(yàn)證工具不是用來(lái)替代你的本地推理引擎。你的 GPU 推理仍然跑在本地 ROCm 環(huán)境里TaoToken 幫你確認(rèn)請(qǐng)求鏈路和模型行為是否一致。這樣在調(diào) hipBLASLt 和 HIP 編譯器時(shí)你有一個(gè)穩(wěn)定的參照系。3. 可復(fù)制配置hipBLASLt 環(huán)境變量與 HIP 編譯參數(shù)骨架3.1 hipBLASLt 運(yùn)行時(shí)環(huán)境變量hipBLASLt 是 ROCm 里的矩陣乘法庫(kù)長(zhǎng)上下文推理中 Attention 和 FFN 的 GEMM 都走它。ROCm 7.x 對(duì)稀疏路徑和內(nèi)核選擇做了調(diào)整但默認(rèn)不一定開(kāi)啟。你可以通過(guò)以下環(huán)境變量控制它的行為# 開(kāi)啟 hipBLASLt 的日志確認(rèn)實(shí)際走了哪個(gè)內(nèi)核 export HIPBLASLT_LOG_LEVEL3 export HIPBLASLT_LOG_MASK32 # 允許 hipBLASLt 使用更激進(jìn)的算法選擇 export HIPBLASLT_TUNING1 # 針對(duì)長(zhǎng)序列優(yōu)先使用 split-K 內(nèi)核 export HIPBLASLT_USE_SPLIT_K1 # 控制 workspace 大小長(zhǎng)上下文下適當(dāng)放大 export HIPBLASLT_WORKSPACE_SIZE134217728這些變量的作用分別是日志級(jí)別幫你確認(rèn)內(nèi)核路徑TUNING 讓庫(kù)在首次運(yùn)行時(shí)做算法搜索SPLIT_K 在長(zhǎng)序列 GEMM 中把 K 維度切分提升并行度WORKSPACE_SIZE 給算法搜索留出足夠顯存。注意 WORKSPACE_SIZE 不要設(shè)得過(guò)大否則會(huì)和 KV Cache 搶顯存。3.2 HIP 編譯器編譯參數(shù)如果你有自定義 Kernel 或者用 PyTorch 的 hipify 路徑HIP 編譯器的參數(shù)會(huì)直接影響生成的機(jī)器碼質(zhì)量。以下是一個(gè)針對(duì)長(zhǎng)上下文推理的編譯骨架hipcc -O3 \ --offload-archgfx942 \ -mllvm -amdgpu-early-inline-alltrue \ -mllvm -amdgpu-function-callsfalse \ -mllvm -amdgpu-sroa1 \ -mllvm -amdgpu-load-store-vectorizer1 \ -mllvm -amdgpu-scalarize-global-loads1 \ -mllvm -amdgpu-unroll-threshold1000 \ -o kernel.out kernel.hip其中--offload-arch要換成你實(shí)際的 GPU 架構(gòu)比如 MI300X 是 gfx942。-amdgpu-early-inline-all和-amdgpu-function-callsfalse減少函數(shù)調(diào)用開(kāi)銷(xiāo)-amdgpu-sroa做標(biāo)量替換聚合減少寄存器壓力-amdgpu-load-store-vectorizer合并內(nèi)存訪問(wèn)-amdgpu-unroll-threshold提高循環(huán)展開(kāi)閾值讓長(zhǎng)序列循環(huán)體更緊湊。如果你是用 vLLM 或 PyTorch編譯參數(shù)通常通過(guò)TORCH_HIPCC_FLAGS或框架的編譯選項(xiàng)傳入export TORCH_HIPCC_FLAGS-O3 -mllvm -amdgpu-early-inline-alltrue -mllvm -amdgpu-function-callsfalse3.3 vLLM 側(cè)的關(guān)鍵配置vLLM 在 ROCm 下有幾個(gè)和長(zhǎng)上下文直接相關(guān)的參數(shù)python -m vllm.entrypoints.openai.api_server \ --model /path/to/model \ --max-model-len 65536 \ --block-size 16 \ --gpu-memory-utilization 0.90 \ --enforce-eager false \ --disable-log-requests--max-model-len決定 KV Cache 上限--block-size影響 PagedAttention 的碎片率長(zhǎng)上下文下 16 比 32 更穩(wěn)--enforce-eager false允許 CUDA Graph 等價(jià)路徑減少 kernel launch 開(kāi)銷(xiāo)。注意 ROCm 下 Graph 支持程度和版本有關(guān)如果遇到不穩(wěn)定可以回退到 eager。4. 驗(yàn)證請(qǐng)求與成功結(jié)果怎么確認(rèn)配置真的生效配置寫(xiě)完不代表生效。你需要做三件事確認(rèn) hipBLASLt 走了預(yù)期內(nèi)核、確認(rèn)編譯參數(shù)被應(yīng)用、確認(rèn)端到端延遲有變化。4.1 確認(rèn) hipBLASLt 內(nèi)核路徑開(kāi)啟日志后發(fā)一個(gè)長(zhǎng)上下文請(qǐng)求觀察日志里出現(xiàn)的 kernel 名稱(chēng)。如果看到Cijk_開(kāi)頭的 split-K 內(nèi)核說(shuō)明 SPLIT_K 生效如果全是稠密內(nèi)核說(shuō)明你的環(huán)境變量沒(méi)被讀取。檢查方式HIPBLASLT_LOG_LEVEL3 python -m vllm.entrypoints.openai.api_server ... 21 | grep -i Cijk4.2 確認(rèn)編譯參數(shù)生效對(duì)于自定義 Kernel可以用roc-obj或llvm-objdump反匯編看指令序列里內(nèi)存加載和計(jì)算指令是否交錯(cuò)llvm-objdump -d --arch-namegfx942 kernel.out | head -100如果看到連續(xù)的global_load后面才跟v_fma說(shuō)明調(diào)度沒(méi)優(yōu)化好如果 load 和 fma 交錯(cuò)出現(xiàn)說(shuō)明指令級(jí)并行生效。4.3 端到端延遲對(duì)照用同一個(gè)模型、同一個(gè)輸入長(zhǎng)度建議 32k tokens分別跑默認(rèn)配置和調(diào)優(yōu)配置記錄 TTFT 和 TPOT。請(qǐng)求示例curl http://localhost:8000/v1/completions \ -H Content-Type: application/json \ -d { model: /path/to/model, prompt: $(python -c print(token * 32000)), max_tokens: 128, temperature: 0 }成功的結(jié)果是TTFT 下降TPOT 波動(dòng)收窄。如果 TTFT 沒(méi)變但 TPOT 變穩(wěn)說(shuō)明 Prefill 階段沒(méi)吃到 hipBLASLt 的優(yōu)化重點(diǎn)查 SPLIT_K 和 workspace如果兩者都沒(méi)變說(shuō)明環(huán)境變量沒(méi)被框架讀取檢查 vLLM 啟動(dòng)時(shí)是否繼承了這些變量。5. 本篇常見(jiàn)錯(cuò)排查5.1 環(huán)境變量沒(méi)生效最常見(jiàn)的問(wèn)題是 vLLM 通過(guò) systemd 或容器啟動(dòng)環(huán)境變量沒(méi)傳進(jìn)去。檢查方式是在服務(wù)進(jìn)程里打印cat /proc/$(pgrep -f vllm)/environ | tr \0 \n | grep HIPBLASLT如果沒(méi)有輸出說(shuō)明變量沒(méi)繼承。解決方式是在啟動(dòng)腳本里顯式 export或者用docker run -e傳入。5.2 編譯參數(shù)被框架覆蓋PyTorch 和 vLLM 有自己的編譯流程TORCH_HIPCC_FLAGS可能被框架內(nèi)部覆蓋。驗(yàn)證方式是看編譯日志里實(shí)際的 hipcc 命令行。如果發(fā)現(xiàn)參數(shù)被截?cái)喔挠每蚣芴峁┑臄U(kuò)展編譯接口或者把自定義 Kernel 單獨(dú)編譯成 .so 再加載。5.3 長(zhǎng)上下文下顯存不足導(dǎo)致回退如果 WORKSPACE_SIZE 設(shè)得太大或者 max-model-len 超過(guò)顯存vLLM 會(huì)回退到更保守的 kernel延遲反而上升。觀察日志里是否有fallback或out of memory關(guān)鍵字。解決方式是降低 workspace 或 block-size先保證不 OOM再談優(yōu)化。5.4 版本差異和配置差異混淆判斷延遲變化來(lái)自版本還是配置最干凈的做法是固定配置、只換 ROCm 版本跑一組再固定版本、只換配置跑一組。兩組數(shù)據(jù)對(duì)比才能分離變量。如果只換版本就有提升說(shuō)明是 ROCm 7.x 的庫(kù)和編譯器默認(rèn)行為變了如果只換配置才有提升說(shuō)明你之前的默認(rèn)配置沒(méi)吃滿硬件。5.5 日志級(jí)別開(kāi)太高拖慢性能HIPBLASLT_LOG_LEVEL3 會(huì)打印大量日志本身會(huì)拖慢推理。驗(yàn)證完內(nèi)核路徑后記得關(guān)掉否則你測(cè)出來(lái)的延遲包含日志開(kāi)銷(xiāo)。6. 語(yǔ)義一致 CTA把驗(yàn)證鏈路固定下來(lái)調(diào)完 hipBLASLt 和 HIP 編譯器之后建議把模型調(diào)用入口固定成一條穩(wěn)定鏈路這樣后續(xù)換版本、換配置時(shí)有一個(gè)不變的參照。模型對(duì)話入口可以用來(lái)快速確認(rèn)模型輸出是否正常接入文檔里有完整的請(qǐng)求格式和參數(shù)說(shuō)明。如果你要長(zhǎng)期跑編碼或 Agent 任務(wù)Coding Plan 頁(yè)面有對(duì)應(yīng)的配置建議。API Keys 在 https://taotoken.net/api-keys 管理控制臺(tái)在 https://taotoken.net/console 。整個(gè)調(diào)優(yōu)過(guò)程的核心不是記住某幾個(gè)環(huán)境變量而是建立「改一個(gè)變量、跑一組對(duì)照、看一個(gè)指標(biāo)」的循環(huán)。ROCm 7.x 的庫(kù)和編譯器確實(shí)給了更多可調(diào)空間但空間越大越需要你用對(duì)照實(shí)驗(yàn)去確認(rèn)每一個(gè)改動(dòng)的實(shí)際收益。