April 15, 2012
On 15/04/12 10:29, Joseph Rushton Wakeling wrote:
> ... the compiler accepts it. Whether that's because it's acceptably pure, or
> because the compiler just doesn't detect this case of impurity, is another
> matter. The int k is certainly mutable from outside the scope of the function,
> so AFAICS it _should_ be disallowed.

Meant to say: outside the scope of the struct.

April 15, 2012
On 15.04.2012 12:29, Joseph Rushton Wakeling wrote:
> On 15/04/12 09:23, ReneSac wrote:
>>> What really amazes me is the difference between g++, DMD and GDC in
>>> size of
>>> the executable binary. 100 orders of magnitude!
>> I have remarked it in another topic before, with a simple "hello
>> world". I need
>> to update there, now that I got DMD working. BTW, it is 2 orders of
>> magnitude.
>
> Ack. Yes, 2 orders of magnitude, 100 _times_ larger. That'll teach me to
> send comments to a mailing list at an hour of the morning so late that
> it can be called early. ;-)
>
>>> Sounds stupid as the C stuff should be fastest, but I've been surprised
>>> sometimes at how using idiomatic D formulations can improve things.
>>
>> Well, it may indeed be faster, especially the IO that is dependent on
>> things
>> like buffering and so on. But for this I just wanted something as
>> close as the
>> C++ code as possible.
>
> Fair dos. Seems worth trying the idiomatic alternatives before assuming
> the speed difference is always going to be so great, though.
>
>> Yeah, I don't know. I just did just throw those qualifiers against the
>> compiler,
>> and saw what sticks. And I was testing the decode speed specially to
>> see easily
>> if the output was corrupted. But maybe it haven't corrupted because
>> the compiler
>> don't optimize based on "pure" yet... there was no speed difference
>> too.. so...
>
> I think it's because although there's mutability outside the function,
> those variables are still internal to the struct. e.g. if you try and
> compile this code:
>
> int k = 23;
>
> pure int twotimes(int a)
> {
> auto b = 2*a;
> auto c = 2*k;
> return b+c;
> }
>
> ... it'll fail, but if you try and compile,
>
> struct TwoTimes
> {
> int k = 23;
>
> pure int twotimes(int a)
> {
> auto b = 2*a;
> auto c = 2*k;
> return b+c;
> }
> }
>

Simple - it's called weakly pure. (it can modify this for instance)
It's allowed so that you can do:
pure int f(){
	Twotimes t;
	return t.towtime(1,1);
}

which is obviously normal/strongly pure. Of course, the compiler knows what kind of purity each function has.

> ... the compiler accepts it. Whether that's because it's acceptably
> pure, or because the compiler just doesn't detect this case of impurity,
> is another matter. The int k is certainly mutable from outside the scope
> of the function, so AFAICS it _should_ be disallowed.


-- 
Dmitry Olshansky
April 15, 2012
On Apr 15, 2012 4:30 AM, "Joseph Rushton Wakeling" < joseph.wakeling@webdrake.net> wrote:
> ... the compiler accepts it.  Whether that's because it's acceptably
pure, or because the compiler just doesn't detect this case of impurity, is another matter.  The int k is certainly mutable from outside the scope of the function, so AFAICS it _should_ be disallowed.

As far as I understand pure includes the "hidden this parameter"  so it is pure if when you call it on the same structure with the same arguments you always get the same results.  Although that seams pretty useless in the optimization standpoint because the function can modify it's own object between calls.


April 15, 2012
Le 15/04/2012 09:23, ReneSac a écrit :
> On Sunday, 15 April 2012 at 02:56:21 UTC, Joseph Rushton Wakeling wrote:
>>> On Saturday, 14 April 2012 at 19:51:21 UTC, Joseph Rushton Wakeling wrote:
>>>> GDC has all the regular gcc optimization flags available IIRC. The
>>
> 
> 

I notice the 2D array is declared
int ct[512][2]; // C++
int ct[2][512]; // D

Any particular reason for this ? May this impede the cache utilization ?


As for the executable size, the D compiler links the druntime and libraries statically in the binary while I would believe g++ links them dynamically.
April 15, 2012
On Sun, Apr 15, 2012 at 5:16 PM, Somedude <lovelydear@mailmetrash.com> wrote:
> Le 15/04/2012 09:23, ReneSac a écrit :
>> On Sunday, 15 April 2012 at 02:56:21 UTC, Joseph Rushton Wakeling wrote:
>>>> On Saturday, 14 April 2012 at 19:51:21 UTC, Joseph Rushton Wakeling wrote:
>>>>> GDC has all the regular gcc optimization flags available IIRC. The
>>>
>>
>>
>
> I notice the 2D array is declared
> int ct[512][2]; // C++
> int ct[2][512]; // D
>

Not quite. It is declared
    int[2][512] ct;  // not valid in C++
which is the same as
    Int ct[512][2],  // also valid in C++

