Hannes Siebenhandl pushed to branch wip/fendor/ghc-pkg-faster-closure at Glasgow Haskell Compiler / GHC

Commits:

2 changed files:

Changes:

  • changelog.d/ghc-pkg-faster-closure
    1
    +section: ghc-pkg
    
    2
    +synopsis: Improve performance of `ghc-pkg list` command
    
    3
    +issues: #27275
    
    4
    +mrs: !16062
    
    5
    +
    
    6
    +description: {
    
    7
    +`ghc-pkg list` was quadratic in the number of packages due to an inefficient `closure` computation.
    
    8
    +We cache the set of seen packages, allowing us to speed up the `closure` computation, improving run-time
    
    9
    +for the commands `list`, `check`, `distrust`, `expose`, `hide`, `trust` and `unregister`.
    
    10
    +}

  • utils/ghc-pkg/Main.hs
    ... ... @@ -1847,21 +1847,28 @@ checkConsistency verbosity my_flags = do
    1847 1847
     
    
    1848 1848
     closure :: [InstalledPackageInfo] -> [InstalledPackageInfo]
    
    1849 1849
             -> ([InstalledPackageInfo], [InstalledPackageInfo])
    
    1850
    -closure pkgs db_stack = go pkgs db_stack
    
    1851
    - where
    
    1852
    -   go avail not_avail =
    
    1853
    -     case partition (depsAvailable avail) not_avail of
    
    1854
    -        ([],        not_avail') -> (avail, not_avail')
    
    1855
    -        (new_avail, not_avail') -> go (new_avail ++ avail) not_avail'
    
    1856
    -
    
    1857
    -   depsAvailable :: [InstalledPackageInfo] -> InstalledPackageInfo
    
    1858
    -                 -> Bool
    
    1859
    -   depsAvailable pkgs_ok pkg = null dangling
    
    1860
    -        where dangling = filter (`notElem` pids) (depends pkg)
    
    1861
    -              pids = map installedUnitId pkgs_ok
    
    1862
    -
    
    1863
    -        -- we want mutually recursive groups of package to show up
    
    1864
    -        -- as broken. (#1750)
    
    1850
    +closure pkgs db_stack = go (pkgs, pkg_ids) db_stack
    
    1851
    +  where
    
    1852
    +    pkg_ids = Set.fromList $ map installedUnitId pkgs
    
    1853
    +    go (avail, avail_ids) not_avail =
    
    1854
    +      case partition (depsAvailable avail_ids) not_avail of
    
    1855
    +        ([],        not_avail') ->
    
    1856
    +          (avail, not_avail')
    
    1857
    +        (new_avail, not_avail') ->
    
    1858
    +          let
    
    1859
    +            all_pkg_ids =
    
    1860
    +              foldl' (flip Set.insert) avail_ids (map installedUnitId new_avail)
    
    1861
    +          in
    
    1862
    +            go (new_avail ++ avail, all_pkg_ids) not_avail'
    
    1863
    +
    
    1864
    +
    
    1865
    +    depsAvailable :: Set.Set UnitId -> InstalledPackageInfo
    
    1866
    +                  -> Bool
    
    1867
    +    depsAvailable pids pkg = null dangling
    
    1868
    +      where dangling = filter (`Set.notMember` pids) (depends pkg)
    
    1869
    +
    
    1870
    +      -- we want mutually recursive groups of package to show up
    
    1871
    +      -- as broken. (#1750)
    
    1865 1872
     
    
    1866 1873
     brokenPackages :: [InstalledPackageInfo] -> [InstalledPackageInfo]
    
    1867 1874
     brokenPackages pkgs = snd (closure [] pkgs)