nixpkgs/pkgs/top-level/metrics.nix
Philip Taron a16d821514
pkgs/top-level/metrics.nix: fix the jq to count derivations
As can be seen on https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qaCountBroken the logic is counting `null` entries today.

I introduced this regression in dfd90bf4c0
2025-09-18 11:17:49 -07:00

223 lines
8.8 KiB
Nix

{ nixpkgs, pkgs }:
let
inherit (pkgs) lib stdenvNoCC;
evalSystem = "x86_64-linux";
in
stdenvNoCC.mkDerivation {
name = "nixpkgs-metrics";
# Use structured attrs to pass in relevant information.
__structuredAttrs = true;
inherit evalSystem nixpkgs;
outputs = [
"out"
"raw"
];
nativeBuildInputs = map lib.getBin [
pkgs.nixVersions.latest
pkgs.time
pkgs.jq
];
# see https://github.com/NixOS/nixpkgs/issues/52436
#requiredSystemFeatures = [ "benchmark" ]; # dedicated `t2a` machine, by @vcunat
# Required because this derivation doesn't have a `src`.
dontUnpack = true;
configurePhase = ''
runHook preConfigure
export NIX_STORE_DIR=$TMPDIR/store
export NIX_STATE_DIR=$TMPDIR/state
export NIX_PAGER=
nix-store --init
runHook postConfigure
'';
buildPhase = ''
runHook preBuild
release="$nixpkgs/nixos/release.nix"
run() {
local name="$1"
shift
echo "running $@"
mkdir -p "metrics/$name"
local output="metrics/$name/output"
local nix_stats="metrics/$name/nix-stats.json"
local time_stats="metrics/$name/time-stats.json"
NIX_SHOW_STATS=1 NIX_SHOW_STATS_PATH="$nix_stats" command time -o "$time_stats" -- "$@" > "$output"
# Show the Nix statistics and the `time` statistics.
echo "Nix statistics for $@"
jq . "$nix_stats"
echo
echo "Time statistics for $@"
jq . "$time_stats"
echo
cpuTime="$(jq '.cpuTime' < "$nix_stats")"
[[ -n $cpuTime ]] || exit 1
echo "$name.time $cpuTime s" >> hydra-metrics
maxresident="$(jq '.max_resident_set_kb' < "$time_stats")"
[[ -n $maxresident ]] || exit 1
echo "$name.maxresident $maxresident KiB" >> hydra-metrics
# Nix also outputs `.symbols.bytes` but since that wasn't summed originally, we don't count it here.
allocations="$(jq '[.envs,.list,.values,.sets] | map(.bytes) | add' < "$nix_stats")"
[[ -n $allocations ]] || exit 1
echo "$name.allocations $allocations B" >> hydra-metrics
values="$(jq '.values.number' < "$nix_stats")"
[[ -n $values ]] || exit 1
echo "$name.values $values" >> hydra-metrics
}
run nixos.smallContainer nix-instantiate --option eval-system "$evalSystem" --dry-run "$release" -A closures.smallContainer.x86_64-linux --show-trace --no-gc-warning
run nixos.kde nix-instantiate --option eval-system "$evalSystem" --dry-run "$release" -A closures.kde.x86_64-linux --show-trace --no-gc-warning
run nixos.lapp nix-instantiate --option eval-system "$evalSystem" --dry-run "$release" -A closures.lapp.x86_64-linux --show-trace --no-gc-warning
run nix-env.qa nix-env --option eval-system "$evalSystem" -f "$nixpkgs" -qa
run nix-env.qaDrv nix-env --option eval-system "$evalSystem" -f "$nixpkgs" -qa --drv-path --meta --json
# It's slightly unclear which of the set to track: qaCount, qaCountDrv, qaCountBroken.
num="$(wc -l < metrics/nix-env.qa/output)"
echo "nix-env.qaCount $num" >> hydra-metrics
qaCountDrv="$(jq -r 'reduce (.[].drvPath? // empty) as $d (0; .+1)' metrics/nix-env.qaDrv/output)"
numBroken="$((num - $qaCountDrv))"
echo "nix-env.qaCountBroken $numBroken" >> hydra-metrics
lines="$(find "$nixpkgs" -name "*.nix" -type f -print0 | xargs -0 cat | wc -l)"
echo "loc $lines" >> hydra-metrics
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir -p $out/nix-support
touch $out/nix-support/hydra-build-products
mv hydra-metrics $out/nix-support/hydra-metrics
# Save and compress the raw output
mv metrics $raw
xz -v $raw/*/output
runHook postInstall
'';
meta = {
description = "Metrics tracked by Hydra about Nixpkgs";
homepage = "https://hydra.nixos.org/job/nixpkgs/trunk/metrics";
longDescription = ''
View the metrics for Nixpkgs evaluation over time at these URLs.
These are all produced from running `nix` with `NIX_SHOW_STATS=1`.
See `EvalState::printStatistics` in the Nix source code for the implementation.
None of these metrics are inherently meaningful on their own.
Exercise caution in interpreting them as "bad" or "good".
# Total repository statistics
- [Lines of code in Nixpkgs](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/loc)
- [Count of broken packages using `nix-env -qa`](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qaCountBroken)
- [Count of packages using `nix-env -qa`](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qaCount)
# Statistics about representative commands
These are statistics gathered by running commands against Nixpkgs.
| Name | Command |
|------|---------|
| `nix-env.qaDrv` | `nix-env -f ${nixpkgs} -qa --drv-path --meta --json` |
| `nix-env.qa` | `nix-env -f ${nixpkgs} -qa` |
| `nixos.kde` | `nix-instantiate --dry-run ${nixpkgs}/nixos/release.nix -A closures.kde.x86_64-linux --show-trace` |
| `nixos.lapp` | `nix-instantiate --dry-run ${nixpkgs}/nixos/release.nix -A closures.lapp.x86_64-linux --show-trace` |
| `nixos.smallContainer` | `nix-instantiate --dry-run ${nixpkgs}/nixos/release.nix -A closures.smallContainer.x86_64-linux --show-trace`|
## Allocations performed (in bytes)
This counts `envs.bytes`, `list.bytes`, `values.bytes`, and `sets.bytes` from the Nix statistics.
- [nix-env.qa.allocations](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qa.allocations)
- [nix-env.qaDrv.allocations](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qaDrv.allocations)
- [nixos.kde.allocations](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.kde.allocations)
- [nixos.lapp.allocations](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.lapp.allocations)
- [nixos.smallContainer.allocations](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.smallContainer.allocations)
## Maximum resident size (in number of KiB)
This counts `maxresident` KiB (`%M`) from the `time` command on Linux.
- [nix-env.qa.maxresident](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qa.maxresident)
- [nix-env.qaDrv.maxresident](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qaDrv.maxresident)
- [nixos.kde.maxresident](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.kde.maxresident)
- [nixos.lapp.maxresident](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.lapp.maxresident)
- [nixos.smallContainer.maxresident](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.smallContainer.maxresident)
## Time taken (in seconds)
This counts `cpuTime` as reported in the Nix statistics. On Linux, this resolves to [`getrusage(RUSAGE_SELF)`](https://man7.org/linux/man-pages/man2/getrusage.2.html).
- [nix-env.qa.time](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qa.time)
- [nix-env.qaDrv.time](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qaDrv.time)
- [nixos.kde.time](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.kde.time)
- [nixos.lapp.time](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.lapp.time)
- [nixos.smallContainer.time](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.smallContainer.time)
## Number of values
This counts the total number of values allocated in Nix (see `EvalState::allocValue` in the Nix source code).
- [nix-env.qa.values](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qa.values)
- [nix-env.qaDrv.values](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qaDrv.values)
- [nixos.kde.values](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.kde.values)
- [nixos.lapp.values](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.lapp.values)
- [nixos.smallContainer.values](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.smallContainer.values)
'';
};
# Convince `time` to output in JSON
env.TIME = builtins.toJSON {
real_time = "%e";
user_time = "%U";
sys_time = "%S";
cpu_percent = "%P";
max_resident_set_kb = "%M";
avg_resident_set_kb = "%t";
avg_total_mem_kb = "%K";
avg_data_kb = "%D";
avg_stack_kb = "%p";
avg_unshared_data_kb = "%X";
avg_shared_text_kb = "%Z";
page_faults_major = "%F";
page_faults_minor = "%R";
swaps = "%W";
context_switches_voluntary = "%c";
context_switches_involuntary = "%w";
io_reads = "%I";
io_writes = "%O";
signals_received = "%k";
exit_status = "%x";
command = "%C";
};
# Don't allow aliases anywhere in Nixpkgs for the metrics.
env.NIXPKGS_CONFIG = builtins.toFile "nixpkgs-config.nix" ''
{
allowAliases = false;
}
'';
}