Array Appending and DRuntime

dsimcha dsimcha at yahoo.com
Sat Apr 25 13:18:06 PDT 2009


For a while now, I've had a suspicion that the builtin array appending has
gotten slower lately.  The talk about array appenders here lately has brought
that to a head, so I decided to test it and find out.  Here's the test program
I used:

import std.stdio, std.perf;

void main() {
    scope pc = new PerformanceCounter;
    pc.start;
    uint[] foo;
    foreach(i; 0..1_000_000) {
        foo ~= i;
    }
    pc.stop;
    writeln(pc.milliseconds);
}

Results:

DMD 2.019 (Last release before druntime):  42 milliseconds.
DMD 2.020 (First release with druntime):  ~1000 milliseconds.
DMD 2.029 (Current version):  ~1000 milliseconds.
DMD 2.029 (Replacing ~= with the Appender struct):  18 milliseconds.
DMD 2.029 (Replacing builtin array with rangeextra.TNew):  19 milliseconds.

I think it's abundantly clear that I wasn't just going crazy and something
changed between 2.019 and 2.020 that made the builtin ~= about 25x slower.  It
probably is related to druntime because this was the only major change between
2.019 and 2.020.  If we could put this back to the way it was in 2.019, this
would drastically reduce the need for more complicated solutions.  Here's some
speculation about what might have happened:

1.  Since Appender and TNew both use the builtin array's reallocation scheme,
it's not a reallocation scheme issue.
2.  gcx.d appears to cache the last block size query.  This means that
repeatedly querying the same block in a single threaded program (where
thread_needLock() returns false and no lock is necessary) is very fast.  This
is true in both the old Phobos GC and the druntime GC.  I wonder if this was
somehow bypassed by the ~= operator when druntime was integrated with DMD in
its early days.



More information about the Digitalmars-d mailing list