packages feed

fibon-0.1.0: tools/fibon-analyse/Fibon/Analyse/Metrics.hs

{-# LANGUAGE FlexibleInstances, GeneralizedNewtypeDeriving#-}
module Fibon.Analyse.Metrics (
    MemSize(..)
  , ExecTime(..)
  , Estimate(..)
  , ConfidenceInterval(..)
  , Measurement(..)
  , Metric(..)
  , PerfData(..)
  , pprPerfData
  , RawPerf(..)
  , NormPerf(..)
  , BasicPerf(..)
  , Summary(..)
  , mkPointEstimate
  , rawPerfToDouble
  , normPerfToDouble
)
where

import Data.Word
import Text.Printf

newtype MemSize    = MemSize  {fromMemSize  :: Word64}
  deriving(Eq, Num, Read, Show)
newtype ExecTime   = ExecTime {fromExecTime :: Double}
  deriving(Eq, Num, Read, Show)

data Estimate a = Estimate {
      ePoint  :: !a
    , eStddev :: !a
    , eSize   :: !Int
    , eCI     :: Maybe (ConfidenceInterval a)
  }
  deriving (Read, Show)

data ConfidenceInterval a = ConfidenceInterval {
      eLowerBound       :: !a
    , eUpperBound       :: !a
    , eConfidenceLevel  :: !Double
}
  deriving (Read, Show)

instance Functor Estimate where
  fmap f e = e {
      ePoint  = f (ePoint e)
    , eStddev = f (eStddev e)
    , eCI     = maybe Nothing (Just . fmap f) (eCI e)
  }

instance Functor ConfidenceInterval where
  fmap f c = c {
      eLowerBound = f (eLowerBound c)
    , eUpperBound = f (eUpperBound c)
  }

data Measurement a = 
    Single   a
  | Interval (Estimate a)
  deriving (Read, Show)

mkPointEstimate :: (Num b) => (b -> a) -> a -> Estimate a
mkPointEstimate mkA a = Estimate {
      ePoint  = a
    , eStddev = mkA 0
    , eSize   = 1
    , eCI     = Nothing
  }

class Metric a where
  perf :: a -> Maybe RawPerf

instance Metric (Measurement ExecTime) where
  perf (Single m)   = Just (RawTime (mkPointEstimate ExecTime m))
  perf (Interval e) = Just (RawTime  e)

instance Metric (Measurement MemSize) where
  perf (Single m)   = Just (RawSize (mkPointEstimate MemSize m))
  perf (Interval e) = Just (RawSize e)

instance Metric a => Metric (Maybe a) where
  --perf = fmap perf
  perf Nothing  = Nothing
  perf (Just x) = perf x

data PerfData =
    NoResult
  | Basic BasicPerf
  | Summary Summary BasicPerf
  deriving(Read, Show)

data BasicPerf =
    Raw RawPerf
  | Norm NormPerf
  deriving(Read, Show)

data RawPerf =
    RawTime (Estimate ExecTime)
  | RawSize (Estimate MemSize)
  deriving(Read, Show)

data NormPerf =
    Percent (Estimate Double) -- ^ (ref  / base) * 100
  | Ratio   (Estimate Double) -- ^ (base / ref)
  deriving(Read, Show)

data Summary =
    Min
  | GeoMean
  | ArithMean
  | Max
  deriving(Read, Show)

pprPerfData :: Bool -> PerfData -> String
pprPerfData _ NoResult    = "--"
pprPerfData u (Basic b) = pprBasicPerf u b
pprPerfData u (Summary _ s) = pprBasicPerf u s

pprBasicPerf :: Bool -> BasicPerf -> String
pprBasicPerf u (Raw  r)    = pprRawPerf  u r
pprBasicPerf u (Norm n)    = pprNormPerf u n

pprNormPerf :: Bool -> NormPerf -> String
pprNormPerf u (Percent d) =
  printf "%0.2f%s" ((ePoint d)  - 100) (pprUnit u "%")
pprNormPerf _ (Ratio d) =
  printf "%0.2f"    (ePoint d)

pprRawPerf :: Bool -> RawPerf -> String
pprRawPerf u (RawTime t)    =
  printf "%0.2f%s"  ((fromExecTime . ePoint) t) (pprUnit u "s")
pprRawPerf u (RawSize s)    =
  printf "%0d%s"
    (round (fromIntegral ((fromMemSize . ePoint) s) / 1000 :: Double)::Word64)
    (pprUnit u "k")
{-
pprRawPerf u (RawTimeInterval e) = printf "%0.2f%s"
                              ((fromExecTime . ePoint) e)
                              (pprPlusMinus e fromExecTime)
                              (pprUnit u "s")
pprRawPerf u (RawSizeInterval e) = printf "%d%s%s"
                              ((fromMemSize . ePoint) e)
                              (pprPlusMinus e fromMemSize)
                              (pprUnit u "k")

pprPlusMinus :: Real b => Estimate a -> (a -> b) -> String
pprPlusMinus e f = printf "%c%0.2d" (chr 0xB1) ((realToFrac spread)::Double)
  where spread = abs ((f . ePoint) e) - ((f . eLowerBound) e)
pprSummaryPerf :: Bool -> SummaryPerf -> String
pprSummaryPerf u (GeoMean n)   = pprBasicPerf u n
pprSummaryPerf u (ArithMean r) = pprBasicPerf u r
-}

pprUnit :: Bool -> String -> String
pprUnit True s = s
pprUnit _    _ = ""

rawPerfToDouble :: RawPerf -> Double
rawPerfToDouble (RawTime t) = (fromExecTime . ePoint) t
rawPerfToDouble (RawSize s) = (fromIntegral . fromMemSize . ePoint) s

normPerfToDouble :: NormPerf -> Double
normPerfToDouble (Percent p) = ePoint p
normPerfToDouble (Ratio   r) = ePoint r