Jump to page: 1 2 3
Thread overview
DMD is faster than LDC and GDC
Nov 12, 2015
Daniel Kozak
Nov 12, 2015
John Colvin
Nov 12, 2015
Daniel Kozak
Nov 12, 2015
John Colvin
Nov 12, 2015
Daniel Kozak
Nov 12, 2015
Artur Skawina
Nov 12, 2015
Iain Buclaw
Nov 12, 2015
Daniel Kozak
Nov 12, 2015
John Colvin
Nov 12, 2015
jmh530
Nov 12, 2015
tired_eyes
Nov 12, 2015
John Colvin
Nov 12, 2015
Walter Bright
Nov 12, 2015
David Nadlinger
Nov 12, 2015
Iain Buclaw
Nov 13, 2015
Vladimir Panteleev
Nov 14, 2015
Manu
Nov 14, 2015
Marc Schütz
Nov 12, 2015
rsw0x
Nov 12, 2015
Ali Çehreli
Nov 13, 2015
Ali Çehreli
Nov 14, 2015
cym13
November 12, 2015
code:

import std.stdio;

auto fmttable(immutable(string[][]) table) {

    import std.array : appender, uninitializedArray;
    import std.range : take, repeat;
    import std.exception : assumeUnique;

    auto res = appender(uninitializedArray!(char[])(128));
    res.clear();

    if (table.length == 0) return "";
    // column widths
    auto widths = new int[](table[0].length);

    foreach (rownum, row; table) {
        foreach (colnum, cell; row) {
            if (cell.length > widths[colnum])
                widths[colnum] = cast(int)cell.length;
        }
    }

    foreach (row; table) {
        res ~= "|";
        foreach (colnum, cell; row) {
            int l = widths[colnum] - cast(int)cell.length;
            res ~= cell;
            if (l)
                res ~= ' '.repeat().take(l);
            res ~= "|";
        }
        res.put("\n");
    }

     return res.data.assumeUnique();
}

void main() {

    immutable table = [
        ["row1.1", "row1.2  ", "row1.3"],
        ["row2.1", "row2.2", "row2.3"],
        ["row3.1", "row3.2", "row3.3  "],
        ["row4.1", "row4.2", "row4.3"],
        ["row5.1", "row5.2", "row5.3"],
    ];

    writeln(fmttable(table));
    int i;
    for (i=0; i < 1000000; ++i) {
        fmttable(table);
    }
    writeln(i);
}

timings:

DMD (-O -release -inline -boundscheck=off):
real	0m0.003s
user	0m0.000s
sys	0m0.000s

LDMD2-ldc2 (-O -release -inline -boundscheck=off):
real	0m1.071s
user	0m1.067s
sys	0m0.000s


GDC (-O3 -finline -frelease -fno-bounds-check):
real	0m0.724s
user	0m0.720s
sys	0m0.003s




November 12, 2015
On Thursday, 12 November 2015 at 11:59:50 UTC, Daniel Kozak wrote:
> code:
>
> import std.stdio;
>
> auto fmttable(immutable(string[][]) table) {
>
>     import std.array : appender, uninitializedArray;
>     import std.range : take, repeat;
>     import std.exception : assumeUnique;
>
>     auto res = appender(uninitializedArray!(char[])(128));
>     res.clear();
>
>     if (table.length == 0) return "";
>     // column widths
>     auto widths = new int[](table[0].length);
>
>     foreach (rownum, row; table) {
>         foreach (colnum, cell; row) {
>             if (cell.length > widths[colnum])
>                 widths[colnum] = cast(int)cell.length;
>         }
>     }
>
>     foreach (row; table) {
>         res ~= "|";
>         foreach (colnum, cell; row) {
>             int l = widths[colnum] - cast(int)cell.length;
>             res ~= cell;
>             if (l)
>                 res ~= ' '.repeat().take(l);
>             res ~= "|";
>         }
>         res.put("\n");
>     }
>
>      return res.data.assumeUnique();
> }
>
> void main() {
>
>     immutable table = [
>         ["row1.1", "row1.2  ", "row1.3"],
>         ["row2.1", "row2.2", "row2.3"],
>         ["row3.1", "row3.2", "row3.3  "],
>         ["row4.1", "row4.2", "row4.3"],
>         ["row5.1", "row5.2", "row5.3"],
>     ];
>
>     writeln(fmttable(table));
>     int i;
>     for (i=0; i < 1000000; ++i) {
>         fmttable(table);
>     }
>     writeln(i);
> }
>
> timings:
>
> DMD (-O -release -inline -boundscheck=off):
> real	0m0.003s
> user	0m0.000s
> sys	0m0.000s
>
> LDMD2-ldc2 (-O -release -inline -boundscheck=off):
> real	0m1.071s
> user	0m1.067s
> sys	0m0.000s
>
>
> GDC (-O3 -finline -frelease -fno-bounds-check):
> real	0m0.724s
> user	0m0.720s
> sys	0m0.003s

