改裝 2080 Ti 22G · part 21
雙 2080 Ti FastLLM 升級:寫程式快 16%、兩人同時用,長請求不再擋人
❯ cat --toc
- 前言
- 這版跟上一篇差在哪:速度、並行、插隊三件事
- 速度:撤掉 d4b04876,再把草稿轉 NVFP4
- 兩個請求同時跑:拿掉 --tokens,max_batch 才會生效
- 長請求不再擋人:排程器在每一塊之間讓出來
- 怎麼編:上游 a2bf07fd、撤掉一個 commit、合併兩個 PR
- 啟動指令
- 會卡住你的四件事
- 能力:140 題 132 / 127
- 那,還能更快嗎?
- 進階:除錯與實驗紀錄
- git bisect 87 個 commit:一步 10 分鐘
- logprobs patch:零影響
- CUDA Graph:「Resource deadlock avoided」是假線索
- 草稿 token 數與其他開關
- 並行:三次才試對
- 排程器:卡在哪一行
- 壓力測試抓到的兩個退步
- 送上游前的三輪 code review
- 版本鎖定
- 還沒做的
TL;DR
兩張改裝 2080 Ti 22G 的 FastLLM + DFlash2 換成自編的上游最新版:寫程式 116.1 tok/s(同一組題目原本 100.3)、數學 135.5、散文 74.2。兩個請求可以同時跑,一條 54K token 的長請求在讀 prompt 時,短請求 1.1 秒就開始回(原本等 39.5 秒)。做法是撤掉一個讓草稿猜中率下降的上游 commit、把草稿轉 NVFP4、改排程器;排程器那兩項已送上游 PR #755、#756。

