Skip to content

Commit f5a540a

Browse files
committed
fix hls-graph test
1 parent 2cc8c97 commit f5a540a

File tree

9 files changed

+132
-184
lines changed

9 files changed

+132
-184
lines changed

ghcide/src/Development/IDE/Core/Rules.hs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -911,20 +911,16 @@ getModSummaryRule displayTHWarning recorder = do
911911
return (Just fp, Just res{msrModSummary = ms})
912912
Nothing -> return (Nothing, Nothing)
913913

914-
generateCore :: Recorder (WithPriority Log) -> RunSimplifier -> NormalizedFilePath -> Action (IdeResult ModGuts)
915-
generateCore recorder runSimplifier file = do
916-
liftIO $ traceEventIO "Generating Core1"
914+
generateCore :: RunSimplifier -> NormalizedFilePath -> Action (IdeResult ModGuts)
915+
generateCore runSimplifier file = do
917916
packageState <- hscEnv <$> use_ GhcSessionDeps file
918-
liftIO $ traceEventIO "Generating Core2"
919917
hsc' <- setFileCacheHook packageState
920-
liftIO $ traceEventIO "Generating Core3"
921918
tm <- use_ TypeCheck file
922-
liftIO $ traceEventIO "Generating Core4"
923919
liftIO $ compileModule runSimplifier hsc' (tmrModSummary tm) (tmrTypechecked tm)
924920

925921
generateCoreRule :: Recorder (WithPriority Log) -> Rules ()
926922
generateCoreRule recorder =
927-
define (cmapWithPrio LogShake recorder) $ \GenerateCore -> generateCore recorder (RunSimplifier True)
923+
define (cmapWithPrio LogShake recorder) $ \GenerateCore -> generateCore (RunSimplifier True)
928924

929925
getModIfaceRule :: Recorder (WithPriority Log) -> Rules ()
930926
getModIfaceRule recorder = defineEarlyCutoff (cmapWithPrio LogShake recorder) $ Rule $ \GetModIface f -> do

