Virtual functions and performance - C++
A good rule of thumb is:
It's not a performance problem until you can prove it.
The use of virtual functions will have a very slight effect on performance, but it's unlikely to affect the overall performance of your application. Better places to look for performance improvements are in algorithms and I/O.
An excellent article that talks about virtual functions (and more) is Member Function Pointers and the Fastest Possible C++ Delegates.
Your question made me curious, so I went ahead and ran some timings on the 3GHz in-order PowerPC CPU we work with. The test I ran was to make a simple 4d vector class with get/set functions
class TestVec
{
float x,y,z,w;
public:
float GetX() { return x; }
float SetX(float to) { return x=to; } // and so on for the other three
}
Then I set up three arrays each containing 1024 of these vectors (small enough to fit in L1) and ran a loop that added them to one another (A.x = B.x + C.x) 1000 times. I ran this with the functions defined as inline
, virtual
, and regular function calls. Here are the results:
- inline: 8ms (0.65ns per call)
- direct: 68ms (5.53ns per call)
- virtual: 160ms (13ns per call)
So, in this case (where everything fits in cache) the virtual function calls were about 20x slower than the inline calls. But what does this really mean? Each trip through the loop caused exactly 3 * 4 * 1024 = 12,288
function calls (1024 vectors times four components times three calls per add), so these times represent 1000 * 12,288 = 12,288,000
function calls. The virtual loop took 92ms longer than the direct loop, so the additional overhead per call was 7 nanoseconds per function.
From this I conclude: yes, virtual functions are much slower than direct functions, and no, unless you're planning on calling them ten million times per second, it doesn't matter.
See also: comparison of the generated assembly.
In very performance critical applications (like video games) a virtual function call can be too slow. With modern hardware, the biggest performance concern is the cache miss. If data isn't in the cache, it may be hundreds of cycles before it's available.
A normal function call can generate an instruction cache miss when the CPU fetches the first instruction of the new function and it's not in the cache.
A virtual function call first needs to load the vtable pointer from the object. This can result in a data cache miss. Then it loads the function pointer from the vtable which can result in another data cache miss. Then it calls the function which can result in an instruction cache miss like a non-virtual function.
In many cases, two extra cache misses are not a concern, but in a tight loop on performance critical code it can dramatically reduce performance.
When Objective-C (where all methods are virtual) is the primary language for the iPhone and freakin' Java is the main language for Android, I think it's pretty safe to use C++ virtual functions on our 3 GHz dual-core towers.