@@ -19,11 +19,6 @@
19-- Maintainer : harendra.kumar@gmail.com
19-- Maintainer : harendra.kumar@gmail.com
20-- Stability : experimental
20-- Stability : experimental
21-- Portability : GHC
21-- Portability : GHC
24−#ifdef DIAGNOSTICS_VERBOSE
28module Streamly.SVar
23module Streamly.SVar
@@ -45,6 +40,8 @@ module Streamly.SVar
45 , setStreamLatency
40 , setStreamLatency
46 , getYieldLimit
41 , getYieldLimit
47 , setYieldLimit
42 , setYieldLimit
49 , cleanupSVar
46 , cleanupSVar
50 , cleanupSVarFromWorker
47 , cleanupSVarFromWorker
@@ -99,17 +96,18 @@ module Streamly.SVar
99 , toStreamVar
96 , toStreamVar
100 , SVarStats (..)
97 , SVarStats (..)
101 , NanoSecs (..)
98 , NanoSecs (..)
103 , dumpSVar
99 , dumpSVar
108import Control.Concurrent
103import Control.Concurrent
109 (ThreadId, myThreadId, threadDelay, throwTo)
104 (ThreadId, myThreadId, threadDelay, throwTo)
110import Control.Concurrent.MVar
105import Control.Concurrent.MVar
111− (MVar, newEmptyMVar, tryPutMVar, takeMVar, newMVar)
106+ (MVar, newEmptyMVar, tryPutMVar, takeMVar, newMVar, tryReadMVar)
107+import Control.Exception
112−import Control.Exception (SomeException(..), catch, mask, assert, Exception)
108+ (SomeException(..), catch, mask, assert, Exception, catches,
109+ throwIO, Handler(..), BlockedIndefinitelyOnMVar(..),
110+ BlockedIndefinitelyOnSTM(..))
113import Control.Monad (when)
111import Control.Monad (when)
114import Control.Monad.Catch (MonadThrow)
112import Control.Monad.Catch (MonadThrow)
115import Control.Monad.IO.Class (MonadIO(..))
113import Control.Monad.IO.Class (MonadIO(..))
@@ -130,24 +128,12 @@ import GHC.Conc (ThreadId(..))
130import GHC.Exts
128import GHC.Exts
131import GHC.IO (IO(..))
129import GHC.IO (IO(..))
132import System.Clock (TimeSpec, Clock(Monotonic), getTime, toNanoSecs)
130import System.Clock (TimeSpec, Clock(Monotonic), getTime, toNanoSecs)
131+import System.IO (hPutStrLn, stderr)
132+import Text.Printf (printf)
134import qualified Data.Heap as H
134import qualified Data.Heap as H
135import qualified Data.Set as S
135import qualified Data.Set as S
137−-- MVar diagnostics has some overhead - around 5% on asyncly null benchmark, we
138−-- can keep it on in production to debug problems quickly if and when they
139−-- happen, but it may result in unexpected output when threads are left hanging
140−-- until they are GCed because the consumer went away.
143−import Control.Concurrent.MVar (tryTakeMVar)
144−import Control.Exception
145− (catches, throwIO, Handler(..), BlockedIndefinitelyOnMVar(..),
146− BlockedIndefinitelyOnSTM(..))
147−import System.IO (hPutStrLn, stderr)
148−import Text.Printf (printf)
151-- Always use signed arithmetic to avoid inadvertant overflows of signed values
137-- Always use signed arithmetic to avoid inadvertant overflows of signed values
152-- on conversion when comparing unsigned quantities with signed.
138-- on conversion when comparing unsigned quantities with signed.
153newtype NanoSecs = NanoSecs Int64
139newtype NanoSecs = NanoSecs Int64
@@ -371,13 +357,14 @@ data SVar t m a = SVar
371 , svarStats :: SVarStats
357 , svarStats :: SVarStats
372 -- to track garbage collection of SVar
358 -- to track garbage collection of SVar
373 , svarRef :: Maybe (IORef ())
359 , svarRef :: Maybe (IORef ())
374−#ifdef DIAGNOSTICS
360+
361+ -- Only for diagnostics
362+ , svarInspectMode :: Bool
375 , svarCreator :: ThreadId
363 , svarCreator :: ThreadId
376 , outputHeap :: IORef ( Heap (Entry Int (AheadHeapEntry t m a))
364 , outputHeap :: IORef ( Heap (Entry Int (AheadHeapEntry t m a))
377 , Maybe Int)
365 , Maybe Int)
378 -- Shared work queue (stream, seqNo)
366 -- Shared work queue (stream, seqNo)
379 , aheadWorkQueue :: IORef ([t m a], Int)
367 , aheadWorkQueue :: IORef ([t m a], Int)
383-------------------------------------------------------------------------------
370-------------------------------------------------------------------------------
@@ -401,6 +388,7 @@ data State t m a = State
401 -- XXX these two can be collapsed into a single type
388 -- XXX these two can be collapsed into a single type
402 , _streamLatency :: Maybe NanoSecs -- bootstrap latency
389 , _streamLatency :: Maybe NanoSecs -- bootstrap latency
403 , _maxStreamRate :: Maybe Rate
390 , _maxStreamRate :: Maybe Rate
391+ , _inspectMode :: Bool
406-------------------------------------------------------------------------------
394-------------------------------------------------------------------------------
@@ -428,6 +416,7 @@ defState = State
428 , _bufferHigh = defaultMaxBuffer
416 , _bufferHigh = defaultMaxBuffer
429 , _maxStreamRate = Nothing
417 , _maxStreamRate = Nothing
430 , _streamLatency = Nothing
418 , _streamLatency = Nothing
419+ , _inspectMode = False
433-- XXX if perf gets affected we can have all the Nothing params in a single
422-- XXX if perf gets affected we can have all the Nothing params in a single
@@ -505,6 +494,12 @@ setStreamLatency n st =
505getStreamLatency :: State t m a -> Maybe NanoSecs
494getStreamLatency :: State t m a -> Maybe NanoSecs
506getStreamLatency = _streamLatency
495getStreamLatency = _streamLatency
497+setInspectMode :: State t m a -> State t m a
498+setInspectMode st = st { _inspectMode = True }
500+getInspectMode :: State t m a -> Bool
501+getInspectMode = _inspectMode
508-------------------------------------------------------------------------------
503-------------------------------------------------------------------------------
509-- Cleanup
504-- Cleanup
510-------------------------------------------------------------------------------
505-------------------------------------------------------------------------------
@@ -526,7 +521,6 @@ cleanupSVarFromWorker sv = do
526-- Dumping the SVar for debug/diag
521-- Dumping the SVar for debug/diag
527-------------------------------------------------------------------------------
522-------------------------------------------------------------------------------
530-- | Convert a number of seconds to a string. The string will consist
524-- | Convert a number of seconds to a string. The string will consist
531-- of four decimal places, followed by a short description of the time
525-- of four decimal places, followed by a short description of the time
@@ -553,8 +547,8 @@ secs k
553 | otherwise = printf "%.3f %s" t u
547 | otherwise = printf "%.3f %s" t u
555-- XXX Code duplicated from collectLatency
549-- XXX Code duplicated from collectLatency
556−drainLatency :: SVarStats -> YieldRateInfo -> IO (Count, TimeSpec, NanoSecs)
550+drainLatency :: SVar t m a -> YieldRateInfo -> IO (Count, TimeSpec, NanoSecs)
557−drainLatency _ss yinfo = do
551+drainLatency sv yinfo = do
558 let cur = workerPendingLatency yinfo
552 let cur = workerPendingLatency yinfo
559 col = workerCollectedLatency yinfo
553 col = workerCollectedLatency yinfo
560 longTerm = svarAllTimeLatency yinfo
554 longTerm = svarAllTimeLatency yinfo
@@ -574,21 +568,19 @@ drainLatency _ss yinfo = do
574 if (pendingCount > 0)
568 if (pendingCount > 0)
576 let new = pendingTime `div` (fromIntegral pendingCount)
570 let new = pendingTime `div` (fromIntegral pendingCount)
577−#ifdef DIAGNOSTICS
571+ when (svarInspectMode sv) $ do
572+ let ss = svarStats sv
578− minLat <- readIORef (minWorkerLatency _ss)
573+ minLat <- readIORef (minWorkerLatency ss)
579− when (new < minLat || minLat == 0) $
574+ when (new < minLat || minLat == 0) $
580− writeIORef (minWorkerLatency _ss) new
575+ writeIORef (minWorkerLatency ss) new
582− maxLat <- readIORef (maxWorkerLatency _ss)
577+ maxLat <- readIORef (maxWorkerLatency ss)
583− when (new > maxLat) $ writeIORef (maxWorkerLatency _ss) new
578+ when (new > maxLat) $ writeIORef (maxWorkerLatency ss) new
584−#endif
579+ modifyIORef (avgWorkerLatency ss) $
580+ \(cnt, t) -> (cnt + pendingCount, t + pendingTime)
585 -- To avoid minor fluctuations update in batches
581 -- To avoid minor fluctuations update in batches
586 writeIORef col (0, 0)
582 writeIORef col (0, 0)
587 writeIORef measured new
583 writeIORef measured new
589− modifyIORef (avgWorkerLatency _ss) $
590− \(cnt, t) -> (cnt + pendingCount, t + pendingTime)
592 modifyIORef longTerm $ \(_, t) -> (lcount', t)
584 modifyIORef longTerm $ \(_, t) -> (lcount', t)
593 return (lcount', ltime, new)
585 return (lcount', ltime, new)
594 else return notUpdated
586 else return notUpdated
@@ -598,7 +590,7 @@ dumpSVarStats sv ss style = do
598 case yieldRateInfo sv of
590 case yieldRateInfo sv of
599 Nothing -> return ()
591 Nothing -> return ()
600 Just yinfo -> do
592 Just yinfo -> do
601− _ <- liftIO $ drainLatency (svarStats sv) yinfo
593+ _ <- liftIO $ drainLatency sv yinfo
602 return ()
594 return ()
604 dispatches <- readIORef $ totalDispatches ss
596 dispatches <- readIORef $ totalDispatches ss
@@ -662,7 +654,7 @@ dumpSVarStats sv ss style = do
662dumpSVar :: SVar t m a -> IO String
654dumpSVar :: SVar t m a -> IO String
663dumpSVar sv = do
655dumpSVar sv = do
664 (oqList, oqLen) <- readIORef $ outputQueue sv
656 (oqList, oqLen) <- readIORef $ outputQueue sv
665− db <- tryTakeMVar $ outputDoorBell sv
657+ db <- tryReadMVar $ outputDoorBell sv
666 aheadDump <-
658 aheadDump <-
667 if svarStyle sv == AheadVar
659 if svarStyle sv == AheadVar
@@ -686,15 +678,17 @@ dumpSVar sv = do
686 stats <- dumpSVarStats sv (svarStats sv) (svarStyle sv)
678 stats <- dumpSVarStats sv (svarStats sv) (svarStyle sv)
688 return $ unlines
680 return $ unlines
689− [ "Creator tid = " ++ show (svarCreator sv)
682+ "Creator tid = " ++ show (svarCreator sv),
690− , "style = " ++ show (svarStyle sv)
683+ "style = " ++ show (svarStyle sv)
691 , "---------CURRENT STATE-----------"
684 , "---------CURRENT STATE-----------"
692 , "outputQueue length computed = " ++ show (length oqList)
685 , "outputQueue length computed = " ++ show (length oqList)
693 , "outputQueue length maintained = " ++ show oqLen
686 , "outputQueue length maintained = " ++ show oqLen
694 -- XXX print the types of events in the outputQueue, first 5
687 -- XXX print the types of events in the outputQueue, first 5
695 , "outputDoorBell = " ++ show db
688 , "outputDoorBell = " ++ show db
697− ++ aheadDump ++ unlines
690+ ++ aheadDump
698 [ "needDoorBell = " ++ show waiting
692 [ "needDoorBell = " ++ show waiting
699 , "running threads = " ++ show rthread
693 , "running threads = " ++ show rthread
700 -- XXX print the status of first 5 threads
694 -- XXX print the status of first 5 threads
@@ -703,6 +697,11 @@ dumpSVar sv = do
703 ++ "---------STATS-----------\n"
697 ++ "---------STATS-----------\n"
700+-- MVar diagnostics has some overhead - around 5% on asyncly null benchmark, we
701+-- can keep it on in production to debug problems quickly if and when they
702+-- happen, but it may result in unexpected output when threads are left hanging
703+-- until they are GCed because the consumer went away.
706{-# NOINLINE mvarExcHandler #-}
705{-# NOINLINE mvarExcHandler #-}
707mvarExcHandler :: SVar t m a -> String -> BlockedIndefinitelyOnMVar -> IO ()
706mvarExcHandler :: SVar t m a -> String -> BlockedIndefinitelyOnMVar -> IO ()
708mvarExcHandler sv label e@BlockedIndefinitelyOnMVar = do
707mvarExcHandler sv label e@BlockedIndefinitelyOnMVar = do
@@ -717,15 +716,14 @@ stmExcHandler sv label e@BlockedIndefinitelyOnSTM = do
717 hPutStrLn stderr $ label ++ " " ++ "BlockedIndefinitelyOnSTM\n" ++ svInfo
716 hPutStrLn stderr $ label ++ " " ++ "BlockedIndefinitelyOnSTM\n" ++ svInfo
718 throwIO e
717 throwIO e
720−withDBGMVar :: SVar t m a -> String -> IO () -> IO ()
719+withDiagMVar :: SVar t m a -> String -> IO () -> IO ()
721−withDBGMVar sv label action =
720+withDiagMVar sv label action =
721+ if svarInspectMode sv
722− action `catches` [ Handler (mvarExcHandler sv label)
723+ action `catches` [ Handler (mvarExcHandler sv label)
723− , Handler (stmExcHandler sv label)
724+ , Handler (stmExcHandler sv label)
725−#else
726+ else action
726−withDBGMVar :: SVar t m a -> String -> IO () -> IO ()
727−withDBGMVar _ _ action = action
730-------------------------------------------------------------------------------
728-------------------------------------------------------------------------------
@@ -1248,22 +1246,19 @@ handleChildException sv e = do
1248 tid <- myThreadId
1246 tid <- myThreadId
1249 void $ send sv (ChildStop tid (Just e))
1247 void $ send sv (ChildStop tid (Just e))
1251−#ifdef DIAGNOSTICS
1249+{-# NOINLINE recordMaxWorkers #-}
1252recordMaxWorkers :: MonadIO m => SVar t m a -> m ()
1250recordMaxWorkers :: MonadIO m => SVar t m a -> m ()
1253recordMaxWorkers sv = liftIO $ do
1251recordMaxWorkers sv = liftIO $ do
1254 active <- readIORef (workerCount sv)
1252 active <- readIORef (workerCount sv)
1255 maxWrk <- readIORef (maxWorkers $ svarStats sv)
1253 maxWrk <- readIORef (maxWorkers $ svarStats sv)
1256 when (active > maxWrk) $ writeIORef (maxWorkers $ svarStats sv) active
1254 when (active > maxWrk) $ writeIORef (maxWorkers $ svarStats sv) active
1257 modifyIORef (totalDispatches $ svarStats sv) (+1)
1255 modifyIORef (totalDispatches $ svarStats sv) (+1)
1260{-# NOINLINE pushWorker #-}
1257{-# NOINLINE pushWorker #-}
1261pushWorker :: MonadAsync m => Count -> SVar t m a -> m ()
1258pushWorker :: MonadAsync m => Count -> SVar t m a -> m ()
1262pushWorker yieldMax sv = do
1259pushWorker yieldMax sv = do
1263 liftIO $ atomicModifyIORefCAS_ (workerCount sv) $ \n -> n + 1
1260 liftIO $ atomicModifyIORefCAS_ (workerCount sv) $ \n -> n + 1
1265− recordMaxWorkers sv
1261+ when (svarInspectMode sv) $ recordMaxWorkers sv
1267 -- This allocation matters when significant number of workers are being
1262 -- This allocation matters when significant number of workers are being
1268 -- sent. We allocate it only when needed.
1263 -- sent. We allocate it only when needed.
1269 winfo <-
1264 winfo <-
@@ -1288,34 +1283,39 @@ pushWorker yieldMax sv = do
1288-- producer side. So we need to use a thread safe modification of
1283-- producer side. So we need to use a thread safe modification of
1289-- workerThreads. Alternatively, we can use a CreateThread event to avoid
1284-- workerThreads. Alternatively, we can use a CreateThread event to avoid
1290-- using a CAS based modification.
1285-- using a CAS based modification.
1291−{-# NOINLINE pushWorkerPar #-}
1286+{-# INLINE pushWorkerPar #-}
1292−pushWorkerPar :: MonadAsync m => SVar t m a -> (Maybe WorkerInfo -> m ()) -> m ()
1289+ => SVar t m a -> (Maybe WorkerInfo -> m ()) -> m ()
1293pushWorkerPar sv wloop =
1290pushWorkerPar sv wloop =
1294− -- We do not use workerCount in case of ParallelVar but still there is no
1291+ if svarInspectMode sv
1295− -- harm in maintaining it correctly.
1292+ then forkWithDiag
1296−#ifdef DIAGNOSTICS
1293+ else doFork (wloop Nothing) (handleChildException sv) >>= modifyThread sv
1298− liftIO $ atomicModifyIORefCAS_ (workerCount sv) $ \n -> n + 1
1299− recordMaxWorkers sv
1300− -- This allocation matters when significant number of workers are being
1301− -- sent. We allocate it only when needed. The overhead increases by 4x.
1303− case yieldRateInfo sv of
1304− Nothing -> return Nothing
1305− Just _ -> liftIO $ do
1306− cntRef <- newIORef 0
1307− t <- getTime Monotonic
1308− lat <- newIORef (0, t)
1309− return $ Just $ WorkerInfo
1310− { workerYieldMax = 0
1311− , workerYieldCount = cntRef
1312− , workerLatencyStart = lat
1315− doFork (wloop winfo) (handleChildException sv) >>= modifyThread sv
1295+ where
1297+ {-# NOINLINE forkWithDiag #-}
1299+ -- We do not use workerCount in case of ParallelVar but still there is
1300+ -- no harm in maintaining it correctly.
1301+ liftIO $ atomicModifyIORefCAS_ (workerCount sv) $ \n -> n + 1
1302+ recordMaxWorkers sv
1303+ -- This allocation matters when significant number of workers are being
1304+ -- sent. We allocate it only when needed. The overhead increases by 4x.
1306+ case yieldRateInfo sv of
1307+ Nothing -> return Nothing
1308+ Just _ -> liftIO $ do
1309+ cntRef <- newIORef 0
1310+ t <- getTime Monotonic
1311+ lat <- newIORef (0, t)
1312+ return $ Just $ WorkerInfo
1313+ { workerYieldMax = 0
1314+ , workerYieldCount = cntRef
1315+ , workerLatencyStart = lat
1317− doFork (wloop Nothing) (handleChildException sv) >>= modifyThread sv
1318+ doFork (wloop winfo) (handleChildException sv) >>= modifyThread sv
1320-- Returns:
1320-- Returns:
1321-- True: can dispatch more
1321-- True: can dispatch more
@@ -1547,8 +1547,8 @@ updateWorkerPollingInterval yinfo latency = do
1547-- whereas the average is used for future estimates e.g. how many workers
1547-- whereas the average is used for future estimates e.g. how many workers
1548-- should be maintained to maintain the rate.
1548-- should be maintained to maintain the rate.
1549-- CAUTION! keep it in sync with getWorkerLatency
1549-- CAUTION! keep it in sync with getWorkerLatency
1550−collectLatency :: SVarStats -> YieldRateInfo -> IO (Count, TimeSpec, NanoSecs)
1550+collectLatency :: SVar t m a -> YieldRateInfo -> IO (Count, TimeSpec, NanoSecs)
1551−collectLatency _ss yinfo = do
1551+collectLatency sv yinfo = do
1552 let cur = workerPendingLatency yinfo
1552 let cur = workerPendingLatency yinfo
1553 col = workerCollectedLatency yinfo
1553 col = workerCollectedLatency yinfo
1554 longTerm = svarAllTimeLatency yinfo
1554 longTerm = svarAllTimeLatency yinfo
@@ -1567,15 +1567,15 @@ collectLatency _ss yinfo = do
1568 if pendingCount > 0
1568 if pendingCount > 0
1570− let new = pendingTime `div` fromIntegral pendingCount
1570+ let new = pendingTime `div` (fromIntegral pendingCount)
1571−#ifdef DIAGNOSTICS
1571+ when (svarInspectMode sv) $ do
1572+ let ss = svarStats sv
1572− minLat <- readIORef (minWorkerLatency _ss)
1573+ minLat <- readIORef (minWorkerLatency ss)
1573− when (new < minLat || minLat == 0) $
1574+ when (new < minLat || minLat == 0) $
1574− writeIORef (minWorkerLatency _ss) new
1575+ writeIORef (minWorkerLatency ss) new
1576− maxLat <- readIORef (maxWorkerLatency _ss)
1577+ maxLat <- readIORef (maxWorkerLatency ss)
1577− when (new > maxLat) $ writeIORef (maxWorkerLatency _ss) new
1578+ when (new > maxLat) $ writeIORef (maxWorkerLatency ss) new
1579 -- When we have collected a significant sized batch we compute the new
1579 -- When we have collected a significant sized batch we compute the new
1580 -- latency using that batch and return the new latency, otherwise we
1580 -- latency using that batch and return the new latency, otherwise we
1581 -- return the previous latency derived from the previous batch.
1581 -- return the previous latency derived from the previous batch.
@@ -1585,13 +1585,13 @@ collectLatency _ss yinfo = do
1585 in prev > 0 && (r > 2 || r < 0.5))
1585 in prev > 0 && (r > 2 || r < 0.5))
1586 || (prev == 0)
1586 || (prev == 0)
1588+ when (svarInspectMode sv) $ do
1589+ let ss = svarStats sv
1590+ modifyIORef (avgWorkerLatency ss) $
1591+ \(cnt, t) -> (cnt + pendingCount, t + pendingTime)
1588 updateWorkerPollingInterval yinfo (max new prev)
1592 updateWorkerPollingInterval yinfo (max new prev)
1589 writeIORef col (0, 0)
1593 writeIORef col (0, 0)
1590 writeIORef measured ((prev + new) `div` 2)
1594 writeIORef measured ((prev + new) `div` 2)
1592− modifyIORef (avgWorkerLatency _ss) $
1593− \(cnt, t) -> (cnt + pendingCount, t + pendingTime)
1595 modifyIORef longTerm $ \(_, t) -> (lcount', t)
1595 modifyIORef longTerm $ \(_, t) -> (lcount', t)
1596 return $ tripleWith new
1596 return $ tripleWith new
@@ -1613,7 +1613,7 @@ dispatchWorkerPaced sv = do
1613 (svarYields, svarElapsed, wLatency) <- do
1613 (svarYields, svarElapsed, wLatency) <- do
1614 now <- liftIO $ getTime Monotonic
1614 now <- liftIO $ getTime Monotonic
1615 (yieldCount, baseTime, lat) <-
1615 (yieldCount, baseTime, lat) <-
1616− liftIO $ collectLatency (svarStats sv) yinfo
1616+ liftIO $ collectLatency sv yinfo
1617 let elapsed = fromInteger $ toNanoSecs $ now - baseTime
1617 let elapsed = fromInteger $ toNanoSecs $ now - baseTime
1618 let latency =
1618 let latency =
1619 if lat == 0
1619 if lat == 0
@@ -1811,7 +1811,7 @@ sendWorkerWait delay dispatch sv = do
1811 if canDoMore
1811 if canDoMore
1812 then sendWorkerWait delay dispatch sv
1812 then sendWorkerWait delay dispatch sv
1814− liftIO $ withDBGMVar sv "sendWorkerWait: nothing to do"
1814+ liftIO $ withDiagMVar sv "sendWorkerWait: nothing to do"
1815 $ takeMVar (outputDoorBell sv)
1815 $ takeMVar (outputDoorBell sv)
1816 (_, len) <- liftIO $ readIORef (outputQueue sv)
1816 (_, len) <- liftIO $ readIORef (outputQueue sv)
1817 when (len <= 0) $ sendWorkerWait delay dispatch sv
1817 when (len <= 0) $ sendWorkerWait delay dispatch sv
@@ -1820,10 +1820,10 @@ sendWorkerWait delay dispatch sv = do
1820readOutputQRaw :: SVar t m a -> IO ([ChildEvent a], Int)
1820readOutputQRaw :: SVar t m a -> IO ([ChildEvent a], Int)
1821readOutputQRaw sv = do
1821readOutputQRaw sv = do
1822 (list, len) <- atomicModifyIORefCAS (outputQueue sv) $ \x -> (([],0), x)
1822 (list, len) <- atomicModifyIORefCAS (outputQueue sv) $ \x -> (([],0), x)
1823−#ifdef DIAGNOSTICS
1823+ when (svarInspectMode sv) $ do
1824+ let ref = maxOutQSize $ svarStats sv
1824− oqLen <- readIORef (maxOutQSize $ svarStats sv)
1825+ oqLen <- readIORef ref
1825− when (len > oqLen) $ writeIORef (maxOutQSize $ svarStats sv) len
1826+ when (len > oqLen) $ writeIORef ref len
1827 return (list, len)
1827 return (list, len)
1829readOutputQBounded :: MonadAsync m => SVar t m a -> m [ChildEvent a]
1829readOutputQBounded :: MonadAsync m => SVar t m a -> m [ChildEvent a]
@@ -1985,9 +1985,7 @@ getAheadSVar st f = do
1985 maxLat <- newIORef (NanoSecs 0)
1985 maxLat <- newIORef (NanoSecs 0)
1986 minLat <- newIORef (NanoSecs 0)
1986 minLat <- newIORef (NanoSecs 0)
1987 stpTime <- newIORef Nothing
1987 stpTime <- newIORef Nothing
1989 tid <- myThreadId
1988 tid <- myThreadId
1992 let getSVar sv readOutput postProc = SVar
1990 let getSVar sv readOutput postProc = SVar
1993 { outputQueue = outQ
1991 { outputQueue = outQ
@@ -2009,11 +2007,10 @@ getAheadSVar st f = do
2009 , accountThread = delThread sv
2007 , accountThread = delThread sv
2010 , workerStopMVar = stopMVar
2008 , workerStopMVar = stopMVar
2011 , svarRef = Nothing
2009 , svarRef = Nothing
2012−#ifdef DIAGNOSTICS
2010+ , svarInspectMode = getInspectMode st
2013 , svarCreator = tid
2011 , svarCreator = tid
2014 , aheadWorkQueue = q
2012 , aheadWorkQueue = q
2015 , outputHeap = outH
2013 , outputHeap = outH
2017 , svarStats = SVarStats
2014 , svarStats = SVarStats
2018 { totalDispatches = disp
2015 { totalDispatches = disp
2019 , maxWorkers = maxWrk
2016 , maxWorkers = maxWrk
@@ -2081,9 +2078,7 @@ getParallelSVar st = do
2081 maxLat <- newIORef (NanoSecs 0)
2078 maxLat <- newIORef (NanoSecs 0)
2082 minLat <- newIORef (NanoSecs 0)
2079 minLat <- newIORef (NanoSecs 0)
2083 stpTime <- newIORef Nothing
2080 stpTime <- newIORef Nothing
2085 tid <- myThreadId
2081 tid <- myThreadId
2088 let sv =
2083 let sv =
2089 SVar { outputQueue = outQ
2084 SVar { outputQueue = outQ
@@ -2106,11 +2101,10 @@ getParallelSVar st = do
2106 , accountThread = modifyThread sv
2101 , accountThread = modifyThread sv
2107 , workerStopMVar = undefined
2102 , workerStopMVar = undefined
2108 , svarRef = Nothing
2103 , svarRef = Nothing
2109−#ifdef DIAGNOSTICS
2104+ , svarInspectMode = getInspectMode st
2110 , svarCreator = tid
2105 , svarCreator = tid
2111 , aheadWorkQueue = undefined
2106 , aheadWorkQueue = undefined
2112 , outputHeap = undefined
2107 , outputHeap = undefined
2114 , svarStats = SVarStats
2108 , svarStats = SVarStats
2115 { totalDispatches = disp
2109 { totalDispatches = disp
2116 , maxWorkers = maxWrk
2110 , maxWorkers = maxWrk
@@ -2128,10 +2122,11 @@ getParallelSVar st = do
2130 readOutputQPar sv = liftIO $ do
2124 readOutputQPar sv = liftIO $ do
2125+ withDiagMVar sv "readOutputQPar: doorbell"
2131− withDBGMVar sv "readOutputQPar: doorbell" $ takeMVar (outputDoorBell sv)
2126+ $ takeMVar (outputDoorBell sv)
2132 case yieldRateInfo sv of
2127 case yieldRateInfo sv of
2133 Nothing -> return ()
2128 Nothing -> return ()
2134− Just yinfo -> void $ collectLatency (svarStats sv) yinfo
2129+ Just yinfo -> void $ collectLatency sv yinfo
2135 fst `fmap` readOutputQRaw sv
2130 fst `fmap` readOutputQRaw sv
2137sendFirstWorker :: MonadAsync m => SVar t m a -> t m a -> m (SVar t m a)
2132sendFirstWorker :: MonadAsync m => SVar t m a -> t m a -> m (SVar t m a)