ghcide/src/Development/IDE/Core/Shake.hs

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -147,14 +147,14 @@ import Development.IDE.Graph hiding (ShakeValue,
147147
import qualified Development.IDE.Graph as Shake
148148
import Development.IDE.Graph.Database (ShakeDatabase,
149149
shakeComputeToPreserve,
150-
shakeDatabaseReverseDep,
151150
shakeGetActionQueueLength,
152151
shakeGetBuildStep,
153152
shakeGetDatabaseKeys,
154153
shakeNewDatabase,
155154
shakeProfileDatabase,
156155
shakeRunDatabaseForKeysSep,
157-
shakeShutDatabase)
156+
shakeShutDatabase,
157+
shakedatabaseRuntimeRevDep)
158158
import Development.IDE.Graph.Internal.Action (runActionInDbCb)
159159
import Development.IDE.Graph.Internal.Database (AsyncParentKill (AsyncParentKill))
160160
import Development.IDE.Graph.Internal.Types (DBQue, Step (..),
@@ -254,7 +254,8 @@ instance Pretty Log where
254254
[ "Restarting build session due to" <+> pretty (sraReason restartArgs)
255255
, "Restarts num:" <+> pretty (sraCount $ restartArgs)
256256
, "Action Queue:" <+> pretty (map actionName actionQueue)
257-
, "Keys:" <+> pretty (map show $ toListKeySet keyBackLog)
257+
-- , "Keys:" <+> pretty (map show $ toListKeySet keyBackLog)
258+
, "Keys:" <+> pretty (length $ toListKeySet keyBackLog)
258259
, "Current step:" <+> pretty (show step)
259260
, "Aborting previous build session took" <+> pretty (showDuration abortDuration) <+> pretty shakeProfilePath ]
260261
LogBuildSessionRestartTakingTooLong seconds ->
@@ -938,38 +939,30 @@ dynShakeRestart dy = case fromDynamic dy of
938939
Just shakeRestartArgs -> shakeRestartArgs
939940
Nothing -> error "Internal error, dynShakeRestart, got invalid dynamic type"
940941

941-
computePreserveAsyncs :: ShakeDatabase -> Set (Async ())
942-
computePreserveAsyncs shakeDb = mempty
943-
944942
runRestartTask :: Recorder (WithPriority Log) -> MVar IdeState -> ShakeRestartArgs -> IO ()
945943
runRestartTask recorder ideStateVar shakeRestartArgs = do
946944
IdeState {shakeDb, shakeSession, shakeExtras, shakeDatabaseProfile} <- readMVar ideStateVar
947945
withShakeDatabaseValuesLock shakeDb $ do
948-
let prepareRestart sra@ShakeRestartArgs {..} = do
949-
keys <- sraBetweenSessions
950-
-- it is every important to update the dirty keys after we enter the critical section
951-
-- see Note [Housekeeping rule cache and dirty key outside of hls-graph]
952-
atomically $ modifyTVar' (dirtyKeys shakeExtras) $ \x -> foldl' (flip insertKeySet) x keys
953-
-- Check if there is another restart request pending, if so, we run that one too
954-
return (sra, keys)
955946
withMVar'
956947
shakeSession
957948
( \runner -> do
958-
(restartArgs, newDirtyKeys) <- prepareRestart shakeRestartArgs
959-
reverseMap <- shakeDatabaseReverseDep shakeDb
949+
newDirtyKeys <- sraBetweenSessions shakeRestartArgs
950+
reverseMap <- shakedatabaseRuntimeRevDep shakeDb
960951
(preservekvs, allRunning2) <- shakeComputeToPreserve shakeDb $ fromListKeySet newDirtyKeys
961-
-- let (preservekvs, allRunning2) = ([], [])
962952
logWith recorder Debug $ LogPreserveKeys (map fst preservekvs) newDirtyKeys allRunning2 reverseMap
963953
(stopTime, ()) <- duration $ logErrorAfter 10 $ cancelShakeSession runner $ S.fromList $ map snd preservekvs
954+
-- it is every important to update the dirty keys after we enter the critical section
955+
-- see Note [Housekeeping rule cache and dirty key outside of hls-graph]
956+
atomically $ modifyTVar' (dirtyKeys shakeExtras) $ \x -> foldl' (flip insertKeySet) x newDirtyKeys
964957

965958
queue <- atomicallyNamed "actionQueue - peek" $ peekInProgress $ actionQueue shakeExtras
966959
res <- shakeDatabaseProfile shakeDb
967960
backlog <- readTVarIO $ dirtyKeys shakeExtras
968961
-- this log is required by tests
969962
step <- shakeGetBuildStep shakeDb
970963

971-
logWith recorder Info $ LogBuildSessionRestart restartArgs queue backlog stopTime res step
972-
return restartArgs
964+
logWith recorder Info $ LogBuildSessionRestart shakeRestartArgs queue backlog stopTime res step
965+
return shakeRestartArgs
973966
)
974967
-- It is crucial to be masked here, otherwise we can get killed
975968
-- between spawning the new thread and updating shakeSession.
@@ -1069,18 +1062,15 @@ newSession recorder extras@ShakeExtras{..} vfsMod shakeDb acts reason = do
10691062
setTag otSpan "queue" (fromString $ unlines $ map actionName reenqueued)
10701063
whenJust allPendingKeys $ \kk -> setTag otSpan "keys" (BS8.pack $ unlines $ map show $ toListKeySet kk)
10711064
res <- try @SomeException $ restore start
1072-
logWith recorder Debug $ LogBuildSessionFinish step res
1065+
logWith recorder Info $ LogBuildSessionFinish step res
10731066

10741067

10751068
let keysActs = pumpActionThread : map run (reenqueued ++ acts)
10761069
-- first we increase the step, so any actions started from here on
1077-
start <- shakeRunDatabaseForKeysSep (toListKeySet <$> allPendingKeys) shakeDb keysActs
1070+
startDatabase <- shakeRunDatabaseForKeysSep (toListKeySet <$> allPendingKeys) shakeDb keysActs
10781071
-- Do the work in a background thread
1079-
parentTid <- myThreadId
10801072
workThread <- asyncWithUnmask $ \x -> do
1081-
childThreadId <- myThreadId
1082-
-- logWith recorder Info $ LogShakeText ("shake thread: " <> T.pack (show childThreadId) <> " (parent: " <> T.pack (show parentTid) <> ")")
1083-
workRun start x
1073+
workRun startDatabase x
10841074

10851075
-- Cancelling is required to flush the Shake database when either
10861076
-- the filesystem or the Ghc configuration have changed

hls-graph/src/Development/IDE/Graph/Database.hs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ module Development.IDE.Graph.Database(
1414
shakeShutDatabase,
1515
shakeGetActionQueueLength,
1616
shakeComputeToPreserve,
17-
shakeDatabaseReverseDep) where
17+
shakedatabaseRuntimeRevDep) where
1818
import Control.Concurrent.Async (Async)
1919
import Control.Concurrent.STM.Stats (atomically,
2020
readTVarIO)
@@ -81,16 +81,14 @@ shakeRunDatabaseForKeysSep keysChanged (ShakeDatabase lenAs1 as1 db) as2 = do
8181
incDatabase db keysChanged
8282
return $ drop lenAs1 <$> runActions (newKey "root") db (map unvoid as1 ++ as2)
8383

