As a follow-up to

https://forum.dlang.org/post/jfgpngdudtprzznrc...@forum.dlang.org

I managed to put together the benchmark

https://github.com/nordlow/phobos-next/blob/fa3526b15c746bda50a195f4e492ab2de9c15287/benchmarks/allocators/source/app.d

which run (via ldc)

dub run --build=release-nobounds

prints

DoubleNode Region allocator: 103 ms and 810 μs
DoubleNode new-allocation: 2 secs, 565 ms, and 566 μs
DoubleNode with global allocator: 2 secs, 680 ms, and 93 μs
...

proving the massive speedups possible when using, for instance, a Region allocator over a single continuous memory block, in this case allocated by the GC.

The code tested is in essence the performance of 10 million consecutive calls to the factory function `make` constructing instances of the class `DoubleNode`:

void benchmarkAllocatorsRegion()
{
immutable nodeCount = 10_000_000; // number of `Nodes`s to allocate

void[] buf = GCAllocator.instance.allocate(nodeCount * __traits(classInstanceSize, DoubleNode)); auto allocator = Region!(NullAllocator, platformAlignment)(cast(ubyte[])buf);

Type make(Type, Args...)(Args args) // TODO this should be pure
    {
        pragma(inline, true);
        return allocator.make!Type(args);
    }

    void[] allocate(size_t bytes)
    {
return allocator.allocate(bytes); // TODO should be @safe pure
    }

/* latest pointer here to prevent fast scoped non-GC allocation in LDC */
    void* latestPtr;

    void testRegionAllocator()
    {
        auto x = make!DoubleNode(42);
        assert(x);
        latestPtr = cast(void*)x;
    }

    void testNewAllocation()
    {
        auto x = new DoubleNode(42);
        latestPtr = cast(void*)x;
    }

    void testGlobalAllocator()
    {
        auto x = theAllocator.make!DoubleNode(42);
        latestPtr = cast(void*)x;
    }

    const results = benchmark!(testRegionAllocator,
                               testNewAllocation,
                               testGlobalAllocator)(nodeCount);
    writeln("DoubleNode Region allocator: ", results[0]);
    writeln("DoubleNode new-allocation: ", results[1]);
    writeln("DoubleNode with global allocator: ", results[2]);
}

However, I can't figure out how we can be sure that the destructors of `DoubleNode` are called for all the 10 million objects. Is there a way to tell the GC where the class instances that need to be destroyed lie (when nothing references them anymore).
  • How to destruct class instanc... Per Nordlöw via Digitalmars-d-learn

Reply via email to