I have a program that, to all appearances, is behaving properly.  It uses
very little memory to run, it has the profile I would expect looking at
+RTS -hc.  I have no reason to believe there is a memory leak (in the sense
that it's not lazily holding on to things it no longer needs or strictly
generating things it doesn't need yet).  But it's slow, and according to
-sstderr, most of the time is spent garbage-collecting.

Why is the garbage-collector consuming so much running time? How can I deal
with it?

The program is a solution to this problem:
https://open.kattis.com/problems/tourist

The input data can be found here:
http://heim.ifi.uio.no/~db/nm-i-programmering/nm2004/testdata/h.in
module Main(main) where

import           Control.DeepSeq
import           Control.Monad
import           Data.Array
import           Data.List

type Col = Int

newtype MInt = M {fromM :: Int}
  deriving (Eq, Ord)

instance NFData MInt

main::IO()
main = do
  numCases <- readLn
  replicateM_ numCases doProb

doProb :: IO()
doProb = do
  [width,height] <- liftM (map read . words) getLine :: IO [Int]
  rows <- replicateM height getLine
  let rowArrays = map (listArray (1, width)) rows
  let initPoints =
        listArray
          ((1, 1), (width, width))
          (m0 : repeat mnone) :: Scores
  let resPoints = foldl' maxPoints initPoints rowArrays
  print . fromM $ resPoints ! (width, width)

type Scores = Array (Col, Col) MInt
type GridRow = Array Col Char

maxPoints :: Scores -> GridRow -> Scores
maxPoints curVals gr = force x1x2
  where
    (_, width) = bounds gr
    blocked :: Col -> Bool
    blocked c = gr ! c == '#'
    grVal :: Col -> MInt
    grVal = getVal . (gr !)
    grVal1 :: (Col, Col) -> MInt
    grVal1 (c1, c2)
      | blocked c1 = mnone
      | c1 < c2 = grVal c1
      | otherwise = m0
    grVal2 :: (Col, Col) -> MInt
    grVal2 (_, c2) = grVal c2
    i1i2 :: Scores
    i1i2 = mapWithIdx go curVals
      where
        go :: (Col, Col) -> MInt -> MInt
        go pr = ((grVal1 pr +^ grVal2 pr) +^)
    computeNext :: Scores -> ((Col, Col) -> MInt) -> Scores
    computeNext prev fun = funArray ((1,1),(width,width)) go
      where
        go (c1, c2) =
          max
            (prev ! (c1, c2))
            (fun (c1, c2))
    x1i2 :: Scores
    x1i2 =
      computeNext i1i2 go
        where
          go pr@(i, j) =
            x1i2 !^ (i - 1, j) +^ grVal1 pr
    x1x2 =
      computeNext x1i2 go
        where
          go pr@(i, j) =
            x1x2 !^ (i, j - 1) +^ grVal2 pr

funArray :: Ix i => (i, i) -> (i -> e) -> Array i e
funArray bs f = listArray bs . map f $ range bs

(!^) :: Ix ix => Array ix MInt -> ix -> MInt
(!^) arr i
  | inRange (bounds arr) i = arr ! i
  | otherwise = mnone

m0 :: MInt
m0 = M 0

mnone :: MInt
mnone = M (-1)

(+^) :: MInt -> MInt -> MInt
M (-1) +^ _ = mnone
_ +^ M (-1) = mnone
M x +^ M y = M (x + y)
infixl 6 +^

mapWithIdx :: Ix i => (i -> a -> b) -> Array i a -> Array i b
mapWithIdx f arr = listArray (bounds arr) . map (uncurry f) $ assocs arr

getVal :: Char -> MInt
getVal '#' = M (-1)
getVal '*' = M 1
getVal '.' = M 0
getVal _ = error "Unrecognized char"
_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

Reply via email to