Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
20905fb
feat(core): expose effective KV cache group block sizes
JulienDarve Sep 9, 2026
0a7bb87
fix(core): expose only the effective attention block size
JulienDarve Sep 11, 2026
6836844
fix(core): store effective attention block size in CacheConfig
JulienDarve Sep 11, 2026
9286956
chore: merge upstream main for proto crate draft
JulienDarve Sep 12, 2026
1506805
fix(grpc): avoid DCP field collision and bump proto crate
JulienDarve Sep 12, 2026
f0a61bd
[Rust][Benchmark] Support HF ShareGPT datasets in multi-turn mode (#5…
xiaguan Sep 14, 2026
bbbd0a0
[Bugfix] Carry over queued work when materializing the dedicated stre…
zhaoguochun1995 Sep 14, 2026
a757644
[ROCm][Bugfix] Initialize Ray NIXL agents for sharded RDT (#56687)
AndreasKaratzas Sep 15, 2026
772e4f0
[Bugfix][Rust] Fix HF multi-turn dataset integration (#56915)
khluu Sep 15, 2026
ef5f7cd
[ROCm][DSv4.1][Perf] Dequantize the MXFP8 weight once when dot_scaled…
JohnQinAMD Sep 15, 2026
84e5f3e
[Bugfix] Validate routed-expert prompt offsets before engine submissi…
aoshen02 Sep 15, 2026
ceaa9f9
[Minor] Invert MRV1 specdec method fallback logic (#56899)
njhill Sep 15, 2026
3192898
[ROCm][CI] Prepare TheRock image for CI (#56921)
mawong-amd Sep 15, 2026
a08dffe
[XPU][CI] update gpt-oss package version (#56783)
zhenwei-intel Sep 15, 2026
17bc3e1
[KVConnector][P2P] Configurable unbound-store timeout and one-RTT rej…
liranschour Sep 15, 2026
567f745
[Bugfix] Export weight-cache IPC tensors separately for each client (…
shaohuaxi Sep 15, 2026
e45bb43
[Bugfix][KV Offload] Ignore pending chunks in invalid sliding windows…
jacklin78911-collab Sep 15, 2026
a529c1a
[Bugfix] Handle bare and malformed tool call openers in Gemma4 parser…
wuhangxian Sep 15, 2026
e6eb0d1
[Model][DSv4.1] Store the whole KV in MXFP8 (FlashMLA V4.1 record) (#…
zyongye Sep 15, 2026
381c61e
[Bugfix][NIXL] Report a full prefix cache hit as finished (#56640)
jyizheng Sep 15, 2026
a72c046
[Bugfix] Avoid nested rerank cancellation handlers (#55602)
migarci2 Sep 15, 2026
9d14fd3
[Kernel][MoE] DeepEP v2: async finalize to overlap shared experts wit…
404mario Sep 15, 2026
8765952
[CI/Build] Retry CPU image stream interruptions (#56597)
khluu Sep 15, 2026
a491b60
[CI] Drop root privileges for the OTel GPU sampler (#56941)
khluu Sep 15, 2026
caf56ce
[CI] Pass the scale-out endpoint flag in EC E2E (#56819)
khluu Sep 15, 2026
45779ef
[Bugfix][NIXL] Fix multiple handles xfer race (#56104)
NickLucche Sep 15, 2026
f84b0c4
[Model Runner V2] Tolerate lack of pinned memory support (#56908)
njhill Sep 15, 2026
7dbc3d6
[Cleanup] Remove vestigial `tpu_input_batch.py` (#56898)
njhill Sep 15, 2026
eb61707
[Bugfix] Fix stale HPC QK-norm weights after weight refit (#56706)
aoshen02 Sep 15, 2026
7b7e117
[CI] Extend DSv4 engine readiness timeout on main (#56735)
khluu Sep 15, 2026
cd10ed6
[feature] [xgrammar] support `patternProperties`/`propertyNames`/`une…
cjackal Sep 15, 2026
ec6b14c
[CI] Select the supported DCP backend for PCP eval (#56677)
khluu Sep 15, 2026
f547c23
[Bugfix][Kimi-K3] Keep transient checkpoints out of prefix-cache evic…
Sy0307 Sep 15, 2026
79e205e
[Doc] Clarify ITL vs TPOT Prometheus metrics (#55283)
ItsRoy69 Sep 15, 2026
51918e2
[Bugfix][SparseMLA] Fix piecewise cudagraph capture crash in index gr…
JaredforReal Sep 15, 2026
000c7df
[KV Offload] Add KVCR secondary-tier adapter (#53624)
mkhazraee Sep 15, 2026
8263ea1
[Build] Move DeepGEMM pin to the vLLM fork and update the Mega MoE ca…
zyongye Sep 15, 2026
2e2fdaa
[CI] Extend Arm CPU kernel shard timeout (#56601)
khluu Sep 15, 2026
ca67438
[Bugfix][Frontend] Handle aborted requests in beam search (#56249)
shaohuaxi Sep 15, 2026
6766503
[Feature][PCP] Support decode-only FULL CUDA graphs (#53867)
pisceskkk Sep 15, 2026
2c2cbd8
[Frontend] Use XGrammar schema constraints for DeepSeek V4.1 (#56408)
Ubospica Sep 15, 2026
2983fc6
[CI] Fix NIXL push worker test stub after failure deferral (#56955)
khluu Sep 15, 2026
abb4cb9
[CI] Shard V1 KV Connectors 1→4 (#56324)
Thangnguyenvn98 Sep 15, 2026
073f883
[Perf][DSpark] Collapse DeepSeek-V4.1 draft states before SP all-gath…
Juntian777 Sep 15, 2026
142020c
[Bugfix][Rust Frontend] Honor `add_generation_prompt` in DeepSeek V3.…
YeonwooSung Sep 15, 2026
24bfbd5
[Refactor] Derive is_reasoning_end from the engine grammar (#56200)
sfeng33 Sep 15, 2026
5be911e
[Bugfix] Load reasoning parser plugins before headless engine config …
alexliluz Sep 15, 2026
bb55077
[Perf][Kernel] Integrate Mega-mHC from DeepGEMM for DeepSeek V4.1 (r…
Juntian777 Sep 15, 2026
78eaaad
[Rust Frontend] Add iteration token histogram (#56990)
BugenZhao Sep 15, 2026
6485608
[Bugfix] Measure complete pooling responses (#56760)
taneem-ibrahim Sep 15, 2026
e6960af
[Refactor] StructuredOutputManager x Speculative Decoding Refactor (#…
yzong-rh Sep 15, 2026
a2e8f1e
[XPU][CI]Skip test_chat_completion_with_tools in Intel GPU CI (#56934)
zxd1997066 Sep 15, 2026
4bac767
[Perf][Nemotron] Skip redundant latent-MoE all-reduce at TP>1 (~13% d…
ECMGit Sep 15, 2026
0136df9
[Bugfix][Spec Decode][MoE] Avoid uninitialized EPLB state in DeepSeek…
luoyuctl Sep 15, 2026
f0fbc98
[Frontend] Share max_num_queued_reqs across API server processes (#54…
chaunceyjiang Sep 15, 2026
1e47ec0
[Bugfix][Gemma 4] Don't read fft_length when profiling unified audio …
averma12 Sep 15, 2026
9446ea1
[Bugfix][Spec Decode] Only create draft_id_to_target_id when draft vo…
drslark Sep 15, 2026
836bb38
[Bugfix] Prevent out-of-bounds access in FlashInfer SM90 sparse MLA m…
chaunceyjiang Sep 15, 2026
241e939
[Bugfix][Attention] Stabilize sparse-MLA DCP for GLM PCP evals (#55879)
khluu Sep 15, 2026
35dc273
[ROCm][Spec Decode] Add Aiter MLA decode support non-causal draft blo…
ppalanga Sep 15, 2026
2f46a1d
[CI] Keep Qwen3 Omni DSpark config fixture complete (#57044)
khluu Sep 15, 2026
dffbb71
[ROCm][Perf] Optimize DSV4.1 K=512 decode top-k on gfx950 (#56743)
Fangzhou-Ai Sep 15, 2026
2fcc524
[Bugfix] Avoid nested score cancellation handlers for /v1/score alias…
taneem-ibrahim Sep 15, 2026
df42d11
[Config] Infer HiSparse attention config from HiSparseConnector (#57041)
NickLucche Sep 15, 2026
18f8aa0
[Refactor] Remove dead kernel code (#56845)
yewentao256 Sep 15, 2026
38ca7a8
[Bugfix][HiSparse] Preserve per-layer offsets in KV cache bindings (#…
LucasWilkinson Sep 15, 2026
b6ce714
[Bugfix] Format kernel-import errors eagerly so warning_once does not…
zwang86 Sep 15, 2026
f2aad6a
[MRV2] Buffer util simplifications (#56888)
njhill Sep 15, 2026
1257512
[DSA] Wire DeepGEMM sparse MQA logits into the DeepSeek V4.1 indexer …
JaredforReal Sep 15, 2026
c6fa1f0
[Perf][Kernel] Add sampled filtering for persistent top-k (#56346)
mgoin Sep 15, 2026
aa5ea01
refactor(rust): move effective block size getter to client
JulienDarve Sep 15, 2026
0fefffc
[KVConnector][NIXL] Support attention-HMA layouts in pipeline-paralle…
zixi-qi Sep 15, 2026
031f581
[Build][NVIDIA] Update public Rubin dependencies and MSA compatibilit…
wangshangsam Sep 15, 2026
85c1f58
[BugFix][Model Runner V2][Spec Decode] Fix decode instance's multi-la…
TheEpicDolphin Sep 16, 2026
1fd119d
[Pooling] Cap max-length padding for chunked embeddings (#56505)
taneem-ibrahim Sep 16, 2026
c8d1cf0
[ROCm] [Bugfix] Enable Load and Inference of GLM-5.3-Flash Quark MXFP…
ColinZ22 Sep 16, 2026
a4d2d9d
[ROCm][Kimi-K3] Enable a4w4 flydsl kernels for KimiK3 (#53940)
ppalanga Sep 16, 2026
b0898a4
[Misc] Allow install empty package from pip (#41074)
wangxiyuan Sep 16, 2026
7d4bba5
[Doc] Show how to get Responses prompt token IDs (#55912)
franciscojavierarceo Sep 16, 2026
0673de9
[Rust Frontend][Metrics] Add per-request preemption histogram (#57033)
reidliu41 Sep 16, 2026
bfd713b
[Rust Frontend] Support HF config overrides `--hf-overrides` (#56931)
BugenZhao Sep 16, 2026
22bb158
[Bugfix][ROCm] Fix MiniMax-M3 fused MXFP8 block scale (#53674)
maithilijoshi20 Sep 16, 2026
fdfcbbc
[CI/Build][Rust Frontend] Retire Buf schema publishing (#57046)
JulienDarve Sep 16, 2026
4ace5cd
[XPU] fix_test_worker_memory_snapshot_for_xpu (#50097)
mayuyuace Sep 16, 2026
ccbaed5
[XPU] Route to fused_qk_rmsnorm_rope_gate triton kernel (#56096)
mfylcek Sep 16, 2026
c16bb60
[Bugfix][Rust Frontend] Tolerate NaN-corrupted logprobs in engine-cor…
almersawi Sep 16, 2026
57c67c8
Merge latest main into jdarve/kv-cache-group-metadata
BugenZhao Sep 16, 2026
f6cbb58
Use a path-only workspace dependency for vllm-proto
BugenZhao Sep 16, 2026
622934e
[XPU] Honor device_ids for worker device placement (#56015)
chaojun-zhang Sep 16, 2026
75dc588
[KV Offload] Add per-request `max_load_tokens control` (#55885)
albertoperdomo2 Sep 16, 2026
a31ec3a
[LoRA][Nemotron] Add LoRA support for Nemotron VL models (for the lan…
danisereb Sep 16, 2026
6ecd97f
[Perf][DSpark] Add KV-only context insertion across V4.1 cache format…
0z5a Sep 16, 2026
af1c014
[Bugfix] Make GPU sync checks safe under torch.compile (#56904)
khluu Sep 16, 2026
711768f
[CI][ROCm] Add opt-in TheRock builds for AMD CI (#56351)
AndreasKaratzas Sep 16, 2026
961c5b6
[Bugfix][KV Offload] Restore MTP-retained sliding-window history (#56…
jacklin78911-collab Sep 16, 2026
ee2c27d
Fix cache config fixture in engine ready timeout test
BugenZhao Sep 16, 2026
fa2a26f
Merge branch 'main' into jdarve/kv-cache-group-metadata
BugenZhao Sep 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 2 additions & 1 deletion .buildkite/intel_jobs/entrypoints_intel.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ steps:
'cd tests &&
pytest -v -s tool_use
--deselect="tests/tool_use/mistral/test_mistral_tool_calls.py::test_tool_call_none_with_tools[ministral-3b]"
--deselect="tests/tool_use/test_chat_completions.py::test_chat_completion_with_tools[granite-3.0-8b]" &&
--deselect="tests/tool_use/test_chat_completions.py::test_chat_completion_with_tools[granite-3.0-8b]"
--deselect="tests/tool_use/test_chat_completions.py::test_chat_completion_with_tools[llama3.2]" &&
pytest -v -s entrypoints/tool_parsers &&
pytest -v -s entrypoints/generate &&
pytest -v -s entrypoints/anthropic &&
Expand Down
3 changes: 2 additions & 1 deletion .buildkite/intel_jobs/lm_eval_intel.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ steps:
commands:
- >-
bash .buildkite/scripts/hardware_ci/run-intel-test.sh
'cd tests &&
'uv pip install "gpt-oss[eval]==0.0.5" &&
cd tests &&
pytest -s -v evals/gpt_oss/test_gpqa_correctness.py --config-list-file=configs/models-xpu.txt'
2 changes: 1 addition & 1 deletion .buildkite/intel_jobs/test-intel.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ steps:
commands:
- >-
bash .buildkite/scripts/hardware_ci/run-intel-test.sh
'cd tests &&
'cd tests && pip install dpctl &&
pytest -v -s v1/core --ignore=v1/core/test_reset_prefix_cache_e2e.py --ignore=v1/core/test_scheduler_e2e.py &&
pytest -v -s v1/engine --ignore=v1/engine/test_output_processor.py &&
pytest -v -s v1/sample --ignore=v1/sample/test_logprobs.py --ignore=v1/sample/test_logprobs_e2e.py -k "not test_topk_only and not test_topp_only and not test_topk_and_topp" &&
Expand Down
78 changes: 63 additions & 15 deletions .buildkite/scripts/ci-bake-rocm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,26 @@ prepare_ci_build_context() {
echo "Using canonical CI Docker context: ${ROCM_BUILD_CONTEXT_ROOT}"
}

configure_custom_rocm_stages() {
using_custom_rocm_dockerfiles || return 0
local context_root="${ROCM_BUILD_CONTEXT_ROOT:-.}"
local dockerfile="${context_root}/${CI_BASE_DOCKERFILE}"
local stages=""

(cd "${context_root}" && \
validate_rocm_dockerfile "${CI_BASE_DOCKERFILE}" \
ci_base test export_vllm export_test_smoke csrc-build rust-build) \
|| return $?
# Hash all stages for custom layouts, including additional helper stages.
stages=$(rocm_dockerfile_stages "${dockerfile}" | paste -sd ' ')
CI_BASE_DOCKERFILE_STAGES="${CI_BASE_DOCKERFILE_STAGES:-${stages}}"
ROCM_CSRC_DOCKERFILE_STAGES="${ROCM_CSRC_DOCKERFILE_STAGES:-${stages}}"
ROCM_RUST_DOCKERFILE_STAGES="${ROCM_RUST_DOCKERFILE_STAGES:-${stages}}"
if [[ " ${stages} " != *" build_rocshmem "* ]]; then
unset ROCSHMEM_BRANCH ROCSHMEM_CACHE_KEY DEEPEP_CACHE_KEY
fi
}

compose_dependency_cache_key() {
local prefix="$1"
local material="$2"
Expand Down Expand Up @@ -569,11 +589,11 @@ hash_dockerfile_stages() {
}
emit = 0
}
$1 == "FROM" {
toupper($1) == "FROM" {
stage = ""
for (idx = 1; idx <= NF; idx++) {
if (tolower($idx) == "as" && idx < NF) {
stage = $(idx + 1)
stage = tolower($(idx + 1))
}
}
emit = (stage in wanted)
Expand Down Expand Up @@ -613,11 +633,11 @@ discover_dockerfile_stage_args() {
}
{
line = $0
if ($1 == "FROM") {
if (toupper($1) == "FROM") {
stage = ""
for (idx = 1; idx <= NF; idx++) {
if (tolower($idx) == "as" && idx < NF) {
stage = $(idx + 1)
stage = tolower($(idx + 1))
}
}
emit = (stage in wanted)
Expand All @@ -630,7 +650,7 @@ discover_dockerfile_stage_args() {
for (idx = 1; idx <= line_count; idx++) {
line = lines[idx]
arg_name = line
sub(/^[[:space:]]*ARG[[:space:]]+/, "", arg_name)
sub(/^[[:space:]]*[Aa][Rr][Gg][[:space:]]+/, "", arg_name)
if (arg_name != line) {
sub(/[=[:space:]].*/, "", arg_name)
if (arg_name ~ /^[A-Za-z_][A-Za-z0-9_]*$/) {
Expand Down Expand Up @@ -716,7 +736,7 @@ extract_dockerfile_arg_default() {
if [[ -n "${ROCM_BUILD_CONTEXT_ROOT:-}" && "${dockerfile}" != /* ]]; then
physical_dockerfile="${ROCM_BUILD_CONTEXT_ROOT}/${dockerfile}"
fi
sed -n -E "s/^[[:space:]]*ARG[[:space:]]+${arg_name}=\"?([^\"[:space:]]+)\"?.*/\\1/p" \
sed -n -E "s/^[[:space:]]*[Aa][Rr][Gg][[:space:]]+${arg_name}=\"?([^\"[:space:]]+)\"?.*/\\1/p" \
"${physical_dockerfile}" | head -1
}

Expand Down Expand Up @@ -1000,7 +1020,21 @@ create_and_bootstrap_builder() {
}

init_config() {
# shellcheck source=.buildkite/scripts/rocm/build-config.sh
source "$(dirname "${BASH_SOURCE[0]}")/rocm/build-config.sh"
configure_rocm_build

TARGET="${1:-test-ci}"
if using_custom_rocm_dockerfiles; then
if [[ -z "${BASE_IMAGE:-}" ]]; then
echo "Custom ROCm builds require BASE_IMAGE from the selected base handoff" >&2
return 1
fi
if ! is_ci_base_target && [[ -z "${CI_BASE_IMAGE:-}" ]]; then
echo "Custom ROCm builds require CI_BASE_IMAGE from the selected ci_base handoff" >&2
return 1
fi
fi
BAKE_TARGETS=("${TARGET}")
DEPENDENCY_CACHE_TARGETS=()
CI_HCL_SOURCE="${CI_HCL_SOURCE:-${CI_HCL_FILE:-${DEFAULT_CI_HCL_SOURCE}}}"
Expand All @@ -1010,10 +1044,12 @@ init_config() {
PYTORCH_ROCM_ARCH="${PYTORCH_ROCM_ARCH:-gfx90a;gfx942;gfx950}"
CI_BASE_CONTENT_FILES="${CI_BASE_CONTENT_FILES:-${DEFAULT_CI_BASE_CONTENT_FILES}}"
CI_BASE_DOCKERFILE="${CI_BASE_DOCKERFILE:-${DEFAULT_CI_BASE_DOCKERFILE}}"
CI_BASE_DOCKERFILE_STAGES="${CI_BASE_DOCKERFILE_STAGES:-${DEFAULT_CI_BASE_DOCKERFILE_STAGES}}"
if ! using_custom_rocm_dockerfiles; then
CI_BASE_DOCKERFILE_STAGES="${CI_BASE_DOCKERFILE_STAGES:-${DEFAULT_CI_BASE_DOCKERFILE_STAGES}}"
fi
CI_BASE_METADATA_VERSION="${CI_BASE_METADATA_VERSION:-${DEFAULT_CI_BASE_METADATA_VERSION}}"
CI_BASE_IMAGE_TAG="${CI_BASE_IMAGE_TAG:-rocm/vllm-dev:ci_base}"
export PYTORCH_ROCM_ARCH
export PYTORCH_ROCM_ARCH CI_BASE_DOCKERFILE

SCRIPT_TMP_DIR=$(mktemp -d -t ci-bake-rocm.XXXXXX)
CI_HCL_PATH="${SCRIPT_TMP_DIR}/ci.hcl"
Expand Down Expand Up @@ -1042,6 +1078,11 @@ print_header() {
}

validate_inputs() {
if using_custom_rocm_dockerfiles; then
validate_rocm_dockerfile "${ROCM_BASE_DOCKERFILE}" || return $?
validate_rocm_dockerfile "${CI_BASE_DOCKERFILE}" \
ci_base test export_vllm export_test_smoke csrc-build rust-build || return $?
fi
if [[ ! -f "${VLLM_BAKE_FILE}" ]]; then
echo "Error: vLLM bake file not found at ${VLLM_BAKE_FILE}"
echo "Make sure you're running from the vLLM repository root"
Expand Down Expand Up @@ -1069,6 +1110,11 @@ load_ci_hcl() {

init_bake_files() {
BAKE_FILES=(-f "${VLLM_BAKE_FILE}" -f "${CI_HCL_PATH}")
if using_custom_rocm_dockerfiles; then
# Custom stacks reuse local cache without replacing the
# standard ROCm registry caches for the same commit or branch.
BAKE_FILES+=(--set '*.cache-to=')
fi
}

compute_ci_base_hash_if_needed() {
Expand Down Expand Up @@ -1804,7 +1850,7 @@ compute_rocm_csrc_content_hash() {
local -a content_args=()

bake_dir=$(dirname "${VLLM_BAKE_FILE}")
dockerfile_rocm="${bake_dir}/Dockerfile.rocm"
dockerfile_rocm="${CI_BASE_DOCKERFILE:-${bake_dir}/Dockerfile.rocm}"
read -r -a content_paths <<< "${content_files}"
mapfile -t content_args < <(
get_content_arg_names "${dockerfile_rocm}" "${stages}" "${ROCM_CSRC_CONTENT_ARGS:-}"
Expand Down Expand Up @@ -1853,7 +1899,7 @@ compute_rocm_rust_content_hash() {
local -a content_args=()

bake_dir=$(dirname "${VLLM_BAKE_FILE}")
dockerfile_rocm="${bake_dir}/Dockerfile.rocm"
dockerfile_rocm="${CI_BASE_DOCKERFILE:-${bake_dir}/Dockerfile.rocm}"
read -r -a content_paths <<< "${content_files}"
mapfile -t content_args < <(
get_content_arg_names \
Expand Down Expand Up @@ -1943,7 +1989,7 @@ write_rocm_build_arg_override() {
local arg_value=""

bake_dir=$(dirname "${VLLM_BAKE_FILE}")
dockerfile_rocm="${bake_dir}/Dockerfile.rocm"
dockerfile_rocm="${CI_BASE_DOCKERFILE:-${bake_dir}/Dockerfile.rocm}"
mapfile -t arg_names < <(
{
get_content_arg_names \
Expand Down Expand Up @@ -2259,7 +2305,7 @@ extract_dependency_pins() {
local val=""

bake_dir=$(dirname "${VLLM_BAKE_FILE}")
dockerfile_rocm="${bake_dir}/Dockerfile.rocm"
dockerfile_rocm="${CI_BASE_DOCKERFILE:-${bake_dir}/Dockerfile.rocm}"
physical_dockerfile="${dockerfile_rocm}"
if [[ -n "${ROCM_BUILD_CONTEXT_ROOT:-}" && "${dockerfile_rocm}" != /* ]]; then
physical_dockerfile="${ROCM_BUILD_CONTEXT_ROOT}/${dockerfile_rocm}"
Expand All @@ -2275,12 +2321,12 @@ extract_dependency_pins() {
fi

val=$(
sed -n -E "s/^[[:space:]]*ARG[[:space:]]+${var}=\"?([^\"[:space:]]+)\"?.*/\\1/p" \
sed -n -E "s/^[[:space:]]*[Aa][Rr][Gg][[:space:]]+${var}=\"?([^\"[:space:]]+)\"?.*/\\1/p" \
"${physical_dockerfile}" | head -1
)
if [[ -n "${val}" ]]; then
export "${var}=${val}"
echo "Extracted ${var}=${val} from Dockerfile.rocm"
echo "Extracted ${var}=${val} from ${dockerfile_rocm}"
fi
done
}
Expand All @@ -2297,7 +2343,7 @@ compute_dependency_cache_keys() {
local deepep_material=""

bake_dir=$(dirname "${VLLM_BAKE_FILE}")
dockerfile_rocm="${bake_dir}/Dockerfile.rocm"
dockerfile_rocm="${CI_BASE_DOCKERFILE:-${bake_dir}/Dockerfile.rocm}"
nixl_branch=$(resolve_dockerfile_arg_value "${dockerfile_rocm}" "NIXL_BRANCH")
ucx_branch=$(resolve_dockerfile_arg_value "${dockerfile_rocm}" "UCX_BRANCH")
rocshmem_branch=$(resolve_dockerfile_arg_value "${dockerfile_rocm}" "ROCSHMEM_BRANCH")
Expand Down Expand Up @@ -2687,6 +2733,7 @@ main() {
init_bake_files
if is_ci_base_target; then
prepare_ci_build_context
configure_custom_rocm_stages
fi
compute_ci_base_hash_if_needed
configure_ci_base_image_refs
Expand All @@ -2697,6 +2744,7 @@ main() {
# version metadata only after that lookup sees the available tag history.
if ! is_ci_base_target; then
prepare_ci_build_context
configure_custom_rocm_stages
fi
extract_dependency_pins
write_rocm_build_arg_override
Expand Down
53 changes: 50 additions & 3 deletions .buildkite/scripts/ci-otel/ci_otel.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,39 @@ _ci_otel_python() {
fi
}

# The Docker test commands run as root, while /workdir is owned by the
# Buildkite checkout user. Run the GPU sampler as that unprivileged identity so
# any future project-code import cannot leave root-owned files in the checkout.
_ci_otel_prepare_gpu_user() {
_CI_INFRA_GPU_UID=""
_CI_INFRA_GPU_GID=""
[ "$(id -u 2>/dev/null || :)" = "0" ] || return 0
command -v setpriv >/dev/null 2>&1 || return 1

_CI_INFRA_OTEL_WORKSPACE_DIR="${CI_INFRA_OTEL_WORKSPACE_DIR:-/workdir}"
[ -d "${_CI_INFRA_OTEL_WORKSPACE_DIR}" ] || return 1
# The owner fields are numeric and whitespace-free on GNU stat.
# shellcheck disable=SC2046
set -- $(stat -c '%u %g' -- "${_CI_INFRA_OTEL_WORKSPACE_DIR}" 2>/dev/null || :)
[ "$#" -eq 2 ] || return 1
case "$1:$2" in
*[!0-9:]* | 0:* | *:0) return 1 ;;
esac

_CI_INFRA_GPU_UID="$1"
_CI_INFRA_GPU_GID="$2"
chown "${_CI_INFRA_GPU_UID}:${_CI_INFRA_GPU_GID}" \
"${CI_INFRA_OTEL_SPOOL_DIR}" || return 1
chmod 0700 "${CI_INFRA_OTEL_SPOOL_DIR}" || return 1
if [ "${_CI_INFRA_OTEL_OWNS_RUNTIME}" = "1" ]; then
# Permit traversal to the private child spool, but not directory listing.
chmod 0711 "${CI_INFRA_OTEL_RUNTIME_DIR}" || return 1
fi
setpriv --reuid="${_CI_INFRA_GPU_UID}" \
--regid="${_CI_INFRA_GPU_GID}" --clear-groups --no-new-privs \
-- test -w "${CI_INFRA_OTEL_SPOOL_DIR}"
}

ci_otel_start() {
_CI_INFRA_OTEL_COMMAND_INDEX="$1"
_CI_INFRA_OTEL_COMMAND_LABEL="${2:-command ${_CI_INFRA_OTEL_COMMAND_INDEX}}"
Expand All @@ -87,9 +120,23 @@ ci_otel_start() {
if [ "${CI_INFRA_GPU_SAMPLING:-1}" != "0" ] &&
[ -f "${CI_INFRA_OTEL_DIR}/ci_gpu.py" ] &&
command -v nvidia-smi >/dev/null 2>&1; then
PYTHONDONTWRITEBYTECODE=1 \
"${_CI_INFRA_OTEL_PYTHON}" "${CI_INFRA_OTEL_DIR}/ci_gpu.py" "$$" </dev/null &
_CI_INFRA_GPU_PID=$!
if _ci_otel_prepare_gpu_user; then
if [ -n "${_CI_INFRA_GPU_UID}" ]; then
PYTHONDONTWRITEBYTECODE=1 setpriv \
--reuid="${_CI_INFRA_GPU_UID}" --regid="${_CI_INFRA_GPU_GID}" \
--clear-groups --no-new-privs -- \
"${_CI_INFRA_OTEL_PYTHON}" "${CI_INFRA_OTEL_DIR}/ci_gpu.py" "$$" \
</dev/null &
else
PYTHONDONTWRITEBYTECODE=1 \
"${_CI_INFRA_OTEL_PYTHON}" "${CI_INFRA_OTEL_DIR}/ci_gpu.py" "$$" \
</dev/null &
fi
_CI_INFRA_GPU_PID=$!
else
echo "vLLM CI OTel: non-root GPU sampler unavailable; sampling disabled" \
>&2 || :
fi
fi
}

Expand Down
79 changes: 79 additions & 0 deletions .buildkite/scripts/ci-otel/tests/test_ci_otel.py
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,85 @@ def upload(spans, timeout_seconds):
assert [len(batch[0].events) for batch in batches] == [1, 1, 1]


def _write_executable(path: Path, body: str) -> None:
path.write_text(f"#!/bin/sh\n{body}")
path.chmod(0o755)


@pytest.mark.parametrize(
"workspace_owner,expect_sampler",
[("997 996", True), ("0 0", False)],
)
def test_root_shell_runs_gpu_sampler_as_checkout_owner(
tmp_path, workspace_owner, expect_sampler
):
bin_dir = tmp_path / "bin"
workspace = tmp_path / "workdir"
runtime = tmp_path / "runtime"
log = tmp_path / "calls.log"
bin_dir.mkdir()
workspace.mkdir()

_write_executable(
bin_dir / "id",
'[ "$1" = "-u" ] && { echo 0; exit 0; }; exec /usr/bin/id "$@"\n',
)
_write_executable(
bin_dir / "stat",
f"printf '%s\\n' '{workspace_owner}'\n",
)
for command in ("chown", "chmod"):
_write_executable(bin_dir / command, "exit 0\n")
_write_executable(
bin_dir / "setpriv",
'printf "setpriv %s\\n" "$*" >> "$CI_OTEL_TEST_LOG"\n'
'while [ "$#" -gt 0 ] && [ "$1" != "--" ]; do shift; done\n'
'[ "$#" -gt 0 ] && shift\n'
'exec "$@"\n',
)
_write_executable(
bin_dir / "python3",
'[ "$1" = "-c" ] && exit 0\n'
'[ "$2" = "new-context" ] && {\n'
' echo "01010101010101010101010101010101 0202020202020202 - 1"\n'
" exit 0\n"
"}\n"
'case "$1" in *ci_gpu.py) echo gpu >> "$CI_OTEL_TEST_LOG";; esac\n'
"exit 0\n",
)
_write_executable(bin_dir / "nvidia-smi", "exit 0\n")
shell = (
f'. "{SCRIPTS_DIR / "ci_otel.sh"}"; '
f"ci_otel_start 1 {_quoted('true')}; ci_otel_finish 0"
)

result = subprocess.run(
["/bin/sh", "-c", shell],
check=False,
capture_output=True,
text=True,
env={
**os.environ,
"PATH": f"{bin_dir}:{os.environ['PATH']}",
"CI_INFRA_OTEL_DIR": str(SCRIPTS_DIR),
"CI_INFRA_OTEL_RUNTIME_DIR": str(runtime),
"CI_INFRA_OTEL_WORKSPACE_DIR": str(workspace),
"CI_OTEL_TEST_LOG": str(log),
},
)

assert result.returncode == 0, result.stderr
calls = log.read_text() if log.exists() else ""
if expect_sampler:
expected = "--reuid=997 --regid=996 --clear-groups --no-new-privs --"
assert calls.count("setpriv") == 2
assert calls.count(expected) == 2
assert "gpu" in calls
else:
assert calls == ""
assert "non-root GPU sampler unavailable" in result.stderr


@pytest.mark.parametrize("sampling", ["1", "0"])
def test_gpu_sampler_stops_with_command_and_preserves_failure_status(
tmp_path, sampling
Expand Down
Loading