on master help sign in
Refactor the "times" function

Factor out the clock creation and reading functions.

commitc3298c1177387de1806b4e7b4c33ce6840a9a888 authorHarendra Kumar <harendra@composewell.com> dateFri 5 Feb 2021, 01:09 (6 years ago) parente4e1d25
2 files changed+48−23
src/Streamly/Internal/Data/Stream/StreamD/Generate.hs+40−22 src/Streamly/Internal/Data/Time/Units.hs+8−1
src/Streamly/Internal/Data/Stream/StreamD/Generate.hs+40−22
@@ -89,10 +89,9 @@ where
8989
9090#include "inline.hs"
9191
92−import Control.Concurrent (threadDelay)
92+import Control.Concurrent (threadDelay, ThreadId)
9393import Control.Monad (forever)
9494import Control.Monad.IO.Class (MonadIO(..))
95−import Data.Int (Int64)
9695import Streamly.Internal.Data.Time.Units (toRelTime64, RelTime64)
9796import Streamly.Internal.Data.Time.Clock (Clock(Monotonic), getTime)
9897import Streamly.Internal.Data.Time.Units
@@ -326,16 +325,17 @@ numFromThen from next = enumerateFromStepNum from (next - from)
326325------------------------------------------------------------------------------
327326
328327{-# INLINE updateTimeVar #-}
329−updateTimeVar :: Prim.IORef Int64 -> IO ()
330−updateTimeVar timeVar = do
331− MicroSecond64 t <- fromAbsTime <$> getTime Monotonic
328+updateTimeVar :: Clock -> Prim.IORef MicroSecond64 -> IO ()
329+updateTimeVar clock timeVar = do
330+ t <- fromAbsTime <$> getTime clock
332331 Prim.modifyIORef' timeVar (const t)
333332
334333{-# INLINE updateWithDelay #-}
335−updateWithDelay :: RealFrac a => a -> Prim.IORef Int64 -> IO ()
336−updateWithDelay precision timeVar = do
334+updateWithDelay :: RealFrac a =>
335+ Clock -> a -> Prim.IORef MicroSecond64 -> IO ()
336+updateWithDelay clock precision timeVar = do
337337 threadDelay (delayTime precision)
338− updateTimeVar timeVar
338+ updateTimeVar clock timeVar
339339
340340 where
341341
@@ -344,12 +344,36 @@ updateWithDelay precision timeVar = do
344344 delayTime g
345345 | g' >= fromIntegral (maxBound :: Int) = maxBound
346346 | g' < 1000 = 1000
347− | otherwise = round g'
347+ | otherwise = round g'
348348
349349 where
350350
351351 g' = g * 10 ^ (6 :: Int)
352352
353+-- XXX Move this to the time/clock module?
354+--
355+-- | @asyncClock g@ starts a clock thread that updates an IORef with current
356+-- time as a 64-bit value in microseconds, every 'g' seconds. The IORef can be
357+-- read asynchronously. The thread exits automatically when the reference to
358+-- the returned 'ThreadId' is lost.
359+--
360+-- Minimum granularity of clock update is 1 ms. Higher is better for
361+-- performance.
362+--
363+-- CAUTION! This is safe only on a 64-bit machine. On a 32-bit machine a 64-bit
364+-- 'Var' cannot be read consistently without a lock while another thread is
365+-- writing to it.
366+asyncClock :: Clock -> Double -> IO (ThreadId, Prim.IORef MicroSecond64)
367+asyncClock clock g = do
368+ timeVar <- Prim.newIORef undefined
369+ updateTimeVar clock timeVar
370+ tid <- forkManaged $ forever (updateWithDelay clock g timeVar)
371+ return (tid, timeVar)
372+
373+{-# INLINE readClock #-}
374+readClock :: (ThreadId, Prim.IORef MicroSecond64) -> IO MicroSecond64
375+readClock (_, timeVar) = Prim.readIORef timeVar
376+
353377{-# INLINE_NORMAL times #-}
354378times :: MonadAsync m => Double -> Stream m (AbsTime, RelTime64)
355379times g = Stream step Nothing
@@ -358,22 +382,16 @@ times g = Stream step Nothing
358382
359383 {-# INLINE_LATE step #-}
360384 step _ Nothing = do
361− -- XXX note that this is safe only on a 64-bit machine. On a 32-bit
362− -- machine a 64-bit 'Var' cannot be read consistently without a lock
363− -- while another thread is writing to it.
364− timeVar <- liftIO $ Prim.newIORef (0 :: Int64)
365− liftIO $ updateTimeVar timeVar
366− tid <- forkManaged $ liftIO $ forever (updateWithDelay g timeVar)
367− a <- liftIO $ Prim.readIORef timeVar
368− return $ Skip $ Just (timeVar, tid, a)
369−
370− step _ s@(Just (timeVar, _, t0)) = do
371− a <- liftIO $ Prim.readIORef timeVar
385+ clock <- liftIO $ asyncClock Monotonic g
386+ a <- liftIO $ readClock clock
387+ return $ Skip $ Just (clock, a)
388+
389+ step _ s@(Just (clock, t0)) = do
390+ a <- liftIO $ readClock clock
372391 -- XXX we can perhaps use an AbsTime64 using a 64 bit Int for
373392 -- efficiency. or maybe we can use a representation using Double for
374393 -- floating precision time
375− return $ Yield (toAbsTime (MicroSecond64 t0),
376− (toRelTime64 (MicroSecond64 (a - t0)))) s
394+ return $ Yield (toAbsTime t0, toRelTime64 (a - t0)) s
377395
378396-------------------------------------------------------------------------------
379397-- From Generators
src/Streamly/Internal/Data/Time/Units.hs+8−1
@@ -1,4 +1,5 @@
1−#include "inline.hs"
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE UnboxedTuples #-}
23
34-- |
45-- Module : Streamly.Internal.Data.Time.Units
@@ -45,9 +46,12 @@ module Streamly.Internal.Data.Time.Units
4546 )
4647where
4748
49+#include "inline.hs"
50+
4851import Text.Printf (printf)
4952
5053import Data.Int
54+import Data.Primitive.Types (Prim(..))
5155import Streamly.Internal.Data.Time.TimeSpec
5256
5357-------------------------------------------------------------------------------
@@ -102,6 +106,7 @@ newtype NanoSecond64 = NanoSecond64 Int64
102106 , Real
103107 , Integral
104108 , Ord
109+ , Prim
105110 )
106111
107112-- | An 'Int64' time representation with a microsecond resolution.
@@ -116,6 +121,7 @@ newtype MicroSecond64 = MicroSecond64 Int64
116121 , Real
117122 , Integral
118123 , Ord
124+ , Prim
119125 )
120126
121127-- | An 'Int64' time representation with a millisecond resolution.
@@ -130,6 +136,7 @@ newtype MilliSecond64 = MilliSecond64 Int64
130136 , Real
131137 , Integral
132138 , Ord
139+ , Prim
133140 )
134141
135142-------------------------------------------------------------------------------