@@ -346,7 +346,7 @@ data SVar t m a = SVar
346 -- Combined/aggregate parameters
346 -- Combined/aggregate parameters
347 , maxWorkerLimit :: Limit
347 , maxWorkerLimit :: Limit
348 , maxBufferLimit :: Limit
348 , maxBufferLimit :: Limit
349− , remainingYields :: Maybe (IORef Count)
349+ , remainingWork :: Maybe (IORef Count)
350 , yieldRateInfo :: Maybe YieldRateInfo
350 , yieldRateInfo :: Maybe YieldRateInfo
352 -- Used only by bounded SVar types
352 -- Used only by bounded SVar types
@@ -779,7 +779,7 @@ doFork action exHandler =
779 exHandler
779 exHandler
780 runInIO (return tid)
780 runInIO (return tid)
782−-- XXX Can we make access to remainingYields and yieldRateInfo fields in sv
782+-- XXX Can we make access to remainingWork and yieldRateInfo fields in sv
783-- faster, along with the fields in sv required by send?
783-- faster, along with the fields in sv required by send?
784-- XXX make it noinline
784-- XXX make it noinline
@@ -793,7 +793,7 @@ doFork action exHandler =
793{-# INLINE decrementYieldLimit #-}
793{-# INLINE decrementYieldLimit #-}
794decrementYieldLimit :: SVar t m a -> IO Bool
794decrementYieldLimit :: SVar t m a -> IO Bool
795decrementYieldLimit sv =
795decrementYieldLimit sv =
796− case remainingYields sv of
796+ case remainingWork sv of
797 Nothing -> return True
797 Nothing -> return True
798 Just ref -> do
798 Just ref -> do
799 r <- atomicModifyIORefCAS ref $ \x -> (x - 1, x)
799 r <- atomicModifyIORefCAS ref $ \x -> (x - 1, x)
@@ -804,7 +804,7 @@ decrementYieldLimit sv =
804{-# INLINE decrementYieldLimitPost #-}
804{-# INLINE decrementYieldLimitPost #-}
805decrementYieldLimitPost :: SVar t m a -> IO Bool
805decrementYieldLimitPost :: SVar t m a -> IO Bool
806decrementYieldLimitPost sv =
806decrementYieldLimitPost sv =
807− case remainingYields sv of
807+ case remainingWork sv of
808 Nothing -> return True
808 Nothing -> return True
809 Just ref -> do
809 Just ref -> do
810 r <- atomicModifyIORefCAS ref $ \x -> (x - 1, x)
810 r <- atomicModifyIORefCAS ref $ \x -> (x - 1, x)
@@ -813,7 +813,7 @@ decrementYieldLimitPost sv =
813{-# INLINE incrementYieldLimit #-}
813{-# INLINE incrementYieldLimit #-}
814incrementYieldLimit :: SVar t m a -> IO ()
814incrementYieldLimit :: SVar t m a -> IO ()
815incrementYieldLimit sv =
815incrementYieldLimit sv =
816− case remainingYields sv of
816+ case remainingWork sv of
817 Nothing -> return ()
817 Nothing -> return ()
818 Just ref -> atomicModifyIORefCAS_ ref (+ 1)
818 Just ref -> atomicModifyIORefCAS_ ref (+ 1)
@@ -1339,6 +1339,9 @@ dispatchWorker yieldCount sv = do
1339 -- XXX in case of Ahead streams we should not send more than one worker
1339 -- XXX in case of Ahead streams we should not send more than one worker
1340 -- when the work queue is done but heap is not done.
1340 -- when the work queue is done but heap is not done.
1341 done <- liftIO $ isWorkDone sv
1341 done <- liftIO $ isWorkDone sv
1342+ -- Note, "done" may not mean that the work is actually finished if there
1343+ -- are workers active, because there may be a worker which has not yet
1344+ -- queued the leftover work.
1342 if (not done)
1345 if (not done)
1344 qDone <- liftIO $ isQueueDone sv
1347 qDone <- liftIO $ isQueueDone sv
@@ -1353,7 +1356,7 @@ dispatchWorker yieldCount sv = do
1353 -- executing. In that case we should either configure the maxWorker
1356 -- executing. In that case we should either configure the maxWorker
1354 -- count to higher or use parallel style instead of ahead or async
1357 -- count to higher or use parallel style instead of ahead or async
1355 -- style.
1358 -- style.
1356− limit <- case remainingYields sv of
1359+ limit <- case remainingWork sv of
1357 Nothing -> return workerLimit
1360 Nothing -> return workerLimit
1358 Just ref -> do
1361 Just ref -> do
1359 n <- liftIO $ readIORef ref
1362 n <- liftIO $ readIORef ref
@@ -1368,12 +1371,12 @@ dispatchWorker yieldCount sv = do
1368 let dispatch = pushWorker yieldCount sv >> return True
1371 let dispatch = pushWorker yieldCount sv >> return True
1369 in case limit of
1372 in case limit of
1370 Unlimited -> dispatch
1373 Unlimited -> dispatch
1371− -- Note that the use of remainingYields and workerCount is not
1374+ -- Note that the use of remainingWork and workerCount is not
1372 -- atomic and the counts may even have changed between reading and
1375 -- atomic and the counts may even have changed between reading and
1373 -- using them here, so this is just approximate logic and we cannot
1376 -- using them here, so this is just approximate logic and we cannot
1374 -- rely on it for correctness. We may actually dispatch more
1377 -- rely on it for correctness. We may actually dispatch more
1375 -- workers than required.
1378 -- workers than required.
1376− Limited lim | active < (fromIntegral lim) -> dispatch
1379+ Limited lim | lim > 0 -> dispatch
1377 _ -> return False
1380 _ -> return False
1379 when (active <= 0) $ pushWorker 0 sv
1382 when (active <= 0) $ pushWorker 0 sv
@@ -1474,9 +1477,9 @@ estimateWorkers workerLimit svarYields gainLossYields
1474 in assert (adjustedLat > 0) $
1477 in assert (adjustedLat > 0) $
1475 if wLatency <= adjustedLat
1478 if wLatency <= adjustedLat
1476 then PartialWorker deltaYields
1479 then PartialWorker deltaYields
1477− else ManyWorkers ( fromIntegral
1479− $ wLatency `div` adjustedLat) deltaYields
1480+ else let workers = withLimit $ wLatency `div` adjustedLat
1481+ limited = min workers (fromIntegral deltaYields)
1482+ in ManyWorkers (fromIntegral limited) deltaYields
1481 let expectedDuration = fromIntegral effectiveYields * targetLat
1484 let expectedDuration = fromIntegral effectiveYields * targetLat
1482 sleepTime = expectedDuration - svarElapsed
1485 sleepTime = expectedDuration - svarElapsed
@@ -2001,7 +2004,7 @@ getAheadSVar st f = do
2002 let getSVar sv readOutput postProc = SVar
2005 let getSVar sv readOutput postProc = SVar
2003 { outputQueue = outQ
2006 { outputQueue = outQ
2004− , remainingYields = yl
2007+ , remainingWork = yl
2005 , maxBufferLimit = getMaxBuffer st
2008 , maxBufferLimit = getMaxBuffer st
2006 , maxWorkerLimit = getMaxThreads st
2009 , maxWorkerLimit = getMaxThreads st
2007 , yieldRateInfo = rateInfo
2010 , yieldRateInfo = rateInfo
@@ -2049,7 +2052,7 @@ getAheadSVar st f = do
2049 isQueueDoneAhead sv q = do
2052 isQueueDoneAhead sv q = do
2050 queueDone <- checkEmpty q
2053 queueDone <- checkEmpty q
2051 yieldsDone <-
2054 yieldsDone <-
2052− case remainingYields sv of
2055+ case remainingWork sv of
2053 Just yref -> do
2056 Just yref -> do
2054 n <- readIORef yref
2057 n <- readIORef yref
2055 return (n <= 0)
2058 return (n <= 0)
@@ -2097,7 +2100,7 @@ getParallelSVar st = do
2098 let sv =
2101 let sv =
2099 SVar { outputQueue = outQ
2102 SVar { outputQueue = outQ
2100− , remainingYields = yl
2103+ , remainingWork = yl
2101 , maxBufferLimit = Unlimited
2104 , maxBufferLimit = Unlimited
2102 , maxWorkerLimit = Unlimited
2105 , maxWorkerLimit = Unlimited
2103 -- Used only for diagnostics
2106 -- Used only for diagnostics