does virtualizing all methods slow C++ down ?

L

Lynn McGuire

Does virtualizing all methods slow C++ down ? We
virtualize all methods as a matter of course since
we use groups of objects all over the place. To
illustrate this I have included the top portion of
our header files:

class GenGroup : public DataGroup
{
public:
int transferingDataNow;
public:
// constructor
GenGroup ();
GenGroup (const GenGroup & rhs);
GenGroup & operator = (const GenGroup & rhs);
// destructor
virtual ~GenGroup ();
virtual GenGroup * clone () { return new GenGroup ( * this); }
virtual void makeUnitsInput (InputCollection * anInpCol);
virtual void reinitStreamBox (FmFile * FMFile);
virtual DataDescriptor * descriptor (int aSymbol, int version);
....

Thanks
Lynn
 
C

Christopher

Does virtualizing all methods slow C++ down ?  We
virtualize all methods as a matter of course since
we use groups of objects all over the place.  To
illustrate this I have included the top portion of
our header files:

class GenGroup : public DataGroup
{
public:
    int transferingDataNow;
public:
       //  constructor
    GenGroup ();
    GenGroup (const GenGroup & rhs);
    GenGroup & operator = (const GenGroup & rhs);
       //  destructor
    virtual ~GenGroup ();
    virtual GenGroup * clone () { return new GenGroup ( * this); }
    virtual void makeUnitsInput (InputCollection * anInpCol);
    virtual void reinitStreamBox (FmFile * FMFile);
    virtual DataDescriptor * descriptor (int aSymbol, int version);
...

Thanks
Lynn

If you virtualize one, there is no cost for virtualizing the others.
There is a cost associated with virtualizing one method. See the FAQ.

I wouldn't virtualize every single method in every single class
though. That is just not thoughtful design. When I see a virtual
method, I assume the author INTENDED for the class to be derived from.
Surely, you have a concrete class somewhere.
 
A

Alain Ketterlin

Lynn McGuire said:
Does virtualizing all methods slow C++ down ? We
virtualize all methods as a matter of course since
we use groups of objects all over the place.

Not sure I understand what you mean, but yes, virtualizing all
(non-really-virtual) methods will slow things down, in cases where the
compiler cannot statically decide the class where the method is defined.
In the worst case:

- all calls through a reference or pointer will be indirect calls
- all other calls will be direct calls.

The branch predictor may help here, but you still pay some price. In
your example:
virtual GenGroup * clone () { return new GenGroup ( * this); }

the compiler would normally (probably) inline any call to this method in
the non-virtual case. With virtual, all calls to this method through a
ref/pointer will be translated into an indirect call.

(I know, cloning usually requires dynamic binding, I used this example
because it was the only method potentially inlinable.)

C++11 provides the "final" qualifier, which may help here. Whether it is
taken into account depends on your compiler.

-- Alain.
 
L

Lynn McGuire

If you virtualize one, there is no cost for virtualizing the others.
There is a cost associated with virtualizing one method. See the FAQ.

I wouldn't virtualize every single method in every single class
though. That is just not thoughtful design. When I see a virtual
method, I assume the author INTENDED for the class to be derived from.
Surely, you have a concrete class somewhere.

We have so many methods in our 600 classes and 700K lines
of code that we are not sure what needs to be virtual and
does not. So we do all to keep from missing 1, 2 or 20.

Thanks,
Lynn
 
L

Lynn McGuire

Not sure I understand what you mean, but yes, virtualizing all
(non-really-virtual) methods will slow things down, in cases where the
compiler cannot statically decide the class where the method is defined.
In the worst case:

- all calls through a reference or pointer will be indirect calls
- all other calls will be direct calls.

The branch predictor may help here, but you still pay some price. In
your example:


the compiler would normally (probably) inline any call to this method in
the non-virtual case. With virtual, all calls to this method through a
ref/pointer will be translated into an indirect call.

(I know, cloning usually requires dynamic binding, I used this example
because it was the only method potentially inlinable.)

C++11 provides the "final" qualifier, which may help here. Whether it is
taken into account depends on your compiler.

-- Alain.

Thanks, I had not thought about the direct calls just
directly binding to the proper method. I'll bet that
there are few direct calls in our code though as we
have many children classes.

ObjPtr -> DataGroup -> GenGroup

ObjPtr -> DataGroup -> NodeGroup -> StreamGroup

are a couple of example lineages.

Lynn
 
C

Christopher

We have so many methods in our 600 classes and 700K lines
of code that we are not sure what needs to be virtual and
does not.  So we do all to keep from missing 1, 2 or 20.

Thanks,
Lynn- Hide quoted text -

- Show quoted text -


Bad design doesn't make up for a bad process.

Surely, you have unit tests for these classes? Surely those tests
would show whether the expected behavior of a method call resolving to
the derived vs the base is occurring?
 
J

jacob navia

Le 06/09/11 21:13, Lynn McGuire a écrit :
Thanks, I had not thought about the direct calls just
directly binding to the proper method. I'll bet that
there are few direct calls in our code though as we
have many children classes.

ObjPtr -> DataGroup -> GenGroup

ObjPtr -> DataGroup -> NodeGroup -> StreamGroup

are a couple of example lineages.

Lynn

This is completely ridiculous. An indirect call vs a direct call
will cost you some pipeline turbulence and the cache may be flushed,
really not a big deal.

Have you MEASURED the slowdown? Is it significant in relationship
to OTHER improvements in your code?

Have you profiled your code to KNOW where it is spending 90% of the
time?

Before you answer THOSE questions, worrying about direc/indirect
calls is WASTED time and effort.
 
A

Alain Ketterlin

jacob navia said:
Le 06/09/11 21:13, Lynn McGuire a écrit :

This is completely ridiculous. An indirect call vs a direct call
will cost you some pipeline turbulence and the cache may be flushed,
really not a big deal.

Depends on the code. With lots of small methods (a la Java, with
getters/setters all over the place), it may be significant, mainly
because of the impossibility to inline. Take any program, compile it
with inlining disabled: the difference may be significant.
Have you MEASURED the slowdown? Is it significant in relationship
to OTHER improvements in your code?

Hard to measure. You need to change tens/hundreds of classes...
Have you profiled your code to KNOW where it is spending 90% of the
time?

In the case I mention above (many small functions), the overhead would
be spread over a large part of the code. Profiling becomes less useful.
Before you answer THOSE questions, worrying about direc/indirect
calls is WASTED time and effort.

I've just done this on a piece code that was evaluating an expression
tree on each vertex of a 4D grid, with an insane number of
floating-point ops. Incredible speedup (~120). Granted, the original was
over-engineered, and this may be a corner case.

Regarding Lynn's case, I would say you're right: he may be better off
keeping his current design safe rather than trying to save a few cycles.

-- Alain.
 
L

Lynn McGuire

Le 06/09/11 21:13, Lynn McGuire a écrit :

This is completely ridiculous. An indirect call vs a direct call
will cost you some pipeline turbulence and the cache may be flushed, really not a big deal.

Have you MEASURED the slowdown? Is it significant in relationship
to OTHER improvements in your code?

Have you profiled your code to KNOW where it is spending 90% of the
time?

Before you answer THOSE questions, worrying about direc/indirect
calls is WASTED time and effort.

I am not planning on changing our design, it works very well
and gets an amazing amount of work done in the amount of
code written. After reading the "Generally, are the programs
written by C++ slower than written by C 10% ?" thread, I was
just wondering about the major difference between C and C++
in our code. In the long and short runs, I would say that
the overhead is more than worth the automatic object method
lookups. More than !

Thanks,
Lynn
 
L

Lynn McGuire

Depends on the code. With lots of small methods (a la Java, with
getters/setters all over the place), it may be significant, mainly
because of the impossibility to inline. Take any program, compile it
with inlining disabled: the difference may be significant.


Hard to measure. You need to change tens/hundreds of classes...


In the case I mention above (many small functions), the overhead would
be spread over a large part of the code. Profiling becomes less useful.


I've just done this on a piece code that was evaluating an expression
tree on each vertex of a 4D grid, with an insane number of
floating-point ops. Incredible speedup (~120). Granted, the original was
over-engineered, and this may be a corner case.

Regarding Lynn's case, I would say you're right: he may be better off
keeping his current design safe rather than trying to save a few cycles.

-- Alain.

You are more than correct, I was just wondering. In fact, we
saved millions of cycles by porting our code from Smalltalk
to C++. We had to do it anyway, our Smalltalk variant was
Win16 (don't even go there !) without a Win32 port. I would
not be surprised if we got a 100X speedup by converting to
C++ and Win32. Our current design is solid and will not be
changed - we have many other dragons to slay.

Thanks,
Lynn
 
K

Kevin P. Fleming

Bad design doesn't make up for a bad process.

Surely, you have unit tests for these classes? Surely those tests
would show whether the expected behavior of a method call resolving to
the derived vs the base is occurring?

.... and surely you have a compiler that is able to warn you when a
derived class overrides a non-virtual member function in one of its base
classes?
 
T

Thomas J. Gritzan

Does virtualizing all methods slow C++ down ?
[...]

If you virtualize one, there is no cost for virtualizing the others.
There is a cost associated with virtualizing one method. See the FAQ.

That's not true.

It is true that the size of an object increases for the first virtual
function you add, but not for further virtual functions (for usual
vpointer implementations).
However, _every_ function might be slower when called virtually, because
the compiler has less potential for optimization (function inlining etc)
than for non-virtual functions.
 
N

Nobody

If you virtualize one, there is no cost for virtualizing the others.
There is a cost associated with virtualizing one method. See the FAQ.

That only deals with the memory cost. There is also a potential speed cost
for every virtual method call.
 
J

Juha Nieminen

Lynn McGuire said:
Does virtualizing all methods slow C++ down ?

The cost of calling a virtual function (compared to calling a normal
member function) is often greatly exaggerated. I once tested the speed
difference myself and the difference was not measurable (in other words,
both tests returned time values that were so close together that even
the variance between runs of the same test were larger).

Of course my sample size is that of 1 (iow. I have tested it only in
one system with one compiler, using one specific test), so the result is
far from definitive. However, it does tell me that the difference is
quite minuscule in practice, and often overwhelmed by everything else
that happens when calling a function (pushing parameters onto the stack
and so on, which, depending on the amount and type of parameters, will
probably take a lot more clock cycles than the indirect virtual function
call.)

However, this is comparing virtual functions with regular *non-inlined*
functions. Function inlining can have a much greater difference, and if
you virtualize an inline function, it might slow it down significantly
in comparison. (Either the compiler will not inline it at all, or else
it will have to add some kind of runtime conditional in the compiled code
to check if the function has been overridden.) Thus if you have for example
some really small getter/setter functions that are better inline and really
don't need to be virtual, don't make them.
 
G

Goran

Does virtualizing all methods slow C++ down ?  We
virtualize all methods as a matter of course since
we use groups of objects all over the place.

Yes, it's obviously slower to go through a virtual method than not.
Compiler might turn some of those into non-virtual and even inline it.
As others have said, you probably can't notice the slowdown. Not
unless something really degenerate is happening in the code (like,
you're spending most of the complete program time virtually calling
functions that are very shot and aren't virtual "in practice").

However, going "all virtual" is IMO pretty dumb. While it might look
as "designing for the future", in practice, it's nothing of the sort.
I think that you should try looking at your virtual functions and
check how many of them are actually overridden in derived classes, and
how. I bet you that overridden version can either be trivially
refactored back into a base class, or it requires so much knowledge of
the base's internals that it's going impossible to change the base
without affecting all derived classes. That "coupling through
inheritance" is poor design.

Goran
 
J

Jorgen Grahn

.
You are more than correct, I was just wondering. In fact, we
saved millions of cycles by porting our code from Smalltalk
to C++.

That explains a lot about that "virtual everywhere" design. Go look in
"The C++ Programming Language"; Stroustrup has a few things to say
about using C++ as if it was Smalltalk.
Our current design is solid and will not be
changed - we have many other dragons to slay.

It may not be highest priority, but I still think there's something
seriously wrong with having the code this way -- especially if you
have design rules to forbid normal C++ in new or rewritten code.

My guess (which is only a guess) is that the worst penalty is that it
discourages the use of small classes, wrappers and helper functions
which would make the code more readable. Inlining makes such things
cost-free, but if you don't have inlining you probably think twice
before doing such simplifications (at least I do).

/Jorgen
 
J

Jorgen Grahn

How "obviously"? Do you have any actual measurement results?

Surely it's obvious? Even TC++PL says so in various places.

If it's /measurably slower/ in a real situation is another thing. I
guess it very rarely is -- except for the missed opportunities for
inlining which many have mentioned.

/Jorgen
 
G

Goran

  How "obviously"? Do you have any actual measurement results?

Obviously, no ;-). Do you really think it's the same/faster?

I was merely alluding to the usual implementation with call
instruction being read off the virtual method table. Hopping twice
(more, really) can't be faster than once :).

Goran.
 
J

Juha Nieminen

Goran said:
Obviously, no ;-). Do you really think it's the same/faster?

"Obviously" just could as well mean "significantly" (iow. the slowdown
is "obvious", ie. very noticeable).

From my own tests there's no practical difference between a virtual
function call and a regular function call. Even if there's a clock cycle
or two of difference, it's so small that this difference gets completely
buried under everything else that is happening.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top