[llvm] [Windows] 12% faster compile by improved PGO training and re-enable ThinLTO (PR #219263)
Marcus Perryman via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 28 05:01:54 PDT 2026
https://github.com/marcpems updated https://github.com/llvm/llvm-project/pull/219263
>From 026c0f8ccf24b44930091d0123286058b5688e78 Mon Sep 17 00:00:00 2001
From: marcpems <marcpems at users.noreply.github.com>
Date: Fri, 28 Aug 2026 11:05:26 +0100
Subject: [PATCH] [Windows] Add optional PGO/ThinLTO/PDB build-variant support
to release-binaries.yml
Adds a minimal, additive build-variant/enable-pdb input to the
existing release-binaries.yml workflow (rather than a separate
duplicate workflow file), plus the corresponding
--enable-pgo/--enable-thinlto/--enable-pdb flags in
build_llvm_release.bat. Default behavior (build-variant=neither,
enable-pdb=false) is unchanged.
Co-authored-by: Copilot <223556219+Copilot at users.noreply.github.com>
---
.github/workflows/release-binaries.yml | 105 +++++++++++++++++++++-
llvm/utils/release/build_llvm_release.bat | 89 ++++++++++++++----
2 files changed, 171 insertions(+), 23 deletions(-)
diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml
index d837461b24643..8d2d8d163dffd 100644
--- a/.github/workflows/release-binaries.yml
+++ b/.github/workflows/release-binaries.yml
@@ -12,6 +12,26 @@ on:
required: true
default: false
type: boolean
+ build-variant:
+ description: "Windows only: which of PGO training / ThinLTO to enable"
+ required: false
+ default: neither
+ type: choice
+ options:
+ - neither
+ - pgo-only
+ - thinlto-only
+ - pgo-and-thinlto
+ enable-pdb:
+ description: "Windows only: also generate and upload PDB debug info"
+ required: false
+ default: false
+ type: boolean
+ enhanced-pgo:
+ description: "Windows only: when PGO is enabled, train the instrumented clang by building LLVMSupport instead of the legacy single-file Sema.cpp training step"
+ required: false
+ default: true
+ type: boolean
runs-on:
description: "Runner to use for the build"
required: true
@@ -36,6 +56,21 @@ on:
required: true
default: false
type: boolean
+ build-variant:
+ description: "Windows only: which of PGO training / ThinLTO to enable"
+ required: false
+ default: neither
+ type: string
+ enable-pdb:
+ description: "Windows only: also generate and upload PDB debug info"
+ required: false
+ default: false
+ type: boolean
+ enhanced-pgo:
+ description: "Windows only: when PGO is enabled, train the instrumented clang by building LLVMSupport instead of the legacy single-file Sema.cpp training step"
+ required: false
+ default: true
+ type: boolean
runs-on:
description: "Runner to use for the build"
required: true
@@ -69,6 +104,10 @@ jobs:
build-runs-on: ${{ steps.vars.outputs.build-runs-on }}
test-runs-on: ${{ steps.vars.outputs.build-runs-on }}
attestation-name: ${{ steps.vars.outputs.attestation-name }}
+ windows-enable-pgo: ${{ steps.vars.outputs.windows-enable-pgo }}
+ windows-enable-thinlto: ${{ steps.vars.outputs.windows-enable-thinlto }}
+ windows-enable-pdb: ${{ steps.vars.outputs.windows-enable-pdb }}
+ windows-enhanced-pgo: ${{ steps.vars.outputs.windows-enhanced-pgo }}
steps:
- name: Validate Release Version
@@ -90,6 +129,9 @@ jobs:
LLVM_VERSION_MAJOR: ${{ steps.version-from-source.outputs.major }}
INPUTS_RUNS_ON: ${{ inputs.runs-on }}
INPUTS_RELEASE_VERSION: ${{ inputs.release-version }}
+ INPUTS_BUILD_VARIANT: ${{ inputs.build-variant }}
+ INPUTS_ENABLE_PDB: ${{ inputs.enable-pdb }}
+ INPUTS_ENHANCED_PGO: ${{ inputs.enhanced-pgo }}
shell: bash
# In order for the test-release.sh script to run correctly, the LLVM
# source needs to be at the following location relative to the build dir:
@@ -160,8 +202,15 @@ jobs:
fi
if [ "$RUNNER_OS" = "Windows" ]; then
- # The build times out on Windows, so we need to disable LTO.
- target_cmake_flags="$target_cmake_flags -DLLVM_RELEASE_ENABLE_LTO=OFF"
+ # The build times out on Windows, so we need to disable LTO by
+ # default; --build-variant can re-enable ThinLTO explicitly.
+ case "$INPUTS_BUILD_VARIANT" in
+ thinlto-only|pgo-and-thinlto)
+ ;;
+ *)
+ target_cmake_flags="$target_cmake_flags -DLLVM_RELEASE_ENABLE_LTO=OFF"
+ ;;
+ esac
fi
case "$INPUTS_RUNS_ON" in
@@ -206,16 +255,41 @@ jobs:
target_cmake_flags="$target_cmake_flags -D${bootstrap_prefix}_CPACK_PACKAGE_FILE_NAME=$release_binary_basename"
+ # Translate --build-variant/--enable-pdb into individual flags
+ # consumed by the Windows build_llvm_release.bat invocation below
+ # (only meaningful for Windows builds).
+ windows_enable_pgo="false"
+ windows_enable_thinlto="false"
+ case "$INPUTS_BUILD_VARIANT" in
+ pgo-only) windows_enable_pgo="true" ;;
+ thinlto-only) windows_enable_thinlto="true" ;;
+ pgo-and-thinlto) windows_enable_pgo="true"; windows_enable_thinlto="true" ;;
+ esac
+ windows_enable_pdb="false"
+ if [ "$INPUTS_ENABLE_PDB" = "true" ]; then
+ windows_enable_pdb="true"
+ fi
+ windows_enhanced_pgo="false"
+ if [ "$INPUTS_ENHANCED_PGO" = "true" ]; then
+ windows_enhanced_pgo="true"
+ fi
+
echo "target-cmake-flags=$target_cmake_flags" >> $GITHUB_OUTPUT
echo "build-runs-on=$build_runs_on" >> $GITHUB_OUTPUT
echo "test-runs-on=$test_runs_on" >> $GITHUB_OUTPUT
echo "attestation-name=$RUNNER_OS-$RUNNER_ARCH-release-binary-attestation" >> $GITHUB_OUTPUT
+ echo "windows-enable-pgo=$windows_enable_pgo" >> $GITHUB_OUTPUT
+ echo "windows-enable-thinlto=$windows_enable_thinlto" >> $GITHUB_OUTPUT
+ echo "windows-enable-pdb=$windows_enable_pdb" >> $GITHUB_OUTPUT
+ echo "windows-enhanced-pgo=$windows_enhanced_pgo" >> $GITHUB_OUTPUT
build-release-package:
name: "Build Release Package"
needs: prepare
if: github.repository_owner == 'llvm'
runs-on: ${{ needs.prepare.outputs.build-runs-on }}
+ # Combined PGO+ThinLTO(+PDB) Windows builds can exceed the default 6h limit.
+ timeout-minutes: 600
outputs:
digest: ${{ steps.digest.outputs.digest }}
artifact-id: ${{ steps.artifact-upload.outputs.artifact-id }}
@@ -295,20 +369,36 @@ jobs:
env:
INPUTS_RUNS_ON: ${{ inputs.runs-on }}
LLVM_VERSION: ${{ needs.prepare.outputs.release-version }}
+ WINDOWS_ENABLE_PGO: ${{ needs.prepare.outputs.windows-enable-pgo }}
+ WINDOWS_ENABLE_THINLTO: ${{ needs.prepare.outputs.windows-enable-thinlto }}
+ WINDOWS_ENABLE_PDB: ${{ needs.prepare.outputs.windows-enable-pdb }}
+ WINDOWS_ENHANCED_PGO: ${{ needs.prepare.outputs.windows-enhanced-pgo }}
run: |
subst S: ${{ github.workspace }}
cd S:\llvm\utils\release\
- .\build_llvm_release.bat "--$($env:RUNNER_ARCH.ToLower())" --version $env:LLVM_VERSION --local-python --skip-checkout
+ $variantArgs = @()
+ if ($env:WINDOWS_ENABLE_PGO -eq "true") { $variantArgs += "--enable-pgo" }
+ if ($env:WINDOWS_ENABLE_THINLTO -eq "true") { $variantArgs += "--enable-thinlto" }
+ if ($env:WINDOWS_ENABLE_PDB -eq "true") { $variantArgs += "--enable-pdb" }
+ if ($env:WINDOWS_ENHANCED_PGO -eq "true") { $variantArgs += "--enhanced-pgo" }
+ .\build_llvm_release.bat "--$($env:RUNNER_ARCH.ToLower())" --version $env:LLVM_VERSION --local-python --skip-checkout @variantArgs
if ($env:INPUTS_RUNS_ON -eq "windows-11-arm") {
$zstd = (Get-ChildItem -Recurse -Filter "zstd.exe" | Select-Object -First 1).fullName
mv $zstd $env:GITHUB_WORKSPACE
}
$installer = (Get-ChildItem -Recurse -Filter "LLVM-*.msi" | Select-Object -First 1).fullName
- $tarball = (Get-ChildItem -Recurse -Filter "*.tar.xz" | Select-Object -First 1).fullName
+ $tarball = (Get-ChildItem -Recurse -Filter "*.tar.xz" | Where-Object { $_.Name -notlike "*-pdb.tar.xz" } | Select-Object -First 1).fullName
# Move installer to top-level directory so it is easier to upload.
mv $installer $env:GITHUB_WORKSPACE
mv $tarball $env:GITHUB_WORKSPACE
echo "windows-installer-filename=$(Split-Path -Path $installer -Leaf)" >> $env:GITHUB_OUTPUT
+ if ($env:WINDOWS_ENABLE_PDB -eq "true") {
+ $pdbArchive = (Get-ChildItem -Recurse -Filter "*-pdb.tar.xz" | Select-Object -First 1).fullName
+ if ($pdbArchive) {
+ mv $pdbArchive $env:GITHUB_WORKSPACE
+ echo "windows-pdb-filename=$(Split-Path -Path $pdbArchive -Leaf)" >> $env:GITHUB_OUTPUT
+ }
+ }
- name: Dump Wix logs
if: runner.os == 'Windows' && failure()
@@ -361,6 +451,13 @@ jobs:
${{ needs.prepare.outputs.release-binary-filename-zstd }}
${{ steps.build-windows.outputs.windows-installer-filename }}
+ - name: Upload Windows PDB debug info
+ if: runner.os == 'Windows' && steps.build-windows.outputs.windows-pdb-filename != ''
+ uses: actions/upload-artifact at 043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ with:
+ name: ${{ runner.os }}-${{ runner.arch }}-release-pdb
+ path: ${{ steps.build-windows.outputs.windows-pdb-filename }}
+
- name: Run Tests
# These almost always fail so don't let them fail the build and prevent the uploads.
if : runner.os != 'Windows'
diff --git a/llvm/utils/release/build_llvm_release.bat b/llvm/utils/release/build_llvm_release.bat
index db74c8bb0456d..818b956acae3f 100644
--- a/llvm/utils/release/build_llvm_release.bat
+++ b/llvm/utils/release/build_llvm_release.bat
@@ -10,7 +10,7 @@ goto begin
echo Script for building the LLVM installer on Windows,
echo used for the releases at https://github.com/llvm/llvm-project/releases
echo.
-echo Usage: build_llvm_release.bat --version ^<version^> [--x86,--x64, --arm64] [--skip-checkout] [--local-python] [--force-msvc]
+echo Usage: build_llvm_release.bat --version ^<version^> [--x86,--x64, --arm64] [--skip-checkout] [--local-python] [--force-msvc] [--enable-pgo] [--enhanced-pgo] [--enable-thinlto] [--enable-pdb]
echo.
echo Options:
echo --version: [required] version to build
@@ -21,6 +21,11 @@ echo --arm64: build and test arm64 variant
echo --skip-checkout: use local git checkout instead of downloading src.zip
echo --local-python: use installed Python and does not try to use a specific version (3.11)
echo --force-msvc: use MSVC compiler for stage0, even if clang-cl is present
+echo --enable-pgo: build an instrumented stage1 clang, train it, and use the resulting profile for stage2 (64-bit builds only)
+echo --enhanced-pgo: when used with --enable-pgo, train the instrumented clang by building LLVMSupport
+echo instead of the legacy single-file Sema.cpp training step (64-bit builds only)
+echo --enable-thinlto: build stage2 with ThinLTO (64-bit builds only)
+echo --enable-pdb: generate PDB debug info files for stage2 and include them as an additional artifact (64-bit builds only)
echo.
echo Note: At least one variant to build is required.
echo.
@@ -40,6 +45,10 @@ set arm64=
set skip-checkout=
set local-python=
set force-msvc=
+set enable-pgo=
+set enhanced-pgo=
+set enable-thinlto=
+set enable-pdb=
call :parse_args %*
if "%help%" NEQ "" goto usage
@@ -185,8 +194,8 @@ set common_cmake_flags=^
-DCMAKE_C_FLAGS="%common_compiler_flags%" ^
-DCMAKE_CXX_FLAGS="%common_compiler_flags%" ^
-DLLVM_ENABLE_RPMALLOC=ON ^
- -DLLVM_ENABLE_PROJECTS="clang;lld" ^
- -DLLVM_ENABLE_RUNTIMES="compiler-rt" ^
+ -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld" ^
+ -DLLVM_ENABLE_RUNTIMES="compiler-rt;openmp" ^
-DCPACK_GENERATOR="WIX" ^
-DCOMPILER_RT_BUILD_ORC=OFF
@@ -263,7 +272,6 @@ REM with forward slash.
set all_cmake_flags=^
%cmake_flags% ^
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld;lldb;" ^
- -DLLVM_ENABLE_RUNTIMES="compiler-rt;openmp" ^
%common_lldb_flags% ^
-DPYTHON_HOME=%PYTHONHOME% ^
-DCMAKE_C_COMPILER=%stage0_bin_dir%/clang-cl.exe ^
@@ -332,6 +340,8 @@ ninja check-lld || exit /b 1
if "%arch%"=="amd64" (
ninja check-runtimes || exit /b 1
)
+ninja check-clang-tools || ninja check-clang-tools || ninja check-clang-tools || exit /b 1
+ninja check-clangd || ninja check-clangd || ninja check-clangd || exit /b 1
cd..
REM CMake expects the paths that specifies the compiler and linker to be
@@ -351,10 +361,12 @@ set cmake_flags=%all_cmake_flags:\=/%
mkdir build_%arch%
cd build_%arch%
-call :do_generate_profile || exit /b 1
+if "%enable-pgo%" == "true" call :do_generate_profile || exit /b 1
+set lto_cmake_flag=
+if "%enable-thinlto%" == "true" set lto_cmake_flag=-DLLVM_ENABLE_LTO=Thin
cmake -GNinja %cmake_flags% ^
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld;lldb;flang;mlir" ^
- -DLLVM_ENABLE_RUNTIMES="compiler-rt;openmp" ^
+ %lto_cmake_flag% ^
%common_lldb_flags% ^
-DPYTHON_HOME=%PYTHONHOME% ^
%cmake_profile_flags% %llvm_src%\llvm || exit /b 1
@@ -378,14 +390,32 @@ if "%arch%"=="amd64" (
) else (
set filename=clang+llvm-%version%-aarch64-pc-windows-msvc
)
+REM NOTE: LLVM_ENABLE_PDB is intentionally only set for this toolchain-only
+REM (tarball) reconfigure, not for the MSI/WiX "ninja package" build above:
+REM bundling PDBs into the WiX-generated MSI causes CPack/WiX packaging
+REM failures (likely due to duplicate file basenames / component limits),
+REM so PDBs are packaged separately as their own tarball instead.
+set pdb_cmake_flag=
+if "%enable-pdb%" == "true" set pdb_cmake_flag=-DLLVM_ENABLE_PDB=ON
cmake -GNinja %cmake_flags% %cmake_profile_flags% -DLLVM_INSTALL_TOOLCHAIN_ONLY=OFF ^
- -DCMAKE_INSTALL_PREFIX=%build_dir%/%filename% %llvm_src%\llvm || exit /b 1
+ -DCMAKE_INSTALL_PREFIX=%build_dir%/%filename% ^
+ %pdb_cmake_flag% ^
+ %llvm_src%\llvm || exit /b 1
ninja install || exit /b 1
:: check llvm_config is present & returns something
%build_dir%/%filename%/bin/llvm-config.exe --bindir || exit /b 1
cd ..
7z a -ttar -so %filename%.tar %filename% | 7z a -txz -si %filename%.tar.xz
+if "%enable-pdb%" == "true" (
+ :: Package the PDB debug info files produced alongside the install tree
+ :: into their own archive so they can be uploaded as a separate artifact.
+ set pdb_filename=%filename%-pdb
+ pushd %filename%
+ 7z a -ttar -so ..\!pdb_filename!.tar bin\*.pdb lib\*.pdb | 7z a -txz -si ..\!pdb_filename!.tar.xz
+ popd
+)
+
exit /b 0
::==============================================================================
@@ -399,8 +429,10 @@ set python_dir=%1
REM Set Python environment
if "%local-python%" == "true" (
- FOR /F "delims=" %%i IN ('where python.exe ^| head -1') DO set python_exe=%%i
- set PYTHONHOME=!python_exe:~0,-11!
+ set python_exe=
+ FOR /F "delims=" %%i IN ('where python.exe') DO if not defined python_exe set python_exe=%%i
+ for %%p in ("!python_exe!") do set PYTHONHOME=%%~dpp
+ if "!PYTHONHOME:~-1!" == "\" set PYTHONHOME=!PYTHONHOME:~0,-1!
) else (
%python_dir%/python.exe --version || exit /b 1
set PYTHONHOME=%python_dir%
@@ -497,18 +529,37 @@ cmake -GNinja %cmake_flags% -DLLVM_TARGETS_TO_BUILD=Native ^
ninja clang || exit /b 1
set instrumented_clang=%cd:\=/%/bin/clang-cl.exe
cd ..
-REM Use that to build part of llvm to generate a profile.
mkdir train
cd train
-cmake -GNinja %cmake_flags% ^
- -DCMAKE_C_COMPILER=%instrumented_clang% ^
- -DCMAKE_CXX_COMPILER=%instrumented_clang% ^
- -DLLVM_ENABLE_PROJECTS=clang ^
- -DLLVM_TARGETS_TO_BUILD=Native ^
- %llvm_src%\llvm || exit /b 1
-REM Drop profiles generated from running cmake; those are not representative.
-del ..\instrument\profiles\*.profraw
-ninja tools/clang/lib/Sema/CMakeFiles/obj.clangSema.dir/Sema.cpp.obj
+if "%enhanced-pgo%" == "true" (
+ REM Build LLVMSupport with the instrumented clang to generate a broad profile.
+ REM This mirrors the Linux perf-training approach (llvm-support/build.test)
+ REM and exercises the compiler across many translation units and code paths,
+ REM rather than compiling a single file (Sema.cpp).
+ cmake -GNinja ^
+ -DCMAKE_BUILD_TYPE=Release ^
+ -DCMAKE_C_COMPILER=%instrumented_clang% ^
+ -DCMAKE_CXX_COMPILER=%instrumented_clang% ^
+ -DLLVM_TARGETS_TO_BUILD=Native ^
+ -DLLVM_ENABLE_PROJECTS="" ^
+ -DLLVM_ENABLE_RUNTIMES="" ^
+ %llvm_src%\llvm || exit /b 1
+ REM Drop profiles generated from running cmake; those are not representative.
+ del ..\instrument\profiles\*.profraw
+ ninja LLVMSupport || exit /b 1
+) else (
+ REM Legacy training step: use that build of clang to compile a single file,
+ REM as a cheap approximation of a real training workload.
+ cmake -GNinja %cmake_flags% ^
+ -DCMAKE_C_COMPILER=%instrumented_clang% ^
+ -DCMAKE_CXX_COMPILER=%instrumented_clang% ^
+ -DLLVM_ENABLE_PROJECTS=clang ^
+ -DLLVM_TARGETS_TO_BUILD=Native ^
+ %llvm_src%\llvm || exit /b 1
+ REM Drop profiles generated from running cmake; those are not representative.
+ del ..\instrument\profiles\*.profraw
+ ninja tools/clang/lib/Sema/CMakeFiles/obj.clangSema.dir/Sema.cpp.obj || exit /b 1
+)
cd ..
set profile=%cd:\=/%/profile.profdata
%stage0_bin_dir%\llvm-profdata merge -output=%profile% instrument\profiles\*.profraw || exit /b 1
More information about the llvm-commits
mailing list