10

Consider this very simple piece of code:

uses Diagnostics;

const
  ITER_COUNT = 100000000;

procedure TForm1.btn2Click(Sender: TObject);
var
  val: Double;
  i: Integer;
begin
  sw := TStopwatch.StartNew;

  val := 1;
  for i := 0 to ITER_COUNT - 1 do
  begin
    val := val + i;
    val := val - i;
    val := val * 10;
    val := val / 10;
  end;

  sw.Stop;

  mmo1.Lines.Add(Format('Simple completed in %D ms. Result: %G',
    [sw.ElapsedMilliseconds, val]));
end;

This simple loop executes in 4027 ms on my PC. Now if I write the same code, only using different thread:

procedure TForm1.btn3Click(Sender: TObject);
begin
  sw := TStopwatch.StartNew;
  TThread.CreateAnonymousThread(
    procedure
    var
      val: Double;
      i: Integer;
    begin
      val := 1;
      for i := 0 to ITER_COUNT- 1 do
      begin
        val := val + i;
        val := val - i;
        val := val * 10;
        val := val / 10;
      end;

      sw.Stop;

      TThread.Queue(nil, procedure
        begin
          mmo1.Lines.Add(Format('Async completed in %D ms. Result: %G',
            [sw.ElapsedMilliseconds, val]));
        end);
    end
  ).Start;
end;

This method which does the same but in the different thread executes in 2910 ms! (Compiled in Delphi XE with Release configuration active) I noticed ~25% gain in the thread no matter how many iterations I have. Why this is so? Shouldn't it be the same results?

EDIT: After further investigations I found that probably the reason for this is Windows 7 OS. On Windows 7 machine simple loop in the main thread executes ~25% slower than async version! I've even tried to run this same project on the same Windows 7 PC using Windows XP mode and then both results were equal - ~3000ms! I'm completely lost here...What is Windows 7 doing with the main thread that it is slower?

Linas
  • 5,485
  • 1
  • 25
  • 35

1 Answers1

12

Strange indeed, but maybe it is because of some offset c.q. alignment.

Maybe the variables in the anonymous thread are proper aligned, and the other one not. You could try to add some dummy variables to change to offset or if you have Delphi XE2, try some different code alignment.

Lieven Keersmaekers
  • 57,207
  • 13
  • 112
  • 146
André
  • 8,920
  • 1
  • 24
  • 24
  • I managed to slow down the first version even more with dummy variables (~5000 ms in some tests), can't make it faster than ~4000ms...But this doesn't affect async version... – Linas Jan 19 '12 at 09:14
  • @Linas Make sure that `val` is always aligned on an 8 byte boundary. For example allocate it with a call to GetMem rather than on the stack. – David Heffernan Jan 19 '12 at 09:17
  • @DavidHeffernan That made the trick. If I manually align my `Double` variable with `GetMem` loop executes as expected. The question is why Delphi does this correctly in the separate anonymous thread but not in the main thread? – Linas Jan 19 '12 at 09:40
  • @Linas That's just down to luck. – David Heffernan Jan 19 '12 at 09:45
  • 6
    To my mind this is a big problem with Delphi for floating point. I've no idea why the compiler doesn't align floating point stack variables correctly. It's trivial to achieve for the compiler vendor. The fact that they can't be bothered to do it makes our life very hard. – David Heffernan Jan 19 '12 at 09:47