{-# LANGUAGE ScopedTypeVariables #-} {- Test different ways of handlings a data type that has large values and a small encoding. To run with limited memory: cabal run big -- +RTS -M2g -} module Main where import qualified Data.ByteString as B import Data.List (foldl') import Flat (Decoded, Flat (..), flat, unflat, unflatWith) import Flat.AsBin (AsBin, unbin) import Flat.AsSize import Flat.Decoder (Get, listTDecoder) import qualified ListT as L import System.TimeIt (timeIt) -- Big is a type that has a small encoded representation but a very large in-memory footprint. -- It is a very large bytestring whose bytes are all set to 0 newtype Big = Big B.ByteString newBig :: Int -> Big newBig gigas = Big $ B.replicate (gigas*giga) 0 -- length of Big in gigas gigas :: Big -> Int gigas (Big b) = B.length b `div` giga giga :: Int giga = 1000000000 instance Show Big where show b = "Big of " ++ show (gigas b) ++ "Gbytes" instance Flat Big where -- The encoded form is just the number of giga zeros (e.g. 5 for 5Giga zeros) size big = size (gigas big) encode big = encode (gigas big) -- The decoded form is massive decode = newBig <$> decode main :: IO () main = tbig tbig = do let numOfBigs = 5 -- A serialised list of Big values let bigsFile = flat $ replicate numOfBigs $ newBig 1 print "Encoding Time" timeIt $ print $ B.length bigsFile tstAsSize bigsFile tstAsBin bigsFile tstListT bigsFile tstBig bigsFile -- If we unserialise a list of Bigs and then process them (e.g. print them out) we end up in trouble, too much memory is required. tstBig :: B.ByteString -> IO () tstBig bigsFile = timeIt $ do print "Decode to [Big]:" let Right (bs :: [Big]) = unflat bigsFile mapM_ print bs -- So instead we unserialise them to a list of their flat representations, to be unflatted on demand later on tstAsBin :: B.ByteString -> IO () tstAsBin bigsFile = timeIt $ do print "Decode to [AsBin Big]:" let Right (bsR :: [AsBin Big]) = unflat bigsFile let bs = map unbin bsR mapM_ print bs tstAsSize :: B.ByteString -> IO () tstAsSize bigsFile = timeIt $ do print "Decode to [AsSize Big]:" let Right (bs :: [AsSize Big]) = unflat bigsFile mapM_ print bs -- Or: we extract one element at the time via a ListT -- See http://hackage.haskell.org/package/list-t-1.0.4/docs/ListT.html tstListT :: B.ByteString -> IO () tstListT bigsFile = timeIt $ do print "Decode to ListT IO Big:" stream :: L.ListT IO Big <- listTDecoder decode bigsFile L.traverse_ print stream