diff options
author | Bartosz Nitka <niteria@gmail.com> | 2017-05-31 10:47:03 -0700 |
---|---|---|
committer | Bartosz Nitka <niteria@gmail.com> | 2017-07-18 05:27:01 -0700 |
commit | b8fec6950ad99cbf11cd22698b8d5ab35afb828f (patch) | |
tree | da026b84ac5cfbf34c910d526fda9e106298cccb /compiler/main/GhcMake.hs | |
parent | 935acb6f0de36822b46f8444199dbc37de784af4 (diff) | |
download | haskell-b8fec6950ad99cbf11cd22698b8d5ab35afb828f.tar.gz |
Make module membership on ModuleGraph faster
When loading/reloading with a large number of modules
(>5000) the cost of linear lookups becomes significant.
The changes here made `:reload` go from 6s to 1s on my
test case.
The bottlenecks were `needsLinker` in `DriverPipeline` and
`getModLoop` in `GhcMake`.
Test Plan: ./validate
Reviewers: simonmar, austin, bgamari
Subscribers: thomie, rwbarton
Differential Revision: https://phabricator.haskell.org/D3703
Diffstat (limited to 'compiler/main/GhcMake.hs')
-rw-r--r-- | compiler/main/GhcMake.hs | 73 |
1 files changed, 49 insertions, 24 deletions
diff --git a/compiler/main/GhcMake.hs b/compiler/main/GhcMake.hs index f4ea4de28d..f4a9a319ac 100644 --- a/compiler/main/GhcMake.hs +++ b/compiler/main/GhcMake.hs @@ -138,9 +138,11 @@ depanal excluded_mods allow_dup_roots = do -- cached finder data. liftIO $ flushFinderCaches hsc_env - mod_graphE <- liftIO $ downsweep hsc_env old_graph + mod_summariesE <- liftIO $ downsweep hsc_env (mgModSummaries old_graph) excluded_mods allow_dup_roots - mod_graph <- reportImportErrors mod_graphE + mod_summaries <- reportImportErrors mod_summariesE + + let mod_graph = mkModuleGraph mod_summaries warnMissingHomeModules hsc_env mod_graph @@ -193,7 +195,7 @@ warnMissingHomeModules hsc_env mod_graph = is_my_target _ _ = False missing = map (moduleName . ms_mod) $ - filter (not . is_known_module) mod_graph + filter (not . is_known_module) (mgModSummaries mod_graph) msg | gopt Opt_BuildingCabalPackage dflags @@ -253,7 +255,7 @@ load' how_much mHscMessage mod_graph = do -- (see msDeps) let all_home_mods = mkUniqSet [ ms_mod_name s - | s <- mod_graph, not (isBootSummary s)] + | s <- mgModSummaries mod_graph, not (isBootSummary s)] -- TODO: Figure out what the correct form of this assert is. It's violated -- when you have HsBootMerge nodes in the graph: then you'll have hs-boot -- files without corresponding hs files. @@ -422,7 +424,7 @@ load' how_much mHscMessage mod_graph = do let no_hs_main = gopt Opt_NoHsMain dflags let main_mod = mainModIs dflags - a_root_is_Main = any ((==main_mod).ms_mod) mod_graph + a_root_is_Main = mgElemModule mod_graph main_mod do_linking = a_root_is_Main || no_hs_main || ghcLink dflags == LinkDynLib || ghcLink dflags == LinkStaticLib -- link everything together @@ -543,8 +545,7 @@ guessOutputFile = modifySession $ \env -> !mod_graph = hsc_mod_graph env mainModuleSrcPath :: Maybe String mainModuleSrcPath = do - let isMain = (== mainModIs dflags) . ms_mod - [ms] <- return (filter isMain mod_graph) + ms <- mgLookupModule mod_graph (mainModIs dflags) ml_hs_file (ms_location ms) name = fmap dropExtension mainModuleSrcPath @@ -889,13 +890,19 @@ parUpsweep n_jobs mHscMessage old_hpt stable_mods cleanup sccs = do -- The list of all loops in the compilation graph. -- NB: For convenience, the last module of each loop (aka the module that -- finishes the loop) is prepended to the beginning of the loop. - let comp_graph_loops = go (map fstOf3 (reverse comp_graph)) + let graph = map fstOf3 (reverse comp_graph) + boot_modules = mkModuleSet [ms_mod ms | ms <- graph, isBootSummary ms] + comp_graph_loops = go graph boot_modules where - go [] = [] - go (ms:mss) | Just loop <- getModLoop ms (ms:mss) - = map mkBuildModule (ms:loop) : go mss - | otherwise - = go mss + remove ms bm + | isBootSummary ms = delModuleSet bm (ms_mod ms) + | otherwise = bm + go [] _ = [] + go mg@(ms:mss) boot_modules + | Just loop <- getModLoop ms mg (`elemModuleSet` boot_modules) + = map mkBuildModule (ms:loop) : go mss (remove ms boot_modules) + | otherwise + = go mss (remove ms boot_modules) -- Build a Map out of the compilation graph with which we can efficiently -- look up the result MVar associated with a particular home module. @@ -1236,12 +1243,22 @@ upsweep upsweep mHscMessage old_hpt stable_mods cleanup sccs = do dflags <- getSessionDynFlags - (res, done) <- upsweep' old_hpt [] sccs 1 (length sccs) + (res, done) <- upsweep' old_hpt emptyMG sccs 1 (length sccs) (unitIdsToCheck dflags) done_holes - return (res, reverse done) + return (res, reverse $ mgModSummaries done) where done_holes = emptyUniqSet + upsweep' + :: GhcMonad m + => HomePackageTable + -> ModuleGraph + -> [SCC ModSummary] + -> Int + -> Int + -> [UnitId] + -> UniqSet ModuleName + -> m (SuccessFlag, ModuleGraph) upsweep' _old_hpt done [] _ _ uids_to_check _ = do hsc_env <- getSession @@ -1319,7 +1336,7 @@ upsweep mHscMessage old_hpt stable_mods cleanup sccs = do old_hpt1 | isBootSummary mod = old_hpt | otherwise = delFromHpt old_hpt this_mod - done' = mod:done + done' = extendMG done mod -- fixup our HomePackageTable after we've finished compiling -- a mutually-recursive loop. We have to do this again @@ -1643,7 +1660,7 @@ Following this fix, GHC can compile itself with --make -O2. reTypecheckLoop :: HscEnv -> ModSummary -> ModuleGraph -> IO HscEnv reTypecheckLoop hsc_env ms graph - | Just loop <- getModLoop ms graph + | Just loop <- getModLoop ms mss appearsAsBoot -- SOME hs-boot files should still -- get used, just not the loop-closer. , let non_boot = filter (\l -> not (isBootSummary l && @@ -1651,11 +1668,18 @@ reTypecheckLoop hsc_env ms graph = typecheckLoop (hsc_dflags hsc_env) hsc_env (map ms_mod_name non_boot) | otherwise = return hsc_env - -getModLoop :: ModSummary -> ModuleGraph -> Maybe [ModSummary] -getModLoop ms graph + where + mss = mgModSummaries graph + appearsAsBoot = (`elemModuleSet` mgBootModules graph) + +getModLoop + :: ModSummary + -> [ModSummary] + -> (Module -> Bool) -- check if a module appears as a boot module in 'graph' + -> Maybe [ModSummary] +getModLoop ms graph appearsAsBoot | not (isBootSummary ms) - , any (\m -> ms_mod m == this_mod && isBootSummary m) graph + , appearsAsBoot this_mod , let mss = reachableBackwards (ms_mod_name ms) graph = Just mss | otherwise @@ -1694,7 +1718,7 @@ reachableBackwards mod summaries topSortModuleGraph :: Bool -- ^ Drop hi-boot nodes? (see below) - -> [ModSummary] + -> ModuleGraph -> Maybe ModuleName -- ^ Root module name. If @Nothing@, use the full graph. -> [SCC ModSummary] @@ -1713,9 +1737,10 @@ topSortModuleGraph -- the a source-import of Foo is an import of Foo -- The resulting graph has no hi-boot nodes, but can be cyclic -topSortModuleGraph drop_hs_boot_nodes summaries mb_root_mod +topSortModuleGraph drop_hs_boot_nodes module_graph mb_root_mod = map (fmap summaryNodeSummary) $ stronglyConnCompG initial_graph where + summaries = mgModSummaries module_graph -- stronglyConnCompG flips the original order, so if we reverse -- the summaries we get a stable topological sort. (graph, lookup_node) = @@ -1999,7 +2024,7 @@ enableCodeGenForTH target nodemap = [ ms | mss <- Map.elems nodemap , Right ms <- mss - , needsTemplateHaskellOrQQ $ [ms] + , isTemplateHaskellOrQQNonBoot ms ] -- find the set of all transitive dependencies of a list of modules. |