Skip to content

Commit d4e0e7f

Browse files
Mark Saroufimngc92
authored andcommitted
Use pre-built wheel from CI instead of building from source on Modal
Simplifies the Modal script to accept a wheel + test files as args, and moves the GPU test job into wheel.yml so it reuses the wheel artifact.
1 parent e28595c commit d4e0e7f

3 files changed

Lines changed: 57 additions & 57 deletions

File tree

.github/workflows/gpu-test.yml

Lines changed: 0 additions & 26 deletions
This file was deleted.

.github/workflows/wheel.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,33 @@ jobs:
5858
name: wheel-${{ matrix.wheel_tag }}
5959
path: wheelhouse/pygpubench*.whl
6060

61+
gpu-test:
62+
name: GPU tests (Modal L4)
63+
needs: wheel
64+
runs-on: ubuntu-24.04
65+
steps:
66+
- uses: actions/checkout@v4
67+
68+
- uses: actions/setup-python@v5
69+
with:
70+
python-version: "3.12"
71+
72+
- name: Download wheel
73+
uses: actions/download-artifact@v4
74+
with:
75+
pattern: wheel-*
76+
path: dist/
77+
merge-multiple: true
78+
79+
- name: Install Modal
80+
run: pip install modal
81+
82+
- name: Run GPU tests
83+
env:
84+
MODAL_TOKEN_ID: ${{ secrets.MODAL_TOKEN_ID }}
85+
MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }}
86+
run: modal run ci/modal_gpu_test.py --wheel dist/pygpubench*.whl --test-dir test
87+
6188
release:
6289
name: Publish to GitHub Releases
6390
needs: wheel

ci/modal_gpu_test.py

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,45 @@
11
"""Run pygpubench GPU tests on a Modal L4 GPU.
22
3-
Usage: modal run ci/modal_gpu_test.py
3+
Usage: modal run ci/modal_gpu_test.py <wheel_path> <test_dir>
44
"""
55

66
import modal
77
from pathlib import Path
88

9-
_repo = Path(__file__).resolve().parent.parent
10-
119
image = (
1210
modal.Image.from_registry(
1311
"nvidia/cuda:13.0.1-cudnn-devel-ubuntu24.04", add_python="3.12"
1412
)
1513
.entrypoint([])
16-
.apt_install("git", "g++-13", "cmake", "ninja-build")
1714
.uv_pip_install("torch", index_url="https://download.pytorch.org/whl/cu130")
18-
.env({
19-
"CUDAARCHS": "80;90",
20-
"CC": "gcc-13",
21-
"CXX": "g++-13",
22-
"CMAKE_GENERATOR": "Ninja",
23-
})
24-
.add_local_dir(str(_repo / "csrc"), remote_path="/root/pygpubench/csrc")
25-
.add_local_dir(str(_repo / "python"), remote_path="/root/pygpubench/python")
26-
.add_local_dir(str(_repo / "test"), remote_path="/root/pygpubench/test")
27-
.add_local_file(str(_repo / "pyproject.toml"), remote_path="/root/pygpubench/pyproject.toml")
28-
.add_local_file(str(_repo / "CMakeLists.txt"), remote_path="/root/pygpubench/CMakeLists.txt")
29-
.add_local_file(str(_repo / "README.md"), remote_path="/root/pygpubench/README.md")
3015
)
3116

3217
app = modal.App("pygpubench-ci", image=image)
3318

3419

3520
@app.function(gpu="L4", timeout=600)
36-
def run_tests():
21+
def run_tests(whl_bytes: bytes, whl_name: str, test_files: dict[str, bytes]):
3722
import subprocess
38-
import shutil
39-
import glob
4023
import sys
4124
import os
4225

43-
# Mounts are read-only; copy to a writable location for the build
44-
shutil.copytree("/root/pygpubench", "/tmp/pygpubench")
45-
os.chdir("/tmp/pygpubench")
26+
# Write wheel and install it
27+
whl_path = f"/tmp/{whl_name}"
28+
with open(whl_path, "wb") as f:
29+
f.write(whl_bytes)
30+
subprocess.run([sys.executable, "-m", "pip", "install", whl_path], check=True)
4631

47-
subprocess.run(["uv", "build", "--wheel"], check=True)
32+
# Write test files
33+
test_dir = "/tmp/tests"
34+
os.makedirs(test_dir, exist_ok=True)
35+
for name, content in test_files.items():
36+
with open(os.path.join(test_dir, name), "wb") as f:
37+
f.write(content)
4838

49-
whl = glob.glob("dist/*.whl")[0]
50-
subprocess.run([sys.executable, "-m", "pip", "install", whl], check=True)
51-
52-
# Run all test scripts in test/
53-
os.chdir("/tmp/pygpubench/test")
39+
# Run all test scripts
40+
os.chdir(test_dir)
5441
failed = []
55-
for test_file in sorted(glob.glob("*.py")):
42+
for test_file in sorted(test_files):
5643
if test_file == "submission.py":
5744
continue
5845
print(f"\n=== {test_file} ===")
@@ -66,5 +53,17 @@ def run_tests():
6653

6754

6855
@app.local_entrypoint()
69-
def main():
70-
run_tests.remote()
56+
def main(wheel: str, test_dir: str = "test"):
57+
import glob
58+
59+
# Read the wheel
60+
whl_path = Path(wheel)
61+
whl_bytes = whl_path.read_bytes()
62+
63+
# Read all test files
64+
test_path = Path(test_dir)
65+
test_files = {}
66+
for f in test_path.glob("*.py"):
67+
test_files[f.name] = f.read_bytes()
68+
69+
run_tests.remote(whl_bytes, whl_path.name, test_files)

0 commit comments

Comments
 (0)