Skip to content
Latchkey

GPU tests workflow (stevezau/media_preview_generator)

The GPU tests workflow from stevezau/media_preview_generator, explained and optimized by Latchkey.

A

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 →
Source: stevezau/media_preview_generator.github/workflows/gpu-tests.ymlLicense MITView source

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

workflow (.yml)
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

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:

This workflow runs 1 job per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.

Actions used in this workflow