module BuildBox.Build.Benchmark ( Benchmark (..) , BenchResult (..) , runBenchmark , iterateBenchmark , timeBuild) where import BuildBox.Build.Base import BuildBox.Data.Physical import Data.Time -- | Benchmark definition. data Benchmark result = forall a. Benchmark { -- | A unique name for the benchmark benchmarkName :: String -- | Setup command to run before the main benchmark. -- This does not contribute to the reported time of the overall result. , benchmarkSetup :: Build () -- | The main command to benchmark. , benchmarkCommand :: Build a -- | Check and post-process the result of the main command. -- This does not contribute to the reported time of the overall result. , benchmarkCheck :: a -> Build result } -- | Benchmark result. data BenchResult result = BenchResult { benchResultName :: String , benchResultIteration :: Int , benchResultTime :: Seconds , benchResultValue :: result } -- | Run a benchmark a single time. runBenchmark :: Benchmark result -> Int -> Build (BenchResult result) runBenchmark (Benchmark name setup cmd check) i = do setup (secs, x) <- timeBuild cmd r <- check x return $ BenchResult name i secs r -- | Run a benchmark the given number of times. iterateBenchmark :: Int -> Benchmark result -> Build [BenchResult result] iterateBenchmark 0 _ = return [] iterateBenchmark count bench = do result <- runBenchmark bench count rest <- iterateBenchmark (count - 1) bench return $ result : rest -- | Run a command, returning its elapsed time. timeBuild :: Build a -> Build (Seconds, a) timeBuild cmd = do start <- io $ getCurrentTime result <- cmd finish <- io $ getCurrentTime let time = fromRational $ toRational $ diffUTCTime finish start return (Seconds time, result)