GPU tests workflow (stevezau/media_preview_generator)
The GPU tests workflow from stevezau/media_preview_generator, explained and optimized by Latchkey.
CI health: A - excellent
Run this on Latchkey for self-healing, caching, and up to 58% lower cost.
Grade your own workflow free or run it on Latchkey →What it does
This is the GPU tests workflow from the stevezau/media_preview_generator repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: GPU tests
# GPU-marker tests need a real NVIDIA GPU. GitHub-hosted runners don't
# have one, so this workflow targets a self-hosted runner labelled
# `self-hosted, linux, gpu`. Set one up by following:
# https://docs.github.com/en/actions/hosting-your-own-runners
# and add `gpu` as an extra label during registration.
#
# Triggers:
# - manual (workflow_dispatch) - for ad-hoc validation before merge
# - weekly schedule - catches driver / FFmpeg regressions
# - PRs labelled `run-gpu` - opt-in per-PR, so the runner isn't
# hammered by every PR push
#
# When no `gpu`-labelled runner is online, the job will queue and
# eventually time out - that is the intended behaviour. The workflow
# is harmless on forks: PRs from forks cannot label themselves.
on:
workflow_dispatch:
schedule:
# 03:00 UTC every Monday - pick a quiet time so the runner is free.
- cron: '0 3 * * 1'
pull_request:
types: [labeled, synchronize]
branches: [main, dev]
# Single concurrent run per ref. A new push to a PR cancels the old
# run so the runner isn't spending hours on stale code.
concurrency:
group: gpu-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write # so we can post a status comment on the PR
jobs:
gpu-tests:
# Skip PR triggers unless the `run-gpu` label was just applied or the
# branch already carries the label. workflow_dispatch and schedule
# always run.
if: >-
github.event_name != 'pull_request' ||
contains(github.event.pull_request.labels.*.name, 'run-gpu')
runs-on: [self-hosted, linux, gpu]
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # setuptools-scm needs full history
- name: Show GPU
run: nvidia-smi -L
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Verify FFmpeg with NVENC
run: |
ffmpeg -version | head -1
ffmpeg -hwaccels 2>&1 | grep -q cuda \
|| (echo "::error::FFmpeg on this runner is missing CUDA hwaccel support"; exit 1)
- name: Install dependencies
run: pip install -e ".[test]"
- name: Run GPU-marker tests
env:
# CUDA stays available on self-hosted runners; allow Python to
# pick up the GPU without explicit DISPLAY etc.
NVIDIA_VISIBLE_DEVICES: all
NVIDIA_DRIVER_CAPABILITIES: all
run: |
/home/data/.venv/bin/python -m pytest -m gpu -n 0 --no-cov -o addopts='' --tb=short -v \
|| pytest -m gpu -n 0 --no-cov -o addopts='' --tb=short -v
- name: Comment on PR (success)
if: ${{ success() && github.event_name == 'pull_request' }}
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '✅ GPU tests passed on self-hosted NVIDIA runner.'
})
- name: Comment on PR (failure)
if: ${{ failure() && github.event_name == 'pull_request' }}
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '❌ GPU tests failed - see workflow logs: ' + context.serverUrl + '/' + context.repo.owner + '/' + context.repo.repo + '/actions/runs/' + context.runId
})
The same workflow, on Latchkey
Estimated ~20% faster on cache hits, plus fewer wasted runs and a safer supply chain. Added and changed lines are highlighted.
name: GPU tests # GPU-marker tests need a real NVIDIA GPU. GitHub-hosted runners don't # have one, so this workflow targets a self-hosted runner labelled # `self-hosted, linux, gpu`. Set one up by following: # https://docs.github.com/en/actions/hosting-your-own-runners # and add `gpu` as an extra label during registration. # # Triggers: # - manual (workflow_dispatch) - for ad-hoc validation before merge # - weekly schedule - catches driver / FFmpeg regressions # - PRs labelled `run-gpu` - opt-in per-PR, so the runner isn't # hammered by every PR push # # When no `gpu`-labelled runner is online, the job will queue and # eventually time out - that is the intended behaviour. The workflow # is harmless on forks: PRs from forks cannot label themselves. on: workflow_dispatch: schedule: # 03:00 UTC every Monday - pick a quiet time so the runner is free. - cron: '0 3 * * 1' pull_request: types: [labeled, synchronize] branches: [main, dev] # Single concurrent run per ref. A new push to a PR cancels the old # run so the runner isn't spending hours on stale code. concurrency: group: gpu-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true permissions: contents: read pull-requests: write # so we can post a status comment on the PR jobs: gpu-tests: # Skip PR triggers unless the `run-gpu` label was just applied or the # branch already carries the label. workflow_dispatch and schedule # always run. if: >- github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'run-gpu') runs-on: [self-hosted, linux, gpu] timeout-minutes: 30 steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # setuptools-scm needs full history - name: Show GPU run: nvidia-smi -L - name: Set up Python uses: actions/setup-python@v5 with: cache: 'pip' python-version: "3.12" - name: Verify FFmpeg with NVENC run: | ffmpeg -version | head -1 ffmpeg -hwaccels 2>&1 | grep -q cuda \ || (echo "::error::FFmpeg on this runner is missing CUDA hwaccel support"; exit 1) - name: Install dependencies run: pip install -e ".[test]" - name: Run GPU-marker tests env: # CUDA stays available on self-hosted runners; allow Python to # pick up the GPU without explicit DISPLAY etc. NVIDIA_VISIBLE_DEVICES: all NVIDIA_DRIVER_CAPABILITIES: all run: | /home/data/.venv/bin/python -m pytest -m gpu -n 0 --no-cov -o addopts='' --tb=short -v \ || pytest -m gpu -n 0 --no-cov -o addopts='' --tb=short -v - name: Comment on PR (success) if: ${{ success() && github.event_name == 'pull_request' }} uses: actions/github-script@v7 with: script: | github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: '✅ GPU tests passed on self-hosted NVIDIA runner.' }) - name: Comment on PR (failure) if: ${{ failure() && github.event_name == 'pull_request' }} uses: actions/github-script@v7 with: script: | github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: '❌ GPU tests failed - see workflow logs: ' + context.serverUrl + '/' + context.repo.owner + '/' + context.repo.repo + '/actions/runs/' + context.runId })
What changed
- Cache dependency installs on the setup step so they are served from cache.
What Latchkey heals here
This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:
- Dependency installs
This workflow runs 1 job per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.