Skip to content

Commit 215028a

Browse files
feat(divan_compat): add divan_compat initial implementation
1 parent 5d59eba commit 215028a

File tree

14 files changed

+459
-6
lines changed

14 files changed

+459
-6
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@ members = [
44
"crates/bencher_compat",
55
"crates/criterion_compat",
66
"crates/cargo-codspeed",
7+
"crates/divan_compat",
8+
"crates/divan_compat/macros",
79
]
810
resolver = "2"

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ This mono-repo contains the integration crates for using CodSpeed in Rust:
1313
- [`cargo-codspeed`](./crates/cargo-codspeed/): A cargo subcommand for running CodSpeed on your project
1414
- [`codspeed-criterion-compat`](./crates/criterion_compat/): Criterion.rs compatibility layer for CodSpeed
1515
- [`codspeed-bencher-compat`](./crates/bencher_compat/): Bencher compatibility layer for CodSpeed
16+
- [`codspeed-divan-compat`](./crates/divan_compat/): Divan compatibility layer for CodSpeed
1617
- [`codspeed`](./crates/codspeed/): The core library used to integrate with Codspeed runners

crates/divan_compat/Cargo.toml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[package]
2+
name = "codspeed-divan-compat"
3+
version = "2.7.2"
4+
rust-version = "1.74" # MSRV TODO: Check versioning
5+
edition = "2021"
6+
description = "Bencher compatibility layer for CodSpeed"
7+
authors = ["Arthur Pastel <[email protected]>"]
8+
documentation = "https://docs.codspeed.io"
9+
readme = "README.md"
10+
repository = "https://github.com/CodSpeedHQ/codspeed-rust"
11+
homepage = "https://codspeed.io"
12+
license = "MIT OR Apache-2.0"
13+
categories = [
14+
"development-tools",
15+
"development-tools::profiling",
16+
"development-tools::testing",
17+
]
18+
keywords = ["codspeed", "benchmark", "divan"]
19+
20+
[dependencies]
21+
codspeed = { path = "../codspeed", version = "=2.7.2" }
22+
divan = "0.1.17"
23+
codspeed-divan-compat-macros = { version = "=2.7.2", path = './macros' }
24+
25+
[[bench]]
26+
name = "basic_example"
27+
harness = false

crates/divan_compat/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
TODO
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// use codspeed_divan_compat as divan;
2+
3+
fn fibo(n: i32) -> i32 {
4+
let mut a = 0;
5+
let mut b = 1;
6+
7+
for _ in 0..n {
8+
let tmp = a;
9+
a = b;
10+
b += tmp;
11+
}
12+
13+
a
14+
}
15+
16+
#[divan::bench]
17+
fn fibo_500() -> i32 {
18+
// divan::black_box(fibo(500))
19+
fibo(500)
20+
}
21+
22+
#[divan::bench]
23+
fn fibo_100() -> i32 {
24+
divan::black_box(fibo(10))
25+
}
26+
27+
fn main() {
28+
// Run `add` benchmark:
29+
divan::main();
30+
}

crates/divan_compat/build.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
println!("cargo:rustc-check-cfg=cfg(codspeed)");
3+
}

crates/divan_compat/macros/Cargo.toml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[package]
2+
name = "codspeed-divan-compat-macros"
3+
version = "2.7.2"
4+
rust-version = "1.74" # MSRV TODO: Check versioning
5+
edition = "2021"
6+
description = "Bencher compatibility layer for CodSpeed"
7+
authors = ["Arthur Pastel <[email protected]>"]
8+
documentation = "https://docs.codspeed.io"
9+
readme = "../README.md"
10+
repository = "https://github.com/CodSpeedHQ/codspeed-rust"
11+
homepage = "https://codspeed.io"
12+
license = "MIT OR Apache-2.0"
13+
categories = [
14+
"development-tools",
15+
"development-tools::profiling",
16+
"development-tools::testing",
17+
]
18+
keywords = ["codspeed", "benchmark", "divan"]
19+
20+
[lib]
21+
proc-macro = true
22+
23+
[dependencies]
24+
divan-macros = { version = "=0.1.17" }
25+
proc-macro2 = "1"
26+
quote = { version = "1", default-features = false }
27+
# Versions prior to *.18 fail to parse empty attribute metadata.
28+
syn = { version = "^2.0.18", default-features = false, features = ["full", "clone-impls", "parsing", "printing", "proc-macro"] }

