vLLM 在 IBM Z(s390x)平台上的 CPU 从源码构建与容器部署指南
【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllm
导读
本文面向需要在 IBM Z / LinuxONE 主机的 s390x CPU 架构上运行 vLLM 的开发者与运维工程师,完整讲解当前仓库中 s390x CPU 后端从源码编译、本地 wheel 安装、Docker 镜像构建到 OpenAI 兼容服务启动的全流程。读完本文,你将掌握:s390x 平台当前的能力边界与硬件/工具链前提、逐个从源码构建torchvision/llvmlite/numba/opencv-python-headless/hf-xet等无预编译 wheel 依赖的关键细节、绕过 LLVM 版本与 Protobuf C++ 扩展等典型坑位的方法,以及如何利用仓库中的 VXE 向量化注意力内核在 Z15 及以上机器上获得原生推理性能。
一、s390x 支持概览:能力边界与当前状态
vLLM 对 IBM Z 平台(s390x 架构)的支持目前仍处于experimental(实验性)阶段。核心限制是:必须从源码构建才能在 IBM Z 上原生运行——当前官方既没有预构建的 IBM Z CPU wheel,也没有预构建的镜像(这一点在 docs/getting_started/installation/cpu.s390x.inc.md 及 docker/Dockerfile.s390x 中均可得到印证)。
从该文档可以确认,s390x CPU 实现当前支持的数据精度与量化方案为:
- 浮点精度:
FP32、BF16、FP16 - 量化:
AWQ与GPTQ的 4-bit 量化,以及compressed-tensors的INT8 W8A8量化
从仓库源码结构看,这一支持并非简单的"能跑通",而是有专门针对 s390x 的底层实现:vLLM 的 CPU 注意力后端为 IBM Z 提供了独立的向量化实现路径(详见下文第五节源码佐证)。因此,使用方需要明确这是针对特定硬件体系做的原生适配,而不是靠模拟或通用回退路径。
二、硬性前提条件(Requirements)
在动手构建之前,请先核对目标环境是否满足以下全部条件,任何一项缺失都会导致构建失败或运行期崩溃:
| 条件 | 要求 | 说明 |
|---|---|---|
| 操作系统 | Linux | 文档示例基于 RHEL 9.6(UBI 9.6) |
| 编译器 | gcc/g++ >= 14.0.0 | 需配套 Command Line Tools(即完整的开发工具链,RHEL 上对应gcc-toolset-14) |
| 指令集 | VXE 支持为必需 | 仅适用于Z15 及以上的 IBM Z 主机(VXE 即 Vector Extension Facility) |
| 上游 Python 包 | 需从源码自行构建 | torchvision、llvmlite、numba、opencv-python-headless、hf-xet均没有 s390x 的预编译 wheel |
上述第 4 点是构建链路中最耗时的部分,因为torchvision、llvmlite、numba、opencv都不是小项目。文档给出的建议做法是参照仓库内的多阶段构建脚本 docker/Dockerfile.s390x 中各阶段使用的精确版本与编译命令逐一构建——也就是说,Dockerfile 本身就是一份"可追溯的构建配方"。
为什么这几个包必须从源码构建?从 requirements/cpu.txt 可以看出仓库侧的印证:
torchvision; platform_machine != "s390x" ...—— 官方依赖中直接排除了 s390x 的 torchvision;numba == 0.65.0; platform_machine != "s390x"—— numba 同样在 s390x 上不可通过 pip 直接安装;- 同理,
torchaudio、torchcodec也均以平台标记排除了 s390x。
而 requirements/build/cpu.txt 则明确torch==2.13.0+cpu需要覆盖x86_64/s390x/aarch64,说明 PyTorch CPU 版本身对 s390x 是有关键支持的。
三、在 IBM Z 上从源码构建 vLLM
本节完全对应原文档build-wheel-from-source章节的命令流程,建议按顺序逐段执行。
3.1 安装系统级构建依赖
以 RHEL 9.6 为例,先用包管理器安装 vLLM 构建所需的基础工具链:
dnf install -y \ which procps findutils tar vim git patch xz ninja-build \ gcc-toolset-14 gcc-toolset-14-binutils gcc-toolset-14-libatomic-devel zlib-devel \ libjpeg-turbo-devel libtiff-devel libpng-devel libwebp-devel freetype-devel harfbuzz-devel \ openssl-devel openblas openblas-devel autoconf automake libtool cmake numpy libsndfile \ clang llvm-devel llvm-static clang-devel要点说明:
gcc-toolset-14系列包是为了满足 gcc/g++ ≥ 14 的前提(注意使用前需 source 对应环境,Dockerfile 中通过显式设置PATH/LD_LIBRARY_PATH指向/opt/rh/gcc-toolset-14/root完成激活,参见 docker/Dockerfile.s390x);openblas/libsndfile等是 PyTorch CPU 推理与音频解码链路常用依赖;llvm-devel、clang等与后面 llvmlite/numba 的源码构建相关(但需注意版本坑,见 3.4 节)。
3.2 从源码构建并安装 numactl
vLLM 的 CPU 后端依赖numactl做 NUMA 感知的核绑定与内存分配,而发行版仓库中的版本可能过旧,因此文档要求从源码安装 v2.0.19:
curl -LO https://github.com/numactl/numactl/archive/refs/tags/v2.0.19.tar.gz tar -xvzf v2.0.19.tar.gz cd numactl-2.0.19 ./autogen.sh && ./configure && make && make install cd ..注:在 docker/Dockerfile.s390x 的
numa-build阶段中,numactl 同样以 v2.0.19 源码构建,并通过C_INCLUDE_PATH=/usr/local/include让后续的 vLLM 编译能找到头文件。
3.3 安装 Rust(≥ 1.80)
outlines-core、uvloop、hf-xet这三个 Python 包在 s390x 上需要 Rust 工具链参与构建,官方要求 Rust ≥ 1.80:
curl https://sh.rustup.rs -sSf | sh -s -- -y && \ . "$HOME/.cargo/env"3.4 从源码构建 5 个无预编译 wheel 的上游包
这一步是整个流程中最容易出现"连环坑"的部分,官方明确提示:
Pre-built wheels are not available for s390x for the following packages. Build them from source before building vLLM:
torchvision,llvmlite,numba,opencv-python-headless,hf-xet. 精确版本与构建命令可参考 docker/Dockerfile.s390x 中各 multi-stage 构建阶段。
其中值得单独展开的是llvmlite 与 LLVM 20 的版本冲突:
LLVM 20 必须从源码构建(llvmlite 的硬性要求)
llvmlite v0.47要求 LLVM 20,但 UBI 9.6 / RHEL 9.6 仓库默认提供的是LLVM 21,二者不兼容。因此必须先从源码构建 LLVM 20(只需 SystemZ 目标后端即可,可大幅缩短编译时间):
curl -LO https://github.com/llvm/llvm-project/releases/download/llvmorg-20.1.8/llvm-project-20.1.8.src.tar.xz tar -xf llvm-project-20.1.8.src.tar.xz cmake -G Ninja -S llvm-project-20.1.8.src/llvm -B llvm-build \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/opt/llvm20 \ -DLLVM_TARGETS_TO_BUILD="SystemZ" \ -DLLVM_ENABLE_RTTI=ON \ -DLLVM_BUILD_TOOLS=OFF \ -DLLVM_BUILD_UTILS=ON \ -DLLVM_BUILD_EXAMPLES=OFF \ -DLLVM_BUILD_TESTS=OFF \ -DLLVM_INCLUDE_TESTS=OFF \ -DLLVM_INCLUDE_EXAMPLES=OFF \ -DLLVM_INCLUDE_BENCHMARKS=OFF ninja -C llvm-build install关键参数解读:
-DLLVM_TARGETS_TO_BUILD="SystemZ":只编译 IBM Z 后端,这是大幅节省构建时间与磁盘的关键;-DLLVM_ENABLE_RTTI=ON:llvmlite 运行时依赖 RTTI,必须开启;- 关闭 Tools/Tests/Examples/Benchmarks 各开关均为最小化构建;
- 安装前缀
/opt/llvm20需与下一步保持一致。
随后基于这份自建 LLVM 20 构建 llvmlite:
CMAKE_PREFIX_PATH=/opt/llvm20 LLVM_CONFIG=/opt/llvm20/bin/llvm-config \ python setup.py bdist_wheel对照 docker/Dockerfile.s390x 的llvm20-build与numba-builder阶段可知,llvmlite 版本固定为v0.47.0,numba 固定为0.65.0,且构建 numba 时还额外对numba/_dispatcher.cpp打了一个补丁(在pycore_atomic.h之前插入dynamic_annotations.h头文件),这是仓库为 s390x 验证过的修正,自行构建时可参照。
至于torchvision(对应v0.28.0)、opencv-python-headless(对应 opencv-python 分支90)、hf-xet(基于 Rust 的maturin build --release)的构建方式,官方并未在文档正文逐一展开,而是统一指向 Dockerfile 中的torch-vision、opencv-builder、hf-xet-builder阶段——那是经过仓库验证的"标准答案",强烈建议直接照抄其中的命令与版本号。
3.5 安装 vLLM 依赖并构建 wheel
完成上述 5 个 wheel 后,即可安装 vLLM 的 CPU 构建依赖并产出最终 wheel。官方首选uv:
uv pip install -v \ /path/to/torchvision.whl \ /path/to/llvmlite.whl \ /path/to/numba.whl \ /path/to/opencv_python_headless.whl \ /path/to/hf_xet.whl \ -r requirements/build/cpu.txt \ -r requirements/cpu.txt \ --torch-backend cpu \ --index-strategy unsafe-best-match && \ VLLM_TARGET_DEVICE=cpu VLLM_CPU_MOE_PREPACK=0 python setup.py bdist_wheel && \ uv pip install dist/*.whl如果使用传统pip,可切换到如下等价命令(需额外指定 PyTorch CPU 索引):
pip install -v \ --extra-index-url https://download.pytorch.org/whl/cpu \ /path/to/torchvision.whl \ /path/to/llvmlite.whl \ /path/to/numba.whl \ /path/to/opencv_python_headless.whl \ /path/to/hf_xet.whl \ -r requirements/build/cpu.txt \ -r requirements/cpu.txt && \ VLLM_TARGET_DEVICE=cpu VLLM_CPU_MOE_PREPACK=0 python setup.py bdist_wheel && \ pip install dist/*.whl两个关键构建期环境变量的作用:
VLLM_TARGET_DEVICE=cpu:显式声明目标是 CPU 设备,控制 setup.py 中平台判定(仓库中可见其对s390x与aarch64/x86_64的显式处理)以及 C++ 扩展的编译开关;VLLM_CPU_MOE_PREPACK=0:关闭 MoE 权重的预打包(prepack)优化路径。从 csrc/cpu/dnnl_kernels.cpp 等源码中可以看到,部分 CPU 内核针对__powerpc64__/__s390x__有不同的编译路径,这里通过环境变量保持保守行为,避免在 s390x 上引入未经验证的打包布局。
3.6 推荐设置 LD_PRELOAD 加载 TCMalloc
为了获得最佳内存分配性能,官方警告必须构建并预加载 TCMalloc(gperftools):
# 从源码构建并安装 TCMalloc curl -LO https://github.com/gperftools/gperftools/releases/download/gperftools-2.16/gperftools-2.16.tar.gz tar -xzf gperftools-2.16.tar.gz cd gperftools-2.16 ./configure --enable-minimal && make -j$(nproc) && sudo make install sudo ldconfig cd .. # 加入 LD_PRELOAD export LD_PRELOAD="/usr/local/lib/libtcmalloc_minimal.so.4:$LD_PRELOAD"说明:CPU 推理场景下大量 KV Cache 与激活值的分配/释放对内存分配器极其敏感,TCMalloc 能显著改善碎片化。如果走 Docker 路线则无需手动处理——官方镜像 docker/Dockerfile.s390x 的gperftools-build阶段已构建 gperftools 2.16 并通过ENV LD_PRELOAD=/usr/local/lib/libtcmalloc_minimal.so.4自动注入。
3.7 绕开 Protobuf C++ 扩展崩溃(s390x 特有)
这是 IBM Z 上运行 vLLM 时必须处理的另一个坑:s390x 上 Protobuf 的 C++ 扩展会崩溃。安装完成后需强制使用纯 Python 实现,并删除 C++ 扩展:
export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python # 移除在 s390x 上会崩溃的 C++ protobuf 扩展 SITE_PKGS=$(python -c "import site; print(site.getsitepackages()[0])") rm -rf "$SITE_PKGS/google/_upb/"*.so \ "$SITE_PKGS/google/protobuf/pyext/"*.so 2>/dev/null || truerm -rf的路径做了精细限定(仅删除_upb与pyext下的.so),并加了2>/dev/null || true容错,可安全执行。同样地,Dockerfile 的最终阶段也执行了等价清理(见 docker/Dockerfile.s390x 中rm -rf /opt/vllm/.../google/_upb/*.so ...),并在环境变量中预设了PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python。
四、Docker 镜像构建与容器化部署
官方为 s390x 提供了专用镜像构建配方 docker/Dockerfile.s390x。该 Dockerfile 是一个高度工程化的多阶段构建,基础镜像为registry.access.redhat.com/ubi9/ubi-minimal:9.6(RHEL UBI 9.6),整体流水线包含:
python-install阶段:安装 Python 3.12 并创建/opt/vllmvenv,装入uv;rust阶段:安装 Rustup 稳定版工具链;numa-build阶段:构建 numactl 2.0.19;gperftools-build阶段:构建 TCMalloc 2.16;torch-vision阶段:在安装torch==2.13.0+cpu后从源码构建 torchvisionv0.28.0;hf-xet-builder阶段:用 Rust +maturin构建hf_xet;llvm20-build阶段:从源码构建 LLVM 20.1.8(仅 SystemZ 目标);numba-builder阶段:构建 llvmlite v0.47.0 与 numba 0.65.0(含_dispatcher.cpp补丁);opencv-builder阶段:从源码构建opencv-python(分支 90,headless 模式);vllm-cpu最终阶段:通过 BuildKit--mount=type=bind将上述各阶段产物以只读方式挂入,统一安装依赖后执行VLLM_TARGET_DEVICE=cpu VLLM_CPU_MOE_PREPACK=0 python setup.py bdist_wheel,最后以vllm serve作为默认入口。
整个多阶段设计把"大量无关但必需的源码编译"与"最终的 vLLM 编译"彻底隔离,任意中间包的重编都不会污染最终层缓存,这也是阅读该 Dockerfile 时值得借鉴的工程实践。
4.1 构建镜像
docker build -f docker/Dockerfile.s390x \ --tag vllm-cpu-env .4.2 启动 OpenAI 兼容服务
# 启动 OpenAI server docker run --rm \ --security-opt seccomp=unconfined \ --cap-add SYS_NICE \ --shm-size 4g \ -p 8000:8000 \ -e VLLM_CPU_KVCACHE_SPACE=<KV cache space> \ -e VLLM_CPU_OMP_THREADS_BIND=<CPU cores for inference> \ vllm-cpu-env \ --model meta-llama/Llama-3.2-1B-Instruct \ --dtype bfloat16 \ other vLLM OpenAI server arguments各参数含义:
--security-opt seccomp=unconfined与--cap-add SYS_NICE:CPU 推理线程的调度与亲和性设置需要放宽容器默认的 seccomp 与权限限制;官方 tip 提到也可以用--privileged=true达到同样效果,但该方式权限面过宽,不推荐在生产使用;--shm-size 4g:为进程间共享内存预留足够空间(数据并行与 NCCL 等分布式初始化依赖/dev/shm);VLLM_CPU_KVCACHE_SPACE:指定分配给 KV Cache 的显存等价空间大小,是 CPU 推理吞吐的关键调优项(例如8表示 8GB);VLLM_CPU_OMP_THREADS_BIND:指定用于推理的 CPU 核列表/亲和策略(例如0-31),vLLM 的 CPU 后端会基于 OpenMP 线程做物理核绑定;- 容器镜像入口已固定为
vllm serve,因此docker run末尾直接追加模型名、--dtype等 serve 参数即可。
需要注意,示例中默认拉起的是带 Chat 模板与 OpenAI 协议兼容的 serve 模式;<KV cache space>、<CPU cores for inference>两处需按实际机型核数与内存替换。
五、源码级佐证:s390x 并非"能跑"而是"有原生内核"
为了让你对"experimental"的含金量有准确预期,这里补充几处仓库中可验证的 s390x 专属实现(均为本文主题直接相关的核心证据,非泛泛介绍):
1. 独立的 VXE 注意力内核。csrc/cpu/cpu_attn_vxe.hpp 是专门面向 IBM Z 的注意力实现文件,内含gemm_micro_s390x_Mx8_Ku4、gemm_macro_s390x_Mx8_Ku4、TileGemmS390X模板类以及AttentionImpl<ISA::VXE, ...>特化;文件头部注明 "s390x Vector = 16 bytes (128 bits)",即基于 128 位 VXE 向量寄存器实现分块 GEMM 与 attention 迭代。CPU 注意力调度的 ISA 枚举也包含VXE(见 csrc/cpu/cpu_attn_impl.hpp),运行期 ISA 判定会回退到 VXE(见 csrc/cpu/cpu_attn.cpp 中的ISA::VXE分支)。这正是"需要 VXE、仅支持 Z15 及以上"这条硬性要求的内核级原因。
2. 大端序与 FP16 的定制处理。csrc/cpu/cpu_types_vxe.hpp 中有两条关键注释:s390x 的 FP16 通过自定义的位操作转换实现(PyTorch 本身缺少原生 s390x FP16 支持);且由于 s390x 是大端架构,BF16 需要以特定字节序排列才能得到正确结果。这解释了为什么 FP16/BF16 在文档中被单独列出为"支持但不平凡"的能力。
3. 快速指数函数的 VXE 指令路径。csrc/cpu/cpu_arch_macros.h 在__s390x__分支中通过DEFINE_FAST_EXP宏把 softmax 所需的exp委托给cpu_types_vxe.hpp中基于 VXE intrinsics 实现的 5 项 minimax 多项式近似——这是注意力 softmax 在 s390x 上保持性能的关键底层支撑。
4. FP8 KV Cache 在 s390x 上为占位路径。同文件 csrc/cpu/cpu_types_vxe.hpp 注释指出 FP8 相关代码在 s390x 上是 dead code(FP8 KV Cache 仅面向 x86),这从内核层面印证了文档中量化支持清单为何只列出 AWQ/GPTQ 4-bit 与 compressed-tensors INT8 W8A8,而不包含 FP8 KV Cache。
5. CPU 指令分发的体系结构适配。构建期脚本 csrc/cpu/generate_cpu_attn_dispatch.py 会为 s390x 生成["VXE", "VEC", "VEC16"]的指令候选序列,说明注意力调度在 s390x 上按 VXE 优先、通用向量次之的顺序做编译期/运行期派发。
六、总结与常见问题提醒
在 IBM Z(s390x)上落地 vLLM 的关键结论可浓缩为以下几条:
- 定位是实验性原生支持:无任何预构建 wheel 或镜像,必须从源码构建,docker/Dockerfile.s390x 是最可信的构建配方参照物;
- 硬件门槛清晰:必须是 Z15 及以上(VXE 必需),工具链需 gcc/g++ ≥ 14;
- 五个上游包必须自建:
torchvision、llvmlite、numba、opencv-python-headless、hf-xet,其中 llvmlite 又强制要求先自建 LLVM 20(仓库发行版默认 LLVM 21 不可用); - 两个运行期必做动作:通过
LD_PRELOAD注入 TCMalloc 提升内存分配性能;设置PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python并删除 Protobuf C++ 扩展以避免崩溃; - 能力范围:支持 FP32/BF16/FP16 精度,AWQ、GPTQ 4-bit 与 compressed-tensors INT8 W8A8 量化;底层由 VXE 向量化注意力内核提供原生性能路径。
按上述流程完成构建后,即可通过vllm serve(或容器入口)在 IBM Z 主机上以 OpenAI 兼容协议对外提供 LLM 推理服务,并继续沿用 vLLM 标准的 CPU 部署调优手段(VLLM_CPU_KVCACHE_SPACE、VLLM_CPU_OMP_THREADS_BIND等)进行性能调优。
【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考