Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Speed test: Virtual Function VS Normal Function

1 view
Skip to first unread message

Skybuck Flying

unread,
Jan 10, 2007, 9:17:55 AM1/10/07
to
Hello,

Are virtual functions slower or faster than normal functions ?

I think CPU tricks at play... not sure though...

(Also setting vMaxCalls 10.000 causes sound squeek from computer case ;))

Generated Assembler Code included.

*** Begin of Code ***

program Project1;

{

Performance test to determine if normal or virtual functions are faster.

Sometimes normal functions always faster, sometimes virtual functions always
faster.

Explanations ?

}

{$APPTYPE CONSOLE}

{$DEFINE DEBUG_OFF}
{$DEFINE PERFORMANCE_TEST_ON}
{$DEFINE DISPLAY_PERFORMANCE_TEST_OFF}
{$DEFINE DISPLAY_WINNER_ON}
uses
SysUtils

{$IFDEF PERFORMANCE_TEST_ON}
,Windows;
{$ELSE}
;
{$ENDIF}

// Care must be taken to place the parenthesis around the conditional
directive as follows:
// {$DEFINE conditional} otherwise it won't work !
// for example:
// {
// $DEFINE conditional
// }
// ^^^ won't work !!! ARGH >D


type
Tmother = class
public
mMotherField : longword;
procedure Test; virtual;
end;

Tchild = class(Tmother)
public
procedure Test; override;
end;

TgrandChild = class(Tchild)
public
mGrandChildField : longword;

procedure Test; override;

procedure NormalTest;
end;

procedure Tmother.Test;
begin
writeln('Tmother.Test');
end;

procedure Tchild.Test;
begin
writeln('Tchild.Test');
end;

procedure TgrandChild.Test;
begin
{$IFDEF DEBUG_ON}
writeln('TgrandChild.Test');
{$ENDIF}
{$IFDEF PERFORMANCE_TEST_ON}
// must do some work.. otherwise call might be optimized away..
// mMotherField := mMotherField + 1; // not necessary
{$ENDIF}
end;

procedure TgrandChild.NormalTest;
begin
{$IFDEF DEBUG_ON}
writeln('NormalTest');
{$ENDIF}
{$IFDEF PERFORMANCE_TEST_ON}
// must do some work.. otherwise call might be optimized away..
// mGrandChildField := mGrandChildField + 1; // not necessary
{$ENDIF}
end;

var
vMother : Tmother;
vIndex : longword;

{$IFDEF PERFORMANCE_TEST_ON}
vFrequency : int64;
vCalls : int64;
vTick1 : int64;
vTick2 : int64;
vMaxCalls : int64;

vVirtualTime : double;
vNormalTime : double;
{$ENDIF}

begin

vMother := TgrandChild.Create;

vMother.Test;
TgrandChild(vMother).NormalTest;

while true do
begin

{$IFDEF PERFORMANCE_TEST_ON}
// initialize frequency for performance test
QueryPerformanceFrequency(vFrequency);

// initialize maximum calls
// vMaxCalls := 10 * 1000; // SQUEEK SOUND COMING FROM COMPUTER AT THIS
SETTING ?!
vMaxCalls := 10 * 1000 * 1000;
{$ENDIF}


