packages feed

hdis86-0.2: tools/test_lazy_bytestring.hs

module Main(main) where

{- Check correctness and speed of lazy ByteString disassembly
   versus strict ByteString disassembly.

   $ for p in mwc-random clock groom; do cabal install $p; done
   $ ghc --make -O test_lazy_bytestring.hs
   $ ./test_lazy_bytestring
-}

import qualified Data.ByteString      as BS
import qualified Data.ByteString.Lazy as BL
import qualified Data.Vector.Unboxed  as V
import qualified System.Random.MWC    as R
import qualified System.Posix.Clock   as C

import Control.Monad
import Control.Exception ( evaluate )
import System.Exit
import System.IO
import Text.Groom
import Text.Printf

import Hdis86
import Hdis86.Incremental

splitBS :: R.GenIO -> BS.ByteString -> IO [BS.ByteString]
splitBS _   bs | BS.length bs < 2 = return [bs]
splitBS gen bs = do
    die <- R.uniformR (0,4) gen
    if die == (0 :: Int)
        then return [bs]
        else do
            i <- R.uniformR (1, BS.length bs - 1) gen
            let (x,y) = BS.splitAt i bs
            fmap (x:) (splitBS gen y)

time :: IO () -> IO Double
time x = do
    let get = C.getTime C.Monotonic
    C.TimeSpec s0 ns0 <- get
    x
    C.TimeSpec s1 ns1 <- get
    let scale = ((10 ** (-9)) *) . fromIntegral
    return (fromIntegral (s1 - s0) + scale (ns1 - ns0))

main :: IO ()
main = R.withSystemRandom $ \gen -> forever $ do
    size   <- R.uniformR (2^16, 2^21) gen
    vec    <- R.uniformVector gen size
    let bs =  BS.pack (V.toList vec)
    chunks <- splitBS gen bs
    let bl =  BL.fromChunks chunks
    _      <- evaluate (BS.length bs)
    _      <- evaluate (BL.length bl)

    let ms = disassembleMetadata amd64 bs
        ml = disassembleLazy     amd64 bl
        force = time . mapM_ (evaluate . inOpcode . mdInst)
    ts <- force $ disassembleMetadata amd64 bs
    tl <- force $ disassembleLazy     amd64 bl

    _  <- printf "%4d kB in %3d chunks: %5.2f s / %5.2f s = %6.2f%% speed\n"
        (size `div` 1024) (length chunks) ts tl (100 * ts / tl)
    when (ms /= ml) $ do
        hPutStr stderr "FAIL; check out.*\n"
        writeFile "out.strict" $ groom ms
        writeFile "out.lazy"   $ groom ml
        exitWith (ExitFailure 1)