crates/divan_compat/macros/src/lib.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use proc_macro::TokenStream;
2+
use quote::quote;
3+
use syn::{
4+
parse::Parse, parse_macro_input, punctuated::Punctuated, ItemFn, Meta, MetaNameValue, Token,
5+
};
6+
7+
struct MyBenchArgs {
8+
args: Punctuated<Meta, Token![,]>,
9+
}
10+
11+
impl Parse for MyBenchArgs {
12+
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
13+
Ok(Self {
14+
args: Punctuated::parse_terminated(input)?,
15+
})
16+
}
17+
}
18+
19+
#[proc_macro_attribute]
20+
pub fn bench_compat(attr: TokenStream, item: TokenStream) -> TokenStream {
21+
let parsed_args = parse_macro_input!(attr as MyBenchArgs);
22+
let input = parse_macro_input!(item as ItemFn);
23+
24+
let mut filtered_args = Vec::new();
25+
26+
for arg in parsed_args.args {
27+
match &arg {
28+
Meta::NameValue(MetaNameValue { path, .. }) if path.is_ident("crate") => {
29+
return quote! {
30+
compile_error!("crate argument is not supported with codspeed_divan_compat");
31+
}
32+
.into();
33+
}
34+
_ => filtered_args.push(arg),
35+
}
36+
}
37+
38+
filtered_args.push(syn::parse_quote!(crate = ::codspeed_divan_compat));
39+
40+
// Important: keep macro name in sync with re-exported macro name in divan-compat lib
41+
let expanded = quote! {
42+
#[::codspeed_divan_compat::bench_original(#(#filtered_args),*)]
43+
#input
44+
};
45+
46+
TokenStream::from(expanded)
47+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//! Handpicked stubs from [divan::entry](https://github.com/nvzqz/divan/blob/main/src/entry/mod.rs)
2+
//! Minimally reimplemented in an API compatible way to run the benches using codspeed intrumentation
3+
use codspeed::codspeed::CodSpeed;
4+
use std::{cell::RefCell, rc::Rc};
5+
6+
/// Benchmarking options set directly by the user in `#[divan::bench]` and
7+
/// `#[divan::bench_group]`.
8+
///
9+
/// Changes to fields must be reflected in the "Options" sections of the docs
10+
/// for `#[divan::bench]` and `#[divan::bench_group]`.
11+
#[derive(Default)]
12+
pub struct BenchOptions<'a> {
13+
pub(crate) _marker: std::marker::PhantomData<&'a ()>,
14+
}
15+
16+
pub struct Bencher<'a, 'b> {
17+
pub(crate) codspeed: Rc<RefCell<CodSpeed>>,
18+
pub(crate) uri: String,
19+
pub(crate) _marker: std::marker::PhantomData<&'a &'b ()>,
20+
}
21+
22+
#[allow(clippy::needless_lifetimes)]
23+
impl<'a, 'b> Bencher<'a, 'b> {
24+
pub(crate) fn new(uri: String) -> Self {
25+
Self {
26+
codspeed: Rc::new(RefCell::new(CodSpeed::new())),
27+
uri,
28+
_marker: std::marker::PhantomData,
29+
}
30+
}
31+
}
32+
33+
#[allow(clippy::needless_lifetimes)]
34+
impl<'a, 'b> Bencher<'a, 'b> {
35+
pub fn bench<O, B>(&self, benched: B)
36+
where
37+
B: Fn() -> O + Sync,
38+
{
39+
let mut codspeed = self.codspeed.borrow_mut();
40+
codspeed.start_benchmark(self.uri.as_str());
41+
divan::black_box(benched());
42+
codspeed.end_benchmark();
43+
}
44+
}

0 commit comments

Comments
 (0)