Skip to content

Commit 00c19e2

Browse files
authored
Add performance regression comparison in CI (rust-lang#2370)
This commit adds a CI job that runs the benchcomp tool on the performance regression suite, comparing the HEAD of the pull request to the branch that the PR targets. The CI job fails if any performance benchmark regresses when run using the HEAD version of Kani with respect to the 'base' branch. Regression is defined as a regression in symex or solver time of 10% for any benchmark for which this value is >2s, or if any performance benchmark fails with the HEAD version while passing with the base. This fixes rust-lang#2277.
1 parent c7e050d commit 00c19e2

File tree

5 files changed

+107
-2
lines changed

5 files changed

+107
-2
lines changed

.github/workflows/kani.yml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,61 @@ jobs:
226226
if-no-files-found: error
227227
# Aggressively short retention: we don't really need these
228228
retention-days: 3
229+
230+
perf-benchcomp:
231+
runs-on: ubuntu-20.04
232+
steps:
233+
- name: Save push event HEAD and HEAD~ to environment variables
234+
if: ${{ github.event_name == 'push' }}
235+
run: |
236+
echo "NEW_REF=${{ github.event.after}}" | tee -a "$GITHUB_ENV"
237+
# We want to compare with $NEW_REF~. But we can't know what
238+
# that ref actually is until we clone the repository, so for
239+
# now make it equal to $NEW_REF
240+
echo "OLD_REF=${{ github.event.after }}" | tee -a "$GITHUB_ENV"
241+
242+
- name: Save pull request HEAD and target to environment variables
243+
if: ${{ github.event_name == 'pull_request' }}
244+
run: |
245+
echo "OLD_REF=${{ github.event.pull_request.base.sha }}" | tee -a "$GITHUB_ENV"
246+
echo "NEW_REF=${{ github.event.pull_request.head.sha }}" | tee -a "$GITHUB_ENV"
247+
248+
- name: Check out Kani (old variant)
249+
uses: actions/checkout@v3
250+
with:
251+
path: ./old
252+
ref: ${{ env.OLD_REF }}
253+
fetch-depth: 2
254+
255+
- name: Check out HEAD~ of push event as 'old' variant
256+
if: ${{ github.event_name == 'push' }}
257+
run: pushd old && git checkout "${NEW_REF}^"
258+
259+
- name: Check out Kani (new variant)
260+
uses: actions/checkout@v3
261+
with:
262+
path: ./new
263+
ref: ${{ env.NEW_REF }}
264+
265+
- name: Set up Kani Dependencies (old variant)
266+
uses: ./old/.github/actions/setup
267+
with:
268+
os: ubuntu-20.04
269+
kani_dir: old
270+
271+
- name: Set up Kani Dependencies (new variant)
272+
uses: ./new/.github/actions/setup
273+
with:
274+
os: ubuntu-20.04
275+
kani_dir: new
276+
277+
- name: Build Kani (new variant)
278+
run: pushd new && cargo build-dev
279+
280+
- name: Build Kani (old variant)
281+
run: pushd old && cargo build-dev
282+
283+
- name: Run benchcomp
284+
run: |
285+
new/tools/benchcomp/bin/benchcomp \
286+
--config new/tools/benchcomp/configs/perf-regression.yaml

tools/benchcomp/benchcomp/entry/run.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ def __call__(self):
5757

5858
if self.copy_benchmarks_dir:
5959
shutil.copytree(
60-
self.directory, self.working_copy, ignore_dangling_symlinks=True)
60+
self.directory, self.working_copy,
61+
ignore_dangling_symlinks=True, symlinks=True)
6162

6263
try:
6364
subprocess.run(

tools/benchcomp/benchcomp/visualizers/utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44

55
import dataclasses
6+
import logging
67
import typing
78

89
import benchcomp.visualizers
@@ -82,7 +83,7 @@ def __call__(self, results):
8283
new = bench["variants"][new_variant]["metrics"][self.metric]
8384

8485
if has_regressed(old, new):
85-
logging.warining(
86+
logging.warning(
8687
"Benchmark '%s' regressed on metric '%s' (%s -> %s)",
8788
bench_name, self.metric, old, new)
8889
ret = True

tools/benchcomp/configs/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Example Benchcomp Configurations
2+
================================
3+
4+
The files in this directory can be passed to benchcomp's -c/--config flag.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Copyright Kani Contributors
2+
# SPDX-License-Identifier: Apache-2.0 OR MIT
3+
#
4+
# Run the Kani perf suite twice, erroring out on regression. This config
5+
# file is primarily intended to be used in CI, because it assumes that
6+
# there are two Kani checkouts in the 'old' and 'new' directories;
7+
# benchcomp compares the performance of these two checkouts.
8+
9+
variants:
10+
kani_new:
11+
config:
12+
directory: new
13+
command_line: PATH=$(realpath new/scripts):$PATH scripts/kani-perf.sh
14+
env:
15+
RUST_TEST_THREADS: "1"
16+
kani_old:
17+
config:
18+
directory: old
19+
command_line: PATH=$(realpath old/scripts):$PATH scripts/kani-perf.sh
20+
env:
21+
RUST_TEST_THREADS: "1"
22+
23+
run:
24+
suites:
25+
kani_perf:
26+
parser:
27+
module: kani_perf
28+
variants: [kani_old, kani_new]
29+
30+
visualize:
31+
- type: error_on_regression
32+
variant_pairs: [[kani_old, kani_new]]
33+
checks:
34+
- metric: success
35+
# Compare the old and new variants of each benchmark. The
36+
# benchmark has regressed if the lambda returns true.
37+
test: "lambda old, new: False if not old else not new"
38+
- metric: solver_runtime
39+
test: "lambda old, new: False if new < 2 else new/old > 1.1"
40+
- metric: symex_runtime
41+
test: "lambda old, new: False if new < 2 else new/old > 1.1"

0 commit comments

Comments
 (0)