-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
add derivation parser benchmark #13569
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <benchmark/benchmark.h> | ||
| ``` | ||
|
|
||
| 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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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")]) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| #include <benchmark/benchmark.h> | ||
| #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 <fstream> | ||
| #include <sstream> | ||
|
|
||
| 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; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| # vim: filetype=meson | ||
|
|
||
| option( | ||
| 'benchmarks', | ||
| type : 'boolean', | ||
| value : false, | ||
| description : 'Build benchmarks (requires gbenchmark)', | ||
| yield : true, | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this option is not the right approach w.r.t. componentized builds? It works in a devshell only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add the option only to the subprojects that have benchmarks and make that option
yield?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could move benchmarks to its own subprojects maybe? Or we just always build them but not run them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if it's warranted for now. Can we stick with just 2 options: in libstore-tests and the top-level file, and the one in
libstore-testswithyield: true.Not a huge fan, because we'd have an unconditional dep on gbenchmark in nixpkgs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the componentized build help here? We would always build the benchmarks, but we don't have to run time, and the thing users actually install won't depend on them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, yeah. I suppose introducing configurability isn't a top priority here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can merge this now, and maybe then consider removing the flags.