Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2011-05

Register variables slowing down floating point operations

12 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

cobines

Hello.

I have written the following program:

program a;
{$mode objfpc}
uses
  SysUtils;
var
  i: integer;
  vd: double;
  t: TDateTime;
  max: int64;// = 100000000;
begin
  t := Now;
  max := 100000000;
  for i := 0 to max do
    vd := i / max;
  Writeln('Time: ', DateTimeToTimeStamp(Now - t).Time, ' ms');
end.

I'm running it on Windows XP i386, compiled with FPC 2.5.1 17430.

# fpc -O a.pas
...
# a.exe
Time: 1462 ms

# fpc -O3 a.pas
...
# a.exe
Time: 3325 ms

It is slower with optimizations.

The for loop with -O looks like this:

.Lj9:
incl U_P$A_I
fildl U_P$A_I
fildq U_P$A_MAX
fdivrp %st,%st(1)
fstpl U_P$A_VD
cmpl U_P$A_I,%eax
jg .Lj9

With -O3 like this:

.Lj9:
incl %ecx
movl %ecx,-4(%ebp)
fildl -4(%ebp)
movl %edx,-16(%ebp)
movl %ebx,-12(%ebp)
fildq -16(%ebp)
fdivrp %st,%st(1)
fstpl U_P$A_VD
cmpl %ecx,%eax
jg .Lj9

It seems storing variables i and max in registers caused the code to be slower, because they have to be written to memory anyway.

Is it something that can be rectified in the optimizer, or is it one of those things that you just have to be aware of?

I have only found that disabling optimizations {$OPTIMIZATION OFF} ... {$OPTIMIZATION DEFAULT} helps, but you have to do it for the entire function.

cobines
Ben
to cobines
cobines wrote
I'm running it on Windows XP i386, compiled with FPC 2.5.1 17430.

I tried this on my system which runs 64-bit Linux with FPC 2.4.3 (64-bit).

Using -O, -O2 or -O3 command line parameters. In each case, the generated executable runs exactly the same. They actually have the exact same result: 828ms

So here, with or without "optimization", it makes zero difference. Which is weird in it's own way.

Ben.
Marcos Douglas
to cobines: Hello. I have written the following program: program a; {$mode objfpc} uses SysUtils; var…
cobines wrote 34 lines
Hello. I have written the following program: program a; {$mode objfpc} uses  SysUtils; var  i: integer;  vd: double;  t: TDateTime;  max: int64;// = 100000000; begin  t := Now;  max := 100000000;  for i := 0 to max do    vd := i / max;  Writeln('Time: ', DateTimeToTimeStamp(Now - t).Time, ' ms'); end. I'm running it on Windows XP i386, compiled with FPC 2.5.1 17430. # fpc -O a.pas ... # a.exe Time: 1462 ms # fpc -O3 a.pas ... # a.exe Time: 3325 ms It is slower with optimizations.

I did this test.
My env is FPC 2.4.3 (/fixes_2_4)

Result:
-O = run in 891 ms
-O1 = run in 875 ms
-O2 = run in 1656 ms
-O3 = run in 1625 ms

And now?

Marcos Douglas

Marcos Douglas
to Marcos Douglas
Marcos Douglas wrote 11 lines
I did this test. My env is FPC 2.4.3 (/fixes_2_4) Result: -O   = run in 891 ms -O1 = run in 875 ms -O2 = run in 1656 ms -O3 = run in 1625 ms And now?

Ah, sorry, I use WinXP SP3.

Marcos Douglas

cobines
to Ben: I tried this on my system which runs 64-bit Linux with FPC 2.4.3 (64-bit). Using -O, -O2…

2011/5/13 Ben :

Show quoted text 14 lines
On 12/05/2011 20:54, cobines wrote: > > I'm running it on Windows XP i386, compiled with FPC 2.5.1 17430. > I tried this on my system which runs 64-bit Linux with FPC 2.4.3 (64-bit). Using -O, -O2 or -O3 command line parameters. In each case, the generated executable runs exactly the same. They actually have the exact same result: 828ms So here, with or without "optimization", it makes zero difference. Which is weird in it's own way.

On x86_64 it seems MMX instructions are used with or without optimizations enabled. Those instructions can operate on memory as well as on registers so there is no additional step where registers are written to memory.

So I tried with "fpc -OpPENTIUM ..." but MMX instructions are not generated anyway for i386.

