From 1989dd7bf9cb9d562b3c97e65498c6eca042a0a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Tue, 29 Jul 2025 09:25:29 +0200 Subject: [PATCH] add derivation parser benchmark the current identified bottlenecks are parseString in derivations.cc and dirOf (because of std::filessystem creation). --- doc/manual/source/SUMMARY.md.in | 1 + doc/manual/source/development/benchmarking.md | 187 ++++++++++++++++++ meson.options | 7 + packaging/dev-shell.nix | 3 +- .../data/derivation/firefox.drv | 1 + src/libstore-tests/data/derivation/hello.drv | 1 + src/libstore-tests/derivation-parser-bench.cc | 45 +++++ src/libstore-tests/meson.build | 16 ++ src/libstore-tests/meson.options | 9 + src/libstore-tests/package.nix | 2 +- 10 files changed, 270 insertions(+), 2 deletions(-) create mode 100644 doc/manual/source/development/benchmarking.md create mode 100644 src/libstore-tests/data/derivation/firefox.drv create mode 100644 src/libstore-tests/data/derivation/hello.drv create mode 100644 src/libstore-tests/derivation-parser-bench.cc create mode 100644 src/libstore-tests/meson.options diff --git a/doc/manual/source/SUMMARY.md.in b/doc/manual/source/SUMMARY.md.in index bfb921567..cc4748f56 100644 --- a/doc/manual/source/SUMMARY.md.in +++ b/doc/manual/source/SUMMARY.md.in @@ -128,6 +128,7 @@ - [Development](development/index.md) - [Building](development/building.md) - [Testing](development/testing.md) + - [Benchmarking](development/benchmarking.md) - [Debugging](development/debugging.md) - [Documentation](development/documentation.md) - [CLI guideline](development/cli-guideline.md) diff --git a/doc/manual/source/development/benchmarking.md b/doc/manual/source/development/benchmarking.md new file mode 100644 index 000000000..74eadd9c2 --- /dev/null +++ b/doc/manual/source/development/benchmarking.md @@ -0,0 +1,187 @@ +# Running Benchmarks + +This guide explains how to build and run performance benchmarks in the Nix codebase. + +## Overview + +Nix uses the [Google Benchmark](https://github.com/google/benchmark) framework for performance testing. Benchmarks help measure and track the performance of critical operations like derivation parsing. + +## Building Benchmarks + +Benchmarks are disabled by default and must be explicitly enabled during the build configuration. For accurate results, use a debug-optimized release build. + +### Development Environment Setup + +First, enter the development shell which includes the necessary dependencies: + +```bash +nix develop .#native-ccacheStdenv +``` + +### Configure Build with Benchmarks + +From the project root, configure the build with benchmarks enabled and optimization: + +```bash +cd build +meson configure -Dbenchmarks=true -Dbuildtype=debugoptimized +``` + +The `debugoptimized` build type provides: +- Compiler optimizations for realistic performance measurements +- Debug symbols for profiling and analysis +- Balance between performance and debuggability + +### Build the Benchmarks + +Build the project including benchmarks: + +```bash +ninja +``` + +This will create benchmark executables in the build directory. Currently available: +- `build/src/libstore-tests/nix-store-benchmarks` - Store-related performance benchmarks + +Additional benchmark executables will be created as more benchmarks are added to the codebase. + +## Running Benchmarks + +### Basic Usage + +Run benchmark executables directly. For example, to run store benchmarks: + +```bash +./build/src/libstore-tests/nix-store-benchmarks +``` + +As more benchmark executables are added, run them similarly from their respective build directories. + +### Filtering Benchmarks + +Run specific benchmarks using regex patterns: + +```bash +# Run only derivation parser benchmarks +./build/src/libstore-tests/nix-store-benchmarks --benchmark_filter="derivation.*" + +# Run only benchmarks for hello.drv +./build/src/libstore-tests/nix-store-benchmarks --benchmark_filter=".*hello.*" +``` + +### Output Formats + +Generate benchmark results in different formats: + +```bash +# JSON output +./build/src/libstore-tests/nix-store-benchmarks --benchmark_format=json > results.json + +# CSV output +./build/src/libstore-tests/nix-store-benchmarks --benchmark_format=csv > results.csv +``` + +### Advanced Options + +```bash +# Run benchmarks multiple times for better statistics +./build/src/libstore-tests/nix-store-benchmarks --benchmark_repetitions=10 + +# Set minimum benchmark time (useful for micro-benchmarks) +./build/src/libstore-tests/nix-store-benchmarks --benchmark_min_time=2 + +# Compare against baseline +./build/src/libstore-tests/nix-store-benchmarks --benchmark_baseline=baseline.json + +# Display time in custom units +./build/src/libstore-tests/nix-store-benchmarks --benchmark_time_unit=ms +``` + +## Writing New Benchmarks + +To add new benchmarks: + +1. Create a new `.cc` file in the appropriate `*-tests` directory +2. Include the benchmark header: + ```cpp + #include + ``` + +3. Write benchmark functions: + ```cpp + static void BM_YourBenchmark(benchmark::State & state) + { + // Setup code here + + for (auto _ : state) { + // Code to benchmark + } + } + BENCHMARK(BM_YourBenchmark); + ``` + +4. Add the file to the corresponding `meson.build`: + ```meson + benchmarks_sources = files( + 'your-benchmark.cc', + # existing benchmarks... + ) + ``` + +## Profiling with Benchmarks + +For deeper performance analysis, combine benchmarks with profiling tools: + +```bash +# Using Linux perf +perf record ./build/src/libstore-tests/nix-store-benchmarks +perf report +``` + +### Using Valgrind Callgrind + +Valgrind's callgrind tool provides detailed profiling information that can be visualized with kcachegrind: + +```bash +# Profile with callgrind +valgrind --tool=callgrind ./build/src/libstore-tests/nix-store-benchmarks + +# Visualize the results with kcachegrind +kcachegrind callgrind.out.* +``` + +This provides: +- Function call graphs +- Instruction-level profiling +- Source code annotation +- Interactive visualization of performance bottlenecks + +## Continuous Performance Testing + +```bash +# Save baseline results +./build/src/libstore-tests/nix-store-benchmarks --benchmark_format=json > baseline.json + +# Compare against baseline in CI +./build/src/libstore-tests/nix-store-benchmarks --benchmark_baseline=baseline.json +``` + +## Troubleshooting + +### Benchmarks not building + +Ensure benchmarks are enabled: +```bash +meson configure build | grep benchmarks +# Should show: benchmarks true +``` + +### Inconsistent results + +- Ensure your system is not under heavy load +- Disable CPU frequency scaling for consistent results +- Run benchmarks multiple times with `--benchmark_repetitions` + +## See Also + +- [Google Benchmark documentation](https://github.com/google/benchmark/blob/main/docs/user_guide.md) diff --git a/meson.options b/meson.options index 30670902e..d2c9fa40c 100644 --- a/meson.options +++ b/meson.options @@ -20,3 +20,10 @@ option( value : true, description : 'Build language bindings (e.g. Perl)', ) + +option( + 'benchmarks', + type : 'boolean', + value : false, + description : 'Build benchmarks (requires gbenchmark)', +) diff --git a/packaging/dev-shell.nix b/packaging/dev-shell.nix index e01a0ed8f..f10a9d56e 100644 --- a/packaging/dev-shell.nix +++ b/packaging/dev-shell.nix @@ -126,7 +126,8 @@ pkgs.nixComponents2.nix-util.overrideAttrs ( ++ lib.optional stdenv.hostPlatform.isLinux pkgs.buildPackages.mold-wrapped; buildInputs = - attrs.buildInputs or [ ] + [ pkgs.gbenchmark ] + ++ attrs.buildInputs or [ ] ++ pkgs.nixComponents2.nix-util.buildInputs ++ pkgs.nixComponents2.nix-store.buildInputs ++ pkgs.nixComponents2.nix-store-tests.externalBuildInputs diff --git a/src/libstore-tests/data/derivation/firefox.drv b/src/libstore-tests/data/derivation/firefox.drv new file mode 100644 index 000000000..98ff69c81 --- /dev/null +++ b/src/libstore-tests/data/derivation/firefox.drv @@ -0,0 +1 @@ +Derive([("out","/nix/store/jycqnr8rdfy035ckiwmar4yql406jjh6-firefox-140.0.4","","")],[("/nix/store/01qkwh6g0xqlrchziwa8zm3c8p6s5ylc-krb5-1.21.3.drv",["lib"]),("/nix/store/03ixv9yqpmi015vv0m4gza1d2ac8wql8-libglvnd-1.7.0.drv",["out"]),("/nix/store/2g73b2yd3qhzp774i9svckdnspyrfrn8-firefox-unwrapped-140.0.4.drv",["out"]),("/nix/store/2wf9wi34rvwyq7dxk0xlk41ccll282z0-make-shell-wrapper-hook.drv",["out"]),("/nix/store/3gr22851nw1nj8zmy34961yb3fbr2iz5-libva-2.22.0.drv",["out"]),("/nix/store/7gzk0w5125wqhgp8sh26l3k15lklm82c-policies.json.drv",["out"]),("/nix/store/b3jvr65plcm9nm4wn8ssw2ymnv2zshmq-extract-binary-wrapper-cmd.drv",["out"]),("/nix/store/ck7ckwkvqv49hz5rl8yp52c4v6p2f6vd-pipewire-1.4.6.drv",["out"]),("/nix/store/fm2b1q5m1wrvy237j6x9xcvhxw95wjfp-alsa-lib-1.2.14.drv",["out"]),("/nix/store/fvch7vyklf8gr8i53p9ybv2azyh6q30y-ffmpeg-7.1.1.drv",["lib"]),("/nix/store/ggzpx6yx9xd5h241ri730acdfpdirxjq-mesa-libgbm-25.1.0.drv",["out"]),("/nix/store/hmwbmap5c8zp3kl20bda0qk1dg4f408d-vulkan-loader-1.4.313.0.drv",["out"]),("/nix/store/hy8x576wmvz2fk9a778r05lqdb0dcbl4-speech-dispatcher-0.12.1.drv",["out"]),("/nix/store/knjlgd5nfd7dw45axa6z7w7d7rb11801-pciutils-3.14.0.drv",["out"]),("/nix/store/l7y4nybngpffyndkw8rwx2g3c8dw4yyj-xdg-utils-1.2.1.drv",["out"]),("/nix/store/lh0mbixp7jiz7z8cxfypm8b17lf8z9la-cups-2.4.12.drv",["lib"]),("/nix/store/lmfgw4dz59sdvplfh3zazqmin8d7gh9d-libnotify-0.8.6.drv",["out"]),("/nix/store/m4zp8p8y4wzxg2lhgq43kbgr2xl5l9px-firefox.desktop.drv",["out"]),("/nix/store/n8hy5gvnrw0kzz6cjdhky3rxr0q024sh-jq-1.8.1.drv",["dev"]),("/nix/store/nz0xp44xmbqcp2sfhsgicsswrrb2cpl7-libXScrnSaver-1.2.4.drv",["out"]),("/nix/store/p2nvbwxxiarbqaq26rqrjqkyw8dl0cf4-lndir-1.0.5.drv",["out"]),("/nix/store/p306lljvhw8906r1lxyyk7jn3bckdypn-sndio-1.10.0.drv",["out"]),("/nix/store/pbqbdcp76r373256ajlbp3fankpw5pdh-libpulseaudio-17.0.drv",["out"]),("/nix/store/q27q075ckyjkpqxx8cgvpghcwr0nzz5v-systemd-minimal-libs-257.6.drv",["out"]),("/nix/store/s4b8yadif84kiv8gyr9nxdi6zbg69b4g-bash-5.2p37.drv",["out"]),("/nix/store/sc2pgkzc1s6zp5dp8j7wsd4msilsnijn-stdenv-linux.drv",["out"]),("/nix/store/sy2kn7hwfw0nyvxq7rvzrmvm2ypxs9x6-gtk+3-3.24.49.drv",["dev"]),("/nix/store/v3sc4j11fhsah2ij0wkziw6nd3il9dyy-libjack2-1.9.22.drv",["out"]),("/nix/store/xy07yjv0x8bcdc3lzyq45lrbbz08hg5p-adwaita-icon-theme-48.0.drv",["out"]),("/nix/store/z8v9j1cf6faasgqrw3jw74xjyjiqwk82-libcanberra-0.30.drv",["out"])],["/nix/store/shkw4qm9qcw5sc5n1k5jznc83ny02r39-default-builder.sh","/nix/store/vj1c3wf9c11a0qs6p3ymfvrnsdgsdcbq-source-stdenv.sh"],"x86_64-linux","/nix/store/p79bgyzmmmddi554ckwzbqlavbkw07zh-bash-5.2p37/bin/bash",["-e","/nix/store/vj1c3wf9c11a0qs6p3ymfvrnsdgsdcbq-source-stdenv.sh","/nix/store/shkw4qm9qcw5sc5n1k5jznc83ny02r39-default-builder.sh"],[("__json","{\"NIX_MAIN_PROGRAM\":\"firefox\",\"buildCommand\":\"if [ ! -x \\\"/nix/store/9ycwpmlavjsjgr0svaqdy0mmjg949nzq-firefox-unwrapped-140.0.4/bin/firefox\\\" ]\\nthen\\n echo \\\"cannot find executable file \\\\`/nix/store/9ycwpmlavjsjgr0svaqdy0mmjg949nzq-firefox-unwrapped-140.0.4/bin/firefox'\\\"\\n exit 1\\nfi\\n\\n#########################\\n# #\\n# EXTRA PREF CHANGES #\\n# #\\n#########################\\n# Link the runtime. The executable itself has to be copied,\\n# because it will resolve paths relative to its true location.\\n# Any symbolic links have to be replicated as well.\\ncd \\\"/nix/store/9ycwpmlavjsjgr0svaqdy0mmjg949nzq-firefox-unwrapped-140.0.4\\\"\\nfind . -type d -exec mkdir -p \\\"$out\\\"/{} \\\\;\\n\\nfind . -type f \\\\( -not -name \\\"firefox\\\" \\\\) -exec ln -sT \\\"/nix/store/9ycwpmlavjsjgr0svaqdy0mmjg949nzq-firefox-unwrapped-140.0.4\\\"/{} \\\"$out\\\"/{} \\\\;\\n\\nfind . -type f \\\\( -name \\\"firefox\\\" -o -name \\\"firefox-bin\\\" \\\\) -print0 | while read -d $'\\\\0' f; do\\n cp -P --no-preserve=mode,ownership --remove-destination \\\"/nix/store/9ycwpmlavjsjgr0svaqdy0mmjg949nzq-firefox-unwrapped-140.0.4/$f\\\" \\\"$out/$f\\\"\\n chmod a+rwx \\\"$out/$f\\\"\\ndone\\n\\n# fix links and absolute references\\n\\nfind . -type l -print0 | while read -d $'\\\\0' l; do\\n target=\\\"$(readlink \\\"$l\\\")\\\"\\n target=${target/#\\\"/nix/store/9ycwpmlavjsjgr0svaqdy0mmjg949nzq-firefox-unwrapped-140.0.4\\\"/\\\"$out\\\"}\\n ln -sfT \\\"$target\\\" \\\"$out/$l\\\"\\ndone\\n\\ncd \\\"$out\\\"\\n\\n\\n# create the wrapper\\n\\nexecutablePrefix=\\\"$out/bin\\\"\\nexecutablePath=\\\"$out/bin/firefox\\\"\\noldWrapperArgs=()\\n\\nif [[ -L $executablePath ]]; then\\n # Symbolic link: wrap the link's target.\\n oldExe=\\\"$(readlink -v --canonicalize-existing \\\"$executablePath\\\")\\\"\\n rm \\\"$executablePath\\\"\\nelif wrapperCmd=$(/nix/store/qczbm5rh1vfkql4jznp1p5lv9nyjz99r-extract-binary-wrapper-cmd \\\"$executablePath\\\"); [[ $wrapperCmd ]]; then\\n # If the executable is a binary wrapper, we need to update its target to\\n # point to $out, but we can't just edit the binary in-place because of length\\n # issues. So we extract the command used to create the wrapper and add the\\n # arguments to our wrapper.\\n parseMakeCWrapperCall() {\\n shift # makeCWrapper\\n oldExe=$1; shift\\n oldWrapperArgs=(\\\"$@\\\")\\n }\\n eval \\\"parseMakeCWrapperCall ${wrapperCmd//\\\"/nix/store/9ycwpmlavjsjgr0svaqdy0mmjg949nzq-firefox-unwrapped-140.0.4\\\"/\\\"$out\\\"}\\\"\\n rm \\\"$executablePath\\\"\\nelse\\n if read -rn2 shebang < \\\"$executablePath\\\" && [[ $shebang == '#!' ]]; then\\n # Shell wrapper: patch in place to point to $out.\\n sed -i \\\"s@/nix/store/9ycwpmlavjsjgr0svaqdy0mmjg949nzq-firefox-unwrapped-140.0.4@$out@g\\\" \\\"$executablePath\\\"\\n fi\\n # Suffix the executable with -old, because -wrapped might already be used by the old wrapper.\\n oldExe=\\\"$executablePrefix/.firefox\\\"-old\\n mv \\\"$executablePath\\\" \\\"$oldExe\\\"\\nfi\\nappendToVar makeWrapperArgs --prefix XDG_DATA_DIRS : \\\"$GSETTINGS_SCHEMAS_PATH\\\"\\nconcatTo makeWrapperArgs oldWrapperArgs\\n\\nmakeWrapper \\\"$oldExe\\\" \\\"$out/bin/firefox\\\" \\\"${makeWrapperArgs[@]}\\\"\\n\\n#############################\\n# #\\n# END EXTRA PREF CHANGES #\\n# #\\n#############################\\nif [ -e \\\"/nix/store/9ycwpmlavjsjgr0svaqdy0mmjg949nzq-firefox-unwrapped-140.0.4/share/icons\\\" ]; then\\n mkdir -p \\\"$out/share\\\"\\n ln -s \\\"/nix/store/9ycwpmlavjsjgr0svaqdy0mmjg949nzq-firefox-unwrapped-140.0.4/share/icons\\\" \\\"$out/share/icons\\\"\\nelse\\n for res in 16 32 48 64 128; do\\n mkdir -p \\\"$out/share/icons/hicolor/${res}x${res}/apps\\\"\\n icon=$( find \\\"/nix/store/9ycwpmlavjsjgr0svaqdy0mmjg949nzq-firefox-unwrapped-140.0.4/lib/\\\" -name \\\"default${res}.png\\\" )\\n if [ -e \\\"$icon\\\" ]; then ln -s \\\"$icon\\\" \\\\\\n \\\"$out/share/icons/hicolor/${res}x${res}/apps/firefox.png\\\"\\n fi\\n done\\nfi\\n\\ninstall -m 644 -D -t $out/share/applications $desktopItem/share/applications/*\\n\\nmkdir -p $out/lib/mozilla/native-messaging-hosts\\nfor ext in ; do\\n ln -sLt $out/lib/mozilla/native-messaging-hosts $ext/lib/mozilla/native-messaging-hosts/*\\ndone\\n\\nmkdir -p $out/lib/mozilla/pkcs11-modules\\nfor ext in ; do\\n ln -sLt $out/lib/mozilla/pkcs11-modules $ext/lib/mozilla/pkcs11-modules/*\\ndone\\n\\n\\n#########################\\n# #\\n# EXTRA PREF CHANGES #\\n# #\\n#########################\\n# user customization\\nlibDir=\\\"$out/lib/firefox\\\"\\n\\n# creating policies.json\\nmkdir -p \\\"$libDir/distribution\\\"\\n\\nPOL_PATH=\\\"$libDir/distribution/policies.json\\\"\\nrm -f \\\"$POL_PATH\\\"\\ncat /nix/store/s9r3kncxydp3s94cari78f2dl68w1k3j-policies.json >> \\\"$POL_PATH\\\"\\n\\nextraPoliciesFiles=()\\nfor extraPoliciesFile in \\\"${extraPoliciesFiles[@]}\\\"; do\\n jq -s '.[0] * .[1]' $extraPoliciesFile \\\"$POL_PATH\\\" > .tmp.json\\n mv .tmp.json \\\"$POL_PATH\\\"\\ndone\\n\\n# preparing for autoconfig\\nprefsDir=\\\"$out/lib/firefox/defaults/pref\\\"\\nmkdir -p \\\"$prefsDir\\\"\\n\\necho 'pref(\\\"general.config.filename\\\", \\\"mozilla.cfg\\\");' > \\\"$prefsDir/autoconfig.js\\\"\\necho 'pref(\\\"general.config.obscure_value\\\", 0);' >> \\\"$prefsDir/autoconfig.js\\\"\\n\\ncat > \\\"$libDir/mozilla.cfg\\\" << EOF\\n// First line must be a comment\\n\\n// Disables addon signature checking\\n// to be able to install addons that do not have an extid\\n// Security is maintained because only user whitelisted addons\\n// with a checksum can be installed\\n\\n\\nEOF\\n\\nextraPrefsFiles=()\\nfor extraPrefsFile in \\\"${extraPrefsFiles[@]}\\\"; do\\n cat \\\"$extraPrefsFile\\\" >> \\\"$libDir/mozilla.cfg\\\"\\ndone\\n\\ncat >> \\\"$libDir/mozilla.cfg\\\" << EOF\\n\\nEOF\\n\\nmkdir -p \\\"$libDir/distribution/extensions\\\"\\n\\n#############################\\n# #\\n# END EXTRA PREF CHANGES #\\n# #\\n#############################\\n\",\"buildInputs\":[\"/nix/store/09050l3isnxqyjbsn4qfbq190i6a85bx-gtk+3-3.24.49-dev\"],\"builder\":\"/nix/store/p79bgyzmmmddi554ckwzbqlavbkw07zh-bash-5.2p37/bin/bash\",\"cmakeFlags\":[],\"configureFlags\":[],\"depsBuildBuild\":[],\"depsBuildBuildPropagated\":[],\"depsBuildTarget\":[],\"depsBuildTargetPropagated\":[],\"depsHostHost\":[],\"depsHostHostPropagated\":[],\"depsTargetTarget\":[],\"depsTargetTargetPropagated\":[],\"desktopItem\":\"/nix/store/w8xccv3flpwzgwan7k0l4rrv9m8ipffa-firefox.desktop\",\"doCheck\":false,\"doInstallCheck\":false,\"env\":{\"NIX_MAIN_PROGRAM\":\"firefox\"},\"gtk_modules\":[\"/nix/store/6pwfsghvp9fa6bpwryk7bwbjd4f5vdxy-libcanberra-0.30/lib/gtk-3.0/\"],\"libs\":\"/nix/store/pb6fwczgq5d08yppb0mxsbvvzi2wl71g-systemd-minimal-libs-257.6/lib:/nix/store/ib8prgicm88f9xbg7cgbk72n3s69c0rx-libva-2.22.0/lib:/nix/store/d6a8ckgb953nqr2qamidqzz1i7v473pm-mesa-libgbm-25.1.0/lib:/nix/store/1mx1hccld2shxc3acmr32kydiw5kb0l3-libnotify-0.8.6/lib:/nix/store/3ia435d0b41k0gz1hmg5yj134fh1j70x-libXScrnSaver-1.2.4/lib:/nix/store/wj5sc0i81fb6hcz802gmsgdsjll79wfc-cups-2.4.12-lib/lib:/nix/store/h0zj2k3q2iqs6b2qdjqrg29l2kaksgkz-pciutils-3.14.0/lib:/nix/store/0jgicjfcml2v3plj470ggf8q88xkxq4d-vulkan-loader-1.4.313.0/lib:/nix/store/z67zjqlvbgz80slzmmibmyv31k68l2r6-speech-dispatcher-0.12.1/lib:/nix/store/gh2fi51xdj78cj9j9za5jfrrj8qgx90c-pipewire-1.4.6/lib:/nix/store/r5a9sknnr626v8whd46h4fm7i6v5yl8l-ffmpeg-7.1.1-lib/lib:/nix/store/7razjlx084wqwcaa359mvrcjd4lx1kn2-krb5-1.21.3-lib/lib:/nix/store/iyy1g70fhkz3hsrckbmbqgxik1j9779c-libglvnd-1.7.0/lib:/nix/store/vfiyznjv206ysafzl3ibnr7cr1lhq83q-libpulseaudio-17.0/lib:/nix/store/7p8rmrv6hy8lx90a52nk94fdm4av51pl-alsa-lib-1.2.14/lib:/nix/store/a5m2h89rn29n7374pdm34d7a120c1j6f-sndio-1.10.0/lib:/nix/store/nwsvsihqzmgabv47kqqrsj94nlmraajp-libjack2-1.9.22/lib:/nix/store/6pwfsghvp9fa6bpwryk7bwbjd4f5vdxy-libcanberra-0.30/lib:/nix/store/pb6fwczgq5d08yppb0mxsbvvzi2wl71g-systemd-minimal-libs-257.6/lib64:/nix/store/ib8prgicm88f9xbg7cgbk72n3s69c0rx-libva-2.22.0/lib64:/nix/store/d6a8ckgb953nqr2qamidqzz1i7v473pm-mesa-libgbm-25.1.0/lib64:/nix/store/1mx1hccld2shxc3acmr32kydiw5kb0l3-libnotify-0.8.6/lib64:/nix/store/3ia435d0b41k0gz1hmg5yj134fh1j70x-libXScrnSaver-1.2.4/lib64:/nix/store/wj5sc0i81fb6hcz802gmsgdsjll79wfc-cups-2.4.12-lib/lib64:/nix/store/h0zj2k3q2iqs6b2qdjqrg29l2kaksgkz-pciutils-3.14.0/lib64:/nix/store/0jgicjfcml2v3plj470ggf8q88xkxq4d-vulkan-loader-1.4.313.0/lib64:/nix/store/z67zjqlvbgz80slzmmibmyv31k68l2r6-speech-dispatcher-0.12.1/lib64:/nix/store/gh2fi51xdj78cj9j9za5jfrrj8qgx90c-pipewire-1.4.6/lib64:/nix/store/r5a9sknnr626v8whd46h4fm7i6v5yl8l-ffmpeg-7.1.1-lib/lib64:/nix/store/7razjlx084wqwcaa359mvrcjd4lx1kn2-krb5-1.21.3-lib/lib64:/nix/store/iyy1g70fhkz3hsrckbmbqgxik1j9779c-libglvnd-1.7.0/lib64:/nix/store/vfiyznjv206ysafzl3ibnr7cr1lhq83q-libpulseaudio-17.0/lib64:/nix/store/7p8rmrv6hy8lx90a52nk94fdm4av51pl-alsa-lib-1.2.14/lib64:/nix/store/a5m2h89rn29n7374pdm34d7a120c1j6f-sndio-1.10.0/lib64:/nix/store/nwsvsihqzmgabv47kqqrsj94nlmraajp-libjack2-1.9.22/lib64:/nix/store/6pwfsghvp9fa6bpwryk7bwbjd4f5vdxy-libcanberra-0.30/lib64\",\"makeWrapperArgs\":[\"--prefix\",\"LD_LIBRARY_PATH\",\":\",\"/nix/store/pb6fwczgq5d08yppb0mxsbvvzi2wl71g-systemd-minimal-libs-257.6/lib:/nix/store/ib8prgicm88f9xbg7cgbk72n3s69c0rx-libva-2.22.0/lib:/nix/store/d6a8ckgb953nqr2qamidqzz1i7v473pm-mesa-libgbm-25.1.0/lib:/nix/store/1mx1hccld2shxc3acmr32kydiw5kb0l3-libnotify-0.8.6/lib:/nix/store/3ia435d0b41k0gz1hmg5yj134fh1j70x-libXScrnSaver-1.2.4/lib:/nix/store/wj5sc0i81fb6hcz802gmsgdsjll79wfc-cups-2.4.12-lib/lib:/nix/store/h0zj2k3q2iqs6b2qdjqrg29l2kaksgkz-pciutils-3.14.0/lib:/nix/store/0jgicjfcml2v3plj470ggf8q88xkxq4d-vulkan-loader-1.4.313.0/lib:/nix/store/z67zjqlvbgz80slzmmibmyv31k68l2r6-speech-dispatcher-0.12.1/lib:/nix/store/gh2fi51xdj78cj9j9za5jfrrj8qgx90c-pipewire-1.4.6/lib:/nix/store/r5a9sknnr626v8whd46h4fm7i6v5yl8l-ffmpeg-7.1.1-lib/lib:/nix/store/7razjlx084wqwcaa359mvrcjd4lx1kn2-krb5-1.21.3-lib/lib:/nix/store/iyy1g70fhkz3hsrckbmbqgxik1j9779c-libglvnd-1.7.0/lib:/nix/store/vfiyznjv206ysafzl3ibnr7cr1lhq83q-libpulseaudio-17.0/lib:/nix/store/7p8rmrv6hy8lx90a52nk94fdm4av51pl-alsa-lib-1.2.14/lib:/nix/store/a5m2h89rn29n7374pdm34d7a120c1j6f-sndio-1.10.0/lib:/nix/store/nwsvsihqzmgabv47kqqrsj94nlmraajp-libjack2-1.9.22/lib:/nix/store/6pwfsghvp9fa6bpwryk7bwbjd4f5vdxy-libcanberra-0.30/lib:/nix/store/pb6fwczgq5d08yppb0mxsbvvzi2wl71g-systemd-minimal-libs-257.6/lib64:/nix/store/ib8prgicm88f9xbg7cgbk72n3s69c0rx-libva-2.22.0/lib64:/nix/store/d6a8ckgb953nqr2qamidqzz1i7v473pm-mesa-libgbm-25.1.0/lib64:/nix/store/1mx1hccld2shxc3acmr32kydiw5kb0l3-libnotify-0.8.6/lib64:/nix/store/3ia435d0b41k0gz1hmg5yj134fh1j70x-libXScrnSaver-1.2.4/lib64:/nix/store/wj5sc0i81fb6hcz802gmsgdsjll79wfc-cups-2.4.12-lib/lib64:/nix/store/h0zj2k3q2iqs6b2qdjqrg29l2kaksgkz-pciutils-3.14.0/lib64:/nix/store/0jgicjfcml2v3plj470ggf8q88xkxq4d-vulkan-loader-1.4.313.0/lib64:/nix/store/z67zjqlvbgz80slzmmibmyv31k68l2r6-speech-dispatcher-0.12.1/lib64:/nix/store/gh2fi51xdj78cj9j9za5jfrrj8qgx90c-pipewire-1.4.6/lib64:/nix/store/r5a9sknnr626v8whd46h4fm7i6v5yl8l-ffmpeg-7.1.1-lib/lib64:/nix/store/7razjlx084wqwcaa359mvrcjd4lx1kn2-krb5-1.21.3-lib/lib64:/nix/store/iyy1g70fhkz3hsrckbmbqgxik1j9779c-libglvnd-1.7.0/lib64:/nix/store/vfiyznjv206ysafzl3ibnr7cr1lhq83q-libpulseaudio-17.0/lib64:/nix/store/7p8rmrv6hy8lx90a52nk94fdm4av51pl-alsa-lib-1.2.14/lib64:/nix/store/a5m2h89rn29n7374pdm34d7a120c1j6f-sndio-1.10.0/lib64:/nix/store/nwsvsihqzmgabv47kqqrsj94nlmraajp-libjack2-1.9.22/lib64:/nix/store/6pwfsghvp9fa6bpwryk7bwbjd4f5vdxy-libcanberra-0.30/lib64\",\"--suffix\",\"PATH\",\":\",\"/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9/bin\",\"--set\",\"MOZ_APP_LAUNCHER\",\"firefox\",\"--set\",\"MOZ_LEGACY_PROFILES\",\"1\",\"--set\",\"MOZ_ALLOW_DOWNGRADE\",\"1\",\"--suffix\",\"GTK_PATH\",\":\",\"/nix/store/6pwfsghvp9fa6bpwryk7bwbjd4f5vdxy-libcanberra-0.30/lib/gtk-3.0/\",\"--suffix\",\"XDG_DATA_DIRS\",\":\",\"/nix/store/1w8x293926aq2vcyys36aw49fy5p8cm5-adwaita-icon-theme-48.0/share\",\"--set-default\",\"MOZ_ENABLE_WAYLAND\",\"1\",\"--suffix\",\"PATH\",\":\",\"/nix/store/yrzm7cya8nf8xnpi8xlfwx16plqkzhgh-xdg-utils-1.2.1/bin\",\"--set\",\"MOZ_SYSTEM_DIR\",\"/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9/lib/mozilla\"],\"mesonFlags\":[],\"name\":\"firefox-140.0.4\",\"nativeBuildInputs\":[\"/nix/store/lnd6p3anjxgwawlhlpzvvl40d4yc2jd4-make-shell-wrapper-hook\",\"/nix/store/kn8zagv6mk3ykmax5fqh4h18raqhxbh6-lndir-1.0.5\",\"/nix/store/x0kva02y0iyh7l0qvnx3l8ci7ll1r5si-jq-1.8.1-dev\"],\"outputChecks\":{\"out\":{\"disallowedRequisites\":[\"/nix/store/7nlf5v84s4p2yhx327j8495yik60qnzh-gcc-wrapper-14.3.0\"]}},\"outputs\":[\"out\"],\"patches\":[],\"pname\":\"firefox\",\"preferLocalBuild\":true,\"propagatedBuildInputs\":[],\"propagatedNativeBuildInputs\":[],\"stdenv\":\"/nix/store/a13rl87yjhzqrbkc4gb0mrwz2mfkivcf-stdenv-linux\",\"strictDeps\":false,\"system\":\"x86_64-linux\",\"version\":\"140.0.4\"}"),("out","/nix/store/jycqnr8rdfy035ckiwmar4yql406jjh6-firefox-140.0.4")]) \ No newline at end of file diff --git a/src/libstore-tests/data/derivation/hello.drv b/src/libstore-tests/data/derivation/hello.drv new file mode 100644 index 000000000..741f7745c --- /dev/null +++ b/src/libstore-tests/data/derivation/hello.drv @@ -0,0 +1 @@ +Derive([("out","/nix/store/hhg83gh653wjw4ny49xn92f13v2j1za4-hello-2.12.2","","")],[("/nix/store/1xz4avqqrxqsxw7idz119vdzw837p1n1-version-check-hook.drv",["out"]),("/nix/store/bsv47sbqcar3205il55spxqacxp8j0fj-hello-2.12.2.tar.gz.drv",["out"]),("/nix/store/s4b8yadif84kiv8gyr9nxdi6zbg69b4g-bash-5.2p37.drv",["out"]),("/nix/store/sc2pgkzc1s6zp5dp8j7wsd4msilsnijn-stdenv-linux.drv",["out"])],["/nix/store/shkw4qm9qcw5sc5n1k5jznc83ny02r39-default-builder.sh","/nix/store/vj1c3wf9c11a0qs6p3ymfvrnsdgsdcbq-source-stdenv.sh"],"x86_64-linux","/nix/store/p79bgyzmmmddi554ckwzbqlavbkw07zh-bash-5.2p37/bin/bash",["-e","/nix/store/vj1c3wf9c11a0qs6p3ymfvrnsdgsdcbq-source-stdenv.sh","/nix/store/shkw4qm9qcw5sc5n1k5jznc83ny02r39-default-builder.sh"],[("NIX_MAIN_PROGRAM","hello"),("__structuredAttrs",""),("buildInputs",""),("builder","/nix/store/p79bgyzmmmddi554ckwzbqlavbkw07zh-bash-5.2p37/bin/bash"),("cmakeFlags",""),("configureFlags",""),("depsBuildBuild",""),("depsBuildBuildPropagated",""),("depsBuildTarget",""),("depsBuildTargetPropagated",""),("depsHostHost",""),("depsHostHostPropagated",""),("depsTargetTarget",""),("depsTargetTargetPropagated",""),("doCheck","1"),("doInstallCheck","1"),("mesonFlags",""),("name","hello-2.12.2"),("nativeBuildInputs","/nix/store/fxzn6kr5anxn5jgh511x56wrg8b3a99a-version-check-hook"),("out","/nix/store/hhg83gh653wjw4ny49xn92f13v2j1za4-hello-2.12.2"),("outputs","out"),("patches",""),("pname","hello"),("postInstallCheck","stat \"${!outputBin}/bin/hello\"\n"),("propagatedBuildInputs",""),("propagatedNativeBuildInputs",""),("src","/nix/store/dw402azxjrgrzrk6j0p66wkqrab5mwgw-hello-2.12.2.tar.gz"),("stdenv","/nix/store/a13rl87yjhzqrbkc4gb0mrwz2mfkivcf-stdenv-linux"),("strictDeps",""),("system","x86_64-linux"),("version","2.12.2")]) \ No newline at end of file diff --git a/src/libstore-tests/derivation-parser-bench.cc b/src/libstore-tests/derivation-parser-bench.cc new file mode 100644 index 000000000..7598758f0 --- /dev/null +++ b/src/libstore-tests/derivation-parser-bench.cc @@ -0,0 +1,45 @@ +#include +#include "nix/store/derivations.hh" +#include "nix/store/store-api.hh" +#include "nix/util/experimental-features.hh" +#include "nix/store/store-open.hh" +#include "nix/store/globals.hh" +#include +#include + +using namespace nix; + +// Benchmark parsing real derivation files +static void BM_ParseRealDerivationFile(benchmark::State & state, const std::string & filename) +{ + // Read the file once + std::ifstream file(filename); + std::stringstream buffer; + buffer << file.rdbuf(); + std::string content = buffer.str(); + + auto store = openStore("dummy://"); + ExperimentalFeatureSettings xpSettings; + + for (auto _ : state) { + auto drv = parseDerivation(*store, std::string(content), "test", xpSettings); + benchmark::DoNotOptimize(drv); + } + state.SetBytesProcessed(state.iterations() * content.size()); +} + +// Register benchmarks for actual test derivation files if they exist +BENCHMARK_CAPTURE(BM_ParseRealDerivationFile, hello, std::string(NIX_UNIT_TEST_DATA) + "/derivation/hello.drv"); +BENCHMARK_CAPTURE(BM_ParseRealDerivationFile, firefox, std::string(NIX_UNIT_TEST_DATA) + "/derivation/firefox.drv"); + +// Custom main to initialize Nix before running benchmarks +int main(int argc, char ** argv) +{ + // Initialize libstore + nix::initLibStore(false); + + // Initialize and run benchmarks + ::benchmark::Initialize(&argc, argv); + ::benchmark::RunSpecifiedBenchmarks(); + return 0; +} diff --git a/src/libstore-tests/meson.build b/src/libstore-tests/meson.build index 79f21620e..89189bab9 100644 --- a/src/libstore-tests/meson.build +++ b/src/libstore-tests/meson.build @@ -105,3 +105,19 @@ test( }, protocol : 'gtest', ) + +# Build benchmarks if enabled +if get_option('benchmarks') + gbenchmark = dependency('benchmark', required : true) + + benchmark_exe = executable( + 'nix-store-benchmarks', + 'derivation-parser-bench.cc', + config_priv_h, + dependencies : deps_private_subproject + deps_private + deps_other + [gbenchmark], + include_directories : include_dirs, + link_args: linker_export_flags, + install : false, + cpp_args : ['-DNIX_UNIT_TEST_DATA="' + meson.current_source_dir() + '/data"'], + ) +endif diff --git a/src/libstore-tests/meson.options b/src/libstore-tests/meson.options new file mode 100644 index 000000000..2b3c1af60 --- /dev/null +++ b/src/libstore-tests/meson.options @@ -0,0 +1,9 @@ +# vim: filetype=meson + +option( + 'benchmarks', + type : 'boolean', + value : false, + description : 'Build benchmarks (requires gbenchmark)', + yield : true, +) diff --git a/src/libstore-tests/package.nix b/src/libstore-tests/package.nix index f606604ba..93c71a382 100644 --- a/src/libstore-tests/package.nix +++ b/src/libstore-tests/package.nix @@ -35,7 +35,7 @@ mkMesonExecutable (finalAttrs: { ../../.version ./.version ./meson.build - # ./meson.options + ./meson.options (fileset.fileFilter (file: file.hasExt "cc") ./.) (fileset.fileFilter (file: file.hasExt "hh") ./.) ];