Skip to content

Commit 61c8bb6

Browse files
committed
perf(bench): add benchmarks with gungraun
1 parent 378c818 commit 61c8bb6

12 files changed

Lines changed: 673 additions & 53 deletions

File tree

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
3030
- [ ] `cargo fmt --check` passes
3131
- [ ] `cargo clippy --all-targets` passes (deny level)
32-
- [ ] `cargo test --all-targets` passes
32+
- [ ] `cargo test --lib --tests && cargo test --doc` passes
3333
- [ ] `cargo doc --no-deps` builds without warnings
3434
- [ ] Documentation updated (README, docs) if behaviour changed
3535
- [ ] Commits follow [Conventional Commits](https://www.conventionalcommits.org) format

.github/workflows/ci.yml

Lines changed: 107 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@
55
# 1. cargo fmt --check -> consistent formatting
66
# 2. cargo clippy (deny) -> zero lint warnings (all+pedantic+nursery)
77
# 3. cargo test --locked -> all tests pass, Cargo.lock respected
8-
# 4. cargo build -> library compiles
9-
# 5. cargo doc -> documentation + doc-comment format valid
10-
# 6. cargo deny check -> no vulnerable/banned dependencies
8+
# 4. cargo bench --no-run -> benchmarks compile without errors
9+
# 5. cargo build -> library compiles
10+
# 6. cargo doc -> documentation + doc-comment format valid
11+
# 7. cargo deny check -> no vulnerable/banned dependencies
12+
#
13+
# Linux benchmark execution:
14+
# - gungraun instruction-count regressions vs PR merge-base
1115

1216
name: CI
1317

@@ -64,15 +68,21 @@ jobs:
6468

6569
# Gate 3: Tests - rejects broken logic; --locked ensures Cargo.lock is honoured
6670
- name: "Gate 3: cargo test"
67-
run: cargo test --locked --all-targets
71+
run: |
72+
cargo test --locked --lib --tests
73+
cargo test --locked --doc
74+
75+
# Gate 4: Benchmarks - rejects benchmarks that do not compile
76+
- name: "Gate 4: cargo bench --no-run"
77+
run: cargo bench --locked --no-run
6878

69-
# Gate 4: Build - rejects code that does not compile
70-
- name: "Gate 4: cargo build"
79+
# Gate 5: Build - rejects code that does not compile
80+
- name: "Gate 5: cargo build"
7181
run: cargo build --locked
7282

73-
# Gate 5: Documentation & doc-comment format - rejects broken links, bare URLs,
83+
# Gate 6: Documentation & doc-comment format - rejects broken links, bare URLs,
7484
# invalid code blocks, and missing crate-level docs.
75-
- name: "Gate 5: cargo doc"
85+
- name: "Gate 6: cargo doc"
7686
run: cargo doc --locked --no-deps
7787
env:
7888
RUSTDOCFLAGS: >-
@@ -82,7 +92,94 @@ jobs:
8292
-D rustdoc::private_intra_doc_links
8393
-D rustdoc::unescaped_backticks
8494
85-
# Gate 6: Dependency audit - rejects vulnerable/banned/unlicensed dependencies.
95+
# Linux-only instruction-count benchmarks with gungraun.
96+
#
97+
# Gungraun executes under valgrind, so benchmark execution is unavailable on
98+
# Windows runners. Pull requests compare the PR head against a merge-base
99+
# baseline from `main` and fail on instruction regressions above the chosen
100+
# Ir limit. Pushes to `main` still run the benchmark suite as a smoke check.
101+
benchmark-regression:
102+
name: Benchmark Regression (Linux)
103+
runs-on: ubuntu-latest
104+
timeout-minutes: 30
105+
env:
106+
GUNGRAUN_SEPARATE_TARGETS: "true"
107+
steps:
108+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
109+
with:
110+
fetch-depth: 0
111+
112+
- name: Install Rust toolchain
113+
uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # 1.94.1
114+
with:
115+
toolchain: stable
116+
117+
- name: Cache Rust dependencies and build artifacts
118+
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
119+
with:
120+
cache-on-failure: true
121+
key: bench
122+
123+
- name: Install Valgrind
124+
run: |
125+
sudo apt-get update
126+
sudo apt-get install -y valgrind
127+
128+
- name: Install gungraun-runner
129+
run: |
130+
version=$(cargo metadata --format-version=1 --no-deps | python -c "import json, sys; data = json.load(sys.stdin); print(next(pkg['version'] for pkg in data['packages'] if pkg['name'] == 'gungraun'))")
131+
cargo install --locked gungraun-runner --version "$version"
132+
133+
- name: Resolve merge-base
134+
id: base
135+
if: github.event_name == 'pull_request'
136+
run: |
137+
base=$(git merge-base HEAD origin/${{ github.base_ref }})
138+
echo "sha=$base" >> "$GITHUB_OUTPUT"
139+
echo "Merge-base: $base"
140+
141+
- name: Run benchmarks on merge-base (establish baseline)
142+
if: github.event_name == 'pull_request'
143+
run: |
144+
head_sha=$(git rev-parse HEAD)
145+
git checkout --detach ${{ steps.base.outputs.sha }}
146+
cargo bench --locked --bench benchmarks -- \
147+
--save-baseline main \
148+
--callgrind-metrics=ir \
149+
--save-summary=json
150+
git checkout --detach "$head_sha"
151+
152+
- name: Run PR benchmark comparison
153+
if: github.event_name == 'pull_request'
154+
run: |
155+
cargo bench --locked --bench benchmarks -- \
156+
--baseline main \
157+
--callgrind-metrics=ir \
158+
--callgrind-limits='ir=1.0%' \
159+
--save-summary=json \
160+
| tee bench_output.txt
161+
162+
- name: Run benchmark smoke check on main pushes
163+
if: github.event_name != 'pull_request'
164+
run: |
165+
cargo bench --locked --bench benchmarks \
166+
-- \
167+
--callgrind-metrics=ir \
168+
--save-summary=json \
169+
| tee bench_output.txt
170+
171+
- name: Upload benchmark reports
172+
if: always()
173+
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
174+
with:
175+
name: benchmark-reports-${{ github.sha }}
176+
path: |
177+
bench_output.txt
178+
target/gungraun
179+
retention-days: 7
180+
if-no-files-found: warn
181+
182+
# Gate 7: Dependency audit - rejects vulnerable/banned/unlicensed dependencies.
86183
# Uses EmbarkStudios/cargo-deny-action (Docker-based, pre-built binary - no
87184
# manual install or caching needed). Advisories are split into a separate
88185
# matrix entry with continue-on-error so a sudden new advisory announcement
@@ -101,7 +198,7 @@ jobs:
101198
steps:
102199
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
103200

104-
- name: "Gate 6: cargo deny check ${{ matrix.checks }}"
201+
- name: "Gate 7: cargo deny check ${{ matrix.checks }}"
105202
uses: EmbarkStudios/cargo-deny-action@82eb9f621fbc699dd0918f3ea06864c14cc84246 # v2
106203
with:
107204
command: check ${{ matrix.checks }}

Cargo.lock

Lines changed: 99 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
name = "nanodock"
33
version = "0.1.0"
44
edition = "2024"
5+
autobenches = false
56
authors = ["Ehsan Khan"]
67
description = "Zero-dependency-light Docker/Podman daemon client for container detection, port mapping, and lifecycle control"
78
license = "MIT"
@@ -34,3 +35,12 @@ libc = "0.2"
3435

3536
[dev-dependencies]
3637
tempfile = "3"
38+
gungraun = "0.18.1"
39+
40+
[profile.bench]
41+
debug = true
42+
43+
[[bench]]
44+
name = "benchmarks"
45+
harness = false
46+
test = false

0 commit comments

Comments
 (0)