[Haskell]Вопорос по ускорению/улучшению проги
От: STilda  
Дата: 09.04.09 20:33
Оценка:
День добрый. Написал небольшую программку. Читает из файла список чисел, фильтрует, записывает результат. Так как с Хаскелем начинающий, спрашиваю общественность, можно ли улучшить/ускорить/уменьшить поток памяти?

module Main where

import qualified Data.ByteString.Lazy.Char8 as B 
import Maybe
import Data.List
import IO
import System.Environment

-- input type
type IT = [Int]

--  output type
type OT = [Int]

main = do 
    (inputFilePath : outputFilePath : []) <- getArgs
    loadData inputFilePath >>= return.treatData >>= saveResult outputFilePath

-- function to load data
loadData :: String -> IO IT
loadData fileName = do
    content <- B.readFile fileName
    loadIntList content

-- load int list
loadIntList :: B.ByteString -> IO IT
loadIntList str = return ( map (fst.fromJust.B.readInt) . filter (not.B.null) . B.splitWith isBreakSymbol $ str )
    where 
        isBreakSymbol '\n' = True
        isBreakSymbol ' '  = True
        isBreakSymbol _    = False

-- function to save data
saveResult :: String -> OT -> IO ()
saveResult fileName res = writeFile fileName ( concat $ map ((" "++).show) res )

-- scale and convert
toDouble :: Double -> [Int] -> [Double]
toDouble scale = map ((scale*).fromIntegral)

-- scale and convert
toInt :: Double -> [Double] -> [Int]
toInt scale = map (truncate.(scale*))

-- dot product of two lists
convolution :: [Double] -> [Double] -> Double
convolution filter dat = zipEx filter dat 0
    where 
        zipEx [] _  acc = acc
        zipEx _  [] acc = acc
        zipEx (a:as) (b:bs) acc = zipEx as bs $! (acc+a*b)

-- Example:
-- for m = 4, p = 2,  [1,2,3,4,5,6,7,8,9,10,...] => [ [1,2,3,4], [3,4,5,6], [5,6,7,8], ... ]
partition1 :: Int -> Int -> [Double] -> [[Double]]
partition1 m p lst = map (take m) $ iterate (drop p) lst

-- function to treat data
treatData :: IT -> OT
treatData = toInt 1000000 . map (convolution filter) . takeWhile (not.null) . partition1 m p . toDouble 0.01
    where
        filter = [0.1,0.3,-0.2,-0.1,3.2,0.7,4.5,7.8,-1.3,6,0.1,0.3,-0.2,-0.1,3.2,0.7,4.5,7.8,-1.3,6]
        m = length filter
        p = 2

компилирую : ghc.exe -O2

Привожу профайлинг для 10 млн чисел на входе.
COST CENTRE                    MODULE               %time %alloc

convolution                    Main                  22.4   18.8
loadIntList                    Main                  21.6   17.6
saveResult                     Main                  20.8   21.3
partition1                     Main                  15.4   23.1
toInt                          Main                  12.0   11.7
treatData                      Main                   4.3    2.7
toDouble                       Main                   3.5    4.2

1. Почему toInt намного затратнее toDouble ?
2. Можно ли оптимизировать partition1 по памяти?
3. Можно ли сделать более эффективно loadIntList и saveResult?

Также через запуск с RTS видно здоровый поток по памяти (9 гиг) что настораживает.
Это нормально или можно поправить?
   9,621,450,136 bytes allocated in the heap
      13,334,116 bytes copied during GC
          36,912 bytes maximum residency (78 sample(s))
          12,460 bytes maximum slop
               2 MB total memory in use (0 MB lost due to fragmentation)

  Generation 0: 18275 collections,     0 parallel,  0.08s,  0.08s elapsed
  Generation 1:    78 collections,     0 parallel,  0.03s,  0.03s elapsed

  INIT  time    0.02s  (  0.00s elapsed)
  MUT   time   12.19s  ( 14.67s elapsed)
  GC    time    0.11s  (  0.11s elapsed)
  EXIT  time    0.00s  (  0.00s elapsed)
  Total time   12.31s  ( 14.78s elapsed)

  %GC time       0.9%  (0.7% elapsed)

  Alloc rate    788,441,496 bytes per MUT second

  Productivity  99.0% of total user, 82.5% of total elapsed

Добавлена разметка — Кодт
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.