84-
-- shakeDatabaseReverseDep :: ShakeDatabase ->
85-
-- shakeDatabaseReverseDep :: ShakeDatabase -> StmContainers.Map.Map Key KeySet
86-
shakeDatabaseReverseDep :: ShakeDatabase -> IO [(Key, KeySet)]
87-
shakeDatabaseReverseDep (ShakeDatabase _ _ db) =
88-
atomically $ ListT.toList $ SMap.listT (databaseReverseDep db)
89-
-- StmContainers.Map.toList $ databaseReverseDep db
84+
shakedatabaseRuntimeRevDep :: ShakeDatabase -> IO [(Key, KeySet)]
85+
shakedatabaseRuntimeRevDep (ShakeDatabase _ _ db) =
86+
atomically $ ListT.toList $ SMap.listT (databaseRuntimeRevDep db)
9087

9188

9289
-- shakeComputeToPreserve :: ShakeDatabase -> KeySet -> IO (Set (Async ()))
9390
-- shakeComputeToPreserve :: ShakeDatabase -> KeySet -> IO [(Key, Async ())]
91+
shakeComputeToPreserve :: ShakeDatabase -> KeySet -> IO ([(Key, Async ())], [Key])
9492
shakeComputeToPreserve (ShakeDatabase _ _ db) ks = atomically (computeToPreserve db ks)
9593

9694
shakeRunDatabaseForKeys

hls-graph/src/Development/IDE/Graph/Internal/Database.hs

Lines changed: 52 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ newDatabase :: (String -> IO ()) -> DBQue -> Dynamic -> TheRules -> IO Database
5555
newDatabase dataBaseLogger databaseQueue databaseExtra databaseRules = do
5656
databaseStep <- newTVarIO $ Step 0
5757
databaseThreads <- newTVarIO []
58-
databaseValuesLock <- newTVarIO False
58+
databaseValuesLock <- newTVarIO True
5959
databaseValues <- atomically SMap.new
60-
databaseReverseDep <- atomically SMap.new
60+
databaseRuntimeRevDep <- atomically SMap.new
6161
pure Database{..}
6262

6363
-- | Increment the step and mark dirty.
@@ -116,92 +116,65 @@ build pk db stack keys = do
116116
builder :: (Traversable f) => Key -> Database -> Stack -> f Key -> IO (f (Key, Result))
117117
-- builder _ st kk | traceShow ("builder", st,kk) False = undefined
118118
builder pk db stack keys = do
119-
waits <- for keys (\k -> builderOneCoroutine pk skipThread db stack k)
119+
waits <- for keys (\k -> builderOne pk db stack k)
120120
for waits interpreBuildContinue
121-
where skipThread = if length keys == 1 then IsSingleton else NotSingleton
122121

