Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/criterion_compat/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,7 @@ harness = false
[[bench]]
name = "test_benches"
harness = false

[[bench]]
name = "repro_custom_main"
harness = false
30 changes: 30 additions & 0 deletions crates/criterion_compat/benches/repro_custom_main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/// Reproducer for COD-2324: URI formatting issues when users bypass criterion_group!/criterion_main!
/// and use a custom main function (like the rtmalloc project does).
use codspeed_criterion_compat::{criterion_group, BenchmarkId, Criterion};

fn bench_with_group(c: &mut Criterion) {
let mut group = c.benchmark_group("my_group");
group.bench_function("my_bench", |b| b.iter(|| 2 + 2));
group.bench_function(BenchmarkId::new("parameterized", 42), |b| b.iter(|| 2 + 2));
group.finish();
}

criterion_group!(benches, bench_with_group);

#[cfg(codspeed)]
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);
}

#[cfg(not(codspeed))]
fn main() {
// Without codspeed, just run through upstream criterion directly
let mut criterion = Criterion::default().configure_from_args();
bench_with_group(&mut criterion);
}
21 changes: 21 additions & 0 deletions crates/criterion_compat/src/compat/criterion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ impl<M: Measurement> Criterion<M> {
self.macro_group = macro_group.into();
}

#[track_caller]
pub fn bench_function<F>(&mut self, id: &str, f: F) -> &mut Criterion<M>
where
F: FnMut(&mut Bencher),
Expand All @@ -101,6 +102,7 @@ impl<M: Measurement> Criterion<M> {
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),
Expand All @@ -118,9 +120,28 @@ impl<M: Measurement> Criterion<M> {
self
}

#[track_caller]
pub fn benchmark_group<S: Into<String>>(&mut self, group_name: S) -> BenchmarkGroup<M> {
self.fill_missing_file_from_caller();
BenchmarkGroup::<M>::new(self, group_name.into())
}

/// When `current_file` wasn't set by `criterion_group!`, derive it from the caller location.
#[track_caller]
fn fill_missing_file_from_caller(&mut self) {
if !self.current_file.is_empty() {
return;
}
let caller = std::panic::Location::caller();
if let Ok(workspace_root) = std::env::var("CODSPEED_CARGO_WORKSPACE_ROOT") {
self.current_file = std::path::PathBuf::from(workspace_root)
.join(caller.file())
.to_string_lossy()
.into_owned();
} else {
self.current_file = caller.file().to_string();
}
}
}

// Dummy methods
Expand Down
26 changes: 19 additions & 7 deletions crates/criterion_compat/src/compat/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,25 @@ impl<'a, M: Measurement> BenchmarkGroup<'a, M> {
F: FnMut(&mut Bencher, &I),
I: ?Sized,
{
let git_relative_file_path = get_git_relative_path(&self.current_file);
let mut uri = format!(
"{}::{}::{}",
git_relative_file_path.to_string_lossy(),
self.macro_group,
self.group_name,
);
let mut uri = String::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.push_str(&file_str);
}
}
if !self.macro_group.is_empty() {
if !uri.is_empty() {
uri.push_str("::");
}
uri.push_str(&self.macro_group);
}
if !uri.is_empty() {
uri.push_str("::");
}
uri.push_str(&self.group_name);
if let Some(function_name) = id.function_name {
uri = format!("{uri}::{function_name}");
}
Expand Down
Loading