前言
超市只開一個結帳櫃台的時候,前面那台推車堆滿月底大採購,後面只拿一瓶水的人也得乾等。
上一篇把 FastLLM + DFlash2 換上這兩張卡之後,它同時要接好幾個 agent 的請求,但一次只處理一個。只要有人丟進一段幾萬 token 的長文,其他人的短問題就排在後面 40 秒。
這一週把它改成這樣:三種題目都快了 14% 到 16%,兩個請求可以同時跑,長請求在讀 prompt 的時候,短請求一秒多就開始回。
這版跟上一篇差在哪:速度、並行、插隊三件事
先看結果,重點在最後一欄的第一和第三列。兩組都是同一台機器、同一支量測腳本,前後各量一次:
| 兩張 2080 Ti,TP=2,Qwen3.8-27B FP8 | 上一篇的設定 | 這一版 |
|---|---|---|
| 寫程式 / 數學 / 散文(tok/s) | 100.3 / 118.6 / 64.8 | 116.1 / 135.5 / 74.2 |
| 同時處理的請求數 | 1 | 2(兩條合計 175.8) |
| 54K token 的請求讀 prompt 時,短請求等第一個字(p95) | 39.5 秒 | 1.13 秒 |
| 取消一個長請求後,下一個請求等第一個字(最大值) | 9.8 秒 | 0.54 秒 |
| 每個請求的 context 上限 | 262,144 | 222,080 |
140 題能力測試(不開思考 / 開思考)是 128 / 125 對 132 / 127,細節在後面。
量法:真實的 chat 請求,temperature 0,每次 512 token,三種題目各打三發取中位數。插隊和取消那兩列是 33 分鐘壓力測試(同一個亂數種子,8 輪、112 個請求)的結果。這組寫程式題要求附大量註解和說明,數字會比純程式碼的題目低。用上一篇那三題量,這一版是寫程式 175.3、數學 154.1、散文 64.7。
三件事是分開做的:
- 速度:換上游最新的 master,撤掉其中一個 commit,再把 DFlash2 草稿轉成 NVFP4。
- 兩個請求同時跑:
--max_batch 2,同時拿掉--tokens。 - 長請求不擋人:改排程器,讓它在長 prompt 的每一塊之間讓出來。
速度:撤掉 d4b04876,再把草稿轉 NVFP4
上一篇用的 FastLLM 停在 9 月 21 日的 14f849af。上游到 9 月 25 日的 a2bf07fd 多了 87 個 commit,直接換上去,數學和散文變快,寫程式反而掉了 15%。
我用同一支腳本對這 87 個 commit 做 git bisect,找到是 d4b04876「修复小批量 RMSNorm 归约舍入差异」。它改的是寬度 5120、batch 1 到 8 的 RMSNorm kernel,主模型和 DFlash2 草稿的 hidden size 剛好都是 5120。換上它之後,草稿第 3 個位置的接受率從 60.9% 掉到 43.5%,被主模型退回的猜測變多,吐字就慢了。
撤掉這一個 commit,再打開草稿的 NVFP4 量化(FASTLLM_DRAFT_QUANT=nvfp4,上游 7e0d6705 把它改成預設開啟)。看寫程式那一欄,第二列掉下去、後兩列拿回來:
| 版本 | 寫程式 | 數學 | 散文 |
|---|---|---|---|
上一篇的設定(14f849af) | 100.3 | 118.6 | 64.8 |
上游最新 a2bf07fd,草稿不量化 | 84.8 | 126.9 | 68.1 |
+ 撤掉 d4b04876 | 102.6 | 122.1 | 70.9 |
| + 草稿轉 NVFP4 | 116.6 | 135.8 | 74.7 |
草稿是一顆 5 層、3.6GB 的小模型,每一步都要跑。它的權重變小,猜的那段時間就變短,主模型驗的次數不變,整體吐字就快了。這一步只改草稿,主模型的權重完全沒動,所以不影響回答的內容。
要先講清楚:d4b04876 是上游為了讓不同 kernel 算出一致結果做的修正。我拿 FP32 當參考值比對新舊兩個 kernel,誤差一樣大,沒找到它算錯的證據。撤掉它是因為在這組硬體加 DFlash2 上它讓猜中率變低,換一張卡可能完全不受影響。
兩個請求同時跑:拿掉 --tokens,max_batch 才會生效
把 --max_batch 1 改成 2,其他不動,重啟後兩個請求還是一條一條輪流跑。log 裡有一行:
explicit-token safety max_batch limited 2 -> 1
Qwen3.8 是混合架構,大部分層用的是 GDN(一種線性注意力),每個請求除了 KV cache 還要帶一份不小的遞迴狀態。FastLLM 在你用 --tokens 明確指定 context 長度時,會把這些狀態的預算限制在 KV 空間的 25% 以內;我這組只放得下一個請求,它就默默把並行數壓回 1。這個 25% 寫死在程式裡,沒有開關可以調。
拿掉 --tokens,讓它自己算 KV 頁數,並行才會生效:
| 設定 | 實際並行 | 單條寫程式 | 兩條同時,合計 | 每個請求的 context 上限 |
|---|---|---|---|---|
--max_batch 2 --tokens 262144 | 1(被壓回) | 116.9 | 約 117(輪流) | 262,144 |
--max_batch 2,不帶 --tokens | 2 | 116.7 | 186 | 222,080 |
單條速度不受影響,兩條同時跑的合計多了六成。代價是每個請求的 context 上限從 262,144 降到 222,080,兩個請求共用同一個 KV 池。
長請求不再擋人:排程器在每一塊之間讓出來
並行打開之後還剩一個問題:只要有一條長請求在讀 prompt,其他請求還是要等它讀完。一條 54K token 的請求讀 prompt 要 40 秒,後面的短請求就等 39 秒。
原因在排程器。Qwen3.8 配 DFlash 時,FastLLM 走的是一個專用的排程迴圈,它挑到長請求之後,會在同一個內層迴圈裡把 prompt 的每一塊(chunk)依序做完,中間不回頭看有沒有別的請求在排隊。所以 --chunked_prefill_size 只決定每一塊多大,不會讓別人插進來;我試了三種 chunk 大小和三個相關的環境變數,短請求一律等 37 到 41 秒。
我改的地方是:長 prompt 每做完一塊,就暫時放開模型的鎖,讓另一條排程執行緒去處理排隊中的短請求,然後再繼續下一塊。開關是 FASTLLM_COOPERATIVE_LONG_PREFILL=1,不設就跟原版完全一樣。
另一個一起修的:取消一個長請求時,上游只把它標記成已中止,prompt 的讀取迴圈沒檢查這個標記,GPU 會把整段硬算完,下一個請求要等 9.8 秒。現在每一塊之間都會檢查,取消後 0.5 秒就能接下一個請求,已經讀完的那幾塊還能留在 prefix cache 裡,重送同一段 prompt 時直接命中。
改完的實測,看第一列就好:
| 54K token 的長請求讀 prompt 期間 | 原本 | 改過之後 |
|---|---|---|
| 插進 1 條短請求:第一個字 / 答完(單次) | 37.4 秒 / 37.8 秒 | 1.18 秒 / 3.8 秒 |
| 同時插進 2 條短請求:第一個字 | 38.1 / 38.6 秒 | 1.3 / 2.7 秒 |
| 插進 1 條短請求:第一個字(33 分鐘壓測,p95) | 39.5 秒 | 1.13 秒 |
| 取消長請求後,下一個請求第一個字(壓測最大值) | 9.8 秒 | 0.54 秒 |
| 長請求自己讀 prompt(壓測 p95) | 42.2 秒 | 42.7 秒(+1%) |
一條短請求插進來最划算,3.8 秒就答完。同時插進兩條時,兩條都會在 3 秒內開始,但它們要跟長請求搶同一組 GPU,生成得很慢(每秒 1 到 2 個字),要等長請求讀完才會加速。第三條會排在前面某一條結束之後,因為並行上限是 2。
這兩個改動都送到上游了:#755 是取消時中止,改動小、對所有人都有用;#756 是排程器,疊在 #755 上面。兩個都還沒合併,所以下面要自己編。
怎麼編:上游 a2bf07fd、撤掉一個 commit、合併兩個 PR
你需要跟上一篇一樣的環境:兩張改裝 2080 Ti 22G、一份有 sm_75 的 NCCL、CUDA 12.4(nvcc)、GCC 13、Python 3.14 的 venv。模型和草稿也是同一份:orcarouter/Qwen3.8-27B-Uncensored-FP8 和 z-lab/Qwen3.8-27B-DFlash2。
git clone https://github.com/ztxz16/fastllm && cd fastllm
git checkout -b dual-2080ti a2bf07fd
git revert --no-edit d4b04876 # 讓 DFlash2 猜中率下降的那個 commit
git fetch origin pull/749/head:pr749 pull/756/head:pr756
git merge --no-edit pr749 # 自訂 AllReduce 註冊快取無上限(長對話會吃滿 GPU0)
git merge --no-edit pr756 # 已經包含 #755
#749 是 9 月送的:DFlash2 在雙卡上每一步都會多配一份指標表,永遠不釋放,長對話跑久了會把 GPU0 吃滿。這三個合併在 a2bf07fd 上都不會衝突。
編譯。後面那串 -D_AMX... 是 CUDA 12.4 配 GCC 13 的 workaround,沒加會在 AMX 的 header 編不過:
mkdir build-fastllm && cd build-fastllm
cmake .. -DUSE_CUDA=ON -DUSE_NUMAS=OFF -DCUDA_ARCH=75 -DCMAKE_CUDA_ARCHITECTURES=75 \
-DCMAKE_CUDA_COMPILER=/usr/bin/nvcc \
-DCMAKE_CUDA_FLAGS="-D_AMXTILEINTRIN_H_INCLUDED -D_AMXINT8INTRIN_H_INCLUDED -D_AMXBF16INTRIN_H_INCLUDED -D_AMXCOMPLEXINTRIN_H_INCLUDED"
make -j24 fastllm_tools
cd tools && ~/venvs/ftllm-dual/bin/pip install --no-deps --force-reinstall .
裝完一樣是 ftllm 這個套件,指令也一樣是 ftllm server。
啟動指令
export LD_PRELOAD=/home/coolthor/nccl-install/lib/libnccl.so.2 # 有 sm_75 的 NCCL
export CUDA_VISIBLE_DEVICES=0,1
export FASTLLM_CUDA_GRAPH=0 # DFlash2 在 sm_75 還是要關
export FASTLLM_DRAFT_QUANT=nvfp4 # 預設就是 nvfp4,寫出來比較清楚
export FASTLLM_COOPERATIVE_LONG_PREFILL=1 # PR #756 的開關
~/venvs/ftllm-dual/bin/ftllm server \
-p /mnt/nvme1t/models/qwen38-27b-uncensored-fp8 --model_name qwen38-27b-ud \
--tp 2 --max_batch 2 --chunked_prefill_size 4096 \
--gpu_mem_ratio 0.95 --kv_cache_dtype fp4 \
--speculative_algorithm dflash \
--speculative_draft_model_path /mnt/nvme1t/models/dflash2-qwen38-zlab \
--speculative_num_draft_tokens 8 \
--prefix_cache true \
--chat_template /mnt/nvme1t/models/qwen-fastllm-low/chat_template.jinja \
--host 0.0.0.0 --port 8082
跟上一篇的差別只有四個地方:拿掉 --tokens 262144、--max_batch 改 2、加 --chunked_prefill_size 4096、多兩個環境變數。chat template 還是上一篇那份 effort 改成 low 的版本。
啟動後看 log 確認兩件事:沒有 max_batch limited 那一行,以及 Model context window: 222080 tokens per session 這類的數字。
會卡住你的四件事
- 帶著
--tokens開--max_batch 2:並行數會被默默壓回 1,只有 log 裡一行提示。 - 直接換上游最新版:在這組硬體上寫程式會從 102 掉到 85,要撤掉
d4b04876。 - 想打開 CUDA Graph:新版開了不會像以前那樣第一個請求就崩,但反而慢 11%。維持
FASTLLM_CUDA_GRAPH=0。 - 以為
--chunked_prefill_size能讓短請求插隊:不能,要 #756 那個開關。
能力:140 題 132 / 127
主模型的權重沒動,能力應該不變,還是照上一篇的 140 題重跑了一次(GSM8K 50、MATH-500 30、MuSR 20、HumanEval+ 40)。看合計那欄:
| GSM8K | MATH-500 | MuSR | HumanEval+ | 合計 | |
|---|---|---|---|---|---|
| 上一篇,不開思考 | 49 | 29 | 15 | 35 | 128 |
| 這一版,不開思考 | 50 | 30 | 16 | 36 | 132 |
| 上一篇,開思考 + low | 50 | 30 | 9 | 36 | 125 |
| 這一版,開思考 + low | 49 | 30 | 12 | 36 | 127 |
多出來的幾題在誤差範圍內,說成「沒有變差」比較準。這兩輪是在加排程器之前的版本上跑的;加了排程器之後另外跑了 20 題 smoke test,20 題都對。
那,還能更快嗎?
這一篇動的都是程式和排程,主模型的權重一直是 FP8,每吐一個字還是要讀 29GB。2080 Ti 沒有 FP4 硬體,把主模型也壓到 4 bit 有沒有用?下一篇。
進階:除錯與實驗紀錄
不讀這節不影響使用。這裡是每一步的原始數字和走過的路。
git bisect 87 個 commit:一步 10 分鐘
每一步都是:編一版純上游(不疊任何 patch)、在另一個 port 開起來、用同一支腳本量寫程式三發取中位數,≥96 算好、≤89 算壞。兩端先量:14f849af 100.2、a2bf07fd 84.7,跟疊了我們 patch 的版本(100.3 / 84.8)一樣,所以退步跟 patch 無關。
| commit | 寫程式 tok/s | 判定 |
|---|---|---|
14f849af | 100.2 | 好 |
809d34b6(SM75 解碼調校) | 101.9 | 好 |
00276210(DFlash 草稿緩衝、CUDA Graph) | 101.9 | 好 |
b2283cc7 | 102.2 | 好 |
2dd79d9d | 102.2 | 好 |
90fc11e4(移除 DFlash 實驗開關) | 102.2 | 好 |
d4b04876(RMSNorm reduction) | 84.7 | 壞 |
6023b070 | 84.7 | 壞 |
a2bf07fd | 84.7 | 壞 |
d4b04876 前後,DFlash 接受率前三位從 87.2 / 74.4 / 60.9% 變成 83.9 / 61.2 / 43.5%。在 a2bf07fd 上只撤掉它:寫程式 102.3、數學 121.4、散文 70.3,數學和散文的進步都留著。
我懷疑新 kernel 在某些 shape 上算錯,寫了一支小程式比對:隨機產生 8×5120 的 FP16 測試資料,量級 0.01、0.5、1、10、100 五組,拿 FP32 算的結果當標準,新舊兩個 kernel 的最大絕對誤差一樣(約 0.00195),40,960 個值裡最多只有 2 個不同,最大差 0.000488。所以不能說它算錯。為什麼接受率會掉那麼多,我還解釋不了。
logprobs patch:零影響
我自己的版本另外疊了 #752(OpenAI API 回傳 logprobs)。擔心它拖慢速度,拿掉前後各量一次:舊版 100.3 / 100.3,新版 84.8 / 84.7,完全一樣。請求沒有要 logprobs 時,它走的就是原本的路徑。
CUDA Graph:「Resource deadlock avoided」是假線索
新版開 FASTLLM_CUDA_GRAPH=1,第一個請求就崩,錯誤訊息是 Resource deadlock avoided,看起來像是鎖出問題。往前找,真正的錯誤是 graph replay 時第一個 decode 回報 cudaErrorIllegalAddress (700)。程式因此要退出,解構時 MTP 執行緒去 pthread_join 自己,才冒出 deadlock 那一行。
看到這個訊息別去查鎖,往 log 前面找第一個 CUDA 錯誤。草稿轉 NVFP4 之後開 graph 不會崩,但寫程式 105.9、數學 120.2、散文 61.1,比不開慢 11%,所以一樣關著。
草稿 token 數與其他開關
在草稿 NVFP4 的版本上:--speculative_num_draft_tokens 4 和 6 都比 8 慢,大於 8 這份草稿 checkpoint 不接受(它的 block size 就是 8)。README 裡三個跟 SM75 有關的開關(FASTLLM_DFLASH_ATTENTION、FASTLLM_TP_NATIVE_GREEDY、SM75 解碼調校)分別關掉,差距都在 2% 以內,維持預設。
並行:三次才試對
| 第幾次 | 設定 | 單條寫程式 | 兩條同時 | 長請求中插短請求 |
|---|---|---|---|---|
| 1 | --max_batch 2 --tokens 262144 | 116.9 | 各約 58,輪流 | 等長請求做完 |
| 2 | --max_batch 2,不帶 --tokens | 116.7 | 各 93,合計 186 | 還是要等 |
| 3 | 第 2 次 + --chunked_prefill_size 4096 | 116.2 | 合計 186.6 | 還是要等(38.6 秒) |
第 1 次的 log 就是那行 explicit-token safety max_batch limited 2 -> 1。第 3 次測下來短請求還是要等,光調 chunk 大小沒用,我才去改排程器。
排程器:卡在哪一行
Qwen3.5 系列配 DFlash 走的是 Qwen35MTPLoop。它挑到長請求後,在 src/models/qwen3_5.cpp 約 24327 到 24489 行的內層迴圈把所有 chunk 做完,forward 鎖到 24715 行附近才放開。短請求在這段時間其實已經送達、也登記成待處理,只是排程器困在迴圈裡沒回頭看。(行號是 a2bf07fd 的。)
先試了不改程式的做法,全部沒用:
| 條件 | 短請求第一個字 | 長請求讀 prompt |
|---|---|---|
| 基準,chunk 4096 | 37.4 秒 | 40.2 秒 |
FASTLLM_ACTIVE_PREFILL_TOKEN_LIMIT=1024 | 37.7 | 40.5 |
FASTLLM_IDLE_PREFILL_BATCH_WAIT_US / QUIET_US 調整 | 37.8 到 39.6 | 40.7 到 42.4 |
| chunk 1024 / 2048 / 8192 | 40.7 / 38.0 / 38.2 | 43.6 / 40.9 / 41.1 |
讀原始碼才知道:ACTIVE_PREFILL_TOKEN_LIMIT 只在通用的排程迴圈生效,IDLE_PREFILL_* 只在另一個沒開的分支才讀。
壓力測試抓到的兩個退步
第一版原型把短請求第一個字壓到 1.26 秒,但 75 分鐘的 A/B 壓力測試(同一個亂數種子,各 18 輪、252 個請求)抓到:兩條請求同時生成時,合計從 175.5 掉到 73.3,每輪都有一條慢到每秒 41 個字。
原因是測試序列裡「兩條同時生成」剛好排在「取消一個長請求」之後,而取消不會中止 prompt 讀取。原版取消後的短請求要等 9.8 秒,等輪到兩條同時生成時,被取消的讀取剛好做完;原型把取消後的短請求 0.5 秒就處理掉了,主執行緒卻還在幫已取消的請求讀 prompt,兩條生成請求一條跟它搶 GPU,另一條要等它讀完。修掉取消這件事之後,同一套測試:
| 18 輪、252 個請求 | 原版 | 原型 | 修正版 |
|---|---|---|---|
| 長請求中插短請求,第一個字 p95 | 39.7 秒 | 1.19 秒 | 1.18 秒 |
| 取消後的短請求,第一個字中位數 | 9.8 秒 | 0.54 秒 | 0.54 秒 |
| 兩條同時生成,合計 | 175.5 | 73.3 | 175.7 |
| 長請求讀 prompt,p95 | 42.4 秒 | 43.1 秒 | 42.9 秒 |
| 錯誤 / 答錯 | 0 / 0 | 0 / 0 | 0 / 0 |
第二個退步是修正版只能讓一條短請求插隊:輔助執行緒把被暫停的長請求也算進自己的名額(同一個檔案約 23570 到 23579 行),--max_batch 2 就只剩一個位置。跳過它之後,同時兩條短請求的第一個字從 1.3 / 36.7 秒變成 1.3 / 2.7 秒,log 裡在長請求讀取的每一塊之間都印出 Decode alive = 2。重啟三次重測,第二條都在 2.58 到 2.66 秒。
最終版跑 18 輪回歸測試:插短請求 p95 1.20 秒、取消後 0.65 秒、兩條同時合計 170.5、長請求 p95 +2.0%、0 錯誤。VRAM 峰值比修正版高約 200 MiB,但同一個執行檔把開關關掉跑 9 輪,也是同樣的斜率往上,所以是新版上游本來就有的現象,跟新排程器無關。
送上游前的三輪 code review
送 PR 前讓 Codex 做了三輪 review。第一輪抓到一個會卡死服務的問題:輔助執行緒空閒時無限期等待,而主執行緒通知它停止時沒拿 lock,通知可能落在它「檢查完、還沒開始等」的空檔,join() 就永遠等下去。另外三個是:取消刪掉 context 後,取 token 的函式重新上鎖時還用舊指標;輔助執行緒判斷長短請求用錯了門檻(4096 對 2048);建立執行緒失敗時沒清理。第二輪抓到修法把主迴圈的閒置等待也改成每 10 ms 醒一次、以及建執行緒失敗會讓排程器跟著退出。第三輪通過。
修完之後針對這幾點測:輔助執行緒停止 50 次都沒卡住;取消長請求的同時另一條在串流,30 輪 90 個請求都正常;2049 到 4096 token 的請求插進來,輔助執行緒不會接手去讀它的 prompt。
版本鎖定
- 上游基底:
a2bf07fd(2026-09-25) - 撤掉:
d4b04876 - 合併:#749、#755、#756(我自己的版本另外有 #751 多模態 prefix cache 修正和 #752 logprobs;#751 在
a2bf07fd上跟basellm.cpp有衝突,要自己解,它只影響「長對話尾端附圖」那種情境) - CUDA 12.4、GCC 13.4、sm_75,NCCL 2.31.2(自編)
還沒做的
- #755、#756 都還沒被合併,上游改動後可能要重新對齊。
- 所有數字只在兩張 2080 Ti、TP=2、DFlash2 這一組上量過。
d4b04876的影響、草稿 NVFP4 的提升幅度,換一張卡可能都不一樣。 - 同時插進兩條短請求時,它們在長請求讀完之前生成得很慢(每秒 1 到 2 個字)。要改善得讓排程器把短請求的生成跟長 prompt 的讀取放進同一步一起算,那是另一個改法。
同系列:
常見問題
- FastLLM 開 --max_batch 2 為什麼還是一次只處理一個請求?
- 因為同時帶了 `--tokens`。Qwen3.8 這類混合模型每個請求的狀態很大,FastLLM 在你明確指定 `--tokens` 時會把並行數壓到 KV 預算的 25% 放得下的量,log 裡會出現 `explicit-token safety max_batch limited 2 -> 1`。拿掉 `--tokens` 讓它自己算 KV 頁數,並行才會生效,代價是每個請求的 context 上限變成自動算出的值(我這組是 222,080)。
- FastLLM 的 --chunked_prefill_size 能讓短請求在長 prompt 讀取中插隊嗎?
- 不能。Qwen3.5/3.8 配 DFlash 時,排程器會在同一個迴圈裡把長 prompt 的所有 chunk 做完才去看別的請求,chunk 大小只影響每一塊多大。我送了上游 PR #756,加一個預設關閉的 `FASTLLM_COOPERATIVE_LONG_PREFILL=1`,在 chunk 之間讓出來服務短請求:54K token 的長請求讀 prompt 時,短請求從等 39.5 秒變成 1.1 秒開始回。
- FastLLM 在 2080 Ti 上開 DFlash2,升級到最新版反而變慢?
- 我遇到的是上游 commit `d4b04876`(小 batch RMSNorm 的 reduction 改寫)。在兩張 2080 Ti、TP=2、DFlash2 這組上,它讓草稿第 3 個位置的接受率從 60.9% 掉到 43.5%,寫程式從 102 掉到 85 tok/s。撤掉它就回來了。這是只在這組硬體上量到的,別的卡不一定受影響。
- 在 FastLLM 裡取消一個長請求,GPU 會馬上停下來嗎?
- 上游目前不會。取消只是把請求標記成已中止,長 prompt 的讀取迴圈沒有檢查這個標記,會繼續把整段算完,我這邊取消後下一個請求要等 9.8 秒。PR #755 改成在每個 chunk 之間檢查這個標記,取消後 0.5 秒就能接下一個請求,已經讀完的部分仍能當 prefix cache 重用。
接著讀
- 2026-09-282080 Ti 沒有 FP4 也能跑 NVFP4:自己轉 Qwen3.8-27B,寫程式快 31%
2080 Ti 沒有 FP4 硬體,FastLLM 在 kernel 裡解包 NVFP4 照樣變快:自己把 Qwen3.8-27B BF16 轉成 NVFP4,寫程式 151.7 tok/s(FP8 116.1),四條請求同時跑合計 297,140 題 131/128。附轉換腳本與三顆 NVFP4 的比較。
- 2026-09-21特化的啟動器 FastLLM + DFlash2,居然可以在魔改的 2080 Ti 雙卡跑出 100+ tok/s!
兩張改裝 2080 Ti 22G 用 FastLLM 跑 Qwen3.8-27B FP8,掛上 DFlash2 草稿模型:寫程式 153.8 tok/s、數學 134.9,散文 53.1。262K context、看圖、prefix cache 都在。附完整啟動指令和四個會卡住你的設定。
- 2026-09-21什麼!?Qwen3.8 27B 居然被壓到 5.9GB,跑起來能力居然有無損模型的 98.2%
PrismML 的 Ternary Bonsai 2 把 Qwen3.8-27B 壓成三值權重,官方說 5.9GB 保留 FP16 的 98.2% 能力。我在一張改裝 2080 Ti 22G 上跑同一組權重的 7.2GB 版:140 題拿 130,兩張卡跑 Q8_0 是 131。附編譯、啟動指令,以及為什麼最小那包反而最慢。
- 2026-08-22[Benchmark] 兩張改裝 2080 Ti 玩 tensor parallel,Qwen3.8-27B 衝到 59.6 tok/s
兩張改裝 2080 Ti 22G 用 llama.cpp 的 tensor parallel 接上 Qwen3.8-27B,配 MTP 投機解碼從單卡 37.1 tok/s 衝到雙卡 59.632 tok/s,還能開到 262K context。內含現在正式在跑的組態、三個上游踩坑,和雙 5060 Ti 社群數字的對照。
不想錯過新文章?
訂閱我確保不漏接!
隨時一鍵退訂。