lib.closePropagation: Remove the quadratic behavior in lib.closePropagation

The code of `lib.closePropagation` was internally using a
recursion on the dependencies and returns all the derivation directly or
indirectly referenced by buildInputs.

`lib.closeProgation` is implemented in pure nix and uses an unique
function for list which is quadratic and does "true" equality, which
needs deep set comparison.

Instead, we use the `builtins.genericClosure` which is implemented as a
builtin and uses a more efficient sorting feature.

Note that `genericClosure` needs a `key` to discriminate the values, we
used the `outPath` which is unique and orderable.

On benchmarks, it performs up to 15x time faster on a benchmark related
to haskellPackages.ghcWithPackages.

+30 -2
+30 -1
lib/deprecated.nix
··· 157 157 } 158 158 ); 159 159 160 - closePropagation = list: (uniqList {inputList = (innerClosePropagation [] list);}); 160 + closePropagationSlow = list: (uniqList {inputList = (innerClosePropagation [] list);}); 161 + 162 + # This is an optimisation of lib.closePropagation which avoids the O(n^2) behavior 163 + # Using a list of derivations, it generates the full closure of the propagatedXXXBuildInputs 164 + # The ordering / sorting / comparison is done based on the `outPath` 165 + # attribute of each derivation. 166 + # On some benchmarks, it performs up to 15 times faster than lib.closePropagation. 167 + # See https://github.com/NixOS/nixpkgs/pull/194391 for details. 168 + closePropagationFast = list: 169 + builtins.map (x: x.val) (builtins.genericClosure { 170 + startSet = builtins.map (x: { 171 + key = x.outPath; 172 + val = x; 173 + }) (builtins.filter (x: x != null) list); 174 + operator = item: 175 + if !builtins.isAttrs item.val then 176 + [ ] 177 + else 178 + builtins.concatMap (x: 179 + if x != null then [{ 180 + key = x.outPath; 181 + val = x; 182 + }] else 183 + [ ]) ((item.val.propagatedBuildInputs or [ ]) 184 + ++ (item.val.propagatedNativeBuildInputs or [ ])); 185 + }); 186 + 187 + closePropagation = if builtins ? genericClosure 188 + then closePropagationFast 189 + else closePropagationSlow; 161 190 162 191 # calls a function (f attr value ) for each record item. returns a list 163 192 mapAttrsFlatten = f: r: map (attr: f attr r.${attr}) (attrNames r);
-1
pkgs/development/haskell-modules/hoogle.nix
··· 36 36 This index includes documentation for many Haskell modules. 37 37 ''; 38 38 39 - # TODO: closePropagation is deprecated; replace 40 39 docPackages = lib.closePropagation 41 40 # we grab the doc outputs 42 41 (map (lib.getOutput "doc") packages);