December 19, 2014
On 12/19/14 12:15 PM, Anonymous wrote:
> On Friday, 19 December 2014 at 15:25:46 UTC, Steven Schveighoffer wrote:
>>
>> This is surprising to me.
>>
>
> Ho ho ho, this year he has brought your surprise sooner than expected...
>

It would be nice if this was the only time this year I was surprised because I didn't fully understand something ;)

-Steve
December 19, 2014
On Friday, 19 December 2014 at 18:38:32 UTC, Steven Schveighoffer wrote:
> On 12/19/14 12:15 PM, Anonymous wrote:
>> On Friday, 19 December 2014 at 15:25:46 UTC, Steven Schveighoffer wrote:
>>>
>>> This is surprising to me.
>>>
>>
>> Ho ho ho, this year he has brought your surprise sooner than expected...
>>
>
> It would be nice if this was the only time this year I was surprised because I didn't fully understand something ;)
>
> -Steve

It's because of this:

On Friday, 19 December 2014 at 14:41:07 UTC, Anonymous wrote:
> On Thursday, 18 December 2014 at 22:27:06 UTC, zeljkog wrote:
>> On 18.12.14 14:50, Steven Schveighoffer wrote:
>>> I wonder how your code compares to this:
>>> 
>>> void append(T)(ref T[] arr, T[] args...)
>>> {
>>>    arr ~= args;
>>> }
>>
>> This is ~20% slower for ints, but it difference  increases for bigger structs.
>
> What a big surprise. If you make an array of struct, each item of your array has the length of the struct. structs a values.
> If you want to append a struct to an array just append a pointer to the struct:
>
> ----------
> struct arg{uint a,r,g,h;};
>
> arg * [] argh;
> arg [] argv;
>
> foreach(immutable i; 0..1000)
>   argh ~= new arg;
> ----------
>
> so in argh, each item is a size_t pointer. damn.
> In argv, the delta between each item is (a.sizeof+r.sizeof+g.sizeof+h.sizeof)
> In argh, the delta between each item is (arg *).sizeof

argv needs to be a contiguous thing so it's slower to append because it's not just storing a reference but the whole thing. There is consequently more realloc().
argh is faster because it stores the addresses of the items.

argv appends maybe 33 bytes, 33 bytes and so on.
argh always appens 4 4 4... (32 bits OS) or 8 8 8...(64 bits OS). It's faster , always aligned...page-aware.that's all.

Oh Oh oh.
December 19, 2014
On 12/19/14 5:28 PM, Anonymous wrote:
>>
>> What a big surprise. If you make an array of struct, each item of your
>> array has the length of the struct. structs a values.
>> If you want to append a struct to an array just append a pointer to
>> the struct:
>>
>> ----------
>> struct arg{uint a,r,g,h;};
>>
>> arg * [] argh;
>> arg [] argv;
>>
>> foreach(immutable i; 0..1000)
>>   argh ~= new arg;
>> ----------
>>
>> so in argh, each item is a size_t pointer. damn.
>> In argv, the delta between each item is
>> (a.sizeof+r.sizeof+g.sizeof+h.sizeof)
>> In argh, the delta between each item is (arg *).sizeof
>
> argv needs to be a contiguous thing so it's slower to append because
> it's not just storing a reference but the whole thing. There is
> consequently more realloc().
> argh is faster because it stores the addresses of the items.
>
> argv appends maybe 33 bytes, 33 bytes and so on.
> argh always appens 4 4 4... (32 bits OS) or 8 8 8...(64 bits OS). It's
> faster , always aligned...page-aware.that's all.
>
> Oh Oh oh.

I'm not sure what you are saying here, sorry.

-Steve
December 19, 2014
On 12/19/2014 07:42 AM, zeljkog wrote:
> On 19.12.14 16:25, Steven Schveighoffer wrote:

>> Did you compile both tests with the same command line parameters?
>
> Yes.

Can we see the test code please.

Ali

December 19, 2014
On 19.12.14 23:56, Ali Çehreli wrote:
> Can we see the test code please.
> 
> Ali

import std.stdio, std.datetime, std.random;

int N = 10_000;
int len = 1000;
int k = 4;

struct S{
   int n1, n2;
//~ 	this(this){
//~ 		writeln("this(this)");
//~ 	}
}

ref T[] append(T, Args...)(ref T[] arr, auto ref Args args)
{
   static if (args.length == 1)
      return arr ~= args[0];
   else{
      arr.length += args.length;
      foreach(i, ref e; args)
         arr[$ - args.length + i] = e;
      return arr;
   }
}

void append1(T)(ref T[] arr, T[] args...)
{
   arr ~= args;
}


