gh-130090: Support PGO for clang-cl on Windows (GH-129907)

This commit is contained in:
Chris Eibl 2025-03-04 20:29:03 +01:00 committed by GitHub
parent 3dd3675492
commit d8a1cf469e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 99 additions and 5 deletions

View file

@ -504,6 +504,7 @@ Grant Edwards
Vlad Efanov
Zvi Effron
John Ehresman
Chris Eibl
Tal Einat
Eric Eisner
Andrew Eland

View file

@ -0,0 +1,2 @@
Building with ``PlatformToolset=ClangCL`` on Windows now supports PGO
(profile guided optimization). Patch by Chris Eibl with invaluable support from Steve Dover.

View file

@ -92,6 +92,7 @@
<AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<Optimization>Disabled</Optimization>
<WholeProgramOptimization>false</WholeProgramOptimization>
<AdditionalOptions Condition="$(PlatformToolset) == 'ClangCL'">%(AdditionalOptions) -fno-lto</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<__PyprojectClangCl_Props_Imported>true</__PyprojectClangCl_Props_Imported>
</PropertyGroup>
<PropertyGroup>
<!-- CLANG_PROFILE_PATH is configurable for "remote PGO builds"
For convenience, we also accept paths without trailing slashes.
-->
<CLANG_PROFILE_PATH Condition="'$(CLANG_PROFILE_PATH)' == ''">$(OutDir)</CLANG_PROFILE_PATH>
<_CLANG_PROFILE_PATH>$(CLANG_PROFILE_PATH)</_CLANG_PROFILE_PATH>
<_CLANG_PROFILE_PATH Condition="!HasTrailingSlash($(_CLANG_PROFILE_PATH))">$(_CLANG_PROFILE_PATH)\</_CLANG_PROFILE_PATH>
</PropertyGroup>
<ItemGroup>
<_profrawFiles Include="$(OutDir)instrumented\$(TargetName)_*.profraw" />
</ItemGroup>
<Target Name="EnsureClangProfileData" BeforeTargets="PrepareForBuild"
Condition="'$(SupportPGO)' and $(Configuration) == 'PGUpdate'">
<Error Text="PGO run did not succeed (no $(TargetName)_*.profraw files) and there is no data to merge"
Condition="$(RequireProfileData) == 'true' and @(_profrawFiles) == ''" />
</Target>
<Target Name="MergeClangProfileData" BeforeTargets="PrepareForBuild"
Condition="'$(SupportPGO)' and $(Configuration) == 'PGUpdate'"
Inputs="@(_profrawFiles)"
Outputs="$(OutDir)instrumented\profdata.profdata">
<Exec
Command='"$(LLVMInstallDir)\bin\llvm-profdata.exe" merge -output="$(OutDir)instrumented\profdata.profdata" "$(OutDir)instrumented\*_*.profraw"' />
</Target>
<Target Name="CleanClangProfileData" BeforeTargets="Clean">
<Delete Files="@(_profrawFiles)" TreatErrorsAsWarnings="true" />
<Delete Files="$(OutDir)instrumented\profdata.profdata" TreatErrorsAsWarnings="true" />
</Target>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalOptions>-Wno-deprecated-non-prototype -Wno-unused-label -Wno-pointer-sign -Wno-incompatible-pointer-types-discards-qualifiers -Wno-unused-function %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="'$(Platform)' == 'Win32'">-m32 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="'$(Platform)' == 'x64'">-m64 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="$(Configuration) != 'Debug'">-flto %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="$(SupportPGO) and $(Configuration) == 'PGInstrument'">-fprofile-instr-generate=$(_CLANG_PROFILE_PATH)$(TargetName)_%m.profraw %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="$(SupportPGO) and $(Configuration) == 'PGUpdate'">-fprofile-instr-use=$(OutDir)instrumented\profdata.profdata -Wno-profile-instr-unprofiled %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
</ItemDefinitionGroup>
</Project>

View file

