[Haskell-cafe] Please help me spot where space leak occur.

Olexander Kozlov ookozlov at gmail.com
Thu Jul 21 10:22:12 CEST 2011


Greetings Haskell community,

I stuck with a space leak problem in simple task. I have a function
described with a list of pairs:

   type Fn a b = [(a, b)]

mapping values from a to b. And I have a composition operation which accepts
two functions and returns
theirs composition:

   compose :: Eq b => Fn a b -> Fn b c -> Fn a c

Finding composition of 1,000,000 functions takes about 240M with the
following implementation:

type Fn a b = [(a, b)]

lkup :: Eq a => a -> Fn a b -> b
lkup x ((a, b) : abs) = if x /= a then lkup x abs else b

compose :: Eq b => Fn a b -> Fn b c -> Fn a c

compose ((a, b) : abs) bcs = (a, lkup b bcs) : compose abs bcs
compose [] _ = []

fldl :: (a -> b -> a) -> a -> [b] -> a

fldl f z (x:xs) = fldl f (f z x) xs
fldl _ z [] = z

fna = [(1, 2), (2, 3), (3, 1)]
fni = [(1, 1), (2, 2), (3, 3)]

test = fldl compose fni (replicate 1000000 fna)

main = print test

I build with:

   ghc --make -prof -auto-all -caf-all -fforce-recomp -rtsopts Test.hs

Profile results:

   Test.exe +RTS -K50M -p -RTS

total time  =        0.34 secs   (17 ticks @ 20 ms)
total alloc = 240,003,820 bytes  (excludes profiling overheads)

COST CENTRE                    MODULE               %time %alloc

compose                        Main                  58.8   80.0
lkup                           Main                  35.3    0.0
test                           Main                   5.9   11.7
fldl                           Main                   0.0    8.3

After reading 'High-Performance Haskell' by Johan Tibell I tried to made my
compose function strict:

compose :: Eq b => Fn a b -> Fn b c -> Fn a c

compose ((a, b) : abs) bcs = let c = lkup b bcs in c `seq` (a, c) : compose
abs bcs
compose [] _ = []

and memory consuption reduced down to 180M. Good achievement but still too
much!

Profile results:

   Test.exe +RTS -K50M -p -RTS

total time  =        0.24 secs   (12 ticks @ 20 ms)
total alloc = 180,003,820 bytes  (excludes profiling overheads)

COST CENTRE                    MODULE               %time %alloc

compose                        Main                  83.3   73.3
lkup                           Main                   8.3    0.0
fldl                           Main                   8.3   11.1
test                           Main                   0.0   15.6

I tried to make fldl strict as well:

fldl :: (a -> b -> a) -> a -> [b] -> a

fldl f z (x:xs) = let z' = f z x in z' `seq` fldl f z' xs
fldl _ z [] = z

and end up with 160M of total allocations.

Profile results:

   Test.exe +RTS -K32M -p -RTS

total time  =        0.30 secs   (15 ticks @ 20 ms)
total alloc = 160,003,820 bytes  (excludes profiling overheads)

COST CENTRE                    MODULE               %time %alloc

compose                        Main                  46.7   82.5
lkup                           Main                  40.0    0.0
test                           Main                   6.7   17.5
fldl                           Main                   6.7    0.0

Please help me spot where space leak occur, I see no other places for space
leaks. I'll appreciate any help.

(I intentionally wrote my own implementations of lookup and foldl to have
direct control on them.)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20110721/6f49ca0f/attachment.htm>


More information about the Haskell-Cafe mailing list