packages feed

raaz-0.3.11: benchmarks/internal/Benchmark/Types.hs

{-# LANGUAGE RecordWildCards #-}

module Benchmark.Types
       ( RaazBench
       , toBenchmarkable
       , nBytes
       , nRuns
       , runRaazBench
       , header
       ) where

import Criterion.Measurement
import Criterion.Measurement.Types hiding (measure)

import Data.Int
import Text.PrettyPrint

import Raaz.Core

-- | The total data processed in each benchmark.
nBytes :: BYTES Int
nBytes = 32 * 1024

-- | How many times to run each benchmark
nRuns :: Int64
nRuns = 10000

type RaazBench         = (String, Benchmarkable)

header :: Doc
header = hsep $ punctuate comma $ map text
         [ "Implementation"
         , "time"
         , "cycles"
         , "rate (bits/sec)"
         , "time/byte"
         , "cycles/byte"
         ]

-- | Execute a benchmark and writeout the results.
runRaazBench :: RaazBench -> IO Doc
runRaazBench (nm, bm) = do
  (memt,_) <- measure bm nRuns
  return $ hsep $ punctuate comma $ text nm : pprMeasured memt


------------------------ Helper functions ------------------------


pprMeasured :: Measured -> [Doc]
pprMeasured Measured{..} =
  [ text (secs tm)          -- time
  , text (humanise cy)      -- cycles
  , text rt                 -- rate
  , text secB               -- secs/byte
  , text (humanise cycB)    -- cycles/byte
  ]
  where tm    = measTime   / fromIntegral nRuns
        cy    = fromIntegral measCycles / fromIntegral nRuns
        bytes = fromIntegral nBytes
        secB  = humanise (tm / bytes) ++ "s"
        cycB  = cy    / bytes
        rt    = humanise $ 8 * bytes / tm


-- | Humanise the output units.
humanise :: Double -> String
humanise u | u < 1     = goL 0 u
           | otherwise = goU 0 u
  where goL e x | x > 1 || e == -3  = restrictDecimals 2  x ++ unitPrefix e
                | otherwise         = goL (e  - 1) (x * 1000)

        goU e x | x < 100 || e == 5 = restrictDecimals 2 x  ++ unitPrefix e
                | otherwise         = goU (e  + 1) (x / 1000)


restrictDecimals :: Int -> Double -> String
restrictDecimals n x = u ++ take (n+1) v
  where (u,v) = span (/= '.') $ show x


-- | @Unit prefix n@ gives proper prefix every 10^{3n} exponent
unitPrefix :: Int -> String
unitPrefix ex
  | ex <  -3   = error "exponent too small name"
  | ex == -3   = "n"
  | ex == -2   = "µ"
  | ex == -1   = "m"
  | ex == 0    = ""
  | ex == 1    = "K"
  | ex == 2    = "M"
  | ex == 3    = "G"
  | ex == 4    = "T"
  | ex == 5    = "P"
  | otherwise  = error "exponent to large to name"