Skip to content

Benchmark workflow improvements#513

Merged
michelle-clayton-work merged 4 commits into
mainfrom
dev/mclayton/benchcheck-variance-detection
Jul 6, 2026
Merged

Benchmark workflow improvements#513
michelle-clayton-work merged 4 commits into
mainfrom
dev/mclayton/benchcheck-variance-detection

Conversation

@michelle-clayton-work

@michelle-clayton-work michelle-clayton-work commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Compare the least-performant base against the best-performing head using the confidence-interval bounds instead of the medians, so a regression is only flagged when the intervals do not overlap. Surface each sample's confidence-interval spread in the report so reviewers can see how noisy a benchmark is.

Also fail 'benchcheck report' on genuine result-file read errors instead of silently returning empty content.

Compare the least-performant base against the best-performing head using the confidence-interval bounds instead of the medians, so a regression is only flagged when the intervals do not overlap. Surface each sample's confidence-interval spread in the report so reviewers can see how noisy a benchmark is.

Also fail 'benchcheck report' on genuine result-file read errors instead of silently returning empty content.
Copilot AI review requested due to automatic review settings July 1, 2026 20:19
@michelle-clayton-work michelle-clayton-work requested a review from a team as a code owner July 1, 2026 20:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the benchcheck benchmark workflow by making regression detection more variance-robust (using confidence-interval bounds to avoid flagging noisy overlaps) and by treating genuine result-file read failures in benchcheck report as fatal errors rather than silently swallowing them.

Changes:

  • Update regression detection to compare base upper CI vs head lower CI and carry CI spread metadata into regression output.
  • Make benchcheck report propagate real read errors (while still treating missing optional files as non-errors).
  • Add targeted tests for the new file-reading behavior and the variance-robust regression logic.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
cmd/benchcheck/check.go Switch regression comparison to CI-bound overlap logic and include CI spread strings in regression output.
cmd/benchcheck/report.go Change helper readers to return errors and fail report on genuine read errors (while allowing missing files).
cmd/benchcheck/report_test.go Add unit tests validating missing-vs-genuine read error behavior for report helpers.
cmd/benchcheck/main_test.go Add regression tests covering overlapping vs separated distributions and ensuring spread strings are populated.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cmd/benchcheck/check.go
Comment thread cmd/benchcheck/check.go Outdated
@michelle-clayton-work

Copy link
Copy Markdown
Contributor Author

@copilot address PR feedback

Copilot AI commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

@copilot address PR feedback

Done in the latest commit. Both issues addressed in cmd/benchcheck/check.go:

  • Dropped the hardcoded ± prefix from the regression output format strings so the spread values from PctRangeString() (e.g. "3%") render cleanly as base 3%, head 3%.
  • Updated the BaseSpread/HeadSpread struct comments from e.g. "±3%" to e.g. "3%" to accurately reflect what PctRangeString() stores.

@dagood

dagood commented Jul 1, 2026

Copy link
Copy Markdown
Member

Do you have an example of this running, for broad context?

@dagood dagood left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on missing files.

Comment thread cmd/benchcheck/report.go Outdated
Comment thread cmd/benchcheck/report.go Outdated
Comment thread cmd/benchcheck/report.go Outdated
Comment on lines +127 to +129
// A missing result file is expected (a job may not produce one); a genuine
// read error is not, and must fail the report rather than be swallowed.
if readErr != nil {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Higher-level question: is it really a good design to intentionally be missing files? Could the system be set up to always create the expected file set, e.g. create an empty failures.txt file if there are no failures?

From a human side, it's simpler IMO to always create the files: an intentionally written empty file is more convincing than a file not existing. Also, does this process delete an existing failures.txt file if there are no failures, or does it leave it alone? You could end up thinking that you have errors even if you don't in that case. Always writing the file avoids that question and potential quirk of using deletion APIs rather than file-write APIs in some cases.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So in check.go it already always writes regressions.txt/failures.txt unconditionally, and the workflow pre-seeds status.json to benchmark_error:true. So empty files are the norm and nothing gets deleted. The only case where a file is genuinely absent is a job that crashes before check runs — which the pre-seeded status.json already reports as an error. The tolerant read just keeps report from failing on a partial/aborted artifact upload rather than being a design that relies on absence.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tolerant read just keeps report from failing on a partial/aborted artifact upload

Hmm, well, when would that happen? Why is it desirable to treat a partial/aborted artifact upload this way?

It's good that it doesn't rely on file absence, but that just means I'm not seeing a reason remaining to handle missing files in a special way rather than fail.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Commenting on this as part of a review to make it more obvious.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right — the partial-upload rationale doesn't really hold up. I guess the only genuine reason report tolerated a missing .txt was the case where the workflow pre-seeds status.json to benchmark_error:true, but check is what writes the other two, so if a job died before check ran they'd be absent while report still had to render the error comment.

I changed it so that with absence no longer a normal state, report now reads those two files strictly — a missing file is a hard error — via a new readTrimmedFile. The tolerant readTrimmedContentIfExists stays only for the optional -job-urls input, whose absence really does just mean "not provided".

@michelle-clayton-work

Copy link
Copy Markdown
Contributor Author

Do you have an example of this running, for broad context?

Yes sorry forgot to link microsoft/go-crypto-winnative#187

@dagood dagood left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, up to you if it makes sense to do anything now/later about the nonexistent file handling.

Rename readFileContent to readTrimmedContentIfExists and loadJobURLs to readJobURLsFileIfExists so the names convey that a missing file is tolerated. readJobURLsFileIfExists now reuses readTrimmedContentIfExists for the read/trim/not-exist handling.
@dagood dagood added the release-on-merge Triggers an automated release when this PR is merged label Jul 6, 2026

@dagood dagood left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still looks fine to me, just not sure the missing file handling approach makes sense.

Comment thread cmd/benchcheck/report.go Outdated
Comment on lines +127 to +129
// A missing result file is expected (a job may not produce one); a genuine
// read error is not, and must fail the report rather than be swallowed.
if readErr != nil {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Commenting on this as part of a review to make it more obvious.)

The bench job now seeds empty failures.txt and regressions.txt alongside status.json, so every uploaded artifact has the full result set even if the job dies before benchcheck runs. report now reads those files strictly (a missing file is a hard error) via a new readTrimmedFile helper, while the optional job-URLs input keeps using the tolerant readTrimmedContentIfExists.
@michelle-clayton-work michelle-clayton-work merged commit 7808155 into main Jul 6, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-on-merge Triggers an automated release when this PR is merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants