I wanted to use Profile Guided Optimization (PGO) for my project, but I have the VS 2015 Community Edition which does not have PGO UI integration. My project has a solution file and the solution file has many other sub-projects within it.
I ended up making a batch file for the instrumentation and a powershell script for optimizing. I also created two property files to override the compile and link options. Let me start with the batch file that performs the instrumentation. A key thing to remember if your solution has multiple projects is that all of the projects must create their executables in one single directory. The output of the linker across all projects must go to this one directory directly, not via a post-build event.
Batch file for instrumenting
msbuild %1 /p:Configuration=%2 /t:Clean
msbuild %1 /p:Configuration=%2 /p:ForceImportBeforeCppTargets=%~dp0\pginstrument.props /maxcpucount:8
This batch file should be invoked from the VS 2015 command prompt. Make sure the one for the right architecture is launched. Invoke this batch file as
pginstrument.bat MySolution.sln Release
The batch file takes the solution file name as the first parameter(%1
) and the configuration as the second(%2
). It begins by cleaning the solution. The ForceImportBeforeCppTargets
overrides a compile option and linker options. The %~dp0
instructs msbuild
to load the pginstrument.props
from the same directory that the batch file was invoked from. The option for maxcpucount
merely instructs msbuild
to use parallel builds. At the end of the build there will be a file with the extension pgd
for each executable file.
Property file for instrumenting (pginstrument.props)
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemDefinitionGroup>
<ClCompile>
<WholeProgramOptimization>true</WholeProgramOptimization>
</ClCompile>
<Link>
<AdditionalOptions>/INCREMENTAL:NO /GENPROFILE /LTCG:PGInstrument %(AdditionalOptions)</AdditionalOptions>
</Link>
</ItemDefinitionGroup>
</Project>
The property file uses the WholeProgramOptimization
tag to set the /GL
flag for the C++ compiler (without this flag the compiler will not be able to instrument the code). It also adds some self-evident linker options.
Run test scenarios
Once the instrumenting build is done, start up the instrumented application and run through the various application scenarios that need to be optimized. This will create files with the pgc
extension for all the DLLs and EXEs that were executed. These files will then be used by the linker to create optimized binaries.
Powershell script for optimizing
param([string]$src, [string]$config = "RelWithDebInfo", [string]$maxcpu = "8")
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser
Get-ChildItem $src -Recurse -Filter *.vcxproj | Where-Object {$_.Name -notlike "INSTALL*"} | ForEach-Object {
$exe = 'msbuild'
$arg1 = $_.FullName
$arg2 = "/p:Configuration=${config}"
$arg3 = "/p:ForceImportBeforeCppTargets=${PSScriptRoot}\pgoptimize.props"
$arg4 = "/t:BuildLink"
$arg5 = "/maxcpucount:${maxcpu}"
&$exe $arg1 $arg2 $arg3 $arg4 $arg5
}
In the optimize step, only the linker step needs to be run. Unfortunately, I could not find a way to run msbuild
on the solution file and only perform the linker step. I could perform the linker step on the individual projects though. However, I have a lot of projects and it seemed tedious to run the optimize step for each one manually. So, I wrote a script that would walk the various project subdirectories, generate and execute the msbuild
statement to optimize. I also use CMake that generates install projects which do not need to be optimized. It’s easier to filter those out in the powershell script. This script file, again, should be invoked from the VS 2015 command prompt. Invoke this script as
powershell pgoptimizer.ps1 -src MySolutionDir -config Release
Property file for optimizing (pgoptimize.props)
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemDefinitionGroup>
<PreBuildEvent>
<Message></Message>
<Command></Command>
</PreBuildEvent>
<Link>
<AdditionalOptions>/INCREMENTAL:NO /USEPROFILE /LTCG:PGOptimize %(AdditionalOptions)</AdditionalOptions>
</Link>
<PostBuildEvent>
<Message></Message>
<Command></Command>
</PostBuildEvent>
</ItemDefinitionGroup>
</Project>
The property file prevents the pre and post build events from running. It also adds linker options to use the pgc
files and optimize the binaries. Test the optimized binaries once they are built.