Performance penalty for working with interfaces in C++?
Asked Answered
M

16

50

Is there a runtime performance penalty when using interfaces (abstract base classes) in C++?

Molecular answered 22/9, 2008 at 8:41 Comment(1)
The answers to this question are also related.Senhorita
L
50

Short Answer: No.

Long Answer: It is not the base class or the number of ancestors a class has in its hierarchy that affects it speed. The only thing is the cost of a method call.

A non virtual method call has a cost (but can be inlined)
A virtual method call has a slightly higher cost as you need to look up the method to call before you call it (but this is a simple table look up not a search). Since all methods on an interface are virtual by definition there is this cost.

Unless you are writing some hyper speed sensitive application this should not be a problem. The extra clarity that you will recieve from using an interface usually makes up for any perceived speed decrease.

Latimore answered 22/9, 2008 at 8:41 Comment(7)
It is worth nothing that a virtual method call on an object with multiple base classes has a slightly higher cost again than a virtual method call on an object with a single inheritance hierarchy.Appositive
Are you sure? Do you have a source for this comment that I can checkout?Slate
The cost is in the conversion. If you have 'D*' and you want to convert to 'B2*', then, where the layout of the class is [ B1, B2 ] the compiler needs to return 'D* + offset to B2'. I disagree that this is worth noting however - it will be insignificant.Senhorita
May even be zero, depending on the addressing modes offered by your CPU. Accessing register+offset is not unusual.Danzig
@Martin: Actually a virtual method will be inlined in exactly the situations where a non-virtual method would be -- namely, when the dynamic type of the object can be determined at compile time and the method is inlineable (not too large + declared either in the class definition or with "inline").Staciastacie
It would be interesting to explain in more technical detail what happens with a virtual call... i.e. in C/ASM code what the vtable stuff actually meansRoundy
@John: This question is old. If you want to know that ask a new question. Though you will probably get beaten over the head saying it is not relevant as vtables is an implementation detail and not required by the standard.Slate
U
28

Functions called using virtual dispatch are not inlined

There is one kind of penalty for virtual functions which is easy to forget about: virtual calls are not inlined in a (common) situation where the type of the object is not know compile time. If your function is small and suitable for inlining, this penalty may be very significant, as you are not only adding a call overhead, but the compiler is also limited in how it can optimize the calling function (it has to assume the virtual function may have changed some registers or memory locations, it cannot propagate constant values between the caller and the callee).

Virtual call cost depends on platform

As for the call overhead penalty compared to a normal function call, the answer depends on your target platform. If your are targeting a PC with x86/x64 CPU, the penalty for calling a virtual function is very small, as modern x86/x64 CPU can perform branch prediction on indirect calls. However, if you are targeting a PowerPC or some other RISC platform, the virtual call penalty may be quite significant, because indirect calls are never predicted on some platforms (Cf. PC/Xbox 360 Cross Platform Development Best Practices).

Unsay answered 22/9, 2008 at 9:39 Comment(5)
It is incorrect to say that virtual calls are not inlined. Whenever the compiler can determine the final type of an object at compile time, method calls on that object are candidates for inlining. It is only when calling via pointer-to-base that inlining cannot be performed.Staciastacie
@Staciastacie Is is only the case that you usually use it as a pointer to base.Carincarina
@Ghita: Even then, an optimising compiler may be able to figure out what the dynamic type of the object must be. My guess would be that most compilers can inline the call to foo() in Base* x = new Derived; x->foo();.Staciastacie
@Staciastacie yes it could. But in a normal use case you usually pass the pointer to base class around. It's interesting to note though that the simplest cases are handled by the compiler.Carincarina
Even pointer to base could be inlined by LTO compilation when a full system analysis is done and the interface is just used for modularization and testability and there is just one subclass. Unfortuantely i'm not sure if this is done by any compiler at the moment.Starnes
D
10

There is a small penalty per virtual function call compared to a regular call. You are unlikely to observe a difference unless you are doing hundreds of thousands of calls per second, and the price is often worth paying for added code clarity anyway.

Dorotea answered 22/9, 2008 at 8:43 Comment(0)
J
5

When you call a virtual function (say through an interface) the program has to do a look up of the function in a table to see which function to call for that object. This gives a small penalty compared to a direct call to the function.

Also, when you use a virtual function the compiler cannot inline the function call. Therefore there could be a penalty to using a virtual function for some small functions. This is generally the biggest performance "hit" you are likely to see. This really only an issue if the function is small and called many times, say from within a loop.

Jegger answered 22/9, 2008 at 8:47 Comment(2)
Don't let it screw up your design, indeed, but only use virtual functions if you really need them - inlining can cause HUGE performance gain when you think of iterating over a (big) number of elements and calling the method on each one of them.Shaner
It is incorrect to say that virtual calls cannot be inlined. Whenever the compiler can determine the final type of an object at compile time, method calls on that object are candidates for inlining. It is only when calling via pointer-to-base that inlining cannot be performed.Staciastacie
M
4

Another alternative that is applicable in some cases is compile-time polymorphism with templates. It is useful, for example, when you want to make an implementation choice at the beginning of the program, and then use it for the duration of the execution. An example with runtime polymorphism

class AbstractAlgo
{
    virtual int func();
};

class Algo1 : public AbstractAlgo
{
    virtual int func();
};