{$IFDEF PERFORMANCE_TEST_ON}
{$IFDEF DISPLAY_PERFORMANCE_TEST_ON}
writeln('Performing ', Trim( Format( '%16.0n', [vMaxCalls/1.0] ) ), ' calls
for vMother.Test (virtual function)...');
{$ENDIF}
vCalls := 0;
QueryPerformanceCounter( vTick1 );
repeat
vMother.Test;
vCalls := vCalls + 1;
until vCalls = vMaxCalls;
QueryPerformanceCounter( vTick2 );
{$IFDEF DISPLAY_PERFORMANCE_TEST_ON}
writeln( 'Calls: ', Trim( Format( '%16.0n', [vCalls/1.0] ) ) );
{$ENDIF}
vVirtualTime := (vTick2 - vTick1) / vFrequency;
{$IFDEF DISPLAY_PERFORMANCE_TEST_ON}
writeln( 'Time: ', vVirtualTime:16:16, ' seconds.' );
{$ENDIF}
{$ENDIF}


{$IFDEF PERFORMANCE_TEST_ON}
{$IFDEF DISPLAY_PERFORMANCE_TEST_ON}
writeln('Performing ', Trim( Format( '%16.0n', [vMaxCalls/1.0] ) ), ' calls
for vMother.NormalTest (normal function)...');
{$ENDIF}
vCalls := 0;
QueryPerformanceCounter( vTick1 );
repeat
TgrandChild(vMother).NormalTest;
vCalls := vCalls + 1;
until vCalls = vMaxCalls;
QueryPerformanceCounter( vTick2 );
{$IFDEF DISPLAY_PERFORMANCE_TEST_ON}
writeln( 'Calls: ', Trim( Format( '%16.0n', [vCalls/1.0] ) ) );
{$ENDIF}
vNormalTime := (vTick2 - vTick1) / vFrequency;
{$IFDEF DISPLAY_PERFORMANCE_TEST_ON}
writeln( 'Time: ', vNormalTime:16:16, ' seconds.' );
{$ENDIF}
{$ENDIF}

{$IFDEF PERFORMANCE_TEST_ON}
{$IFDEF DISPLAY_WINNER_ON}
if vVirtualTime < vNormalTime then
begin
writeln('Winner: Virtual function, ', (vNormalTime - vVirtualTime):16:16,
' seconds faster. Calls: ', Trim( Format( '%16.0n', [vMaxCalls/1.0] ) ) );
end else
if vVirtualTime = vNormalTime then
begin
writeln('No winner (EQUAL)');
end else
begin
writeln('Winner: Normal function, ', (vVirtualTime - vNormalTime):16:16, '
seconds faster. Calls: ', Trim( Format( '%16.0n', [vMaxCalls/1.0] ) ) );
end;
{$ENDIF}

{$ENDIF}

end;

// This test is kinda weird... at first the virtual function was winning...
but later on the normal function was winning.

// Maybe it has something to do with cpu caches/tricks etc.

// Also at vMaxCalls 10.000 setting a squeek sound is coming from computer
;)

(*

Delphi 2006 generated instructions:


Project1.dpr.123: vMother.Test;
004091AC 8BC3 mov eax,ebx
004091AE 8B10 mov edx,[eax]
004091B0 FF12 call dword ptr [edx]

Project1.dpr.144: TgrandChild(vMother).NormalTest;
0040923C 8BC3 mov eax,ebx
0040923E E889FBFFFF call TgrandChild.NormalTest

*)

vMother.Free;

readln;
end.


*** End of Code ***

Maybe later I will analyze the generated assembler code with the
optimization manual for AMD64.

Bye,
Skybuck.


Skybuck Flying

unread,
Jan 10, 2007, 9:21:59 AM1/10/07
to
The winner was always the normal test function.

Changing the display code by commenting out the trim and format function
calls makes the winner always the virtual function.

{$IFDEF PERFORMANCE_TEST_ON}
{$IFDEF DISPLAY_WINNER_ON}
if vVirtualTime < vNormalTime then
begin
writeln('Winner: Virtual function, ', (vNormalTime - vVirtualTime):16:16,

' seconds faster.'); // Calls: ', Trim( Format( '%16.0n',

[vMaxCalls/1.0] ) ) );
end else
if vVirtualTime = vNormalTime then
begin
writeln('No winner (EQUAL)');
end else
begin
writeln('Winner: Normal function, ', (vVirtualTime - vNormalTime):16:16, '

seconds faster. '); // Calls: ', Trim( Format( '%16.0n',

[vMaxCalls/1.0] ) ) );
end;
{$ENDIF}

{$ENDIF}

end;

Why is that ?

Bye,
Skybuck.

Skybuck Flying

unread,
Jan 10, 2007, 9:31:32 AM1/10/07
to
Cool,

This code causes my computer to "shoot out" laser beam sounds.

Maybe I am gonna write a nice program to make my computer sing or make cool
sounds.

And maybe I will just record them for being crazy ;) =D

Hopefully it not gonna damage anything.. but I don't really care... it's not
supposed to damage anything.

So let it sing sing sing sing and squeek and shoot laser beam sounds ;) =D

