@@ -496,11 +496,9 @@ getStreamRate = _maxStreamRate
496496setStreamLatency :: Int -> State t m a -> State t m a
497497setStreamLatency n st =
498498 st { _streamLatency =
499− if n < 0
499+ if n <= 0
500500 then Nothing
501− else if n == 0
502− then Nothing
503− else Just (fromIntegral n)
501+ else Just (fromIntegral n)
504502 }
505503
506504getStreamLatency :: State t m a -> Maybe NanoSecs
@@ -513,14 +511,14 @@ getStreamLatency = _streamLatency
513511cleanupSVar :: SVar t m a -> IO ()
514512cleanupSVar sv = do
515513 workers <- readIORef (workerThreads sv)
516− Prelude.mapM_ (\tid -> throwTo tid ThreadAbort)
514+ Prelude.mapM_ (`throwTo` ThreadAbort)
517515 (S.toList workers)
518516
519517cleanupSVarFromWorker :: SVar t m a -> IO ()
520518cleanupSVarFromWorker sv = do
521519 workers <- readIORef (workerThreads sv)
522520 self <- myThreadId
523− mapM_ (\tid -> throwTo tid ThreadAbort)
521+ mapM_ (`throwTo` ThreadAbort)
524522 (S.toList workers \\ [self])
525523
526524-------------------------------------------------------------------------------
@@ -751,6 +749,21 @@ atomicModifyIORefCAS ref fn = do
751749 then return result
752750 else loop tkt (tries - 1)
753751
752+{-# INLINE ringDoorBell #-}
753+ringDoorBell :: SVar t m a -> IO ()
754+ringDoorBell sv = do
755+ storeLoadBarrier
756+ w <- readIORef $ needDoorBell sv
757+ when w $ do
758+ -- Note: the sequence of operations is important for correctness here.
759+ -- We need to set the flag to false strictly before sending the
760+ -- outputDoorBell, otherwise the outputDoorBell may get processed too early and
761+ -- then we may set the flag to False to later making the consumer lose
762+ -- the flag, even without receiving a outputDoorBell.
763+ atomicModifyIORefCAS_ (needDoorBell sv) (const False)
764+ void $ tryPutMVar (outputDoorBell sv) ()
765+
766+
754767------------------------------------------------------------------------------
755768-- Spawning threads and collecting result in streamed fashion
756769------------------------------------------------------------------------------
@@ -770,7 +783,7 @@ type MonadAsync m = (MonadIO m, MonadBaseControl IO m, MonadThrow m)
770783{-# INLINE rawForkIO #-}
771784rawForkIO :: IO () -> IO ThreadId
772785rawForkIO action = IO $ \ s ->
773− case (fork# action s) of (# s1, tid #) -> (# s1, ThreadId tid #)
786+ case fork# action s of (# s1, tid #) -> (# s1, ThreadId tid #)
774787
775788{-# INLINE doFork #-}
776789doFork :: MonadBaseControl IO m
@@ -857,7 +870,7 @@ send sv msg = do
857870 Unlimited -> return True
858871 Limited lim -> do
859872 active <- readIORef (workerCount sv)
860− return $ len < ((fromIntegral lim) - active)
873+ return $ len < (fromIntegral lim - active)
861874
862875workerCollectLatency :: WorkerInfo -> IO (Maybe (Count, NanoSecs))
863876workerCollectLatency winfo = do
@@ -865,7 +878,7 @@ workerCollectLatency winfo = do
865878 cnt1 <- readIORef (workerYieldCount winfo)
866879 let cnt = cnt1 - cnt0
867880
868− if (cnt > 0)
881+ if cnt > 0
869882 then do
870883 t1 <- getTime Monotonic
871884 let period = fromInteger $ toNanoSecs (t1 - t0)
@@ -919,7 +932,7 @@ checkRatePeriodic :: SVar t m a
919932checkRatePeriodic sv yinfo winfo ycnt = do
920933 i <- readIORef (workerPollingInterval yinfo)
921934 -- XXX use generation count to check if the interval has been updated
922− if (i /= 0 && (ycnt `mod` i) == 0)
935+ if i /= 0 && (ycnt `mod` i) == 0
923936 then do
924937 workerUpdateLatency yinfo winfo
925938 -- XXX not required for parallel streams
@@ -961,12 +974,11 @@ workerStopUpdate winfo info = do
961974sendStop :: SVar t m a -> Maybe WorkerInfo -> IO ()
962975sendStop sv mwinfo = do
963976 atomicModifyIORefCAS_ (workerCount sv) $ \n -> n - 1
964− case mwinfo of
965− Just winfo ->
966− case yieldRateInfo sv of
967− Nothing -> return ()
968− Just info -> workerStopUpdate winfo info
969− Nothing -> return ()
977+ case (mwinfo, yieldRateInfo sv) of
978+ (Just winfo, Just info) ->
979+ workerStopUpdate winfo info
980+ _ ->
981+ return ()
970982 myThreadId >>= \tid -> void $ send sv (ChildStop tid Nothing)
971983
972984-------------------------------------------------------------------------------
@@ -981,16 +993,7 @@ sendStop sv mwinfo = do
981993enqueueLIFO :: SVar t m a -> IORef [t m a] -> t m a -> IO ()
982994enqueueLIFO sv q m = do
983995 atomicModifyIORefCAS_ q $ \ms -> m : ms
984− storeLoadBarrier
985− w <- readIORef $ needDoorBell sv
986− when w $ do
987− -- Note: the sequence of operations is important for correctness here.
988− -- We need to set the flag to false strictly before sending the
989− -- outputDoorBell, otherwise the outputDoorBell may get processed too early and
990− -- then we may set the flag to False to later making the consumer lose
991− -- the flag, even without receiving a outputDoorBell.
992− atomicModifyIORefCAS_ (needDoorBell sv) (const False)
993− void $ tryPutMVar (outputDoorBell sv) ()
996+ ringDoorBell sv
994997
995998-------------------------------------------------------------------------------
996999-- WAsync
@@ -1004,16 +1007,7 @@ enqueueLIFO sv q m = do
10041007enqueueFIFO :: SVar t m a -> LinkedQueue (t m a) -> t m a -> IO ()
10051008enqueueFIFO sv q m = do
10061009 pushL q m
1007− storeLoadBarrier
1008− w <- readIORef $ needDoorBell sv
1009− when w $ do
1010− -- Note: the sequence of operations is important for correctness here.
1011− -- We need to set the flag to false strictly before sending the
1012− -- outputDoorBell, otherwise the outputDoorBell may get processed too early and
1013− -- then we may set the flag to False to later making the consumer lose
1014− -- the flag, even without receiving a outputDoorBell.
1015− atomicModifyIORefCAS_ (needDoorBell sv) (const False)
1016− void $ tryPutMVar (outputDoorBell sv) ()
1010+ ringDoorBell sv
10171011
10181012-------------------------------------------------------------------------------
10191013-- Ahead
@@ -1085,16 +1079,7 @@ enqueueAhead sv q m = do
10851079 atomicModifyIORefCAS_ q $ \ case
10861080 ([], n) -> ([m], n + 1) -- increment sequence
10871081 _ -> error "not empty"
1088− storeLoadBarrier
1089− w <- readIORef $ needDoorBell sv
1090− when w $ do
1091− -- Note: the sequence of operations is important for correctness here.
1092− -- We need to set the flag to false strictly before sending the
1093− -- outputDoorBell, otherwise the outputDoorBell may get processed too early and
1094− -- then we may set the flag to False to later making the consumer lose
1095− -- the flag, even without receiving a outputDoorBell.
1096− atomicModifyIORefCAS_ (needDoorBell sv) (const False)
1097− void $ tryPutMVar (outputDoorBell sv) ()
1082+ ringDoorBell sv
10981083
10991084-- enqueue without incrementing the sequence number
11001085{-# INLINE reEnqueueAhead #-}
@@ -1103,11 +1088,7 @@ reEnqueueAhead sv q m = do
11031088 atomicModifyIORefCAS_ q $ \ case
11041089 ([], n) -> ([m], n) -- DO NOT increment sequence
11051090 _ -> error "not empty"
1106− storeLoadBarrier
1107− w <- readIORef $ needDoorBell sv
1108− when w $ do
1109− atomicModifyIORefCAS_ (needDoorBell sv) (const False)
1110− void $ tryPutMVar (outputDoorBell sv) ()
1091+ ringDoorBell sv
11111092
11121093-- Normally the thread that has the token should never go away. The token gets
11131094-- handed over to another thread, but someone or the other has the token at any
@@ -1138,7 +1119,7 @@ queueEmptyAhead q = liftIO $ do
11381119{-# INLINE dequeueAhead #-}
11391120dequeueAhead :: MonadIO m
11401121 => IORef ([t m a], Int) -> m (Maybe (t m a, Int))
1141−dequeueAhead q = liftIO $ do
1122+dequeueAhead q = liftIO $
11421123 atomicModifyIORefCAS q $ \case
11431124 ([], n) -> (([], n), Nothing)
11441125 (x : [], n) -> (([], n), Just (x, n))
@@ -1235,7 +1216,7 @@ addThread sv tid =
12351216{-# INLINE delThread #-}
12361217delThread :: MonadIO m => SVar t m a -> ThreadId -> m ()
12371218delThread sv tid =
1238− liftIO $ modifyIORef (workerThreads sv) $ (\s -> S.delete tid s)
1219+ liftIO $ modifyIORef (workerThreads sv) (S.delete tid)
12391220
12401221-- If present then delete else add. This takes care of out of order add and
12411222-- delete i.e. a delete arriving before we even added a thread.
@@ -1245,14 +1226,13 @@ delThread sv tid =
12451226modifyThread :: MonadIO m => SVar t m a -> ThreadId -> m ()
12461227modifyThread sv tid = do
12471228 changed <- liftIO $ atomicModifyIORefCAS (workerThreads sv) $ \old ->
1248− if (S.member tid old)
1249− then let new = (S.delete tid old) in (new, new)
1250− else let new = (S.insert tid old) in (new, old)
1251− if null changed
1252− then liftIO $ do
1253− writeBarrier
1254− void $ tryPutMVar (outputDoorBell sv) ()
1255− else return ()
1229+ if S.member tid old
1230+ then let new = S.delete tid old in (new, new)
1231+ else let new = S.insert tid old in (new, old)
1232+ when (null changed) $
1233+ liftIO $ do
1234+ writeBarrier
1235+ void $ tryPutMVar (outputDoorBell sv) ()
12561236
12571237-- | This is safe even if we are adding more threads concurrently because if
12581238-- a child thread is adding another thread then anyway 'workerThreads' will
@@ -1292,7 +1272,7 @@ pushWorker yieldMax sv = do
12921272 cntRef <- newIORef 0
12931273 t <- getTime Monotonic
12941274 lat <- newIORef (0, t)
1295− return $ Just $ WorkerInfo
1275+ return $ Just WorkerInfo
12961276 { workerYieldMax = yieldMax
12971277 , workerYieldCount = cntRef
12981278 , workerLatencyStart = lat
@@ -1309,10 +1289,11 @@ pushWorker yieldMax sv = do
13091289-- using a CAS based modification.
13101290{-# NOINLINE pushWorkerPar #-}
13111291pushWorkerPar :: MonadAsync m => SVar t m a -> (Maybe WorkerInfo -> m ()) -> m ()
1312−pushWorkerPar sv wloop = do
1292+pushWorkerPar sv wloop =
13131293 -- We do not use workerCount in case of ParallelVar but still there is no
13141294 -- harm in maintaining it correctly.
13151295#ifdef DIAGNOSTICS
1296+ do
13161297 liftIO $ atomicModifyIORefCAS_ (workerCount sv) $ \n -> n + 1
13171298 recordMaxWorkers sv
13181299 -- This allocation matters when significant number of workers are being
@@ -1347,14 +1328,14 @@ dispatchWorker yieldCount sv = do
13471328 -- Note, "done" may not mean that the work is actually finished if there
13481329 -- are workers active, because there may be a worker which has not yet
13491330 -- queued the leftover work.
1350− if (not done)
1331+ if not done
13511332 then do
13521333 qDone <- liftIO $ isQueueDone sv
13531334 -- Note that the worker count is only decremented during event
13541335 -- processing in fromStreamVar and therefore it is safe to read and
13551336 -- use it without a lock.
13561337 active <- liftIO $ readIORef $ workerCount sv
1357− if (not qDone)
1338+ if not qDone
13581339 then do
13591340 -- Note that we may deadlock if the previous workers (tasks in the
13601341 -- stream) wait/depend on the future workers (tasks in the stream)
@@ -1408,7 +1389,7 @@ rateRecoveryTime :: NanoSecs
14081389rateRecoveryTime = 1000000
14091390
14101391nanoToMicroSecs :: NanoSecs -> Int
1411−nanoToMicroSecs s = (fromIntegral s) `div` 1000
1392+nanoToMicroSecs s = fromIntegral s `div` 1000
14121393
14131394-- We either block, or send one worker with limited yield count or one or more
14141395-- workers with unlimited yield count.
@@ -1493,7 +1474,7 @@ estimateWorkers workerLimit svarYields gainLossYields
14931474 in assert (sleepTime >= 0) $
14941475 -- if s is less than 0 it means our maxSleepTime is less
14951476 -- than the worker latency.
1496− if (s > 0) then BlockWait s else ManyWorkers 1 (Count 0)
1477+ if s > 0 then BlockWait s else ManyWorkers 1 (Count 0)
14971478 where
14981479 withLimit n =
14991480 case workerLimit of
@@ -1519,7 +1500,7 @@ getWorkerLatency yinfo = do
15191500 pendingTime = colTime + time
15201501 new =
15211502 if pendingCount > 0
1522− then let lat = pendingTime `div` (fromIntegral pendingCount)
1503+ then let lat = pendingTime `div` fromIntegral pendingCount
15231504 -- XXX Give more weight to new?
15241505 in (lat + prev) `div` 2
15251506 else prev
@@ -1583,9 +1564,9 @@ collectLatency _ss yinfo = do
15831564 lcount' = lcount + pendingCount
15841565 tripleWith lat = (lcount', ltime, lat)
15851566
1586− if (pendingCount > 0)
1567+ if pendingCount > 0
15871568 then do
1588− let new = pendingTime `div` (fromIntegral pendingCount)
1569+ let new = pendingTime `div` fromIntegral pendingCount
15891570#ifdef DIAGNOSTICS
15901571 minLat <- readIORef (minWorkerLatency _ss)
15911572 when (new < minLat || minLat == 0) $
@@ -1599,7 +1580,7 @@ collectLatency _ss yinfo = do
15991580 -- return the previous latency derived from the previous batch.
16001581 if (pendingCount > fromIntegral magicMaxBuffer)
16011582 || (pendingTime > minThreadDelay)
1602− || (let r = (fromIntegral new) / (fromIntegral prev) :: Double
1583+ || (let r = fromIntegral new / fromIntegral prev :: Double
16031584 in prev > 0 && (r > 2 || r < 0.5))
16041585 || (prev == 0)
16051586 then do
@@ -1698,18 +1679,17 @@ dispatchWorkerPaced sv = do
16981679 liftIO $ writeIORef periodRef period
16991680
17001681 cnt <- liftIO $ readIORef $ workerCount sv
1701− if (cnt < netWorkers)
1682+ if cnt < netWorkers
17021683 then do
17031684 let total = netWorkers - cnt
17041685 batch = max 1 $ fromIntegral $
17051686 minThreadDelay `div` targetLat
1706− r <- dispatchN (min total batch)
17071687 -- XXX stagger the workers over a period?
17081688 -- XXX cannot sleep, as that would mean we cannot process the
17091689 -- outputs. need to try a different mechanism to stagger.
17101690 -- when (total > batch) $
17111691 -- liftIO $ threadDelay $ nanoToMicroSecs minThreadDelay
1712− return r
1692+ dispatchN (min total batch)
17131693 else return False
17141694
17151695 where
@@ -1723,7 +1703,7 @@ dispatchWorkerPaced sv = do
17231703 else yields + buf
17241704 liftIO $ modifyIORef (svarGainedLostYields yinfo) (+ delta)
17251705
1726− dispatchN n = do
1706+ dispatchN n =
17271707 if n == 0
17281708 then return True
17291709 else do
@@ -1736,12 +1716,13 @@ sendWorkerDelayPaced :: SVar t m a -> IO ()
17361716sendWorkerDelayPaced _ = return ()
17371717
17381718sendWorkerDelay :: SVar t m a -> IO ()
1739−sendWorkerDelay _sv = do
1719+sendWorkerDelay _sv =
17401720 -- XXX we need a better way to handle this than hardcoded delays. The
17411721 -- delays may be different for different systems.
17421722 -- If there is a usecase where this is required we can create a combinator
17431723 -- to set it as a config in the state.
17441724 {-
1725+ do
17451726 ncpu <- getNumCapabilities
17461727 if ncpu <= 1
17471728 then
@@ -1816,7 +1797,7 @@ sendWorkerWait delay dispatch sv = do
18161797 -- doorbell on the next enqueue.
18171798
18181799 liftIO $ atomicModifyIORefCAS_ (needDoorBell sv) $ const True
1819− liftIO $ storeLoadBarrier
1800+ liftIO storeLoadBarrier
18201801 canDoMore <- dispatch sv
18211802
18221803 -- XXX test for the case when we miss sending a worker when the worker
@@ -1865,12 +1846,12 @@ readOutputQBounded sv = do
18651846 cnt <- liftIO $ readIORef $ workerCount sv
18661847 when (cnt <= 0) $ do
18671848 done <- liftIO $ isWorkDone sv
1868− when (not done) $ pushWorker 0 sv
1849+ when (not done) (pushWorker 0 sv)
18691850
18701851 {-# INLINE blockingRead #-}
18711852 blockingRead = do
18721853 sendWorkerWait sendWorkerDelay (dispatchWorker 0) sv
1873− liftIO $ (readOutputQRaw sv >>= return . fst)
1854+ liftIO (fst `fmap` readOutputQRaw sv)
18741855
18751856readOutputQPaced :: MonadAsync m => SVar t m a -> m [ChildEvent a]
18761857readOutputQPaced sv = do
@@ -1888,7 +1869,7 @@ readOutputQPaced sv = do
18881869 {-# INLINE blockingRead #-}
18891870 blockingRead = do
18901871 sendWorkerWait sendWorkerDelayPaced dispatchWorkerPaced sv
1891− liftIO $ (readOutputQRaw sv >>= return . fst)
1872+ liftIO (fst `fmap` readOutputQRaw sv)
18921873
18931874postProcessBounded :: MonadAsync m => SVar t m a -> m Bool
18941875postProcessBounded sv = do
@@ -1907,7 +1888,7 @@ postProcessBounded sv = do
19071888 r <- liftIO $ isWorkDone sv
19081889 -- Note that we need to guarantee a worker, therefore we cannot just
19091890 -- use dispatchWorker which may or may not send a worker.
1910− when (not r) $ pushWorker 0 sv
1891+ when (not r) (pushWorker 0 sv)
19111892 -- XXX do we need to dispatch many here?
19121893 -- void $ dispatchWorker sv
19131894 return r
@@ -2150,7 +2131,7 @@ getParallelSVar st = do
21502131 case yieldRateInfo sv of
21512132 Nothing -> return ()
21522133 Just yinfo -> void $ collectLatency (svarStats sv) yinfo
2153− readOutputQRaw sv >>= return . fst
2134+ fst `fmap` readOutputQRaw sv
21542135
21552136sendFirstWorker :: MonadAsync m => SVar t m a -> t m a -> m (SVar t m a)
21562137sendFirstWorker sv m = do
@@ -2160,7 +2141,7 @@ sendFirstWorker sv m = do
21602141 liftIO $ enqueue sv m
21612142 case yieldRateInfo sv of
21622143 Nothing -> pushWorker 0 sv
2163− Just yinfo -> do
2144+ Just yinfo ->
21642145 if svarLatencyTarget yinfo == maxBound
21652146 then liftIO $ threadDelay maxBound
21662147 else pushWorker 1 sv
@@ -2190,7 +2171,7 @@ newParallelVar st = liftIO $ getParallelSVar st
21902171-- be read back from the SVar using 'fromSVar'.
21912172toStreamVar :: MonadAsync m => SVar t m a -> t m a -> m ()
21922173toStreamVar sv m = do
2193− liftIO $ (enqueue sv) m
2174+ liftIO $ enqueue sv m
21942175 done <- allThreadsDone sv
21952176 -- XXX This is safe only when called from the consumer thread or when no
21962177 -- consumer is present. There may be a race if we are not running in the