Performance variability of C++ pure virtual function calls
Asked Answered
G

1

13

I had to design and develop a C++ module which will be used in a real time environment (it will be run on a modern multi-core PC). When I designed it I created C++ interfaces (classes with only pure virtual member functions) and I used dependency injection in order to be able to test it with Google Mock Framework. I know that this approach has run time performance overhead compered to the static binding but the testability was an important factor.

I thought we can measure the execution time during the development and also run tests at the integration phases to decide if the performance overhead is acceptable.

In the past few days I received a critics that this approach will not work because late binding has an nondeterministict nature. This nondeterministict nature means even if I test it and I measure the execution times, later, in the production environment the execution time can be more only because of the late binding (because I used pure virtual functions).

As far as I know it is not possible (with exception of the cache misses and things like that). If you use interfaces it means you will have some additional layers of indirection and the compiler cannot optimize in some cases (inline functions for example), but that's it.

So my question is not the performance overhead but the variability of the performance. Can it vary between two execution?

I cannot find any article or benchmark about this topic. The found articles benchmark the constant performance difference between the static and dynamic binding but again it is not the question now.

If you know any openly accessible articles, webpages, books, source or anything that can help, please share with me.

Thank you!

Update: I would like to put the links and documents where I found the answer:

  1. How the virtual function call works: Parashift C++ FAQ
  2. Technical Report on C++ Performance, page 87: "If the static type of an object can be determined at compile-time, calling a virtual function may be no more expensive than calling a non-virtual member function. If the type must be dynamically determined at run-time, the overhead will typically be a fixed number of machine instructions (§5.3.3) for each call."
  3. Agnes Fog's Optimizing software in C++: An optimization guide for Windows, Linux and Mac platforms, page 53: "The time it takes to call a virtual member function is a few clock cycles more than it takes to call a non-virtual member function, provided that the function call statement always calls the same version of the virtual function."
Garb answered 7/12, 2013 at 7:53 Comment(9)
'late binding has an nondeterministic nature', sounds like nonsense to meCharge
There is very little in (non-concurrent) computing that has nondeterministic nature. Ask them to come up with a specific example illustrating what they mean.Vendee
I agree with @Vendee -- the burden of proof should be theirs.Yesteryear
Your critics might be confused with Objective-c style messaging, which has variable overhead. See #982616 As stated below, this is not how C++ implementations work.Su
or they come from hard real time systems where branch prediction, cache misses and out of order execution makes your life difficult. just because you have to do worst case execution time analysis.Mercy
A modern multicore PC is probably not a good choice for a true real time environment.Kiele
@CharlesBailey generally I agree, but the OP named real time in the question. it would be interesting in how far this is related. then again, if it would be hard real time people would have shown him the right tools already.Mercy
It doesn't matter. It's like worrying about air drag on a turtle. I wish I could find the comment that said "worrying about the cost of virtual function calls is like getting a haircut to lose weight". If that's what you care about, you are almost certainly being blind to much bigger issues.Redfin
Very interesting question (I'm dealing with a similar issue, but rather I'm the developer and the critic -- in one). In support of the critics: the question is not about average/best performance (which is what most of software devs care about), but about the execution time deterministic-ness (?) / boundedness. Re: the air drag on turtle analogy. Yes, 99.(9)% times it will not matter, but if at least once there is enough wind blowing to make the turtle stop or tumble backwards, the code is wrong. Welcome to the realm of hard real-time.Cullet
S
16

The international C++ standardization committee in 2005 published a Technical Report on C++ Performance , which I believe qualifies as both article and benchmark about this topic.

The short answer is that cache misses can influence run time considerably, and in a call of a virtual function the vtable is (usually) consulted.

But in practice (as opposed to the formal) the overhead per call in terms of executed machine code, is fixed, because all extant compiled C++ implementations use vtables. You can derive classes to your heart's content without affecting the call overhead. Any call still performs (1) look up vtable pointer in known place in object, (2) look up function address in known place in vtable, (3) call that function, unless the compiler knows that the function pointer is available from e.g. an earlier call, which just, if anything, makes the call go a wee bit faster.

Sergent answered 7/12, 2013 at 8:3 Comment(1)
+1. The TR is indeed an interesting read. The fact that it does not mention non-determinism anywhere (at least when it comes to virtual function calls) is proof enough for me that the claim the OP is confronted with is bogus.Yesteryear

© 2022 - 2024 — McMap. All rights reserved.