void main() {
   S[] arr1 = new S[len];
   S[] arr2, arr3, arr4, arr5;
   foreach (i; 0..len)
      arr1[i] = S(uniform(0, 100), uniform(0, 100));
   auto sw = new StopWatch;

   sw.start();
   foreach(n; 0..N){
      for (int i = 0; i < len; i += k){
         arr2 ~= arr1[i];
         arr2 ~= arr1[i+1];
         arr2 ~= arr1[i+2];
         arr2 ~= arr1[i+3];
//~ 			arr2 ~= arr1[i+4];
//~ 			arr2 ~= arr1[i+5];
      }
      delete arr2;
   }
   sw.stop();
   long tm = sw.peek.msecs;
   writeln(tm);

   sw.reset();
   sw.start();
   foreach(n; 0..N){
      for (int i = 0; i < len; i += k){
         arr3 ~= [arr1[i], arr1[i+1], arr1[i+2], arr1[i+3]/+  , arr1[i+4], arr1[i+5] +/];
      }
      delete arr3;
   }
   sw.stop();
   tm = sw.peek.msecs;
   writeln(tm);

   sw.reset();
   sw.start();
   foreach(n; 0..N){
      for (int i = 0; i < len; i += k){
         arr4.append(arr1[i], arr1[i+1], arr1[i+2], arr1[i+3]/+   , arr1[i+4], arr1[i+5] +/);
      }
      delete arr4;
   }
   sw.stop();
   tm = sw.peek.msecs;
   writeln(tm);

   sw.reset();
   sw.start();
   foreach(n; 0..N){
      for (int i = 0; i < len; i += k){
         arr5.append1(arr1[i], arr1[i+1], arr1[i+2], arr1[i+3]/+   , arr1[i+4], arr1[i+5] +/);
      }
      delete arr5;
   }
   sw.stop();
   tm = sw.peek.msecs;
   writeln(tm);
}
December 20, 2014
On Friday, 19 December 2014 at 23:24:13 UTC, zeljkog wrote:
> On 19.12.14 23:56, Ali Çehreli wrote:
>> Can we see the test code please.
>> 
>> Ali
>
> import std.stdio, std.datetime, std.random;
>
> int N = 10_000;
> int len = 1000;
> int k = 4;
>
> struct S{
>    int n1, n2;
> //~ 	this(this){
> //~ 		writeln("this(this)");
> //~ 	}
> }
>
> ref T[] append(T, Args...)(ref T[] arr, auto ref Args args)
> {
>    static if (args.length == 1)
>       return arr ~= args[0];
>    else{
>       arr.length += args.length;
>       foreach(i, ref e; args)
>          arr[$ - args.length + i] = e;
>       return arr;
>    }
> }
>
> void append1(T)(ref T[] arr, T[] args...)
> {
>    arr ~= args;
> }
>
>
> void main() {
>    S[] arr1 = new S[len];
>    S[] arr2, arr3, arr4, arr5;
>    foreach (i; 0..len)
>       arr1[i] = S(uniform(0, 100), uniform(0, 100));
>    auto sw = new StopWatch;
>
>    sw.start();
>    foreach(n; 0..N){
>       for (int i = 0; i < len; i += k){
>          arr2 ~= arr1[i];
>          arr2 ~= arr1[i+1];
>          arr2 ~= arr1[i+2];
>          arr2 ~= arr1[i+3];
> //~ 			arr2 ~= arr1[i+4];
> //~ 			arr2 ~= arr1[i+5];
>       }
>       delete arr2;
>    }
>    sw.stop();
>    long tm = sw.peek.msecs;
>    writeln(tm);
>
>    sw.reset();
>    sw.start();
>    foreach(n; 0..N){
>       for (int i = 0; i < len; i += k){
>          arr3 ~= [arr1[i], arr1[i+1], arr1[i+2], arr1[i+3]/+  , arr1[i+4], arr1[i+5] +/];
>       }
>       delete arr3;
>    }
>    sw.stop();
>    tm = sw.peek.msecs;
>    writeln(tm);
>
>    sw.reset();
>    sw.start();
>    foreach(n; 0..N){
>       for (int i = 0; i < len; i += k){
>          arr4.append(arr1[i], arr1[i+1], arr1[i+2], arr1[i+3]/+
>   , arr1[i+4], arr1[i+5] +/);
>       }
>       delete arr4;
>    }
>    sw.stop();
>    tm = sw.peek.msecs;
>    writeln(tm);
>
>    sw.reset();
>    sw.start();
>    foreach(n; 0..N){
>       for (int i = 0; i < len; i += k){
>          arr5.append1(arr1[i], arr1[i+1], arr1[i+2], arr1[i+3]/+   , arr1[i+4], arr1[i+5] +/);
>       }
>       delete arr5;
>    }
>    sw.stop();
>    tm = sw.peek.msecs;
>    writeln(tm);
> }

You've forget the array of ref version. (append the address of the first data)
And adding S to an array is biased. S is fucking only >>8<< bytes. add more data to your struct.

