Skip to main content
gamedev.net
🔒 Locked

c++ virtual function question

Started by warp X 13 replies 4k views
Original Post
warp X
warp X
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.
"I got stuck between levels 4 and 5 and got into this strange place: warp X..."
Tera_Dragon
Tera_Dragon
Sounds to me as though that would be just as slow (maybe more so) than just calling a virtual method.
____________________________________________________________Programmers Resource Central
Antheus
Antheus
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.

rip-off
rip-off
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.
Evil Steve
Evil Steve
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]
jpetrie
jpetrie
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 :(
warp X
warp X
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
"I got stuck between levels 4 and 5 and got into this strange place: warp X..."
Evil Steve
Evil Steve
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.
warp X
warp X
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.
"I got stuck between levels 4 and 5 and got into this strange place: warp X..."
Evil Steve
Evil Steve
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.
_BTK_
_BTK_
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.
warp X
warp X
Thank you very much Steve. But what is that 'squared distances' you mentioned? Without sqrt? I must check that out.
"I got stuck between levels 4 and 5 and got into this strange place: warp X..."
Evil Steve
Evil Steve
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.
warp X
warp X
Of course. Thanks!
"I got stuck between levels 4 and 5 and got into this strange place: warp X..."

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.