diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 0000000..d49a42b --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,55 @@ +name: Benchmark + +on: + push: + branches: + - main + pull_request: + workflow_dispatch: + +permissions: + contents: read + +env: + UV_FROZEN: true + UV_PYTHON: 3.14 + RUST_VERSION: "1.90.0" + +jobs: + benchmark: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository. + uses: actions/checkout@v4 + + - name: Install UV. + uses: astral-sh/setup-uv@v6 + + - name: Install dependencies. + run: uv sync --group testing + + - name: Compile. + run: uv pip install -v -e . + env: + RUST_BACKTRACE: 1 + + - name: Run Benchmarks. + run: uv run pytest . -m benchmark_main --benchmark-enable --benchmark-json=output.json + + - name: Download previous benchmark data. + uses: actions/cache@v4 + with: + path: ./benchmark-data + key: benchmark-${{ github.base_ref || github.ref_name }} + + - name: Benchmark results. + uses: benchmark-action/github-action-benchmark@v1 + with: + tool: 'pytest' + output-file-path: output.json + external-data-json-path: ./benchmark-data/output.json + summary-always: true + fail-on-alert: true + skip-fetch-gh-pages: true + save-data-file: ${{ github.event_name != 'pull_request' }} diff --git a/pyproject.toml b/pyproject.toml index 4a81447..613221f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,6 +60,9 @@ all = [ ] [tool.pytest.ini_options] +markers = [ + 'benchmark_main: marks tests as main benchmarks to run selectively' +] addopts = [ '--benchmark-columns', 'min,mean,stddev,outliers,rounds,iterations', '--benchmark-disable', # use --benchmark-enable diff --git a/pytests/test_dag_cbor.py b/pytests/test_dag_cbor.py index fee7708..c48c2c6 100644 --- a/pytests/test_dag_cbor.py +++ b/pytests/test_dag_cbor.py @@ -101,11 +101,13 @@ def test_dag_cbor_decode(benchmark, data) -> None: _dag_cbor_roundtrip(benchmark, data) +@pytest.mark.benchmark_main @pytest.mark.parametrize('data', load_json_data_fixtures(_REAL_DATA_DIR), ids=lambda data: data[0]) def test_dag_cbor_encode_real_data(benchmark, data) -> None: _dag_cbor_encode(benchmark, data) +@pytest.mark.benchmark_main @pytest.mark.parametrize('data', load_json_data_fixtures(_REAL_DATA_DIR), ids=lambda data: data[0]) def test_dag_cbor_decode_real_data(benchmark, data) -> None: _dag_cbor_roundtrip(benchmark, data) @@ -116,6 +118,7 @@ def test_dag_cbor_decode_fixtures(benchmark, data) -> None: _dag_cbor_decode(benchmark, data) +@pytest.mark.benchmark_main def test_dag_cbor_decode_torture_cids(benchmark) -> None: dag_cbor = open(_TORTURE_CIDS_DAG_CBOR_PATH, 'rb').read() benchmark(libipld.decode_dag_cbor, dag_cbor) diff --git a/pytests/test_decode_car.py b/pytests/test_decode_car.py index 76ea661..15d40c5 100644 --- a/pytests/test_decode_car.py +++ b/pytests/test_decode_car.py @@ -14,6 +14,7 @@ def car() -> bytes: return load_car_fixture(_DID, _REPO_CAR_PATH) +@pytest.mark.benchmark_main def test_decode_car(benchmark, car) -> None: header, blocks = benchmark(libipld.decode_car, car)