GC question

Cym13 via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Feb 5 05:08:37 PST 2017


On Sunday, 5 February 2017 at 04:22:30 UTC, rikki cattermole 
wrote:
> On 05/02/2017 5:02 PM, thedeemon wrote:
>
> snip
>
>> It may look so from a distance. But in my experience it's not 
>> that bad.
>> In most software I did in D it did not matter really (it's 
>> either 64-bit
>> or short lived programs) and the control D gives to choose how 
>> to deal
>> with everything makes it all quite manageable, I can decide 
>> what to take
>> from both worlds and hence pick the best, not the worst.
>
> The best of both worlds can be done quite simply.
>
> Instead of a chain of input ranges like:
>
> int[] data = input.filter!"a != 7".map!"a * 2".array;
>
> Use:
>
> int[] data;
> data.length = input.length;
>
> size_t i;
> foreach(v; input.filter!"a != 7".map!"a * 2") {
> 	data[i] = v;
> 	i++;
> }
>
> data.length = i;
>
> Of course this is dirt simple example, but instead look at it 
> for e.g. a csv parser with some complex data structure creation 
> + manipulation.
>
> I have some real world code here[0] that uses it. Not only is 
> there less allocations and uses the GC but also it ends up 
> being significantly faster!
>
> [0] 
> https://gist.github.com/rikkimax/42c3dfa6500155c5e441cbb1437142ea#file-reports-d-L124

Some data to weigh that in order to compare different memory 
management strategies on that simple case:

#!/usr/bin/env rdmd

import std.conv;
import std.stdio;
import std.array;
import std.range;
import std.algorithm;

auto input = [1, 2, 7, 3, 7, 8, 8, 9, 7, 1, 0];


void naive() {
     int[] data = input.filter!(a => a!= 7).map!(a => a*2).array;
     assert(data == [2, 4, 6, 16, 16, 18, 2, 0], data.to!string);
}

void maxReallocs() {
     int[] data;

     size_t i;
     foreach(v ; input.filter!(a => a!=7).map!(a => a*2)) {
         data ~= v;
     }

     assert(data == [2, 4, 6, 16, 16, 18, 2, 0], data.to!string);
}

void betterOfTwoWorlds() {
     int[] data;
     data.length = input.length;

     size_t i;
     foreach(v ; input.filter!(a => a!=7).map!(a => a*2)) {
         data[i] = v;
         i++;
     }
     data.length = i;

     assert(data == [2, 4, 6, 16, 16, 18, 2, 0], data.to!string);
}

void explicitNew() {
     int[] data = new int[input.length];
     scope(exit) delete data;

     size_t i;
     foreach(v ; input.filter!(a => a!=7).map!(a => a*2)) {
         data[i] = v;
         i++;
     }
     data.length = i;

     assert(data == [2, 4, 6, 16, 16, 18, 2, 0], data.to!string);
}

void cStyle() @nogc {
     import std.c.stdlib;

     int* data = cast(int*)malloc(input.length * int.sizeof);
     scope(exit) free(data);

     size_t i;
     foreach(v ; input.filter!(a => a!=7).map!(a => a*2)) {
         data[i++] = v;
     }

     debug assert(data[0..i] == [2, 4, 6, 16, 16, 18, 2, 0], 
data.to!string);
}

void onTheStack() @nogc {
     int[100] data;

     size_t i;
     foreach(v ; input.filter!(a => a!=7).map!(a => a*2)) {
         data[i++] = v;
     }

     debug assert(data[0..i] == [2, 4, 6, 16, 16, 18, 2, 0], 
data.to!string);
}

void main(string[] args) {
     import std.datetime;
     benchmark!(
         naive,
         maxReallocs,
         betterOfTwoWorlds,
         explicitNew,
         cStyle,
         onTheStack
     )(100000).each!writeln;
}

/* Results:

Compiled with dmd -profile=gc test.d
====================================

TickDuration(385731143)  // naive,
TickDuration(575673615)  // maxReallocs,
TickDuration(255928562)  // betterOfTwoWorlds,
TickDuration(270497154)  // explicitNew,
TickDuration(97596363)   // cStyle,
TickDuration(96467459)   // onTheStack

GC usage:

bytes allocated, allocations, type, function, file:line
        17600000          100000 int[] test.explicitNew test.d:43
         4400000          100000 int[] test.betterOfTwoWorlds 
test.d:30
         3200000          800000 int[] test.maxReallocs test.d:22
         3200000          100000 int[] test.maxReallocs test.d:25
         3200000          100000 int[] test.explicitNew test.d:51
         3200000          100000 int[] test.explicitNew test.d:53
         3200000          100000 int[] test.betterOfTwoWorlds 
test.d:37
         3200000          100000 int[] test.betterOfTwoWorlds 
test.d:39
         3200000          100000 
std.array.Appender!(int[]).Appender.Data 
std.array.Appender!(int[]).Appender.this 
/usr/include/dlang/dmd/std/array.d:2675
         3200000          100000 int[] test.naive test.d:14

Compiled with dmd -O -inline test.d
===================================

TickDuration(159383005)  // naive,
TickDuration(187192137)  // maxReallocs,
TickDuration(94094585)   // betterOfTwoWorlds,
TickDuration(102374657)  // explicitNew,
TickDuration(41801695)   // cStyle,
TickDuration(45613954)   // onTheStack

Compiled with dmd -O -inline -release -boundscheck=off test.d
=============================================================

TickDuration(152151439)  // naive,
TickDuration(140870515)  // maxReallocs,
TickDuration(46740440)   // betterOfTwoWorlds,
TickDuration(59089016)   // explicitNew,
TickDuration(26038060)   // cStyle,
TickDuration(25984371)   // onTheStack

*/



More information about the Digitalmars-d-learn mailing list