packages feed

snappy-hs-0.1.1.0: benchmark/Bench.hs

{-# LANGUAGE BangPatterns #-}
module Main where

import Control.Exception (evaluate)
import Data.IORef
import qualified Data.ByteString as BS
import Data.Time.Clock.POSIX (getPOSIXTime)
import Data.Word (Word8)
import Snappy

main :: IO ()
main = do
    src <- BS.readFile "./data/Isaac.Newton-Opticks.txt"
    let !payloadMB = fromIntegral (BS.length src) / (1024 * 1024) :: Double
        iters = 200 :: Int

    putStrLn $ "Input: " ++ show (BS.length src) ++ " bytes, " ++ show iters ++ " iterations"

    -- Pre-generate varied inputs (16 KB + 1 byte each, tiny overhead)
    let inputs = [ BS.snoc src (fromIntegral i :: Word8) | i <- [1..iters] ]

    -- Compress benchmark
    cRef <- newIORef undefined
    t0c  <- getPOSIXTime
    mapM_ (\tweaked -> do
        let !c = compress tweaked
        _ <- evaluate (BS.length c)
        writeIORef cRef c) inputs
    t1c <- getPOSIXTime
    compressed <- readIORef cRef
    let totalCompMs = realToFrac (t1c - t0c) * 1000 :: Double
        compSecs = realToFrac (t1c - t0c) / fromIntegral iters :: Double
    putStrLn $ "compress: " ++ show (BS.length compressed) ++ " bytes -> "
                ++ showMBps payloadMB compSecs ++ " MB/s"
                ++ "  (total " ++ showMs totalCompMs ++ "ms)"

    -- Pre-compress all inputs so decompress benchmark is decompress-only
    let compInputs = map (compress . BS.snoc src . (fromIntegral :: Int -> Word8)) [1..iters]

    -- Decompress benchmark (decompress only, no compress overhead)
    dRef <- newIORef undefined
    t0d  <- getPOSIXTime
    mapM_ (\c ->
        case decompress c of
            Left e  -> putStrLn ("error: " ++ show e)
            Right !d -> do
                _ <- evaluate (BS.length d)
                writeIORef dRef d) compInputs
    t1d <- getPOSIXTime
    decompResult <- readIORef dRef
    let totalDecompMs = realToFrac (t1d - t0d) * 1000 :: Double
        decompSecs = realToFrac (t1d - t0d) / fromIntegral iters :: Double
    putStrLn $ "decomp:   " ++ show (BS.length decompResult) ++ " bytes -> "
                ++ showMBps payloadMB decompSecs ++ " MB/s"
                ++ "  (total " ++ showMs totalDecompMs ++ "ms)"

showMBps :: Double -> Double -> String
showMBps mb secs = show (round (mb / secs) :: Int)

showMs :: Double -> String
showMs x = show (round x :: Int)