Archived

This topic is now archived and is closed to further replies.

Getting Rid of overhead of virtual functions

This topic is 5399 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I''ve read that there is significant overhead on heavily using virtual functions, and was curious if there is a common way to alleviate this overhead. In my case I am using a base win32 wrapper class which contains a number of virtual functions such as: getSurface(), drawLine(Point p1, Point p2, ColorRGB color) and a multitude of other functions including stuff for rendering a triangle strip, getting a list of vertices for a triangle strip/fan, etc... Needless to say 90% of my program will be calling and using virtual functions, but this is the only really decent way to write the program to allow for seamless use of DirectX or OpenGL, which is what I want to do. If there is overhead its going to bite me soon, and I''m trying to get rid of it before the project becomes too large to change within a reasonable time frame. Anyhow, what''s the common opinion on implementing virtual functions and their overhead? Thanks. The project is written in C++/VC7.0.

Share this post


Link to post
Share on other sites
The DirectX API uses interfaces, which are basically classes populated only with virtual functions. The overhead might show up if you go crazy with virtual functions, but otherwise I wouldn''t worry about it. It''s never affected me before.

Someone correct me if it''s a more serious problem than I think it is.

Share this post


Link to post
Share on other sites
quote:

I''ve read that there is significant overhead on heavily
using virtual functions, and was curious if there is a
common way to alleviate this overhead.



If you need run-time dispatch, you''ll find out that you need each and every step a virtual function call does, and that talking of "overhead" is complete nonsense. Overhead compared to what ? Non-virtual function calls don''t offer the same functionality. You want the functionality, you pay the price.

And figuring out whether you need it or not is part of a programmer''s job.

In the most common implementation, the overhead consists in looking up the function address in a table instead of having it ''hard-coded''. The table is selected by a hidden pointer stored in every object of classes which have virtual functions.

On the other hand, when the compiler knows unambiguously the type of the object (Foo f; f.vfunc();), it usually directly generates the right address.

If only for this reason, you don''t want to reimplement virtual functions yourself. Odds are the compiler won''t go "Aha ! He''s trying to reimplement virtual functions !", and generate code less efficient than for what it knows to be virtual functions.

At any rate, the overhead is not significant unless you are calling such a function repeatedly in a tight loop. If you know you have an homogeneous set of objects (all Foos), you can dispense from the virtual function call, and use a non-virtual function ( define two functions, the virtual one calls the non-virtual - or, with gcc and borland c++ you can ''freeze'' the virtual function, but not with VC). If not, you don''t have a choice.


[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]

Share this post


Link to post
Share on other sites
As mentioned, the calling overhead is minimal compared to the functionality you gain. The only other aspect to consider is that of memory. If you are working in a very tight memory model, you should be aware that virtual functions can take up to three times as much memory to make the call (I don''t know why exactly, it''s something to do with creating additional pointers for the virtual pointing). But as the non-virtual pointers take up very little memory anyway, you would have to be using an extremely limited memory model before this became an issue.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
quote:
Original post by haro
Needless to say 90% of my program will be calling and
using virtual functions, but this is the only really
decent way to write the program to allow for seamless
use of DirectX or OpenGL, which is what I want to do.
Not really the only decent way. With a heavy use of templates, you could have two totally separate class systems: one for OpenGL, one for DirectX. There''s no need to mix between these two so templates would work out well, and you could get rid of ALL the virtual functions whose sole purpose is to enable the use of both OpenGL and DirectX. BUT: your compile times would increase significantly since every class should be templatized and template classes must be placed on headers (so long, precompiled code).

Okay, so maybe templates don''t qualify as a ''decent way''.

Share this post


Link to post
Share on other sites
it''s not just compile times that would increase. there would be a significant increase in the size of the executable produced when you make heavy use of templates.

Share this post


Link to post
Share on other sites
quote:
Original post by Damocles
If you are working in a very tight memory model, you should be aware that virtual functions can take up to three times as much memory to make the call (I don''t know why exactly, it''s something to do with creating additional pointers for the virtual pointing).



Pointers to virtual member functions may indeed be larger than pointers to non-virtual member functions, but that doesn''t affect you unless you are explicitely creating such a pointer. The compiler doesn''t need them to make a call.

The only real memory cost is the virtual function table pointer in each object. If the objects are otherwise small and you have many of them, that cost may be significant. The cost of the virtual function tables itself is insignificant, unless you have billions of classes, which would either mean an astronomical object count or a really inept programmer.

And don''t go about creating your own type field, it won''t buy you anything in practice in most cases and will become a maintenance nightmare in short time.

quote:
Original post by daerid
The curiously recurring template pattern can also be used in some situation.


