Performance of method calls

Bill Baxter wbaxter at gmail.com
Wed Nov 29 23:18:45 PST 2006


Daniel Keep wrote:
> Hi.
> 
> I'm currently working on a research project as part of my Honours, and 
> one of the requirements is speed--the code I'm writing has to be very 
> efficient.
> 
> Before I started, my supervisor warned me about object-oriented 
> programming and that it seems to be much slower than just flat function 
> calls.
> 
> Anyway, I was wondering what the difference between three kinds of 
> function calls would be:
> 
> 1. Foo x; x.call(); // Where Foo is a struct
> 2. Foo_call(x); // C-style API
> 3. auto y = new FooClass; y.call(); // Where call is final
> 
> I hooked up a test app which used a loop with 100,000 iterations for 
> each call type, and ran that program 100 times, and averaged the outputs.
> 
> #1 was 2.84 times slower than #2, and #3 was 3.15 times slower than #2. 
>  Are those numbers right??  Is it really that much slower?  I would have 
> thought that they should have been about the same since each one needs 
> to pass only one thing: a pointer.  I've attached the test programs I 
> used; if anyone can offer any insight or even corrections, I'd be very 
> grateful.
> 
> Incidentally, any other insights regarding performance differences 
> between OO-style and flat procedural-style would be very welcome.
> 
>     -- Daniel
> 
> 
> ------------------------------------------------------------------------
> 
> #!/bin/bash
> 
> for I in {1..100}; do
>     ./struct_calls
> done | awk '
>     BEGIN {sum1 = 0; sum2 = 0; count = 0;}
>     {sum1 += $5; sum2 += $11; count += 1;
>      print $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11;}
>     END {print "Averages: " sum1/count ", " sum2/count}
> ' | tee struct_calls.log
> 
> 
> 
> ------------------------------------------------------------------------
> 
> module struct_calls;
> 
> import std.perf;
> import std.stdio;
> 
> const COUNT = 100_000u;
> 
> struct Foo
> {
>     uint dummy;
> 
>     void call()
>     {
>         //this.dummy = arg;
>     }
> }
> 
> class FooClass
> {
>     uint dummy;
> 
>     final void call()
>     {
>         //this.dummy = arg;
>     }
> }
> 
> void Foo_call(Foo* _this)
> {
>     //_this.dummy = arg;
> }
> 
> void main()
> {
>     Foo x;
> 
>     scope perf = new HighPerformanceCounter();
> 
>     perf.start();
>     for( uint i=0; i<COUNT; i++ )
>         x.call();
>     perf.stop();
> 
>     // count1: x.call()
>     auto count1 = perf.periodCount();
> 
>     perf.start();
>     for( uint i=0; i<COUNT; i++ )
>         Foo_call(&x);
>     perf.stop();
> 
>     // count2: Foo_call(&x)
>     auto count2 = perf.periodCount();
> 
>     scope y = new FooClass();
> 
>     perf.start();
>     for( uint i=0; i<COUNT; i++ )
>         y.call();
>     perf.stop();
> 
>     // count3: y.call()
>     auto count3 = perf.periodCount();
> 
>     writefln("%d / %d = %f -- %d / %d = %f",
>             count1, count2, cast(real)count1 / cast(real)count2,
>             count3, count2, cast(real)count3 / cast(real)count2);
> }
> 


A call to a final method shouldn't be any slower than straight funciton 
call.  But I have heard grumblings that final in D doesn't actually work 
as spec'ed.

But anyway the main point of this reply is that even if method call is 
3x slower than function call, it really means nothing if function call 
overhead is 0.01% of your run time to begin with.  There's a popular 
thing to teach in computer architecture classes called "Amdahl's Law", 
and basically to paraphrase it says don't fixate on optimizing things 
that represent trivial fractions of the overall runtime to begin with. 
For example if method calls represents 0.03% of your overall runtime the 
BEST speedup you could achieve by eliminating all calls entirely would 
be 0.03%.  Pretty trivial.  It's like trying to figure out how to 
improve driving times from home to work, and focusing on increasing your 
speed in your driveway.  Even if you achieve a 100x speedup in how long 
you spend driving on your driveway, you've still only sped up the hour 
long drive by a second or two.  Not worth the effort.

In other words, for all but the most rare of cases, the benifits reaped 
in terms of code reability, maintainablity, and speed of development 
when using virtual functions vastly outweighs the tiny cost.

What you should do is put something representative of the work you 
actually plan to do inside those functions in your test program and see 
if the 3x difference in call speed actually makes any significant 
difference.

--bb



More information about the Digitalmars-d mailing list