1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
|
{-# LANGUAGE CPP #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE DeriveDataTypeable, DeriveGeneric, GADTs, RecordWildCards #-}
{-# OPTIONS_GHC -funbox-strict-fields #-}
-- |
-- Module : Criterion.Types
-- Copyright : (c) 2009-2014 Bryan O'Sullivan
--
-- License : BSD-style
-- Maintainer : bos@serpentine.com
-- Stability : experimental
-- Portability : GHC
--
-- Types for benchmarking.
--
-- The core type is 'Benchmarkable', which admits both pure functions
-- and 'IO' actions.
--
-- For a pure function of type @a -> b@, the benchmarking harness
-- calls this function repeatedly, each time with a different 'Int64'
-- argument (the number of times to run the function in a loop), and
-- reduces the result the function returns to weak head normal form.
--
-- For an action of type @IO a@, the benchmarking harness calls the
-- action repeatedly, but does not reduce the result.
module Criterion.Types
(
-- * Configuration
Config(..)
, Verbosity(..)
-- * Benchmark descriptions
, Benchmarkable(..)
, Benchmark(..)
-- * Measurements
, Measured(..)
, fromInt
, toInt
, fromDouble
, toDouble
, measureAccessors
, measureKeys
, measure
, rescale
-- * Benchmark construction
, env
, envWithCleanup
, perBatchEnv
, perBatchEnvWithCleanup
, perRunEnv
, perRunEnvWithCleanup
, toBenchmarkable
, bench
, bgroup
, addPrefix
, benchNames
-- ** Evaluation control
, nf
, whnf
, nfIO
, whnfIO
, nfAppIO
, whnfAppIO
-- * Result types
, Outliers(..)
, OutlierEffect(..)
, OutlierVariance(..)
, Regression(..)
, KDE(..)
, Report(..)
, SampleAnalysis(..)
, DataRecord(..)
) where
import Control.DeepSeq (NFData(rnf))
import Criterion.Measurement.Types
import Data.Aeson (FromJSON(..), ToJSON(..))
import Data.Binary (Binary(..), putWord8, getWord8)
import Data.Binary.Orphans ()
import Data.Data (Data, Typeable)
import Data.Int (Int64)
import Data.Map (Map)
import GHC.Generics (Generic)
import Prelude ()
import Prelude.Compat
import qualified Data.Vector as V
import qualified Data.Vector.Unboxed as U
import qualified Statistics.Types as St
import Statistics.Resampling.Bootstrap ()
-- | Control the amount of information displayed.
data Verbosity = Quiet
| Normal
| Verbose
deriving (Eq, Ord, Bounded, Enum, Read, Show, Typeable, Data,
Generic)
-- | Top-level benchmarking configuration.
data Config = Config {
confInterval :: St.CL Double
-- ^ Confidence interval for bootstrap estimation (greater than
-- 0, less than 1).
, timeLimit :: Double
-- ^ Number of seconds to run a single benchmark. (In practice,
-- execution time will very slightly exceed this limit.)
, resamples :: Int
-- ^ Number of resamples to perform when bootstrapping.
, regressions :: [([String], String)]
-- ^ Regressions to perform.
, rawDataFile :: Maybe FilePath
-- ^ File to write binary measurement and analysis data to. If
-- not specified, this will be a temporary file.
, reportFile :: Maybe FilePath
-- ^ File to write report output to, with template expanded.
, csvFile :: Maybe FilePath
-- ^ File to write CSV summary to.
, jsonFile :: Maybe FilePath
-- ^ File to write JSON-formatted results to.
, junitFile :: Maybe FilePath
-- ^ File to write JUnit-compatible XML results to.
, verbosity :: Verbosity
-- ^ Verbosity level to use when running and analysing
-- benchmarks.
, template :: FilePath
-- ^ Template file to use if writing a report.
} deriving (Eq, Read, Show, Typeable, Data, Generic)
-- | Outliers from sample data, calculated using the boxplot
-- technique.
data Outliers = Outliers {
samplesSeen :: !Int64
, lowSevere :: !Int64
-- ^ More than 3 times the interquartile range (IQR) below the
-- first quartile.
, lowMild :: !Int64
-- ^ Between 1.5 and 3 times the IQR below the first quartile.
, highMild :: !Int64
-- ^ Between 1.5 and 3 times the IQR above the third quartile.
, highSevere :: !Int64
-- ^ More than 3 times the IQR above the third quartile.
} deriving (Eq, Read, Show, Typeable, Data, Generic)
instance FromJSON Outliers
instance ToJSON Outliers
instance Binary Outliers where
put (Outliers v w x y z) = put v >> put w >> put x >> put y >> put z
get = Outliers <$> get <*> get <*> get <*> get <*> get
instance NFData Outliers
-- | A description of the extent to which outliers in the sample data
-- affect the sample mean and standard deviation.
data OutlierEffect = Unaffected -- ^ Less than 1% effect.
| Slight -- ^ Between 1% and 10%.
| Moderate -- ^ Between 10% and 50%.
| Severe -- ^ Above 50% (i.e. measurements
-- are useless).
deriving (Eq, Ord, Read, Show, Typeable, Data, Generic)
instance FromJSON OutlierEffect
instance ToJSON OutlierEffect
instance Binary OutlierEffect where
put Unaffected = putWord8 0
put Slight = putWord8 1
put Moderate = putWord8 2
put Severe = putWord8 3
get = do
i <- getWord8
case i of
0 -> return Unaffected
1 -> return Slight
2 -> return Moderate
3 -> return Severe
_ -> fail $ "get for OutlierEffect: unexpected " ++ show i
instance NFData OutlierEffect
instance Semigroup Outliers where
(<>) = addOutliers
instance Monoid Outliers where
mempty = Outliers 0 0 0 0 0
#if !(MIN_VERSION_base(4,11,0))
mappend = addOutliers
#endif
addOutliers :: Outliers -> Outliers -> Outliers
addOutliers (Outliers s a b c d) (Outliers t w x y z) =
Outliers (s+t) (a+w) (b+x) (c+y) (d+z)
{-# INLINE addOutliers #-}
-- | Analysis of the extent to which outliers in a sample affect its
-- standard deviation (and to some extent, its mean).
data OutlierVariance = OutlierVariance {
ovEffect :: OutlierEffect
-- ^ Qualitative description of effect.
, ovDesc :: String
-- ^ Brief textual description of effect.
, ovFraction :: Double
-- ^ Quantitative description of effect (a fraction between 0 and 1).
} deriving (Eq, Read, Show, Typeable, Data, Generic)
instance FromJSON OutlierVariance
instance ToJSON OutlierVariance
instance Binary OutlierVariance where
put (OutlierVariance x y z) = put x >> put y >> put z
get = OutlierVariance <$> get <*> get <*> get
instance NFData OutlierVariance where
rnf OutlierVariance{..} = rnf ovEffect `seq` rnf ovDesc `seq` rnf ovFraction
-- | Results of a linear regression.
data Regression = Regression {
regResponder :: String
-- ^ Name of the responding variable.
, regCoeffs :: Map String (St.Estimate St.ConfInt Double)
-- ^ Map from name to value of predictor coefficients.
, regRSquare :: St.Estimate St.ConfInt Double
-- ^ R² goodness-of-fit estimate.
} deriving (Eq, Read, Show, Typeable, Generic)
instance FromJSON Regression
instance ToJSON Regression
instance Binary Regression where
put Regression{..} =
put regResponder >> put regCoeffs >> put regRSquare
get = Regression <$> get <*> get <*> get
instance NFData Regression where
rnf Regression{..} =
rnf regResponder `seq` rnf regCoeffs `seq` rnf regRSquare
-- | Result of a bootstrap analysis of a non-parametric sample.
data SampleAnalysis = SampleAnalysis {
anRegress :: [Regression]
-- ^ Estimates calculated via linear regression.
, anMean :: St.Estimate St.ConfInt Double
-- ^ Estimated mean.
, anStdDev :: St.Estimate St.ConfInt Double
-- ^ Estimated standard deviation.
, anOutlierVar :: OutlierVariance
-- ^ Description of the effects of outliers on the estimated
-- variance.
} deriving (Eq, Read, Show, Typeable, Generic)
instance FromJSON SampleAnalysis
instance ToJSON SampleAnalysis
instance Binary SampleAnalysis where
put SampleAnalysis{..} = do
put anRegress; put anMean; put anStdDev; put anOutlierVar
get = SampleAnalysis <$> get <*> get <*> get <*> get
instance NFData SampleAnalysis where
rnf SampleAnalysis{..} =
rnf anRegress `seq` rnf anMean `seq`
rnf anStdDev `seq` rnf anOutlierVar
-- | Data for a KDE chart of performance.
data KDE = KDE {
kdeType :: String
, kdeValues :: U.Vector Double
, kdePDF :: U.Vector Double
} deriving (Eq, Read, Show, Typeable, Data, Generic)
instance FromJSON KDE
instance ToJSON KDE
instance Binary KDE where
put KDE{..} = put kdeType >> put kdeValues >> put kdePDF
get = KDE <$> get <*> get <*> get
instance NFData KDE where
rnf KDE{..} = rnf kdeType `seq` rnf kdeValues `seq` rnf kdePDF
-- | Report of a sample analysis.
data Report = Report {
reportNumber :: Int
-- ^ A simple index indicating that this is the /n/th report.
, reportName :: String
-- ^ The name of this report.
, reportKeys :: [String]
-- ^ See 'measureKeys'.
, reportMeasured :: V.Vector Measured
-- ^ Raw measurements.
, reportAnalysis :: SampleAnalysis
-- ^ Report analysis.
, reportOutliers :: Outliers
-- ^ Analysis of outliers.
, reportKDEs :: [KDE]
-- ^ Data for a KDE of times.
} deriving (Eq, Read, Show, Typeable, Generic)
instance FromJSON Report
instance ToJSON Report
instance Binary Report where
put Report{..} =
put reportNumber >> put reportName >> put reportKeys >>
put reportMeasured >> put reportAnalysis >> put reportOutliers >>
put reportKDEs
get = Report <$> get <*> get <*> get <*> get <*> get <*> get <*> get
instance NFData Report where
rnf Report{..} =
rnf reportNumber `seq` rnf reportName `seq` rnf reportKeys `seq`
rnf reportMeasured `seq` rnf reportAnalysis `seq` rnf reportOutliers `seq`
rnf reportKDEs
data DataRecord = Measurement Int String (V.Vector Measured)
| Analysed Report
deriving (Eq, Read, Show, Typeable, Generic)
instance Binary DataRecord where
put (Measurement i n v) = putWord8 0 >> put i >> put n >> put v
put (Analysed r) = putWord8 1 >> put r
get = do
w <- getWord8
case w of
0 -> Measurement <$> get <*> get <*> get
1 -> Analysed <$> get
_ -> error ("bad tag " ++ show w)
instance NFData DataRecord where
rnf (Measurement i n v) = rnf i `seq` rnf n `seq` rnf v
rnf (Analysed r) = rnf r
instance FromJSON DataRecord
instance ToJSON DataRecord
|