Skip to content

Commit 7a592ff

Browse files
[ci]: cache FastVideo kernel builds in Modal (#1562)
1 parent 8b23984 commit 7a592ff

11 files changed

Lines changed: 1472 additions & 56 deletions

File tree

.github/workflows/infra-build-image.yml

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,23 @@ on:
1313
required: false
1414
default: false
1515
type: boolean
16-
# Auto-rebuild the CUDA images when their Dockerfile changes on main. The CUDA
17-
# matrix is the only lane that builds from docker/Dockerfile, so a path-scoped
18-
# push trigger is a sufficient change detector on its own -- no separate
19-
# detect-changes/paths-filter job is needed now that there is a single
20-
# in-scope Dockerfile. Dreamverse (apps/dreamverse/docker/Dockerfile) and the
21-
# rocm Dockerfile stay manual-dispatch only.
16+
# Auto-rebuild the CUDA images when a repository-controlled image input
17+
# changes on main. This includes the trusted SM89 kernel artifact's source,
18+
# metadata/key helper, ABI dependency metadata, and build orchestration.
19+
# Dreamverse (apps/dreamverse/docker/Dockerfile) and the ROCm Dockerfile stay
20+
# manual-dispatch only.
2221
push:
2322
branches: [main]
2423
paths:
24+
- '.dockerignore'
25+
- '.github/workflows/_template-build-image.yml'
26+
- '.github/workflows/infra-build-image.yml'
27+
- '.gitmodules'
2528
- 'docker/Dockerfile'
29+
- 'docker/uv-excludes'
30+
- 'fastvideo-kernel/**'
31+
- 'fastvideo/tests/modal/kernel_build_cache.py'
32+
- 'pyproject.toml'
2633

2734

2835
permissions:
@@ -50,7 +57,7 @@ jobs:
5057
# 2.8.3 comes from the architecture-specific prebuilt releases.
5158
build-cuda-images:
5259
# Runs on a manual dispatch when build_cuda_matrix is set, or automatically
53-
# on a push that changed docker/Dockerfile (inputs are null on push). The
60+
# on an in-scope main push (inputs are null on push). The
5461
# repository guard keeps fork syncs from auto-building; manual dispatch
5562
# still works in forks.
5663
if: ${{ (github.event_name == 'push' && github.repository == 'hao-ai-lab/FastVideo') || github.event.inputs.build_cuda_matrix == 'true' }}

docker/Dockerfile

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,15 +186,40 @@ RUN --mount=type=cache,target=/opt/uv/cache \
186186

187187
COPY . .
188188

189-
# Install FastVideo Unified Kernel exactly once. build.sh initializes only its
190-
# CUTLASS/ThunderKittens submodules, then compiles for TORCH_CUDA_ARCH_LIST
191-
# (default Hopper sm_90a) without requiring a live GPU.
189+
# Build immutable FastVideo kernel wheels for the published image. The requested
190+
# architecture remains installed for normal image users; amd64 images also carry
191+
# an SM89 artifact so the predominant L40S Modal lanes can reuse it exactly.
192+
ARG FASTVIDEO_KERNEL_PREBUILT_DIR=/opt/fastvideo-kernel-prebuilt
192193
RUN --mount=type=cache,target=/opt/uv/cache \
193194
source $HOME/.local/bin/env && \
194195
source /opt/venv/bin/activate && \
196+
default_arch="${TORCH_CUDA_ARCH_LIST}" && \
197+
default_wheel_dir="${FASTVIDEO_KERNEL_PREBUILT_DIR}/${default_arch}" && \
198+
export TORCH_CUDA_ARCH_LIST="${default_arch}" && \
195199
cd fastvideo-kernel && \
196-
CMAKE_BUILD_PARALLEL_LEVEL=${CMAKE_BUILD_PARALLEL_LEVEL} \
197-
TORCH_CUDA_ARCH_LIST=${TORCH_CUDA_ARCH_LIST} ./build.sh
200+
CMAKE_ARGS= CMAKE_BUILD_PARALLEL_LEVEL=${CMAKE_BUILD_PARALLEL_LEVEL} \
201+
./build.sh --wheel-dir "${default_wheel_dir}" && \
202+
cd /FastVideo && \
203+
CMAKE_ARGS= python fastvideo/tests/modal/kernel_build_cache.py write-build-info \
204+
--wheel-dir "${default_wheel_dir}" \
205+
--output "${default_wheel_dir}/metadata.json" && \
206+
if [[ "${TARGETARCH:-amd64}" == "amd64" && "${default_arch}" != "8.9" ]]; then \
207+
export TORCH_CUDA_ARCH_LIST=8.9 && \
208+
l40s_wheel_dir="${FASTVIDEO_KERNEL_PREBUILT_DIR}/8.9" && \
209+
cd /FastVideo/fastvideo-kernel && \
210+
CMAKE_ARGS= CMAKE_BUILD_PARALLEL_LEVEL=${CMAKE_BUILD_PARALLEL_LEVEL} \
211+
./build.sh --wheel-dir "${l40s_wheel_dir}" && \
212+
cd /FastVideo && \
213+
CMAKE_ARGS= python fastvideo/tests/modal/kernel_build_cache.py write-build-info \
214+
--wheel-dir "${l40s_wheel_dir}" \
215+
--output "${l40s_wheel_dir}/metadata.json"; \
216+
fi && \
217+
export TORCH_CUDA_ARCH_LIST="${default_arch}" && \
218+
default_wheel="$(find "${default_wheel_dir}" -maxdepth 1 -type f \
219+
\( -name 'fastvideo_kernel-*.whl' -o -name 'fastvideo-kernel-*.whl' \) \
220+
| sort | tail -n 1)" && \
221+
uv pip install "${default_wheel}" \
222+
--reinstall-package fastvideo-kernel --no-deps
198223

