comp.lang.ada
 help / color / mirror / Atom feed
From: Colin Paul Gloster <Colin_Paul_Gloster@ACM.org>
Subject: Re: Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient?
Date: Tue, 16 Feb 2010 16:50:22 +0000
Date: 2010-02-16T16:50:22+00:00	[thread overview]
Message-ID: <alpine.LNX.2.00.1002161530460.21651@Bluewhite64.example.net> (raw)
In-Reply-To: <d9ca32ef-5582-48a2-8c1e-423d2a35a5c1@d27g2000yqf.googlegroups.com>

[-- Attachment #1: Type: TEXT/PLAIN, Size: 12325 bytes --]

On Mon, 15 Feb 2010, S. J. W. posted:

|---------------------------------------------------------------------------|
|"[..]                                                                      |
|>                                                                          |
|> You see now what's happening.  With the gnatn switch the                 |
|> compiler is smart enough to call the Log just once, rather               |
|> than 10**6 times.                                                        |
|>                                                                          |
|> If you remove the -gnatn or -gnatN switches, then it runs in             |
|>  0m0.024s again.                                                         |
|                                                                           |
|The trouble is that that benchmark does something other than Colin's!"     |
|---------------------------------------------------------------------------|

That is not the problem. The code which I posted at the beginning of
this thread was not a means in itself, but was intended for timing
performances of implementations of logarithm functions in the base of
ten in a manner representative of real code which I use. The real code
is not dedicated to calculating something approximately equal to
6.3E+08. I could have written 500 * 1_000_000 calls or 3.14 * 1000
calls or a single call. A single call might have been overwhelmed by
overhead unrelated to the logarithm function. In the case of the C++
version when using a particular compilation switch, I failed in the
task because the hardcoded arguments I provided resulted in a trivial
and dramatic optimization which would not happen in the real code.

While it is unfortunate for Ada code in general that Ada compilers
fail to mimic this optimization of G++'s, that particular optimization
would not benefit the usage of logarithms in the real code I
mentioned. Dr. Jonathan Parker is free to pursue this problem in a
subthread or with vendors.

|---------------------------------------------------------------------------|
|"This might be a more accurate translation:                                |
|                                                                           |
|with Ada.Numerics.Generic_Elementary_Functions;                            |
|with Text_IO; use Text_IO;                                                 |
|procedure Log_Bench_0 is                                                   |
|   type Real is digits 15;                                                 |
|   package Math is new Ada.Numerics.Generic_Elementary_Functions           |
|(Real);                                                                    |
|   use Math;                                                               |
|   Answer : Real := 0.0;                                                   |
|   Log_Base_10_Of_E : constant := 0.434_294_481_903_251_827_651_129;       |
|begin                                                                      |
|   for I in 1 .. 1_000_000 loop                                            |
|      declare                                                              |
|         X : Real := 0.1;                                                  |
|      begin                                                                |
|         for J in 1 .. 500 loop                                            |
|            Answer := Answer + Log_Base_10_Of_E * Log (X);                 |
|            X := X + 0.1;                                                  |
|         end loop;                                                         |
|      end;                                                                 |
|   end loop;                                                               |
|   Put (Real'Image(Answer));                                               |
|end Log_Bench_0;                                                           |
|                                                                           |
|I've tried inlining GNAT's implementation (GCC 4.5.0, x86_64-aqpple-       |
|darwin10.2.0) and even just calling up the C log10 routine using an        |
|inline. None was very impressive compared to the g++ result.               |
|                                                                           |
|Colin's time: 37s                                                          |
|Jonathan's time (-O3 -ffast-math -gnatp): 16s                              |
|Jonathan;s time (-O3 -ffast-math -gnatp -gnatN -funroll-loops): 14s        |
|Jonathan's time (same opts, but using C log10()): 11s"                     |
|---------------------------------------------------------------------------|

That ordering does not necessarily hold...

GCC4.2.4...

gnatmake -O3 -ffast-math -gnatp Log_Bench_0.adb -o  Log_Bench_0_compiled_by_GCC4.2.4_with_-ffast-math_and_-gnatp

time ./Log_Bench_0_compiled_by_GCC4.2.4_with_-ffast-math_and_-gnatp
  6.34086408606382E+08

real    0m14.328s
user    0m14.329s
sys     0m0.000s


gnatmake -O3 -ffast-math -gnatp -gnatN -funroll-loops Log_Bench_0.adb -o  Log_Bench_0_compiled_by_GCC4.2.4_with_-ffast-math_and_-gnatp_and_-gnatN_and_-funroll-loops

time ./Log_Bench_0_compiled_by_GCC4.2.4_with_-ffast-math_and_-gnatp_and_-gnatN_and_-funroll-loops
  6.34086408606382E+08

real    0m14.346s
user    0m14.341s
sys     0m0.004s


GCC4.4.3 (slower than GCC4.2.4 for this program)...

gnatmake -O3 -ffast-math  Log_Bench_0.adb -o  Log_Bench_0_compiled_by_GCC4.4.3_with_-ffast-math

  time ./Log_Bench_0_compiled_by_GCC4.4.3_with_-ffast-math
  6.34086408606382E+08

real    0m14.713s
user    0m14.689s
sys     0m0.000s


  gnatmake -O3 -ffast-math -gnatp Log_Bench_0.adb -o  Log_Bench_0_compiled_by_GCC4.4.3_with_-ffast-math_and_-gnatp

  time ./Log_Bench_0_compiled_by_GCC4.4.3_with_-ffast-math_and_-gnatp
  6.34086408606382E+08

real    0m14.691s
user    0m14.693s
sys     0m0.000s


gnatmake -O3 -ffast-math -gnatp -gnatN -funroll-loops Log_Bench_0.adb -o  Log_Bench_0_compiled_by_GCC4.4.3_with_-ffast-math_and_-gnatp_and_-gnatN_and_-funroll-loops

  time ./Log_Bench_0_compiled_by_GCC4.4.3_with_-ffast-math_and_-gnatp_and_-gnatN_and_-funroll-loops
  6.34086408606382E+08

real    0m14.690s
user    0m14.689s
sys     0m0.000s

|---------------------------------------------------------------------------|
|"so we still have 3 orders of magnitude to go to get to the g++ result:    |
|0.02s                                                                      |
|                                                                           |
|This is my final version, with the inlined GNAT implementation too:        |
|                                                                           |
|with Ada.Numerics.Generic_Elementary_Functions;                            |
|with System.Machine_Code; use System.Machine_Code;                         |
|with Text_IO; use Text_IO;                                                 |
|procedure Log_Bench is                                                     |
|   type Real is digits 15;                                                 |
|   package Math is new Ada.Numerics.Generic_Elementary_Functions           |
|(Real);                                                                    |
|   use Math;                                                               |
|   Answer : Real := 0.0;                                                   |
|   Log_Base_10_Of_E : constant := 0.434_294_481_903_251_827_651_129;       |
|   function LogM (X : Real) return Real;                                   |
|   pragma Inline_Always (LogM);                                            |
|   function LogM (X : Real) return Real is                                 |
|      Result : Real;                                                       |
|      NL : constant String := ASCII.LF & ASCII.HT;                         |
|   begin                                                                   |
|      Asm (Template =>                                                     |
|         "fldln2               " & NL                                      |
|       & "fxch                 " & NL                                      |
|       & "fyl2x                " & NL,                                     |
|         Outputs  => Real'Asm_Output ("=t", Result),                       |
|         Inputs   => Real'Asm_Input  ("0", X));                            |
|      return Result;                                                       |
|   end LogM;                                                               |
|   function LogL (X : Real) return Real;                                   |
|   pragma Import (C, LogL, "log10");                                       |
|begin                                                                      |
|   for I in 1 .. 1_000_000 loop                                            |
|      declare                                                              |
|         X : Real := 0.1;                                                  |
|      begin                                                                |
|         for J in 1 .. 500 loop                                            |
|--              Answer := Answer + Log_Base_10_Of_E * LogM (X);            |
|            Answer := Answer + LogL (X);                                   |
|            X := X + 0.1;                                                  |
|         end loop;                                                         |
|      end;                                                                 |
|   end loop;                                                               |
|   Put (Real'Image(Answer));                                               |
|end Log_Bench;                                                             |
|                                                                           |
|[..]"                                                                      |
|---------------------------------------------------------------------------|

Not all of those switches would yield fair proxies for timings of
logarithms in the real code which inspired this thread, but anyway...


64bit GCC4.2.4...
gnatmake -O3 -ffast-math  Log_Bench.adb -o  Log_Bench_compiled_by_GCC4.2.4_with_-ffast-math -largs /lib/libm.so.6

time ./Log_Bench_compiled_by_GCC4.2.4_with_-ffast-math
  6.34086408606382E+08

real    0m34.497s
user    0m34.494s
sys     0m0.004s


gnatmake -gnatp -O3 -ffast-math  Log_Bench.adb -o  Log_Bench_compiled_by_GCC4.2.4_with_-ffast-math_and_-gnatp -largs /lib/libm.so.6

  time ./Log_Bench_compiled_by_GCC4.2.4_with_-ffast-math_and_-gnatp
  6.34086408606382E+08

real    0m34.503s
user    0m34.506s
sys     0m0.000s


gnatmake -gnatN -funroll-loops -gnatp -O3 -ffast-math  Log_Bench.adb -o  Log_Bench_compiled_by_GCC4.2.4_with_-ffast-math_and_-gnatp_and_-gnatN_and_-funroll-loops -largs /lib/libm.so.6

  time ./Log_Bench_compiled_by_GCC4.2.4_with_-ffast-math_and_-gnatp_and_-gnatN_and_-funroll-loops
  6.34086408606382E+08

real    0m34.547s
user    0m34.546s
sys     0m0.004s

64bit GCC4.4.3...
gnatmake -O3 -ffast-math  Log_Bench.adb -o  Log_Bench_compiled_by_GCC4.4.3_with_-ffast-math -largs /lib/libm.so.6

  time ./Log_Bench_compiled_by_GCC4.4.3_with_-ffast-math
  6.34086408606382E+08

real    0m34.257s
user    0m34.258s
sys     0m0.000s


gnatmake -gnatp -O3 -ffast-math  Log_Bench.adb -o  Log_Bench_compiled_by_GCC4.4.3_with_-ffast-math_and_-gnatp -largs /lib/libm.so.6

  time ./Log_Bench_compiled_by_GCC4.4.3_with_-ffast-math_and_-gnatp
  6.34086408606382E+08

real    0m34.474s
user    0m34.478s
sys     0m0.000s


gnatmake -gnatN -funroll-loops -gnatp -O3 -ffast-math  Log_Bench.adb -o  Log_Bench_compiled_by_GCC4.4.3_with_-ffast-math_and_-gnatp_and_-gnatN_and_-funroll-loops -largs /lib/libm.so.6

  time ./Log_Bench_compiled_by_GCC4.4.3_with_-ffast-math_and_-gnatp_and_-gnatN_and_-funroll-loops
  6.34086408606382E+08

real    0m34.188s
user    0m34.182s
sys     0m0.004s

  reply	other threads:[~2010-02-16 16:50 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-02-15 10:58 Is there an Ada compiler whose Ada.Numerics.Generic_Elementary_Functions.Log(Base=>10, X=>variable) is efficient? Colin Paul Gloster
2010-02-15 13:02 ` John B. Matthews
2010-02-15 14:17   ` Colin Paul Gloster
2010-02-15 17:19     ` John B. Matthews
2010-02-15 14:54 ` jonathan
2010-02-15 15:04   ` jonathan
2010-02-15 19:50     ` sjw
2010-02-16 16:50       ` Colin Paul Gloster [this message]
2010-02-15 18:26 ` (see below)
2010-02-15 18:51   ` jonathan
2010-02-15 20:00   ` sjw
2010-02-15 21:17     ` jonathan
2010-02-16  0:09       ` jonathan
2010-02-16 17:33   ` Colin Paul Gloster
2010-02-24 10:07     ` Colin Paul Gloster
2010-02-15 23:04 ` Jeffrey R. Carter
2010-02-16 14:54   ` Colin Paul Gloster
2010-02-16 15:24     ` Colin Paul Gloster
2010-02-16 19:01     ` Jeffrey R. Carter
2010-02-17 10:25       ` Colin Paul Gloster
2010-02-15 23:20 ` Randy Brukardt
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox