[CI] Speed up dependency install: dual-ABI Rust ext cache and prevalidation pruning (#33619)
This commit is contained in:
@@ -12,7 +12,7 @@ inputs:
|
||||
cache_key_prefix:
|
||||
description: 'Must match what _pr-test-rust-ext-build.yml saves under.'
|
||||
required: false
|
||||
default: rust-ext-x86_64
|
||||
default: rust-ext-x86_64-cp310-cp312
|
||||
|
||||
outputs:
|
||||
hit:
|
||||
|
||||
@@ -36,9 +36,9 @@ on:
|
||||
type: string
|
||||
default: rust-ext-x86_64
|
||||
cache_key_prefix:
|
||||
description: 'Cache key prefix. Callers share it on purpose to reuse each other''s build; it encodes the arch, since the modules are not portable across architectures.'
|
||||
description: 'Cache key prefix. Callers share it on purpose to reuse each other''s build; it encodes the arch and the interpreter ABI set, since the modules are portable across neither.'
|
||||
type: string
|
||||
default: rust-ext-x86_64
|
||||
default: rust-ext-x86_64-cp310-cp312
|
||||
max_glibc:
|
||||
description: 'Highest GLIBC symbol version the built .so files may require. Set by the oldest test runner image, jammy at glibc 2.35 - the pools are not all on one image.'
|
||||
type: string
|
||||
@@ -102,6 +102,26 @@ jobs:
|
||||
path: python/sglang/srt/*/_core*.so
|
||||
key: ${{ inputs.cache_key_prefix }}-${{ hashFiles('rust/**', 'python/setup.py') }}
|
||||
|
||||
# On a miss: different hash = rust/setup.py moved; no entries = evicted.
|
||||
- name: Report cache lookup
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
PRIMARY_KEY: ${{ steps.cache.outputs.cache-primary-key }}
|
||||
MATCHED_KEY: ${{ steps.cache.outputs.cache-matched-key }}
|
||||
KEY_PREFIX: ${{ inputs.cache_key_prefix }}
|
||||
run: |
|
||||
if [ -n "${MATCHED_KEY}" ]; then
|
||||
echo "hit: ${MATCHED_KEY}"
|
||||
ls -l python/sglang/srt/*/_core*.so
|
||||
else
|
||||
echo "miss: ${PRIMARY_KEY}"
|
||||
echo "entries under ${KEY_PREFIX}- (created / ref / size / key):"
|
||||
gh cache list --repo "${GITHUB_REPOSITORY}" --key "${KEY_PREFIX}-" \
|
||||
--limit 15 --json createdAt,ref,sizeInBytes,key \
|
||||
--jq '.[] | [.createdAt, .ref, ((.sizeInBytes / 1048576 | floor | tostring) + " MiB"), .key] | @tsv' \
|
||||
|| echo "(gh cache list unavailable: token lacks actions:read)"
|
||||
fi
|
||||
|
||||
# No MAX_GLIBC: these are the bytes the compile job already checked before
|
||||
# saving them under this key. The module count is still worth re-checking,
|
||||
# so a truncated entry fails here rather than as a test import error.
|
||||
@@ -139,15 +159,20 @@ jobs:
|
||||
|
||||
- uses: ./.github/actions/check-maintenance
|
||||
|
||||
# No crate sets abi3, so the ABI tag is minor-version specific and only the
|
||||
# pools on this version can use the result - h20 ships 3.12 and falls back to
|
||||
# compiling during install. Pinned rather than left to the image so the tag is
|
||||
# at least predictable.
|
||||
# No crate sets abi3, so build one module set per interpreter the pools
|
||||
# run (h100 ships 3.10, h20 ships 3.12); EXT_SUFFIX keeps them apart.
|
||||
- name: Set up Python 3.10
|
||||
id: py310
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Set up Python 3.12
|
||||
id: py312
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Install protoc and Rust toolchain
|
||||
run: bash scripts/ci/utils/install_rust_protoc.sh
|
||||
|
||||
@@ -155,32 +180,36 @@ jobs:
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
export PATH="${CARGO_HOME:-$HOME/.cargo}/bin:${PATH}"
|
||||
# Same path ci_install_dependency.sh uses, so a runner that also runs test
|
||||
# stages keeps one warm cache. Its guard is repeated here because nothing
|
||||
# prunes the tree on a runner that only ever builds.
|
||||
export CARGO_TARGET_DIR="${HOME}/.cache/sglang-cargo-target"
|
||||
mkdir -p "${CARGO_TARGET_DIR}"
|
||||
used="$(df --output=pcent "${CARGO_TARGET_DIR}" 2>/dev/null | tr -dc '0-9')"
|
||||
# Per-interpreter subdirs (set in the loop): PyO3's fingerprint tracks
|
||||
# the interpreter, so a shared dir rebuilds on every ABI switch.
|
||||
cargo_target_root="${HOME}/.cache/sglang-cargo-target"
|
||||
mkdir -p "${cargo_target_root}"
|
||||
used="$(df --output=pcent "${cargo_target_root}" 2>/dev/null | tr -dc '0-9')"
|
||||
if [ "${used:-0}" -ge 85 ]; then
|
||||
echo "cargo target dir filesystem at ${used}%; dropping ${CARGO_TARGET_DIR}"
|
||||
rm -rf "${CARGO_TARGET_DIR}"
|
||||
mkdir -p "${CARGO_TARGET_DIR}"
|
||||
echo "cargo target dir filesystem at ${used}%; dropping ${cargo_target_root}"
|
||||
rm -rf "${cargo_target_root}"
|
||||
mkdir -p "${cargo_target_root}"
|
||||
fi
|
||||
python3 -m pip install --upgrade pip
|
||||
command -v uv >/dev/null 2>&1 || pip install uv
|
||||
# build_rust needs only the build backend, not sglang's ~294 runtime deps.
|
||||
# Per-job path: these runners are persistent and shared, so a fixed one
|
||||
# both inherits the previous job's venv and races a concurrent build.
|
||||
venv="${RUNNER_TEMP:-/tmp}/sglang-ci-rust-ext-${GITHUB_RUN_ID:-norun}-$$"
|
||||
venv_root="${RUNNER_TEMP:-/tmp}/sglang-ci-rust-ext-${GITHUB_RUN_ID:-norun}-$$"
|
||||
# Best-effort, like ci_cleanup_venv.sh: under set -e a failing EXIT trap
|
||||
# would fail the step, and nothing here is worth keeping for a postmortem.
|
||||
trap 'rm -rf "${venv}" || true' EXIT
|
||||
uv venv "${venv}" --python python3.10 --seed
|
||||
# shellcheck disable=SC1091
|
||||
source "${venv}/bin/activate"
|
||||
uv pip install "setuptools>=61.0" "setuptools-rust>=1.10" "setuptools-scm>=8.0" wheel
|
||||
cd python
|
||||
SGLANG_BUILD_RUST_EXTS=all python setup.py build_rust --inplace
|
||||
trap 'rm -rf "${venv_root}" || true' EXIT
|
||||
for python_bin in "${{ steps.py310.outputs.python-path }}" "${{ steps.py312.outputs.python-path }}"; do
|
||||
minor="$("${python_bin}" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')"
|
||||
export CARGO_TARGET_DIR="${cargo_target_root}/py${minor}"
|
||||
venv="${venv_root}/py${minor}"
|
||||
uv venv "${venv}" --python "${python_bin}" --seed
|
||||
# shellcheck disable=SC1091
|
||||
source "${venv}/bin/activate"
|
||||
uv pip install "setuptools>=61.0" "setuptools-rust>=1.10" "setuptools-scm>=8.0" wheel
|
||||
(cd python && SGLANG_BUILD_RUST_EXTS=all python setup.py build_rust --inplace)
|
||||
deactivate
|
||||
done
|
||||
|
||||
- name: Verify modules and stage for upload
|
||||
env:
|
||||
|
||||
@@ -10,6 +10,8 @@ on:
|
||||
paths:
|
||||
- 'rust/**'
|
||||
- 'python/setup.py'
|
||||
# The key's prefix lives in this file, so a bump there also moves the key.
|
||||
- '.github/workflows/_pr-test-rust-ext-build.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
# Only the newest merge needs to seed; earlier ones are already stale.
|
||||
@@ -17,9 +19,10 @@ concurrency:
|
||||
group: seed-rust-ext-cache
|
||||
cancel-in-progress: true
|
||||
|
||||
# Declaring permissions at all drops everything not listed, and check-maintenance
|
||||
# needs issues: read to reach the maintenance issue.
|
||||
# Declaring permissions at all drops everything not listed. issues: read for
|
||||
# check-maintenance; actions: read for the restore job's gh cache list.
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
issues: read
|
||||
|
||||
|
||||
Reference in New Issue
Block a user