virtual function performance

Pages: 12
I am seeing a performance issue with virtual functions and it impacts every function call with virtual functions. why am i seeing virtual fns execute slower? Is it because virtual function call requires run time type of owning class to be identified or it has to search for proper class binding or it requires a table lookup at runtime before calling or class must use memory to maintain a table of virtual function pointers? please clarify me here.

In below code for both the call on obj.f(); and on
obj2ref.f(); there is the possibility that at run time obj is of some derived class, so it has to search for the actual type in order to determine which f() is to be called.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct Class{ 
  virtual void f() {...} 
}; 
 
struct Class2 : public Class { 
  virtual void f() {...} 
}; 
 
Class obj; 
 
obj.f(); 
 
Class2 obj2; 
obj2.f(); 
Class& obj2ref = obj2; 
 
obj2ref.f(); 
Last edited on
Lookup / dereference. Search "C++ vtable".
Ok, so virtual function is slower than normal functions as it requires a table lookup at runtime before calling. Correct?
Yes. - although the standard doesn't require use of a vtable, in practice this is how they're all (??) done.
> Ok, so virtual function is slower than normal functions as it requires a table lookup at runtime before calling.
> Correct?

The cost of the v-table look up may not be the most significant overhead; inability to inline (and optimise across) the call, and (in large programs) poor cache performance may contribute more to the overhead.

A v-table look up may not be required if the compiler can determine the the final overrider at compile time.
For example: https://gcc.godbolt.org/z/9hhsWxdjz
The virtual function call has to search for the correct class binding. Does this impact the slowness or performance here? Also is there any way to overcome the slowness of virtual function in c++? any way to override it?
My understanding is that virtual function requires a table lookup at runtime before calling. Are there any other factors that might impact the performance by using virtual functions here?
JLBorges did already list some. (And also noted that in some cases the runtime lookup is not required.)
Ok, so if runtime lookup is not needed here, does it mean slowness could be due to the fact that class must use memory to maintain a table of virtual function pointers?
> could be due to the fact that class must use memory to maintain a table of virtual function pointers?

Not usually; the v-table does not take a huge amount of storage. Certainly not relevant in such a small program.
How big are these functions? Did you compile the code with optimisations enabled?
https://gcc.godbolt.org/z/M3We55s7K
I haven't tried optimizations on it as its big code base. But just want to clarify if the slowness is because "the virtual function call requires the run time type of the owning class to be identified", when comparing it to a statically bound call ?
Last edited on
the virtual function call requires the run time type of the owning class to be identified
No. The virtual table does not need the runtime type.

Normally it's an static array which pointer is attached to the object. Hence instead of

func(....)

it is

vtable[.](....)

An additional array indexing. So to have a noticeable difference when calling the one or the other you need millions if not billons of calls.
> "the virtual function call requires the run time type of the owning class to be identified"

In the typical implementation, the object in question would have a v-table pointer as part of its object layout. That (and the table it points to) is what is looked up at run-time.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Class{ 
    virtual void f() = 0 ;
    int i ;
}; 
 

int foo( Class& c )
{ 
    c.f() ; 
    /*
     mov     rax, QWORD PTR [rdi] // get the vtbl pointer in the object (into rax)
     call    [QWORD PTR [rax]] // look up the vtbl and call the function
    */
}

https://gcc.godbolt.org/z/fo4K7Ynza

Things would be a bit more involved with multiple inheritance or virtual base classes; but the basic idea would remain the same.
Could slowness be due to fact that virtual function call has to search for the correct class binding?
> Could slowness be due to fact that virtual function call has to search for the correct class binding?

No, there is no elaborate 'search' involved.
1. Look into the object and get the v-table pointer
2. Look up the v-table, get the address of the function and call the function at that address.
Could slowness be due to fact that virtual function call has to search for the correct class binding?
Probably not. The pointer to the vtable is set when the object is constructed, so the "search for the correct class" is simply a dereferencing the vtable pointer.

Let's go back to the beginning:
I am seeing a performance issue with virtual functions and it impacts every function call with virtual functions.
Can you tell us more about this. What makes you think that the problem is the fact that the functions are virtual, rather than the content of the functions themselves? Unless the virtual functions are extremely small, I doubt that a performance problem is related to them being virtual.
I feel that finding the proper function call in the table, will only add more cost to it. Isn't so?
> I feel that finding the proper function call in the table, will only add more cost to it. Isn't so?

Yes, it would add a small cost.

Calling a virtual function is roughly equivalent to calling a function through a pointer stored in an array.

- Technical Report on C++ Performance (n1666)
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1666.pdf

Somewhat dated; but it may be worth perusing section 5.3 'Classes and Inheritance'
I have read the doc from the link. Thanks for sharing it. so can I conclude that compared to a statically bound call, virtual function calls are slower as virtual function call requires the run time type of the owning class to be identified?
Pages: 12