packages feed

disk-bytes-0.1.0.0: src-bench/bench-memory.hs

module Main where

import Control.Concurrent
    ( threadDelay )
import Control.Exception
    ( evaluate )
import Control.Monad
    ( forM )
import Data.ByteString
    ( ByteString )
import System.Mem.Disk
import System.Mem
    ( performGC )
import Data.IORef

import qualified Data.ByteString as BS

{-----------------------------------------------------------------------------
    Benchmark parameters ------------------------------------------------------------------------------}
chunkSize, totalSize, maxSize :: Int
chunkSize = 2000 -- bytes
maxSize   = 1000 * chunkSize -- bytes
totalSize = 3 * maxSize -- bytes

{-----------------------------------------------------------------------------
    Benchmark execution ------------------------------------------------------------------------------}
main :: IO ()
main = withDiskSqlite "bench-mem.db" $ \disk -> do
    let batches = totalSize `div` maxSize
        batchSize = maxSize `div` chunkSize

    xss <- forM [1 .. batches] $ \i -> do
        say $ "Batch number " <> show i
        say $ ".. create `DiskBytes` and garbage collect `ByteString`"
        say $ "   invariant: `DiskBytes` in WHNF does not use RAM"
        xs <- forM [1 .. batchSize] $ \j -> do
            let x = toDiskBytes disk (mkBytes chunkSize j) :: DiskBytes
            x `seq` performGC
            pure x

        say $ ".. evaluate and discard `fromDiskBytes`"
        say $ "   invariant: `DiskBytes` store valid data"
        mapM_ (evaluate . fromDiskBytes) xs

        say $ ".. [pause]"
        threadDelaySeconds 2

        say $ ".. garbage collect on-disk `DiskBytes`"
        say $ "   invariant: disk memory is released for `DiskBytes`"
              <> " that are not alive"
        performGC

        say . (\x -> "Disk size: " <> show x <> " bytes") =<< getDiskSize disk
        pure []

    evaluate $ concat xss

    pure ()

mkBytes :: Int -> Int -> ByteString
mkBytes n seed = BS.pack $ map (\x -> toEnum $ (x+seed) `mod` 2^8) [1..n]

say :: String -> IO ()
say = putStrLn

threadDelaySeconds :: Int -> IO ()
threadDelaySeconds s = threadDelay (s * 1000 * 1000)