debugging memory allocations

Duncan Coutts duncan.coutts at worc.ox.ac.uk
Wed Feb 2 08:37:56 EST 2005


All,

I'm looking for advice on how to figure out why some piece of code is
allocating memory when I think it ought to be able to work in constant
space.

In these cases we cannot turn on traditional profiling since that would
interfere with the optimisations we are relying on to eliminate most of
the other memory allocations.

Would looking at the core files help? What would I be looking for?

Here's a simple version that I would expect to run in constance space.

pixbufSetGreen :: Pixbuf -> IO ()
pixbufSetGreen pixbuf = do
  ptr <- pixbufGetPixels pixbuf
  sequence_ 
    [ do pokeByteOff ptr (y*384+3*x)   (0  ::Word8)
         pokeByteOff ptr (y*384+3*x+1) (128::Word8)
         pokeByteOff ptr (y*384+3*x+2) (96 ::Word8)
    | y <- [0..127]
    , x <- [0..127] ]

(Don't worry about all those random constants, it's just test code!)

I thought this might be the case since in ghc's Data.Array.Base we have
some similar style code:

{-# INLINE newArray #-}
        -- The INLINE is crucial, because until we know at least which monad
        -- we are in, the code below allocates like crazy.  So inline it,
        -- in the hope that the context will know the monad.
newArray (l,u) init = do
        marr <- newArray_ (l,u)
        sequence_ [unsafeWrite marr i init | i <- [0 .. rangeSize (l,u) - 1]]
        return marr

Note of course that in my example we know exactly which monad we're using.

Here is the real example code I was writing when I found that it was
using lots of cpu cycles and +RTS -B -RTS beeps lots and lots.

Compiled using -O (-O2 is the same) -fglasgow-exts with ghc-6.2.2.

pixbufSetPixelsRGB8 :: Pixbuf -> (Int -> Int -> (# Word8, Word8, Word8 #)) -> IO ()
pixbufSetPixelsRGB8 pixbuf setPixel = do
  -- TODO assert that the format is RGB8
  rowStride <- pixbufGetRowstride pixbuf
  width <- pixbufGetWidth pixbuf
  height <- pixbufGetHeight pixbuf
  let loop ptr y | y == height = return ()
                 | otherwise = do
        let rowLoop ptr x | x == width = return ()
                          | otherwise =
              case setPixel x y of
                (# red, green, blue #) -> do
                  pokeByteOff ptr 0 red
                  pokeByteOff ptr 1 green
                  pokeByteOff ptr 2 blue
                  rowLoop (ptr `plusPtr` 3) (x+1)
        rowLoop ptr 0
        loop (ptr `plusPtr` rowStride) (y+1)

  pixelsPtr <- pixbufGetPixels pixbuf
  loop pixelsPtr 0

It was being called like so:

setWierdColour :: Int -> Pixbuf -> IO ()
setWierdColour counter pixbuf =
  let val = fromIntegral counter in
  pixbufSetPixelsRGB8 pixbuf (\x y -> (# fromIntegral x + val
                                       , fromIntegral y + val
                                       , fromIntegral x + fromIntegral y + val #))

Duncan



More information about the Glasgow-haskell-users mailing list