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.

Changed files
+30 -2
lib
pkgs
development
haskell-modules
+30 -1
lib/deprecated.nix
···
}
);
-
closePropagation = list: (uniqList {inputList = (innerClosePropagation [] list);});
+
closePropagationSlow = list: (uniqList {inputList = (innerClosePropagation [] list);});
+
+
# This is an optimisation of lib.closePropagation which avoids the O(n^2) behavior
+
# Using a list of derivations, it generates the full closure of the propagatedXXXBuildInputs
+
# The ordering / sorting / comparison is done based on the `outPath`
+
# attribute of each derivation.
+
# On some benchmarks, it performs up to 15 times faster than lib.closePropagation.
+
# See https://github.com/NixOS/nixpkgs/pull/194391 for details.
+
closePropagationFast = list:
+
builtins.map (x: x.val) (builtins.genericClosure {
+
startSet = builtins.map (x: {
+
key = x.outPath;
+
val = x;
+
}) (builtins.filter (x: x != null) list);
+
operator = item:
+
if !builtins.isAttrs item.val then
+
[ ]
+
else
+
builtins.concatMap (x:
+
if x != null then [{
+
key = x.outPath;
+
val = x;
+
}] else
+
[ ]) ((item.val.propagatedBuildInputs or [ ])
+
++ (item.val.propagatedNativeBuildInputs or [ ]));
+
});
+
+
closePropagation = if builtins ? genericClosure
+
then closePropagationFast
+
else closePropagationSlow;
# calls a function (f attr value ) for each record item. returns a list
mapAttrsFlatten = f: r: map (attr: f attr r.${attr}) (attrNames r);
-1
pkgs/development/haskell-modules/hoogle.nix
···
This index includes documentation for many Haskell modules.
'';
-
# TODO: closePropagation is deprecated; replace
docPackages = lib.closePropagation
# we grab the doc outputs
(map (lib.getOutput "doc") packages);