module Data.HdrHistogram (
Histogram(..), empty, fromConfig,
record, recordValues,
Range(..),
percentile,
Config, HasConfig
) where
import Data.Bits (Bits, FiniteBits)
import Data.HdrHistogram.Config
import Data.HdrHistogram.Config.Internal
import Data.Proxy (Proxy (Proxy))
import Data.Tagged (Tagged (Tagged))
import Data.Vector.Unboxed ((!), (//))
import qualified Data.Vector.Unboxed as U
data Histogram config value count = Histogram {
_config :: HistogramConfig value,
totalCount :: count,
counts :: U.Vector count
} deriving (Eq, Show)
empty :: forall config value count. (HasConfig config, Integral value, FiniteBits value, U.Unbox count, Integral count) => Histogram config value count
empty = fromConfig (Tagged c :: Tagged config (HistogramConfig value))
where
p = Proxy :: Proxy config
c = getConfig p
fromConfig :: (U.Unbox count, Integral count) => Tagged c (HistogramConfig value) -> Histogram c value count
fromConfig (Tagged c) = Histogram {
_config = c,
totalCount = 0,
counts = U.replicate (size c) 0
}
instance (HasConfig config, Integral value, FiniteBits value, U.Unbox count, Integral count) =>
Monoid (Histogram config value count) where
mempty = empty
Histogram config' t c `mappend` Histogram _ t' c' = Histogram config' (t + t') (U.zipWith (+) c c')
record :: (U.Unbox count,
Integral count, Integral value, FiniteBits value)
=> Histogram config value count
-> value
-> Histogram config value count
record h val = recordValues h val 1
recordValues :: (U.Unbox count, Integral count, Integral value, FiniteBits value) => Histogram config value count -> value -> count -> Histogram config value count
recordValues h val count = h {
totalCount = totalCount h + count,
counts = counts h // [(index, (counts h ! index) + count)]
}
where
index = indexForValue (_config h) val
percentile :: (Integral value, Integral count, U.Unbox count, Bits value)
=> Histogram config value count
-> Float
-> Range value
percentile h q = case U.find ((>= count) . snd) totals of
Nothing -> Range 0 0
Just (i, _) -> rangeForIndex c i
where
c = _config h
q' = min q 100
count = floor $ (q' / 100) * fromIntegral (totalCount h) + 0.5
totals = U.scanl f (0 :: Int, 0) withIndex
where
f (_, v') (i, v) = (i, v' + v)
withIndex = U.imap (,) (counts h)