Skip to content

Commit bee241d

Browse files
authored
Enhance CI benchmarks with regression detection (#531)
This commit introduces a new script to detect performance regressions. It compares the 'http_reqs' rate metric from the PR summary against the main branch summary and determines if there is a regression of more than 2%. Also, the commit adds .gitignore entries, a script to detect regressions, and changes to the CI workflow to execute the benchmarks and compare the results.
1 parent 6179f66 commit bee241d

File tree

6 files changed

+109
-2
lines changed

6 files changed

+109
-2
lines changed

.github/workflows/ci.yaml

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,46 @@ jobs:
128128
- name: Build router
129129
run: cargo build --release -p hive-router
130130
- name: Run router
131-
run: ./target/release/hive_router & sleep 5
131+
run: |
132+
./target/release/hive_router &
133+
echo "$!" > router.pid
134+
sleep 5
132135
env:
133136
SUPERGRAPH_FILE_PATH: bench/supergraph.graphql
134-
- name: Run k6 benchmark
137+
# run only on main
138+
- name: Run k6 benchmark for Pull Request
139+
if: github.event_name == 'push'
135140
run: k6 run bench/k6.js
141+
# run only on PR
142+
- name: Run k6 benchmark for Pull Request
143+
if: github.event_name == 'pull_request'
144+
run: k6 run -e SUMMARY_PATH=./bench/results/pr bench/k6.js
145+
- name: Checkout main branch in a separate directory
146+
if: github.event_name == 'pull_request'
147+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
148+
with:
149+
ref: main
150+
path: main-branch
151+
- name: Build router
152+
if: github.event_name == 'pull_request'
153+
run: cargo build --release -p hive-router
154+
working-directory: main-branch
155+
- name: Run router
156+
if: github.event_name == 'pull_request'
157+
run: |
158+
kill $(cat router.pid)
159+
./main-branch/target/release/hive_router &
160+
sleep 5
161+
env:
162+
SUPERGRAPH_FILE_PATH: bench/supergraph.graphql
163+
- name: Run k6 benchmark for main
164+
if: github.event_name == 'pull_request'
165+
run: k6 run -e SUMMARY_PATH=./bench/results/main bench/k6.js
166+
- name: Compare benchmark results
167+
if: github.event_name == 'pull_request'
168+
run: |
169+
chmod +x ./bench/ci-detect-regression.sh
170+
./bench/ci-detect-regression.sh
136171
137172
graphql-over-http:
138173
runs-on: ubuntu-latest

bench/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
./results/main
2+
./results/pr

bench/ci-detect-regression.sh

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/bin/bash
2+
3+
# This script is meant to be run in CI (./github/workflows/ci.yaml#router-benchmark).
4+
#
5+
# It's a script to detect performance regression between two k6 benchmark summary files.
6+
# It compares the 'http_reqs' rate metric from the PR summary against the main branch
7+
# summary and determines if there is a regression of more than 2%.
8+
# If a regression is detected, the script exits with a non-zero status code.
9+
10+
# Ensure jq and bc are installed
11+
if ! command -v jq &> /dev/null
12+
then
13+
echo "jq could not be found. Please install jq to run this script."
14+
exit 1
15+
fi
16+
if ! command -v bc &> /dev/null
17+
then
18+
echo "bc could not be found. Please install bc to run this script."
19+
exit 1
20+
fi
21+
22+
PR_SUMMARY="./bench/results/pr/k6_summary.json"
23+
MAIN_SUMMARY="./bench/results/main/k6_summary.json"
24+
25+
# Check if the summary files exist
26+
if [ ! -f "$PR_SUMMARY" ] || [ ! -f "$MAIN_SUMMARY" ]; then
27+
echo "Benchmark summary files ($PR_SUMMARY and/or $MAIN_SUMMARY) not found."
28+
exit 1
29+
fi
30+
31+
# Extract the rate values
32+
MAIN_RATE=$(jq '.metrics.http_reqs.values.rate' "$MAIN_SUMMARY")
33+
PR_RATE=$(jq '.metrics.http_reqs.values.rate' "$PR_SUMMARY")
34+
35+
# Check if jq successfully extracted the rates
36+
if [ -z "$MAIN_RATE" ] || [ -z "$PR_RATE" ] || [ "$MAIN_RATE" == "null" ] || [ "$PR_RATE" == "null" ]; then
37+
echo "Could not extract rate from one or both summary files."
38+
exit 1
39+
fi
40+
41+
# Handle case where main rate is 0 to avoid division by zero
42+
if (( $(echo "$MAIN_RATE == 0" | bc -l) )); then
43+
echo "Main branch rate is zero, cannot calculate percentage change."
44+
# If the main rate is 0, any positive PR rate is an improvement, not a regression.
45+
exit 0
46+
fi
47+
48+
# Calculate the percentage difference using bc
49+
# scale determines the number of decimal places
50+
diff=$(echo "scale=4; (($PR_RATE - $MAIN_RATE) / $MAIN_RATE) * 100" | bc)
51+
52+
# Print the results
53+
echo "Main branch http_reqs rate: $MAIN_RATE"
54+
echo "PR branch http_reqs rate: $PR_RATE"
55+
printf "Difference: %.2f%%\n" "$diff"
56+
57+
# Check if the difference is a regression of more than 5%
58+
# bc returns 1 for true, 0 for false. We compare with a negative number.
59+
is_regression=$(echo "$diff < -2" | bc)
60+
61+
if [ "$is_regression" -eq 1 ]; then
62+
echo "Performance regression detected! The PR is more than 2% slower than main."
63+
exit 1
64+
else
65+
echo "No significant performance regression detected."
66+
exit 0
67+
fi

bench/k6.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,9 @@ function handleBenchmarkSummary(data, additionalContext = {}) {
155155
};
156156

157157
if (__ENV.SUMMARY_PATH) {
158+
console.log(
159+
`Writing summary to ${__ENV.SUMMARY_PATH}/k6_summary.json and .txt`,
160+
);
158161
out[`${__ENV.SUMMARY_PATH}/k6_summary.json`] = JSON.stringify(
159162
Object.assign(data, additionalContext),
160163
);

bench/results/main/.gitkeep

Whitespace-only changes.

bench/results/pr/.gitkeep

Whitespace-only changes.

0 commit comments

Comments
 (0)