Skip to content

Commit 7802d9a

Browse files
feat: add support for args divan macro argument
1 parent f6cc073 commit 7802d9a

File tree

11 files changed

+696
-0
lines changed

11 files changed

+696
-0
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "codspeed-divan-compat-examples"
3+
version = "0.0.0"
4+
edition = "2021"
5+
description = "Examples for Divan, a comfy benchmarking framework."
6+
publish = false
7+
license = "MIT OR Apache-2.0"
8+
9+
[dependencies]
10+
fastrand = "2.3.0"
11+
divan = { package = "codspeed-divan-compat", version = "*", path = ".." }
12+
13+
[[bench]]
14+
name = "math"
15+
harness = false
16+
17+
[[bench]]
18+
name = "sort"
19+
harness = false
20+
21+
[[bench]]
22+
name = "time"
23+
harness = false
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Example benchmarks
2+
3+
Mostly copied from [divan's examples](https://github.com/nvzqz/divan/tree/main/examples).
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use divan::black_box;
2+
use std::collections::{BTreeMap, HashMap};
3+
4+
fn main() {
5+
divan::main();
6+
}
7+
8+
#[divan::bench]
9+
fn add() -> i32 {
10+
black_box(2) + black_box(1)
11+
}
12+
13+
#[divan::bench]
14+
#[ignore]
15+
fn sub() -> i32 {
16+
black_box(2) - black_box(1)
17+
}
18+
19+
#[divan::bench]
20+
fn mul() -> i32 {
21+
black_box(2) * black_box(1)
22+
}
23+
24+
#[divan::bench]
25+
fn div() -> i32 {
26+
black_box(2) / black_box(1)
27+
}
28+
29+
#[divan::bench]
30+
fn rem() -> i32 {
31+
black_box(2) % black_box(1)
32+
}
33+
34+
// 1, 1, 2, 3, 5, ...
35+
mod fibonacci {
36+
use super::*;
37+
38+
const VALUES: &[u64] = &[0, 5, 10, 20, 30];
39+
40+
// O(n)
41+
#[divan::bench(args = VALUES)]
42+
fn iterative(n: u64) -> u64 {
43+
let mut previous = 1;
44+
let mut current = 1;
45+
46+
for _ in 2..=n {
47+
let next = previous + current;
48+
previous = current;
49+
current = next;
50+
}
51+
52+
current
53+
}
54+
55+
// O(2^n)
56+
#[divan::bench(args = VALUES, max_time = 1)]
57+
fn recursive(n: u64) -> u64 {
58+
if n <= 1 {
59+
1
60+
} else {
61+
recursive(n - 2) + recursive(n - 1)
62+
}
63+
}
64+
65+
#[allow(dead_code)]
66+
trait Map: Default {
67+
fn get(&self, key: u64) -> Option<u64>;
68+
fn set(&mut self, key: u64, value: u64);
69+
}
70+
71+
impl Map for HashMap<u64, u64> {
72+
fn get(&self, key: u64) -> Option<u64> {
73+
self.get(&key).copied()
74+
}
75+
76+
fn set(&mut self, key: u64, value: u64) {
77+
self.insert(key, value);
78+
}
79+
}
80+
81+
impl Map for BTreeMap<u64, u64> {
82+
fn get(&self, key: u64) -> Option<u64> {
83+
self.get(&key).copied()
84+
}
85+
86+
fn set(&mut self, key: u64, value: u64) {
87+
self.insert(key, value);
88+
}
89+
}
90+
91+
// Will be ignored in instrumented mode as we do not support type generics yet
92+
// O(n)
93+
#[cfg(not(codspeed))]
94+
#[divan::bench(
95+
types = [BTreeMap<u64, u64>, HashMap<u64, u64>],
96+
args = VALUES,
97+
)]
98+
fn recursive_memoized<M: Map>(n: u64) -> u64 {
99+
fn fibonacci<M: Map>(n: u64, cache: &mut M) -> u64 {
100+
if let Some(result) = cache.get(n) {
101+
return result;
102+
}
103+
104+
if n <= 1 {
105+
return 1;
106+
}
107+
108+
let result = fibonacci(n - 2, cache) + fibonacci(n - 1, cache);
109+
cache.set(n, result);
110+
result
111+
}
112+
113+
fibonacci(n, &mut M::default())
114+
}
115+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use divan::{AllocProfiler, Bencher};
2+
3+
#[global_allocator]
4+
static ALLOC: AllocProfiler = AllocProfiler::system();
5+
6+
fn main() {
7+
divan::main();
8+
}
9+
10+
/// Functions that generate deterministic values.
11+
mod gen {
12+
pub const LEN: usize = 100_000;
13+
14+
pub fn rand_int_generator() -> impl FnMut() -> i32 {
15+
let mut rng = fastrand::Rng::with_seed(42);
16+
move || rng.i32(..)
17+
}
18+
19+
pub fn rand_int_vec_generator() -> impl FnMut() -> Vec<i32> {
20+
let mut rand_int_generator = rand_int_generator();
21+
move || (0..LEN).map(|_| rand_int_generator()).collect()
22+
}
23+
24+
pub fn sorted_int_vec_generator() -> impl FnMut() -> Vec<i32> {
25+
move || (0..LEN).map(|i| i as i32).collect()
26+
}
27+
}
28+
29+
mod random {
30+
use super::*;
31+
32+
#[divan::bench]
33+
fn sort(bencher: Bencher) {
34+
bencher
35+
.with_inputs(gen::rand_int_vec_generator())
36+
.bench_local_refs(|v| v.sort());
37+
}
38+
39+
#[divan::bench]
40+
fn sort_unstable(bencher: Bencher) {
41+
bencher
42+
.with_inputs(gen::rand_int_vec_generator())
43+
.bench_local_refs(|v| v.sort_unstable());
44+
}
45+
}
46+
47+
mod sorted {
48+
use super::*;
49+
50+
#[divan::bench]
51+
fn sort(bencher: Bencher) {
52+
bencher
53+
.with_inputs(gen::sorted_int_vec_generator())
54+
.bench_local_refs(|v| v.sort());
55+
}
56+
57+
#[divan::bench]
58+
fn sort_unstable(bencher: Bencher) {
59+
bencher
60+
.with_inputs(gen::sorted_int_vec_generator())
61+
.bench_local_refs(|v| v.sort_unstable());
62+
}
63+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
use std::time::{Instant, SystemTime};
2+
3+
use divan::{AllocProfiler, Bencher};
4+
5+
#[global_allocator]
6+
static ALLOC: AllocProfiler = AllocProfiler::system();
7+
8+
fn main() {
9+
divan::main();
10+
}
11+
12+
mod now {
13+
use super::*;
14+
15+
#[divan::bench]
16+
fn instant() -> Instant {
17+
Instant::now()
18+
}
19+
20+
#[divan::bench]
21+
fn system_time() -> SystemTime {
22+
SystemTime::now()
23+
}
24+
25+
#[divan::bench(name = if cfg!(target_arch = "aarch64") {
26+
"tsc (aarch64)"
27+
} else {
28+
"tsc (x86)"
29+
})]
30+
#[cfg(all(
31+
not(miri),
32+
any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64"),
33+
))]
34+
pub fn tsc() -> u64 {
35+
#[cfg(target_arch = "aarch64")]
36+
unsafe {
37+
let timestamp: u64;
38+
std::arch::asm!(
39+
"mrs {}, cntvct_el0",
40+
out(reg) timestamp,
41+
// Leave off `nomem` because this should be a compiler fence.
42+
options(nostack, preserves_flags),
43+
);
44+
timestamp
45+
}
46+
47+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
48+
unsafe {
49+
#[cfg(target_arch = "x86")]
50+
use std::arch::x86;
51+
#[cfg(target_arch = "x86_64")]
52+
use std::arch::x86_64 as x86;
53+
54+
x86::_rdtsc()
55+
}
56+
}
57+
}
58+
59+
mod duration_since {
60+
use super::*;
61+
62+
#[divan::bench]
63+
fn instant(bencher: Bencher) {
64+
bencher
65+
.with_inputs(|| [Instant::now(), Instant::now()])
66+
.bench_values(|[start, end]| end.duration_since(start));
67+
}
68+
69+
#[divan::bench]
70+
fn system_time(bencher: Bencher) {
71+
bencher
72+
.with_inputs(|| [SystemTime::now(), SystemTime::now()])
73+
.bench_values(|[start, end]| end.duration_since(start));
74+
}
75+
76+
#[divan::bench(name = if cfg!(target_arch = "aarch64") {
77+
"tsc (aarch64)"
78+
} else {
79+
"tsc (x86)"
80+
})]
81+
#[cfg(all(
82+
not(miri),
83+
any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64"),
84+
))]
85+
fn tsc(bencher: Bencher) {
86+
bencher
87+
.with_inputs(|| [crate::now::tsc(), crate::now::tsc()])
88+
.bench_values(|[start, end]| {
89+
// Simply subtract because an optimized timing implementation
90+
// would want to keep the value as TSC units for as long as
91+
// possible before dividing by the TSC frequency.
92+
//
93+
// Saturating arithmetic to ensures monotonicity.
94+
end.saturating_sub(start)
95+
})
96+
}
97+
}

crates/divan_compat/examples/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+
}

0 commit comments

Comments
 (0)