What versions of these compilers? I suspect the majority (maybe 80%-ish) of the time is spent allocating memory, so you might be seeing GC improvements in recent DMD
November 12, 2015
V Thu, 12 Nov 2015 12:10:30 +0000
John Colvin via Digitalmars-d <digitalmars-d@puremagic.com> napsáno:

> On Thursday, 12 November 2015 at 11:59:50 UTC, Daniel Kozak wrote:
> > code:
> >
> > import std.stdio;
> >
> > auto fmttable(immutable(string[][]) table) {
> >
> >     import std.array : appender, uninitializedArray;
> >     import std.range : take, repeat;
> >     import std.exception : assumeUnique;
> >
> >     auto res = appender(uninitializedArray!(char[])(128));
> >     res.clear();
> >
> >     if (table.length == 0) return "";
> >     // column widths
> >     auto widths = new int[](table[0].length);
> >
> >     foreach (rownum, row; table) {
> >         foreach (colnum, cell; row) {
> >             if (cell.length > widths[colnum])
> >                 widths[colnum] = cast(int)cell.length;
> >         }
> >     }
> >
> >     foreach (row; table) {
> >         res ~= "|";
> >         foreach (colnum, cell; row) {
> >             int l = widths[colnum] - cast(int)cell.length;
> >             res ~= cell;
> >             if (l)
> >                 res ~= ' '.repeat().take(l);
> >             res ~= "|";
> >         }
> >         res.put("\n");
> >     }
> >
> >      return res.data.assumeUnique();
> > }
> >
> > void main() {
> >
> >     immutable table = [
> >         ["row1.1", "row1.2  ", "row1.3"],
> >         ["row2.1", "row2.2", "row2.3"],
> >         ["row3.1", "row3.2", "row3.3  "],
> >         ["row4.1", "row4.2", "row4.3"],
> >         ["row5.1", "row5.2", "row5.3"],
> >     ];
> >
> >     writeln(fmttable(table));
> >     int i;
> >     for (i=0; i < 1000000; ++i) {
> >         fmttable(table);
> >     }
> >     writeln(i);
> > }
> >
> > timings:
> >
> > DMD (-O -release -inline -boundscheck=off):
> > real	0m0.003s
> > user	0m0.000s
> > sys	0m0.000s
> >
> > LDMD2-ldc2 (-O -release -inline -boundscheck=off):
> > real	0m1.071s
> > user	0m1.067s
> > sys	0m0.000s
> >
> >
> > GDC (-O3 -finline -frelease -fno-bounds-check):
> > real	0m0.724s
> > user	0m0.720s
> > sys	0m0.003s
> 
> What versions of these compilers? I suspect the majority (maybe 80%-ish) of the time is spent allocating memory, so you might be seeing GC improvements in recent DMD

DMD 2.069

LDC 2.067

GDC 2.065

No it is not cause by memory allocations.

It seems DMD can recognize that fmttable has same result every time, so it does compute it only once.

November 12, 2015
On 12 November 2015 at 12:59, Daniel Kozak via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> code:
>
>
<snip>


>
> GDC (-O3 -finline -frelease -fno-bounds-check):
> real    0m0.724s
> user    0m0.720s
> sys     0m0.003s
>
>
Not to be pedantic, but -finline does nothing (what you really want is
-finline-functions)

However.... -finline-functions is enabled automatically at -O3, so the whole -finline just becomes wasted typing.  :-)


