@@ -129,9 +129,9 @@ import Development.IDE.Types.Options as Options
129129import qualified Language.LSP.Protocol.Message as LSP
130130import qualified Language.LSP.Server as LSP
131131
132- import Control.Exception ( Exception ( fromException ) )
133- import Data.Either ( isLeft , isRight ,
134- lefts )
132+ import Data.Either ( isRight , lefts )
133+ import Data.Int ( Int64 )
134+ import Data.IORef.Extra ( atomicModifyIORef'_ )
135135import Development.IDE.Core.Tracing
136136import Development.IDE.GHC.Compat (NameCache ,
137137 NameCacheUpdater ,
@@ -142,13 +142,15 @@ import Development.IDE.Graph hiding (ShakeValue,
142142 action )
143143import qualified Development.IDE.Graph as Shake
144144import Development.IDE.Graph.Database (ShakeDatabase ,
145+ shakeGetActionQueueLength ,
145146 shakeGetBuildStep ,
146147 shakeGetDatabaseKeys ,
147148 shakeNewDatabase ,
148149 shakeProfileDatabase ,
149150 shakeRunDatabaseForKeys ,
151+ shakeRunDatabaseForKeysSep ,
150152 shakeShutDatabase )
151- import Development.IDE.Graph.Internal.Action (runActionInDb )
153+ import Development.IDE.Graph.Internal.Action (runActionInDbCb )
152154import Development.IDE.Graph.Internal.Database (AsyncParentKill (AsyncParentKill ))
153155import Development.IDE.Graph.Internal.Types (Step (.. ),
154156 getShakeStep )
@@ -184,15 +186,15 @@ import qualified StmContainers.Map as STM
184186import System.FilePath hiding (makeRelative )
185187import System.IO.Unsafe (unsafePerformIO )
186188import System.Time.Extra
187- import UnliftIO (MonadUnliftIO (withRunInIO ))
188- import qualified UnliftIO.Exception as UE
189+ import UnliftIO (MonadUnliftIO (withRunInIO ),
190+ newIORef , readIORef )
189191
190192
191193
192194data Log
193195 = LogCreateHieDbExportsMapStart
194196 | LogCreateHieDbExportsMapFinish ! Int
195- | LogBuildSessionRestart ! String ! [DelayedActionInternal ] ! KeySet ! Seconds ! (Maybe FilePath )
197+ | LogBuildSessionRestart ! String ! [DelayedActionInternal ] ! KeySet ! Seconds ! (Maybe FilePath ) ! Int
196198 | LogBuildSessionRestartTakingTooLong ! Seconds
197199 | LogDelayedAction ! (DelayedAction () ) ! Seconds
198200 | LogBuildSessionFinish ! Step ! (Either SomeException [Either SomeException () ])
@@ -207,10 +209,13 @@ data Log
207209 -- * OfInterest Log messages
208210 | LogSetFilesOfInterest ! [(NormalizedFilePath , FileOfInterestStatus )]
209211 | LogShakeText ! T. Text
212+ | LogMonitering ! T. Text ! Int64
210213 deriving Show
211214
212215instance Pretty Log where
213216 pretty = \ case
217+ LogMonitering name value ->
218+ " Monitoring:" <+> pretty name <+> " value:" <+> pretty value
214219 LogDiagsPublishLog key lastDiags diags ->
215220 vcat
216221 [ " Publishing diagnostics for" <+> pretty (show key)
@@ -222,11 +227,12 @@ instance Pretty Log where
222227 " Initializing exports map from hiedb"
223228 LogCreateHieDbExportsMapFinish exportsMapSize ->
224229 " Done initializing exports map from hiedb. Size:" <+> pretty exportsMapSize
225- LogBuildSessionRestart reason actionQueue keyBackLog abortDuration shakeProfilePath ->
230+ LogBuildSessionRestart reason actionQueue keyBackLog abortDuration shakeProfilePath step ->
226231 vcat
227232 [ " Restarting build session due to" <+> pretty reason
228233 , " Action Queue:" <+> pretty (map actionName actionQueue)
229234 , " Keys:" <+> pretty (map show $ toListKeySet keyBackLog)
235+ , " Current step:" <+> pretty (show step)
230236 , " Aborting previous build session took" <+> pretty (showDuration abortDuration) <+> pretty shakeProfilePath ]
231237 LogBuildSessionRestartTakingTooLong seconds ->
232238 " Build restart is taking too long (" <> pretty seconds <> " seconds)"
@@ -690,7 +696,7 @@ shakeOpen :: Recorder (WithPriority Log)
690696shakeOpen recorder lspEnv defaultConfig idePlugins debouncer
691697 shakeProfileDir (IdeReportProgress reportProgress)
692698 ideTesting
693- withHieDb threadQueue opts monitoring rules rootDir = mdo
699+ withHieDb threadQueue opts argMonitoring rules rootDir = mdo
694700 -- see Note [Serializing runs in separate thread]
695701 let indexQueue = tIndexQueue threadQueue
696702 restartQueue = tRestartQueue threadQueue
@@ -717,12 +723,12 @@ shakeOpen recorder lspEnv defaultConfig idePlugins debouncer
717723 let hiedbWriter = HieDbWriter {.. }
718724 exportsMap <- newTVarIO mempty
719725 -- lazily initialize the exports map with the contents of the hiedb
720- -- TODO: exceptions can be swallowed here?
721- _ <- async $ do
726+ async <- async $ do
722727 logWith recorder Debug LogCreateHieDbExportsMapStart
723728 em <- createExportsMapHieDb withHieDb
724729 atomically $ modifyTVar' exportsMap (<> em)
725730 logWith recorder Debug $ LogCreateHieDbExportsMapFinish (ExportsMap. size em)
731+ link async
726732
727733 progress <-
728734 if reportProgress
@@ -750,26 +756,46 @@ shakeOpen recorder lspEnv defaultConfig idePlugins debouncer
750756
751757 checkParents <- optCheckParents
752758
759+
760+ logMonitoring <- newLogMonitoring recorder
761+ let monitoring = logMonitoring <> argMonitoring
753762 -- monitoring
754763 let readValuesCounter = fromIntegral . countRelevantKeys checkParents <$> getStateKeys shakeExtras
755764 readDirtyKeys = fromIntegral . countRelevantKeys checkParents . toListKeySet <$> readTVarIO(dirtyKeys shakeExtras)
756765 readIndexPending = fromIntegral . HMap. size <$> readTVarIO (indexPending $ hiedbWriter shakeExtras)
757766 readExportsMap = fromIntegral . ExportsMap. exportsMapSize <$> readTVarIO (exportsMap shakeExtras)
758767 readDatabaseCount = fromIntegral . countRelevantKeys checkParents . map fst <$> shakeGetDatabaseKeys shakeDb
759768 readDatabaseStep = fromIntegral <$> shakeGetBuildStep shakeDb
769+ readDatabaseActionQueueCount = fromIntegral <$> shakeGetActionQueueLength shakeDb
760770
761771 registerGauge monitoring " ghcide.values_count" readValuesCounter
762772 registerGauge monitoring " ghcide.dirty_keys_count" readDirtyKeys
763773 registerGauge monitoring " ghcide.indexing_pending_count" readIndexPending
764774 registerGauge monitoring " ghcide.exports_map_count" readExportsMap
765775 registerGauge monitoring " ghcide.database_count" readDatabaseCount
766776 registerCounter monitoring " ghcide.num_builds" readDatabaseStep
777+ registerCounter monitoring " ghcide.database_action_queue_count" readDatabaseActionQueueCount
767778
768779 stopMonitoring <- start monitoring
769780
770781 let ideState = IdeState {.. }
771782 return ideState
772-
783+ newLogMonitoring :: MonadIO m => Recorder (WithPriority Log ) -> m Monitoring
784+ newLogMonitoring logger = do
785+ actions <- newIORef []
786+ let registerCounter name readA = do
787+ let update = do
788+ val <- readA
789+ logWith logger Info $ LogMonitering name (fromIntegral val)
790+ atomicModifyIORef'_ actions (update : )
791+ registerGauge = registerCounter
792+ let start = do
793+ a <- regularly 10 $ sequence_ =<< readIORef actions
794+ return (cancel a)
795+ return Monitoring {.. }
796+ where
797+ regularly :: Seconds -> IO () -> IO (Async () )
798+ regularly delay act = async $ forever (act >> sleep delay)
773799
774800getStateKeys :: ShakeExtras -> IO [Key ]
775801getStateKeys = (fmap . fmap ) fst . atomically . ListT. toList . STM. listT . stateValues
@@ -837,7 +863,8 @@ shakeRestart recorder IdeState{..} vfs reason acts ioActionBetweenShakeSession =
837863 res <- shakeDatabaseProfile shakeDb
838864 backlog <- readTVarIO $ dirtyKeys shakeExtras
839865 -- this log is required by tests
840- logWith recorder Debug $ LogBuildSessionRestart reason queue backlog stopTime res
866+ step <- shakeGetBuildStep shakeDb
867+ logWith recorder Debug $ LogBuildSessionRestart reason queue backlog stopTime res step
841868 )
842869 -- It is crucial to be masked here, otherwise we can get killed
843870 -- between spawning the new thread and updating shakeSession.
@@ -859,12 +886,13 @@ shakeEnqueue :: ShakeExtras -> DelayedAction a -> IO (IO a)
859886shakeEnqueue ShakeExtras {actionQueue, shakeRecorder} act = do
860887 (b, dai) <- instantiateDelayedAction act
861888 atomicallyNamed " actionQueue - push" $ pushQueue dai actionQueue
889+ logWith shakeRecorder Debug $ LogShakeText (T. pack $ " Enqueued action: " <> actionName act)
862890 let wait' barrier =
863891 waitBarrier barrier `catches`
864892 [ Handler (\ BlockedIndefinitelyOnMVar ->
865893 fail $ " internal bug: forever blocked on MVar for " <>
866894 actionName act)
867- , Handler (\ e@ AsyncCancelled -> do
895+ , Handler (\ e@ ( SomeAsyncException _) -> do
868896 logWith shakeRecorder Debug $ LogCancelledAction (T. pack $ actionName act)
869897
870898 atomicallyNamed " actionQueue - abort" $ abortQueue dai actionQueue
@@ -892,6 +920,7 @@ newSession recorder extras@ShakeExtras{..} vfsMod shakeDb acts reason = do
892920 VFSModified vfs -> atomically $ writeTVar vfsVar vfs
893921
894922 IdeOptions {optRunSubset} <- getIdeOptionsIO extras
923+
895924 reenqueued <- atomicallyNamed " actionQueue - peek" $ peekInProgress actionQueue
896925 step <- getShakeStep shakeDb
897926 allPendingKeys <-
@@ -907,37 +936,39 @@ newSession recorder extras@ShakeExtras{..} vfsMod shakeDb acts reason = do
907936 Left e -> logWith recorder Error $ LogShakeText (T. pack $ label ++ " failed: " ++ show e)
908937 Right r -> logWith recorder Debug $ LogShakeText (T. pack $ label ++ " finished: " ++ show r)
909938 pumpActionThread = do
910- d <- liftIO $ atomicallyNamed " action queue - pop" $ popQueue actionQueue
911- r <- runActionInDb [run d]
912- liftIO $ logResult " pumpActionThread" r
939+ logWith recorder Debug $ LogShakeText (T. pack $ " Starting action" ++ " (step: " <> show step)
940+ d <- runActionInDbCb actionName run (popQueue actionQueue) (logResult " pumpActionThread" . return )
941+ step <- getShakeStep shakeDb
942+ logWith recorder Debug $ LogShakeText (T. pack $ " started action" ++ " (step: " <> show step <> " ): " <> actionName d)
913943 pumpActionThread
914944
915945 -- TODO figure out how to thread the otSpan into defineEarlyCutoff
916- run d = do
946+ run d = do
917947 start <- liftIO offsetTime
918948 getAction d
919949 liftIO $ atomicallyNamed " actionQueue - done" $ doneQueue d actionQueue
920950 runTime <- liftIO start
921951 logWith recorder (actionPriority d) $ LogDelayedAction d runTime
922952
923953 -- The inferred type signature doesn't work in ghc >= 9.0.1
924- workRun :: (forall b . IO b -> IO b ) -> IO ()
925- workRun restore = withSpan " Shake session" $ \ otSpan -> do
954+ -- workRun :: (forall b. IO b -> IO b) -> IO ()
955+ workRun start restore = withSpan " Shake session" $ \ otSpan -> do
926956 setTag otSpan " reason" (fromString reason)
927957 setTag otSpan " queue" (fromString $ unlines $ map actionName reenqueued)
928958 whenJust allPendingKeys $ \ kk -> setTag otSpan " keys" (BS8. pack $ unlines $ map show $ toListKeySet kk)
929- let keysActs = pumpActionThread : map run (reenqueued ++ acts)
930- res <- try @ SomeException $
931- restore $ shakeRunDatabaseForKeys (toListKeySet <$> allPendingKeys) shakeDb keysActs
932- logWith recorder Debug $ LogBuildSessionFinish step $ res
959+ res <- try @ SomeException $ restore start
960+ logWith recorder Debug $ LogBuildSessionFinish step res
933961
962+
963+ let keysActs = pumpActionThread : map run (reenqueued ++ acts)
964+ -- first we increase the step, so any actions started from here on
965+ start <- shakeRunDatabaseForKeysSep (toListKeySet <$> allPendingKeys) shakeDb keysActs
934966 -- Do the work in a background thread
935967 parentTid <- myThreadId
936968 workThread <- asyncWithUnmask $ \ x -> do
937969 childThreadId <- myThreadId
938970 logWith recorder Info $ LogShakeText (" Starting shake thread: " <> T. pack (show childThreadId) <> " (parent: " <> T. pack (show parentTid) <> " )" )
939- workRun x
940-
971+ workRun start x
941972
942973 -- Cancelling is required to flush the Shake database when either
943974 -- the filesystem or the Ghc configuration have changed
@@ -949,7 +980,7 @@ newSession recorder extras@ShakeExtras{..} vfsMod shakeDb acts reason = do
949980 cancelWith workThread $ AsyncParentKill tid step
950981 shakeShutDatabase shakeDb
951982
952-
983+ -- should wait until the step has increased
953984 pure (ShakeSession {.. })
954985
955986instantiateDelayedAction
0 commit comments