on master help sign in
Pass WorkerInfo only when needed

impacts performance quite a bit when lots of workers are sent, especially in the case of parallel streams.

commitd73041c957d4211a6dc89624f0ebff54178bda6a authorHarendra Kumar <harendra.kumar@gmail.com> dateThu 6 Sep 2018, 17:30 (8 years ago) parent772dbd4
4 files changed+72−49
src/Streamly/SVar.hs+49−33 src/Streamly/Streams/Ahead.hs+16−11 src/Streamly/Streams/Async.hs+4−4 src/Streamly/Streams/Parallel.hs+3−1
src/Streamly/SVar.hs+49−33
@@ -347,7 +347,7 @@ data SVar t m a = SVar
347347 , enqueue :: t m a -> IO ()
348348 , isWorkDone :: IO Bool
349349 , needDoorBell :: IORef Bool
350− , workLoop :: WorkerInfo -> m ()
350+ , workLoop :: Maybe WorkerInfo -> m ()
351351
352352 -- Shared, thread tracking
353353 , workerThreads :: IORef (Set ThreadId)
@@ -905,13 +905,16 @@ workerRateControl sv yinfo winfo = do
905905-- streams. latency update must be done when we yield directly to outputQueue
906906-- or when we yield to heap.
907907{-# INLINE sendYield #-}
908−sendYield :: SVar t m a -> WorkerInfo -> ChildEvent a -> IO Bool
909−sendYield sv winfo msg = do
908+sendYield :: SVar t m a -> Maybe WorkerInfo -> ChildEvent a -> IO Bool
909+sendYield sv mwinfo msg = do
910910 r <- send sv msg
911911 rateLimitOk <-
912− case yieldRateInfo sv of
912+ case mwinfo of
913+ Just winfo ->
914+ case yieldRateInfo sv of
915+ Nothing -> return True
916+ Just yinfo -> workerRateControl sv yinfo winfo
913917 Nothing -> return True
914− Just yinfo -> workerRateControl sv yinfo winfo
915918 return $ r && rateLimitOk
916919
917920{-# INLINE workerStopUpdate #-}
@@ -921,12 +924,15 @@ workerStopUpdate winfo info = do
921924 when (i /= 0) $ workerUpdateLatency info winfo
922925
923926{-# INLINABLE sendStop #-}
924−sendStop :: SVar t m a -> WorkerInfo -> IO ()
925−sendStop sv winfo = do
927+sendStop :: SVar t m a -> Maybe WorkerInfo -> IO ()
928+sendStop sv mwinfo = do
926929 atomicModifyIORefCAS_ (workerCount sv) $ \n -> n - 1
927− case yieldRateInfo sv of
930+ case mwinfo of
931+ Just winfo ->
932+ case yieldRateInfo sv of
933+ Nothing -> return ()
934+ Just info -> workerStopUpdate winfo info
928935 Nothing -> return ()
929− Just info -> workerStopUpdate winfo info
930936 myThreadId >>= \tid -> void $ send sv (ChildStop tid Nothing)
931937
932938-------------------------------------------------------------------------------
@@ -1193,17 +1199,20 @@ pushWorker yieldMax sv = do
11931199#ifdef DIAGNOSTICS
11941200 recordMaxWorkers sv
11951201#endif
1196− -- XXX we can make this allocation conditional, it might matter when
1197− -- significant number of workers are being sent.
1198− winfo <- do
1199− cntRef <- liftIO $ newIORef 0
1200− t <- liftIO $ getTime Monotonic
1201− lat <- liftIO $ newIORef (0, t)
1202− return $ WorkerInfo
1203− { workerYieldMax = yieldMax
1204− , workerYieldCount = cntRef
1205− , workerLatencyStart = lat
1206− }
1202+ -- This allocation matters when significant number of workers are being
1203+ -- sent. We allocate it only when needed.
1204+ winfo <-
1205+ case yieldRateInfo sv of
1206+ Nothing -> return Nothing
1207+ Just _ -> liftIO $ do
1208+ cntRef <- newIORef 0
1209+ t <- getTime Monotonic
1210+ lat <- newIORef (0, t)
1211+ return $ Just $ WorkerInfo
1212+ { workerYieldMax = yieldMax
1213+ , workerYieldCount = cntRef
1214+ , workerLatencyStart = lat
1215+ }
12071216 doFork (workLoop sv winfo) (handleChildException sv) >>= addThread sv
12081217
12091218-- XXX we can push the workerCount modification in accountThread and use the
@@ -1215,25 +1224,32 @@ pushWorker yieldMax sv = do
12151224-- workerThreads. Alternatively, we can use a CreateThread event to avoid
12161225-- using a CAS based modification.
12171226{-# NOINLINE pushWorkerPar #-}
1218−pushWorkerPar :: MonadAsync m => SVar t m a -> (WorkerInfo -> m ()) -> m ()
1227+pushWorkerPar :: MonadAsync m => SVar t m a -> (Maybe WorkerInfo -> m ()) -> m ()
12191228pushWorkerPar sv wloop = do
12201229 -- We do not use workerCount in case of ParallelVar but still there is no
12211230 -- harm in maintaining it correctly.
12221231#ifdef DIAGNOSTICS
12231232 liftIO $ atomicModifyIORefCAS_ (workerCount sv) $ \n -> n + 1
12241233 recordMaxWorkers sv
1225−#endif
1226− winfo <- do
1227− cntRef <- liftIO $ newIORef 0
1228− t <- liftIO $ getTime Monotonic
1229− lat <- liftIO $ newIORef (0, t)
1230− return $ WorkerInfo
1231− { workerYieldMax = 0
1232− , workerYieldCount = cntRef
1233− , workerLatencyStart = lat
1234− }
1234+ -- This allocation matters when significant number of workers are being
1235+ -- sent. We allocate it only when needed. The overhead increases by 4x.
1236+ winfo <-
1237+ case yieldRateInfo sv of
1238+ Nothing -> return Nothing
1239+ Just _ -> liftIO $ do
1240+ cntRef <- newIORef 0
1241+ t <- getTime Monotonic
1242+ lat <- newIORef (0, t)
1243+ return $ Just $ WorkerInfo
1244+ { workerYieldMax = 0
1245+ , workerYieldCount = cntRef
1246+ , workerLatencyStart = lat
1247+ }
12351248
12361249 doFork (wloop winfo) (handleChildException sv) >>= modifyThread sv
1250+#else
1251+ doFork (wloop Nothing) (handleChildException sv) >>= modifyThread sv
1252+#endif
12371253
12381254-- Returns:
12391255-- True: can dispatch more
@@ -1860,7 +1876,7 @@ getAheadSVar :: MonadAsync m
18601876 -> IORef (Heap (Entry Int (AheadHeapEntry t m a)), Int)
18611877 -> State t m a
18621878 -> SVar t m a
1863− -> WorkerInfo
1879+ -> Maybe WorkerInfo
18641880 -> m ())
18651881 -> IO (SVar t m a)
18661882getAheadSVar st f = do
@@ -2050,7 +2066,7 @@ newAheadVar :: MonadAsync m
20502066 -> IORef (Heap (Entry Int (AheadHeapEntry t m a)), Int)
20512067 -> State t m a
20522068 -> SVar t m a
2053− -> WorkerInfo
2069+ -> Maybe WorkerInfo
20542070 -> m ())
20552071 -> m (SVar t m a)
20562072newAheadVar st m wloop = do
src/Streamly/Streams/Ahead.hs+16−11
@@ -192,7 +192,7 @@ processHeap :: MonadIO m
192192 -> IORef (Heap (Entry Int (AheadHeapEntry Stream m a)) , Int)
193193 -> State Stream m a
194194 -> SVar Stream m a
195− -> WorkerInfo
195+ -> Maybe WorkerInfo
196196 -> AheadHeapEntry Stream m a
197197 -> Int
198198 -> Bool -- we are draining the heap before we stop
@@ -306,7 +306,7 @@ drainHeap :: MonadIO m
306306 -> IORef (Heap (Entry Int (AheadHeapEntry Stream m a)) , Int)
307307 -> State Stream m a
308308 -> SVar Stream m a
309− -> WorkerInfo
309+ -> Maybe WorkerInfo
310310 -> m ()
311311drainHeap q heap st sv winfo = do
312312 ent <- liftIO $ dequeueFromHeap heap
@@ -320,7 +320,7 @@ processWithoutToken :: MonadIO m
320320 -> IORef (Heap (Entry Int (AheadHeapEntry Stream m a)) , Int)
321321 -> State Stream m a
322322 -> SVar Stream m a
323− -> WorkerInfo
323+ -> Maybe WorkerInfo
324324 -> Stream m a
325325 -> Int
326326 -> m ()
@@ -344,16 +344,21 @@ processWithoutToken q heap st sv winfo m sno = do
344344 ((H.insert (Entry seqNo ent) h, snum), h)
345345
346346 heapOk <- liftIO $ underMaxHeap sv hp
347+ let keepDraining = drainHeap q heap st sv winfo
348+ mainLoop = workLoopAhead q heap st sv winfo
347349 if heapOk
348350 then
349351 case yieldRateInfo sv of
350− Nothing -> workLoopAhead q heap st sv winfo
352+ Nothing -> mainLoop
351353 Just yinfo -> do
352− rateOk <- liftIO $ workerRateControl sv yinfo winfo
353− if rateOk
354− then workLoopAhead q heap st sv winfo
355− else drainHeap q heap st sv winfo
356− else drainHeap q heap st sv winfo
354+ case winfo of
355+ Just info -> do
356+ rateOk <- liftIO $ workerRateControl sv yinfo info
357+ if rateOk
358+ then mainLoop
359+ else keepDraining
360+ Nothing -> mainLoop
361+ else keepDraining
357362
358363 singleToHeap seqNo a = toHeap seqNo (AheadEntryPure a)
359364 yieldToHeap seqNo a r = toHeap seqNo (AheadEntryStream (a `K.cons` r))
@@ -363,7 +368,7 @@ processWithToken :: MonadIO m
363368 -> IORef (Heap (Entry Int (AheadHeapEntry Stream m a)) , Int)
364369 -> State Stream m a
365370 -> SVar Stream m a
366− -> WorkerInfo
371+ -> Maybe WorkerInfo
367372 -> Stream m a
368373 -> Int
369374 -> m ()
@@ -461,7 +466,7 @@ workLoopAhead :: MonadIO m
461466 -> IORef (Heap (Entry Int (AheadHeapEntry Stream m a)) , Int)
462467 -> State Stream m a
463468 -> SVar Stream m a
464− -> WorkerInfo
469+ -> Maybe WorkerInfo
465470 -> m ()
466471workLoopAhead q heap st sv winfo = do
467472#ifdef DIAGNOSTICS
src/Streamly/Streams/Async.hs+4−4
@@ -79,7 +79,7 @@ workLoopLIFO
7979 => IORef [Stream m a]
8080 -> State Stream m a
8181 -> SVar Stream m a
82− -> WorkerInfo
82+ -> Maybe WorkerInfo
8383 -> m ()
8484workLoopLIFO q st sv winfo = run
8585
@@ -118,7 +118,7 @@ workLoopLIFOLimited
118118 => IORef [Stream m a]
119119 -> State Stream m a
120120 -> SVar Stream m a
121− -> WorkerInfo
121+ -> Maybe WorkerInfo
122122 -> m ()
123123workLoopLIFOLimited q st sv winfo = run
124124
@@ -178,7 +178,7 @@ workLoopFIFO
178178 => LinkedQueue (Stream m a)
179179 -> State Stream m a
180180 -> SVar Stream m a
181− -> WorkerInfo
181+ -> Maybe WorkerInfo
182182 -> m ()
183183workLoopFIFO q st sv winfo = run
184184
@@ -208,7 +208,7 @@ workLoopFIFOLimited
208208 => LinkedQueue (Stream m a)
209209 -> State Stream m a
210210 -> SVar Stream m a
211− -> WorkerInfo
211+ -> Maybe WorkerInfo
212212 -> m ()
213213workLoopFIFOLimited q st sv winfo = run
214214
src/Streamly/Streams/Parallel.hs+3−1
@@ -60,7 +60,9 @@ import qualified Streamly.Streams.StreamK as K
6060-------------------------------------------------------------------------------
6161
6262{-# NOINLINE runOne #-}
63−runOne :: MonadIO m => State Stream m a -> Stream m a -> WorkerInfo -> m ()
63+runOne
64+ :: MonadIO m
65+ => State Stream m a -> Stream m a -> Maybe WorkerInfo -> m ()
6466runOne st m winfo = unStream m st stop single yieldk
6567
6668 where