{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

module Network.QUIC.Recovery.Metrics (
    updateRTT,
    updateCC,
    metricsUpdated,
    setInitialCongestionWindow,
) where

import Data.Sequence (Seq)
import UnliftIO.STM

import Network.QUIC.Imports
import Network.QUIC.Qlog
import Network.QUIC.Recovery.Constants
import Network.QUIC.Recovery.Misc
import Network.QUIC.Recovery.Persistent
import Network.QUIC.Recovery.Types
import Network.QUIC.Types

updateRTT :: LDCC -> EncryptionLevel -> Microseconds -> Microseconds -> IO ()
updateRTT :: LDCC -> EncryptionLevel -> Microseconds -> Microseconds -> IO ()
updateRTT ldcc :: LDCC
ldcc@LDCC{Array EncryptionLevel (IORef Bool)
Array EncryptionLevel (IORef PeerPacketNumbers)
Array EncryptionLevel (IORef LossDetection)
Array EncryptionLevel (IORef SentPackets)
TVar (Maybe EncryptionLevel)
TVar TimerInfoQ
TVar CC
TVar SentPackets
IORef Bool
IORef PacketNumber
IORef (Maybe TimeoutKey)
IORef (Maybe TimerInfo)
IORef PeerPacketNumbers
IORef RTT
ConnState
PlainPacket -> IO ()
QLogger
ldccState :: ConnState
ldccQlogger :: QLogger
putRetrans :: PlainPacket -> IO ()
recoveryRTT :: IORef RTT
recoveryCC :: TVar CC
spaceDiscarded :: Array EncryptionLevel (IORef Bool)
sentPackets :: Array EncryptionLevel (IORef SentPackets)
lossDetection :: Array EncryptionLevel (IORef LossDetection)
timerKey :: IORef (Maybe TimeoutKey)
timerInfo :: IORef (Maybe TimerInfo)
lostCandidates :: TVar SentPackets
ptoPing :: TVar (Maybe EncryptionLevel)
speedingUp :: IORef Bool
pktNumPersistent :: IORef PacketNumber
peerPacketNumbers :: Array EncryptionLevel (IORef PeerPacketNumbers)
previousRTT1PPNs :: IORef PeerPacketNumbers
timerInfoQ :: TVar TimerInfoQ
ldccState :: LDCC -> ConnState
ldccQlogger :: LDCC -> QLogger
putRetrans :: LDCC -> PlainPacket -> IO ()
recoveryRTT :: LDCC -> IORef RTT
recoveryCC :: LDCC -> TVar CC
spaceDiscarded :: LDCC -> Array EncryptionLevel (IORef Bool)
sentPackets :: LDCC -> Array EncryptionLevel (IORef SentPackets)
lossDetection :: LDCC -> Array EncryptionLevel (IORef LossDetection)
timerKey :: LDCC -> IORef (Maybe TimeoutKey)
timerInfo :: LDCC -> IORef (Maybe TimerInfo)
lostCandidates :: LDCC -> TVar SentPackets
ptoPing :: LDCC -> TVar (Maybe EncryptionLevel)
speedingUp :: LDCC -> IORef Bool
pktNumPersistent :: LDCC -> IORef PacketNumber
peerPacketNumbers :: LDCC -> Array EncryptionLevel (IORef PeerPacketNumbers)
previousRTT1PPNs :: LDCC -> IORef PeerPacketNumbers
timerInfoQ :: LDCC -> TVar TimerInfoQ
..} EncryptionLevel
lvl Microseconds
latestRTT0 Microseconds
ackDelay0 = LDCC -> IO () -> IO ()
metricsUpdated LDCC
ldcc (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    Bool
firstTime <- IORef RTT -> (RTT -> (RTT, Bool)) -> IO Bool
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef RTT
recoveryRTT RTT -> (RTT, Bool)
update
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
firstTime (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
        LDCC -> IO ()
setPktNumPersistent LDCC
ldcc
        LDCC -> Debug -> IO ()
forall q. KeepQlog q => q -> Debug -> IO ()
qlogDebug LDCC
ldcc (Debug -> IO ()) -> Debug -> IO ()
forall a b. (a -> b) -> a -> b
$ LogStr -> Debug
Debug LogStr
"RTT first sample"
  where
    -- don't use latestRTT, use latestRTT0 instead
    --
    -- First time:
    -- Overwriting the initial value with the first sample.
    -- Initial value was used to calculate PTO.
    --
    -- smoothed_rtt = rtt_sample
    -- rttvar = rtt_sample / 2
    update :: RTT -> (RTT, Bool)
update rtt :: RTT
rtt@RTT{PacketNumber
Microseconds
latestRTT :: Microseconds
smoothedRTT :: Microseconds
rttvar :: Microseconds
minRTT :: Microseconds
maxAckDelay1RTT :: Microseconds
ptoCount :: PacketNumber
latestRTT :: RTT -> Microseconds
smoothedRTT :: RTT -> Microseconds
rttvar :: RTT -> Microseconds
minRTT :: RTT -> Microseconds
maxAckDelay1RTT :: RTT -> Microseconds
ptoCount :: RTT -> PacketNumber
..}
        | Microseconds
latestRTT Microseconds -> Microseconds -> Bool
forall a. Eq a => a -> a -> Bool
== PacketNumber -> Microseconds
Microseconds PacketNumber
0 =
            ( RTT
rtt
                { latestRTT = latestRTT0
                , minRTT = latestRTT0
                , smoothedRTT = latestRTT0
                , rttvar = latestRTT0 `unsafeShiftR` 1
                }
            , Bool
True
            )
    -- Others:
    update rtt :: RTT
rtt@RTT{PacketNumber
Microseconds
latestRTT :: RTT -> Microseconds
smoothedRTT :: RTT -> Microseconds
rttvar :: RTT -> Microseconds
minRTT :: RTT -> Microseconds
maxAckDelay1RTT :: RTT -> Microseconds
ptoCount :: RTT -> PacketNumber
latestRTT :: Microseconds
smoothedRTT :: Microseconds
rttvar :: Microseconds
minRTT :: Microseconds
maxAckDelay1RTT :: Microseconds
ptoCount :: PacketNumber
..} =
        ( RTT
rtt
            { latestRTT = latestRTT0
            , minRTT = minRTT'
            , smoothedRTT = smoothedRTT'
            , rttvar = rttvar'
            }
        , Bool
False
        )
      where
        -- minRTT ignores ack delay.
        minRTT' :: Microseconds
minRTT' = Microseconds -> Microseconds -> Microseconds
forall a. Ord a => a -> a -> a
min Microseconds
minRTT Microseconds
latestRTT0
        -- Limit ack_delay by max_ack_delay
        -- ack_delay = min(Ack Delay in ACK Frame, max_ack_delay)
        ackDelay :: Microseconds
ackDelay = Microseconds -> Microseconds -> Microseconds
forall a. Ord a => a -> a -> a
min Microseconds
ackDelay0 (Microseconds -> Microseconds) -> Microseconds -> Microseconds
forall a b. (a -> b) -> a -> b
$ Maybe EncryptionLevel -> Microseconds -> Microseconds
getMaxAckDelay (EncryptionLevel -> Maybe EncryptionLevel
forall a. a -> Maybe a
Just EncryptionLevel
lvl) Microseconds
maxAckDelay1RTT
        -- Adjust for ack delay if plausible.
        -- adjusted_rtt = latest_rtt
        -- if (latest_rtt >= min_rtt + ack_delay):
        --   adjusted_rtt = latest_rtt - ack_delay
        adjustedRTT :: Microseconds
adjustedRTT
            | Microseconds
latestRTT0 Microseconds -> Microseconds -> Bool
forall a. Ord a => a -> a -> Bool
>= Microseconds
minRTT Microseconds -> Microseconds -> Microseconds
forall a. Num a => a -> a -> a
+ Microseconds
ackDelay = Microseconds
latestRTT0 Microseconds -> Microseconds -> Microseconds
forall a. Num a => a -> a -> a
- Microseconds
ackDelay
            | Bool
otherwise = Microseconds
latestRTT0
        -- rttvar_sample = abs(smoothed_rtt - adjusted_rtt)
        -- rttvar = 3/4 * rttvar + 1/4 * rttvar_sample
        rttvar' :: Microseconds
rttvar' =
            Microseconds
rttvar
                Microseconds -> Microseconds -> Microseconds
forall a. Num a => a -> a -> a
- (Microseconds
rttvar Microseconds -> PacketNumber -> Microseconds
forall a. Bits a => a -> PacketNumber -> a
!>>. PacketNumber
2)
                Microseconds -> Microseconds -> Microseconds
forall a. Num a => a -> a -> a
+ (Microseconds -> Microseconds
forall a. Num a => a -> a
abs (Microseconds
smoothedRTT Microseconds -> Microseconds -> Microseconds
forall a. Num a => a -> a -> a
- Microseconds
adjustedRTT) Microseconds -> PacketNumber -> Microseconds
forall a. Bits a => a -> PacketNumber -> a
!>>. PacketNumber
2)
        -- smoothed_rtt = 7/8 * smoothed_rtt + 1/8 * adjusted_rtt
        smoothedRTT' :: Microseconds
smoothedRTT' =
            Microseconds
smoothedRTT
                Microseconds -> Microseconds -> Microseconds
forall a. Num a => a -> a -> a
- (Microseconds
smoothedRTT Microseconds -> PacketNumber -> Microseconds
forall a. Bits a => a -> PacketNumber -> a
!>>. PacketNumber
3)
                Microseconds -> Microseconds -> Microseconds
forall a. Num a => a -> a -> a
+ (Microseconds
adjustedRTT Microseconds -> PacketNumber -> Microseconds
forall a. Bits a => a -> PacketNumber -> a
!>>. PacketNumber
3)

updateCC :: LDCC -> Seq SentPacket -> Bool -> IO ()
updateCC :: LDCC -> Seq SentPacket -> Bool -> IO ()
updateCC ldcc :: LDCC
ldcc@LDCC{Array EncryptionLevel (IORef Bool)
Array EncryptionLevel (IORef PeerPacketNumbers)
Array EncryptionLevel (IORef LossDetection)
Array EncryptionLevel (IORef SentPackets)
TVar (Maybe EncryptionLevel)
TVar TimerInfoQ
TVar CC
TVar SentPackets
IORef Bool
IORef PacketNumber
IORef (Maybe TimeoutKey)
IORef (Maybe TimerInfo)
IORef PeerPacketNumbers
IORef RTT
ConnState
PlainPacket -> IO ()
QLogger
ldccState :: LDCC -> ConnState
ldccQlogger :: LDCC -> QLogger
putRetrans :: LDCC -> PlainPacket -> IO ()
recoveryRTT :: LDCC -> IORef RTT
recoveryCC :: LDCC -> TVar CC
spaceDiscarded :: LDCC -> Array EncryptionLevel (IORef Bool)
sentPackets :: LDCC -> Array EncryptionLevel (IORef SentPackets)
lossDetection :: LDCC -> Array EncryptionLevel (IORef LossDetection)
timerKey :: LDCC -> IORef (Maybe TimeoutKey)
timerInfo :: LDCC -> IORef (Maybe TimerInfo)
lostCandidates :: LDCC -> TVar SentPackets
ptoPing :: LDCC -> TVar (Maybe EncryptionLevel)
speedingUp :: LDCC -> IORef Bool
pktNumPersistent :: LDCC -> IORef PacketNumber
peerPacketNumbers :: LDCC -> Array EncryptionLevel (IORef PeerPacketNumbers)
previousRTT1PPNs :: LDCC -> IORef PeerPacketNumbers
timerInfoQ :: LDCC -> TVar TimerInfoQ
ldccState :: ConnState
ldccQlogger :: QLogger
putRetrans :: PlainPacket -> IO ()
recoveryRTT :: IORef RTT
recoveryCC :: TVar CC
spaceDiscarded :: Array EncryptionLevel (IORef Bool)
sentPackets :: Array EncryptionLevel (IORef SentPackets)
lossDetection :: Array EncryptionLevel (IORef LossDetection)
timerKey :: IORef (Maybe TimeoutKey)
timerInfo :: IORef (Maybe TimerInfo)
lostCandidates :: TVar SentPackets
ptoPing :: TVar (Maybe EncryptionLevel)
speedingUp :: IORef Bool
pktNumPersistent :: IORef PacketNumber
peerPacketNumbers :: Array EncryptionLevel (IORef PeerPacketNumbers)
previousRTT1PPNs :: IORef PeerPacketNumbers
timerInfoQ :: TVar TimerInfoQ
..} Seq SentPacket
lostPackets Bool
isRecovery = do
    Bool
persistent <- LDCC -> Seq SentPacket -> IO Bool
inPersistentCongestion LDCC
ldcc Seq SentPacket
lostPackets
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
persistent Bool -> Bool -> Bool
|| Bool -> Bool
not Bool
isRecovery) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
        PacketNumber
minWindow <- LDCC -> IO PacketNumber
kMinimumWindow LDCC
ldcc
        TimeMicrosecond
now <- IO TimeMicrosecond
getTimeMicrosecond
        LDCC -> IO () -> IO ()
metricsUpdated LDCC
ldcc (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ STM () -> IO ()
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ TVar CC -> (CC -> CC) -> STM ()
forall a. TVar a -> (a -> a) -> STM ()
modifyTVar' TVar CC
recoveryCC ((CC -> CC) -> STM ()) -> (CC -> CC) -> STM ()
forall a b. (a -> b) -> a -> b
$ \cc :: CC
cc@CC{PacketNumber
Maybe TimeMicrosecond
CCMode
bytesInFlight :: PacketNumber
congestionWindow :: PacketNumber
congestionRecoveryStartTime :: Maybe TimeMicrosecond
ssthresh :: PacketNumber
bytesAcked :: PacketNumber
numOfAckEliciting :: PacketNumber
ccMode :: CCMode
bytesInFlight :: CC -> PacketNumber
congestionWindow :: CC -> PacketNumber
congestionRecoveryStartTime :: CC -> Maybe TimeMicrosecond
ssthresh :: CC -> PacketNumber
bytesAcked :: CC -> PacketNumber
numOfAckEliciting :: CC -> PacketNumber
ccMode :: CC -> CCMode
..} ->
            let halfWindow :: PacketNumber
halfWindow = PacketNumber -> PacketNumber -> PacketNumber
forall a. Ord a => a -> a -> a
max PacketNumber
minWindow (PacketNumber -> PacketNumber) -> PacketNumber -> PacketNumber
forall a b. (a -> b) -> a -> b
$ PacketNumber -> PacketNumber
kLossReductionFactor PacketNumber
congestionWindow
                cwin :: PacketNumber
cwin
                    | Bool
persistent = PacketNumber
minWindow
                    | Bool
otherwise = PacketNumber
halfWindow
                sst :: PacketNumber
sst = PacketNumber
halfWindow
                mode :: CCMode
mode
                    | PacketNumber
cwin PacketNumber -> PacketNumber -> Bool
forall a. Ord a => a -> a -> Bool
< PacketNumber
sst = CCMode
SlowStart -- persistent
                    | Bool
otherwise = CCMode
Recovery
             in CC
cc
                    { congestionRecoveryStartTime = Just now
                    , congestionWindow = cwin
                    , ssthresh = sst
                    , ccMode = mode
                    , bytesAcked = 0
                    }
        CC{CCMode
ccMode :: CC -> CCMode
ccMode :: CCMode
ccMode} <- TVar CC -> IO CC
forall (m :: * -> *) a. MonadIO m => TVar a -> m a
readTVarIO TVar CC
recoveryCC
        LDCC -> CCMode -> IO ()
forall q. KeepQlog q => q -> CCMode -> IO ()
qlogContestionStateUpdated LDCC
ldcc CCMode
ccMode

setInitialCongestionWindow :: LDCC -> Int -> IO ()
setInitialCongestionWindow :: LDCC -> PacketNumber -> IO ()
setInitialCongestionWindow ldcc :: LDCC
ldcc@LDCC{Array EncryptionLevel (IORef Bool)
Array EncryptionLevel (IORef PeerPacketNumbers)
Array EncryptionLevel (IORef LossDetection)
Array EncryptionLevel (IORef SentPackets)
TVar (Maybe EncryptionLevel)
TVar TimerInfoQ
TVar CC
TVar SentPackets
IORef Bool
IORef PacketNumber
IORef (Maybe TimeoutKey)
IORef (Maybe TimerInfo)
IORef PeerPacketNumbers
IORef RTT
ConnState
PlainPacket -> IO ()
QLogger
ldccState :: LDCC -> ConnState
ldccQlogger :: LDCC -> QLogger
putRetrans :: LDCC -> PlainPacket -> IO ()
recoveryRTT :: LDCC -> IORef RTT
recoveryCC :: LDCC -> TVar CC
spaceDiscarded :: LDCC -> Array EncryptionLevel (IORef Bool)
sentPackets :: LDCC -> Array EncryptionLevel (IORef SentPackets)
lossDetection :: LDCC -> Array EncryptionLevel (IORef LossDetection)
timerKey :: LDCC -> IORef (Maybe TimeoutKey)
timerInfo :: LDCC -> IORef (Maybe TimerInfo)
lostCandidates :: LDCC -> TVar SentPackets
ptoPing :: LDCC -> TVar (Maybe EncryptionLevel)
speedingUp :: LDCC -> IORef Bool
pktNumPersistent :: LDCC -> IORef PacketNumber
peerPacketNumbers :: LDCC -> Array EncryptionLevel (IORef PeerPacketNumbers)
previousRTT1PPNs :: LDCC -> IORef PeerPacketNumbers
timerInfoQ :: LDCC -> TVar TimerInfoQ
ldccState :: ConnState
ldccQlogger :: QLogger
putRetrans :: PlainPacket -> IO ()
recoveryRTT :: IORef RTT
recoveryCC :: TVar CC
spaceDiscarded :: Array EncryptionLevel (IORef Bool)
sentPackets :: Array EncryptionLevel (IORef SentPackets)
lossDetection :: Array EncryptionLevel (IORef LossDetection)
timerKey :: IORef (Maybe TimeoutKey)
timerInfo :: IORef (Maybe TimerInfo)
lostCandidates :: TVar SentPackets
ptoPing :: TVar (Maybe EncryptionLevel)
speedingUp :: IORef Bool
pktNumPersistent :: IORef PacketNumber
peerPacketNumbers :: Array EncryptionLevel (IORef PeerPacketNumbers)
previousRTT1PPNs :: IORef PeerPacketNumbers
timerInfoQ :: TVar TimerInfoQ
..} PacketNumber
pktSiz = LDCC -> IO () -> IO ()
metricsUpdated LDCC
ldcc (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
    STM () -> IO ()
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
        TVar CC -> (CC -> CC) -> STM ()
forall a. TVar a -> (a -> a) -> STM ()
modifyTVar' TVar CC
recoveryCC ((CC -> CC) -> STM ()) -> (CC -> CC) -> STM ()
forall a b. (a -> b) -> a -> b
$ \CC
cc ->
            CC
cc
                { congestionWindow = kInitialWindow pktSiz
                }

----------------------------------------------------------------

metricsUpdated :: LDCC -> IO () -> IO ()
metricsUpdated :: LDCC -> IO () -> IO ()
metricsUpdated ldcc :: LDCC
ldcc@LDCC{Array EncryptionLevel (IORef Bool)
Array EncryptionLevel (IORef PeerPacketNumbers)
Array EncryptionLevel (IORef LossDetection)
Array EncryptionLevel (IORef SentPackets)
TVar (Maybe EncryptionLevel)
TVar TimerInfoQ
TVar CC
TVar SentPackets
IORef Bool
IORef PacketNumber
IORef (Maybe TimeoutKey)
IORef (Maybe TimerInfo)
IORef PeerPacketNumbers
IORef RTT
ConnState
PlainPacket -> IO ()
QLogger
ldccState :: LDCC -> ConnState
ldccQlogger :: LDCC -> QLogger
putRetrans :: LDCC -> PlainPacket -> IO ()
recoveryRTT :: LDCC -> IORef RTT
recoveryCC :: LDCC -> TVar CC
spaceDiscarded :: LDCC -> Array EncryptionLevel (IORef Bool)
sentPackets :: LDCC -> Array EncryptionLevel (IORef SentPackets)
lossDetection :: LDCC -> Array EncryptionLevel (IORef LossDetection)
timerKey :: LDCC -> IORef (Maybe TimeoutKey)
timerInfo :: LDCC -> IORef (Maybe TimerInfo)
lostCandidates :: LDCC -> TVar SentPackets
ptoPing :: LDCC -> TVar (Maybe EncryptionLevel)
speedingUp :: LDCC -> IORef Bool
pktNumPersistent :: LDCC -> IORef PacketNumber
peerPacketNumbers :: LDCC -> Array EncryptionLevel (IORef PeerPacketNumbers)
previousRTT1PPNs :: LDCC -> IORef PeerPacketNumbers
timerInfoQ :: LDCC -> TVar TimerInfoQ
ldccState :: ConnState
ldccQlogger :: QLogger
putRetrans :: PlainPacket -> IO ()
recoveryRTT :: IORef RTT
recoveryCC :: TVar CC
spaceDiscarded :: Array EncryptionLevel (IORef Bool)
sentPackets :: Array EncryptionLevel (IORef SentPackets)
lossDetection :: Array EncryptionLevel (IORef LossDetection)
timerKey :: IORef (Maybe TimeoutKey)
timerInfo :: IORef (Maybe TimerInfo)
lostCandidates :: TVar SentPackets
ptoPing :: TVar (Maybe EncryptionLevel)
speedingUp :: IORef Bool
pktNumPersistent :: IORef PacketNumber
peerPacketNumbers :: Array EncryptionLevel (IORef PeerPacketNumbers)
previousRTT1PPNs :: IORef PeerPacketNumbers
timerInfoQ :: TVar TimerInfoQ
..} IO ()
body = do
    RTT
rtt0 <- IORef RTT -> IO RTT
forall a. IORef a -> IO a
readIORef IORef RTT
recoveryRTT
    CC
cc0 <- TVar CC -> IO CC
forall (m :: * -> *) a. MonadIO m => TVar a -> m a
readTVarIO TVar CC
recoveryCC
    IO ()
body
    RTT
rtt1 <- IORef RTT -> IO RTT
forall a. IORef a -> IO a
readIORef IORef RTT
recoveryRTT
    CC
cc1 <- TVar CC -> IO CC
forall (m :: * -> *) a. MonadIO m => TVar a -> m a
readTVarIO TVar CC
recoveryCC
    let ~[(String, PacketNumber)]
diff =
            [Maybe (String, PacketNumber)] -> [(String, PacketNumber)]
forall a. [Maybe a] -> [a]
catMaybes
                [ String
-> Microseconds -> Microseconds -> Maybe (String, PacketNumber)
forall {a}.
a -> Microseconds -> Microseconds -> Maybe (a, PacketNumber)
time String
"min_rtt" (RTT -> Microseconds
minRTT RTT
rtt0) (RTT -> Microseconds
minRTT RTT
rtt1)
                , String
-> Microseconds -> Microseconds -> Maybe (String, PacketNumber)
forall {a}.
a -> Microseconds -> Microseconds -> Maybe (a, PacketNumber)
time String
"smoothed_rtt" (RTT -> Microseconds
smoothedRTT RTT
rtt0) (RTT -> Microseconds
smoothedRTT RTT
rtt1)
                , String
-> Microseconds -> Microseconds -> Maybe (String, PacketNumber)
forall {a}.
a -> Microseconds -> Microseconds -> Maybe (a, PacketNumber)
time String
"latest_rtt" (RTT -> Microseconds
latestRTT RTT
rtt0) (RTT -> Microseconds
latestRTT RTT
rtt1)
                , String
-> Microseconds -> Microseconds -> Maybe (String, PacketNumber)
forall {a}.
a -> Microseconds -> Microseconds -> Maybe (a, PacketNumber)
time String
"rtt_variance" (RTT -> Microseconds
rttvar RTT
rtt0) (RTT -> Microseconds
rttvar RTT
rtt1)
                , String
-> PacketNumber -> PacketNumber -> Maybe (String, PacketNumber)
forall {b} {a}. Eq b => a -> b -> b -> Maybe (a, b)
numb String
"pto_count" (RTT -> PacketNumber
ptoCount RTT
rtt0) (RTT -> PacketNumber
ptoCount RTT
rtt1)
                , String
-> PacketNumber -> PacketNumber -> Maybe (String, PacketNumber)
forall {b} {a}. Eq b => a -> b -> b -> Maybe (a, b)
numb String
"bytes_in_flight" (CC -> PacketNumber
bytesInFlight CC
cc0) (CC -> PacketNumber
bytesInFlight CC
cc1)
                , String
-> PacketNumber -> PacketNumber -> Maybe (String, PacketNumber)
forall {b} {a}. Eq b => a -> b -> b -> Maybe (a, b)
numb String
"congestion_window" (CC -> PacketNumber
congestionWindow CC
cc0) (CC -> PacketNumber
congestionWindow CC
cc1)
                , String
-> PacketNumber -> PacketNumber -> Maybe (String, PacketNumber)
forall {b} {a}. Eq b => a -> b -> b -> Maybe (a, b)
numb String
"ssthresh" (CC -> PacketNumber
ssthresh CC
cc0) (CC -> PacketNumber
ssthresh CC
cc1)
                ]
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless ([(String, PacketNumber)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(String, PacketNumber)]
diff) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ LDCC -> MetricsDiff -> IO ()
forall q. KeepQlog q => q -> MetricsDiff -> IO ()
qlogMetricsUpdated LDCC
ldcc (MetricsDiff -> IO ()) -> MetricsDiff -> IO ()
forall a b. (a -> b) -> a -> b
$ [(String, PacketNumber)] -> MetricsDiff
MetricsDiff [(String, PacketNumber)]
diff
  where
    time :: a -> Microseconds -> Microseconds -> Maybe (a, PacketNumber)
time a
tag (Microseconds PacketNumber
v0) (Microseconds PacketNumber
v1)
        | PacketNumber
v0 PacketNumber -> PacketNumber -> Bool
forall a. Eq a => a -> a -> Bool
== PacketNumber
v1 = Maybe (a, PacketNumber)
forall a. Maybe a
Nothing
        | Bool
otherwise = (a, PacketNumber) -> Maybe (a, PacketNumber)
forall a. a -> Maybe a
Just (a
tag, PacketNumber
v1)
    numb :: a -> b -> b -> Maybe (a, b)
numb a
tag b
v0 b
v1
        | b
v0 b -> b -> Bool
forall a. Eq a => a -> a -> Bool
== b
v1 = Maybe (a, b)
forall a. Maybe a
Nothing
        | Bool
otherwise = (a, b) -> Maybe (a, b)
forall a. a -> Maybe a
Just (a
tag, b
v1)