Skip to content

Add GPU test CI workflow with JIT and AOT jobs#1004

Merged
rodlima78 merged 1 commit into
mainfrom
achauveau/gpu-ci
Jul 24, 2026
Merged

Add GPU test CI workflow with JIT and AOT jobs#1004
rodlima78 merged 1 commit into
mainfrom
achauveau/gpu-ci

Conversation

@achauveau-nv

@achauveau-nv achauveau-nv commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Introduce .github/workflows/gpu_tests.yml, a test pipeline executing on self-hosted GPU runners. Two jobs run with CUDA 12.9:

  • jit-test-debug: editable install with DEBUG=1, JIT compiles CUDA extensions on first import; runs the full pytest suite.
  • aot-test-release: builds a wheel with 'pip wheel -v' (GSPLAT_DISABLE_JIT=1 triggers AOT compilation), installs it, then runs the pytest suite.

Key implementation decisions:

Jobs run in a Docker container and not directly on the runner to provide isolation.

Dependencies install is performed during the workflow over a vanilla CUDA 12.9 container image:

  • It takes time and is not fully reproducible, but it makes a good starting point as the maintenance of custom container images would be heavier.
  • pip dependencies are cached into a persistent volume to improve performance.

Both AOT and JIT compilation for gsplat and dependencies go through ccache, also with a persistent volume. Pulling already up-to-date compilation results from cache can offer several minutes of time saving per job.

Container spec and five setup steps are shared via YAML anchors. GitHub's schema rejects unknown top-level keys, so there's no workflow-level node to hang them on; they're defined in the first job and reused by the second one.

A root conftest.py marks a set of known-failing test_basic.py cases as xfail, gated on GPU_CI_XFAIL=1 set at the workflow level so the marker stays CI-only. These are marginal floating-point tolerance mismatches on the runner GPU rather than logic errors in the workflow setup and should be fixed as a follow-up.

Trigger policy: the workflow runs automatically on push to main and is manually triggerable via workflow_dispatch (Actions UI or gh CLI). The pull_request trigger is intentionally omitted for now: job runtime is too long to gate every PR. The intent is to enable it by default once job execution time has been optimized.

- &step-install-python-deps
name: Install Python deps
run: |
python3 -m venv /opt/venv

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use uv for virtual environment and package management instead of bare venv/pip. It's quite a bit faster and will save on CI usage.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general I agree with the benefits of using this more modern tooling. However for the purpose of this PR I chose to stick with pip to remain consistent with current practice in the repo's existing workflows. Switching to uv is, I think, a worthy improvement to consider across all workflows, and separately from this PR.

Introduce .github/workflows/gpu_tests.yml, a test pipeline executing
on self-hosted GPU runners. Two jobs run with CUDA 12.9:

- jit-test-debug: editable install with DEBUG=1, JIT compiles CUDA
  extensions on first import; runs the full pytest suite.
- aot-test-release: builds a wheel with 'pip wheel -v' (GSPLAT_DISABLE_JIT=1
  triggers AOT compilation), installs it, then runs the pytest suite.

Key implementation decisions:

Jobs run in a Docker container and not directly on the runner to provide
isolation.

Dependencies install is performed during the workflow over a vanilla
CUDA 12.9 container image:

- It takes time and is not fully reproducible, but it makes a good
  starting point as the maintenance of custom container images would be
  heavier.
- pip dependencies are cached into a persistent volume to improve
  performance.

Both AOT and JIT compilation for gsplat and dependencies go through
ccache, also with a persistent volume. Pulling already up-to-date
compilation results from cache can offer several minutes of time saving
per job.

Container spec and five setup steps are shared via YAML anchors. GitHub's
schema rejects unknown top-level keys, so there's no workflow-level node
to hang them on; they're defined in the first job and reused by the
second one.

A root conftest.py marks a set of known-failing test_basic.py cases as
xfail, gated on GPU_CI_XFAIL=1 set at the workflow level so the marker
stays CI-only. These are marginal floating-point tolerance mismatches on
the runner GPU rather than logic errors in the workflow setup and should
be fixed as a follow-up.

Trigger policy: the workflow runs automatically on push to main and is
manually triggerable via workflow_dispatch (Actions UI or gh CLI). The
pull_request trigger is intentionally omitted for now: job runtime is
too long to gate every PR. The intent is to enable it by default once
job execution time has been optimized.
@achauveau-nv

Copy link
Copy Markdown
Collaborator Author

Auto-trigger on main PRs has been demoted at this stage after discussion with the team. The latest version was validated with an explicit trigger: https://github.com/nerfstudio-project/gsplat/actions/runs/30080994300

@rodlima78
rodlima78 merged commit 2b902ff into main Jul 24, 2026
4 checks passed
@rodlima78
rodlima78 deleted the achauveau/gpu-ci branch July 24, 2026 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants