content: -- | Simple benchmarking of IO functions.
  module Cryptol.Utils.Benchmark
    ( BenchmarkStats (..)
    , benchmark
    , secs
    ) where
  
  import           Criterion.Measurement       (runBenchmark, secs, threshold)
  import           Criterion.Measurement.Types
  import           Data.Int
  import qualified Data.Vector                 as V
  import qualified Data.Vector.Unboxed         as U
  
  -- | Statistics returned by 'benchmark'.
  --
  -- This is extremely crude compared to the full analysis that criterion can do,
  -- but is enough for now.
  data BenchmarkStats = BenchmarkStats
    { benchAvgTime    :: !Double
    , benchAvgCpuTime :: !Double
    , benchAvgCycles  :: !Int64
    } deriving Show
  
  -- | Benchmark the application of the given function to the given input and the
  -- execution of the resulting IO action to WHNF, spending at least the given
  -- amount of time in seconds to collect measurements.
  benchmark :: Double -> (a -> IO b) -> a -> IO BenchmarkStats
  benchmark period f x = do
    (meas, _) <- runBenchmark (whnfAppIO f x) period
    let meas' = rescale <$> V.filter ((>= threshold) . measTime) meas
        len = length meas'
        sumMeasure sel = U.sum $ measure sel meas'
    pure BenchmarkStats
      { benchAvgTime = sumMeasure measTime / fromIntegral len
      , benchAvgCpuTime = sumMeasure measCpuTime / fromIntegral len
      , benchAvgCycles = sumMeasure measCycles `div` fromIntegral len }
  