That's because you look at it as ((int)[2])[512]  512-sized array of
2-sized array of ints.
April 15, 2012
Le 15/04/2012 23:33, Ashish Myles a écrit :
> On Sun, Apr 15, 2012 at 5:16 PM, Somedude <lovelydear@mailmetrash.com> wrote:
>> Le 15/04/2012 09:23, ReneSac a écrit :
>>> On Sunday, 15 April 2012 at 02:56:21 UTC, Joseph Rushton Wakeling wrote:
>>>>> On Saturday, 14 April 2012 at 19:51:21 UTC, Joseph Rushton Wakeling wrote:
>>>>>> GDC has all the regular gcc optimization flags available IIRC. The
>>>>
>>>
>>>
>>
>> I notice the 2D array is declared
>> int ct[512][2]; // C++
>> int ct[2][512]; // D
>>
> 
> Not quite. It is declared
>     int[2][512] ct;  // not valid in C++
> which is the same as
>     Int ct[512][2],  // also valid in C++
> 
> That's because you look at it as ((int)[2])[512]  512-sized array of
> 2-sized array of ints.

 Oh right, sorry for this. It's a bit confusing.
April 15, 2012
Le 15/04/2012 23:41, Somedude a écrit :
> Le 15/04/2012 23:33, Ashish Myles a écrit :
>> On Sun, Apr 15, 2012 at 5:16 PM, Somedude <lovelydear@mailmetrash.com> wrote:
> 
>  Oh right, sorry for this. It's a bit confusing.

Now apart from comparing the generated asm, I don't see.
April 15, 2012
On 04/15/2012 02:23 PM, Kevin Cox wrote:
>
> On Apr 15, 2012 4:30 AM, "Joseph Rushton Wakeling"
> <joseph.wakeling@webdrake.net <mailto:joseph.wakeling@webdrake.net>> wrote:
>  > ... the compiler accepts it.  Whether that's because it's acceptably
> pure, or because the compiler just doesn't detect this case of impurity,
> is another matter.  The int k is certainly mutable from outside the
> scope of the function, so AFAICS it _should_ be disallowed.
>
> As far as I understand pure includes the "hidden this parameter"  so it
> is pure if when you call it on the same structure with the same
> arguments you always get the same results.  Although that seams pretty
> useless in the optimization standpoint

It is useful, because the guarantees it gives still are quite strong. Besides, mutation of the receiver object can be explicitly disabled by marking the method const or immutable; there is no reason why 'pure' should imply 'const'.

> because the function can modify
> it's own object between calls.
>

S foo(int a)pure{
    S x;
    x.foo(a);
    x.bar(a);
    return x;
}
April 16, 2012
Are you on linux/windows/mac?

On Saturday, 14 April 2012 at 19:05:40 UTC, ReneSac wrote:
> I have this simple binary arithmetic coder in C++ by Mahoney and translated to D by Maffi. I added "notrow", "final" and "pure"  and "GC.disable" where it was possible, but that didn't made much difference. Adding "const" to the Predictor.p() (as in the C++ version) gave 3% higher performance. Here the two versions:
>
> http://mattmahoney.net/dc/  <-- original zip
>
> http://pastebin.com/55x9dT9C  <-- Original C++ version.
> http://pastebin.com/TYT7XdwX  <-- Modified D translation.
>
> The problem is that the D version is 50% slower:
>
> test.fpaq0 (16562521 bytes) -> test.bmp (33159254 bytes)
>
> Lang| Comp  | Binary size | Time (lower is better)
> C++  (g++)  -      13kb   -  2.42s  (100%)   -O3 -s
> D    (DMD)  -     230kb   -  4.46s  (184%)   -O -release -inline
> D    (GDC)  -    1322kb   -  3.69s  (152%)   -O3 -frelease -s
>
>
> The only diference I could see between the C++ and D versions is that C++ has hints to the compiler about which functions to inline, and I could't find anything similar in D. So I manually inlined the encode and decode functions:
>
> http://pastebin.com/N4nuyVMh  - Manual inline
>
> D    (DMD)  -     228kb   -  3.70s  (153%)   -O -release -inline
> D    (GDC)  -    1318kb   -  3.50s  (144%)   -O3 -frelease -s
>
> Still, the D version is slower. What makes this speed diference? Is there any way to side-step this?
>
> Note that this simple C++ version can be made more than 2 times faster with algoritimical and io optimizations, (ab)using templates, etc. So I'm not asking for generic speed optimizations, but only things that may make the D code "more equal" to the C++ code.


April 16, 2012
On Sat, 14 Apr 2012 22:31:40 -0400, Jonathan M Davis <jmdavisProg@gmx.com> wrote:

> On Sunday, April 15, 2012 04:21:09 Joseph Rushton Wakeling wrote:
>> On 14/04/12 23:03, q66 wrote:
>> > He also uses a class. And -noboundscheck should be automatically  
>> induced
>> > by
>> > -release.
>>
>> ... but the methods are marked as final -- shouldn't that substantially
>> reduce any speed hit from using class instead of struct?
>
> In theory. If they don't override anything, then that signals to the compiler
> that they don't need to be virtual, in which case, they _shouldn't_ be
> virtual, but that's up to the compiler to optimize, and I don't know how good
> it is about that right now.

You are misunderstanding something.  Final functions can be in the vtable, and still not be called via the vtable.

i.e.:

class C
{
   int foo() { return 1; }
}

class D : C
{
   override final int foo() { return 2; }
}

void main()
{
   auto d = new D;
   C c = d;

   assert(d.foo() == 2); // non-virtual, inline-able call.
   assert(c.foo() == 2); // virtual call
}

Disclaimer -- I haven't examined any of the code being discussed or the issues contained in this thread.  I just wanted to point out this misunderstanding.

-Steve