[Haskell-cafe] Memory usage when passing arrays in state
Ryan Ingram
ryani.spam at gmail.com
Tue Mar 3 20:48:54 EST 2009
I've found DiffArrays to be way too slow/memory-hogging for real usage.
Since you are in IO already (StateT s IO), you'll probably be better
off using a mutable array for a data structure.
Some things are still best done in the imperative style. You can be a
bit safer by using ST as the bottom monad, however, and returning the
result as a pure array. This gives you a single copy per "runST".
Alternatively, use IntMap instead of arrays if you want a pure data
structure with reasonably efficient update/lookup.
-- ryan
On Tue, Mar 3, 2009 at 4:44 PM, Tobias Olausson <tobsan at gmail.com> wrote:
> Hello all.
> I am currently implementing an emulation of a CPU, in which the CPU's
> RAM is part of the internal state
> that is passed around in the program using a state monad. However, the
> program performs
> unexpectingly bad, and some profiling information makes us believe
> that the problem is the high
> memory usage of the program.
>
> The program below is similar to our main program used when testing a
> sorting algorithm in this CPU:
>
> module Main where
>
> import Control.Monad.State.Lazy
> import Data.Word
> import Data.Array.Diff
> import Control.Concurrent (threadDelay)
>
> data LoopState = LoopState
> { intVal :: Integer
> , diff :: DiffUArray Word8 Word8
> }
>
> initState :: LoopState
> initState = LoopState 0 (array (0x00,0xFF) [(idx,0)|idx<-[0x00..0xFF]])
>
> main :: IO ()
> main = do
> execStateT looper initState >>= putStrLn . show . intVal
>
> looper :: StateT LoopState IO ()
> looper = do
> st <- get
> let res = intVal st + 1
> idx = fromIntegral res
> put $ st { intVal = res, diff = (diff st) // [(idx,idx)] }
> if res == 13000000
> then return ()
> else looper
>
> Of course our program does more than updating a counter ;-)
> Compiling and running this program yields the following result:
>
> [~]:[olaussot] >> ghc --make -O2 -o array ArrayPlay.hs
> [~]:[olaussot] >> ./array +RTS -sstderr
> ./array +RTS -sstderr
> 13000000
> 313,219,740 bytes allocated in the heap
> 1,009,986,984 bytes copied during GC
> 200,014,828 bytes maximum residency (8 sample(s))
> 4,946,648 bytes maximum slop
> 393 MB total memory in use (3 MB lost due to fragmentation)
>
> Generation 0: 590 collections, 0 parallel, 3.06s, 3.09s elapsed
> Generation 1: 8 collections, 0 parallel, 3.56s, 4.21s elapsed
>
> INIT time 0.00s ( 0.00s elapsed)
> MUT time 0.27s ( 0.27s elapsed)
> GC time 6.62s ( 7.30s elapsed)
> EXIT time 0.00s ( 0.00s elapsed)
> Total time 6.89s ( 7.57s elapsed)
>
> %GC time 96.1% (96.4% elapsed)
>
> Alloc rate 1,155,958,754 bytes per MUT second
>
> Productivity 3.9% of total user, 3.6% of total elapsed
>
> Why does the program spend 96.1% of its total running time collecting garbage?
> Any tips to make this program perform better are appreciated.
> Please do tell if anything is unclear.
>
> --
> Tobias Olausson
> tobsan at gmail.com
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
More information about the Haskell-Cafe
mailing list