123-
data IsSingletonTask = IsSingleton | NotSingleton
124122
-- the first run should not block
125-
data RunFirst = RunFirst | RunLater deriving stock (Eq, Show)
126123
data BuildContinue = BCContinue (IO (Key, Result)) | BCStop Key Result
127124

128125
interpreBuildContinue :: BuildContinue -> IO (Key, Result)
129126
interpreBuildContinue (BCStop k v) = return (k, v)
130127
interpreBuildContinue (BCContinue ioR) = ioR
131128

132-
-- possible improvements:
133-
-- suppose it is in the direct dirty set. We have already recorded the parent key as its reverse dep.
134-
-- fource possible situation
135-
-- running stage1, we have line up the run but it is scheduled after the restart. Clean.
136-
-- running stage2, all of it have gone before the restart. Dirty
137-
-- clean or exception, we picked old value. Dirty
138-
-- dirty, impossible situation, should throw errors.
139-
140-
-- stage 1 to stage 2 transition, run in serial
141-
142-
-- first we marked we have reached stage2, annotate the current step
143-
-- then spawn the thread to do the actual work
144-
-- finally, catch any (async) exception and mark the key as exception
145-
146-
-- submmittBuildInDb :: Database -> IO a -> IO a
147-
-- submmittBuildInDb :: Database -> Stack -> Key -> Maybe Result -> IO ()
148-
-- submmittBuildInDb db stack id s = do
149-
-- uninterruptibleMask_ $ do
150-
-- do
151-
-- curStep <- readTVarIO $ databaseStep db
152-
-- startBarrier <- newEmptyTMVarIO
153-
-- newAsync <-
154-
-- async
155-
-- (do
156-
-- uninterruptibleMask_ $ atomically $ readTMVar startBarrier
157-
-- void (refresh db stack id s) `catch` \e@(SomeException _) ->
158-
-- atomically $ SMap.focus (updateStatus $ Exception curStep e s) id (databaseValues db)
159-
-- )
160-
-- -- todo should only update if still at stage 1
161-
-- -- atomically $ SMap.focus (updateStatus $ Running curStep s $ RunningStage2 newAsync) id (databaseValues db)
162-
-- atomically $ putTMVar startBarrier ()
163-
-- atomically $ modifyTVar' (databaseThreads db) ((newAsync) :)
164-
165-
builderOneCoroutine :: Key -> IsSingletonTask -> Database -> Stack -> Key -> IO BuildContinue
166-
builderOneCoroutine parentKey isSingletonTask db stack id =
167-
builderOneCoroutine' db stack id
168-
where
169-
builderOneCoroutine' :: Database -> Stack -> Key -> IO BuildContinue
170-
builderOneCoroutine' db@Database {..} stack id = do
171-
traceEvent ("builderOne: " ++ show id) return ()
172-
barrier <- newEmptyMVar
173-
liftIO $ atomicallyNamed "builder" $ do
174-
-- Spawn the id if needed
175-
dbNotLocked db
176-
insertDatabaseReverseDepOne id parentKey db
177-
-- if a build is running, wait
178-
-- it will either be killed or continue
179-
-- depending on wether it is marked as dirty
180-
status <- SMap.lookup id databaseValues
181-
current <- readTVar databaseStep
182-
case viewDirty current $ maybe (Dirty Nothing) keyStatus status of
183-
Dirty s -> do
184-
-- we need to run serially to avoid summiting run but killed in the middle
185-
let wait = readMVar barrier
186-
runOneInDataBase (do {
187-
status <- atomically (SMap.lookup id databaseValues)
188-
; let cur = fromIntegral $ case keyStatus <$> status of
189-
Just (Running entryStep _s _wait RunningStage1) -> entryStep
190-
_ -> current
191-
; return $ DeliverStatus cur (show (parentKey, id))}) db
192-
(\adyncH ->
193-
-- it is safe from worker thread
194-
atomically $ SMap.focus (updateStatus $ Running current s wait (RunningStage2 adyncH) ) id databaseValues)
195-
(refresh db stack id s >>= putMVar barrier . (id,)) $ \e -> do
196-
atomically $ SMap.focus (updateStatus $ Exception current e s) id databaseValues
197-
putMVar barrier (throw e)
198-
SMap.focus (updateStatus $ Running current s wait RunningStage1) id databaseValues
199-
return $ BCContinue $ readMVar barrier
200-
Clean r -> return $ BCStop id r
201-
Running _step _s wait _
202-
| memberStack id stack -> throw $ StackException stack
203-
| otherwise -> return $ BCContinue wait
204-
Exception _ e _s -> throw e
129+
builderOne :: Key -> Database -> Stack -> Key -> IO BuildContinue
130+
builderOne parentKey db@Database {..} stack id = do
131+
traceEvent ("builderOne: " ++ show id) return ()
132+
barrier <- newEmptyMVar
133+
liftIO $ atomicallyNamed "builder" $ do
134+
-- Spawn the id if needed
135+
dbNotLocked db
136+
insertdatabaseRuntimeRevDep id parentKey db
137+
-- if a build is running, wait
138+
-- it will either be killed or continue
139+
-- depending on wether it is marked as dirty
140+
status <- SMap.lookup id databaseValues
141+
current <- readTVar databaseStep
142+
case viewDirty current $ maybe (Dirty Nothing) keyStatus status of
143+
Dirty s -> do
144+
-- we need to run serially to avoid summiting run but killed in the middle
145+
let wait = readMVar barrier
146+
runOneInDataBase
147+
( do
148+
status <- atomically (SMap.lookup id databaseValues)
149+
let cur = fromIntegral $ case keyStatus <$> status of
150+
-- this is ensure that we get an bumped up step when not dirty
151+
-- after an restart to skipped an rerun
152+
Just (Running entryStep _s _wait RunningStage1) -> entryStep
153+
_ -> current
154+
return $ DeliverStatus cur (show (parentKey, id))
155+
)
156+
db
157+
( \adyncH ->
158+
-- it is safe from worker thread
159+
atomically $ SMap.focus (updateStatus $ Running current s wait (RunningStage2 adyncH)) id databaseValues
160+
)
161+
(refresh db stack id s >>= putMVar barrier . (id,))
162+
$ \e -> do
163+
atomically $ SMap.focus (updateStatus $ Exception current e s) id databaseValues
164+
putMVar barrier (throw e)
165+
SMap.focus (updateStatus $ Running current s wait RunningStage1) id databaseValues
166+
return $ BCContinue $ readMVar barrier
167+
Clean r -> return $ BCStop id r
168+
Running _step _s wait _
169+
| memberStack id stack -> throw $ StackException stack
170+
| otherwise -> return $ BCContinue wait
171+
Exception _ e _s -> throw e
172+
where
173+
warpLog title a =
174+
bracket_
175+
(dataBaseLogger ("Starting async action: " ++ title))
176+
(dataBaseLogger $ "Finished async action: " ++ title)
177+
a
205178

206179
-- | isDirty
207180
-- only dirty when it's build time is older than the changed time of one of its dependencies
@@ -285,11 +258,6 @@ updateStatus res = Focus.alter
285258
(Just . maybe (KeyDetails res mempty)
286259
(\it -> it{keyStatus = res}))
287260

288-
-- alterStatus :: Monad m => (Status -> Status) -> Focus.Focus KeyDetails m ()
289-
-- alterStatus f = Focus.alter
290-
-- (Just . maybe (KeyDetails res mempty)
291-
-- (\it -> it{keyStatus = res}))
292-
293261
-- | Returns the set of dirty keys annotated with their age (in # of builds)
294262
getDirtySet :: Database -> IO [(Key, Int)]
295263
getDirtySet db = do

0 commit comments

Comments
 (0)