That''s a structural pattern, not a behavioral pattern.
It saves you some typing, but does nothing at run-time.


[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]

Share this post


Link to post
Share on other sites
quote:
Original post by Fruny
That''s a structural pattern, not a behavioral pattern.
It saves you some typing, but does nothing at run-time.



It''s a way to simulate inheritance without having vtables or virtual function pointers.

Share this post


Link to post
Share on other sites
please note, I agree with everyone who said you shouldn''t try to reinvent virtual functions, because really the cost you pay is as low as it can possibly be for the run time functionality ... but let''s talk about what that is, and which parts you need ...

there are two things a virtual function gives you, 1 it gives the the same functionality as any other usage of run-time function pointers, and at the exact same cost as if hand coded in C. 2 it makes it easy to overload the function, with other function of the exact same type, because the comipler does all the figuring for you, and all the mapping to correct function ... so it simple eases the job of code management.

In the case you speak of, about wanting to seamlessly switch between DirectX and OpenGL impelentations, you do not actually need virtual functions ... bear with me a minute, and I''m note saying they are wrong or bad here, just not technically needed .. here''s why

You have absolutely no intention of mixing and matching DirectX and OpenGL components with each other at run-time, so you have no need of run-time polymorphism ... what you need is either compile-time polymorphism, or some manual code management ...

For example, if you wanted the base class Render class to store a base class Buffer pointer ... instead the DirectXRender class could store a DirectXBuffer pointer ... and the OpenGLRender class an OpenGL pointer ... so here we do not actually need polymophism ... but if you don''t use virtual functions, the question becomes, how do you make sure changes to 1 class heirarchy (such as bug fixes, or feature additions) get added into the other class tree, at little development cost, and without adding errors ... well, you can use templates (which are awesome when applicable, and almost never a bad idea) ... or you can use some sort of silly cocked up precompiler system using defines .. so that each library gets generated from the same base code .. but chances are this would take to long, and not really help ...

My actual guess for the best way to implement it is this ... Either use templates OR virtual functions .. and then after your done, and you have it working, THEN make the two trees different (selectively replacing virtual functions with normal functions, and base class pointers, with derived class pointers)in the places where the profiler tells you there is too much time spent ...

Share this post


Link to post
Share on other sites
quote:
Original post by daerid
It's a way to simulate inheritance without having vtables or virtual function pointers.



