overhead of virtual function calls

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
Post Reply
tstuefe
Posts: 40
Joined: Wed Jan 07, 2004 12:53 pm
Location: Heidelberg, Germany
Contact:

overhead of virtual function calls

Post by tstuefe »

Hi folks,

I just wondered what the real overhead of virtual function calls is and I was surprised:

Code: Select all

#include <time.h>

// performance tests for virtual functino call overheads

class Animal
{
	public:
	virtual void sound () = 0;

}; 

class Dog: public Animal
{
	int ntimesbarked;
	public:
	void sound ();
};
void Dog::sound () { ntimesbarked ++; }

class independent_cat
{
	int ntimesmeowed;
	public:
	void sound ();
};
void independent_cat::sound () { ntimesmeowed ++; }

void main ()
{
	Dog dog;
	Animal& animal = dog;
	independent_cat cat;
	time_t t1, t2;

	/* test virtual function call overhead */
	time ( &t1 );
	for ( int i = 0; i < 1000000000; i ++ )
	{
		animal.sound ();
	}
	time ( &t2 );

	printf ( "\n*********time to bark: %d\n", t2 - t1 );

	time ( &t1 );
	for (  i = 0; i < 1000000000; i ++ )
	{
		cat.sound ();
	}
	time ( &t2 );

	printf ( "\n*********time to meow: %d\n", t2 - t1 );

	getchar();

}
The result (VC++60):
unoptimized code - ratio is 4 (virtual function call) : 3 (direct call)
optimized code - ratio is 6 (virtual function call) : 4 (direct call)

So, bottomline, a direct function call invocation is 20-25% faster. That it would be faster is not a surprise, but I never thought it would amount to so much time.

Whats the meaning: Yes, OO and interfaces are cool and that, but I'd probably avoid using inheritance and virtuality for small, atomar objects. Better make some concessions and put several behaviours into one object than to pay for the abstract beauty of a design.

Notice that this is by no means an absolut rule. Whenever I can afford a good OO design, I do it.
niko
Site Admin
Posts: 1759
Joined: Fri Aug 22, 2003 4:44 am
Location: Vienna, Austria
Contact:

Post by niko »

Interesting. Ok, so never use virtual functions in huge mulitple inner loops in the core of important algorithms. :)
How long took it to do the 1000000000 calls? Would be interesting too.
keless
Posts: 805
Joined: Mon Dec 15, 2003 10:37 pm
Location: Los Angeles, California, USA

Post by keless »

what if you explicitly cast animal to dog before calling sound? does this get rid of the overhead?

currently ICE uses inheritance and virtuals as its base.
also, IrrLicht uses abstract base classes for its interfaces

perhaps its a matter of your Animal& animal ? or does this work out exactly the same as an Animal*, just with different syntax?
a screen cap is worth 0x100000 DWORDS
tstuefe
Posts: 40
Joined: Wed Jan 07, 2004 12:53 pm
Location: Heidelberg, Germany
Contact:

Post by tstuefe »

Niko:

debug build:
*********time to bark: 38

*********time to meow: 33

release build:
*********time to bark: 6

*********time to meow: 4

keless: the explicit cast does not bring anything. And it does not matter whether you use references or pointers, same result. AFAIK the overhead comes from the one indirection more the code flow has to go: no direct method call, but via vtable.

But, there are good news :-)
1) You only pay the overhead for virtual functions which are declared in a parent class and implemented in a child class (Example: the typical interface implementation as abstract base class in C++). You don't pay the overhead for functions which are already implemented in a parent class. So, if you have a bunch of classes which simply share the implementation of one function from the parent class, you don't.
An example for the latter is: Lets say you have tons of 3D objects, monsters, players, vehicles, projectiles, whatnot. All of them have a parent class CPosition, which keeps their position and orientation in space. You can call CPosition methods without penalty, as long as they are also implemented in CPosition.
2) Probably, the real ratio between virtual function call and real function call is in reality not as bad. The time penalty is paid for the function invocation and is amortized over the time the function takes. So, my example was almost the worst case, because I don't do much in that function.
Interesting. Ok, so never use virtual functions in huge mulitple inner loops in the core of important algorithms.
Yes, like that. The coolest thing would be: In a huge inner loop call a pure virtual getter function which does only a return value;. Extra points for not making this function inline. :-)
keless
Posts: 805
Joined: Mon Dec 15, 2003 10:37 pm
Location: Los Angeles, California, USA

Post by keless »

excellent information, thanks for posting this

"The time penalty is paid for the function invocation and is amortized over the time the function takes"
::whew:: :lol:
a screen cap is worth 0x100000 DWORDS
Post Reply