December 20, 2014
On Saturday, 20 December 2014 at 00:15:21 UTC, MarcelDuchamp wrote:
> On Friday, 19 December 2014 at 23:24:13 UTC, zeljkog wrote:
>> On 19.12.14 23:56, Ali Çehreli wrote:
>>> Can we see the test code please.
>>> 
>>> Ali
>>
>> import std.stdio, std.datetime, std.random;
>>
>> int N = 10_000;
>> int len = 1000;
>> int k = 4;
>>
>> struct S{
>>   int n1, n2;
>> //~ 	this(this){
>> //~ 		writeln("this(this)");
>> //~ 	}
>> }
>>
>> ref T[] append(T, Args...)(ref T[] arr, auto ref Args args)
>> {
>>   static if (args.length == 1)
>>      return arr ~= args[0];
>>   else{
>>      arr.length += args.length;
>>      foreach(i, ref e; args)
>>         arr[$ - args.length + i] = e;
>>      return arr;
>>   }
>> }
>>
>> void append1(T)(ref T[] arr, T[] args...)
>> {
>>   arr ~= args;
>> }
>>
>>
>> void main() {
>>   S[] arr1 = new S[len];
>>   S[] arr2, arr3, arr4, arr5;
>>   foreach (i; 0..len)
>>      arr1[i] = S(uniform(0, 100), uniform(0, 100));
>>   auto sw = new StopWatch;
>>
>>   sw.start();
>>   foreach(n; 0..N){
>>      for (int i = 0; i < len; i += k){
>>         arr2 ~= arr1[i];
>>         arr2 ~= arr1[i+1];
>>         arr2 ~= arr1[i+2];
>>         arr2 ~= arr1[i+3];
>> //~ 			arr2 ~= arr1[i+4];
>> //~ 			arr2 ~= arr1[i+5];
>>      }
>>      delete arr2;
>>   }
>>   sw.stop();
>>   long tm = sw.peek.msecs;
>>   writeln(tm);
>>
>>   sw.reset();
>>   sw.start();
>>   foreach(n; 0..N){
>>      for (int i = 0; i < len; i += k){
>>         arr3 ~= [arr1[i], arr1[i+1], arr1[i+2], arr1[i+3]/+  , arr1[i+4], arr1[i+5] +/];
>>      }
>>      delete arr3;
>>   }
>>   sw.stop();
>>   tm = sw.peek.msecs;
>>   writeln(tm);
>>
>>   sw.reset();
>>   sw.start();
>>   foreach(n; 0..N){
>>      for (int i = 0; i < len; i += k){
>>         arr4.append(arr1[i], arr1[i+1], arr1[i+2], arr1[i+3]/+
>>  , arr1[i+4], arr1[i+5] +/);
>>      }
>>      delete arr4;
>>   }
>>   sw.stop();
>>   tm = sw.peek.msecs;
>>   writeln(tm);
>>
>>   sw.reset();
>>   sw.start();
>>   foreach(n; 0..N){
>>      for (int i = 0; i < len; i += k){
>>         arr5.append1(arr1[i], arr1[i+1], arr1[i+2], arr1[i+3]/+   , arr1[i+4], arr1[i+5] +/);
>>      }
>>      delete arr5;
>>   }
>>   sw.stop();
>>   tm = sw.peek.msecs;
>>   writeln(tm);
>> }
>
> You've forget the array of ref version. (append the address of the first data)
> And adding S to an array is biased. S is fucking only >>8<< bytes. add more data to your struct.

Seriously, do you get what I mean: 'roger this'/'copy that' ?

on an 64 bit OS, to append a 8 bytes struct is the same as appending a pointer. It Becommes more interesting to make an array of pointer when the struct is bigger.
When I've read your test I just thought: buy a rope man, you don't get the thing...
You want to add things but what ? a pointer or full stack of values ? 8 bytes it's nothing...


December 20, 2014
If you wish run this just add:

struct S{
   int n1, n2, n3, n4, n5 ...;
}
December 20, 2014
On Saturday, 20 December 2014 at 00:44:54 UTC, zeljkog wrote:
> If you wish run this just add:
>
> struct S{
>    int n1, n2, n3, n4, n5 ...;
> }

I wish. And I also wish you to get that to append in an array or a in a list some ptr its not the same as appending structs, particularly when the structs are bigger than a ptr.

Thank for hearing me. Your measures will be better.
ОПА!

December 20, 2014
On Friday, 19 December 2014 at 14:41:07 UTC, Anonymous wrote:
> What a big surprise. If you make an array of struct, each item of your array has the length of the struct. structs a values.
> If you want to append a struct to an array just append a pointer to the struct:
>
> ----------
> struct arg{uint a,r,g,h;};
>
> arg * [] argh;
> arg [] argv;
>
> foreach(immutable i; 0..1000)
>   argh ~= new arg;
> ----------
>
> so in argh, each item is a size_t pointer. damn.
> In argv, the delta between each item is (a.sizeof+r.sizeof+g.sizeof+h.sizeof)
> In argh, the delta between each item is (arg *).sizeof

The two versions which zeljkog compared both deal with values,
not pointers. You're barking up the wrong tree.