Benchmark workflow (Neoteroi/BlackSheep)
The Benchmark workflow from Neoteroi/BlackSheep, explained and optimized by Latchkey.
CI health: C - fair
Point runs-on at Latchkey and get caching, job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Benchmark workflow from the Neoteroi/BlackSheep 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
####################################################################################
# Runs benchmarks for BlackSheep source code for various versions of Python
# and Operating System and publishes the results.
# See the perf folder for more information.
####################################################################################
name: Benchmark
on:
# push:
# paths:
# - '.github/**'
# - 'perf/**'
workflow_dispatch:
jobs:
perf-tests:
strategy:
fail-fast: false
matrix:
python-version: ["3.12", "3.13", "3.14"]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 9
submodules: false
- name: Use Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install flake8
- name: Compile Cython extensions
run: |
cython blacksheep/url.pyx
cython blacksheep/exceptions.pyx
cython blacksheep/headers.pyx
cython blacksheep/cookies.pyx
cython blacksheep/contents.pyx
cython blacksheep/messages.pyx
cython blacksheep/scribe.pyx
cython blacksheep/baseapp.pyx
python setup.py build_ext --inplace
- name: Install dependencies for benchmark
run: |
pip install memory-profiler==0.61.0 psutil==7.0.0
- name: Run benchmark
shell: bash
run: |
export PYTHONPATH="."
python perf/main.py --times 5
- name: Upload results
uses: actions/upload-artifact@v4
with:
name: benchmark-results-${{ matrix.os }}-${{ matrix.python-version }}
path: benchmark_results
perf-tests-pypy:
strategy:
fail-fast: false
matrix:
python-version: ["pypy-3.11"]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 9
submodules: false
- name: Use Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
pip install -r requirements.pypy.txt
- name: Install dependencies for benchmark
run: |
pip install memory-profiler==0.61.0 psutil==7.0.0
- name: Run benchmark
shell: bash
run: |
export PYTHONPATH="."
python perf/main.py --times 5
- name: Upload results
uses: actions/upload-artifact@v4
with:
name: benchmark-results-${{ matrix.os }}-${{ matrix.python-version }}
path: benchmark_results
genreport:
runs-on: ubuntu-latest
needs: [perf-tests, perf-tests-pypy]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 9
submodules: false
- name: Download a distribution artifact
uses: actions/download-artifact@v4
with:
pattern: benchmark-results-*
merge-multiple: true
path: benchmark_results
- name: Use Python 3.13
uses: actions/setup-python@v5
with:
python-version: '3.13'
- name: Install dependencies
run: |
cd perf
pip install -r req.txt
- name: Generate report
shell: bash
run: |
ls -R benchmark_results
chmod -R 755 benchmark_results
export PYTHONPATH="."
python perf/genreport.py
python perf/genreport.py --output windows-results.xlsx --platform Windows
python perf/genreport.py --output linux-results.xlsx --platform Linux
python perf/genreport.py --output macos-results.xlsx --platform macOS
- name: Upload reports
uses: actions/upload-artifact@v4
with:
name: benchmark-reports
path: "**/*.xlsx" # Upload all .xlsx files
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.
#################################################################################### # Runs benchmarks for BlackSheep source code for various versions of Python # and Operating System and publishes the results. # See the perf folder for more information. #################################################################################### name: Benchmark on: # push: # paths: # - '.github/**' # - 'perf/**' workflow_dispatch: jobs: perf-tests: timeout-minutes: 30 strategy: fail-fast: false matrix: python-version: ["3.12", "3.13", "3.14"] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 with: fetch-depth: 9 submodules: false - name: Use Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: cache: 'pip' python-version: ${{ matrix.python-version }} - name: Install dependencies run: | pip install -r requirements.txt pip install flake8 - name: Compile Cython extensions run: | cython blacksheep/url.pyx cython blacksheep/exceptions.pyx cython blacksheep/headers.pyx cython blacksheep/cookies.pyx cython blacksheep/contents.pyx cython blacksheep/messages.pyx cython blacksheep/scribe.pyx cython blacksheep/baseapp.pyx python setup.py build_ext --inplace - name: Install dependencies for benchmark run: | pip install memory-profiler==0.61.0 psutil==7.0.0 - name: Run benchmark shell: bash run: | export PYTHONPATH="." python perf/main.py --times 5 - name: Upload results uses: actions/upload-artifact@v4 with: name: benchmark-results-${{ matrix.os }}-${{ matrix.python-version }} path: benchmark_results perf-tests-pypy: timeout-minutes: 30 strategy: fail-fast: false matrix: python-version: ["pypy-3.11"] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 with: fetch-depth: 9 submodules: false - name: Use Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: cache: 'pip' python-version: ${{ matrix.python-version }} - name: Install dependencies run: | pip install -r requirements.pypy.txt - name: Install dependencies for benchmark run: | pip install memory-profiler==0.61.0 psutil==7.0.0 - name: Run benchmark shell: bash run: | export PYTHONPATH="." python perf/main.py --times 5 - name: Upload results uses: actions/upload-artifact@v4 with: name: benchmark-results-${{ matrix.os }}-${{ matrix.python-version }} path: benchmark_results genreport: timeout-minutes: 30 runs-on: latchkey-small needs: [perf-tests, perf-tests-pypy] steps: - uses: actions/checkout@v4 with: fetch-depth: 9 submodules: false - name: Download a distribution artifact uses: actions/download-artifact@v4 with: pattern: benchmark-results-* merge-multiple: true path: benchmark_results - name: Use Python 3.13 uses: actions/setup-python@v5 with: cache: 'pip' python-version: '3.13' - name: Install dependencies run: | cd perf pip install -r req.txt - name: Generate report shell: bash run: | ls -R benchmark_results chmod -R 755 benchmark_results export PYTHONPATH="." python perf/genreport.py python perf/genreport.py --output windows-results.xlsx --platform Windows python perf/genreport.py --output linux-results.xlsx --platform Linux python perf/genreport.py --output macos-results.xlsx --platform macOS - name: Upload reports uses: actions/upload-artifact@v4 with: name: benchmark-reports path: "**/*.xlsx" # Upload all .xlsx files
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Cache dependency installs on the setup step so they are served from cache.
- Add a job timeout so a hung step cannot burn hours of runner time.
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 3 jobs (13 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.