Skip to content

feat: native Windows vLLM guide + ported benchmark harness - #974

Open
BlackBox-Labs wants to merge 8 commits into
noonghunna:masterfrom
BlackBox-Labs:docs/windows-native-vllm-guide
Open

feat: native Windows vLLM guide + ported benchmark harness#974
BlackBox-Labs wants to merge 8 commits into
noonghunna:masterfrom
BlackBox-Labs:docs/windows-native-vllm-guide

Conversation

@BlackBox-Labs

@BlackBox-Labs BlackBox-Labs commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Native Windows vLLM Guide + Ported Benchmark Harness

This PR ships a complete guide for running vLLM on native Windows (no WSL2, no Docker), along with a PowerShell-port of the club-3090 benchmark harness.

What's in this PR

Guide: docs/vllm-windows-native.md

A step-by-step recipe for running vLLM on Windows 11 — no Docker, no WSL2, no VMs. Covers:

  • Prerequisites: CUDA Toolkit 12.6/12.8, Python 3.12, MSVC Build Tools, hardware requirements
  • Building vLLM: Two methods — pre-built wheel from SystemPanic/vllm-windows (recommended) or build from source with MSVC
  • Environment variables (matching the compose profile conventions):
    • NCCL_P2P_DISABLE=1 — disables GPU-to-GPU NVLink P2P (unreliable on Windows; forces PCIe ring / shared memory)
    • NCCL_CUMEM_ENABLE=0 — disables cumulative memory allocator (can cause OOM on Windows)
    • VLLM_NCCL_SO_PATH — points vLLM to the Windows-compiled NCCL DLL from SystemPanic/nccl-windows
    • VLLM_HOST_IP=127.0.0.1 — pins NCCL/gloo rendezvous to loopback — multi-GPU works without touching WiFi/Ethernet
    • PYTORCH_CUDA_ALLOC_CONF=expandable_segments:False,max_split_size_mb:512 — reduces CUDA memory fragmentation
    • XDG_CACHE_HOME / TRITON_CACHE_DIR — puts Triton kernel cache on your data drive
  • Launching the server: vllm serve with --host, --port, --dtype, --tensor-parallel-size, --max-model-len
  • Multi-GPU tensor parallelism: 2× RTX 3090 with --tensor-parallel-size 2, NVLink vs. PCIe P2P detection
  • WiFi-independent launch: loopback rendezvous via VLLM_HOST_IP=127.0.0.1 (avoids NCCL_SOCKET_IFNAME=lo trap)
  • Boot log evidence: real multi-GPU startup log showing NCCL DLL resolution, model loading, KV cache allocation, and HTTP server readiness

Ported Benchmark Harness: scripts/ps1/ (31 scripts, ~8,700 lines)

A complete PowerShell-native port of the club-3090 benchmark suite. The harness was originally written for Docker/Linux and has been ported to work natively on Windows.

Structure by category:

Category Scripts Purpose
Core verification verify.ps1, verify-full.ps1, verify-stress.ps1, verify-ours.ps1 Functional smoke tests, boundary checks, stress testing
Benchmarking bench-full.ps1, bench-agentic.ps1, submit-bench.ps1 Decode TPS measurement, agent benchmarking, result submission
Soak testing soak-test.ps1, rebench-runtime.ps1 Long-running VRAM stability tests
Quality quality-full.ps1, quality.ps1, quality-baseline.ps1 benchlocal-cli quality packs (tool-call, instruction-following)
Reporting report.ps1, capture.ps1 System info, GPU config, model info, report generation
Launcher launcher.ps1, all-in-one-comprehensive.ps1 Menu-driven dispatch (12 phases), full pipeline orchestration
Diagnostics arch-ab.ps1, check-issues.ps1, check-syntax.ps1, concurrency-probe.ps1, detect_nvlink.ps1, get-model.ps1, health.ps1, log.ps1 Architecture A/B, issue detection, syntax validation, GPU/NVLink detection, health checks
Utilities catalog-baseline.ps1, power-cap-sweep.ps1, rebench-full.ps1, rerun-failed-packs.ps1 Baseline catalog, power cap sweeps, re-benchmarking, failed scenario reruns

