You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(ci): stop the benchmark suite starving CI and publishing partial numbers
Three open issues on 2.4.0 turned out to be one lane: nothing rationed the
most expensive workflow in the repository.
Runs accumulated. benchmarks.yml declared no concurrency group, so five
pushes over one review loop created five uncancelled eight-shard runs and
left CI and Coverage queued for ~50 minutes behind numbers nobody would
read. The workflow now supersedes its own in-flight run, keyed on the PR
number; the main path is keyed on the commit SHA instead, so every commit
is its own group, cancel-in-progress can never discard one, and the
published series keeps every point. Closes#319.
Runs overlapped. With three branches in flight every shard measured
1.75-2.0x its baseline and one hit the 120-minute cap - on two pull
requests whose diffs were XML doc comments only. The quiet failure is the
worse one: a shard that finishes under uneven contention still publishes
its skewed delta. scripts/benchmark_relevant_changes.js now gates the PR
path and does not run the suite when the diff cannot move a number. It is
one-directional by construction (only documentation, the three projects
Celerity.Benchmarks.csproj does not reference, and .cs files whose text is
unchanged once comments are stripped can be skipped) and never applies to
main, so a gate mistake costs a missing PR comment rather than an unseen
regression. It correctly skips both pull requests the issue names and runs
on every code change it was tested against.
The issue's own first choice - a global serialize-everything concurrency
group - was deliberately not taken: GitHub queues at most one pending run
per group and cancels the older pending one, so serializing would silently
drop runs. What ships is its option 2, which it rated cheapest and most
obviously correct. Closes#335.
The two sides of the A/B packed from different class lists. Greedy
bin-packing is a function of the whole list and the PR head has a class
main does not, so shard i was not the same slice on both sides and could
pair a light head slice with a heavy base one. The base now replays the
class list the head resolved, which makes it a subset of the head by
construction: the pair is bounded by twice the head slice, the quantity
the packer already balances. Option 4 of that issue ships alongside - a
report missing a shard says so above the fold, since a partial comparison
previously read exactly like a complete one. Closes#300.
The comment-stripping rests on a real C# scanner rather than a //-prefix
test, because // occurs inside literals and the verbatim / interpolated /
raw forms desynchronise a guess; a --self-test pins it in a new
benchmark-gate job. --shard-dry-run resolves a shard's class list without
measuring, so the packing is inspectable without a multi-hour run.
# Name the shards that did not report before anything else. `if: always()` means
228
+
# this job runs on a partial matrix, and the merged report is then legitimately
229
+
# missing whole benchmark classes — including, on the PR that motivated this,
230
+
# part of the new collection's own numbers. Nothing downstream could tell.
231
+
missing=""
232
+
for s in $(seq 0 $((SHARD_TOTAL - 1))); do
233
+
if [ ! -f "/tmp/reports/head-shard-${s}.json" ]; then
234
+
missing="${missing}${missing:+, }${s}"
235
+
fi
236
+
done
237
+
if [ -n "$missing" ]; then
238
+
echo "::warning title=Incomplete benchmark report::Shard(s) ${missing} produced no report; the comparison below is missing every benchmark class packed onto them."
Copy file name to clipboardExpand all lines: CHANGELOG.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -24,9 +24,15 @@ All notable changes to Celerity are documented here. This project follows [Keep
24
24
-`scripts/check_doc_anchors.js` — a CI guard that resolves every anchor link and relative file link across all tracked markdown, so a link that scrolls nowhere fails the build instead of shipping. Closes [#339](https://github.com/marius-bughiu/Celerity/issues/339).
25
25
- A `--self-test` mode on that script, pinning the heading-slug rule against ids GitHub actually rendered, and a `doc-anchors` job in `ci.yml` that runs both modes on every PR. Closes [#339](https://github.com/marius-bughiu/Celerity/issues/339).
26
26
- A "Documentation links" section in `CONTRIBUTING.md` covering the slug rule and how to look an anchor up rather than guess it. Closes [#339](https://github.com/marius-bughiu/Celerity/issues/339).
27
+
-`scripts/benchmark_relevant_changes.js` — a gate that skips the sharded benchmark run on a pull request whose diff cannot move a measured number: documentation, the test / fuzz / AOT-smoke projects, or comments inside `.cs` files. It is one-directional (anything it cannot prove inert runs the suite) and never applies to `main`, so a wrong answer costs a PR comment rather than an unmeasured regression. A `--self-test` mode pins its C# comment-stripping lexer, run by a new `benchmark-gate` job in `ci.yml`. Closes [#335](https://github.com/marius-bughiu/Celerity/issues/335).
28
+
- A `--shard-dry-run` switch on the benchmarks runner that resolves a shard's class list and stops, so the packing can be inspected without a multi-hour measuring run. Closes [#300](https://github.com/marius-bughiu/Celerity/issues/300).
27
29
28
30
### Fixed
29
31
32
+
- Pushing to a pull request no longer stacks another eight-runner benchmark matrix behind the last — the workflow supersedes its own in-flight run. Five pushes over one review loop had left `CI` and `Coverage`, the checks that actually gate correctness, queued for ~50 minutes behind perf numbers nobody would read. Pushes to `main` are keyed per commit instead, so none is ever cancelled and the published history keeps every point. Closes [#319](https://github.com/marius-bughiu/Celerity/issues/319).
33
+
- A benchmark shard no longer times out on a pull request that adds a benchmark class. The `main` base now replays the class list the PR head resolved rather than bin-packing its own, so shard *i* is the same slice on both sides and a job can no longer pair a light head slice with a heavy base one. Closes [#300](https://github.com/marius-bughiu/Celerity/issues/300).
34
+
- A benchmark comparison that is missing a shard now says so above the fold in the PR comment and as a workflow warning. Previously a partial report was indistinguishable from a complete one — the tables were simply shorter. Closes [#300](https://github.com/marius-bughiu/Celerity/issues/300).
35
+
30
36
-`PartialSort.TopK` now throws `ArgumentException` when its `destination` overlaps its `source`, instead of silently returning a wrong answer and writing to the source it documents as untouched. Disjoint slices of one array are still accepted, matching `RadixSort` and `CountingSort`.
31
37
- Eight documentation links pointed at anchors that do not exist: seven `CeleritySet` / `SwissSet` references in `docs/api/collections.md` and one in `CHANGELOG.md`. GitHub deletes `<`, `>` and `,` from a heading without substituting a separator, so `CeleritySet<T, THasher>` anchors as `#celeritysett-thasher`, not the `#celerityset-t-thasher` everyone writes. Closes [#339](https://github.com/marius-bughiu/Celerity/issues/339).
Copy file name to clipboardExpand all lines: CONTRIBUTING.md
+7-1Lines changed: 7 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -82,9 +82,15 @@ dotnet run -c Release -- --filter '*' # run everything with the default (slow, h
82
82
83
83
Results are parsed by [`benchmark-action/github-action-benchmark`](https://github.com/benchmark-action/github-action-benchmark) and:
84
84
85
-
-**On a PR**: a comment is posted with the same-runner A/B comparison vs `main`. Rows that move by more than ±10% *and* beyond the combined standard deviation of both measurements are flagged; the flags are advisory, so a noisy row does not fail the job.
85
+
-**On a PR**: a comment is posted with the same-runner A/B comparison vs `main`. Rows that move by more than ±10% *and* beyond the combined standard deviation of both measurements are flagged; the flags are advisory, so a noisy row does not fail the job. If any shard failed to report, the comment says so above the fold — a partial comparison is otherwise indistinguishable from a clean one.
86
86
-**On a push to `main`**: the new measurement is appended to the `gh-pages`-stored history powering the dashboard at <https://marius-bughiu.github.io/Celerity/dev/bench/>.
87
87
88
+
Three things about the run are worth knowing before you wonder why it did or did not happen:
89
+
90
+
-**It supersedes itself.** Pushing to a PR cancels that PR's in-flight benchmark run rather than stacking another eight-runner matrix behind it; only the newest numbers are ever read. Pushes to `main` are keyed per commit instead, so none is ever cancelled and the published history has no gaps.
91
+
-**It is skipped when the diff cannot move a number.**[`scripts/benchmark_relevant_changes.js`](scripts/benchmark_relevant_changes.js) gates the PR path: a diff that touches only documentation, only the test / fuzz / AOT-smoke projects, or only comments inside `.cs` files does not buy a three-hour A/B run. The gate is one-directional — anything it cannot prove inert (an added or deleted file, a `.csproj`, a git command that fails) runs the suite — and it never applies to `main`, so a wrongly-skipped PR is still measured on merge. Run it yourself with `node scripts/benchmark_relevant_changes.js <base> <head>`.
92
+
-**Shard *i* means the same slice on both sides.** The base run replays the class list the head resolved instead of packing its own. Shard membership comes from bin-packing over the benchmark class list, so a PR that *adds* a benchmark class would otherwise pack the two sides differently and could pair a light head slice with a heavy base one.
93
+
88
94
If a change is motivated by performance, include before/after numbers from a local Release run in the PR description — the CI job is a guardrail, not a precision instrument. Numbers without `-c Release` are not useful — BenchmarkDotNet refuses to run in Debug.
0 commit comments