动态调度的实际运行时性能成本是多少? [英] What are the actual runtime performance costs of dynamic dispatch?

查看:102
本文介绍了动态调度的实际运行时性能成本是多少?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

静态和动态调度,但 tl;dr 是在特征引用和其他一些不同情况(函数指针等)上调用方法会导致动态而不是静态调度.

There's some background on this topic in the Rust book section on static and dynamic dispatch, but the tl;dr is that calling a method on a trait reference and a few other various situation (function pointers, etc) results in dynamic instead of static dispatch.

在应用优化之后,它的实际运行时间成本是多少?

What is actual runtime cost of this, after optimizations have been applied?

例如,想象这组结构体 &特点:

For example, imagine this set of structs & traits:

struct Buffer;
struct TmpBuffer;
struct TmpMutBuffer;

impl BufferType for Buffer { ... }
impl BufferType for BufferTmp { ... }
impl BufferType for BufferTmpMut { ... }

impl Buffer2D for BufferType { ... }

impl Buffer2DExt for Buffer2D { ... }

请注意,这里的 trait 是在 trait 本身上实现的.

Notice that the traits here are implemented on traits themselves.

在结构引用上从 Buffer2DExt 调用方法的动态调度的调用成本是多少?

What is the calling cost of dynamic dispatch to invoke a method from Buffer2DExt on a struct reference?

最近的问题 Rust 的确切自动取消引用规则是什么? 关于取消引用规则;这些规则是在编译时还是运行时应用?

The recent question What are Rust's exact auto-dereferencing rules? regards the dereferencing rules; are these rules applied at compile time, or runtime?

推荐答案

免责声明:该问题相当开放,因此此答案可能不完整.用比平时更大的盐粒来对待它.

Rust 使用一个简单的虚拟表";实现动态调度.这个策略也用在 C++ 中,你可以看到在这里研究.不过这项研究有点过时了.

Rust uses a simple "virtual table" to implement dynamic dispatch. This strategy is also used in C++ for which you can see a study here. The study is a bit dated though.

虚拟分派会导致间接性,这有多种原因造成的成本:

Virtual dispatch induces indirection, this has a cost for multiple reasons:

  • 间接是不透明的:这会抑制内联和常量传播,这是许多编译器优化的关键推动因素
  • 间接具有运行时成本:如果预测不正确,您会看到管道停顿和昂贵的内存获取

然而,编译器通过尽最大努力优化间接性来搅浑水.

Compilers, however, muddies the water by trying their best at optimizing indirection away.

  • 去虚拟化:有时编译器可以在编译时解析虚拟表查找(通常是因为它知道对象的具体类型);如果是这样,它因此可以使用常规函数调用而不是间接函数调用,并优化间接调用
  • 概率去虚拟化:去年 Honza Hubička 推出了一个gcc 中的新优化(阅读由 5 部分组成的系列,因为它非常有指导意义).该策略的要点是构建继承图以对潜在类型进行有根据的猜测,然后使用像 if v.hasType(A) { vA::call() } elif v 这样的模式.hasType(B) { vB::call() } else { v.virtual-call() };特殊情况下最可能的类型意味着在这种情况下常规调用,因此是内联/常量传播/完整的好东西调用.
  • devirtualization: sometimes the compiler can resolve the virtual table look-up at compile time (usually, because it knows the concrete type of the object); if so, it can therefore use a regular function call rather than an indirect one, and optimize away the indirection
  • probabilistic devirtualization: last year Honza Hubička introduced a new optimization in gcc (read the 5-part series as it is very instructive). The gist of the strategy is to build the inheritance graph to make an educated guess at the potential type(s), and then use a pattern like if v.hasType(A) { v.A::call() } elif v.hasType(B) { v.B::call() } else { v.virtual-call() }; special-casing the most likely types means regular calls in this case, and therefore inlined/constant-propagated/full-goodies calls.

由于一致性规则和隐私规则,后一种策略在 Rust 中可能会相当有趣,因为它应该有更多的情况,其中完整的继承"是不完整的.图是已知的.

This latter strategy could be fairly interesting in Rust due to the coherence rules and privacy rules, as it should have more cases where the full "inheritance" graph is provably known.

在 Rust 中,您可以使用编译时多态而不是运行时多态;编译器将为它采用的每个独特的编译时参数组合发出一个版本的函数.这本身是有代价的:

In Rust, you can use compile-time polymorphism instead of run-time polymorphism; the compiler will emit one version of the function for each unique combination of compile-time parameters it takes. This, itself, has a cost:

  • 编译时间成本:要生成更多代码,要优化更多代码
  • 二进制大小成本:生成的二进制文件最终会更大,这是典型的大小/速度权衡
  • 运行时成本:较大的代码大小可能会导致 CPU 级别的缓存未命中

编译器可能能够将最终具有相同实现的专用函数合并在一起(例如,由于幻像类型),但是它仍然很有可能比生成的二进制文件(可执行文件和库)最终会更大.

The compiler might be able to merge together specialized functions that end up having the same implementation (because of phantom types, for example), however it is still more than likely than the produced binaries (executables and libraries) will end up larger.

与性能一样,您必须根据自己的情况衡量哪些更有益.

As usual with performance, you have to measure in your case what is more beneficial.

这篇关于动态调度的实际运行时性能成本是多少?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