-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy pathRateCalc.hs
83 lines (71 loc) · 2.74 KB
/
RateCalc.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
-- | Rate calculation.
{-# LANGUAGE BangPatterns #-}
module RateCalc (
-- * Types
Rate
-- * Interface
, new
, update
, extractCount
, extractRate
)
where
import Control.DeepSeq
import Data.Time.Clock
-- | A Rate is a record of information used for calculating the rate
data Rate = Rate
{ rate :: !Double -- ^ The current rate
, bytes :: !Int -- ^ The amount of bytes transferred since last rate extraction
, count :: !Int -- ^ The amount of bytes transferred since last count extraction
, lastExt :: !UTCTime -- ^ When was the last rate update
, rateSince :: !UTCTime -- ^ From where is the rate measured
}
instance NFData Rate where
rnf (Rate r b c _ _) =
rnf r `seq` rnf b `seq` rnf c
fudge :: NominalDiffTime
fudge = fromInteger 5 -- Seconds
maxRatePeriod :: NominalDiffTime
maxRatePeriod = fromInteger 20 -- Seconds
new :: UTCTime -> Rate
new t = Rate { rate = 0.0
, bytes = 0
, count = 0
, lastExt = addUTCTime (-fudge) t
, rateSince = addUTCTime (-fudge) t
}
-- | The call @update n rt@ updates the rate structure @rt@ with @n@ new bytes
update :: Int -> Rate -> Rate
update n rt = {-# SCC "update" #-}
rt { bytes = nb, count = nc}
where !nb = bytes rt + n
!nc = count rt + n
-- | The call @extractRate t rt@ extracts the current rate from the rate
-- structure and updates the rate structures internal book-keeping
extractRate :: UTCTime -> Rate -> (Double, Rate)
extractRate t rt = {-# SCC "extractRate" #-}
let since = rateSince rt
lext = lastExt rt
n = bytes rt
oldWindow :: Double
oldWindow = {-# SCC "diffUTC1" #-} realToFrac $ diffUTCTime lext since
newWindow :: Double
newWindow = {-# SCC "diffUTS2" #-} realToFrac $ diffUTCTime t since
!r = {-# SCC "r" #-} (rate rt * oldWindow + (fromIntegral n)) / newWindow
!nrt = {-# SCC "rt_creat" #-}
rt { rate = r
, bytes = 0
, lastExt = t
, rateSince = {-# SCC "max" #-} max since (addUTCTime (-maxRatePeriod) t)
}
in
-- Update the rate and book-keep the missing pieces. The total is simply a built-in
-- counter. The point where we expect the next update is pushed at most 5 seconds ahead
-- in time. But it might come earlier if the rate is high.
-- Last is updated with the current time. Finally, we move the windows earliest value
-- forward if it is more than 20 seconds from now.
(r, nrt)
-- | The call @extractCount rt@ extract the bytes transferred since last extraction
extractCount :: Rate -> (Int, Rate)
extractCount rt = {-# SCC "extractCount" #-} (crt, rt { count = 0 })
where crt = count rt