在C ++类中有一个虚方法的性能成本是多少? [英] What is the performance cost of having a virtual method in a C++ class?

查看:93
本文介绍了在C ++类中有一个虚方法的性能成本是多少?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C ++类(或其任何父类)中至少有一个虚方法意味着该类将有一个虚表,每个实例都有一个虚指针。

Having at least one virtual method in a C++ class (or any of its parent classes) means that the class will have a virtual table, and every instance will have a virtual pointer.

所以内存成本是很清楚的。最重要的是实例上的内存成本(特别是如果实例很小,例如,如果它们只是包含一个整数):在这种情况下,在每个实例中有一个虚拟指针可能会加倍实例的大小。虚拟表使用的内存空间,我想这相对于实际方法代码占用的空间通常是可以忽略的。

So the memory cost is quite clear. The most important is the memory cost on the instances (especially if the instances are small, for example if they are just meant to contain an integer: in this case having a virtual pointer in every instance might double the size of the instances. As for the memory space used up by the virtual tables, I guess it is usually negligible compared to the space used up by the actual method code.

这给我的问题:是否有一个可衡量的性能成本(即速度影响)使一个方法是虚拟的?在每个方法调用时,在运行时将在虚拟表中查找,所以如果有非常频繁的调用这个方法,如果这个方法非常短,那么可能会有一个可衡量的性能打击我想这取决于平台,但有任何人运行一些基准?

This brings me to my question: is there a measurable performance cost (i.e. speed impact) for making a method virtual? There will be a lookup in the virtual table at runtime, upon every method call, so if there are very frequent calls to this method, and if this method is very short, then there might be a measurable performance hit? I guess it depends on the platform, but has anyone run some benchmarks?

我问的原因是,遇到了一个错误,这是由于程序员忘记定义一个虚拟的方法,这不是我第一次看到这种错误。我想:为什么我们在需要时添加虚拟关键字而不是删除虚拟关键字,当我们绝对确定不需要 ?如果性能成本较低,我想我会在我的团队中简单推荐以下内容:在每个类中,只要将每个方法默认为虚拟(包括析构函数),并且只在需要时删除它。

The reason I am asking is that I came across a bug that happened to be due to a programmer forgetting to define a method virtual. This is not the first time I see this kind of mistake. And I thought: why do we add the virtual keyword when needed instead of removing the virtual keyword when we are absolutely sure that it is not needed? If the performance cost is low, I think I will simply recommend the following in my team: simply make every method virtual by default, including the destructor, in every class, and only remove it when you need to. Does that sound crazy to you?

推荐答案

在一个3GHz的有序PowerPC处理器上运行一些时间。在该架构上,虚函数调用比直接(非虚拟)函数调用花费7纳秒。

I ran some timings on a 3ghz in-order PowerPC processor. On that architecture, a virtual function call costs 7 nanoseconds longer than a direct (non-virtual) function call.

所以,真的不值得担心成本,除非函数是一个简单的Get()/ Set()访问器,其中除了inline是什么浪费。对0.5ns的内联函数的7ns开销是严重的;对于花费500ms执行的函数,7ns的开销是无意义的。

So, not really worth worrying about the cost unless the function is something like a trivial Get()/Set() accessor, in which anything other than inline is kind of wasteful. A 7ns overhead on a function that inlines to 0.5ns is severe; a 7ns overhead on a function that takes 500ms to execute is meaningless.

虚函数的巨大成本并不是在vtable中查找函数指针通常只有一个周期),但间接跳转通常不能被分支预测。这可能导致大的管线气泡,因为处理器不能获取任何指令,直到间接跳转(通过函数指针的调用)已经退休并且计算新的指令指针。因此,虚拟函数调用的成本远远大于查看程序集所看到的,但仍然只有7纳秒。

The big cost of virtual functions isn't really the lookup of a function pointer in the vtable (that's usually just a single cycle), but that the indirect jump usually cannot be branch-predicted. This can cause a large pipeline bubble as the processor cannot fetch any instructions until the indirect jump (the call through the function pointer) has retired and a new instruction pointer computed. So, the cost of a virtual function call is much bigger than it might seem from looking at the assembly... but still only 7 nanoseconds.

编辑: 安德鲁,不确定,其他人也提出了一个非常好的点,一个虚拟函数调用可能会导致指令缓存未命中:如果你跳转到一个不在缓存中的代码地址,那么整个程序就会停止而指令则从主存储器中取出。这是总是一个重大的失速:在氙,约650个周期(通过我的测试)。

Andrew, Not Sure, and others also raise the very good point that a virtual function call may cause an instruction cache miss: if you jump to a code address that is not in cache then the whole program comes to a dead halt while the instructions are fetched from main memory. This is always a significant stall: on Xenon, about 650 cycles (by my tests).

但是,这不是虚函数特有的问题,因为即使直接函数调用会跳转到不在缓存中的指令,也会导致错过。重要的是函数是否在最近之前运行(使它更有可能在缓存中),以及您的架构是否可以预测静态(而非虚拟)分支并提前将这些指令提取到缓存中。我的PPC没有,但也许是英特尔最新的硬件。

However this isn't a problem specific to virtual functions because even a direct function call will cause a miss if you jump to instructions that aren't in cache. What matters is whether the function has been run before recently (making it more likely to be in cache), and whether your architecture can predict static (not virtual) branches and fetch those instructions into cache ahead of time. My PPC does not, but maybe Intel's most recent hardware does.

我的计时控制icache未命中对执行的影响(故意,因为我试图孤立地检查CPU流水线),所以他们折扣那个成本。

My timings control for the influence of icache misses on execution (deliberately, since I was trying to examine the CPU pipeline in isolation), so they discount that cost.

这篇关于在C ++类中有一个虚方法的性能成本是多少?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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