Bug 17577 – 20%+ Performance degradation in std.conv.to due to 'import std.getopt'
Status
RESOLVED
Resolution
WORKSFORME
Severity
normal
Priority
P1
Component
phobos
Product
D
Version
D2
Platform
x86
OS
Mac OS X
Creation time
2017-06-30T00:48:20Z
Last change time
2019-12-02T13:01:42Z
Assigned to
No Owner
Creator
Jon Degenhardt
Comments
Comment #0 by jrdemail2000-dlang — 2017-06-30T00:48:20Z
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.
Comment #1 by dlang-bugzilla — 2017-06-30T01:00:24Z
Reproducible on Linux x86_64 (11.6 / 10.6 seconds with dmd)
(In reply to Jon Degenhardt from comment #0)
> Implication so far is that
> something is interfering with proper inlining.
> [...]
> $ ldc2 -release -O3 -boundscheck=off -singleobj use_conv_to.d
> $ dmd -release -O -boundscheck=off use_conv_to.d
This command line does not include -inline.
Comment #2 by jrdemail2000-dlang — 2017-06-30T01:08:57Z
(In reply to Vladimir Panteleev from comment #1)
> Reproducible on Linux x86_64 (11.6 / 10.6 seconds with dmd)
>
> (In reply to Jon Degenhardt from comment #0)
> > Implication so far is that
> > something is interfering with proper inlining.
> > [...]
> > $ ldc2 -release -O3 -boundscheck=off -singleobj use_conv_to.d
> > $ dmd -release -O -boundscheck=off use_conv_to.d
>
> This command line does not include -inline.
Nice catch. I'll add -inline to the DMD command lines and retry. (It doesn't apply to the LDC command line.) Thanks!
Comment #3 by jrdemail2000-dlang — 2017-06-30T01:34:46Z
Properly adding -inline to the DMD compiler line eliminates the degradation in the DMD builds, at least in 2.075.0-b1. (I deleted 2.074 when updating to beta-1.)
The updated table:
| | Without | With |
| Compiler | getopt import | getopt import |
|----------------+---------------+---------------|
| DMD 2.075.0-b1 | 5.00 | 4.98 |
| LDC 1.2 | 4.27 | 6.06 |
| LDC 1.3 | 3.61 | 4.63 |
Comment #4 by jrdemail2000-dlang — 2017-06-30T05:35:57Z
Comment #5 by dlang-bugzilla — 2017-06-30T08:17:14Z
But... it's reproducible with DMD...
Comment #6 by jrdemail2000-dlang — 2017-06-30T08:49:25Z
Re-opened, as suggested. It is reproducible in DMD. Also, code structure in Phobos could be a contributing factor.
Comment #7 by bugzilla — 2019-12-02T13:01:42Z
Seems to be fixed meanwhile.
Current dmd (v2.089.0-rc.1-243-g4431f198d) produced 6.26 (without) vs. 6.25 (with) and ldc2 (1.12.0) 4.32 (without) vs 4.26 (with).