Skip to content

Commit e0e4cf4

Browse files
committed
ci(mm-rdma): dedicated native wheel for the RDMA e2e
The RDMA multimodal e2e needs a gateway built with --features mm-rdma, but the shared wheel is cross-compiled with maturin --zig (LLVM libc++), which can't link nixl-sys's GNU-libstdc++ C++ stub. Build a dedicated mm-rdma wheel natively on the bare Ubuntu CPU runner (GNU libstdc++, same runner image as the GPU e2e lanes), upload it as smg-wheel-mm-rdma, and run test_multimodal_rdma.py in a dedicated e2e-1gpu-mm-rdma job via e2e-gpu-job's new wheel_artifact input. The shared wheel and other e2e lanes are untouched; the RDMA test is excluded from the shared vLLM lane. Signed-off-by: Simo Lin <linsimo.mark@gmail.com>
1 parent 294608d commit e0e4cf4

4 files changed

Lines changed: 117 additions & 2 deletions

File tree

.github/workflows/e2e-gpu-job.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ on:
5454
type: string
5555
default: "nixl"
5656
description: "KV transfer backend for vLLM PD workers: nixl or mooncake"
57+
wheel_artifact:
58+
required: false
59+
type: string
60+
default: "smg-wheel"
61+
description: "Name of the wheel artifact to install (e.g. smg-wheel-mm-rdma)"
5762

5863
jobs:
5964
run:
@@ -92,7 +97,7 @@ jobs:
9297
- name: Download wheel artifact
9398
uses: actions/download-artifact@v8
9499
with:
95-
name: smg-wheel
100+
name: ${{ inputs.wheel_artifact }}
96101
path: wheel/
97102

98103
- name: Download WASM test fixtures

