Commit 6ae8efaf authored by zimbatm's avatar zimbatm
Browse files

splice: replace listToAttrs+map with mapAttrs

listToAttrs forces every list element to extract `.name`, calling merge
eagerly for the entire union of attribute names (~60k). mapAttrs already
knows the keys; the lambda is only invoked when a key is selected,
letting the 99.7% unforced ones stay as untouched thunks.

NIX_SHOW_STATS delta on pkgsCross.aarch64-multiplatform.hello.drvPath:

  nrFunctionCalls:  567,512 -> 507,404   (-10.6%)
  nrThunks:         613,138 -> 552,356   (-9.9%)
  sets.number:      158,787 -> 98,339    (-38.1%)
  list.elements:    295,085 -> 174,189   (-41.0%)
  gc.totalBytes:      117.5M -> 111.7M   (-4.9%)

Repro:

  NIX_SHOW_STATS=1 nix-instantiate --eval \
    -E '(import ./. {}).pkgsCross.aarch64-multiplatform.hello.drvPath' \
    2>stats.json >/dev/null
  jq . stats.json
parent d8c4c60d
Loading
Loading
Loading
Loading
+34 −35
Original line number Diff line number Diff line
@@ -31,11 +31,11 @@ let
        # The same pkgs sets one probably intends
        // inputs.buildHost
        // inputs.hostTarget;
      merge = name: {
        inherit name;
        value =
      # perf: mapAttrs defers merge calls until a key is selected, avoiding
      # ~60k eager closures that listToAttrs+map would create.
      merge =
        name: defaultValue:
        let
            defaultValue = mash.${name};
          # `or {}` is for the non-derivation attsert splicing case, where `{}` is the identity.
          value' = mapCrossIndex (x: x.${name} or { }) inputs;

@@ -65,9 +65,8 @@ let
          # Don't be fancy about non-derivations. But we could have used used
          # `__functor__` for functions instead.
          defaultValue;
      };
    in
    lib.listToAttrs (map merge (lib.attrNames mash));
    builtins.mapAttrs merge mash;

  splicePackages =
    {