Skip to content

Commit 41b6e07

Browse files
committed
refactor: a more friendly dynamic_dispatch bench
Signed-off-by: xiaguan <[email protected]>
1 parent 6b820fa commit 41b6e07

File tree

3 files changed

+73
-94
lines changed

3 files changed

+73
-94
lines changed

foyer-memory/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ tokio = { workspace = true }
3030
[dev-dependencies]
3131
bytesize = "1"
3232
clap = { version = "4", features = ["derive"] }
33+
criterion = "0.5.1"
3334
hdrhistogram = "7"
3435
moka = { version = "0", features = ["sync"] }
3536
rand = "0.8"

foyer-memory/benches/bench_dynamic_dispatch.rs

+67-92
Original file line numberDiff line numberDiff line change
@@ -12,110 +12,85 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use std::{
16-
sync::Arc,
17-
time::{Duration, Instant},
18-
};
19-
20-
use rand::{distributions::Alphanumeric, thread_rng, Rng};
21-
22-
struct T<F>
23-
where
24-
F: Fn(&str) -> usize,
25-
{
26-
f1: F,
27-
f2: Box<dyn Fn(&str) -> usize>,
28-
f3: Arc<dyn Fn(&str) -> usize>,
15+
use criterion::{criterion_group, criterion_main, Criterion};
16+
use std::sync::Arc;
17+
18+
pub trait Processor {
19+
fn process(&self) -> usize;
2920
}
3021

31-
fn rand_string(len: usize) -> String {
32-
thread_rng()
33-
.sample_iter(&Alphanumeric)
34-
.take(len)
35-
.map(char::from)
36-
.collect()
22+
pub struct SimpleProcessor {
23+
data: usize,
3724
}
3825

39-
fn bench_static_dispatch<F>(t: &T<F>, loops: usize) -> Duration
40-
where
41-
F: Fn(&str) -> usize,
42-
{
43-
let mut dur = Duration::default();
44-
for _ in 0..loops {
45-
let s = rand_string(thread_rng().gen_range(0..100));
46-
let now = Instant::now();
47-
let _ = (t.f1)(&s);
48-
dur += now.elapsed();
26+
impl SimpleProcessor {
27+
pub fn new(data: usize) -> Self {
28+
SimpleProcessor { data }
4929
}
50-
Duration::from_nanos((dur.as_nanos() as usize / loops) as _)
5130
}
5231

53-
fn bench_box_dynamic_dispatch<F>(t: &T<F>, loops: usize) -> Duration
54-
where
55-
F: Fn(&str) -> usize,
56-
{
57-
let mut dur = Duration::default();
58-
for _ in 0..loops {
59-
let s = rand_string(thread_rng().gen_range(0..100));
60-
let now = Instant::now();
61-
let _ = (t.f3)(&s);
62-
dur += now.elapsed();
32+
impl Processor for SimpleProcessor {
33+
fn process(&self) -> usize {
34+
self.data * self.data
6335
}
64-
Duration::from_nanos((dur.as_nanos() as usize / loops) as _)
6536
}
6637

67-
fn bench_arc_dynamic_dispatch<F>(t: &T<F>, loops: usize) -> Duration
68-
where
69-
F: Fn(&str) -> usize,
70-
{
71-
let mut dur = Duration::default();
72-
for _ in 0..loops {
73-
let s = rand_string(thread_rng().gen_range(0..100));
74-
let now = Instant::now();
75-
let _ = (t.f2)(&s);
76-
dur += now.elapsed();
38+
pub struct ComplexProcessor {
39+
data: Vec<usize>,
40+
}
41+
42+
impl ComplexProcessor {
43+
pub fn new(data: Vec<usize>) -> Self {
44+
ComplexProcessor { data }
7745
}
78-
Duration::from_nanos((dur.as_nanos() as usize / loops) as _)
7946
}
8047

81-
fn main() {
82-
let t = T {
83-
f1: |s: &str| s.len(),
84-
f2: Box::new(|s: &str| s.len()),
85-
f3: Arc::new(|s: &str| s.len()),
86-
};
87-
88-
let _ = T {
89-
f1: |s: &str| s.len(),
90-
f2: Box::new(|s: &str| s.len() + 1),
91-
f3: Arc::new(|s: &str| s.len() + 1),
92-
};
93-
94-
let _ = T {
95-
f1: |s: &str| s.len(),
96-
f2: Box::new(|s: &str| s.len() + 2),
97-
f3: Arc::new(|s: &str| s.len() + 2),
98-
};
99-
100-
let _ = T {
101-
f1: |s: &str| s.len(),
102-
f2: Box::new(|s: &str| s.len() + 3),
103-
f3: Arc::new(|s: &str| s.len() + 3),
104-
};
105-
106-
for loops in [100_000, 1_000_000, 10_000_000] {
107-
println!();
108-
109-
println!(" statis - {} loops : {:?}", loops, bench_static_dispatch(&t, loops));
110-
println!(
111-
"box dynamic - {} loops : {:?}",
112-
loops,
113-
bench_box_dynamic_dispatch(&t, loops)
114-
);
115-
println!(
116-
"arc dynamic - {} loops : {:?}",
117-
loops,
118-
bench_arc_dynamic_dispatch(&t, loops)
119-
);
48+
impl Processor for ComplexProcessor {
49+
fn process(&self) -> usize {
50+
self.data.iter().sum()
12051
}
12152
}
53+
54+
fn bench_processor_types(c: &mut Criterion) {
55+
let simple_data = 42;
56+
let complex_data: Vec<usize> = (1..=10_000).collect();
57+
58+
let simple_processor = SimpleProcessor::new(simple_data);
59+
let box_simple_processor: Box<dyn Processor> = Box::new(SimpleProcessor::new(simple_data));
60+
let arc_simple_processor: Arc<dyn Processor> = Arc::new(SimpleProcessor::new(simple_data));
61+
62+
let complex_processor = ComplexProcessor::new(complex_data.clone());
63+
let box_complex_processor: Box<dyn Processor> = Box::new(ComplexProcessor::new(complex_data.clone()));
64+
let arc_complex_processor: Arc<dyn Processor> = Arc::new(ComplexProcessor::new(complex_data.clone()));
65+
66+
let mut group = c.benchmark_group("Processor Types");
67+
group.bench_function("simple_direct_reference", |b| b.iter(|| simple_processor.process()));
68+
group.bench_function("simple_box_dynamic_dispatch", |b| {
69+
b.iter(|| box_simple_processor.process())
70+
});
71+
group.bench_function("simple_arc_dynamic_dispatch", |b| {
72+
b.iter(|| arc_simple_processor.process())
73+
});
74+
75+
group.bench_function("complex_direct_reference", |b| b.iter(|| complex_processor.process()));
76+
group.bench_function("complex_box_dynamic_dispatch", |b| {
77+
b.iter(|| box_complex_processor.process())
78+
});
79+
group.bench_function("complex_arc_dynamic_dispatch", |b| {
80+
b.iter(|| arc_complex_processor.process())
81+
});
82+
83+
group.finish();
84+
}
85+
86+
/*
87+
Processor Types/simple_direct_reference time: [299.32 ps 299.45 ps 299.67 ps]
88+
simple_box_dynamic_dispatch time: [1.4963 ns 1.4969 ns 1.4980 ns]
89+
simple_arc_dynamic_dispatch time: [1.4962 ns 1.4964 ns 1.4967 ns]
90+
91+
complex_direct_reference time: [753.43 ns 753.53 ns 753.65 ns]
92+
complex_box_dynamic_dispatch time: [757.12 ns 757.31 ns 757.58 ns]
93+
complex_arc_dynamic_dispatch time: [757.55 ns 757.67 ns 757.84 ns]
94+
*/
95+
criterion_group!(benches, bench_processor_types);
96+
criterion_main!(benches);

foyer-workspace-hack/Cargo.toml

+5-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ publish = true
2121
ahash = { version = "0.8" }
2222
allocator-api2 = { version = "0.2" }
2323
crossbeam-channel = { version = "0.5" }
24+
crossbeam-deque = { version = "0.8" }
2425
crossbeam-epoch = { version = "0.9" }
2526
crossbeam-utils = { version = "0.8" }
2627
either = { version = "1", default-features = false, features = ["use_std"] }
@@ -30,19 +31,21 @@ futures-executor = { version = "0.3" }
3031
futures-sink = { version = "0.3" }
3132
futures-util = { version = "0.3", default-features = false, features = ["async-await-macro", "channel", "io", "sink"] }
3233
hashbrown = { version = "0.14", features = ["raw"] }
33-
itertools = { version = "0.12" }
3434
libc = { version = "0.2", features = ["extra_traits"] }
3535
parking_lot = { version = "0.12", features = ["arc_lock", "deadlock_detection"] }
3636
parking_lot_core = { version = "0.9", default-features = false, features = ["deadlock_detection"] }
3737
rand = { version = "0.8", features = ["small_rng"] }
38+
regex = { version = "1", default-features = false, features = ["std", "unicode-case", "unicode-perl"] }
39+
regex-automata = { version = "0.4", default-features = false, features = ["meta", "std", "unicode-case", "unicode-perl", "unicode-word-boundary"] }
40+
regex-syntax = { version = "0.8", default-features = false, features = ["std", "unicode-case", "unicode-perl"] }
41+
serde = { version = "1", features = ["alloc", "derive"] }
3842
smallvec = { version = "1", default-features = false, features = ["const_new"] }
3943
tokio = { version = "1", features = ["fs", "io-std", "io-util", "macros", "net", "rt-multi-thread", "signal", "sync", "time", "tracing"] }
4044
tracing-core = { version = "0.1" }
4145

4246
[build-dependencies]
4347
cc = { version = "1", default-features = false, features = ["parallel"] }
4448
either = { version = "1", default-features = false, features = ["use_std"] }
45-
itertools = { version = "0.12" }
4649
proc-macro2 = { version = "1" }
4750
quote = { version = "1" }
4851
syn = { version = "2", features = ["extra-traits", "full", "visit-mut"] }

0 commit comments

Comments
 (0)