Skip to content

Commit

Permalink
refactor: a more friendly dynamic_dispatch bench
Browse files Browse the repository at this point in the history
Signed-off-by: xiaguan <751080330@qq.com>
  • Loading branch information
xiaguan committed Apr 12, 2024
1 parent 6b820fa commit c247346
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 94 deletions.
1 change: 1 addition & 0 deletions foyer-memory/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ tokio = { workspace = true }
[dev-dependencies]
bytesize = "1"
clap = { version = "4", features = ["derive"] }
criterion = "0.5.1"
hdrhistogram = "7"
moka = { version = "0", features = ["sync"] }
rand = "0.8"
Expand Down
159 changes: 67 additions & 92 deletions foyer-memory/benches/bench_dynamic_dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,110 +12,85 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{
sync::Arc,
time::{Duration, Instant},
};

use rand::{distributions::Alphanumeric, thread_rng, Rng};

struct T<F>
where
F: Fn(&str) -> usize,
{
f1: F,
f2: Box<dyn Fn(&str) -> usize>,
f3: Arc<dyn Fn(&str) -> usize>,
use criterion::{criterion_group, criterion_main, Criterion};
use std::sync::Arc;

pub trait Processor {
fn process(&self) -> usize;
}

fn rand_string(len: usize) -> String {
thread_rng()
.sample_iter(&Alphanumeric)
.take(len)
.map(char::from)
.collect()
pub struct SimpleProcessor {
data: usize,
}

fn bench_static_dispatch<F>(t: &T<F>, loops: usize) -> Duration
where
F: Fn(&str) -> usize,
{
let mut dur = Duration::default();
for _ in 0..loops {
let s = rand_string(thread_rng().gen_range(0..100));
let now = Instant::now();
let _ = (t.f1)(&s);
dur += now.elapsed();
impl SimpleProcessor {
pub fn new(data: usize) -> Self {
SimpleProcessor { data }
}
Duration::from_nanos((dur.as_nanos() as usize / loops) as _)
}

fn bench_box_dynamic_dispatch<F>(t: &T<F>, loops: usize) -> Duration
where
F: Fn(&str) -> usize,
{
let mut dur = Duration::default();
for _ in 0..loops {
let s = rand_string(thread_rng().gen_range(0..100));
let now = Instant::now();
let _ = (t.f3)(&s);
dur += now.elapsed();
impl Processor for SimpleProcessor {
fn process(&self) -> usize {
self.data * self.data
}
Duration::from_nanos((dur.as_nanos() as usize / loops) as _)
}

fn bench_arc_dynamic_dispatch<F>(t: &T<F>, loops: usize) -> Duration
where
F: Fn(&str) -> usize,
{
let mut dur = Duration::default();
for _ in 0..loops {
let s = rand_string(thread_rng().gen_range(0..100));
let now = Instant::now();
let _ = (t.f2)(&s);
dur += now.elapsed();
pub struct ComplexProcessor {
data: Vec<usize>,
}

impl ComplexProcessor {
pub fn new(data: Vec<usize>) -> Self {
ComplexProcessor { data }
}
Duration::from_nanos((dur.as_nanos() as usize / loops) as _)
}

fn main() {
let t = T {
f1: |s: &str| s.len(),
f2: Box::new(|s: &str| s.len()),
f3: Arc::new(|s: &str| s.len()),
};

let _ = T {
f1: |s: &str| s.len(),
f2: Box::new(|s: &str| s.len() + 1),
f3: Arc::new(|s: &str| s.len() + 1),
};

let _ = T {
f1: |s: &str| s.len(),
f2: Box::new(|s: &str| s.len() + 2),
f3: Arc::new(|s: &str| s.len() + 2),
};

let _ = T {
f1: |s: &str| s.len(),
f2: Box::new(|s: &str| s.len() + 3),
f3: Arc::new(|s: &str| s.len() + 3),
};

for loops in [100_000, 1_000_000, 10_000_000] {
println!();

println!(" statis - {} loops : {:?}", loops, bench_static_dispatch(&t, loops));
println!(
"box dynamic - {} loops : {:?}",
loops,
bench_box_dynamic_dispatch(&t, loops)
);
println!(
"arc dynamic - {} loops : {:?}",
loops,
bench_arc_dynamic_dispatch(&t, loops)
);
impl Processor for ComplexProcessor {
fn process(&self) -> usize {
self.data.iter().sum()
}
}

fn bench_processor_types(c: &mut Criterion) {
let simple_data = 42;
let complex_data: Vec<usize> = (1..=1_000).collect();

let simple_processor = SimpleProcessor::new(simple_data);
let box_simple_processor: Box<dyn Processor> = Box::new(SimpleProcessor::new(simple_data));
let arc_simple_processor: Arc<dyn Processor> = Arc::new(SimpleProcessor::new(simple_data));

let complex_processor = ComplexProcessor::new(complex_data.clone());
let box_complex_processor: Box<dyn Processor> = Box::new(ComplexProcessor::new(complex_data.clone()));
let arc_complex_processor: Arc<dyn Processor> = Arc::new(ComplexProcessor::new(complex_data.clone()));

let mut group = c.benchmark_group("Processor Types");
group.bench_function("simple_direct_reference", |b| b.iter(|| simple_processor.process()));
group.bench_function("simple_box_dynamic_dispatch", |b| {
b.iter(|| box_simple_processor.process())
});
group.bench_function("simple_arc_dynamic_dispatch", |b| {
b.iter(|| arc_simple_processor.process())
});

group.bench_function("complex_direct_reference", |b| b.iter(|| complex_processor.process()));
group.bench_function("complex_box_dynamic_dispatch", |b| {
b.iter(|| box_complex_processor.process())
});
group.bench_function("complex_arc_dynamic_dispatch", |b| {
b.iter(|| arc_complex_processor.process())
});

group.finish();
}

/*
Processor Types/simple_direct_reference time: [299.32 ps 299.45 ps 299.67 ps]
simple_box_dynamic_dispatch time: [1.4963 ns 1.4969 ns 1.4980 ns]
simple_arc_dynamic_dispatch time: [1.4962 ns 1.4964 ns 1.4967 ns]
complex_direct_reference time: [42.189 ns 42.221 ns 42.261 ns]
complex_box_dynamic_dispatch time: [41.946 ns 41.972 ns 42.001 ns]
complex_arc_dynamic_dispatch time: [60.411 ns 60.609 ns 60.841 ns]
*/
criterion_group!(benches, bench_processor_types);
criterion_main!(benches);
7 changes: 5 additions & 2 deletions foyer-workspace-hack/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ publish = true
ahash = { version = "0.8" }
allocator-api2 = { version = "0.2" }
crossbeam-channel = { version = "0.5" }
crossbeam-deque = { version = "0.8" }
crossbeam-epoch = { version = "0.9" }
crossbeam-utils = { version = "0.8" }
either = { version = "1", default-features = false, features = ["use_std"] }
Expand All @@ -30,19 +31,21 @@ futures-executor = { version = "0.3" }
futures-sink = { version = "0.3" }
futures-util = { version = "0.3", default-features = false, features = ["async-await-macro", "channel", "io", "sink"] }
hashbrown = { version = "0.14", features = ["raw"] }
itertools = { version = "0.12" }
libc = { version = "0.2", features = ["extra_traits"] }
parking_lot = { version = "0.12", features = ["arc_lock", "deadlock_detection"] }
parking_lot_core = { version = "0.9", default-features = false, features = ["deadlock_detection"] }
rand = { version = "0.8", features = ["small_rng"] }
regex = { version = "1", default-features = false, features = ["std", "unicode-case", "unicode-perl"] }
regex-automata = { version = "0.4", default-features = false, features = ["meta", "std", "unicode-case", "unicode-perl", "unicode-word-boundary"] }
regex-syntax = { version = "0.8", default-features = false, features = ["std", "unicode-case", "unicode-perl"] }
serde = { version = "1", features = ["alloc", "derive"] }
smallvec = { version = "1", default-features = false, features = ["const_new"] }
tokio = { version = "1", features = ["fs", "io-std", "io-util", "macros", "net", "rt-multi-thread", "signal", "sync", "time", "tracing"] }
tracing-core = { version = "0.1" }

[build-dependencies]
cc = { version = "1", default-features = false, features = ["parallel"] }
either = { version = "1", default-features = false, features = ["use_std"] }
itertools = { version = "0.12" }
proc-macro2 = { version = "1" }
quote = { version = "1" }
syn = { version = "2", features = ["extra-traits", "full", "visit-mut"] }
Expand Down

0 comments on commit c247346

Please sign in to comment.