Sign in to follow this  
warp X

c++ virtual function question

Recommended Posts

warp X    192
In my game I have code that calls virtual functions very much every frame. Would it be better/faster to call functions that are not virtual, but in them, test if there is a need for a virtual function call, and if is, then call? Sorry if this was not well put. Edit: What I mean is, that there isn't always a need. Actually mostly isn't.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Test it, but maybe your overhead for testing is much more expensive then just calling the virtual function. It's slower to call a virtual function but it's far from slow.
I don't think the improvement is worth the effort.

Share this post


Link to post
Share on other sites
Antheus    2409
Virtual calls are part of OO paradigm. If you find they are a problem (performance bottleneck), change the design not to use the OO aproach (use objects, but don't use inheritance).

Do not change anything at all, unless you have a performance problem. Just because something is used a lot, it makes no difference if it does not slow you down.

Share this post


Link to post
Share on other sites
rip-off    10979
Unless virtual function calls are posing a slowdown, and they shouldn't be, then don't bother. This is premature optimisation, avoid it.

The test would probably end up being about as expensive anyway, due to the overhead of maintiaining information about which functions are available. You are probably going to be accesing an object like so:


if( object->hasFunc )
{
object->func();
}


as opposed to

object->func();

My advice would be just to call it directly.

Share this post


Link to post
Share on other sites
Evil Steve    2017
As the AP said, don't test. It'll be even slower than calling the function. Virtual functions do have an overhead, but it's minimal; just two pointer dereferences usually (I think...).

EDIT: Way to slow [smile]

Share this post


Link to post
Share on other sites
jpetrie    13138
I wouldn't worry about it. You won't be able to "test if a virtual function call is needed" in any feasible way that will be faster than the compiler actually invoking the virtual call (you'll have to use dynamic_cast or typeid prior at the call site and that will be slower than the table lookup the compiler will do to find the correct virtual function and once you determine if the type wouldn't actually 'need' the vtable lookup you'll have to do a bunch of extra mucking about to get the compiler to not perform the lookup; its not worth it).

If you've profiled and determined that the virtual dispatch mechanism is actually taking up a signifigant bit of time (which I doubt) you may want to look into methods to reduce the number of virtual calls you make. But again, I really doubt its going to be a speed concern unless you are working on a very, very limiting platform.

EDIT: Way too slow :(

Share this post


Link to post
Share on other sites
warp X    192
Ok, thanks for advice. There is, however performace problems in my application. I am making a bird-view 2D war game with soldiers, tanks, etc. It is getting a bit slow, when you have tens and tens of soldiers there, and you got to detect collisions for them and for the projectiles they shoot. You also have AI routines for them that detect the closest enemy to fire at. So there is lots going on, lots of iterating through all the game objects. I did limit the collision detection so that it is not called on every frame anymore, which helped a bit. I am using collisionspheres.

In the collision detection routine you have to consider how many collisionspheres an object has, because it might have many.

A short story long, sorry for this, but don't read if you don't want to:

I did already this kind of optimization:

I had code like this:





virtual int GameObject::getCollisionSphereCount() { return 1; }
int Tank::getCollisionSphereCount() { return 2; }

I changed it into this:

int GameObject::collisionSphereCount;
GameObject::GameObject() { collisionSphereCount = 1; }
Tank::Tank() { collisionSphereCount = 2; }
int GameObject::getCollisionSphereCount() { return collisionSphereCount; } //*

//*this is in the gameobject.h -file so it's inline and all, right?

So this is a fair optimization, I think, right?




But, here's an other case I'm wondering if I should do:

I have code like this:

class GameObject { ... };
class Tank : public GameObject { ... };

float GameObject::x;
float GameObject::y;
struct CollisionSphere { float x, y, radius; }
virtual ColisionSphere GameObject::getCollisionSphere(int index = 0)
{
CollisionSphere cs;
cs.x = x;
cs.y = y;
cs.radius = collisionSphereRadius; //defined somewhere....
return cs;
}
collisionSphere Tank::getCollisionSphere(int index = 0)
{
if (index == 0)
return getCollisionSphere1(); //defnied somewhere...
else
return getCollisionSphere2(); //defnied somewhere...
}



Should I do this like this:

virtual CollisionSphere GameObject::getDynamicCollisionSphere(int index) { ... }
CollisionSphere Tank::getDynamicCollisionSphere(int index) { ... }
ColisionSphere GameObject::getCollisionSphere(int index = 0)
{
if (collisionSphereCount > 1)
getDynamicCollisionSphere(index);
else
{
CollisionSphere cs;
cs.x = x;
cs.y = y;
cs.radius = collisionSphereRadius; //defined somewhere...
}
return cs;
}

Edit: added class hieratchy desciription

Share this post


Link to post
Share on other sites
Evil Steve    2017
Profile. There's no point in blindly optimizing in the hope that what you're doing is improving performance. What IDE are you using? There's a few profilers about for Visual C, or you could write your own functions into your code.

I very much doubt that the virtual functions are your problem if you only have 10 units. If you had 1000 or more, then maybe the virtual function overhead would start to become a problem.

I'd recommend partitioning your map up using a quadtree or octree or some other spatial partitioning. After you've profiled your code and determined that the collision detection is a problem.

Share this post


Link to post
Share on other sites
warp X    192
You are right. It might be just waste of my time.
I am using Visual Studio .net 2003. Ok, I should learn that profiling thing, I haven't used that.

I have not decided yet what is the maximum number of units on screen. It will, of course, be affected by the overall performance. I hope there could be lots of units at the same time.

That space partitioning sounds interesting, but does it make a difference in a 2D game?

I'm using lots of math functions like pow, sqrt, sin, cos, etc. I have read that these might be slow. Should I consider optimizing the math? I'm for example determining object distances with pythagoras like this: distance = sgrt(pow(a, 2), pow(b, 2)).

Edit: thank you for banging some wisdom into my thick skull.

Share this post


Link to post
Share on other sites
Evil Steve    2017
Quote:
Original post by warp X
I'm using lots of math functions like pow, sqrt, sin, cos, etc. I have read that these might be slow. Should I consider optimizing the math? I'm for example determining object distances with pythagoras like this: distance = sgrt(pow(a, 2), pow(b, 2)).
Again, only optimize them if you know it's a problem. One optimization you can make (and should be making) is to use squared distances wherever possible, that saves you a sqrt() call. If you just want to check bounding spheres / circles for instance, you only need to check if the squared distance causes them to instersect, there's no need to get the actual distance.

I've used DevPartner Profiler with VC 2003, and I'm very happy with it. It's simple to use, and integrates into Visual Studio nicely.

Share this post


Link to post
Share on other sites
_BTK_    128
I have found out that if you have to use virtual functions then the virtual function sollution is almost always faster than non-virtual one. If you have to test if some function is some type you have then lost that potential speed gain because virtual functions have to have one(?) indirection and in that if almost always have more commands than that indirection.

Share this post


Link to post
Share on other sites
Evil Steve    2017
Quote:
Original post by warp X
Thank you very much Steve. But what is that 'squared distances' you mentioned? Without sqrt? I must check that out.
Yup. Instead of doing float dist = sqrt(x*x + y*y); you can do float dist_squared = x*x + y*y; in most places. If you're going to check for a collision between two objects using a bounding sphere, then you'd normally do this:

struct Unit
{
float x, y; // Position of unit
float fRadius; // Radius of bounding sphere
};

bool IsCollision(const Unit& u1, const Unit& u2)
{
float x = u2.x - u1.x;
float y = u2.y - u1.y;
float fDist = sqrt(x*x + y*y);
if(fDist < u1.fRadius+u2.fRadius)
return true;
return false;
}



But you don't need to bother with the sqrt there, you could square the bounding sphere size instead:

struct Unit
{
float x, y; // Position of unit
float fRadius; // Radius of bounding sphere
};

bool IsCollision(const Unit& u1, const Unit& u2)
{
float x = u2.x - u1.x;
float y = u2.y - u1.y;
float fDistSq = x*x + y*y;
if(fDistSq < u1.fRadius*u1.fRadius + u2.fRadius*u2.fRadius)
return true;
return false;
}



Which will have the same effect, but will be less costly.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this