Assuming you meant polymorphism ( the curiously recurring template pattern already involves inheritance, so it doesn't "simulate" it ), you'll still only get compile-time polymorphism.


template<class T> class Base {};
class Derived : Base<Derived> {};


Unless you're doing template metaprogramming, the CTRP offers little advantage in that respect. With public inheritance, a virtual destructor is still needed. With private inheritance, you need a set of using-declarations, which negate any advantage the CRTP offers.

Its main use is to not have to rewrite code that relies on the type of the leaf :

    
class Cloneable
{
virtual Cloneable* Clone() const = 0;
virtual ~Cloneable();
};

template<class T>
class CloneableCRTP : public Cloneable
{
virtual T* Clone() const { return new T(*(T*)this); }
// Return Cloneable* if you don't have covariant return type support.

};

class Foo : public CloneableCRTP<Foo> {};


Of course, if I am wrong, feel free to correct me.


[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]


[edited by - Fruny on March 2, 2003 10:19:41 PM]

Share this post


Link to post
Share on other sites
You can chase fairy tales, myths and wild geese or you can use your time productively. This is not a productive use of your time. You will certainly run into situations where a virtual function call is the source of a performance problem or at least making a major contribution to it. When you do though the solution will be to eliminate the call. I just can''t picture a situation where the actual "virtual" part of it is the problem. Far more likely is that the function call period is the problem.

Share this post


Link to post
Share on other sites
quote:
Original post by Damocles
As mentioned, the calling overhead is minimal compared to the functionality you gain. The only other aspect to consider is that of memory. If you are working in a very tight memory model, you should be aware that virtual functions can take up to three times as much memory to make the call (I don''t know why exactly, it''s something to do with creating additional pointers for the virtual pointing). But as the non-virtual pointers take up very little memory anyway, you would have to be using an extremely limited memory model before this became an issue.


I''ve have heared (but not specifically tested, sorry) that the greatest performance reduction that comes with virtual function is that you can''t inline them. This could lead to a loss of 20% in execution time, if your functions are small and called very often.

Share this post


Link to post
Share on other sites
Last time I wrote a similar application to yours, I used function pointers to implement it. I simply make a list of functions that are required, and load them from whatever .dll file you pass the function. So, I can write the graphics code, or update it, or add new ones, or have other people add them, without even recompiling my game code. It was basically a plugin graphics system.

Share this post


Link to post
Share on other sites
quote:
Original post by Ready4Dis
Last time I wrote a similar application to yours, I used function pointers to implement it. I simply make a list of functions that are required, and load them from whatever .dll file you pass the function.

You mean you reinvented COM without the compiler neutrality? Aww... that''s cute.

Share this post


Link to post
Share on other sites
quote:
Original post by Lorenzo
I''ve have heared (but not specifically tested, sorry) that the greatest performance reduction that comes with virtual function is that you can''t inline them.



inline = Replace the function call by this bit of code NOW.
virtual = I''ll tell you what function to call at run-time.

Knowing that, the incompatibility is obvious.

quote:

This could lead to a loss of 20% in execution time, if your functions are small and called very often.



As compared to what ? A non-virtual function call ? Their roles and semantics are different - compile-time dispatch vs. run-time dispatch - so the difference in execution time is irrelevant. A meaningful comparison would be between a virtual function and hand-coded dynamic dispatch.

Of course, a programmer who uses a virtual function call where it is not needed will see a drop in performance. But that''s ultimately due to a program design error (improper call semantics) than to a problem with the virtual function mechanism, which is why I am reluctant to use the term ''overhead'' which implies pointless inefficiency.

Additionally, I should point out that careless inlining may be just as nefarious as improper use of virtual functions : over-inlining will cause code bloat, cache hitrate drop, forced inlining can cause potential semantic errors (the interactions of inline and static are fascinating).

Learn to use what each language feature is for, and use it where you need to, and nowhere else.



[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]

Share this post


Link to post
Share on other sites
quote:
Original post by Lorenzo
I''ve have heared (but not specifically tested, sorry) that the greatest performance reduction that comes with virtual function is that you can''t inline them.

They can be inlined, but it would be prohibitively expensive.
quote:

This could lead to a loss of 20% in execution time, if your functions are small and called very often.

20%?

Share this post


Link to post
Share on other sites
quote:
Original post by Fruny

inline = Replace the function call by this bit of code NOW.
virtual = I''ll tell you what function to call at run-time.



I know what is inline, thanks....

quote:

Knowing that, the incompatibility is obvious.



Oh, Yeah... what I meant is that if you really don''t need virtual calls, you must avoid them. Duplicate the code, if necessary. If you have code for an OpenGL renderer and a DirectX renderer, compile them separately in two DLLs or static LIBs. Expose externally only long methods, (methods that do a lot of stuff) and don''t make virtual anything like void addVertex() or drawLine()

quote:

As compared to what ? A non-virtual function call ? Their roles and semantics are different - compile-time dispatch vs. run-time dispatch - so the difference in execution time is irrelevant.



Why their roles are different? You can do anythingh you can with a virtual call using non-virtual function call and templates.

quote:

Additionally, I should point out that careless inlining may be just as nefarious as improper use of virtual functions : over-inlining will cause code bloat, cache hitrate drop, forced inlining can cause potential semantic errors (the interactions of inline and static are fascinating).



That''s true... but very rare. If you let your compiler decide what functions inline for you, you''ll gain a performance boost.

Share this post


Link to post
Share on other sites
quote:
Original post by Lorenzo
Why their roles are different? You can do anythingh you can with a virtual call using non-virtual function call and templates.

Using templates, you cannot rely on information obtained at compile-time to despatch a call. For example, imagine you are deserialising a file. You have a Virtual Constructor which chooses concrete instantiations based on a type-code held in the file, and it returns a pointer to the base class through which you interact with the instantiations. Now call a virtual function through the base class pointer. How do you despatch the call with templates, given you obtained the information from a file? Some decisions have to be made during run-time, and that''s what virtual functions are for.

Share this post


Link to post
Share on other sites
quote:
Original post by SabreMan
[quote]Original post by Lorenzo
Why their roles are different? You can do anythingh you can with a virtual call using non-virtual function call and templates.

Using templates, you cannot rely on information obtained at compile-time to despatch a call. For example, imagine you are deserialising a file. You have a Virtual Constructor which chooses concrete instantiations based on a type-code held in the file, and it returns a pointer to the base class through which you interact with the instantiations. Now call a virtual function through the base class pointer. How do you despatch the call with templates, given you obtained the information from a file? Some decisions have to be made during run-time, and that''s what virtual functions are for.

In the case-study you propose, I''ll use a design patterm, maybe Generic Factory + chain of responsibility. Register the file readers in an hash table or a vector, using the type/code as a key, and return an instance of the associated handler.

I agree with you that with templates I can''t obtain information at run-time, but often you can design your application in a little different manner and avoid virtual functions.

Share this post


Link to post
Share on other sites