class Algo2 : public AbstractAlgo
{
    virtual int func();
};

void compute(AbstractAlgo* algo)
{
      // Use algo many times, paying virtual function cost each time

}   

int main()
{
    int which;
     AbstractAlgo* algo;

    // read which from config file
    if (which == 1)
       algo = new Algo1();
    else
       algo = new Algo2();
    compute(algo);
}

The same using compile time polymorphism

class Algo1
{
    int func();
};

class Algo2
{
    int func();
};


template<class ALGO>  void compute()
{
    ALGO algo;
      // Use algo many times.  No virtual function cost, and func() may be inlined.
}   

int main()
{
    int which;
    // read which from config file
    if (which == 1)
       compute<Algo1>();
    else
       compute<Algo2>();
}
Maretz answered 22/9, 2008 at 13:2 Comment(2)
Unfortunately, this does not apply to plugin classes and other dynamically loaded types (yes, this is possible in C++ :-)Kicker
This adds a lot to code bloat and i still wait for any study that examines the impact of template code bloat on performance (cache problems, branch predictions ...).Starnes
M
3

I don't think that the cost comparison is between virtual function call and a straight function call. If you are thinking about using a abstract base class (interface), then you have a situation where you want to perform one of several actions based of the dynamic type of an object. You have to make that choice somehow. One option is to use virtual functions. Another is a switch on the type of the object, either through RTTI (potentially expensive), or adding a type() method to the base class (potentially increasing memory use of each object). So the cost of the virtual function call should be compared to the cost of the alternative, not to the cost of doing nothing.

Maretz answered 22/9, 2008 at 12:42 Comment(0)
D
3

Most people note the runtime penalty, and rightly so.

However, in my experience working on large projects, the benefits from clear interfaces and proper encapsulation quickly offset the gain in speed. Modular code can be swapped for an improved implementation, so the net result is a large gain.

Your mileage may vary, and it clearly depend on the application you're developing.

Dolph answered 22/9, 2008 at 17:0 Comment(1)
I'd like to offer the counter point: For embedded systems (others have mentioned video game consoles), the performance hit might be too large and unless there's alot of be gained from maintainability/readability/clarity, etc. they should be avoided.Jota
D
3

Note that multiple inheritance bloats the object instance with multiple vtable pointers. With G++ on x86, if your class has a virtual method and no base class, you have one pointer to vtable. If you have one base class with virtual methods, you still have one pointer to vtable. If you have two base classes with virtual methods, you have two vtable pointers on each instance.

Thus, with multiple inheritance (which is what implementing interfaces in C++ is), you pay base classes times pointer size in the object instance size. The increase in memory footprint may have indirect performance implications.

Dipper answered 12/10, 2008 at 11:42 Comment(0)
E
2

One thing that should be noted is that virtual function call cost can vary from one platform to another. On consoles they may be more noticeable, as usually vtable call means a cache miss and can screw branch prediction.

Eximious answered 22/9, 2008 at 9:38 Comment(1)
I've heard this stated often, but never actually validated. The cost effective cost on global performance application performance, in consoles or not, actually depends on the frequency at which you call the method. Most of my friends in the gaming industry are not allowed to use virtual functions at all on behalf of your argument. They end up with messed up code to circumvent this limitation even for higher-level function called once per render cycle.Kicker
I
0

Using abstract base classes in C++ generally mandates the use of a virtual function table, all your interface calls are going to be looked up through that table. The cost is tiny compared to a raw function call, so be sure that you need to be going faster than that before worrying about it.

Ignace answered 22/9, 2008 at 8:45 Comment(0)
Q
0

The only main difference I know of is that, since you're not using a concrete class, inlining is (much?) harder to do.

Quinquagesima answered 22/9, 2008 at 8:45 Comment(0)
D
0

The only thing I can think of is that virtual methods are a little bit slower to call than non-virtual methods, because the call has to go through the virtual method table.

However, this is a bad reason to screw up your design. If you need more performance, use a faster server.

Doorkeeper answered 22/9, 2008 at 8:45 Comment(0)
V
0

As for any class that contains a virtual function, a vtable is used. Obviously, invoking a method through a dispatching mechanism like a vtable is slower than a direct call, but in most cases you can live with that.

Vie answered 22/9, 2008 at 8:48 Comment(0)
U
0

Yes, but nothing noteworthy to my knowledge. The performance hit is because of 'indirection' you have in each method call.

However, it really depends on the compiler you're using since some compilers are not able to inline the method calls within the classes inheriting from the abstract base class.

If you want to be sure you should run your own tests.

Underthrust answered 22/9, 2008 at 8:53 Comment(0)
S
0

Yes, there is a penalty. Something which may improve performance on your platform is to use a non-abstract class with no virtual functions. Then use a member function pointer to your non-virtual function.

Scrunch answered 22/9, 2008 at 14:24 Comment(0)
N
0

I know it's an uncommon viewpoint, but even mentioning this issue makes me suspect you're putting way too much thought into the class structure. I've seen many systems that had way too many "levels of abstraction", and that alone made them prone to severe performance problems, not due the cost of method calls, but due to the tendency to make unnecessary calls. If this happens over multiple levels, it's a killer. take a look

Neotropical answered 4/11, 2008 at 22:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.