forked from Holmusk/three-layer
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMeasure.hs
More file actions
57 lines (48 loc) · 1.76 KB
/
Measure.hs
File metadata and controls
57 lines (48 loc) · 1.76 KB
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
module Lib.Effects.Measure
( MonadMeasure
, MonadTimed (timedAction) -- temporarily required for mock tests
-- * Internals
, timedActionImpl
) where
import Relude.Extra.CallStack (ownName)
import Lib.App (App, Has (..), Timings, grab)
import qualified Data.HashMap.Strict as HashMap
import qualified GHC.Clock as Clock
import qualified System.Metrics as Metrics
import qualified System.Metrics.Distribution as Distribution
-- | Performs action
class Monad m => MonadTimed m where
timedAction :: HasCallStack => m a -> m a
instance MonadTimed App where
timedAction = withFrozenCallStack timedActionImpl
type MonadMeasure m = (HasCallStack, MonadTimed m)
-- | Measure the time taken to perform the given action and store it
-- in the 'timings' distribution with the given label
timedActionImpl
:: forall r m a .
( MonadReader r m
, Has Timings r
, Has Metrics.Store r
, MonadIO m
, HasCallStack
)
=> m a -> m a
timedActionImpl action = do
start <- liftIO Clock.getMonotonicTimeNSec
!result <- action
end <- liftIO Clock.getMonotonicTimeNSec
let !timeTaken = fromIntegral (end - start) * 1e-9
dist <- getOrCreateDistribution $ toText ownName
liftIO $ Distribution.add dist timeTaken
return result
where
getOrCreateDistribution :: Text -> m Distribution.Distribution
getOrCreateDistribution label = do
timingsRef <- grab @Timings
store <- grab @Metrics.Store
liftIO $ do
distMap <- readIORef timingsRef
whenNothing (HashMap.lookup label distMap) $ do
newDist <- Metrics.createDistribution label store
modifyIORef' timingsRef (HashMap.insert label newDist)
pure newDist