var
vLol : double;

...

vLol := 1;

while true do
begin
{$IFDEF PERFORMANCE_TEST_ON}
// initialize frequency for performance test
QueryPerformanceFrequency(vFrequency);

// initialize maximum calls
// vMaxCalls := 10 * 1000; // SQUEEK SOUND COMING FROM COMPUTER AT THIS
SETTING ?!

vMaxCalls := round(vlol * 1000);
vLol := vLol + 0.01;
if vLol > 20 then vLol := 1; // laser beam.
writeln(vlol:4:4);
{$ENDIF}

Bye,
Skybuck.

Skybuck Flying

unread,
Jan 10, 2007, 10:12:10 AM1/10/07
to
Here is the laser beam sound:

http://members.home.nl/hbthouppermans/DreamPC2006/

;)

Bye,
Skybuck.


Nicholas Ring

unread,
Jan 10, 2007, 4:12:16 PM1/10/07
to
Skybuck Flying wrote:

> The winner was always the normal test function.

And the down side of 'normal' test function?

Cheers,
Nick

Skybuck Flying

unread,
Jan 11, 2007, 5:29:34 AM1/11/07
to

"Nicholas Ring" <Nichol...@smf.com.au> wrote in message
news:xn0f12tz...@reader.news.telstra.net...

> Skybuck Flying wrote:
>
>> The winner was always the normal test function.

> And the down side of 'normal' test function?

Actually the winner was always the virtual test function, until I added the
format function to display the calls.

In the writeln('Winner:.. ' code section

Your theory sucks Nicholas ;)

Bye,
Skybuck.


Rudy Velthuis

unread,
Jan 11, 2007, 6:57:33 AM1/11/07
to
Skybuck Flying wrote:

> Hello,
>
> Are virtual functions slower or faster than normal functions ?

Slightly slower, if called virtually. If you knew how the virtual
mechanism works, you wouldn't have to ask.

IOW: first get your basics right. Read the ENTIRE Delphi Language Guide
before you try to become a clever dick.
--
Rudy Velthuis http://rvelthuis.de

"Manuscript: something submitted in haste and returned at
leisure." -- Oliver Herford (1863-1935)

peek^

unread,
Jan 11, 2007, 12:56:17 PM1/11/07
to
Normal function:
Call address XXX

Virtual function:
Lookup address of function A
Call looked up address of function A


"Normal" functions are a bit faster. Virtual functions are a bit slower,
especially when called many times. Virtual functions are used for power
that object oriented programming brings, not for fast. There are games
written than use virtual functions, so that means you shouldnt worry much
about this when you writing your Notepad clone, lol.


Skybuck Flying

unread,
Jan 11, 2007, 2:32:56 PM1/11/07
to
Ok,

It seems the difference between normal functions and virtual functions is
not so big.

I was a bit worried about if virtual functions would be really slow because
of this look up stuff.

But it doesn't really seem to be the case.

Thus they pretty fast too.

Bye,
Skybuck ;)


J French

unread,
Jan 12, 2007, 4:53:57 AM1/12/07
to

In absolute terms they are fast, since machines are fast and Delphi is
fast - twiddling a bit of memory is ... well fast.

In relative terms that fiddling around is a lot slower than calling an
in-line memory address directly.

Shark8

unread,
Jan 16, 2007, 11:46:45 AM1/16/07
to
Thanks SkyBuck! I was looking for a good laser-beam sound! :)
Thanks for sharing, and have a great, ok!

Skybuck Flying

unread,
Jan 16, 2007, 9:01:17 PM1/16/07
to
You serious ?

If so what you gonna use it for ? :):):)

I can think of a couple of things:

(After processing it with a wave editor)

1. New ghostbuster game
2. New startrek episode or game LOL.
3. New Quake 5 weapen sound LOL.

=D

Bye,
Skybuck.

"Shark8" <OneWing...@gmail.com> wrote in message
news:1168966001....@11g2000cwr.googlegroups.com...

Shark8

unread,
Jan 17, 2007, 1:05:31 PM1/17/07
to
Close...
Me and a friend are tentatively working on a Wing Commander-style
game.
0 new messages