@ -24,6 +24,9 @@
<LinkIncremental Condition="$(Configuration) != 'Debug'">false</LinkIncremental>
</PropertyGroup>
<!-- We need the above overridden OutDir, so this must be imported after PropertyGroup -->
<Import Project="pyproject-clangcl.props" Condition="$(PlatformToolset) == 'ClangCL' and $(__PyprojectClangCl_Props_Imported) != 'true'" />
<PropertyGroup Condition="$(TargetExt) != ''">
<TargetNameExt>$(TargetName)$(TargetExt)</TargetNameExt>
<_TargetNameSep>$(TargetNameExt.LastIndexOf(`.`))</_TargetNameSep>
@ -69,8 +72,6 @@
<ControlFlowGuard Condition="$(EnableControlFlowGuard) != ''">$(EnableControlFlowGuard)</ControlFlowGuard>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="$(PlatformToolset) == 'ClangCL'">-Wno-deprecated-non-prototype -Wno-unused-label -Wno-pointer-sign -Wno-incompatible-pointer-types-discards-qualifiers -Wno-unused-function %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="$(Configuration) != 'Debug' and $(PlatformToolset) == 'ClangCL'">-flto %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="$(MSVCHasBrokenARM64Clamping) == 'true' and $(Platform) == 'ARM64'">-d2pattern-opt-disable:-932189325 %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="$(MSVCHasBrokenARM64SignExtension) == 'true' and $(Platform) == 'ARM64'">-d2ssa-patterns-all- %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="$(GenerateSourceDependencies) == 'true'">/sourceDependencies "$(IntDir.Trim(`\`))" %(AdditionalOptions)</AdditionalOptions>
@ -186,7 +187,7 @@ public override bool Execute() {
Targets="CleanAll" />
</Target>
<Target Name="CopyPGCFiles" BeforeTargets="PrepareForBuild" Condition="$(Configuration) == 'PGUpdate'">
<Target Name="CopyPGCFiles" BeforeTargets="PrepareForBuild" Condition="$(Configuration) == 'PGUpdate' and $(PlatformToolset) != 'ClangCL'">
<ItemGroup>
<_PGCFiles Include="$(OutDir)instrumented\$(TargetName)!*.pgc" />
<_PGDFile Include="$(OutDir)instrumented\$(TargetName).pgd" />
@ -194,7 +195,7 @@ public override bool Execute() {
</ItemGroup>
<Delete Files="@(_CopyFiles->'$(OutDir)%(Filename)%(Extension)')" />
<Error Text="PGO run did not succeed (no $(TargetName)!*.pgc files) and there is no data to merge"
Condition="$(RequirePGCFiles) == 'true' and @(_PGCFiles) == ''" />
Condition="$(RequireProfileData) == 'true' and @(_PGCFiles) == ''" />
<Copy SourceFiles="@(_CopyFiles)"
DestinationFolder="$(OutDir)"
UseHardLinksIfPossible="true"

View file

@ -81,7 +81,7 @@
</ImportGroup>
<PropertyGroup>
<KillPython>true</KillPython>
<RequirePGCFiles>true</RequirePGCFiles>
<RequireProfileData>true</RequireProfileData>
<IncludeExternals Condition="$(IncludeExternals) == '' and Exists('$(zlibDir)\zlib.h')">true</IncludeExternals>
<IncludeExternals Condition="$(IncludeExternals) == ''">false</IncludeExternals>
</PropertyGroup>

View file

@ -52,6 +52,45 @@ Release
settings, though without PGO.
Building Python using Clang/LLVM
--------------------------------
See https://learn.microsoft.com/cpp/build/clang-support-msbuild
for how to install and use clang-cl bundled with Microsoft Visual Studio.
You can use the IDE to switch to clang-cl for local development,
but because this alters the *.vcxproj files, the recommended way is
to use build.bat:
build.bat "/p:PlatformToolset=ClangCL"
All other build.bat options continue to work as with MSVC, so this
will create a 64bit release binary.
You can also use a specific version of clang-cl downloaded from
https://github.com/llvm/llvm-project/releases, e.g.
clang+llvm-18.1.8-x86_64-pc-windows-msvc.tar.xz.
Given you have extracted that to <my-clang-dir>, you can use it like so
build.bat --pgo "/p:PlatformToolset=ClangCL" "/p:LLVMInstallDir=<my-clang-dir> "/p:LLVMToolsVersion=18"
Setting LLVMToolsVersion to the major version is enough, although you
can be specific and use 18.1.8 in the above example, too.
Use the --pgo option to build with PGO (Profile Guided Optimization).
However, if you want to run the PGO task
on a different host than the build host, you must pass
"/p:CLANG_PROFILE_PATH=<relative-path-to-instrumented-dir-on-remote-host>"
in the PGInstrument step to make sure the profile data is generated
into the instrumented directory when running the PGO task.
E.g., if you place the instrumented binaries into the folder
"workdir/instrumented" and then run the PGO task using "workdir"
as the current working directory, the usage is
"/p:CLANG_PROFILE_PATH=instrumented"
Like in the MSVC case, after fetching (or manually copying) the instrumented
folder back into your build tree, you can continue with the PGUpdate
step with no further parameters.
Building Python using the build.bat script
----------------------------------------------