Benchmark of a matrices example

We present a small benchmark comparing time and space performance of a program whose original version is compared against the fused version obtained with HFusion. The results were measured by compiling the program with the Glasgow Haskell Compiler (GHC) version 6.12.3 feeding it with the -O flag. The -O flag enables various optimizations incluiding the shortcut fusion implementation of GHC for functions in the standard libraries. This implies that the tests presented below always offered a chance to GHC to improve the programs via shortcut fusion, though it would do so only in the case of compositions of functions in the standard libraries.

The following table presents the time comparisons in seconds. The time ratio is calculated as 100 * F/O where O is the running time of the original program and F is the running time of the fused program.

Program O F time ratio
transposeMapConcat 10.85 6.88 63%

In the following table we present the comparisons of total allocated bytes. The space ratio is calculated as 100 * F/O where O is the count of kilobytes allocated by the original program and F is the count of kilobytes allocated by the fused program.

Program O F space ratio
transposeMapConcat 10,329,161 8,872,539 86%

Testsuite

We first present the original program followed by the fused program.

transposeMapConcat.hs (original)


main = pr . transpose . map concat$ matrix

transpose = foldr (zipWith (:)) (repeat [])

n, m, k :: Int
n = 3000
m = 3000
k = 4000

matrix :: [[[Int]]]
matrix = replicate k (replicate m (replicate 1 n)) 

pr :: Show a => [[a]] -> IO ()
pr = print . concat 

transposeMapConcat.hs (fused)


main = pr . tm$ matrix

n, m, k :: Int
n = 3000
m = 3000
k = 4000

matrix :: [[[Int]]]
matrix = replicate k (replicate m (replicate 1 n)) 

pr :: Show a => [[a]] -> IO ()
pr = print . concat 

{- Definitions used for fusion:

-- |foldr (zipWith (:) (repeat [])| specialized
transpose [] = repeat []
transpose (xs:xss) = zipWith (:) xs (transpose xss)

-- |map concat| specialized 
mapConcat [] = []
mapConcat (xs:xss) = concat xs : mapConcat xss

concat [] = []
concat (xs:xss) = xs ++ concat xss

[] ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)

zipWith f (x:xs) (y:ys)  = f x y : zipWith f xs ys
zipWith f _ _            = []

-}

{- result of fusing |transpose . mapConcat|

tm [] = repeat []
tm (xs9:xss9) = zipWith (:) (concat xs9) (tm xss9)

-}

-- result of fusing |zipWith f . concat|: 

zc f [] v8 = []
zc f (xs29:xss30) v8 = v19 f xss30 xs29 v8

v19 f xss29 [] v8 = zc f xss29 v8
v19 f xss29 (x8:xs30) (y:ys) = f x8 y : v19 f xss29 xs30 ys
v19 f xss29 (_:_) v8 = []

-- |tm| rewritten to use zc
tm [] = repeat []
tm (xs9:xss9) = zc (:) xs9 (tm xss9)