November 12, 2015
On Thursday, 12 November 2015 at 12:23:11 UTC, Daniel Kozak wrote:
> V Thu, 12 Nov 2015 12:10:30 +0000
> John Colvin via Digitalmars-d <digitalmars-d@puremagic.com> napsáno:
>
>> On Thursday, 12 November 2015 at 11:59:50 UTC, Daniel Kozak wrote:
>> > [...]
>> 
>> What versions of these compilers? I suspect the majority (maybe 80%-ish) of the time is spent allocating memory, so you might be seeing GC improvements in recent DMD
>
> DMD 2.069
>
> LDC 2.067
>
> GDC 2.065
>
> No it is not cause by memory allocations.
>
> It seems DMD can recognize that fmttable has same result every time, so it does compute it only once.

Ok, then my second hypothesis is that dmd is inferring the pure attribute for fmttable because it returns auto (new in 2.069 IIRC), which enable the above optimisation that you have noted. Gdc and ldc (and dmd) can do similar things in their backend, but perhaps not here.

Do you have older dmd versions on hand to test?
November 12, 2015
V Thu, 12 Nov 2015 13:37:28 +0100
Iain Buclaw via Digitalmars-d <digitalmars-d@puremagic.com> napsáno:

> On 12 November 2015 at 12:59, Daniel Kozak via Digitalmars-d < digitalmars-d@puremagic.com> wrote:
> 
> > code:
> >
> >
> <snip>
> 
> 
> >
> > GDC (-O3 -finline -frelease -fno-bounds-check):
> > real    0m0.724s
> > user    0m0.720s
> > sys     0m0.003s
> >
> >
> Not to be pedantic, but -finline does nothing (what you really want is
> -finline-functions)
> 
> However.... -finline-functions is enabled automatically at -O3, so the whole -finline just becomes wasted typing.  :-)

Yeah I know, but it is a bad habit from past

November 12, 2015
V Thu, 12 Nov 2015 12:38:47 +0000
John Colvin via Digitalmars-d <digitalmars-d@puremagic.com> napsáno:

> On Thursday, 12 November 2015 at 12:23:11 UTC, Daniel Kozak wrote:
> > V Thu, 12 Nov 2015 12:10:30 +0000
> > John Colvin via Digitalmars-d <digitalmars-d@puremagic.com>
> > napsáno:
> > 
> >> On Thursday, 12 November 2015 at 11:59:50 UTC, Daniel Kozak wrote:
> >> > [...]
> >> 
> >> What versions of these compilers? I suspect the majority (maybe 80%-ish) of the time is spent allocating memory, so you might be seeing GC improvements in recent DMD
> >
> > DMD 2.069
> >
> > LDC 2.067
> >
> > GDC 2.065
> >
> > No it is not cause by memory allocations.
> >
> > It seems DMD can recognize that fmttable has same result every time, so it does compute it only once.
> 
> Ok, then my second hypothesis is that dmd is inferring the pure attribute for fmttable because it returns auto (new in 2.069 IIRC), which enable the above optimisation that you have noted. Gdc and ldc (and dmd) can do similar things in their backend, but perhaps not here.
> 
> Do you have older dmd versions on hand to test?

Yes (DVM) and it is same for older versions (2.066.1, 2.067.1)

November 12, 2015
On Thursday, 12 November 2015 at 11:59:50 UTC, Daniel Kozak wrote:
> code:
>
> import std.stdio;
>
> auto fmttable(immutable(string[][]) table) {
>
>     import std.array : appender, uninitializedArray;
>     import std.range : take, repeat;
>     import std.exception : assumeUnique;
>
>     auto res = appender(uninitializedArray!(char[])(128));
>     res.clear();
>
>     if (table.length == 0) return "";
>     // column widths
>     auto widths = new int[](table[0].length);
>
>     foreach (rownum, row; table) {
>         foreach (colnum, cell; row) {
>             if (cell.length > widths[colnum])
>                 widths[colnum] = cast(int)cell.length;
>         }
>     }
>
>     foreach (row; table) {
>         res ~= "|";
>         foreach (colnum, cell; row) {
>             int l = widths[colnum] - cast(int)cell.length;
>             res ~= cell;
>             if (l)
>                 res ~= ' '.repeat().take(l);
>             res ~= "|";
>         }
>         res.put("\n");
>     }
>
>      return res.data.assumeUnique();
> }
>
> void main() {
>
>     immutable table = [
>         ["row1.1", "row1.2  ", "row1.3"],
>         ["row2.1", "row2.2", "row2.3"],
>         ["row3.1", "row3.2", "row3.3  "],
>         ["row4.1", "row4.2", "row4.3"],
>         ["row5.1", "row5.2", "row5.3"],
>     ];
>
>     writeln(fmttable(table));
>     int i;
>     for (i=0; i < 1000000; ++i) {
>         fmttable(table);
>     }
>     writeln(i);
> }
>
> timings:
>
> DMD (-O -release -inline -boundscheck=off):
> real	0m0.003s
> user	0m0.000s
> sys	0m0.000s
>
> LDMD2-ldc2 (-O -release -inline -boundscheck=off):
> real	0m1.071s
> user	0m1.067s
> sys	0m0.000s
>
>
> GDC (-O3 -finline -frelease -fno-bounds-check):
> real	0m0.724s
> user	0m0.720s
> sys	0m0.003s

