fix(criterion-compat): fix URI formatting when criterion_group!/criterion_main! are bypassed#169
Conversation
…rion_main! are bypassed
There was a problem hiding this comment.
Pull request overview
Fixes CodSpeed Criterion-compat benchmark URI construction when users bypass criterion_group! / criterion_main! (e.g., custom main), ensuring URIs don’t include empty segments and that current_file is derived from the callsite when missing.
Changes:
- Build benchmark URIs from non-empty components (file / macro group / group name / function) to avoid malformed
::sequences. - Derive
current_filefrom#[track_caller]callsite whencriterion_group!didn’t set it. - Add a new bench reproducer for the “custom main” scenario and register it in
Cargo.toml.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| crates/criterion_compat/src/compat/group.rs | Makes URI formatting robust to missing file and/or macro group components. |
| crates/criterion_compat/src/compat/criterion.rs | Adds callsite-based fallback to populate current_file when macros aren’t used. |
| crates/criterion_compat/benches/repro_custom_main.rs | Adds a reproducer bench for bypassing criterion_group!/criterion_main!. |
| crates/criterion_compat/Cargo.toml | Registers the new repro_custom_main bench target. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| let mut uri_parts: Vec<String> = Vec::new(); | ||
|
|
||
| if !self.current_file.is_empty() { | ||
| let git_relative_file_path = get_git_relative_path(&self.current_file); | ||
| let file_str = git_relative_file_path.to_string_lossy(); | ||
| if !file_str.is_empty() { | ||
| uri_parts.push(file_str.into_owned()); | ||
| } | ||
| } | ||
| if !self.macro_group.is_empty() { | ||
| uri_parts.push(self.macro_group.clone()); | ||
| } | ||
| uri_parts.push(self.group_name.clone()); | ||
|
|
||
| let mut uri = uri_parts.join("::"); |
| #[track_caller] | ||
| pub fn bench_function<F>(&mut self, id: &str, f: F) -> &mut Criterion<M> | ||
| where | ||
| F: FnMut(&mut Bencher), | ||
| { | ||
| self.fill_missing_file_from_caller(); | ||
| self.benchmark_group(id) | ||
| .bench_function(BenchmarkId::no_function(), f); | ||
| self | ||
| } | ||
|
|
||
| #[track_caller] | ||
| pub fn bench_with_input<F, I>(&mut self, id: BenchmarkId, input: &I, f: F) -> &mut Criterion<M> | ||
| where | ||
| F: FnMut(&mut Bencher, &I), | ||
| { | ||
| self.fill_missing_file_from_caller(); | ||
| let group_name = id.function_name.expect( |
| fn main() { | ||
| // Pattern A: Using new_instrumented() but calling bench functions directly (not through criterion_group!) | ||
| let mut criterion = Criterion::new_instrumented(); | ||
| bench_with_group(&mut criterion); | ||
|
|
||
| // Pattern B: Calling through criterion_group!-generated function (should work correctly) | ||
| let mut criterion2 = Criterion::new_instrumented(); | ||
| benches(&mut criterion2); |
Merging this PR will improve performance by ×3.2
Performance Changes
Comparing Footnotes
|
No description provided.