Skip to content

Latest commit

 

History

History
68 lines (54 loc) · 2.71 KB

enum_dispatch.md

File metadata and controls

68 lines (54 loc) · 2.71 KB

在运行 enum_dispatch 的 benchmark 的时候我发现一个很有意思,运行源码中默认的 bench trait 有一个方法,每次迭代两个 variant 都调用一次

test benches::boxdyn_blackbox       ... bench:     225,386 ns/iter (+/- 14,061)
test benches::enumdispatch_blackbox ... bench:     279,590 ns/iter (+/- 91,416)

test benches::boxdyn_homogeneous_vec       ... bench:   3,488,651 ns/iter (+/- 322,595)
test benches::enumdispatch_homogeneous_vec ... bench:     273,401 ns/iter (+/- 14,862)

一次 iter 一百万次调用,vec 测试中长度为 1024 但也是一百万次调用

可见 Vec Box dyn 默认情况下性能甚至更好,但 Vec Box dyn 性能骤降应该是缓存命中问题

索引vtable的速度是O(1),但动态分发仍然有一定的性能开销。这是因为它需要额外的内存访问(获取vtable和函数指针),并且可能对现代CPU的预测分支优化(branch prediction)造成不利影响

试试看把 trait/vtable 的函数数量增加到12个,结果enum_dispatch跟box dyn的性能差距被拉近

test benches::boxdyn_blackbox       ... bench:     219,917 ns/iter (+/- 19,326)
test benches::enumdispatch_blackbox ... bench:     222,376 ns/iter (+/- 12,845)
#[enum_dispatch]
pub trait ReturnsValue {
    fn return_value(&self) -> usize;
    fn r1(&self) -> i32;
    fn r2(&self) -> i32;
    fn r3(&self) -> i32;
    fn r4(&self) -> i32;
    fn r5(&self) -> i32;
    fn r6(&self) -> i32;
    fn r7(&self) -> i32;
    fn r8(&self) -> i32;
    fn r9(&self) -> i32;
    fn r10(&self) -> i32;
}

fn boxdyn_blackbox(b: &mut Bencher) {
    let dis0: Box<dyn ReturnsValue> = Box::new(Zero);
    let dis1: Box<dyn ReturnsValue> = Box::new(One);

    b.iter(|| {
        for _ in 0..ITERATIONS {
            test::black_box(dis0.return_value());
            test::black_box(dis0.r3());
            test::black_box(dis0.r6());
            test::black_box(dis0.r9());
            test::black_box(dis1.return_value());
            test::black_box(dis1.r3());
            test::black_box(dis1.r6());
            test::black_box(dis1.r9());
        }
    })
}

结果当每次迭代访问虚表不同的方法数量变多后,box dyn性能就比静态分发慢一个数量级,应该是分支预测和cpu缓存命中率都下降了

test benches::boxdyn_blackbox       ... bench:   6,918,933 ns/iter (+/- 456,640)
test benches::enumdispatch_blackbox ... bench:     901,027 ns/iter (+/- 124,013)

结论就是封闭生态的应用例如公司内同一个cargo workspace下面的trait的全部实现,可以用enum_dispatch静态分发加速,对于开放生态的公共库还是暴露 box dyn 的接口更佳