[Git][ghc/ghc][master] 2 commits: Make the order of usages deterministic
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC Commits: d216412b by Ian-Woo Kim at 2026-06-16T20:25:57-04:00 Make the order of usages deterministic It has been observed that the ordering of usages can be non-determinstic in parallel builds. Therefore, this contribution introduces sorting of usages based on a platform- and race-independent sorting criterion. Resolves #26877. Co-authored-by: Wolfgang Jeltsch <wolfgang@well-typed.com> - - - - - 8e1cc105 by Wolfgang Jeltsch at 2026-06-16T20:25:57-04:00 Change the descriptions of two existing changelog entries The descriptions now describe the changes in a user-friendly manner, as opposed to describing the contributions that led to these changes in a developer-friendly manner. - - - - - 5 changed files: - + changelog.d/deterministic-usage-order - changelog.d/module-graph-reuse-in-downsweep - changelog.d/more-efficient-home-unit-imports-finding - compiler/GHC/HsToCore/Usage.hs - compiler/GHC/Unit/Module/Deps.hs Changes: ===================================== changelog.d/deterministic-usage-order ===================================== @@ -0,0 +1,8 @@ +section: compiler +synopsis: Make the order of usages deterministic +issues: #26877 +mrs: !15484 +description: { + The order in which usages appear in interface files is now + deterministic. +} ===================================== changelog.d/module-graph-reuse-in-downsweep ===================================== @@ -3,7 +3,7 @@ synopsis: Allow `downsweep` to use nodes of an existing module graph issues: #27054 mrs: !16028 description: { - This contribution enables `downsweep` to use the nodes of a module - graph obtained from a previous downsweeping round, which allows GHC - API applications to build module graphs somewhat incrementally. + The `downsweep` operation can now use the nodes of a module graph + obtained from a previous downsweeping round, which allows GHC API + applications to build module graphs somewhat incrementally. } ===================================== changelog.d/more-efficient-home-unit-imports-finding ===================================== @@ -3,13 +3,10 @@ synopsis: Introduce a cache of home module name providers issues: #27055 mrs: !15888 description: { - This contribution optimizes the algorithm for finding out which home - unit provides the module that a certain import declaration refers - to. The previous approach has been to simply search all home units - in no particular order. This change introduces a cache that allows - for efficiently determining those complete home units that provide a - certain module name and changes the module-finding algorithm such - that it searches these units before the other home units. This leads - to significant performance improvements in situations where there - are lots of home units. + For finding out which home unit provides the module that a certain + import declaration refers to, we now use a better algorithm. The + previous approach was to simply search all home units in no + particular order. The new algorithm first searches those complete + home units that provide a certain module name, before searching the + other home units. } ===================================== compiler/GHC/HsToCore/Usage.hs ===================================== @@ -70,6 +70,8 @@ data UsageConfig = UsageConfig { uc_safe_implicit_imps_req :: !Bool -- ^ Are all implicit imports required to be safe for this Safe Haskell mode? } +-- | Build the list of 'Usage's that drive recompilation checking. +-- The resulting list is deterministically sorted. mkUsageInfo :: UsageConfig -> Plugins -> FinderCache -> UnitEnv -> Module -> ImportedMods -> [ImportUserSpec] -> NameSet -> [FilePath] -> [FilePath] -> [(Module, Fingerprint)] -> [LinkableUsage] -> PkgsLoaded @@ -100,10 +102,10 @@ mkUsageInfo uc plugins fc unit_env } | (mod, hash) <- merged ] ++ object_usages - usages `seqList` return usages - -- seq the list of Usages returned: occasionally these - -- don't get evaluated for a while and we can end up hanging on to - -- the entire collection of Ifaces. + usages `seqList` return (sortBy stableUsageCmp usages) + -- The use of 'seqList' is important because occasionally the returned list + -- is not evaluated for a while, so that with too much laziness here we + -- could end up hanging on to the entire collection of 'Iface's. {- Note [Plugin dependencies] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ===================================== compiler/GHC/Unit/Module/Deps.hs ===================================== @@ -1,5 +1,8 @@ {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE DerivingVia #-} + +{-# OPTIONS_GHC -Wwarn=incomplete-record-selectors #-} + -- | Dependencies and Usage of a module module GHC.Unit.Module.Deps ( Dependencies(dep_direct_mods @@ -17,6 +20,7 @@ module GHC.Unit.Module.Deps , noDependencies , pprDeps , Usage (..) + , stableUsageCmp , HomeModImport (..) , HomeModImportedAvails (..) , ImportAvails (..) @@ -52,6 +56,7 @@ import GHC.Utils.Outputable import Control.DeepSeq import Data.Bifunctor import qualified Data.Foldable as Foldable +import Data.Function (on) import Data.List (sortBy, sort, partition) import Data.Set (Set) import qualified Data.Set as Set @@ -497,6 +502,47 @@ instance Binary Usage where i -> error ("Binary.get(Usage): " ++ show i) +-- | Compares 'Usage's by constructor and, if the constructors are the same, by +-- identifying strings, to achieve a predictable ordering. +stableUsageCmp :: Usage -> Usage -> Ordering +stableUsageCmp + usage1@UsagePackageModule {} + usage2@UsagePackageModule {} + = (compare `on` usg_mod) usage1 usage2 +stableUsageCmp + usage1@UsageHomeModule {} + usage2@UsageHomeModule {} + = (compare `on` Module <$> usg_unit_id <*> usg_mod_name) usage1 usage2 +stableUsageCmp + usage1@UsageFile {} + usage2@UsageFile {} + = (lexicalCompareFS `on` usg_file_path) usage1 usage2 +stableUsageCmp + usage1@UsageDirectory {} + usage2@UsageDirectory {} + = (lexicalCompareFS `on` usg_dir_path) usage1 usage2 +stableUsageCmp + usage1@UsageHomeModuleBytecode {} + usage2@UsageHomeModuleBytecode {} + = (compare `on` Module <$> usg_unit_id <*> usg_mod_name) usage1 usage2 +stableUsageCmp + usage1@UsageMergedRequirement {} + usage2@UsageMergedRequirement {} + = (compare `on` usg_mod) usage1 usage2 +stableUsageCmp + usage1 + usage2 + = (compare `on` constructorIndex) usage1 usage2 + where + + constructorIndex :: Usage -> Int + constructorIndex UsagePackageModule {} = 0 + constructorIndex UsageHomeModule {} = 1 + constructorIndex UsageFile {} = 2 + constructorIndex UsageDirectory {} = 3 + constructorIndex UsageHomeModuleBytecode {} = 4 + constructorIndex UsageMergedRequirement {} = 5 + -- | Records the imports that we depend on from a home module, -- for recompilation checking. -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/a3fa10e0c93a58f46815c4fab7522f4... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/a3fa10e0c93a58f46815c4fab7522f4... You're receiving this email because of your account on gitlab.haskell.org.
participants (1)
-
Marge Bot (@marge-bot)