Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why looping in Delphi faster than C#?

Tags:

c#

delphi

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

like image 492
isa Avatar asked Apr 18 '10 15:04

isa


3 Answers

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.

like image 199
Clifford Avatar answered Oct 21 '22 11:10

Clifford


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
like image 39
Frank Avatar answered Oct 21 '22 11:10

Frank


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?

like image 42
SLaks Avatar answered Oct 21 '22 11:10

SLaks