threadscope-0.2.0: Events/SparkStats.hs
module Events.SparkStats (
SparkStats(rateCreated, rateDud, rateOverflowed,
rateConverted, rateFizzled, rateGCd,
meanPool, maxPool, minPool),
initial, create, rescale, aggregate, agEx,
) where
import Data.Word (Word64)
-- | Sparks change state. Each state transition process has a duration.
-- Spark statistics, for a given duration, record the spark transition rate
-- (the number of sparks that enter a given state within the interval)
-- and the absolute mean, maximal and minimal number of sparks
-- in the spark pool within the duration.
data SparkStats =
SparkStats { rateCreated, rateDud, rateOverflowed,
rateConverted, rateFizzled, rateGCd,
meanPool, maxPool, minPool :: {-# UNPACK #-}!Double }
deriving (Show, Eq)
-- | Initial, default value of spark stats, at the start of runtime,
-- before any spark activity is recorded.
initial :: SparkStats
initial = SparkStats 0 0 0 0 0 0 0 0 0
-- | Create spark stats for a duration, given absolute
-- numbers of sparks in all categories at the start and end of the duration.
-- The units for spark transitions (first 6 counters) is [spark/duration]:
-- the fact that intervals may have different lenghts is ignored here.
-- The units for the pool stats are just [spark].
-- The values in the second counter have to be greater or equal
-- to the values in the first counter, except for the spark pool size.
-- For pool size, we take into account only the first sample,
-- to visualize more detail at high zoom levels, at the cost
-- of a slight shift of the graph. Mathematically, this corresponds
-- to taking the initial durations as centered around samples,
-- but to have the same tree for rates and pool sizes, we then have
-- to shift the durations by half interval size to the right
-- (which would be neglectable if the interval was small and even).
create :: (Word64, Word64, Word64, Word64, Word64, Word64, Word64) ->
(Word64, Word64, Word64, Word64, Word64, Word64, Word64) ->
SparkStats
create (crt1, dud1, ovf1, cnv1, fiz1, gcd1, remaining1)
(crt2, dud2, ovf2, cnv2, fiz2, gcd2, _remaining2) =
let (crt, dud, ovf, cnv, fiz, gcd) =
(fromIntegral $ crt2 - crt1,
fromIntegral $ dud2 - dud1,
fromIntegral $ ovf2 - ovf1,
fromIntegral $ cnv2 - cnv1,
fromIntegral $ fiz2 - fiz1,
fromIntegral $ gcd2 - gcd1)
p = fromIntegral remaining1
in SparkStats crt dud ovf cnv fiz gcd p p p
-- | Reduce a list of spark stats; spark pool stats are overwritten.
foldStats :: (Double -> Double -> Double)
-> Double -> Double -> Double
-> [SparkStats] -> SparkStats
foldStats f meanP maxP minP l
= SparkStats
(foldr f 0 (map rateCreated l))
(foldr f 0 (map rateDud l))
(foldr f 0 (map rateOverflowed l))
(foldr f 0 (map rateConverted l))
(foldr f 0 (map rateFizzled l))
(foldr f 0 (map rateGCd l))
meanP maxP minP
-- | Rescale the spark transition stats, e.g., to change their units.
rescale :: Double -> SparkStats -> SparkStats
rescale scale s =
let f w _ = scale * w
in foldStats f (meanPool s) (maxPool s) (minPool s) [s]
-- | Derive spark stats for an interval from a list of spark stats,
-- in reverse chronological order, of consecutive subintervals
-- that sum up to the original interval.
aggregate :: [SparkStats] -> SparkStats
aggregate [s] = s -- optimization
aggregate l =
let meanP = sum (map meanPool l) / fromIntegral (length l) -- TODO: inaccurate
maxP = maximum (map maxPool l)
minP = minimum (map minPool l)
in foldStats (+) meanP maxP minP l
-- | Extrapolate spark stats from previous data.
-- Absolute pools size values extrapolate by staying constant,
-- rates of change of spark status extrapolate by dropping to 0
-- (which corresponds to absolute numbers of sparks staying constant).
extrapolate :: SparkStats -> SparkStats
extrapolate s =
let f w _ = 0 * w
in foldStats f (meanPool s) (maxPool s) (minPool s) [s]
-- | Aggregate, if any data provided. Extrapolate from previous data, otherwise.
-- In both cases, the second component is the new choice of "previous data".
-- The list of stats is expected in reverse chronological order,
-- as for aggregate.
agEx :: [SparkStats] -> SparkStats -> (SparkStats, SparkStats)
agEx [] s = (extrapolate s, s)
agEx l@(s:_) _ = (aggregate l, s)