.github/workflows/pr-test-rust.yml

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,37 @@ jobs:
212212
python3 -c "from smg.smg_rs import Router; print('Rust extension: OK')"
213213
python3 -m smg.launch_router --help > /dev/null && echo "Entry point: OK"
214214
215+
build-wheel-mm-rdma:
216+
# Dedicated mm-rdma wheel for the RDMA e2e, built natively on the bare Ubuntu
217+
# runner (GNU libstdc++). The shared wheel is cross-compiled with
218+
# `maturin --zig`, which ships LLVM libc++ and can't link nixl-sys's
219+
# GNU-libstdc++ C++ stub; building it separately here keeps that off the
220+
# shared wheel so it can't break the other e2e lanes. Runs on the same runner
221+
# image as the GPU e2e lanes, so the native wheel loads there unchanged.
222+
needs: detect-changes
223+
if: >-
224+
always()
225+
&& !cancelled()
226+
&& (github.event_name != 'pull_request'
227+
|| (needs.detect-changes.result == 'success'
228+
&& (needs.detect-changes.outputs.common == 'true'
229+
|| needs.detect-changes.outputs.chat-completions == 'true')))
230+
runs-on: k8s-runner-cpu
231+
permissions:
232+
contents: read
233+
steps:
234+
- uses: actions/checkout@v7
235+
- name: Setup Rust
236+
uses: ./.github/actions/setup-rust
237+
- name: Build mm-rdma wheel
238+
run: bash scripts/ci_build_wheel_mm_rdma.sh
239+
- name: Upload mm-rdma wheel artifact
240+
uses: actions/upload-artifact@v7
241+
with:
242+
name: smg-wheel-mm-rdma
243+
path: bindings/python/dist/*.whl
244+
retention-days: 1
245+
215246
python-unit-tests:
216247
needs: build-wheel
217248
runs-on: k8s-runner-cpu
@@ -508,6 +539,9 @@ jobs:
508539
- engine: vllm
509540
timeout: 24
510541
test_timeout: 18
542+
# The RDMA multimodal test needs the dedicated mm-rdma wheel + a NIXL
543+
# runner; it runs in e2e-1gpu-mm-rdma, not this shared-wheel lane.
544+
test_filter: "--ignore=e2e_test/chat_completions/test_multimodal_rdma.py"
511545
- engine: trtllm
512546
timeout: 32
513547
test_timeout: 18
@@ -529,6 +563,31 @@ jobs:
529563
timeout: ${{ matrix.timeout }}
530564
test_timeout: ${{ matrix.test_timeout }}
531565
test_dirs: ${{ matrix.test_dirs || 'e2e_test/chat_completions' }}
566+
test_filter: ${{ matrix.test_filter || '' }}
567+
secrets: inherit
568+
569+
e2e-1gpu-mm-rdma:
570+
# Isolated RDMA multimodal e2e: installs the dedicated mm-rdma wheel and runs
571+
# only test_multimodal_rdma.py against a vLLM worker on a NIXL-capable runner.
572+
needs: [build-wheel, build-wheel-mm-rdma, detect-changes]
573+
if: >-
574+
always()
575+
&& !cancelled()
576+
&& needs.build-wheel.result == 'success'
577+
&& needs.build-wheel-mm-rdma.result == 'success'
578+
&& (github.event_name != 'pull_request'
579+
|| (needs.detect-changes.result == 'success'
580+
&& (needs.detect-changes.outputs.common == 'true'
581+
|| needs.detect-changes.outputs.chat-completions == 'true')))
582+
uses: ./.github/workflows/e2e-gpu-job.yml
583+
with:
584+
engine: vllm
585+
gpu_tier: "1"
586+
runner: 1-gpu-h100
587+
timeout: 24
588+
test_timeout: 18
589+
test_dirs: e2e_test/chat_completions/test_multimodal_rdma.py
590+
wheel_artifact: smg-wheel-mm-rdma
532591
secrets: inherit
533592

534593
e2e-1gpu-completions:
@@ -1037,7 +1096,7 @@ jobs:
10371096
path: benchmark_go_bindings/
10381097

10391098
finish:
1040-
needs: [pre-commit, python-lint, grpc-proto-build-check, build-wheel, python-unit-tests, unit-tests, benchmarks, e2e-1gpu-chat, e2e-1gpu-completions, e2e-1gpu-embeddings, e2e-1gpu-gateway, e2e-1gpu-responses, e2e-2gpu-pd, e2e-4gpu-chat, e2e-4gpu-gateway, e2e-4gpu-epd, e2e-vendor, go-unit-tests, go-bindings-e2e]
1099+
needs: [pre-commit, python-lint, grpc-proto-build-check, build-wheel, build-wheel-mm-rdma, python-unit-tests, unit-tests, benchmarks, e2e-1gpu-chat, e2e-1gpu-mm-rdma, e2e-1gpu-completions, e2e-1gpu-embeddings, e2e-1gpu-gateway, e2e-1gpu-responses, e2e-2gpu-pd, e2e-4gpu-chat, e2e-4gpu-gateway, e2e-4gpu-epd, e2e-vendor, go-unit-tests, go-bindings-e2e]
10411100
if: always()
10421101
runs-on: k8s-runner-cpu
10431102
permissions: {}
@@ -1048,10 +1107,12 @@ jobs:
10481107
"${{ needs.python-lint.result }}" == "failure" || \
10491108
"${{ needs.grpc-proto-build-check.result }}" == "failure" || \
10501109
"${{ needs.build-wheel.result }}" == "failure" || \
1110+
"${{ needs.build-wheel-mm-rdma.result }}" == "failure" || \
10511111
"${{ needs.python-unit-tests.result }}" == "failure" || \
10521112
"${{ needs.unit-tests.result }}" == "failure" || \
10531113
"${{ needs.benchmarks.result }}" == "failure" || \
10541114
"${{ needs.e2e-1gpu-chat.result }}" == "failure" || \
1115+
"${{ needs.e2e-1gpu-mm-rdma.result }}" == "failure" || \
10551116
"${{ needs.e2e-1gpu-completions.result }}" == "failure" || \
10561117
"${{ needs.e2e-1gpu-embeddings.result }}" == "failure" || \
10571118
"${{ needs.e2e-1gpu-gateway.result }}" == "failure" || \

bindings/python/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ workspace = true
3636
default = ["pyo3/extension-module"]
3737
opencv-video = ["smg/opencv-video"]
3838
vendored-openssl = ["smg/vendored-openssl"]
39+
mm-rdma = ["smg/mm-rdma"]
3940

4041
[profile.ci]
4142
inherits = "release"

scripts/ci_build_wheel_mm_rdma.sh

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#!/bin/bash
2+
# Build the mm-rdma smg wheel for the RDMA e2e, natively on the bare Ubuntu
3+
# runner (GNU libstdc++).
4+
#
5+
# Why a separate build (not the shared ci_build_wheel.sh): the shared wheel is
6+
# cross-compiled with `maturin --zig`, which ships LLVM libc++. nixl-sys (pulled
7+
# by the mm-rdma feature) compiles a C++ stub that references GNU libstdc++
8+
# (std::cerr / _ZSt4cerr), so it must be linked against GNU libstdc++ or the
9+
# wheel fails to import ("undefined symbol: _ZSt4cerr"). Building natively with
10+
# the runner's GNU toolchain links the C++ stub cleanly, and the wheel runs on
11+
# the GPU e2e runner unchanged (same runner image, same libstdc++.so.6).
12+
#
13+
# Assumes ./.github/actions/setup-rust already ran (Rust + build-essential/g++ +
14+
# protoc). This wheel is CI-only (installed by the RDMA e2e job), so a plain
15+
# linux tag is fine.
16+
set -euxo pipefail
17+
18+
# libclang for nixl-sys bindgen; setup-rust installs build-essential (g++ ->
19+
# libstdc++) but not clang.
20+
export DEBIAN_FRONTEND=noninteractive
21+
if command -v sudo >/dev/null 2>&1; then
22+
sudo apt-get update
23+
sudo apt-get install -y --no-install-recommends libclang-dev
24+
else
25+
apt-get update
26+
apt-get install -y --no-install-recommends libclang-dev
27+
fi
28+
29+
# setup-rust adds cargo to GITHUB_PATH; source for good measure (and local runs).
30+
if [ -f "$HOME/.cargo/env" ]; then
31+
source "$HOME/.cargo/env"
32+
fi
33+
export RUSTC_WRAPPER="${RUSTC_WRAPPER:-sccache}"
34+
35+
python3 -m pip install --upgrade pip maturin
36+
37+
echo "Building mm-rdma wheel (native, GNU libstdc++)..."
38+
cd bindings/python
39+
# abi3 wheel (pyo3 abi3-py38) -> one build works for all 3.8+.
40+
# --manylinux off: CI-only wheel; skip auditwheel's manylinux policy and
41+
# dynamically link libstdc++.so.6 (present on the GPU e2e runner).
42+
maturin build \
43+
--profile ci \
44+
--features vendored-openssl,mm-rdma \
45+
--manylinux off \
46+
--out dist
47+
echo "mm-rdma wheel: OK"
48+
ls -lh dist/

0 commit comments

Comments
 (0)