[Performance] shootout.binarytrees when implemented with gc is 10x slower than C# on .NET 2.0
Kyle Furlong
kylefurlong at gmail.com
Sat Nov 11 16:27:23 PST 2006
Andrey Khropov wrote:
> Here is the D code for shootout.binarytrees with GC. Absolutely equal to the C#
> code (I also embedded a timer):
>
> ------------------------------------------------------------------------
> import std.c.stdlib, std.stdio, std.perf, std.gc;
>
> int main(char[][] args)
> {
> int N = args.length > 1 ? atoi(args[1]) : 1;
>
> auto t = new HighPerformanceCounter();
> t.start();
>
> int minDepth = 4;
> int maxDepth = (minDepth + 2) > N ? minDepth + 2 : N;
> int stretchDepth = maxDepth + 1;
>
> TreeNode stretchTree = TreeNode.BottomUpTree(0, stretchDepth);
> writefln("stretch tree of depth ",stretchDepth,"\t check:
> ",stretchTree.ItemCheck);
>
> TreeNode longLivedTree = TreeNode.BottomUpTree(0, maxDepth);
>
> int depth;
> for(depth = minDepth; depth <= maxDepth; depth += 2)
> {
> int check, iterations = 1 << (maxDepth - depth + minDepth);
>
> for(int i = 1; i <= iterations; i++)
> {
> auto tempTree = TreeNode.BottomUpTree(i, depth);
> check += tempTree.ItemCheck;
> //delete tempTree;
>
> tempTree = TreeNode.BottomUpTree(-i, depth);
> check += tempTree.ItemCheck;
> //delete tempTree;
> }
>
> writefln(iterations * 2,"\t trees of depth ",depth,"\t check: ",check);
> }
>
> writefln("long lived tree of depth ",maxDepth,"\t check:
> ",longLivedTree.ItemCheck);
>
> t.stop();
>
> writefln(t.milliseconds()," ms elapsed.");
>
> return 0;
> }
>
> class TreeNode
> {
> public:
> this(int item, TreeNode left = null, TreeNode right = null)
> {
> this.item = item;
> this.left = left;
> this.right = right;
> }
>
> static TreeNode BottomUpTree(int item, int depth)
> {
> if(depth > 0)
> return new TreeNode(item
> ,BottomUpTree(2 * item - 1, depth - 1)
> ,BottomUpTree(2 * item, depth - 1));
> return new TreeNode(item);
> }
>
> int ItemCheck()
> {
> if(left)
> return item + left.ItemCheck() - right.ItemCheck();
> return item;
> }
> private:
> TreeNode left, right;
> int item;
> }
> ------------------------------------------------------------------------
> Here's the C# code (also with embedded timer):
> ------------------------------------------------------------------------
> using System;
> using System.Diagnostics;
>
> class BinaryTrees
> {
> const int minDepth = 4;
>
> public static void Main(String[] args)
> {
> int n = 0;
> if (args.Length > 0) n = Int32.Parse(args[0]);
>
> Stopwatch t = new Stopwatch();
> t.Start();
>
> int maxDepth = Math.Max(minDepth + 2, n);
> int stretchDepth = maxDepth + 1;
>
> int check = (TreeNode.bottomUpTree(0,stretchDepth)).itemCheck();
> Console.WriteLine("stretch tree of depth {0}\t check: {1}", stretchDepth,
> check);
>
> TreeNode longLivedTree = TreeNode.bottomUpTree(0,maxDepth);
>
> for (int depth=minDepth; depth<=maxDepth; depth+=2){
> int iterations = 1 << (maxDepth - depth + minDepth);
>
> check = 0;
> for (int i=1; i<=iterations; i++)
> {
> check += (TreeNode.bottomUpTree(i,depth)).itemCheck();
> check += (TreeNode.bottomUpTree(-i,depth)).itemCheck();
> }
>
> Console.WriteLine("{0}\t trees of depth {1}\t check: {2}",
> iterations*2, depth, check);
> }
>
> Console.WriteLine("long lived tree of depth {0}\t check: {1}",
> maxDepth, longLivedTree.itemCheck());
>
> t.Stop();
> Console.WriteLine(t.ElapsedMilliseconds + "ms elapsed.");
> }
>
>
> class TreeNode
> {
> private TreeNode left, right;
> private int item;
>
> TreeNode(int item){
> this.item = item;
> }
>
> TreeNode(int item,TreeNode left, TreeNode right){
> this.left = left;
> this.right = right;
> this.item = item;
> }
>
> internal static TreeNode bottomUpTree(int item, int depth){
> if (depth>0){
> return new TreeNode(
> item,
> bottomUpTree(2*item-1, depth-1),
> bottomUpTree(2*item, depth-1)
> );
> }
> else {
> return new TreeNode(item);
> }
> }
>
> internal int itemCheck(){
> // if necessary deallocate here
> if (left==null) return item;
> else return item + left.itemCheck() - right.itemCheck();
> }
> }
> }
> ------------------------------------------------------------------------
>
> So the results are (with cmdline parameter = 16):
>
> C# on .NET 2.0 : 1.902 sec
> DMD 0.173 - malloc(original version) : 5.189 sec
> C# on Mono 1.1.18 : 6.630 sec
> DMD 0.173 - full GC : 19.720 sec
>
Andrey, its no secret that the D GC is not implemented to be the fastest
around. C# I believe uses at the least a generational collector, which I
think is also copying.
D currently uses a conservative mark and sweep collector. Rock solid,
but slow.
More information about the Digitalmars-d
mailing list