Небольшой рефакторинг (в основном, влево) дает гораздо лучшую производительность и значительно снижает накладные расходы GC при разборе файла 8388600 байт.
{-# LANGUAGE BangPatterns #-}
module Main (main) where
import qualified Data.ByteString.Lazy as BL
import Data.Binary.Get
data Trade = Trade
{ timestamp :: {-# UNPACK #-} !Int
, price :: {-# UNPACK #-} !Int
, qty :: {-# UNPACK #-} !Int
} deriving (Show)
getTrade :: Get Trade
getTrade = do
timestamp <- getWord32le
price <- getWord32le
qty <- getWord16le
return $! Trade (fromIntegral timestamp) (fromIntegral price) (fromIntegral qty)
countTrades :: BL.ByteString -> Int
countTrades input = stepper (0, input) where
stepper (!count, !buffer)
| BL.null buffer = count
| otherwise =
let (trade, rest, _) = runGetState getTrade buffer 0
in stepper (count+1, rest)
main :: IO()
main = do
input <- BL.readFile "trades.bin"
let trades = countTrades input
print trades
И соответствующая статистика времени выполнения. Несмотря на то, что номера распределения близки, GC и максимальный размер кучи в ревизиях немного отличаются.
Все приведенные здесь примеры были построены с использованием GHC 7.4.1 -O2.
Исходный источник, запускается с + RTS -K1G -RTS из-за чрезмерного использования стека:
426,003,680 bytes allocated in the heap
443,141,672 bytes copied during GC
99,305,920 bytes maximum residency (9 sample(s))
203 MB total memory in use (0 MB lost due to fragmentation)
Total time 0.62s ( 0.81s elapsed)
%GC time 83.3% (86.4% elapsed)
Редакция Даниила:
357,851,536 bytes allocated in the heap
220,009,088 bytes copied during GC
40,846,168 bytes maximum residency (8 sample(s))
85 MB total memory in use (0 MB lost due to fragmentation)
Total time 0.24s ( 0.28s elapsed)
%GC time 69.1% (71.4% elapsed)
И этот пост:
290,725,952 bytes allocated in the heap
109,592 bytes copied during GC
78,704 bytes maximum residency (10 sample(s))
2 MB total memory in use (0 MB lost due to fragmentation)
Total time 0.06s ( 0.07s elapsed)
%GC time 5.0% (6.0% elapsed)