To test the speed of fmttable itself I split fmttable and main in to different modules, made fmttable extern(C) so I could just prototype it in the main module (no import), then compiled them separately before linking. This should prevent any possible inlining/purity cleverness. ~1s for ldmd2, ~2s for dmd, which is business as normal.

dmd is being clever and spotting that fmttable is pure, it would be good if ldc/gdc could spot this to.
November 12, 2015
On Thursday, 12 November 2015 at 14:44:49 UTC, John Colvin wrote:
>
> dmd is being clever and spotting that fmttable is pure, it would be good if ldc/gdc could spot this to.

I don't recall seeing anything in the 2.069.0 change log about improved attribute inference for auto functions. If you can find a link pointing to where it was discussed (either change log or forum or bug report), I would appreciate it.
November 12, 2015
On 11/12/15 13:22, Daniel Kozak via Digitalmars-d wrote:
>>> timings:
>>> > >
>>> > > DMD (-O -release -inline -boundscheck=off):
>>> > > real	0m0.003s
>>> > > user	0m0.000s
>>> > > sys	0m0.000s
>>> > >
>>> > > LDMD2-ldc2 (-O -release -inline -boundscheck=off):
>>> > > real	0m1.071s
>>> > > user	0m1.067s
>>> > > sys	0m0.000s
>>> > >
>>> > >
>>> > > GDC (-O3 -finline -frelease -fno-bounds-check):
>>> > > real	0m0.724s
>>> > > user	0m0.720s
>>> > > sys	0m0.003s
>> > 
>> > What versions of these compilers? I suspect the majority (maybe 80%-ish) of the time is spent allocating memory, so you might be seeing GC improvements in recent DMD
> DMD 2.069
> 
> LDC 2.067
> 
> GDC 2.065
> 
> No it is not cause by memory allocations.
> 
> It seems DMD can recognize that fmttable has same result every time, so it does compute it only once.

Comparisons using different frontend versions are very unfair -
- *every D release introduces a new language dialect* (for example:
http://dlang.org/changelog/2.068.0.html#attribinference3).

Out of curiosity, how does this slightly more sane version perform? (I don't have any dmd or ldc compilers; it takes ~80ms using GDC)

   import std.stdio;

   auto fmttable(alias sink=sink)(immutable(string[][]) table) {
       import std.range : take, repeat;

       if (table.length == 0) return;
       // column widths
       auto widths = new int[](table[0].length);

       foreach (rownum, row; table) {
           foreach (colnum, cell; row) {
               if (cell.length > widths[colnum])
                   widths[colnum] = cast(int)cell.length;
           }
       }

       foreach (row; table) {
           sink("|");
           foreach (colnum, cell; row) {
               sink(cell, ' '.repeat().take(widths[colnum]-cast(int)cell.length), "|");
           }
           sink("\n");
       }
   }

   void sink(S...)(S s) {
      foreach(I, _; S)
         write(s[I]);
   }

   void sink0(S...)(S s) {}

   void main() {
       immutable table = [
           ["row1.1", "row1.2  ", "row1.3"],
           ["row2.1", "row2.2", "row2.3"],
           ["row3.1", "row3.2", "row3.3  "],
           ["row4.1", "row4.2", "row4.3"],
           ["row5.1", "row5.2", "row5.3"],
       ];

       fmttable(table);
       int i;
       for (i=0; i < 1000000; ++i) {
           fmttable!sink0(table);
       }
       sink(i, "\n");
   }


artur
« First   ‹ Prev
1 2 3