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
- - - - -
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.