C++纯虚拟函数调用的性能可变性

Performance variability of C++ pure virtual function calls

本文关键字:性能 可变性 函数调用 虚拟 C++      更新时间:2023-10-16

我不得不设计和开发一个将在实时环境中使用的C++模块(它将在现代多核PC上运行)。当我设计它时,我创建了C++接口(只有纯虚拟成员函数的类),并使用了依赖项注入,以便能够用Google Mock Framework测试它。我知道这种方法的运行时性能开销与静态绑定相当,但可测试性是一个重要因素。

我认为我们可以在开发过程中测量执行时间,也可以在集成阶段运行测试,以确定性能开销是否可以接受。

在过去的几天里,我收到了一些批评,认为这种方法行不通,因为后期绑定具有不确定性。这种不确定性意味着,即使我测试它并测量执行时间,稍后在生产环境中,执行时间可能会更多,这只是因为后期绑定(因为我使用了纯虚拟函数)。

据我所知,这是不可能的(缓存未命中和类似的情况除外)。如果你使用接口,这意味着你将有一些额外的间接层,编译器在某些情况下无法优化(例如内联函数),但仅此而已

所以我的问题不是性能开销,而是性能的可变性。两次执行之间会有所不同吗?

我找不到任何关于这个主题的文章或基准。所发现的文章对静态绑定和动态绑定之间的恒定性能差异进行了基准测试,但现在这不是问题所在。

如果你知道任何可以公开访问的文章、网页、书籍、来源或任何有帮助的东西,请与我分享。

谢谢!

更新:我想把链接和文件放在我找到答案的地方:

  1. 虚拟函数调用的工作原理:Parashift C++常见问题解答
  2. 《C++性能技术报告》,第87页:"如果对象的静态类型可以在编译时确定,那么调用虚拟函数可能不会比调用非虚拟成员函数更昂贵。如果类型必须在运行时动态确定,那么每次调用的开销通常是固定数量的机器指令(§5.3.3)。"
  3. Agnes Fog的C++优化软件:Windows、Linux和Mac平台的优化指南,第53页:"调用虚拟成员函数所需的时间比调用非虚拟成员函数多几个时钟周期,前提是函数调用语句始终调用相同版本的虚拟函数。"

2005年,国际C++标准化委员会发布了一份《C++性能技术报告》,我认为该报告既是关于这一主题的文章,也是关于这一话题的基准。

简单的答案是,缓存未命中会极大地影响运行时间,并且在调用虚拟函数时(通常)会咨询vtable。

但在实践中(与形式上相反),就执行的机器代码而言,每次调用的开销是固定的,因为所有现存的编译C++实现都使用vtables。您可以随心所欲地派生类,而不会影响调用开销。任何调用仍然执行(1)在对象的已知位置查找vtable指针,(2)在vtable的已知位置查询函数地址,(3)调用该函数,除非编译器知道函数指针可以从早期调用中获得,否则这只会使调用更快。