Skip to content

Commit 212338b

Browse files
committed
add CI to detect performance regressions
Compares two release builds of cpp-linter binary: 1. the previous commit (for push events) or the base branch of a PR 2. the newest commit on the branch Caching is enabled to reduce CI runtime. Results are output to the CI workflow's job summary. This CI does not (currently) fail when a regression is detected.
1 parent 023c170 commit 212338b

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed

.github/workflows/bench.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import argparse
2+
import json
3+
from os import environ
4+
from pathlib import Path
5+
from typing import List, Any, Dict
6+
7+
class Args(argparse.Namespace):
8+
json_file: Path
9+
10+
def main():
11+
arg_parser = argparse.ArgumentParser()
12+
arg_parser.add_argument("json_file", type=Path)
13+
arg_parser.parse_args(namespace=Args)
14+
15+
bench_json = Args.json_file.read_text(encoding="utf-8")
16+
bench: List[Dict[str, Any]] = json.loads(bench_json)["results"]
17+
18+
assert len(bench) == 2
19+
assert bench[0]["command"] == "previous-build"
20+
assert bench[1]["command"] == "current-build"
21+
22+
old_mean: float = bench[0]["mean"]
23+
new_mean: float = bench[1]["mean"]
24+
25+
diff = round(new_mean - old_mean, 2)
26+
scalar = round(new_mean / old_mean, 2)
27+
28+
output = []
29+
if diff > 0.5:
30+
output.extend([
31+
"> [!CAUTION]",
32+
"> Detected a performance regression in new changes:",]
33+
)
34+
elif diff < -0.5:
35+
output.extend([
36+
"> [!TIP]",
37+
"> Detect a performance improvement in new changes:",]
38+
)
39+
else:
40+
output.extend([
41+
"> [!NOTE]",
42+
"> Determined a negligible difference in performance with new changes:",]
43+
)
44+
output[-1] += f" {diff}s ({scalar} %)"
45+
annotation = "\n".join(output)
46+
47+
48+
if "GITHUB_STEP_SUMMARY" in environ:
49+
with open(environ["GITHUB_STEP_SUMMARY"], "a") as summary:
50+
summary.write(f"\n{annotation}\n")
51+
else:
52+
print(annotation)
53+
54+
if __name__ == "__main__":
55+
main()

.github/workflows/perf-test.yml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
name: Performance Regression
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
include:
15+
- commit: ${{ github.sha }}
16+
name: current
17+
- commit: ${{ github.event_name == 'pull_request' && github.base_ref || github.event.before }}
18+
name: previous
19+
steps:
20+
- name: Checkout ${{ matrix.name }}
21+
uses: actions/checkout@v4
22+
with:
23+
ref: ${{ matrix.commit }}
24+
- name: Cache base ref build
25+
uses: actions/cache@v4
26+
id: cache
27+
with:
28+
key: bin-cache-${{ matrix.name }}-${{ matrix.commit }}
29+
path: target/release/cpp-linter
30+
- run: rustup update --no-self-update
31+
if: steps.cache.outputs.cache-hit != 'true'
32+
- run: cargo build --bin cpp-linter --release
33+
if: steps.cache.outputs.cache-hit != 'true'
34+
- name: Upload build artifact
35+
uses: actions/upload-artifact@v4
36+
with:
37+
name: ${{ matrix.name }}
38+
path: target/release/cpp-linter
39+
40+
benchmark:
41+
name: Measure Performance Difference
42+
needs: [build]
43+
runs-on: ubuntu-latest
44+
steps:
45+
- name: Checkout libgit2
46+
uses: actions/checkout@v4
47+
with:
48+
repository: libgit2/libgit2
49+
ref: v1.8.1
50+
- name: Download built binaries
51+
uses: actions/download-artifact@v4
52+
- name: Install cargo-binstall
53+
uses: cargo-bins/cargo-binstall@main
54+
- name: Install hyperfine
55+
run: cargo binstall -y hyperfine
56+
- name: Run hyperfine tool
57+
run: >-
58+
hyperfine
59+
--shell=default
60+
--warmup 1
61+
--runs 5
62+
--style color
63+
--export-markdown '${{ runner.temp }}/benchmark.md'
64+
--export-json '${{ runner.temp }}/benchmark.json'
65+
--command-name=previous-build './previous/cpp-linter -l 0'
66+
--command-name=current-build './current/cpp-linter -l 0'
67+
- run: cat ${{ runner.temp }}/bench.md >> $GITHUB_STEP_SUMMARY
68+
- name: Upload JSON results
69+
uses: actions/upload-artifact@v4
70+
with:
71+
path: ${{ runner.temp }}/benchmark.json
72+
- uses: actions/setup-python@v5
73+
with:
74+
python-version: 3.x
75+
- name: Annotate summary
76+
run: python .github/workflows/bench.py "${{ runner.temp }}/benchmark.json"
77+

0 commit comments

Comments
 (0)