From 9c58c8f739799725c6d43e1b94731f1cce5a900b Mon Sep 17 00:00:00 2001 From: Sergei Zimmerman Date: Sun, 20 Jul 2025 18:23:13 +0300 Subject: [PATCH] ci: Add build profiling job This adds a GHA jobs to help analyze build times and its regressions. It is based on `clangStdenv` with `-ftime-trace` together with `ClangBuildAnalyzer` to prepare markdown summary for individual components. This also has the minor benefit of dogfooding CA and impure derivations. --- .github/workflows/ci.yml | 23 +++++++ ci/gha/profile-build/default.nix | 101 +++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 ci/gha/profile-build/default.nix diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da6f35907..6f5167834 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -221,3 +221,26 @@ jobs: github_token: ${{ secrets.GITHUB_TOKEN }} - uses: DeterminateSystems/magic-nix-cache-action@main - run: nix build -L --out-link ./new-nix && PATH=$(pwd)/new-nix/bin:$PATH MAX_FLAKES=25 flake-regressions/eval-all.sh + + profile_build: + needs: tests + runs-on: ubuntu-24.04 + timeout-minutes: 60 + if: >- + github.event_name == 'push' && + github.ref_name == 'master' + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: ./.github/actions/install-nix-action + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + dogfood: true + extra_nix_config: | + experimental-features = flakes nix-command ca-derivations impure-derivations + max-jobs = 1 + - uses: DeterminateSystems/magic-nix-cache-action@main + - run: | + nix build -L --file ./ci/gha/profile-build buildTimeReport --out-link build-time-report.md + cat build-time-report.md >> $GITHUB_STEP_SUMMARY diff --git a/ci/gha/profile-build/default.nix b/ci/gha/profile-build/default.nix new file mode 100644 index 000000000..2b7261b71 --- /dev/null +++ b/ci/gha/profile-build/default.nix @@ -0,0 +1,101 @@ +{ + nixFlake ? builtins.getFlake ("git+file://" + toString ../../..), + system ? builtins.currentSystem, + pkgs ? nixFlake.inputs.nixpkgs.legacyPackages.${system}, +}: + +let + inherit (pkgs) lib; + + nixComponentsInstrumented = + (nixFlake.lib.makeComponents { + inherit pkgs; + getStdenv = p: p.clangStdenv; + }).overrideScope + ( + _: _: { + mesonComponentOverrides = finalAttrs: prevAttrs: { + outputs = (prevAttrs.outputs or [ "out" ]) ++ [ "buildprofile" ]; + nativeBuildInputs = [ pkgs.clangbuildanalyzer ] ++ prevAttrs.nativeBuildInputs or [ ]; + __impure = true; + + env = { + CFLAGS = "-ftime-trace"; + CXXFLAGS = "-ftime-trace"; + }; + + preBuild = '' + ClangBuildAnalyzer --start $PWD + ''; + + postBuild = '' + ClangBuildAnalyzer --stop $PWD $buildprofile + ''; + }; + } + ); + + componentsToProfile = { + "nix-util" = { }; + "nix-util-c" = { }; + "nix-util-test-support" = { }; + "nix-util-tests" = { }; + "nix-store" = { }; + "nix-store-c" = { }; + "nix-store-test-support" = { }; + "nix-store-tests" = { }; + "nix-fetchers" = { }; + "nix-fetchers-c" = { }; + "nix-fetchers-tests" = { }; + "nix-expr" = { }; + "nix-expr-c" = { }; + "nix-expr-test-support" = { }; + "nix-expr-tests" = { }; + "nix-flake" = { }; + "nix-flake-c" = { }; + "nix-flake-tests" = { }; + "nix-main" = { }; + "nix-main-c" = { }; + "nix-cmd" = { }; + "nix-cli" = { }; + }; + + componentDerivationsToProfile = builtins.intersectAttrs componentsToProfile nixComponentsInstrumented; + componentBuildProfiles = lib.mapAttrs ( + n: v: lib.getOutput "buildprofile" v + ) componentDerivationsToProfile; + + buildTimeReport = + pkgs.runCommand "build-time-report" + { + __impure = true; + __structuredAttrs = true; + nativeBuildInputs = [ pkgs.clangbuildanalyzer ]; + inherit componentBuildProfiles; + } + '' + { + echo "# Build time performance profile for components:" + echo + echo "This reports the build profile collected via \`-ftime-trace\` for each component." + echo + } >> $out + + for name in "''\${!componentBuildProfiles[@]}"; do + { + echo "
$name" + echo + echo '````' + ClangBuildAnalyzer --analyze "''\${componentBuildProfiles[$name]}" + echo '````' + echo + echo "
" + } >> $out + done + ''; +in + +{ + inherit buildTimeReport; + inherit componentDerivationsToProfile; +}