@@ -100,7 +100,6 @@ module Streamly.SVar
101 , toStreamVar
101 , toStreamVar
102 , SVarStats (..)
102 , SVarStats (..)
104 , dumpSVar
103 , dumpSVar
@@ -133,27 +132,15 @@ import Data.Set (Set)
133import GHC.Conc (ThreadId(..))
132import GHC.Conc (ThreadId(..))
134import GHC.Exts
133import GHC.Exts
135import GHC.IO (IO(..))
134import GHC.IO (IO(..))
136−import System.Clock (TimeSpec, Clock(Monotonic), getTime, toNanoSecs)
135+import Streamly.Clock
136+ (AbsTime, NanoSecond64(..), MicroSecond64(..), getTime, diffAbsTime64,
137+ fromRelTime64, toRelTime64)
137import System.IO (hPutStrLn, stderr)
138import System.IO (hPutStrLn, stderr)
138import Text.Printf (printf)
139import Text.Printf (printf)
140import qualified Data.Heap as H
141import qualified Data.Heap as H
141import qualified Data.Set as S
142import qualified Data.Set as S
143−-- Always use signed arithmetic to avoid inadvertant overflows of signed values
144−-- on conversion when comparing unsigned quantities with signed.
145−newtype NanoSecs = NanoSecs Int64
157newtype Count = Count Int64
144newtype Count = Count Int64
158 deriving ( Eq
145 deriving ( Eq
@@ -230,7 +217,7 @@ data WorkerInfo = WorkerInfo
230 -- total number of yields by the worker till now
217 -- total number of yields by the worker till now
231 , workerYieldCount :: IORef Count
218 , workerYieldCount :: IORef Count
232 -- yieldCount at start, timestamp
219 -- yieldCount at start, timestamp
233− , workerLatencyStart :: IORef (Count, TimeSpec)
220+ , workerLatencyStart :: IORef (Count, AbsTime)
@@ -262,13 +249,13 @@ data Rate = Rate
264data LatencyRange = LatencyRange
251data LatencyRange = LatencyRange
265− { minLatency :: NanoSecs
252+ { minLatency :: NanoSecond64
266− , maxLatency :: NanoSecs
253+ , maxLatency :: NanoSecond64
267 } deriving Show
254 } deriving Show
269-- Rate control.
256-- Rate control.
270data YieldRateInfo = YieldRateInfo
257data YieldRateInfo = YieldRateInfo
271− { svarLatencyTarget :: NanoSecs
258+ { svarLatencyTarget :: NanoSecond64
272 , svarLatencyRange :: LatencyRange
259 , svarLatencyRange :: LatencyRange
273 , svarRateBuffer :: Int
260 , svarRateBuffer :: Int
274 , svarGainedLostYields :: IORef Count
261 , svarGainedLostYields :: IORef Count
@@ -279,11 +266,11 @@ data YieldRateInfo = YieldRateInfo
279 -- rate. The idle time of workers is adjusted in this, so that we only
266 -- rate. The idle time of workers is adjusted in this, so that we only
280 -- account for the rate when the consumer actually demands data.
267 -- account for the rate when the consumer actually demands data.
281 -- XXX interval latency is enough, we can move this under diagnostics build
268 -- XXX interval latency is enough, we can move this under diagnostics build
282− , svarAllTimeLatency :: IORef (Count, TimeSpec)
269+ , svarAllTimeLatency :: IORef (Count, AbsTime)
284 -- XXX Worker latency specified by the user to be used before the first
271 -- XXX Worker latency specified by the user to be used before the first
285 -- actual measurement arrives. Not yet implemented
272 -- actual measurement arrives. Not yet implemented
286− , workerBootstrapLatency :: Maybe NanoSecs
273+ , workerBootstrapLatency :: Maybe NanoSecond64
288 -- After how many yields the worker should update the latency information.
275 -- After how many yields the worker should update the latency information.
289 -- If the latency is high, this count is kept lower and vice-versa. XXX If
276 -- If the latency is high, this count is kept lower and vice-versa. XXX If
@@ -297,7 +284,7 @@ data YieldRateInfo = YieldRateInfo
297 -- empty into workerCollectedLatency stats at certain intervals - whenever
284 -- empty into workerCollectedLatency stats at certain intervals - whenever
298 -- we process the stream elements yielded in this period.
285 -- we process the stream elements yielded in this period.
299 -- (yieldCount, timeTaken)
286 -- (yieldCount, timeTaken)
300− , workerPendingLatency :: IORef (Count, NanoSecs)
287+ , workerPendingLatency :: IORef (Count, NanoSecond64)
302 -- This is the second level stat which is an accmulation from
289 -- This is the second level stat which is an accmulation from
303 -- workerPendingLatency stats. We keep accumulating latencies in this
290 -- workerPendingLatency stats. We keep accumulating latencies in this
@@ -305,10 +292,10 @@ data YieldRateInfo = YieldRateInfo
305 -- to start collecting for the next period and retain the computed average
292 -- to start collecting for the next period and retain the computed average
306 -- latency for the last period in workerMeasuredLatency.
293 -- latency for the last period in workerMeasuredLatency.
307 -- (yieldCount, timeTaken)
294 -- (yieldCount, timeTaken)
308− , workerCollectedLatency :: IORef (Count, NanoSecs)
295+ , workerCollectedLatency :: IORef (Count, NanoSecond64)
310 -- Latency as measured by workers, aggregated for the last period.
297 -- Latency as measured by workers, aggregated for the last period.
311− , workerMeasuredLatency :: IORef NanoSecs
298+ , workerMeasuredLatency :: IORef NanoSecond64
314data SVarStats = SVarStats {
301data SVarStats = SVarStats {
@@ -317,10 +304,10 @@ data SVarStats = SVarStats {
317 , maxOutQSize :: IORef Int
304 , maxOutQSize :: IORef Int
318 , maxHeapSize :: IORef Int
305 , maxHeapSize :: IORef Int
319 , maxWorkQSize :: IORef Int
306 , maxWorkQSize :: IORef Int
320− , avgWorkerLatency :: IORef (Count, NanoSecs)
307+ , avgWorkerLatency :: IORef (Count, NanoSecond64)
321− , minWorkerLatency :: IORef NanoSecs
308+ , minWorkerLatency :: IORef NanoSecond64
322− , maxWorkerLatency :: IORef NanoSecs
309+ , maxWorkerLatency :: IORef NanoSecond64
323− , svarStopTime :: IORef (Maybe TimeSpec)
310+ , svarStopTime :: IORef (Maybe AbsTime)
326data Limit = Unlimited | Limited Word deriving Show
313data Limit = Unlimited | Limited Word deriving Show
@@ -393,7 +380,7 @@ data State t m a = State
393 , _threadsHigh :: Limit
380 , _threadsHigh :: Limit
394 , _bufferHigh :: Limit
381 , _bufferHigh :: Limit
395 -- XXX these two can be collapsed into a single type
382 -- XXX these two can be collapsed into a single type
396− , _streamLatency :: Maybe NanoSecs -- bootstrap latency
383+ , _streamLatency :: Maybe NanoSecond64 -- bootstrap latency
397 , _maxStreamRate :: Maybe Rate
384 , _maxStreamRate :: Maybe Rate
398 , _inspectMode :: Bool
385 , _inspectMode :: Bool
@@ -505,7 +492,7 @@ setStreamLatency n st =
505 else Just (fromIntegral n)
492 else Just (fromIntegral n)
508−getStreamLatency :: State t m a -> Maybe NanoSecs
495+getStreamLatency :: State t m a -> Maybe NanoSecond64
509getStreamLatency = _streamLatency
496getStreamLatency = _streamLatency
511setInspectMode :: State t m a -> State t m a
498setInspectMode :: State t m a -> State t m a
@@ -561,7 +548,7 @@ secs k
561 | otherwise = printf "%.3f %s" t u
548 | otherwise = printf "%.3f %s" t u
563-- XXX Code duplicated from collectLatency
550-- XXX Code duplicated from collectLatency
564−drainLatency :: SVar t m a -> YieldRateInfo -> IO (Count, TimeSpec, NanoSecs)
551+drainLatency :: SVar t m a -> YieldRateInfo -> IO (Count, AbsTime, NanoSecond64)
565drainLatency sv yinfo = do
552drainLatency sv yinfo = do
566 let cur = workerPendingLatency yinfo
553 let cur = workerPendingLatency yinfo
567 col = workerCollectedLatency yinfo
554 col = workerCollectedLatency yinfo
@@ -624,11 +611,11 @@ dumpSVarStats sv ss style = do
624 gl <- readIORef (svarGainedLostYields yinfo)
611 gl <- readIORef (svarGainedLostYields yinfo)
625 case t of
612 case t of
626 Nothing -> do
613 Nothing -> do
627− now <- getTime Monotonic
614+ now <- getTime
628− let interval = toNanoSecs (now - startTime)
615+ let interval = diffAbsTime64 now startTime
629 return (cnt, gl, interval `div` fromIntegral cnt)
616 return (cnt, gl, interval `div` fromIntegral cnt)
630 Just stopTime -> do
617 Just stopTime -> do
631− let interval = toNanoSecs (stopTime - startTime)
618+ let interval = diffAbsTime64 stopTime startTime
632 return (cnt, gl, interval `div` fromIntegral cnt)
619 return (cnt, gl, interval `div` fromIntegral cnt)
633 else return (0, 0, 0)
620 else return (0, 0, 0)
@@ -898,7 +885,7 @@ send sv msg = do
898 active <- readIORef (workerCount sv)
885 active <- readIORef (workerCount sv)
899 return $ len < (fromIntegral lim - active)
886 return $ len < (fromIntegral lim - active)
901−workerCollectLatency :: WorkerInfo -> IO (Maybe (Count, NanoSecs))
888+workerCollectLatency :: WorkerInfo -> IO (Maybe (Count, NanoSecond64))
902workerCollectLatency winfo = do
889workerCollectLatency winfo = do
903 (cnt0, t0) <- readIORef (workerLatencyStart winfo)
890 (cnt0, t0) <- readIORef (workerLatencyStart winfo)
904 cnt1 <- readIORef (workerYieldCount winfo)
891 cnt1 <- readIORef (workerYieldCount winfo)
@@ -906,8 +893,8 @@ workerCollectLatency winfo = do
907 if cnt > 0
894 if cnt > 0
909− t1 <- getTime Monotonic
896+ t1 <- getTime
910− let period = fromInteger $ toNanoSecs (t1 - t0)
897+ let period = fromRelTime64 $ diffAbsTime64 t1 t0
911 writeIORef (workerLatencyStart winfo) (cnt1, t1)
898 writeIORef (workerLatencyStart winfo) (cnt1, t1)
912 return $ Just (cnt, period)
899 return $ Just (cnt, period)
913 else return Nothing
900 else return Nothing
@@ -1305,7 +1292,7 @@ pushWorker yieldMax sv = do
1305 Nothing -> return Nothing
1292 Nothing -> return Nothing
1306 Just _ -> liftIO $ do
1293 Just _ -> liftIO $ do
1307 cntRef <- newIORef 0
1294 cntRef <- newIORef 0
1308− t <- getTime Monotonic
1295+ t <- getTime
1309 lat <- newIORef (0, t)
1296 lat <- newIORef (0, t)
1310 return $ Just WorkerInfo
1297 return $ Just WorkerInfo
1311 { workerYieldMax = yieldMax
1298 { workerYieldMax = yieldMax
@@ -1348,7 +1335,7 @@ pushWorkerPar sv wloop =
1348 Nothing -> return Nothing
1335 Nothing -> return Nothing
1349 Just _ -> liftIO $ do
1336 Just _ -> liftIO $ do
1350 cntRef <- newIORef 0
1337 cntRef <- newIORef 0
1351− t <- getTime Monotonic
1338+ t <- getTime
1352 lat <- newIORef (0, t)
1339 lat <- newIORef (0, t)
1353 return $ Just WorkerInfo
1340 return $ Just WorkerInfo
1354 { workerYieldMax = 0
1341 { workerYieldMax = 0
@@ -1420,24 +1407,21 @@ dispatchWorker yieldCount sv = do
1420-- sleep time is accumulated.
1407-- sleep time is accumulated.
1421-- 3. Collected latencies are computed and transferred to measured latency
1408-- 3. Collected latencies are computed and transferred to measured latency
1422-- after a minimum of this period.
1409-- after a minimum of this period.
1423−minThreadDelay :: NanoSecs
1410+minThreadDelay :: NanoSecond64
1424−minThreadDelay = 10^(6 :: Int)
1411+minThreadDelay = 1000000
1426-- | Another magic number! When we have to start more workers to cover up a
1413-- | Another magic number! When we have to start more workers to cover up a
1427-- number of yields that we are lagging by then we cannot start one worker for
1414-- number of yields that we are lagging by then we cannot start one worker for
1428-- each yield because that may be a very big number and if the latency of the
1415-- each yield because that may be a very big number and if the latency of the
1429-- workers is low these number of yields could be very high. We assume that we
1416-- workers is low these number of yields could be very high. We assume that we
1430-- run each extra worker for at least this much time.
1417-- run each extra worker for at least this much time.
1431−rateRecoveryTime :: NanoSecs
1418+rateRecoveryTime :: NanoSecond64
1432rateRecoveryTime = 1000000
1419rateRecoveryTime = 1000000
1434−nanoToMicroSecs :: NanoSecs -> Int
1435−nanoToMicroSecs s = fromIntegral s `div` 1000
1437-- We either block, or send one worker with limited yield count or one or more
1421-- We either block, or send one worker with limited yield count or one or more
1438-- workers with unlimited yield count.
1422-- workers with unlimited yield count.
1439data Work
1423data Work
1440− = BlockWait NanoSecs
1424+ = BlockWait NanoSecond64
1441 | PartialWorker Count
1425 | PartialWorker Count
1442 | ManyWorkers Int Count
1426 | ManyWorkers Int Count
1443 deriving Show
1427 deriving Show
@@ -1447,9 +1431,9 @@ estimateWorkers
1447 :: Limit
1431 :: Limit
1448 -> Count
1432 -> Count
1449 -> Count
1433 -> Count
1450− -> NanoSecs
1434+ -> NanoSecond64
1451− -> NanoSecs
1435+ -> NanoSecond64
1452− -> NanoSecs
1436+ -> NanoSecond64
1453 -> LatencyRange
1437 -> LatencyRange
1455estimateWorkers workerLimit svarYields gainLossYields
1439estimateWorkers workerLimit svarYields gainLossYields
@@ -1500,7 +1484,7 @@ estimateWorkers workerLimit svarYields gainLossYields
1500 fromIntegral rateRecoveryTime
1484 fromIntegral rateRecoveryTime
1501 yieldsFreq = 1.0 / fromIntegral targetLat
1485 yieldsFreq = 1.0 / fromIntegral targetLat
1502 totalYieldsFreq = yieldsFreq + deltaYieldsFreq
1486 totalYieldsFreq = yieldsFreq + deltaYieldsFreq
1503− requiredLat = NanoSecs $ round $ 1.0 / totalYieldsFreq
1487+ requiredLat = NanoSecond64 $ round $ 1.0 / totalYieldsFreq
1504 adjustedLat = min (max requiredLat (minLatency range))
1488 adjustedLat = min (max requiredLat (minLatency range))
1505 (maxLatency range)
1489 (maxLatency range)
1506 in assert (adjustedLat > 0) $
1490 in assert (adjustedLat > 0) $
@@ -1527,7 +1511,7 @@ estimateWorkers workerLimit svarYields gainLossYields
1527-- | Get the worker latency without resetting workerPendingLatency
1511-- | Get the worker latency without resetting workerPendingLatency
1528-- Returns (total yield count, base time, measured latency)
1512-- Returns (total yield count, base time, measured latency)
1529-- CAUTION! keep it in sync with collectLatency
1513-- CAUTION! keep it in sync with collectLatency
1530−getWorkerLatency :: YieldRateInfo -> IO (Count, TimeSpec, NanoSecs)
1514+getWorkerLatency :: YieldRateInfo -> IO (Count, AbsTime, NanoSecond64)
1531getWorkerLatency yinfo = do
1515getWorkerLatency yinfo = do
1532 let cur = workerPendingLatency yinfo
1516 let cur = workerPendingLatency yinfo
1533 col = workerCollectedLatency yinfo
1517 col = workerCollectedLatency yinfo
@@ -1552,8 +1536,8 @@ getWorkerLatency yinfo = do
1552isBeyondMaxRate :: SVar t m a -> YieldRateInfo -> IO Bool
1536isBeyondMaxRate :: SVar t m a -> YieldRateInfo -> IO Bool
1553isBeyondMaxRate sv yinfo = do
1537isBeyondMaxRate sv yinfo = do
1554 (count, tstamp, wLatency) <- getWorkerLatency yinfo
1538 (count, tstamp, wLatency) <- getWorkerLatency yinfo
1555− now <- getTime Monotonic
1539+ now <- getTime
1556− let duration = fromInteger $ toNanoSecs $ now - tstamp
1540+ let duration = fromRelTime64 $ diffAbsTime64 now tstamp
1557 let targetLat = svarLatencyTarget yinfo
1541 let targetLat = svarLatencyTarget yinfo
1558 gainLoss <- readIORef (svarGainedLostYields yinfo)
1542 gainLoss <- readIORef (svarGainedLostYields yinfo)
1559 let work = estimateWorkers (maxWorkerLimit sv) count gainLoss duration
1543 let work = estimateWorkers (maxWorkerLimit sv) count gainLoss duration
@@ -1575,7 +1559,7 @@ isBeyondMaxRate sv yinfo = do
1575-- value is updated an existing worker must check it again on the next yield.
1559-- value is updated an existing worker must check it again on the next yield.
1576-- Otherwise it is possible that we may keep updating it and because of the mod
1560-- Otherwise it is possible that we may keep updating it and because of the mod
1577-- worker keeps skipping it.
1561-- worker keeps skipping it.
1578−updateWorkerPollingInterval :: YieldRateInfo -> NanoSecs -> IO ()
1562+updateWorkerPollingInterval :: YieldRateInfo -> NanoSecond64 -> IO ()
1579updateWorkerPollingInterval yinfo latency = do
1563updateWorkerPollingInterval yinfo latency = do
1580 let periodRef = workerPollingInterval yinfo
1564 let periodRef = workerPollingInterval yinfo
1581 cnt = max 1 $ minThreadDelay `div` latency
1565 cnt = max 1 $ minThreadDelay `div` latency
@@ -1589,7 +1573,7 @@ updateWorkerPollingInterval yinfo latency = do
1589-- whereas the average is used for future estimates e.g. how many workers
1573-- whereas the average is used for future estimates e.g. how many workers
1590-- should be maintained to maintain the rate.
1574-- should be maintained to maintain the rate.
1591-- CAUTION! keep it in sync with getWorkerLatency
1575-- CAUTION! keep it in sync with getWorkerLatency
1592−collectLatency :: SVar t m a -> YieldRateInfo -> IO (Count, TimeSpec, NanoSecs)
1576+collectLatency :: SVar t m a -> YieldRateInfo -> IO (Count, AbsTime, NanoSecond64)
1593collectLatency sv yinfo = do
1577collectLatency sv yinfo = do
1594 let cur = workerPendingLatency yinfo
1578 let cur = workerPendingLatency yinfo
1595 col = workerCollectedLatency yinfo
1579 col = workerCollectedLatency yinfo
@@ -1653,10 +1637,10 @@ dispatchWorkerPaced :: MonadAsync m => SVar t m a -> m Bool
1653dispatchWorkerPaced sv = do
1637dispatchWorkerPaced sv = do
1654 let yinfo = fromJust $ yieldRateInfo sv
1638 let yinfo = fromJust $ yieldRateInfo sv
1655 (svarYields, svarElapsed, wLatency) <- do
1639 (svarYields, svarElapsed, wLatency) <- do
1656− now <- liftIO $ getTime Monotonic
1640+ now <- liftIO $ getTime
1657 (yieldCount, baseTime, lat) <-
1641 (yieldCount, baseTime, lat) <-
1658 liftIO $ collectLatency sv yinfo
1642 liftIO $ collectLatency sv yinfo
1659− let elapsed = fromInteger $ toNanoSecs $ now - baseTime
1643+ let elapsed = fromRelTime64 $ diffAbsTime64 now baseTime
1660 let latency =
1644 let latency =
1661 if lat == 0
1645 if lat == 0
@@ -1698,7 +1682,8 @@ dispatchWorkerPaced sv = do
1698 -- still have a Stop event waiting in the outputQueue.
1682 -- still have a Stop event waiting in the outputQueue.
1699 done <- allThreadsDone sv
1683 done <- allThreadsDone sv
1700 when done $ void $ do
1684 when done $ void $ do
1685+ let us = fromRelTime64 (toRelTime64 s) :: MicroSecond64
1701− liftIO $ threadDelay $ nanoToMicroSecs s
1686+ liftIO $ threadDelay (fromIntegral us)
1702 dispatchWorker 1 sv
1687 dispatchWorker 1 sv
1703 return False
1688 return False
1704 PartialWorker yields -> do
1689 PartialWorker yields -> do
@@ -1974,7 +1959,7 @@ getYieldRateInfo st = do
1974 measured <- newIORef 0
1959 measured <- newIORef 0
1975 wcur <- newIORef (0,0)
1960 wcur <- newIORef (0,0)
1976 wcol <- newIORef (0,0)
1961 wcol <- newIORef (0,0)
1977− now <- getTime Monotonic
1962+ now <- getTime
1978 wlong <- newIORef (0,now)
1963 wlong <- newIORef (0,now)
1979 period <- newIORef 1
1964 period <- newIORef 1
1980 gainLoss <- newIORef (Count 0)
1965 gainLoss <- newIORef (Count 0)
@@ -1999,9 +1984,9 @@ newSVarStats = do
1999 maxOq <- newIORef 0
1984 maxOq <- newIORef 0
2000 maxHs <- newIORef 0
1985 maxHs <- newIORef 0
2001 maxWq <- newIORef 0
1986 maxWq <- newIORef 0
2002− avgLat <- newIORef (0, NanoSecs 0)
1987+ avgLat <- newIORef (0, NanoSecond64 0)
2003− maxLat <- newIORef (NanoSecs 0)
1988+ maxLat <- newIORef (NanoSecond64 0)
2004− minLat <- newIORef (NanoSecs 0)
1989+ minLat <- newIORef (NanoSecond64 0)
2005 stpTime <- newIORef Nothing
1990 stpTime <- newIORef Nothing
2007 return SVarStats
1992 return SVarStats