vLLM on Intel Xeon CPUs
- Skill version: 1.1
- Tested against vLLM:
v0.20.2 - Minimum vLLM:
v0.17.0
Upstream First
Intel upstreams Xeon CPU optimizations directly to vLLM. This skill encodes deployment, tuning, validation, and a short benchmarking walkthrough — always consult upstream for the latest:
When to Use
Invoke this skill when the user wants to:
- Deploy or serve vLLM on an Intel Xeon CPU (no GPU).
- Tune CPU-serving performance knobs (KV cache, OMP bind, batched tokens, num seqs).
- Validate Xeon hardware (AMX flags, NUMA topology) before deploying.
- Run a minimal CPU benchmark to measure TTFT / TPOT / throughput.
Do not use for GPU vLLM, model training, deep quantization tuning, model selection (point users at the Intel Xeon AI Performance Advisor), or non-Xeon CPUs.
Prerequisites
| Item | Requirement |
|---|---|
| OS | Linux |
| Python | 3.10–3.13 (only if not using Docker) |
| CPU | 4th Gen Intel Xeon or newer; must expose amx_tile, amx_bf16, amx_int8 for best BF16/INT8 performance |
| Tools | curl, numactl, jq, g++, python3-dev, python3-venv (sudo apt-get install -y --no-install-recommends curl git jq numactl htop python3-venv python3-full g++ python3-dev). g++ and Python headers are required by PyTorch inductor to JIT-compile CPU kernels. |
| Docker | Recent Docker with --cap-add SYS_NICE and --security-opt seccomp=unconfined permitted |
Procedure 1 — Validate Hardware
Goal: confirm Xeon generation, AMX support, and NUMA topology before deploying.
- Inspect CPU model, sockets, cores, threads, NUMA nodes:
lscpu | grep -E "Model name|Socket|Core|Thread|NUMA node" - Check for AMX and AVX-512 flags:
lscpu | grep -E "amx_(tile|bf16|int8)|avx512_bf16|avx512f|avx2"- All of
amx_tile,amx_bf16,amx_int8present → proceed; BF16 AMX kernels will activate. - AMX missing –> Warn user. vLLM will still run, but inference throughput will be substantially lower. Recommend a 4th Gen Xeon (Sapphire Rapids) or newer.
- All of
- Inspect NUMA topology:
numactl --hardwareRecord the NUMA node count
N— it drives--tensor-parallel-sizeand KV cache sizing.
Procedure 2 — Deploy (Docker Fast Path)
Goal: serve a model via the official vllm/vllm-openai-cpu image with Xeon-tuned env vars.
- (Optional) Install Docker if not present (Ubuntu 24.04):
sudo apt-get update sudo apt-get install -y docker.io sudo systemctl enable --now docker sudo usermod -aG docker $USER newgrp docker # apply group without re-login - Pin a release tag (do not use
latest-x86_64in production):export VLLM_VERSION=0.20.2 # update to the latest release that meets the minimum above docker pull vllm/vllm-openai-cpu:v${VLLM_VERSION}-x86_64 - Run the container with the required Xeon env vars and Docker capabilities:
docker run --rm \ --name vllm-cpu \ --security-opt seccomp=unconfined \ --cap-add SYS_NICE \ --shm-size=8g \ -p 8000:8000 \ -e HF_TOKEN="${HF_TOKEN}" \ -e VLLM_CPU_KVCACHE_SPACE=20 \ -e VLLM_CPU_OMP_THREADS_BIND=auto \ -e VLLM_CPU_NUM_OF_RESERVED_CPU=1 \ vllm/vllm-openai-cpu:v${VLLM_VERSION}-x86_64 \ <model-id> \ --dtype=bfloat16 \ --max-num-batched-tokens 2048 \ --max-num-seqs 128SYS_NICE+seccomp=unconfinedenable vLLM’s NUMA memory-policy calls. Without them serving still works but logs may showget_mempolicy: Operation not permittedand NUMA placement weakens.VLLM_CPU_KVCACHE_SPACEis in GiB per NUMA node (start20–40) — must fit in node-local memory.VLLM_CPU_OMP_THREADS_BIND=autobinds OpenMP workers to NUMA-local cores. For manual control use ranges like0-31|32-63.VLLM_CPU_NUM_OF_RESERVED_CPU=1keeps a core free for API serving, tokenization, networking, and OS work.
- Validate the OpenAI-compatible endpoint:
curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "<model-id>", "messages": [{"role": "user", "content": "Give three CPU inference tuning tips."}], "max_tokens": 128 }'
Procedure 3 — Tune Performance Knobs
Goal: improve TTFT / TPOT / throughput methodically. Change one knob per run and compare.
- Pick the use case:
- Online serving → start
--max-num-batched-tokens 2048,--max-num-seqs 128. - Offline batch → start
--max-num-batched-tokens 4096,--max-num-seqs 256.
- Online serving → start
- Set
--tensor-parallel-size:- Single NUMA node → leave default.
- Multi NUMA → set to the NUMA node count
Nfrom Procedure 1. --tensor-parallel-size=6is currently unsupported on CPU; avoid it.
- Size
VLLM_CPU_KVCACHE_SPACE(GiB per NUMA node):- Start at
20–40. Larger value → more concurrency / longer context, but must fit in node-local RAM. - If the server OOMs or pages, halve and retry.
- Start at
- Bind OpenMP threads with
VLLM_CPU_OMP_THREADS_BIND:- Prefer
auto. Use manual ranges (0-31|32-63) only whenautomis-pins (verify withnumastat -p $(pgrep -f 'vllm serve|api_server' | head -n1)).
- Prefer
- (Experimental) Low-latency small-batch serving:
VLLM_CPU_SGL_KERNEL=1enables x86 small-batch kernels. Requires AMX, BF16 weights, and compatible shapes.
- Quantization (when functional quality is acceptable):
- Try INT8 or AWQ to reduce weight memory and memory-bandwidth pressure. Validate quality before promoting.
Full knob reference: tuning matrix.
Procedure 4 — Benchmark (Minimal CPU Walkthrough)
Goal: measure TTFT, TPOT, and throughput against the running server with a reproducible warm-up.
- Confirm the server is reachable and inspect environment:
curl -s http://localhost:8000/v1/models | jq . docker exec vllm-cpu vllm collect-env # or `vllm collect-env` for native installs SERVER_PID=$(pgrep -f 'vllm serve|api_server' | head -n 1) numastat -p "${SERVER_PID}" # verify NUMA locality - Run
vllm bench servewith warm-ups (warm-ups avoid measuring JIT/compile overhead):vllm bench serve \ --model <model-id> \ --dataset-name random \ --random-input-len 128 \ --random-output-len 128 \ --num-prompts 100 \ --num-warmups 5 \ --request-rate inf \ --save-result \ --result-dir ./bench-results \ --percentile-metrics ttft,tpot,itlExecution context: prefix
vllm bench servewithdocker exec vllm-cpuif you deployed via Procedure 2 (Docker), or run it directly on a native/venv install. A nativeFailed to infer device typeerror means the generic CUDA wheel is installed instead of the CPU wheel — reinstall the wheel whose version ends in+cpu(e.g.0.20.2+cpu) fromhttps://download.pytorch.org/whl/cpu. - Sweep methodically — one variable per run:
- Vary input/output lengths:
64,128,256,512. - Vary concurrency via
--num-prompts:10,50,100,200,500. - Track TTFT, TPOT, output tokens/sec, requests/sec, peak RSS, NUMA locality, and any OOM events.
- When tuning, change only one of
VLLM_CPU_KVCACHE_SPACE,VLLM_CPU_OMP_THREADS_BIND,--max-num-batched-tokens,--max-num-seqs, or--block-sizeper run. Compare results across runs using the saved JSON files in./bench-results.
- Vary input/output lengths:
- For the full CI-grade harness (
run-performance-benchmarks.shwithON_CPU=1,SERVING_JSON,DRY_RUN,MODEL_FILTER,DTYPE_FILTER), see the upstream vLLM benchmarking docs.
Output the Agent Should Produce
After running these procedures, return to the user:
- The hardware validation summary (Xeon generation, AMX flags present, NUMA node count).
- The exact
docker runcommand used, with values chosen for their hardware. - Any tuning recommendations with the one knob changed per recommendation and the expected metric impact.
- Benchmark numbers (TTFT, TPOT, throughput) with the corresponding configuration.
References
- Tuning matrix — full env-var / CLI knob table with guard rails.
- vLLM CPU installation guide
- vLLM CPU-supported models
- vLLM optimization and tuning guide
- vLLM Intel quantization support
- Intel Xeon AI Performance Advisor (cloud)
- Intel Xeon AI Performance Advisor (on-prem)
- Intel AI Software Catalog — Model Guidance