199224
# Install FastVideo itself (editable) now that the source is present, and set up
200225
# shell configuration. Dependencies and the local kernel are already installed,

docs/contributing/ci_architecture.md

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -269,16 +269,26 @@ The docs job:
269269
### Docker Images
270270

271271
`.github/workflows/infra-build-image.yml` supports manual `workflow_dispatch`
272-
runs and automatically rebuilds the CUDA matrix when `docker/Dockerfile`
273-
changes on `main` in the canonical repository. Manual runs let maintainers
274-
choose which image families to build. The `fastvideo-dev` matrix builds Python
275-
3.12 images for CUDA 12.6 and CUDA 13 on native `amd64` and `arm64` runners,
276-
then publishes one multi-platform manifest per CUDA version. CUDA 12.6 owns the
277-
`py3.12-latest` and global `latest` tags, as well as the explicit
278-
`py3.12-cuda12.6.3-latest` alias. CUDA 13 is published under the explicit
279-
`py3.12-cuda13.0.0-latest` tag. This publication policy does not change the
280-
unparameterized `docker/Dockerfile` build defaults, which remain CUDA 13 and
281-
`cu130`.
272+
runs and automatically rebuilds the CUDA matrix when a repository-controlled
273+
image input changes on `main` in the canonical repository. Those inputs include
274+
the CUDA Dockerfile and reusable workflow, dependency metadata, Docker context
275+
policy, `fastvideo-kernel/**`, and the kernel artifact metadata/key helper.
276+
Manual runs let maintainers choose which image families to build. The
277+
`fastvideo-dev` matrix builds Python 3.12 images for CUDA 12.6 and CUDA 13 on
278+
native `amd64` and `arm64` runners, then publishes one multi-platform manifest
279+
per CUDA version. CUDA 12.6 owns the `py3.12-latest` and global `latest` tags, as
280+
well as the explicit `py3.12-cuda12.6.3-latest` alias. CUDA 13 is published under
281+
the explicit `py3.12-cuda13.0.0-latest` tag. This publication policy does not
282+
change the unparameterized `docker/Dockerfile` build defaults, which remain CUDA
283+
13 and `cu130`.
284+
285+
Published amd64 development images keep their configured Hopper kernel wheel
286+
installed and also carry an immutable SM89 wheel under
287+
`/opt/fastvideo-kernel-prebuilt`. Modal PR and SSIM jobs select the exact
288+
source, ABI, and GPU-architecture match from that directory, so L40S jobs reuse
289+
the trusted image artifact while kernel-changing PRs still build locally. Once
290+
a kernel or artifact-key change reaches `main`, the image workflow republishes
291+
the matching trusted artifact before later jobs consume the updated image tag.
282292

283293
The optional Dreamverse matrix builds backend and UI images for CUDA 12.6 and
284294
CUDA 13 on `amd64`. Dreamverse remains `amd64`-only because its FA4 dependency

fastvideo-kernel/build.sh

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ set -ex
44
# Simple build script wrapping uv/pip
55
# Usage:
66
# ./build.sh # local build (torch-based arch detection, TK only on SM90)
7+
# ./build.sh --wheel-dir /tmp/wheels # build + install a reusable wheel
78
# Environment overrides (if set, they win over auto-detection):
89
# TORCH_CUDA_ARCH_LIST
910
# CMAKE_ARGS (for FASTVIDEO_KERNEL_BUILD_TK / CMAKE_CUDA_ARCHITECTURES / GPU_BACKEND)
@@ -67,12 +68,25 @@ fi
6768
# Install build dependencies
6869
uv pip install scikit-build-core cmake ninja
6970

70-
RELEASE=0
7171
GPU_BACKEND=CUDA
72-
for arg in "$@"; do
73-
case "$arg" in
72+
WHEEL_DIR=""
73+
while [[ $# -gt 0 ]]; do
74+
case "$1" in
7475
--rocm)
7576
GPU_BACKEND=ROCM
77+
shift
78+
;;
79+
--wheel-dir)
80+
if [[ $# -lt 2 ]]; then
81+
echo "ERROR: --wheel-dir requires a directory path" >&2
82+
exit 2
83+
fi
84+
WHEEL_DIR="$2"
85+
shift 2
86+
;;
87+
*)
88+
echo "ERROR: unknown argument: $1" >&2
89+
exit 2
7690
;;
7791
esac
7892
done
@@ -165,4 +179,15 @@ echo "CMAKE_ARGS: ${CMAKE_ARGS:-<unset>}"
165179
echo "GPU_BACKEND: ${GPU_BACKEND:-<unset>}"
166180
# Build and install
167181
# Use -v for verbose output
168-
uv pip install . -v --no-build-isolation
182+
if [ -n "${WHEEL_DIR}" ]; then
183+
mkdir -p "${WHEEL_DIR}"
184+
uv build --wheel -v --no-build-isolation --out-dir "${WHEEL_DIR}" .
185+
wheel_path="$(find "${WHEEL_DIR}" -maxdepth 1 -type f \( -name 'fastvideo_kernel-*.whl' -o -name 'fastvideo-kernel-*.whl' \) | sort | tail -n 1)"
186+
if [ -z "${wheel_path}" ]; then
187+
echo "ERROR: no fastvideo-kernel wheel was built in ${WHEEL_DIR}" >&2
188+
exit 1
189+
fi
190+
uv pip install "${wheel_path}" --reinstall-package fastvideo-kernel --no-deps
191+
else
192+
uv pip install . -v --no-build-isolation
193+
fi

0 commit comments

Comments
 (0)