[Haskell-cafe] GHC vs GCC

Rafael Cunha de Almeida almeidaraf at gmail.com
Fri Mar 26 13:46:58 EDT 2010


Hello,

During a talk with a friend I came up with two programs, one written in
C and another in haskell.

Haskell
	main :: IO ()
	main = print $ rangeI 0 0
	
	rangeK :: Int -> Int -> Int -> Int -> Int
	rangeK i j k acc
	    | k < 1000 =
	        if i * i + j * j + k * k `mod` 7 == 0
	        then rangeK i j (k+1) (acc+1)
	        else rangeK i j (k+1) acc
	    | otherwise = acc
	
	rangeJ :: Int -> Int -> Int -> Int
	rangeJ i j acc
	    | j < 1000 = rangeJ i (j+1) (acc + rangeK i j 0 0)
	    | otherwise = acc
	
	rangeI :: Int -> Int -> Int
	rangeI i acc
	    | i < 1000 = rangeI (i+1) (acc + (rangeJ i 0 0))
	    | otherwise = acc

C
	main()
	{
	    printf("%d\n", rangeI(0, 0));
	    return 0;
	}
	
	rangeK(i, j, k, acc)
	{
		if (k < 1000) {
			if (i * i + j * j + k * k % 7 == 0)
				return rangeK(i, j, k+1, acc+1);
			else
				return rangeK(i, j, k+1, acc);
		} else
			return acc;
	}
	
	rangeJ(i, j, acc)
	{
		if (j < 1000)
			return rangeJ(i, j+1, acc + rangeK(i, j, 0, 0));
		else
			return acc;
	}
	
	rangeI(i, acc)
	{
		if (i < 1000)
			return rangeI(i+1, acc + rangeJ(i, 0, 0));
		else
			return acc;
	}

I tried to keep both programs as similar as possible. I'm pretty
confident that the algorithm being executed are exactly the same. That
is, there's no lists being used vs. arrays or anything like that. I even
used Int instead of Integer to make sure an equivalent version of +, *
and mod are called (perhaps that was what I did wrong?)

I compiled the haskell code with ghc -O3 and I compiled the C code with
gcc -O3. The execution time of the programs were dramatically different.
You can test it yourselves, but here is the time I've got in my system:

The Haskell version:
real	0m45.335s
user	0m45.275s
sys	0m0.004s

against the C version:
real	0m6.021s
user	0m6.004s
sys	0m0.004s

Also, I found it interesting that a iterative version of that algorithm
in C ran in the same time as the recursive version. So it seems like gcc
was successfuly able to make those tail recursive functions into iterations.

It strikes me as surprising that Haskell would perform so much slower in
that example. I was expecting maybe a few seconds due to the garbage
collector or something like that, but not more than 7 times slower.


More information about the Haskell-Cafe mailing list