Skip to content

Commit 1d99d4c

Browse files
lcy-sesoIbuki-wind
andauthored
[CI] retire run-local venv across CI; install via image-baked stack (tile-ai#1606)
## What Full RFC §4 cleanup on top of the ephemeral containerized-runner migration. The runner image bakes tilelang + the runtime/dev stack, so CI stops building/copying per-run venvs and installs only tileops (`--no-deps`) via `scripts/ci/install_tileops.sh`. - **gpu-smoke**: drop `Set up Python`, `Resolve runtime state` (venv hash/copy/mtime-sync/divergence guard), `Cleanup isolated fork state`; install via `install_tileops.sh`; run with the image's `python3`; trust-route PRs by collaborator permission (write/maintain/admin → resident `nightly` pool; everyone else + lookup failure → `fork` pool, fail-closed); reclaim the `/ci-cache` layout (no wheels, no tool-cache prune); per-test `--timeout` + a `timeout-minutes` backstop so a wedged kernel cannot hold the single runner. - **nightly**: `setup_nightly_venv.sh` → `install_tileops.sh`; system `python3`; cache env `/data7` → `/ci-cache`; per-test timeout on the pytest runs. - **runner-maintenance**: drop the retired `venv` runs-on label (→ `nightly`). - **preflight**: pin CPU installs with `constraints.txt`. - **pyproject / constraints**: tilelang as a compatibility range (constraints pins its deps, not tilelang itself); pin `pytest-timeout`. - **reclaim action + verify script**: `/ci-cache` layout, drop `WHEEL_DIR`; trim stamp on the persistent cache. - **delete**: `setup_nightly_venv.sh`, `ci_venv_hash.py` and their obsolete tests. ## In scope vs follow-up To keep CI dispatching, installing and importing cleanly on the new stack, this PR DOES adapt the import surface: `gqa_fwd_fp8` guards its `from tvm import tir` with a sentinel that raises a targeted error only when the kernel is built, and the fp8-GQA / topk-selector kernel-building smoke cases are skipped via a `tvm.tir` availability gate (with a focused test for the gate). So **CI is green at import**, not red. **Out of scope (follow-up):** the actual kernel migration off `tvm.tir` (`tir.call_extern` → `tilelang.language` `T.*`) and any other new-stack kernel regressions surfaced by gpu-smoke (e.g. a build hang in `FP8LightingIndexerKernel`). Those are tracked separately; until they land, the corresponding smoke cases are skipped or fail on the per-test timeout rather than wedging the runner. --------- Co-authored-by: Ibuki 🍃 — a wind born from GPTs <Ibuki-wind@users.noreply.github.com>
1 parent fefcb10 commit 1d99d4c

18 files changed

Lines changed: 223 additions & 795 deletions

.github/actions/reclaim-runner-disk/action.yml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,15 @@ inputs:
4949
description: >
5050
Newline-separated list of cache directory roots whose files older than
5151
cache-age-days should be trimmed at file granularity. Defaults target
52-
the shared /data7-backed runner cache layout.
52+
the bind-mounted /ci-cache runner cache layout.
5353
Do NOT include atomic cache roots here (see atomic-cache-dirs); file-
5454
level trim on an atomic root can produce a half-dead "directory exists
5555
but sentinel missing" state that crashes downstream consumers.
5656
required: false
5757
default: |
58-
/data7/shared/ci-cache/triton
59-
/data7/shared/ci-cache/pip
60-
/data7/shared/ci-cache/wheels
61-
/data7/shared/ci-cache/tilelang/tmp
58+
/ci-cache/triton
59+
/ci-cache/pip
60+
/ci-cache/tilelang/tmp
6261
atomic-cache-dirs:
6362
description: >
6463
Newline-separated list of cache directory roots whose first-level
@@ -75,7 +74,7 @@ inputs:
7574
tuning artefacts alongside a best_config.json sentinel.
7675
required: false
7776
default: |
78-
/data7/shared/ci-cache/tilelang/autotuner
77+
/ci-cache/tilelang/autotuner
7978
prune-tool-cache:
8079
description: >
8180
Whether to prune old tileops_ci_venv_* directories under runner.tool_cache.
@@ -195,7 +194,9 @@ runs:
195194
AVAIL_KB=$(df -Pk "${RUNNER_TEMP}" | awk 'NR==2 {print $4}')
196195
MIN_KB=$(( MIN_AVAIL_GIB * 1024 * 1024 ))
197196
RECLAIM_BELOW_KB=$(( RECLAIM_BELOW_GIB * 1024 * 1024 ))
198-
CACHE_TRIM_STAMP="/home/ci-runner/.ci-maintenance/reclaim-runner-disk-cache-trim.stamp"
197+
# Stamp lives on the persistent bind-mounted cache (not the ephemeral container fs under
198+
# /home/ci-runner), so the cache-trim cooldown survives across ephemeral runner jobs.
199+
CACHE_TRIM_STAMP="/ci-cache/.ci-maintenance/reclaim-runner-disk-cache-trim.stamp"
199200
DID_RECLAIM="false"
200201
SHOULD_RECLAIM="false"
201202

.github/actions/reclaim-runner-disk/reclaim_cache.sh

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
# validate behaviour against a tmp_path fixture.
1212
#
1313
# The core safety invariant this script enforces is that some cache
14-
# roots (notably /data7/shared/ci-cache/tilelang/autotuner) store
14+
# roots (notably /ci-cache/tilelang/autotuner) store
1515
# *atomic* first-level subdirectories: consumers assume "directory
1616
# exists => contents complete" and the directory is only valid if the
1717
# sentinel file (best_config.json) is present. File-level `-mtime`
@@ -37,8 +37,7 @@
3737
# trim-files <age-days> <root> [<root>...]
3838
# File-level `-mtime +N -delete` trim for non-atomic cache
3939
# roots, followed by empty-directory cleanup. This is the legacy
40-
# behaviour used for /data7/shared/ci-cache/triton,
41-
# /data7/shared/ci-cache/pip, /data7/shared/ci-cache/wheels, etc.
40+
# behaviour used for /ci-cache/triton, /ci-cache/pip, etc.
4241
#
4342
# All subcommands are idempotent, tolerate missing roots (skipped
4443
# silently), and never exit non-zero for per-directory errors so a

.github/workflows/gpu-smoke.yml

Lines changed: 57 additions & 268 deletions
Large diffs are not rendered by default.

.github/workflows/nightly.yml

Lines changed: 24 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,10 @@ concurrency:
1818
# ---------------------------------------------------------------------------
1919

2020
env:
21-
TILELANG_CACHE_DIR: /data7/shared/ci-cache/tilelang
22-
TILELANG_TMP_DIR: /data7/shared/ci-cache/tilelang/tmp
23-
TRITON_CACHE_DIR: /data7/shared/ci-cache/triton
24-
PIP_CACHE_DIR: /data7/shared/ci-cache/pip
25-
WHEEL_DIR: /data7/shared/ci-cache/wheels
21+
TILELANG_CACHE_DIR: /ci-cache/tilelang
22+
TILELANG_TMP_DIR: /ci-cache/tilelang/tmp
23+
TRITON_CACHE_DIR: /ci-cache/triton
24+
PIP_CACHE_DIR: /ci-cache/pip
2625
MAX_JOBS: "64"
2726

2827
jobs:
@@ -43,31 +42,17 @@ jobs:
4342
run: scripts/ci/verify_nightly_runner.sh
4443
shell: bash
4544

46-
- name: Set up run-local venv
47-
run: scripts/ci/setup_nightly_venv.sh
45+
- name: Install TileOPs (image-baked stack, --no-deps)
46+
run: bash scripts/ci/install_tileops.sh
4847
shell: bash
4948

5049
- name: Warm kernel compilation cache
5150
continue-on-error: true
5251
run: |
5352
set -euo pipefail
54-
# shellcheck source=/dev/null
55-
source "${VENV_PATH}/bin/activate"
56-
57-
PIP_NO_BUILD_ISOLATION=1 pip install -e ".[dev]"
58-
5953
export PYTHONPATH="${GITHUB_WORKSPACE}${PYTHONPATH:+:$PYTHONPATH}"
6054
echo "Starting kernel cache warmup..."
61-
python scripts/warmup_kernel_cache.py --max-workers 64 -n 16
62-
shell: bash
63-
64-
- name: Cleanup run-local venv
65-
if: ${{ always() }}
66-
run: |
67-
set -euo pipefail
68-
if [[ -n "${RUNTIME_ROOT:-}" && "${RUNTIME_ROOT}" == "${RUNNER_TEMP}/nightly-"* ]]; then
69-
rm -rf "${RUNTIME_ROOT}"
70-
fi
55+
python3 scripts/warmup_kernel_cache.py --max-workers 64 -n 16
7156
shell: bash
7257

7358
# =========================================================================
@@ -92,17 +77,15 @@ jobs:
9277
run: scripts/ci/verify_nightly_runner.sh
9378
shell: bash
9479

95-
- name: Set up run-local venv
96-
run: scripts/ci/setup_nightly_venv.sh
80+
- name: Install TileOPs (image-baked stack, --no-deps)
81+
run: bash scripts/ci/install_tileops.sh
9782
shell: bash
9883

9984
- name: Run benchmark ops
10085
id: benchmark_tests
10186
continue-on-error: true
10287
run: |
10388
set -euo pipefail
104-
# shellcheck source=/dev/null
105-
source "${VENV_PATH}/bin/activate"
10689
10790
# Validate GPU frequency
10891
TARGET_CLOCK_MHZ=1500
@@ -118,16 +101,15 @@ jobs:
118101
sleep 2
119102
done
120103
121-
PIP_NO_BUILD_ISOLATION=1 pip install -e ".[dev]"
122-
123104
export PYTHONPATH="${GITHUB_WORKSPACE}${PYTHONPATH:+:$PYTHONPATH}"
124105
echo "Runtime cache env:"
125106
echo "TILELANG_CACHE_DIR=${TILELANG_CACHE_DIR:-}"
126107
echo "TILELANG_TMP_DIR=${TILELANG_TMP_DIR:-}"
127108
echo "TRITON_CACHE_DIR=${TRITON_CACHE_DIR:-}"
128109
129110
set -o pipefail
130-
python -m pytest -q benchmarks/ops --junit-xml=bench_results.xml | tee tileops_benchmarks.log
111+
python3 -m pip install -q -c constraints.txt pytest-timeout
112+
python3 -m pytest -q benchmarks/ops --timeout=900 --timeout-method=thread --junit-xml=bench_results.xml | tee tileops_benchmarks.log
131113
132114
if [ -f profile_run.log ]; then
133115
{ echo; echo "===== profile_run.log summary ====="; cat profile_run.log; } >> tileops_benchmarks.log
@@ -152,15 +134,6 @@ jobs:
152134
run: exit 1
153135
shell: bash
154136

155-
- name: Cleanup run-local venv
156-
if: ${{ always() }}
157-
run: |
158-
set -euo pipefail
159-
if [[ -n "${RUNTIME_ROOT:-}" && "${RUNTIME_ROOT}" == "${RUNNER_TEMP}/nightly-"* ]]; then
160-
rm -rf "${RUNTIME_ROOT}"
161-
fi
162-
shell: bash
163-
164137
# =========================================================================
165138
# Phase 3 — Op correctness tests (serial after benchmark for GPU exclusivity)
166139
# =========================================================================
@@ -179,19 +152,15 @@ jobs:
179152
run: scripts/ci/verify_nightly_runner.sh
180153
shell: bash
181154

182-
- name: Set up run-local venv
183-
run: scripts/ci/setup_nightly_venv.sh
155+
- name: Install TileOPs (image-baked stack, --no-deps)
156+
run: bash scripts/ci/install_tileops.sh
184157
shell: bash
185158

186159
- name: Run full op tests
187160
id: op_tests
188161
continue-on-error: true
189162
run: |
190163
set -euo pipefail
191-
# shellcheck source=/dev/null
192-
source "${VENV_PATH}/bin/activate"
193-
194-
PIP_NO_BUILD_ISOLATION=1 pip install -e ".[dev]"
195164
196165
export PYTHONPATH="${GITHUB_WORKSPACE}${PYTHONPATH:+:$PYTHONPATH}"
197166
echo "Runtime cache env:"
@@ -200,7 +169,8 @@ jobs:
200169
echo "TRITON_CACHE_DIR=${TRITON_CACHE_DIR:-}"
201170
202171
set -o pipefail
203-
python -m pytest tests/ -v --tb=short --junit-xml=test_results.xml | tee tileops_op_test.log
172+
python3 -m pip install -q -c constraints.txt pytest-timeout
173+
python3 -m pytest tests/ -v --tb=short --timeout=900 --timeout-method=thread --junit-xml=test_results.xml | tee tileops_op_test.log
204174
shell: bash
205175

206176
- name: Download benchmark artifacts
@@ -277,18 +247,15 @@ jobs:
277247
if: ${{ always() }}
278248
run: |
279249
set -euo pipefail
280-
# shellcheck source=/dev/null
281-
source "${VENV_PATH}/bin/activate"
282250
283-
pip install --no-deps -e . 2>/dev/null
284251
export PYTHONPATH="${GITHUB_WORKSPACE}${PYTHONPATH:+:$PYTHONPATH}"
285252
286253
HISTORY_ARGS=()
287254
if [ -f .perf_history/perf_history.json ]; then
288255
HISTORY_ARGS=(--history .perf_history/perf_history.json)
289256
fi
290257
291-
python scripts/nightly_report.py \
258+
python3 scripts/nightly_report.py \
292259
--test-xml test_results.xml \
293260
--bench-xml bench_results.xml \
294261
"${HISTORY_ARGS[@]}" \
@@ -328,15 +295,6 @@ jobs:
328295
run: exit 1
329296
shell: bash
330297

331-
- name: Cleanup run-local venv
332-
if: ${{ always() }}
333-
run: |
334-
set -euo pipefail
335-
if [[ -n "${RUNTIME_ROOT:-}" && "${RUNTIME_ROOT}" == "${RUNNER_TEMP}/nightly-"* ]]; then
336-
rm -rf "${RUNTIME_ROOT}"
337-
fi
338-
shell: bash
339-
340298
# =========================================================================
341299
# Phase 3b — Publish benchmark data to the nightly-bench orphan branch
342300
# Consumed by tile-ai/TileOPs.github.io to render the docs Benchmarks page.
@@ -423,16 +381,14 @@ jobs:
423381
run: scripts/ci/verify_nightly_runner.sh
424382
shell: bash
425383

426-
- name: Set up run-local venv
427-
run: scripts/ci/setup_nightly_venv.sh
384+
- name: Install TileOPs (image-baked stack, --no-deps)
385+
run: bash scripts/ci/install_tileops.sh
428386
shell: bash
429387

430388
- name: Build and test wheel package
431389
run: |
432390
set -euo pipefail
433391
exec > >(tee packaging.log) 2>&1
434-
# shellcheck source=/dev/null
435-
source "${VENV_PATH}/bin/activate"
436392
437393
# Validate GPU frequency
438394
TARGET_CLOCK_MHZ=1500
@@ -448,17 +404,17 @@ jobs:
448404
sleep 2
449405
done
450406
451-
pip install build pytest
407+
python3 -m pip install -c constraints.txt build pytest pytest-timeout
452408
453409
echo "=== Build wheel package ==="
454-
python -m build --wheel
410+
python3 -m build --wheel
455411
echo "=== Build artifacts ==="
456412
ls -lh dist/*.whl
457413
458414
echo "=== Install built wheel ==="
459-
pip install dist/*.whl
415+
python3 -m pip install dist/*.whl
460416
461-
TMP_TEST_DIR="$(mktemp -d "${RUNTIME_ROOT}/packaging-test.XXXXXX")"
417+
TMP_TEST_DIR="$(mktemp -d "${RUNNER_TEMP}/packaging-test.XXXXXX")"
462418
cp -r tests "${TMP_TEST_DIR}/tests"
463419
cp pyproject.toml "${TMP_TEST_DIR}/"
464420
cd "${TMP_TEST_DIR}"
@@ -469,7 +425,8 @@ jobs:
469425
echo "TRITON_CACHE_DIR=${TRITON_CACHE_DIR:-}"
470426
471427
echo "=== Run pytest packaging ==="
472-
python -m pytest -q tests/ops -m "packaging" \
428+
python3 -m pytest -q tests/ops -m "packaging" \
429+
--timeout=900 --timeout-method=thread \
473430
--junit-xml="${GITHUB_WORKSPACE}/packaging_smoke.xml"
474431
shell: bash
475432

@@ -499,12 +456,3 @@ jobs:
499456
with:
500457
files: dist/*.whl
501458
fail_on_unmatched_files: true
502-
503-
- name: Cleanup run-local venv
504-
if: ${{ always() }}
505-
run: |
506-
set -euo pipefail
507-
if [[ -n "${RUNTIME_ROOT:-}" && "${RUNTIME_ROOT}" == "${RUNNER_TEMP}/nightly-"* ]]; then
508-
rm -rf "${RUNTIME_ROOT}"
509-
fi
510-
shell: bash

.github/workflows/preflight.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ jobs:
247247
python-version: "3.10"
248248

249249
- name: Install TileOPs and validator dependencies
250-
run: pip install -e .
250+
run: pip install -e . -c constraints.txt
251251

252252
- name: Validate ops manifest
253253
run: python scripts/validate_manifest.py --levels schema,signature,shape,dtype,bench --strict
@@ -299,7 +299,7 @@ jobs:
299299
python-version: "3.10"
300300

301301
- name: Install TileOPs (with dev extras)
302-
run: pip install -e ".[dev]"
302+
run: pip install -e ".[dev]" -c constraints.txt
303303

304304
- name: Run benchmark contract tests
305305
run: python -m pytest -q benchmarks/tests

.github/workflows/runner-maintenance.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ name: Runner Maintenance
77
# cooldown; this scheduled job forces the full cleanup pass on days with
88
# little PR traffic.
99
#
10-
# GPU smoke and nightly share the persistent cache tree under
11-
# `/data7/shared/ci-cache/*`.
10+
# GPU smoke and nightly share the persistent cache tree bind-mounted at
11+
# `/ci-cache/*` inside the runner container.
1212

1313
on:
1414
schedule:
@@ -25,7 +25,9 @@ concurrency:
2525
jobs:
2626
reclaim-disk:
2727
if: ${{ github.repository == 'tile-ai/TileOPs' }}
28-
runs-on: [self-hosted, tile-ops, venv]
28+
# `nightly` (not `fork`) keeps maintenance on the resident shared-cache runners; the
29+
# destructive autotuner age-trim must never run against a fork pool's overlay cache.
30+
runs-on: [self-hosted, tile-ops, nightly]
2931
timeout-minutes: 60
3032
steps:
3133
# Invoke the action directly via owner/repo/path@ref so this workflow

constraints.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,6 @@ typing_extensions==4.15.0
2121
Cython==3.2.4
2222
z3-solver==4.15.4.0
2323
torch_c_dlpack_ext==0.1.5
24+
# CI test plugin: per-test hang guard for the GPU jobs. Pinned here so the runtime install is
25+
# deterministic; the runner image should bake it (follow-up) and drop the per-job install.
26+
pytest-timeout==2.3.1

pyproject.toml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ readme = "README.md"
66
authors = [{ name="Tile-AI"}]
77
dependencies = [
88
"torch>=2.1.0,<2.11.0",
9-
"tilelang==0.1.9",
10-
# FIXME(apache-tvm-ffi-pin): Remove once tilelang carries its own
11-
# apache-tvm-ffi<0.1.10 pin (already on tilelang main, not yet released).
12-
# Tracking: https://github.com/tile-ai/TileOPs/issues/969
13-
"apache-tvm-ffi>=0.1.2,<0.1.10",
9+
# tilelang as a compatibility range, not a source or exact pin. CI does not resolve tilelang
10+
# from this range: the runner image bakes a specific tilelang build and CI installs tileops
11+
# with --no-deps against it. constraints.txt pins tilelang's runtime deps (torch, triton,
12+
# apache-tvm-ffi, ...) for reproducibility but intentionally does NOT pin tilelang itself.
13+
# Downstream `pip install tileops` resolves a compatible tilelang release; apache-tvm-ffi
14+
# comes in transitively via tilelang's own metadata — no manual cap here.
15+
"tilelang>=0.1.9,<0.2.0",
1416
"einops",
1517
"pyyaml>=6.0",
1618
]

0 commit comments

Comments
 (0)