isa
isa

Reputation: 1085

Why looping in Delphi faster than C#?

Delphi:


procedure TForm1.Button1Click(Sender: TObject);
var I,Tick:Integer;
begin
  Tick := GetTickCount();
  for I := 0 to 1000000000 do
    begin
    end;
  Button1.Caption := IntToStr(GetTickCount()-Tick)+' ms';
end;

C#:


private void button1_Click(object sender, EventArgs e)
        {
            int tick = System.Environment.TickCount;
            for (int i = 0; i < 1000000000; ++i)
            {
            }
            tick = System.Environment.TickCount - tick;
            button1.Text = tick.ToString()+" ms"; 
        }

Delphi gives around 515 ms

C# gives around 3775 ms

Upvotes: 5

Views: 4599

Answers (10)

Adrian
Adrian

Reputation: 21

In Delphi the break condition is calculated only once before the loop procedure begins whereas in C# the break condition is calculated in each loop pass again.

That’s why the looping in Delphi is faster than in C#.

Upvotes: 0

Graza
Graza

Reputation: 5050

Delphi would almost definitely optimise that loop to execute in reverse order (ie DOWNTO zero rather than FROM zero) - Delphi does this whenever it determines it is "safe" to do, presumably because either subtraction or checking against zero is faster than addition or checking against a non-zero number.

What happens if you try both cases specifying the loops to execute in reverse order?

Upvotes: 0

hehewaffles
hehewaffles

Reputation: 582

"// int i = 0; while (++i != 1000000000) ;"

That's interesting.

while (++i != x) is not the same as for (; i != x; i++)

The difference is that the while loop doesn't execute the loop for i = 0.