I tried on Linux i386 and have the same thing, so this is only on i386 I think.

cobines
Marcos Douglas
to cobines
cobines wrote 25 lines
2011/5/13 Ben : > On 12/05/2011 20:54, cobines wrote: >> >> I'm running it on Windows XP i386, compiled with FPC 2.5.1 17430. >> > > > I tried this on my system which runs 64-bit Linux with FPC 2.4.3 (64-bit). > > Using -O, -O2 or -O3 command line parameters. In each case, the > generated executable runs exactly the same. They actually have the exact > same result: 828ms > > So here, with or without "optimization", it makes zero difference. Which > is weird in it's own way. On x86_64 it seems MMX instructions are used with or without optimizations enabled. Those instructions can operate on memory as well as on registers so there is no additional step where registers are written to memory. So I tried with "fpc -OpPENTIUM ..." but MMX instructions are not generated anyway for i386. I tried on Linux i386 and have the same thing, so this is only on i386 I think.

So, not to use the option -O in i386?
When I compile FPC sources, on Win32 XP SP3, using make, the option is used.

I'm confusing now...

Marcos Douglas

Vincent Snijders
to Marcos Douglas

2011/5/13 Marcos Douglas :

So, not to use the option -O in i386? When I compile FPC sources, on Win32 XP SP3, using make, the option is used. I'm confusing now...

Did you try one of the -Cf options to enable MMX on i386?

Vincent

Marcos Douglas
to Vincent Snijders: 2011/5/13 Marcos Douglas : Did you try one of the -Cf options to enable MMX on i386?…
Vincent Snijders wrote 7 lines
2011/5/13 Marcos Douglas : > So, not to use the option -O in i386? > When I compile FPC sources, on Win32 XP SP3, using make, the option is used. > > I'm confusing now... Did you try one of the -Cf options to enable MMX on i386?

No, I did not.

The compiler can choose the best compilation, it self? How I will know the best options?

Marcos Douglas

cobines
to Vincent Snijders: 2011/5/13 Marcos Douglas : Did you try one of the -Cf options to enable MMX on i386?…

2011/5/13 Vincent Snijders :

Did you try one of the -Cf options to enable MMX on i386?

I was wrong, sorry. The instruction in question is "cvtsi2sd", which is SSE2 not MMX. Maybe on x86_64 SSE2 is default.

Indeed if I add -CfSSE2 than those instructions are generated for i386, at least for variable "i" (Integer). Int64 "max" is stored in two registers so it is still handled the same way.

cobines
Marcos Douglas
to Jonas Maebe: It is used because in general it results in faster code. This is one particular example…
Jonas Maebe wrote 10 lines
On 13 May 2011, at 16:08, Marcos Douglas wrote: > So, not to use the option -O in i386? > When I compile FPC sources, on Win32 XP SP3, using make, the option is > used. It is used because in general it results in faster code. This is one particular example where it doesn't. That does not mean that you should never use it.

So, is better use it in all compilations?
Sorry, I don't understand all optimizations of processors (but I can learn about it). I just want choose the better option for 90% of cases of algoritms, if that exists.

Thanks,
Marcos Douglas

Unknown author

On Thu, 12 May 2011 20:54:16 +0200 cobines wrote

Show quoted text 5 lines
I have written the following program: ... max := 100000000; for i := 0 to max do vd := i / max;

A really smart compiler would notice that this in this loop the value of vd is never examined, the loop being equivalent to

       vd := 1 ;

and would code it appropriately. This sort of thing caused all kinds of trouble some 20 (30?) years ago with benchmarks involving small timing loops of this kind. One has to be very, very careful before believing such timing results!

I have recently been "modernizing" my old benchmark programs, with many bizarre results. Funny things like replacing fixed size arrays by dynamic ones making things slower ... until I put the code inside a subroutine: the optimizer did a super job optimizing access to the local variables inside the subroutine!

One should really use a large, complex program to test how well optimization works. Results with short loops are, as you found, likely to give inconsistent and misleading results.

By the way, I gave up writing Assembler programs for number crunching when optimized Free Pascal got within 10% of the best I could do. That was some years ago and there have been several improvements in Free Pascal since: the compiled code is now, I think, faster than anything I could do in Assembler. And, yes: I have the odd program that goes faster with optimization off! Most like optimization on.

For comparison, my Assembler was over 4 times faster than Turbo Pascal 3.01A for a similar number crunching application.

Andrew Bennett