module Network.Mux.DeltaQ.TraceStats
( step
, OneWayDeltaQSample (..)
, constructSample
, StatsA
, initialStatsA
) where
import Data.IntMap.Strict (IntMap)
import qualified Data.IntMap.Strict as IM
import Data.Maybe
import Data.Word (Word32)
import Control.Monad.Class.MonadTime.SI
import Network.Mux.DeltaQ.TraceStatsSupport
import Network.Mux.DeltaQ.TraceTypes
import Network.Mux.Types
step :: RemoteClockModel
-> Time
-> Int
-> StatsA
-> (Maybe OneWayDeltaQSample, StatsA)
step :: RemoteClockModel
-> Time -> Key -> StatsA -> (Maybe OneWayDeltaQSample, StatsA)
step RemoteClockModel
remoteTS Time
localTS Key
obsSize StatsA
s
| forall a. Maybe a -> Bool
isNothing (StatsA -> Maybe (Word32, Time)
referenceTimePoint StatsA
s)
= RemoteClockModel
-> Time -> Key -> StatsA -> (Maybe OneWayDeltaQSample, StatsA)
step RemoteClockModel
remoteTS Time
localTS Key
obsSize
(StatsA
s { referenceTimePoint :: Maybe (Word32, Time)
referenceTimePoint = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$! (RemoteClockModel -> Word32
unRemoteClockModel RemoteClockModel
remoteTS, Time
localTS)
, nextSampleAt :: Time
nextSampleAt = DiffTime
sampleInterval DiffTime -> Time -> Time
`addTime` Time
localTS
, timeLastObs :: Time
timeLastObs = Time
localTS
})
| Time
localTS forall a. Ord a => a -> a -> Bool
<= StatsA -> Time
nextSampleAt StatsA
s
= let refTimePoint :: (Word32, Time)
refTimePoint = case StatsA -> Maybe (Word32, Time)
referenceTimePoint StatsA
s of
Just (Word32, Time)
a -> (Word32, Time)
a
Maybe (Word32, Time)
Nothing -> forall a. HasCallStack => [Char] -> a
error [Char]
"step: missing referenceTimePoint"
transitTime :: SISec
transitTime = (Word32, Time) -> RemoteClockModel -> Time -> SISec
calcTransitTime (Word32, Time)
refTimePoint RemoteClockModel
remoteTS Time
localTS
in (forall a. Maybe a
Nothing, StatsA -> Time -> Key -> SISec -> StatsA
recordObservation StatsA
s Time
localTS Key
obsSize SISec
transitTime)
| Bool
otherwise
= let sample :: OneWayDeltaQSample
sample = StatsA -> OneWayDeltaQSample
constructSample StatsA
s
(Maybe OneWayDeltaQSample
_, StatsA
s') = RemoteClockModel
-> Time -> Key -> StatsA -> (Maybe OneWayDeltaQSample, StatsA)
step RemoteClockModel
remoteTS Time
localTS Key
obsSize StatsA
initialStatsA
in (forall a. a -> Maybe a
Just OneWayDeltaQSample
sample, StatsA
s')
calcTransitTime :: (Word32, Time)
-> RemoteClockModel
-> Time
-> SISec
calcTransitTime :: (Word32, Time) -> RemoteClockModel -> Time -> SISec
calcTransitTime (Word32
remoteRefTS, Time
localRefTS) RemoteClockModel
remoteTS' Time
localTS
= let remoteTS :: Word32
remoteTS
= RemoteClockModel -> Word32
unRemoteClockModel RemoteClockModel
remoteTS'
remoteClockDiffAsTimeDiff :: Word32 -> DiffTime
remoteClockDiffAsTimeDiff
= (DiffTime
remoteClockPrecision forall a. Num a => a -> a -> a
*) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Fractional a => Rational -> a
fromRational forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (Integral a, Num b) => a -> b
fromIntegral
correctedEmitTime :: Time
correctedEmitTime
| Word32
remoteTS forall a. Ord a => a -> a -> Bool
>= Word32
remoteRefTS
= (Word32 -> DiffTime
remoteClockDiffAsTimeDiff forall a b. (a -> b) -> a -> b
$ Word32
remoteTS forall a. Num a => a -> a -> a
- Word32
remoteRefTS)
DiffTime -> Time -> Time
`addTime` Time
localRefTS
| Bool
otherwise
= (Word32 -> DiffTime
remoteClockDiffAsTimeDiff forall a b. (a -> b) -> a -> b
$ forall a. Bounded a => a
maxBound forall a. Num a => a -> a -> a
- (Word32
remoteRefTS forall a. Num a => a -> a -> a
- Word32
remoteTS))
DiffTime -> Time -> Time
`addTime` Time
localRefTS
in Float -> SISec
S forall a b. (a -> b) -> a -> b
$! forall a. Fractional a => Rational -> a
fromRational (forall a. Real a => a -> Rational
toRational (Time
localTS Time -> Time -> DiffTime
`diffTime` Time
correctedEmitTime))
recordObservation :: StatsA -> Time -> Int -> SISec -> StatsA
recordObservation :: StatsA -> Time -> Key -> SISec -> StatsA
recordObservation StatsA
s Time
obsTime Key
obsSize SISec
transitTime
= let f :: Maybe PerSizeRecord -> Maybe PerSizeRecord
f Maybe PerSizeRecord
Nothing = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$! SISec -> PerSizeRecord
makePerSizeRecord SISec
transitTime
f (Just PerSizeRecord
a) = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$! SISec -> PerSizeRecord
makePerSizeRecord SISec
transitTime forall a. Semigroup a => a -> a -> a
<> PerSizeRecord
a
in StatsA
s { timeLastObs :: Time
timeLastObs = Time
obsTime
, numObservations :: Key
numObservations = forall a. Enum a => a -> a
succ (StatsA -> Key
numObservations StatsA
s)
, observables :: IntMap PerSizeRecord
observables = forall a. (Maybe a -> Maybe a) -> Key -> IntMap a -> IntMap a
IM.alter Maybe PerSizeRecord -> Maybe PerSizeRecord
f Key
obsSize (StatsA -> IntMap PerSizeRecord
observables StatsA
s)
}
constructSample :: StatsA -> OneWayDeltaQSample
constructSample :: StatsA -> OneWayDeltaQSample
constructSample StatsA
sa = OneWaySample
{ duration :: Double
duration = forall a. Fractional a => Rational -> a
fromRational forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Real a => a -> Rational
toRational forall a b. (a -> b) -> a -> b
$
forall b a. b -> (a -> b) -> Maybe a -> b
maybe DiffTime
0 (\(Word32
_,Time
a) -> StatsA -> Time
timeLastObs StatsA
sa Time -> Time -> DiffTime
`diffTime` Time
a)
(StatsA -> Maybe (Word32, Time)
referenceTimePoint StatsA
sa)
, sumPackets :: Key
sumPackets = Key
population
, sumTotalSDU :: Key
sumTotalSDU = Key
totalSDUOctets
, estDeltaQS :: Double
estDeltaQS = Double -> Double
normCheck Double
dQSEst
, estDeltaQVMean :: Double
estDeltaQVMean = Double -> Double
normCheck forall a b. (a -> b) -> a -> b
$ Double
vSum forall a. Fractional a => a -> a -> a
/ Double
pop
, estDeltaQVVar :: Double
estDeltaQVVar = Double -> Double
normCheck forall a b. (a -> b) -> a -> b
$ (Double
vSum2 forall a. Num a => a -> a -> a
- Double
vSum forall a. Num a => a -> a -> a
* Double
vSum forall a. Fractional a => a -> a -> a
/ Double
pop) forall a. Fractional a => a -> a -> a
/ Double
pop
, estR :: Double
estR = Double -> Double
normCheck Double
rEst
, sizeDist :: [Char]
sizeDist = forall a. Show a => a -> [Char]
show [ (Key
a,PerSizeRecord -> Key
count PerSizeRecord
b, let S Float
mtt = PerSizeRecord -> SISec
minTransitTime PerSizeRecord
b in Float
mtt)
| (Key
a, PerSizeRecord
b) <- forall a. IntMap a -> [(Key, a)]
IM.toAscList (StatsA -> IntMap PerSizeRecord
observables StatsA
sa)
, PerSizeRecord -> Key
count PerSizeRecord
b forall a. Ord a => a -> a -> Bool
> Key
0]
}
where
population :: Key
population = StatsA -> Key
numObservations StatsA
sa
pop :: Double
pop = forall a b. (Integral a, Num b) => a -> b
fromIntegral Key
population
normCheck :: Double -> Double
normCheck Double
x
| forall a. IntMap a -> Key
IM.size (StatsA -> IntMap PerSizeRecord
observables StatsA
sa) forall a. Ord a => a -> a -> Bool
> Key
1 = Double
x
| Bool
otherwise = Double
nan
(Key
totalSDUOctets, [(Key, SISec)]
minSRev)
= forall a b. (Key -> a -> b -> b) -> b -> IntMap a -> b
IM.foldrWithKey Key
-> PerSizeRecord -> (Key, [(Key, SISec)]) -> (Key, [(Key, SISec)])
accum (Key
0, []) forall a b. (a -> b) -> a -> b
$ StatsA -> IntMap PerSizeRecord
observables StatsA
sa
accum :: Key
-> PerSizeRecord -> (Key, [(Key, SISec)]) -> (Key, [(Key, SISec)])
accum Key
nOctets PerSizeRecord
psr (Key
sumSize, [(Key, SISec)]
minS)
= ( Key
sumSize forall a. Num a => a -> a -> a
+ (PerSizeRecord -> Key
count PerSizeRecord
psr) forall a. Num a => a -> a -> a
* Key
nOctets
, (Key
nOctets, PerSizeRecord -> SISec
minTransitTime PerSizeRecord
psr) forall a. a -> [a] -> [a]
: [(Key, SISec)]
minS)
(Double
dQGEst, Double
dQSEst, Double
rEst) = [(Key, SISec)] -> (Double, Double, Double)
estimateGS [(Key, SISec)]
minSRev
normalisedObservations :: IntMap PerSizeRecord
normalisedObservations
= let norm :: a -> SISec
norm a
n = Float -> SISec
S forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Fractional a => Rational -> a
fromRational forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Real a => a -> Rational
toRational
forall a b. (a -> b) -> a -> b
$ Double
dQGEst forall a. Num a => a -> a -> a
+ (forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n) forall a. Num a => a -> a -> a
* Double
dQSEst
in forall a b. (Key -> a -> b) -> IntMap a -> IntMap b
IM.mapWithKey (\Key
k -> SISec -> PerSizeRecord -> PerSizeRecord
normalisePSR (forall {a}. Integral a => a -> SISec
norm Key
k)) (StatsA -> IntMap PerSizeRecord
observables StatsA
sa)
(Double
vSum, Double
vSum2)
= let S Float
v = SISec
vSum'
S2 Float
v2 = SISec2
vSum2'
in (forall a. Fractional a => Rational -> a
fromRational forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Real a => a -> Rational
toRational forall a b. (a -> b) -> a -> b
$ Float
v, forall a. Fractional a => Rational -> a
fromRational forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Real a => a -> Rational
toRational forall a b. (a -> b) -> a -> b
$ Float
v2)
(SISec
vSum', SISec2
vSum2')
= forall a b. (a -> b -> b) -> b -> IntMap a -> b
IM.foldr PerSizeRecord -> (SISec, SISec2) -> (SISec, SISec2)
vCalc (SISec
0,SISec2
0) IntMap PerSizeRecord
normalisedObservations
vCalc :: PerSizeRecord -> (SISec, SISec2) -> (SISec, SISec2)
vCalc PerSizeRecord
psr (SISec
x, SISec2
x2)
= (SISec
x forall a. Num a => a -> a -> a
+ PerSizeRecord -> SISec
sumTransitTime PerSizeRecord
psr, SISec2
x2 forall a. Num a => a -> a -> a
+ PerSizeRecord -> SISec2
sumTransitTimeSq PerSizeRecord
psr)
data OneWayDeltaQSample = OneWaySample
{ OneWayDeltaQSample -> Double
duration :: Double
, OneWayDeltaQSample -> Key
sumPackets :: Int
, OneWayDeltaQSample -> Key
sumTotalSDU :: Int
, OneWayDeltaQSample -> Double
estDeltaQS :: Double
, OneWayDeltaQSample -> Double
estDeltaQVMean :: Double
, OneWayDeltaQSample -> Double
estDeltaQVVar :: Double
, OneWayDeltaQSample -> Double
estR :: Double
, OneWayDeltaQSample -> [Char]
sizeDist :: String
}
data StatsA = StatsA
{
StatsA -> Maybe (Word32, Time)
referenceTimePoint :: !(Maybe (Word32, Time))
, StatsA -> Time
nextSampleAt :: !Time
, StatsA -> Key
numObservations :: !Int
, StatsA -> Time
timeLastObs :: !Time
, StatsA -> IntMap PerSizeRecord
observables :: !(IntMap PerSizeRecord)
}
data PerSizeRecord = PSR
{ PerSizeRecord -> SISec
minTransitTime :: !SISec
, PerSizeRecord -> Key
count :: !Int
, PerSizeRecord -> SISec
sumTransitTime :: !SISec
, PerSizeRecord -> SISec2
sumTransitTimeSq :: !SISec2
}
instance Semigroup PerSizeRecord where
PerSizeRecord
a <> :: PerSizeRecord -> PerSizeRecord -> PerSizeRecord
<> PerSizeRecord
b = PSR { minTransitTime :: SISec
minTransitTime = (PerSizeRecord -> SISec
minTransitTime PerSizeRecord
a) forall a. Ord a => a -> a -> a
`min` (PerSizeRecord -> SISec
minTransitTime PerSizeRecord
b)
, count :: Key
count = PerSizeRecord -> Key
count PerSizeRecord
a forall a. Num a => a -> a -> a
+ PerSizeRecord -> Key
count PerSizeRecord
b
, sumTransitTime :: SISec
sumTransitTime = PerSizeRecord -> SISec
sumTransitTime PerSizeRecord
a forall a. Num a => a -> a -> a
+ PerSizeRecord -> SISec
sumTransitTime PerSizeRecord
b
, sumTransitTimeSq :: SISec2
sumTransitTimeSq = PerSizeRecord -> SISec2
sumTransitTimeSq PerSizeRecord
a forall a. Num a => a -> a -> a
+ PerSizeRecord -> SISec2
sumTransitTimeSq PerSizeRecord
b
}
normalisePSR :: SISec -> PerSizeRecord -> PerSizeRecord
normalisePSR :: SISec -> PerSizeRecord -> PerSizeRecord
normalisePSR SISec
norm PerSizeRecord
psr
= let adj :: SISec
adj = (forall a b. (Integral a, Num b) => a -> b
fromIntegral (PerSizeRecord -> Key
count PerSizeRecord
psr) forall a. Num a => a -> a -> a
* SISec
norm)
stt' :: SISec
stt' = (PerSizeRecord -> SISec
sumTransitTime PerSizeRecord
psr) forall a. Num a => a -> a -> a
- SISec
adj
ttt :: SISec -> SISec -> SISec2
ttt (S Float
a) (S Float
b)
= Float -> SISec2
S2 forall a b. (a -> b) -> a -> b
$ Float
a forall a. Num a => a -> a -> a
* Float
b
in PerSizeRecord
psr { minTransitTime :: SISec
minTransitTime = PerSizeRecord -> SISec
minTransitTime PerSizeRecord
psr forall a. Num a => a -> a -> a
- SISec
norm
, sumTransitTime :: SISec
sumTransitTime = SISec
stt'
, sumTransitTimeSq :: SISec2
sumTransitTimeSq = PerSizeRecord -> SISec2
sumTransitTimeSq PerSizeRecord
psr
forall a. Num a => a -> a -> a
- SISec
norm SISec -> SISec -> SISec2
`ttt` (SISec
2 forall a. Num a => a -> a -> a
* SISec
stt' forall a. Num a => a -> a -> a
+ SISec
norm)
}
initialStatsA :: StatsA
initialStatsA :: StatsA
initialStatsA = StatsA
{ referenceTimePoint :: Maybe (Word32, Time)
referenceTimePoint = forall a. Maybe a
Nothing
, nextSampleAt :: Time
nextSampleAt = Time
noTime
, numObservations :: Key
numObservations = Key
0
, timeLastObs :: Time
timeLastObs = Time
noTime
, observables :: IntMap PerSizeRecord
observables = forall a. IntMap a
IM.empty
}
where
noTime :: Time
noTime = DiffTime -> Time
Time DiffTime
0
makePerSizeRecord :: SISec -> PerSizeRecord
makePerSizeRecord :: SISec -> PerSizeRecord
makePerSizeRecord SISec
tt = PSR
{ minTransitTime :: SISec
minTransitTime = SISec
tt
, count :: Key
count = Key
1
, sumTransitTime :: SISec
sumTransitTime = SISec
tt
, sumTransitTimeSq :: SISec2
sumTransitTimeSq = SISec -> SISec2
squareSISec SISec
tt
}
sampleInterval :: DiffTime
sampleInterval :: DiffTime
sampleInterval = DiffTime -> DiffTime
check DiffTime
10
where
check :: DiffTime -> DiffTime
check DiffTime
n
| DiffTime
n forall a. Ord a => a -> a -> Bool
> DiffTime
0 Bool -> Bool -> Bool
&& DiffTime
n forall a. Ord a => a -> a -> Bool
< DiffTime
wrapInterval
= DiffTime
n
| Bool
otherwise
= forall a. HasCallStack => [Char] -> a
error [Char]
"Infeasible sampleInterval"
wrapInterval :: DiffTime
wrapInterval
= DiffTime
remoteClockPrecision forall a. Num a => a -> a -> a
* (forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ RemoteClockModel -> Word32
unRemoteClockModel forall a. Bounded a => a
maxBound)
nan :: Double
nan :: Double
nan = Double
0forall a. Fractional a => a -> a -> a
/Double
0