(try it out: run something like this:


int i;

for (i = 0; i < 5; i++)
    Console.WriteLine(i);

i = 0;
while (++i != 5)
    Console.WriteLine(i);

Upvotes: -1

sharper
sharper

Reputation: 71

You are comparing native code against VM JITted code, and that is not fair. Native code will be ALWAYS faster since the JITter can not optimize the code like a native compiler can.

That said, comparing Delphi against C# is not fair at all, a Delphi binary will win always (faster, smaller, without any kind of dependencies, etc).

Btw, I'm sadly amazed how many posters here don't know this differences... or may be you just hurted some .NET zealots that try to defend C# against anything that shows there are better options out there.

Upvotes: 3

Frank
Frank

Reputation: 2788

If this is intended as a benchmark, it's an exceptional bad one as in both cases the loop can be optimized away, so you have to look at the generated machine code to see what's going on. If you use release mode for C#, the following code

 Stopwatch sw = Stopwatch.StartNew();
 for (int i = 0; i < 1000000000; ++i){ }
 sw.Stop();
 Console.WriteLine(sw.Elapsed);

is transformed by the JITter to this:

 push        ebp 
 mov         ebp,esp 
 push        edi 
 push        esi 
 call        67CDBBB0 
 mov         edi,eax 
 xor         eax,eax               ; i = 0
 inc         eax                   ; ++i
 cmp         eax,3B9ACA00h         ; i == 1000000000?
 jl          0000000E              ; false: jmp
 mov         ecx,edi 
 cmp         dword ptr [ecx],ecx 
 call        67CDBC10 
 mov         ecx,66DDAEDCh 
 call        FFE8FBE0 
 mov         esi,eax 
 mov         ecx,edi 
 call        67CD75A8 
 mov         ecx,eax 
 lea         eax,[esi+4] 
 mov         dword ptr [eax],ecx 
 mov         dword ptr [eax+4],edx 
 call        66A94C90 
 mov         ecx,eax 
 mov         edx,esi 
 mov         eax,dword ptr [ecx] 
 mov         eax,dword ptr [eax+3Ch] 
 call        dword ptr [eax+14h] 
 pop         esi 
 pop         edi 
 pop         ebp 
 ret

Upvotes: 9

kludg
kludg

Reputation: 27493

The Delphi compiler uses the for loop counter downwards (if possible); the above code sample is compiled to:

Unit1.pas. 42: Tick := GetTickCount();
00489367 E8B802F8FF       call GetTickCount
0048936C 8BF0             mov esi,eax
Unit1.pas.43: for I := 0 to 1000000000 do
0048936E B801CA9A3B       mov eax,$3b9aca01
00489373 48               dec eax
00489374 75FD             jnz $00489373

Upvotes: 4

Behrooz
Behrooz

Reputation: 1734

this is the c# disassembly:
DEBUG:

// int i = 0; while (++i != 1000000000) ;//==for(int i ...blah blah blah)
0000004e 33 D2            xor         edx,edx 
00000050 89 55 B8         mov         dword ptr [ebp-48h],edx 
00000053 90               nop              
00000054 EB 00            jmp         00000056 
00000056 FF 45 B8         inc         dword ptr [ebp-48h] 
00000059 81 7D B8 00 CA 9A 3B cmp         dword ptr [ebp-48h],3B9ACA00h 
00000060 0F 95 C0         setne       al   
00000063 0F B6 C0         movzx       eax,al 
00000066 89 45 B4         mov         dword ptr [ebp-4Ch],eax 
00000069 83 7D B4 00      cmp         dword ptr [ebp-4Ch],0 
0000006d 75 E7            jne         00000056 

as you see it is a waste of cpu.
EDIT:
RELEASE:

   //unchecked
   //{
   //int i = 0; while (++i != 1000000000) ;//==for(int i ...blah blah blah)
00000032 33 D2            xor         edx,edx 
00000034 89 55 F4         mov         dword ptr [ebp-0Ch],edx 
00000037 FF 45 F4         inc         dword ptr [ebp-0Ch] 
0000003a 81 7D F4 00 CA 9A 3B cmp         dword ptr [ebp-0Ch],3B9ACA00h 
00000041 75 F4            jne         00000037 
   //}

EDIT:
and this is the c++ version:running about 9x faster in my machine.

    __asm
    {
        PUSH ECX
        PUSH EBX
        XOR  ECX, ECX
        MOV  EBX, 1000000000
NEXT:   INC  ECX
        CMP  ECX, EBX
        JS   NEXT
        POP  EBX
        POP  ECX
    }

Upvotes: 2

Clifford
Clifford

Reputation: 93476

Delphi is compiled to native code, whereas C# is compiled to CLR code which is then translated at runtime. That said C# does use JIT compilation, so you might expect the timing to be more similar, but it is not a given.

It would be useful if you could describe the hardware you ran this on (CPU, clock rate).

I do not have access to Delphi to repeat your experiment, but using native C++ vs C# and the following code:

VC++ 2008

#include <iostream>
#include <windows.h>

int main(void)
{
    int tick = GetTickCount() ;
    for (int i = 0; i < 1000000000; ++i)
    {
    }
    tick = GetTickCount() - tick;
    std::cout << tick << " ms" << std::endl  ; 
}

C#

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int tick = System.Environment.TickCount;
            for (int i = 0; i < 1000000000; ++i)
            {
            }
            tick = System.Environment.TickCount - tick;
            Console.Write( tick.ToString() + " ms" ) ; 
        }
    }
}

I initially got:

C++  2792ms
C#   2980ms

However I then performed a Rebuild on the C# version and ran the executable in <project>\bin\release and <project>\bin\debug respectively directly from the command line. This yielded:

C# (release):  720ms
C# (debug):    3105ms

So I reckon that is where the difference truly lies, you were running the debug version of the C# code from the IDE.

In case you are thinking that C++ is then particularly slow, I ran that as an optimised release build and got:

C++ (Optimised): 0ms

This is not surprising because the loop is empty, and the control variable is not used outside the loop so the optimiser removes it altogether. To avoid that I declared i as a volatile with the following result:

C++ (volatile i): 2932ms

My guess is that the C# implementation also removed the loop and that the 720ms is from something else; this may explain most of the difference between the timings in the first test.

What Delphi is doing I cannot tell, you might look at the generated assembly code to see.

All the above tests on AMD Athlon Dual Core 5000B 2.60GHz, on Windows 7 32bit.

Upvotes: 28

C. Dragon 76
C. Dragon 76

Reputation: 10062

You should attach a debugger and take a look at the machine code generated by each.

Upvotes: 1

SLaks
SLaks

Reputation: 887469

TickCount is not a reliable timer; you should use .Net's Stopwatch class. (I don't know what the Delphi equivalent is).

Also, are you running a Release build?
Do you have a debugger attached?

Upvotes: 7

Related Questions