The default sidecar pointed at qsa_kv_scales_swift.json, a name no checkpoint on this box carries. The guard in start.sh then stopped every start with "scales sidecar missing", and a start without the guard would run FP8 KV at scale 1.0. Point the default at qsa_kv_scales.json, the file both checkpoints ship, and rename the sidecar in the start.sh header, both READMEs, and the Dockerfile comment. Name SCALES in the guard message. Co-Authored-By: Hinata <hinata@idihore.id> Signed-off-by: MOVZX <movzx@yahoo.com>
335 lines
16 KiB
Markdown
335 lines
16 KiB
Markdown
# 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.
|
|
|
|
## 2. Cara Build
|
|
|
|
```bash
|
|
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:
|
|
|
|
1. `MAX_JOBS` — jumlah job compile. Bawaannya `32`. Turunkan nilainya ketika
|
|
build kehabisan RAM.
|
|
2. `ARCH` — arsitektur GPU. Bawaannya `8.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.
|
|
|
|
### 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
|
|
|
|
```bash
|
|
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.
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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`:
|
|
|
|
```bash
|
|
./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`:
|
|
|
|
```bash
|
|
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.
|
|
|
|
Ada dua route build:
|
|
|
|
```bash
|
|
# 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: head tree, 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`:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
```
|
|
|
|
## 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/` | 103 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. |
|
|
| `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. |
|
|
| `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:
|
|
|
|
```bash
|
|
uv tool install git+https://github.com/eugr/llama-benchy
|
|
```
|
|
|
|
Jalankan dari root repo:
|
|
|
|
```bash
|
|
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`.
|
|
|
|
```bash
|
|
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.
|