Key modules:

  • nvlink-env.ps1 — Shared NVLink/P2P environment configuration (auto/force_on/force_off/pcie_p2p modes), mirrors the compose NCCL_P2P_* conventions
  • launcher.ps1 — Menu-driven dispatch with powershell runner, child-output capture, 12-phase pipeline

Environment variables (mirrors compose .env conventions):

Variable Default Purpose
URL http://localhost:8010 vLLM endpoint
MODEL auto-detected Served model name (from /v1/models)
RUNS 5 Measured runs per prompt
WARMUPS 3 Warm-up runs
MAX_TOKENS_NARR 1000 Max tokens for narrative prompt
MAX_TOKENS_CODE 800 Max tokens for code prompt
QUICK 0 Quick mode (1 warmup, 1 run, narrative only)
ENABLE_THINKING 0 Enable thinking mode

Bug Fixes (discovered during porting)

The port revealed several issues in the original harness:

  1. PS5.1 Invoke-RestMethod body serialisation — hashtable bodies sent as form-urlencoded instead of JSON (fixed: wrap with ConvertTo-Json + add -ContentType 'application/json')
  2. Hardcoded Docker container namesvllm-qwen36-27b replaced with vllm-8010
  3. WSL/bash assumptions — scripts now use PowerShell-native paths with bash fallbacks
  4. benchlocal-cli command format — added run subcommand + --endpoint/--model args

Verification

The harness runs end-to-end on native Windows. All scripts pass syntax validation and the full pipeline executes without errors.

Notes for the Community

This is a starting point — the guide and harness work on the dev rig but you may need to adjust paths, GPU detection, or model versions for your setup. The harness environment variables mirror the compose .env conventions, so if you're already familiar with the Docker setup, the mental model transfers directly.

How this was built: The guide was authored on Linux, tested and validated there, then cross-validated on native Windows from the same system. The harness was ported to PowerShell and verified end-to-end on Windows — no WSL2, no Docker.

We welcome everyone to test it on their rigs, report what works and what doesn't, and share their experiences. Community-validated is the only way this gets better.

Thanks for being part of this project! 🎉

BlackBox-Labs and others added 8 commits August 13, 2026 09:51
…6-08-13 results

Add two audience-neutral guides for running vLLM natively on Windows (no WSL):
- docs/vllm-windows-setup.md  (fresh install)
- docs/vllm-windows-migration.md (moving a Linux club-3090 setup to Windows)

Both cover the Windows-specific gotchas: SystemPanic vllm-windows + nccl-windows
wheels, VLLM_NCCL_SO_PATH wiring, the NCCL_SOCKET_IFNAME=lo 'invalid usage' trap,
and WiFi-independent loopback rendezvous (VLLM_HOST_IP=127.0.0.1).

Ported PowerShell bench harness (scripts/ps1/) and a fresh bench-full run against
qwen3.6-35b-a3b-autoround-int4 (TP=2, 2x RTX 3090 PCIe, v3 chat template,
thinking OFF): ~70.8 wall TPS narrative / ~69.2 code, TTFT ~229/207 ms. Raw logs
in results/windows-native-20260813/.

Co-Authored-By: BlackBox-Labs <noreply@blackbox-labs.local>
…put capture

- launcher.ps1 Invoke-Script: add missing elseif ($Runner -eq "powershell")
  branch so every menu item actually launches (was a silent no-op for all
  26 entries). Use *>&1 to surface child Write-Host output.
- all-in-one-comprehensive.ps1: fix bench phase to call bench-full.ps1
  (bench.ps1 does not exist) and capture all streams (*>&1) so the
  orchestrator no longer returns after 5 header lines.
…ness + Windows-native vLLM guide

- get-model.ps1: throw instead of literal 'qwen-8010' fallback when undetectable
- bench-full/verify/verify-full: use $DETECTED_MODEL; fix bench.ps1 -> bench-full.ps1 stale refs
- health.ps1: Join-String -> -join; exit 1 on failure (D5)
- rebench-full/rerun-failed-packs/arch-ab/quality-baseline: 2>&1 -> *>&1 (child output capture)
- verify-stress.ps1: $1 -> $msg.content bug (D1); 120s->300s timeout
- detect_nvlink: Remove-ItemEnv -> Remove-Item env: (D2)
- bench-agentic: remove dead $Url=$Url block (D4)
- check-issues: fix $Dir path (D6); submit-bench: capture exit codes (D7)
- catalog-baseline: check $LASTEXITCODE (D8)
- capture/report/verify-full: model-probe + generation timeouts 5/15/120 -> 300s
- power-cap-sweep: /tmp -> $env:TEMP; add WSL TODO
- comment drift :8020/:8030 -> :8010
- add docs/vllm-windows-native.md (scrubbed, $VLLM_HOME placeholder, boot-log evidence)

