www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 17577] New: 20%+ Performance degradation in std.conv.to due

https://issues.dlang.org/show_bug.cgi?id=17577

          Issue ID: 17577
           Summary: 20%+ Performance degradation in std.conv.to due to
                    'import std.getopt'
           Product: D
           Version: D2
          Hardware: x86
                OS: Mac OS X
            Status: NEW
          Severity: normal
          Priority: P1
         Component: phobos
          Assignee: nobody puremagic.com
          Reporter: jrdemail2000-dlang yahoo.com

Importing std.getopt causes a performance degradation in calls to std.conv.to.
This degradation occurs when simply importing std.getopt, it is not necessary
to use features from std.getopt. This has been observed DMD 2.074.0, DMD
2.075.0-beta1, LDC 1.2, and LDC 1.3-beta 1 and 2.

This was first encountered as a performance regression from LDC 1.2 to LDC 1.3
in several benchmarks used by the TSV Utilities library. The degradation in
these benchmarks is from 20-30%.

Narrowing down the case identified a much smaller example exhibiting the
problem. Simply importing std.getopt causes a performance degradation
converting char[] to double via std.conv.to. Implication so far is that
something is interfering with proper inlining.

An important behavior change for the smaller sample is that it affects LDC 1.2,
LDC 1.3, and DMD. In the TSV Utilities test, the degradation was seen in LDC
1.3, but not LDC 1.2. This could be due the larger size of the programs.

The LDC issue:  https://github.com/ldc-developers/ldc/issues/2168

A sample program illustrating the issue:

===== use_conv_to.d ======
import std.conv : to;
import std.stdio;
import std.getopt;

void main()
{
    string num = "0.108236736784";
    size_t end = num.length;
    double sum = 0.0;
    foreach (i; 0 .. 100_000_000)
    {
        sum += num[0 .. end].to!double;
        end = (end == num.length) ? 1 : end + 1;
    }
    writeln("sum: ", sum);
}
=======================

Here are timing differences with and without the 'import std.getopt;' line.
Times were on OS X (xcode 8.3.3), and are in seconds:

| Compiler       | Without getopt import | With getopt import |
|----------------+-----------------------+--------------------|
| DMD 2.074.0    |                 12.30 |              13.02 |
| DMD 2.075.0-b1 |                 12.72 |              13.19 |
| LDC 1.2        |                  4.27 |               6.06 |
| LDC 1.3        |                  3.61 |               4.63 |

Compilation lines:
  $ ldc2 -release -O3 -boundscheck=off -singleobj use_conv_to.d
  $ dmd -release -O -boundscheck=off use_conv_to.d

LDC 1.3 was based on commit 6c97a02, so it includes the fix for boundscheck=off
(https://github.com/ldc-developers/ldc/issues/2161)

It is not known if other facilities are affected, though if inlining is being
affected this seems likely.

I tried adding std.getopt to the compiler line as an additional file, but not
importing it. This did not produce the degradation, so it appears related to
import.

I tried importing a version of std.getopt with all the unit test blocks
removed. This still produced the degradation. Hypothesis was repeated parsing
of templates in the unittest blocks might causing an issue, but this does not
appear to be the case.

I tried importing a small file which did little besides import std.conv.to,
which std.getopt does. This did not produce the degradation.

--
Jun 29 2017