1{ nixpkgs, pkgs }: 2 3let 4 inherit (pkgs) lib stdenvNoCC; 5 evalSystem = "x86_64-linux"; 6in 7 8stdenvNoCC.mkDerivation { 9 name = "nixpkgs-metrics"; 10 11 # Use structured attrs to pass in relevant information. 12 __structuredAttrs = true; 13 inherit evalSystem nixpkgs; 14 15 outputs = [ 16 "out" 17 "raw" 18 ]; 19 20 nativeBuildInputs = map lib.getBin [ 21 pkgs.nixVersions.latest 22 pkgs.time 23 pkgs.jq 24 ]; 25 26 # see https://github.com/NixOS/nixpkgs/issues/52436 27 #requiredSystemFeatures = [ "benchmark" ]; # dedicated `t2a` machine, by @vcunat 28 29 # Required because this derivation doesn't have a `src`. 30 dontUnpack = true; 31 32 configurePhase = '' 33 runHook preConfigure 34 35 export NIX_STORE_DIR=$TMPDIR/store 36 export NIX_STATE_DIR=$TMPDIR/state 37 export NIX_PAGER= 38 nix-store --init 39 40 runHook postConfigure 41 ''; 42 43 buildPhase = '' 44 runHook preBuild 45 46 release="$nixpkgs/nixos/release.nix" 47 48 run() { 49 local name="$1" 50 shift 51 52 echo "running $@" 53 54 mkdir -p "metrics/$name" 55 local output="metrics/$name/output" 56 local nix_stats="metrics/$name/nix-stats.json" 57 local time_stats="metrics/$name/time-stats.json" 58 59 NIX_SHOW_STATS=1 NIX_SHOW_STATS_PATH="$nix_stats" command time -o "$time_stats" -- "$@" > "$output" 60 61 # Show the Nix statistics and the `time` statistics. 62 echo "Nix statistics for $@" 63 jq . "$nix_stats" 64 echo 65 echo "Time statistics for $@" 66 jq . "$time_stats" 67 echo 68 69 cpuTime="$(jq '.cpuTime' < "$nix_stats")" 70 [[ -n $cpuTime ]] || exit 1 71 echo "$name.time $cpuTime s" >> hydra-metrics 72 73 maxresident="$(jq '.max_resident_set_kb' < "$time_stats")" 74 [[ -n $maxresident ]] || exit 1 75 echo "$name.maxresident $maxresident KiB" >> hydra-metrics 76 77 # Nix also outputs `.symbols.bytes` but since that wasn't summed originally, we don't count it here. 78 allocations="$(jq '[.envs,.list,.values,.sets] | map(.bytes) | add' < "$nix_stats")" 79 [[ -n $allocations ]] || exit 1 80 echo "$name.allocations $allocations B" >> hydra-metrics 81 82 values="$(jq '.values.number' < "$nix_stats")" 83 [[ -n $values ]] || exit 1 84 echo "$name.values $values" >> hydra-metrics 85 } 86 87 run nixos.smallContainer nix-instantiate --option eval-system "$evalSystem" --dry-run "$release" -A closures.smallContainer.x86_64-linux --show-trace --no-gc-warning 88 run nixos.kde nix-instantiate --option eval-system "$evalSystem" --dry-run "$release" -A closures.kde.x86_64-linux --show-trace --no-gc-warning 89 run nixos.lapp nix-instantiate --option eval-system "$evalSystem" --dry-run "$release" -A closures.lapp.x86_64-linux --show-trace --no-gc-warning 90 run nix-env.qa nix-env --option eval-system "$evalSystem" -f "$nixpkgs" -qa 91 run nix-env.qaDrv nix-env --option eval-system "$evalSystem" -f "$nixpkgs" -qa --drv-path --meta --json 92 93 # It's slightly unclear which of the set to track: qaCount, qaCountDrv, qaCountBroken. 94 num="$(wc -l < metrics/nix-env.qa/output)" 95 echo "nix-env.qaCount $num" >> hydra-metrics 96 qaCountDrv="$(jq -r 'reduce (.[].drvPath? // empty) as $d (0; .+1)' metrics/nix-env.qaDrv/output)" 97 numBroken="$((num - $qaCountDrv))" 98 echo "nix-env.qaCountBroken $numBroken" >> hydra-metrics 99 100 lines="$(find "$nixpkgs" -name "*.nix" -type f -print0 | xargs -0 cat | wc -l)" 101 echo "loc $lines" >> hydra-metrics 102 103 runHook postBuild 104 ''; 105 106 installPhase = '' 107 runHook preInstall 108 109 mkdir -p $out/nix-support 110 touch $out/nix-support/hydra-build-products 111 mv hydra-metrics $out/nix-support/hydra-metrics 112 113 # Save and compress the raw output 114 mv metrics $raw 115 xz -v $raw/*/output 116 117 runHook postInstall 118 ''; 119 120 meta = { 121 description = "Metrics tracked by Hydra about Nixpkgs"; 122 homepage = "https://hydra.nixos.org/job/nixpkgs/trunk/metrics"; 123 longDescription = '' 124 View the metrics for Nixpkgs evaluation over time at these URLs. 125 126 These are all produced from running `nix` with `NIX_SHOW_STATS=1`. 127 See `EvalState::printStatistics` in the Nix source code for the implementation. 128 None of these metrics are inherently meaningful on their own. 129 Exercise caution in interpreting them as "bad" or "good". 130 131 # Total repository statistics 132 133 - [Lines of code in Nixpkgs](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/loc) 134 - [Count of broken packages using `nix-env -qa`](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qaCountBroken) 135 - [Count of packages using `nix-env -qa`](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qaCount) 136 137 # Statistics about representative commands 138 139 These are statistics gathered by running commands against Nixpkgs. 140 141 | Name | Command | 142 |------|---------| 143 | `nix-env.qaDrv` | `nix-env -f ${nixpkgs} -qa --drv-path --meta --json` | 144 | `nix-env.qa` | `nix-env -f ${nixpkgs} -qa` | 145 | `nixos.kde` | `nix-instantiate --dry-run ${nixpkgs}/nixos/release.nix -A closures.kde.x86_64-linux --show-trace` | 146 | `nixos.lapp` | `nix-instantiate --dry-run ${nixpkgs}/nixos/release.nix -A closures.lapp.x86_64-linux --show-trace` | 147 | `nixos.smallContainer` | `nix-instantiate --dry-run ${nixpkgs}/nixos/release.nix -A closures.smallContainer.x86_64-linux --show-trace`| 148 149 ## Allocations performed (in bytes) 150 151 This counts `envs.bytes`, `list.bytes`, `values.bytes`, and `sets.bytes` from the Nix statistics. 152 153 - [nix-env.qa.allocations](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qa.allocations) 154 - [nix-env.qaDrv.allocations](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qaDrv.allocations) 155 - [nixos.kde.allocations](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.kde.allocations) 156 - [nixos.lapp.allocations](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.lapp.allocations) 157 - [nixos.smallContainer.allocations](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.smallContainer.allocations) 158 159 ## Maximum resident size (in number of KiB) 160 161 This counts `maxresident` KiB (`%M`) from the `time` command on Linux. 162 163 - [nix-env.qa.maxresident](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qa.maxresident) 164 - [nix-env.qaDrv.maxresident](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qaDrv.maxresident) 165 - [nixos.kde.maxresident](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.kde.maxresident) 166 - [nixos.lapp.maxresident](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.lapp.maxresident) 167 - [nixos.smallContainer.maxresident](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.smallContainer.maxresident) 168 169 ## Time taken (in seconds) 170 171 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). 172 173 - [nix-env.qa.time](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qa.time) 174 - [nix-env.qaDrv.time](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qaDrv.time) 175 - [nixos.kde.time](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.kde.time) 176 - [nixos.lapp.time](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.lapp.time) 177 - [nixos.smallContainer.time](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.smallContainer.time) 178 179 ## Number of values 180 181 This counts the total number of values allocated in Nix (see `EvalState::allocValue` in the Nix source code). 182 183 - [nix-env.qa.values](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qa.values) 184 - [nix-env.qaDrv.values](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nix-env.qaDrv.values) 185 - [nixos.kde.values](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.kde.values) 186 - [nixos.lapp.values](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.lapp.values) 187 - [nixos.smallContainer.values](https://hydra.nixos.org/job/nixpkgs/trunk/metrics/metric/nixos.smallContainer.values) 188 ''; 189 }; 190 191 # Convince `time` to output in JSON 192 env.TIME = builtins.toJSON { 193 real_time = "%e"; 194 user_time = "%U"; 195 sys_time = "%S"; 196 cpu_percent = "%P"; 197 max_resident_set_kb = "%M"; 198 avg_resident_set_kb = "%t"; 199 avg_total_mem_kb = "%K"; 200 avg_data_kb = "%D"; 201 avg_stack_kb = "%p"; 202 avg_unshared_data_kb = "%X"; 203 avg_shared_text_kb = "%Z"; 204 page_faults_major = "%F"; 205 page_faults_minor = "%R"; 206 swaps = "%W"; 207 context_switches_voluntary = "%c"; 208 context_switches_involuntary = "%w"; 209 io_reads = "%I"; 210 io_writes = "%O"; 211 signals_received = "%k"; 212 exit_status = "%x"; 213 command = "%C"; 214 }; 215 216 # Don't allow aliases anywhere in Nixpkgs for the metrics. 217 env.NIXPKGS_CONFIG = builtins.toFile "nixpkgs-config.nix" '' 218 { 219 allowAliases = false; 220 } 221 ''; 222}