Validated: 27/27 PS5.1 syntax parse clean; verify.ps1 4/4 PASS;
health.ps1 exit 0 on live 8010; get-model.ps1 no literal fallback.
Specialist dispatch: Developer (fixes) + Tester (validation) + Documenter (guide) on local vLLM-8010.
- rebench-full.ps1: fix stale 'bench.ps1' phase map entry -> 'bench-full.ps1'
- check-issues.ps1: remove dead 'bench.ps1' entry from FailList
- verify-full.ps1: correct stale log text 'scripts/bench.ps1' -> 'scripts/bench-full.ps1'
- verify-full.ps1: replace ConvertTo-Json -Compress (depth-2 truncation) with -Depth 10 across all request bodies (tool-call defs now serialize fully)
- launcher.ps1: Invoke-Script child launch 2>&1 -> *>&1 so child Write-Host/Warning surface
PowerShell 5.1 Invoke-RestMethod -Body @{hashtable} serialises as
application/x-www-form-urlencoded, which vLLM rejects with 400
'Unsupported Media Type'. Pass the body as a JSON string via
-Body (@{} | ConvertTo-Json -Depth 10) and set
-ContentType 'application/json' on all 7 chat/completions POST calls
(system_fingerprint probe, warmup, [3/9] basic, [4/9] tools,
[7/9] thinking, [8/9] output-quality, [9/9] metrics trigger).

Verified: verify-full.ps1 now reports 7/9 PASS, 2 SKIP (docker-only)
against live vLLM @ :8010.
- launcher.ps1: split [string] into array before splatting (@Args on a
  string is invalid PS5.1 and throws when args are non-empty); remove dead
  $NoAnimation reference in Show-Progress
- soak-test.ps1: replace session-scoped $SECONDS timeout with epoch-based
  elapsed seconds (robust when script is dot-sourced into a long-lived session)
- verify-full.ps1: drop dead preflight.ps1 block (file does not exist at the
  resolved scripts\scripts\ path)

All three files parse clean (PowerShell 5.1 parser).
- Fix PS5.1 Invoke-RestMethod form-urlencoded bug: wrap hashtable
  bodies as JSON string + add -ContentType 'application/json'
  (verify-stress: 5 sites, report: 1 site)
- Correct container name default from 'vllm-qwen36-27b' to 'vllm-8010'
  across all 5 scripts (verify-stress, verify-full, bench-full, report,
  verify) + guard docker inspect so native runs don't crash
- Rename quality-test.ps1 → quality-full.ps1; fix benchlocal-cli args
  (run subcommand, --endpoint, --model, --UseBasicParsing)
- Add nvlink-env.ps1 shared module; refactor detect_nvlink.ps1
- power-cap-sweep.ps1: bash→PS fallback (no WSL required)
- check-issues.ps1: dynamic Get-ChildItem discovery
- bench-agentic.ps1: auto-generate missing fixture
- rerun-failed-packs.ps1: updated to quality-full.ps1
…, output handling

- Create quality.ps1 — thin wrapper around quality-full.ps1 -Quick
- Rename quality-test.ps1 → quality-full.ps1 (mirrors bench/bench-full)
- Launcher menu: Quality (quick) + Quality Full (full)
- Fix benchlocal-cli: run subcommand + --endpoint + --model args
- Add -UseBasicParsing to all Invoke-WebRequest calls
- Remove 2>&1 from benchlocal-cli call (PowerShell misinterprets stdout)
- Remove hardcoded URL defaults — auto-detect from running vLLM
- Fix cosmetic launcher menu reference
@BlackBox-Labs BlackBox-Labs changed the title fix(ps1): port harness to native Windows — transport fix, container name, quality naming feat: native Windows vLLM guide + ported benchmark harness Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant