lib.meta: Avoid attrset allocation in platformMatch

Benchmarks (`nix-instantiate ./. -A python3`)

- Before
``` json
{
  "cpuTime": 0.30625399947166443,
  "envs": {
    "bytes": 4484216,
    "elements": 221443,
    "number": 169542
  },
  "gc": {
    "heapSize": 402915328,
    "totalBytes": 53091024
  },
  "list": {
    "bytes": 749424,
    "concats": 4242,
    "elements": 93678
  },
  "nrAvoided": 253991,
  "nrFunctionCalls": 149848,
  "nrLookups": 49614,
  "nrOpUpdateValuesCopied": 1588326,
  "nrOpUpdates": 10106,
  "nrPrimOpCalls": 130356,
  "nrThunks": 359013,
  "sets": {
    "bytes": 30432320,
    "elements": 1860540,
    "number": 41480
  },
  "sizes": {
    "Attr": 16,
    "Bindings": 16,
    "Env": 16,
    "Value": 24
  },
  "symbols": {
    "bytes": 236218,
    "number": 24459
  },
  "values": {
    "bytes": 10504632,
    "number": 437693
  }
}
```

- After
```
{
  "cpuTime": 0.29695799946784973,
  "envs": {
    "bytes": 3296712,
    "elements": 169055,
    "number": 121517
  },
  "gc": {
    "heapSize": 402915328,
    "totalBytes": 49044992
  },
  "list": {
    "bytes": 504928,
    "concats": 4242,
    "elements": 63116
  },
  "nrAvoided": 175403,
  "nrFunctionCalls": 110554,
  "nrLookups": 44907,
  "nrOpUpdateValuesCopied": 1588326,
  "nrOpUpdates": 10106,
  "nrPrimOpCalls": 82330,
  "nrThunks": 306625,
  "sets": {
    "bytes": 29943328,
    "elements": 1843076,
    "number": 28382
  },
  "sizes": {
    "Attr": 16,
    "Bindings": 16,
    "Env": 16,
    "Value": 24
  },
  "symbols": {
    "bytes": 236218,
    "number": 24459
  },
  "values": {
    "bytes": 9037752,
    "number": 376573
  }
}
```
This commit is contained in:
adisbladis 2023-11-25 01:58:52 +13:00
parent 2819a35bf4
commit 4b4d413817
2 changed files with 42 additions and 10 deletions

View file

@ -3,6 +3,11 @@
{ lib }:
let
inherit (lib) matchAttrs any all;
inherit (builtins) isString;
in
rec {
@ -83,14 +88,21 @@ rec {
We can inject these into a pattern for the whole of a structured platform,
and then match that.
*/
platformMatch = platform: elem: let
pattern =
if builtins.isString elem
then { system = elem; }
else if elem?parsed
then elem
else { parsed = elem; };
in lib.matchAttrs pattern platform;
platformMatch = platform: elem: (
# Check with simple string comparison if elem was a string.
#
# The majority of comparisons done with this function will be against meta.platforms
# which contains a simple platform string.
#
# Avoiding an attrset allocation results in significant performance gains (~2-30) across the board in OfBorg
# because this is a hot path for nixpkgs.
if isString elem then platform ? system && elem == platform.system
else matchAttrs (
# Normalize platform attrset.
if elem ? parsed then elem
else { parsed = elem; }
) platform
);
/* Check if a package is available on a given platform.
@ -102,8 +114,8 @@ rec {
2. None of `meta.badPlatforms` pattern matches the given platform.
*/
availableOn = platform: pkg:
((!pkg?meta.platforms) || lib.any (platformMatch platform) pkg.meta.platforms) &&
lib.all (elem: !platformMatch platform elem) (pkg.meta.badPlatforms or []);
((!pkg?meta.platforms) || any (platformMatch platform) pkg.meta.platforms) &&
all (elem: !platformMatch platform elem) (pkg.meta.badPlatforms or []);
/* Get the corresponding attribute in lib.licenses
from the SPDX ID.

View file

@ -1948,4 +1948,24 @@ runTests {
testGetExe'FailureSecondArg = testingThrow (
getExe' { type = "derivation"; } "dir/executable"
);
testPlatformMatch = {
expr = meta.platformMatch { system = "x86_64-linux"; } "x86_64-linux";
expected = true;
};
testPlatformMatchAttrs = {
expr = meta.platformMatch (systems.elaborate "x86_64-linux") (systems.elaborate "x86_64-linux").parsed;
expected = true;
};
testPlatformMatchNoMatch = {
expr = meta.platformMatch { system = "x86_64-darwin"; } "x86_64-linux";
expected = false;
};
testPlatformMatchMissingSystem = {
expr = meta.platformMatch { } "x86_64-linux";
expected = false;
};
}