Three faults ended a re-run before step 8, so a deleted artifacts/ was never written again. The import check read the first word of stdout, and vLLM logs to stdout. On a box with mixed 3090 and 3090 Ti devices the device-mismatch WARNING comes first, so the build stopped with "vllm reports WARNING, expected 0.30.0". Print a BUILD_SMOKE marker and read the version from that line. Patch 0103 committed .build-products.sha256 into the serving tree, and write_sums rewrites that file, so every re-run stopped at "modified tracked files". Drop the file from the patch and exclude the two build record paths from the check. The series now yields tree a823fa36d3fd640f87b3de87153268d938130a47; OPS_OBJ is unchanged, so the compiled kernels stay valid. Step 8 skipped the pack whenever the kernels came from a tarball, and judged an existing set by file presence alone. Require the tarball, the per-file list, the manifest and the sidecar, verify the sidecar, and pack from the products in the tree when any check fails. Co-Authored-By: Hinata <hinata@idihore.id> Signed-off-by: MOVZX <movzx@yahoo.com>
19 KiB
iHoree-vLLM-4xRTX3090
Dokumen ini adalah terjemahan dari README.md. Bahasa Inggris tetap acuan.
Jika isinya berbeda, ikuti README.md.
Swift-1.5-Qwen3.8-Flash-Next-W4A16 berjalan dari empat kartu RTX 3090. Modelnya adalah MoE 125B dengan bobot 4-bit. Modelnya berjalan TP2xPP2 + EP dengan MTP K=3. Pool KV FP8 menampung 924.993 token pada konteks 262.144 token. Keluaran satu aliran diukur pada 158-184 tok/s.
1. Kebutuhan
| Item | Kebutuhan |
|---|---|
| GPU | 4 kartu bebas 24 GB, semua model yang sama |
| RAM | 96 GiB atau lebih. Tabel PLE memakai 69 GiB RAM host. |
/dev/shm |
1 GB atau lebih |
| Driver | CUDA 13.0 atau lebih baru |
| Disk | 30 GB bebas untuk build, 115 GB untuk checkpoint |
| Python | 3.13 |
| Build tools | cmake 3.26 atau lebih baru, ninja, cc, c++ |
Checkpoint harus berisi qsa_kv_scales.json. File itu menyimpan scale KV FP8.
Swift 1.5 mengubah k_proj/v_proj, jadi file scale satu checkpoint tidak bekerja
untuk checkpoint lain.
SCALES menunjuk ke sidecar lain. Beri path host; Compose mem-mount-nya ke container.
Bawaannya $MODEL_DIR/qsa_kv_scales.json.
2. Cara Build
sudo apt-get install -y cmake ninja-build ccache
./build.sh
build.sh menjalankan delapan langkah: tools, tree serving, venv, runtime
terkunci, toolchain CUDA, ops yang di-compile, install, dan pack kernel. Compile
pertama butuh 20 menit pada CPU 64 core.
Dua variabel mengontrol compile:
MAX_JOBS— jumlah job compile. Bawaannya32. Turunkan nilainya ketika build kehabisan RAM.ARCH— arsitektur GPU. Bawaannya8.6(Ampere).
Build mencetak setiap langkah. Installer berjalan dengan -v, jadi setiap baris
compiler terlihat, dan satu baris status muncul setiap 60 detik. Output lengkap
masuk ke build-<timestamp>.log di root repo.
2.1. Jalankan Ulang
Jalankan ulang pada tree yang tidak berubah melewati compile dan install. Ia
membaca commit tree dan dua hash ekstensi dari vllm/.build-products,
meng-hash ulang vllm/.build-products.sha256, dan mencari install vllm di venv.
Setiap ketidakcocokan memulai compile. ./build.sh --force selalu meng-compile.
Jalankan ulang juga memeriksa ulang artifacts/. Kalau foldernya hilang atau tidak
lengkap, langkah 8 menulisnya lagi dari kernel yang sudah di-compile (lihat 7).
2.2. Tree
Langkah 2 membangun vllm/ dari tag upstream v0.30.0 plus patches/, lalu
membandingkan hasilnya dengan hash tree yang diharapkan. Tree yang benar dibiarkan,
jadi menjalankan ulang tidak butuh jaringan. FETCH=1 ./build.sh menerapkan ulang
seri patch dari base. VLLM_UPSTREAM_URL= menunjuk ke mirror.
2.3. Tools di Mesin Build
build.sh memakai uv untuk venv ketika uv ada di PATH, dan CPython 3.13 pada
kedua kasus. Set UV=0 untuk menolak uv, UV=/path/to/uv untuk memilih satu.
Cache wheel milik user saat ini ($HOME/.cache/uv, $HOME/.cache/pip) dicetak
pada langkah 3 dan dipakai ulang.
build.sh memakai ccache ketika ada di PATH, sebagai launcher compiler CMake
untuk C, C++, CUDA, dan HIP. Objek masuk ke direktori ccache milik user saat ini.
Langkah 1 mencetak direktorinya, langkah 7 mencetak jumlah hit dan miss. Set
CCACHE_DIR= untuk memindahkannya. Tanpa ccache, setiap kernel di-compile dari
nol.
cargo 1.95 bersifat opsional. Jika ada, build meng-compile frontend Rust
(vllm-rs, _rust_tool_parser). Jika tidak ada, tool parser Python yang dipakai.
3. Cara Menjalankan
sudo ./start.sh
tail -f /var/log/vllm.log
Bawaan start.sh: 127.0.0.1:8000, nama model qwen38-flash-next, log
/var/log/vllm.log. Compose menyetel MODEL_NAME=Hinata sebagai bawaan. Install
systemd menulis MODEL_NAME=Hinata ke /etc/default/vllm. Pakai sudo untuk
file log. Set HOST=0.0.0.0 untuk melayani semua interface.
start.sh menyimpan cache compile di .vllm-cache/ di direktori ini.
CACHE_ROOT=/path/to/cache ./start.sh
Start pertama meng-compile cudagraphs ke $CACHE_ROOT dan butuh sekitar 6 menit.
Request pertama membangun kernel FlashInfer. Setiap start berikutnya butuh
sekitar 3 menit.
4. Jalankan sebagai Service systemd
sudo scripts/install-as-service.sh install
sudo vi /etc/default/vllm
sudo scripts/install-as-service.sh start
sudo scripts/install-as-service.sh status
install menulis ulang /opt/vllm di systemd/vllm.service ke path repo ini,
jadi service menjalankan repo ini di tempat. update menjalankan ./build.sh
dan restart. logs menampilkan ekor log engine. uninstall menghapus unit,
file environment, dan file logrotate.
5. Log
start.sh menulis engine dan proses anak PLE offload ke /var/log/vllm.log.
Set LOG=/other/path untuk memindahkan file. Set LOG= (kosong) untuk
menampilkan output di terminal. Image memakai mode itu, jadi
docker compose logs bekerja.
Pasang kebijakan rotasi:
sudo install -m 0644 systemd/vllm.logrotate /etc/logrotate.d/vllm
Perintah itu menggantikan /etc/logrotate.d/vllm yang sudah ada di host.
Kebijakan itu merotasi file setiap hari, pada 100 MB. Ia menyimpan 14 file,
mengompresnya, dan menghapus log lebih tua dari 60 hari. Container membatasi
log-nya sendiri dengan cara yang sama (json-file, 100 MB x 14).
vllm-logs.sh mencetak baris statistik engine sebagai satu baris berwarna per
pembaruan (throughput, pemakaian KV, prefix cache, penerimaan draft). Baca log
container, atau log file dengan -f:
./vllm-logs.sh # docker logs dari container vllm, 10 menit terakhir
./vllm-logs.sh -f -n 500 # ekor /var/log/vllm.log, dari 500 baris terakhir
6. Uji Server
/v1/models mengembalikan 200 ketika engine mati. Lakukan generate satu token.
Set model ke nama yang dilayani, nilai MODEL_NAME:
curl -s localhost:8000/v1/chat/completions -H 'Content-Type: application/json' \
-d '{"model":"qwen38-flash-next","messages":[{"role":"user","content":"hi"}],"max_tokens":1,\
"chat_template_kwargs":{"enable_thinking":false}}'
Start yang sehat menulis baris ini ke log:
GPU KV cache size: 924,993 tokens
Angka itu berubah bersama setting memori KV.
7. Container (opsional)
Pakai container ketika image dibangun di mesin tanpa GPU dan tanpa driver, lalu berjalan di host GPU.
Langkah 8 dari build.sh menulis kernel yang sudah di-compile ke artifacts/:
satu tarball, daftar sha256 per file, dan satu manifest. --no-pack (PACK=0)
melewati langkah itu. Jalan kedua pada tree yang sama tidak mem-pack ulang. Hapus isi
artifacts/ dan jalan berikutnya menulisnya lagi. Biayanya satu kali packing (sekitar 45
detik), bukan compile ulang.
Ada dua route build:
# kernel dari artifacts/, tanpa compile, sekitar 2 menit
docker build --build-context ops="$PWD/artifacts" -t vllm:latest .
# compile penuh, 20-40 menit, disk build 15 GB
docker build -t vllm:latest .
docker compose build mengirim context ops dari artifacts/ sendiri.
Build memeriksa tarball sebelum ia memasangnya: input yang di-compile (lihat 7.5), arsitektur GPU, CPython minor, CUDA major, versi torch, dan sha256 setiap file hasil ekstrak. Tarball yang tidak cocok dengan tree menghentikan build dan menyebut item yang tidak cocok.
Build image butuh akses jaringan: ia mengunduh vLLM v0.30.0 dan wheel terkunci.
Base-nya Debian trixie. Kernel yang dibangun di Debian 13 butuh glibc 2.38, dan
bookworm (glibc 2.36) tidak dapat memuatnya. cmake 3.25 di trixie terlalu tua,
jadi image memasang cmake dan ninja dari pip. Image membawa toolchain
compiler, jadi ukurannya besar.
Build image menerima dua argumen compile yang sama dengan build.sh:
docker build -t vllm:latest --build-arg MAX_JOBS=16 --build-arg ARCH=8.6 .
7.1. Stub Driver CUDA
Kernel men-link CUDA::cuda_driver (libcuda.so.1). Paket driver NVIDIA
menyediakan itu. Container build tanpa GPU tidak punya, dan wheel CUDA tidak
punya stub untuk itu, jadi langkah 5 menjalankan scripts/gen-cuda-stub.sh. Ia
menulis stub link-time di samping toolkit di venv: 548 entry point, tanpa body,
92 KB, soname libcuda.so.1. Tidak ada loader search path yang memasukkan
direktori itu, jadi ekstensi membuka driver asli saat jalan. Tanpa stub, cmake
berhenti dengan Target "_C_stable_libtorch" links to: CUDA::cuda_driver but the target was not found. Di host driver ada, jadi langkah itu tidak melakukan apa
pun setelah pertama kali berjalan.
Pemeriksaan import di akhir build.sh butuh driver juga. Tanpa driver, ia
memeriksa layer link dan mengatakannya. Import penuh berjalan saat serve di host
GPU. libcuda.so.1 hanya diharapkan ada di
vllm/_C_stable_libtorch.abi3.so. Kernel MoE mendapat CUDA melalui
libtorch_cuda, jadi ia tidak ada di daftar NEEDED mereka.
7.2. Cache Build
Build membaca tiga BuildKit cache mounts: cache wheel uv, cache pip, dan
cache objek ccache. Ketiganya hidup di luar image, jadi rebuild tidak
mengunduh apa pun dan hanya meng-compile kernel yang sumbernya berubah.
Ketiganya mulai dalam keadaan kosong, jadi build pertama mengunduh sekitar 6 GB
wheel. Kirim cache milik user saat ini untuk mencegah itu:
docker build -t vllm:latest \
--build-context uvcache="$HOME/.cache/uv" \
--build-context pipcache="$HOME/.cache/pip" .
Build membaca folder itu. Build tidak pernah menulis ke dalamnya.
7.3. Jalankan dengan Docker Compose
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
cp .env.example .env
mkdir -p .vllm-cache "$HOME/.cache/uv" "$HOME/.cache/pip"
docker compose up -d
docker compose logs -f
docker compose up mengirim tiga context ke build image: artifacts (kernel
dari ./build.sh), uvcache dan pipcache (cache wheel user ini). Masing-masing
harus folder yang ada. .vllm-cache adalah folder cache saat jalan, di-mount ke
/cache.
7.4. Jalankan Image Tanpa Compose
docker run -d --name vllm --gpus all --stop-timeout 20 --shm-size=16g \
--ulimit memlock=-1 -p 8080:8000 \
-v /data/models/checkpoint:/models/model:ro \
-v "$PWD/.vllm-cache":/cache \
-e MODEL_NAME=Hinata vllm:latest
Tanpa Compose, mount sendiri sidecar-nya: -v <host>/scales.json:/opt/vllm/qsa_kv_scales.json:ro -e SCALES=/opt/vllm/qsa_kv_scales.json.
7.5. Tambah Patch Tanpa Compile Ulang
Tarball ops berisi kernel yang sudah di-compile. build.sh menguncinya pada OPS_OBJ,
yaitu hash dari input yang di-compile saja: csrc, CMakeLists.txt, cmake, setup.py,
pyproject.toml, MANIFEST.in, requirements, tools, rust-toolchain.toml,
vllm/third_party, dan vllm/vllm_flash_attn. Daftarnya ada di OPS_PATHS pada build.sh.
Patch yang hanya menyentuh Python tidak mengubah OPS_OBJ. artifacts/ tetap valid, jadi
build image tetap di jalur ~2 menit. Patch yang menyentuh satu path di daftar itu membatalkan
tarball, dan build akan meng-compile.
Cara menambah patch ke seri:
- Taruh patch format mail di akhir
patches/, dinamaiNNNN-<slug>.patch.git format-patchmenulis format itu. - Jalankan
./build.sh. Step 2 memasang seri dan mencetak tree yang ia build kalau tree itu tidak cocok denganEXPECTED_TREE. - Tulis hash tree itu ke
EXPECTED_TREEdibuild.sh, beserta tanggal verifikasi. - Jalankan
./build.shlagi. Ia memasang seri, mencocokkan tree, dan memakai ulang kernel.
Patch dari fork upstream jarang langsung cocok ke seri ini. Seri ini menggeser file yang sama.
Uji di tree bersih sebelum menambahnya:
git -C vllm worktree add -q --detach /tmp/wt HEAD, lalu git -C /tmp/wt am --keep-non-patch <patch>, lalu git -C vllm worktree remove --force /tmp/wt. Kalau konflik, rebase patch itu
ke seri dan ekspor ulang dengan git format-patch.
8. File
| File | Guna |
|---|---|
build.sh |
Ambil v0.30.0, pasang patches/, build .venv/ (py3.13, 196 pin), compile, pack |
start.sh |
Build pada jalan pertama, uji mesin, cache di .vllm-cache/, serve, tulis log |
vllm-logs.sh |
Baca log engine sebagai satu baris statistik per pembaruan |
scripts/install-as-service.sh |
Pasang unit systemd untuk repo ini, start, update, log, uninstall |
systemd/ |
vllm.service dan kebijakan logrotate |
Dockerfile, docker-compose.yml, .env.example |
Jalur container |
scripts/ |
Pemilih topologi, requirements terkunci, stub driver CUDA |
patches/ |
105 patch, dalam urutan pasang |
benchmarks/ |
Wrapper bench.sh, dan benchmark power limit (Inggris, Indonesia) |
abliteration/ |
File arah refusal untuk QWEN38_ABLITERATION |
9. Variabel
| Variabel | Bawaan | Arti |
|---|---|---|
MODEL_DIR |
tidak ada, wajib | Direktori host tempat checkpoint. Compose berhenti dengan pesan ketika kosong. |
CKPT |
/data/models/halt95/Swift1.5-Qwen3.8-Flash-Next-W4A16-Merlin |
Folder checkpoint di host. Argumen pertama start.sh mengaturnya. |
MODEL_MOUNT_PATH |
/models/Qwen3.8-Flash-Next |
Path checkpoint di dalam container. Compose mem-mount MODEL_DIR ke sini. |
SCALES |
$MODEL_DIR/qsa_kv_scales.json |
Path host sidecar scale KV FP8. Compose mem-mount-nya ke container. |
MODEL_NAME |
Hinata (compose), qwen38-flash-next (start.sh) |
Nama di field model pada request. Spasi membuat alias. |
HOST_PORT |
8080 |
Port host untuk API. |
VLLM_API_KEY |
kosong | Kosong berarti tanpa autentikasi. |
CACHE_HOST_DIR |
.vllm-cache di direktori ini |
Tempat cache compile berada. Jalur host memakai folder yang sama. |
CUDA_VISIBLE_DEVICES |
0,1,2,3 |
Jalur GPU, dalam urutan bus. |
PLE_HOME |
0 |
Kartu yang menjadi inang PLE offload. Kartu itu tidak mendapat CUDA context untuk itu. |
QWEN38_ABLITERATION |
Qwen3.8-Flash-Next-Uncensored |
Hapus arah refusal saat jalan. Kosong menonaktifkannya. Lihat patches/0102. |
ABLITERATION_DIR |
./abliteration |
Folder host dengan file arah itu. Compose mem-mount ke /opt/qwen38/abliteration. |
GUARD |
warn |
Telemetri bounds-guard: off, warn, atau raise. |
COUNTERS |
0 |
1 menambah counter kernel khusus log. |
VLLM_LOG_STATS_INTERVAL |
1 |
Jeda antar baris stats engine, dalam detik. Default vLLM: 10 s. |
MAX_SEQS |
4 |
Jumlah request serentak. CUDA graph dicapture sampai batch MAX_SEQS x 4 token. |
MAX_BATCHED_TOKENS |
2048 |
Ukuran chunk prefill dalam token. Harus >= MAX_SEQS. Sama dengan --block-size. |
MAX_JOBS, ARCH |
32, 8.6 |
Job compile dan arsitektur GPU, hanya untuk build. |
10. Benchmark
benchmarks/bench.sh menjalankan llama-benchy terhadap server lokal. Pasang
tool-nya lebih dulu:
uv tool install git+https://github.com/eugr/llama-benchy
Jalankan dari root repo:
benchmarks/bench.sh [PP] [TG] [CONCURRENCY] [DEPTH] [arg llama-benchy tambahan]
| Argumen | Bawaan | Arti |
|---|---|---|
PP |
32768 |
Token prompt. Pakai 1 untuk hanya decode. |
TG |
2048 |
Token yang dihasilkan. Pakai 1 untuk hanya prefill. |
CONCURRENCY |
1 |
Satu tingkat, atau daftar dengan pemisah spasi, contoh "1 2 4". |
DEPTH |
0 |
Token percakapan sebelumnya sebelum prompt yang diukur. Daftar juga bisa. |
Argumen tambahan diteruskan ke llama-benchy. Script mengunci URL server, nama
model, dan path tokenizer. Ganti dengan BASE_URL, MODEL, dan TOKENIZER.
benchmarks/bench.sh 32768 1 # kecepatan prefill
benchmarks/bench.sh 1 4096 # kecepatan decode
benchmarks/bench.sh 32768 2048 "1 2 4" # sweep concurrency
benchmarks/bench.sh 128 256 1 "0 8192 65536" # sweep depth, turn kecil
DEPTH mengubah apa yang diukur satu run. --pp 8320 --depth 0 mengukur satu
prompt 8K yang dingin. --pp 128 --depth 8192 mengukur turn 128 token di dalam
percakapan 8K. Kecepatan decode turun seiring depth. Satu turn 128 token yang
diukur: 186 t/s pada depth 0, lalu 156 t/s pada depth 8192.
Tambah --enable-prefix-caching untuk mengukur dua fase dalam satu run. Tool
itu lalu mencetak baris dingin (ia memuat prefix) dan baris hangat (server
memakai ulang cache). Tambah --runs N untuk lebih banyak run per sel, dan
--no-cache untuk melewati uji koherensi.
benchmarks/gpu-power-limit-effects-en.md dan benchmarks/gpu-power-limit-effects-id.md
mencatat sweep power limit (220 W, 250 W, 285 W, PCIe Gen4 dan Gen3) dengan
metode lengkap dan rekomendasinya.