optimisation

Avoid an unncessary STM transaction. This will happen when the worker
pool is not completely full of the new stage, which is the common case.

In the uncommon case, this adds only a tiny bit of overhead for the
extra traversal of the worker pool. And the thread is going to block
for some time anyway.
This commit is contained in:
Joey Hess 2019-06-19 20:13:19 -04:00
parent 0e1140ac47
commit 26f0f8b20f
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38

View file

@ -100,8 +100,8 @@ enteringStage newstage a = Annex.getState Annex.workers >>= \case
- ActiveWorker with an IdleWorker. - ActiveWorker with an IdleWorker.
- -
- Must avoid a deadlock if all worker threads end up here at the same - Must avoid a deadlock if all worker threads end up here at the same
- time, or if there are no suitable IdleWorkers left. So we first - time, or if there are no suitable IdleWorkers left. So if necessary
- replace our ActiveWorker with an IdleWorker in the pool, to allow - we first replace our ActiveWorker with an IdleWorker in the pool, to allow
- some other thread to use it, before waiting for a suitable IdleWorker - some other thread to use it, before waiting for a suitable IdleWorker
- for us to use. - for us to use.
- -
@ -112,17 +112,26 @@ enteringStage newstage a = Annex.getState Annex.workers >>= \case
-} -}
changeStageTo :: ThreadId -> TMVar (WorkerPool AnnexState) -> WorkerStage -> Annex (Maybe WorkerStage) changeStageTo :: ThreadId -> TMVar (WorkerPool AnnexState) -> WorkerStage -> Annex (Maybe WorkerStage)
changeStageTo mytid tv newstage = liftIO $ changeStageTo mytid tv newstage = liftIO $
replaceidle >>= maybe (return Nothing) waitidle replaceidle >>= maybe
(return Nothing)
(either waitidle (return . Just))
where where
replaceidle = atomically $ do replaceidle = atomically $ do
pool <- takeTMVar tv pool <- takeTMVar tv
if memberStage newstage (usedStages pool) if memberStage newstage (usedStages pool)
then case removeThreadIdWorkerPool mytid pool of then case removeThreadIdWorkerPool mytid pool of
Just ((myaid, oldstage), pool') Just ((myaid, oldstage), pool')
| oldstage /= newstage -> do | oldstage /= newstage -> case getIdleWorkerSlot newstage pool' of
putTMVar tv $ Nothing -> do
addWorkerPool (IdleWorker oldstage) pool' putTMVar tv $
return $ Just (myaid, oldstage) addWorkerPool (IdleWorker oldstage) pool'
return $ Just $ Left (myaid, oldstage)
Just pool'' -> do
-- optimisation
putTMVar tv $
addWorkerPool (IdleWorker oldstage) $
addWorkerPool (ActiveWorker myaid newstage) pool''
return $ Just $ Right oldstage
| otherwise -> do | otherwise -> do
putTMVar tv pool putTMVar tv pool
return Nothing return Nothing
@ -157,11 +166,14 @@ waitInitialWorkerSlot tv = do
return v return v
waitIdleWorkerSlot :: WorkerStage -> WorkerPool Annex.AnnexState -> STM (WorkerPool Annex.AnnexState) waitIdleWorkerSlot :: WorkerStage -> WorkerPool Annex.AnnexState -> STM (WorkerPool Annex.AnnexState)
waitIdleWorkerSlot wantstage pool = do waitIdleWorkerSlot wantstage = maybe retry return . getIdleWorkerSlot wantstage
getIdleWorkerSlot :: WorkerStage -> WorkerPool Annex.AnnexState -> Maybe (WorkerPool Annex.AnnexState)
getIdleWorkerSlot wantstage pool = do
l <- findidle [] (workerList pool) l <- findidle [] (workerList pool)
return $ pool { workerList = l } return $ pool { workerList = l }
where where
findidle _ [] = retry findidle _ [] = Nothing
findidle c ((IdleWorker stage):rest) | stage == wantstage = findidle c ((IdleWorker stage):rest)
return (c ++ rest) | stage == wantstage = Just (c ++ rest)
findidle c (w:rest) = findidle (w:c) rest findidle c (w:rest) = findidle (w:c) rest