diff --git a/CMakeLists.txt b/CMakeLists.txt
index a40d7f284df8..a25742172110 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -486,6 +486,11 @@ if(CLR_CROSS_COMPONENTS_BUILD)
include(crosscomponents.cmake)
endif(CLR_CROSS_COMPONENTS_BUILD)
+#-------------------
+# Enable PGO support
+#-------------------
+include(pgosupport.cmake)
+
#-----------------------------------------
# Add Projects
# - project which require platform header not clr's
diff --git a/build.cmd b/build.cmd
index 0974b000add3..2dc479c2c319 100644
--- a/build.cmd
+++ b/build.cmd
@@ -52,6 +52,8 @@ set __BuildTypeChecked=0
set __BuildTypeRelease=0
set __BuildJit32="-DBUILD_JIT32=0"
+set __PgoInstrument=0
+
REM __PassThroughArgs is a set of things that will be passed through to nested calls to build.cmd
REM when using "all".
set __PassThroughArgs=
@@ -103,6 +105,7 @@ if /i "%1" == "skiptests" (set __BuildTests=0&set processedArgs=!proce
if /i "%1" == "skipbuildpackages" (set __BuildPackages=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
if /i "%1" == "usenmakemakefiles" (set __NMakeMakefiles=1&set __ConfigureOnly=1&set __BuildNative=1&set __BuildNativeCoreLib=0&set __BuildCoreLib=0&set __BuildTests=0&set __BuildPackages=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
if /i "%1" == "buildjit32" (set __BuildJit32="-DBUILD_JIT32=1"&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
+if /i "%1" == "pgoinstrument" (set __PgoInstrument=1&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop)
if /i "%1" == "toolset_dir" (set __ToolsetDir=%2&set __PassThroughArgs=%__PassThroughArgs% %2&set processedArgs=!processedArgs! %1 %2&shift&shift&goto Arg_Loop)
if [!processedArgs!]==[] (
@@ -186,6 +189,15 @@ call "%__VSToolsRoot%\VsDevCmd.bat"
@call %__ProjectDir%\run.cmd build -Project=%__ProjectDir%\build.proj -generateHeaderWindows -NativeVersionHeaderFile="%__RootBinDir%\obj\_version.h" %__RunArgs% %__UnprocessedBuildArgs%
+REM =========================================================================================
+REM ===
+REM === Restore optimization profile data
+REM ===
+REM =========================================================================================
+
+echo %__MsgPrefix%Restoring the OptimizationData Package
+@call %__ProjectDir%\run.cmd sync -optdata
+
REM =========================================================================================
REM ===
REM === Build the CLR VM
@@ -228,7 +240,8 @@ if %__BuildNative% EQU 1 (
echo %__MsgPrefix%Regenerating the Visual Studio solution
pushd "%__IntermediatesDir%"
- call "%__SourceDir%\pal\tools\gen-buildsys-win.bat" "%__ProjectDir%" %__VSVersion% %__BuildArch% %__BuildJit32%
+ set __ExtraCmakeArgs="-DCLR_CMAKE_TARGET_OS=%__BuildOs%" "-DCLR_CMAKE_PACKAGES_DIR=%__PackagesDir%" "-DCLR_CMAKE_PGO_INSTRUMENT=%__PgoInstrument%"
+ call "%__SourceDir%\pal\tools\gen-buildsys-win.bat" "%__ProjectDir%" %__VSVersion% %__BuildArch% %__BuildJit32% !__ExtraCmakeArgs!
@if defined __echo @echo on
popd
:SkipConfigure
@@ -281,7 +294,7 @@ if /i "%__DoCrossArchBuild%"=="1" (
pushd "%__CrossCompIntermediatesDir%"
set __CMakeBinDir=%__CrossComponentBinDir%
set "__CMakeBinDir=!__CMakeBinDir:\=/!"
- set __ExtraCmakeArgs="-DCLR_CROSS_COMPONENTS_BUILD=1" "-DCLR_CMAKE_TARGET_ARCH=%__BuildArch%"
+ set __ExtraCmakeArgs="-DCLR_CROSS_COMPONENTS_BUILD=1" "-DCLR_CMAKE_TARGET_ARCH=%__BuildArch%" "-DCLR_CMAKE_TARGET_OS=%__BuildOs%" "-DCLR_CMAKE_PACKAGES_DIR=%__PackagesDir%" "-DCLR_CMAKE_PGO_INSTRUMENT=%__PgoInstrument%"
call "%__SourceDir%\pal\tools\gen-buildsys-win.bat" "%__ProjectDir%" %__VSVersion% %__CrossArch% !__ExtraCmakeArgs!
@if defined __echo @echo on
popd
@@ -522,6 +535,7 @@ echo for the specified platform ^(FreeBSD, Linux, NetBSD, OS X or Windows,
echo respectively^).
echo add nativemscorlib to go further and build the native image for designated mscorlib.
echo toolset_dir ^
: set the toolset directory -- Arm64 use only. Required for Arm64 builds.
+echo pgoinstrument: generate instrumented code for profile guided optimization enabled binaries.
echo configureonly: skip all builds; only run CMake ^(default: CMake and builds are run^)
echo skipconfigure: skip CMake ^(default: CMake is run^)
echo skipmscorlib: skip building System.Private.CoreLib ^(default: System.Private.CoreLib is built^).
diff --git a/build.proj b/build.proj
index 7df2904e3690..c8d7a5d76bfe 100644
--- a/build.proj
+++ b/build.proj
@@ -24,6 +24,10 @@
+
+
+
+
diff --git a/build.sh b/build.sh
index 5959abdfa996..e639ca0197ba 100755
--- a/build.sh
+++ b/build.sh
@@ -35,6 +35,7 @@ usage()
echo "clangx.y - optional argument to build using clang version x.y."
echo "cross - optional argument to signify cross compilation,"
echo " - will use ROOTFS_DIR environment variable if set."
+ echo "pgoinstrument - generate instrumented code for profile guided optimization enabled binaries."
echo "configureonly - do not perform any builds; just configure the build."
echo "skipconfigure - skip build configuration."
echo "skipnative - do not build native components."
@@ -175,10 +176,14 @@ build_coreclr()
echo $__versionSourceLine > $__versionSourceFile
fi
+ echo "Restoring the OptimizationData package"
+ "$__ProjectRoot/run.sh" sync -optdata
+
pushd "$__IntermediatesDir"
# Regenerate the CMake solution
- echo "Invoking \"$__ProjectRoot/src/pal/tools/gen-buildsys-clang.sh\" \"$__ProjectRoot\" $__ClangMajorVersion $__ClangMinorVersion $__BuildArch $__BuildType $__CodeCoverage $__IncludeTests $generator $__cmakeargs"
- "$__ProjectRoot/src/pal/tools/gen-buildsys-clang.sh" "$__ProjectRoot" $__ClangMajorVersion $__ClangMinorVersion $__BuildArch $__BuildType $__CodeCoverage $__IncludeTests $generator "$__cmakeargs"
+ __ExtraCmakeArgs="-DCLR_CMAKE_TARGET_OS=$__BuildOS -DCLR_CMAKE_PACKAGES_DIR=$__PackagesDir -DCLR_CMAKE_PGO_INSTRUMENT=$__PgoInstrument"
+ echo "Invoking \"$__ProjectRoot/src/pal/tools/gen-buildsys-clang.sh\" \"$__ProjectRoot\" $__ClangMajorVersion $__ClangMinorVersion $__BuildArch $__BuildType $__CodeCoverage $__IncludeTests $generator $__ExtraCmakeArgs $__cmakeargs"
+ "$__ProjectRoot/src/pal/tools/gen-buildsys-clang.sh" "$__ProjectRoot" $__ClangMajorVersion $__ClangMinorVersion $__BuildArch $__BuildType $__CodeCoverage $__IncludeTests $generator "$__ExtraCmakeArgs" "$__cmakeargs"
popd
fi
@@ -459,6 +464,7 @@ __RunArgs=
__MSBCleanBuildArgs=
__UseNinja=0
__VerboseBuild=0
+__PgoInstrument=0
__ConfigureOnly=0
__SkipConfigure=0
__SkipRestore=""
@@ -558,6 +564,10 @@ while :; do
__UseNinja=1
;;
+ pgoinstrument)
+ __PgoInstrument=1
+ ;;
+
configureonly)
__ConfigureOnly=1
__SkipMSCorLib=1
diff --git a/config.json b/config.json
index 1ddb2f94f508..d25fdba043d2 100644
--- a/config.json
+++ b/config.json
@@ -48,6 +48,12 @@
"values": [],
"defaultValue": ""
},
+ "RestoreOptData": {
+ "description": "MsBuild target that restores optimization profile data.",
+ "valueType": "target",
+ "values": [],
+ "defaultValue": ""
+ },
"RestoreDuringBuild": {
"description": "Enables/disables package restore.",
"valueType": "property",
@@ -362,6 +368,14 @@
"RestoreNETCorePlatforms": "default"
}
},
+ "optdata": {
+ "description": "Restores optimization profile data for the repository.",
+ "settings": {
+ "Project": "./build.proj",
+ "RestoreDuringBuild": true,
+ "RestoreOptData": "default"
+ }
+ },
"ab": {
"description": "Downloads the latests product packages from Azure. The values for '-AzureAccount' and '-AzureToken' are required",
"settings": {
diff --git a/extract-from-json.py b/extract-from-json.py
new file mode 100755
index 000000000000..e432b2b067f0
--- /dev/null
+++ b/extract-from-json.py
@@ -0,0 +1,56 @@
+#!/usr/bin/python
+
+import argparse
+import json
+import sys
+
+def parse_args():
+ parser = argparse.ArgumentParser(
+ description="""Extracts information from a json file by navigating the JSON object using a
+ sequence of property accessors and returning the JSON subtree, or the raw data, found
+ at that location."""
+ )
+
+ parser.add_argument(
+ '-f', '--file',
+ metavar='',
+ help="Path to project.json file to parse",
+ required=True,
+ )
+
+ parser.add_argument(
+ 'property',
+ metavar='property_name',
+ help="""Name of property to extract using object notation.
+ Pass multiple values to drill down into nested objects (in order).""",
+ nargs='*',
+ )
+
+ parser.add_argument(
+ '-r', '--raw',
+ help="""Dumps the raw object found at the requested location.
+ If omitted, returns a JSON formatted object instead.""",
+ action='store_true',
+ default=False
+ )
+
+ return parser.parse_args()
+
+def main():
+ args = parse_args()
+
+ with open(args.file) as json_file:
+ selected_property = json.load(json_file)
+
+ for prop in args.property:
+ selected_property = selected_property[prop]
+
+ if args.raw:
+ print(selected_property)
+ else:
+ print(json.dumps(selected_property))
+
+ return 0
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/functions.cmake b/functions.cmake
index df2216c8854b..f8a2eeae048d 100644
--- a/functions.cmake
+++ b/functions.cmake
@@ -179,6 +179,11 @@ function(install_clr targetName)
else()
install(FILES ${strip_destination_file} DESTINATION .)
endif()
+ if(CLR_CMAKE_PGO_INSTRUMENT)
+ if(WIN32)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/$/${targetName}.pgd DESTINATION PGD OPTIONAL)
+ endif()
+ endif()
endif()
endfunction()
diff --git a/pgosupport.cmake b/pgosupport.cmake
new file mode 100644
index 000000000000..27fe13df6d00
--- /dev/null
+++ b/pgosupport.cmake
@@ -0,0 +1,80 @@
+function(clr_pgo_unknown_arch)
+ if (WIN32)
+ message(FATAL_ERROR "Only AMD64, ARM and I386 are supported for PGO")
+ else()
+ message(FATAL_ERROR "PGO not currently supported on the current platform")
+ endif()
+endfunction(clr_pgo_unknown_arch)
+
+# Adds Profile Guided Optimization (PGO) flags to the current target
+function(add_pgo TargetName)
+ if(WIN32)
+ set(ProfileFileName "${TargetName}.pgd")
+ endif(WIN32)
+
+ file(TO_NATIVE_PATH
+ "${CLR_CMAKE_PACKAGES_DIR}/${CLR_CMAKE_OPTDATA_PACKAGEWITHRID}/${CLR_CMAKE_OPTDATA_VERSION}/data/${ProfileFileName}"
+ ProfilePath
+ )
+
+ # Enable PGO only for optimized configs
+ set(ConfigTypeList RELEASE RELWITHDEBINFO)
+
+ foreach(ConfigType IN LISTS ConfigTypeList)
+ set(LinkFlagsProperty "LINK_FLAGS_${ConfigType}")
+ if(CLR_CMAKE_PGO_INSTRUMENT)
+ if(WIN32)
+ set_property(TARGET ${TargetName} APPEND_STRING PROPERTY ${LinkFlagsProperty} "/LTCG /GENPROFILE")
+ endif(WIN32)
+ else(CLR_CMAKE_PGO_INSTRUMENT)
+ # If we don't have profile data availble, gracefully fall back to a non-PGO opt build
+ if(EXISTS ${ProfilePath})
+ if(WIN32)
+ set_property(TARGET ${TargetName} APPEND_STRING PROPERTY ${LinkFlagsProperty} "/LTCG /USEPROFILE:PGD=${ProfilePath}")
+ endif(WIN32)
+ endif(EXISTS ${ProfilePath})
+ endif(CLR_CMAKE_PGO_INSTRUMENT)
+ endforeach(ConfigType)
+endfunction(add_pgo)
+
+set(CLR_CMAKE_OPTDATA_PACKAGEID "optimization.PGO.CoreCLR")
+set(CLR_CMAKE_OPTDATA_PACKAGEWITHRID "optimization.${CLR_CMAKE_TARGET_OS}-${CLR_CMAKE_TARGET_ARCH}.PGO.CoreCLR")
+
+# Parse optdata package version from project.json
+file(TO_NATIVE_PATH "${CMAKE_SOURCE_DIR}/extract-from-json.py" ExtractFromJsonScript)
+file(TO_NATIVE_PATH "${CMAKE_SOURCE_DIR}/src/.nuget/optdata/project.json" OptDataProjectJsonPath)
+execute_process(
+ COMMAND python "${ExtractFromJsonScript}" -rf "${OptDataProjectJsonPath}" dependencies "${CLR_CMAKE_OPTDATA_PACKAGEID}"
+ OUTPUT_VARIABLE CLR_CMAKE_OPTDATA_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+
+if(WIN32)
+ if(CLR_CMAKE_PGO_INSTRUMENT)
+ # Instrumented PGO binaries on Windows introduce an additional runtime dependency, pgort.dll.
+ # Make sure we copy it next to the installed product to make it easier to redistribute the package.
+
+ string(SUBSTRING ${CMAKE_VS_PLATFORM_TOOLSET} 1 -1 VS_PLATFORM_VERSION_NUMBER)
+ set(PGORT_FILENAME "pgort${VS_PLATFORM_VERSION_NUMBER}.dll")
+
+ get_filename_component(PATH_CXX_ROOTDIR ${CMAKE_CXX_COMPILER} DIRECTORY)
+
+ if(CLR_CMAKE_PLATFORM_ARCH_I386)
+ set(PATH_VS_PGORT_DLL "${PATH_CXX_ROOTDIR}/${PGORT_FILENAME}")
+ elseif(CLR_CMAKE_PLATFORM_ARCH_AMD64)
+ set(PATH_VS_PGORT_DLL "${PATH_CXX_ROOTDIR}/../amd64/${PGORT_FILENAME}")
+ elseif(CLR_CMAKE_PLATFORM_ARCH_ARM)
+ set(PATH_VS_PGORT_DLL "${PATH_CXX_ROOTDIR}/../arm/${PGORT_FILENAME}")
+ else()
+ clr_pgo_unknown_arch()
+ endif()
+
+ if (EXISTS ${PATH_VS_PGORT_DLL})
+ message(STATUS "Found PGO runtime: ${PATH_VS_PGORT_DLL}")
+ install(PROGRAMS ${PATH_VS_PGORT_DLL} DESTINATION .)
+ else()
+ message(FATAL_ERROR "file not found: ${PATH_VS_PGORT_DLL}")
+ endif()
+
+ endif(CLR_CMAKE_PGO_INSTRUMENT)
+endif(WIN32)
diff --git a/src/.nuget/optdata/project.json b/src/.nuget/optdata/project.json
new file mode 100644
index 000000000000..e8b45c85c0c7
--- /dev/null
+++ b/src/.nuget/optdata/project.json
@@ -0,0 +1,11 @@
+{
+ "dependencies": {
+ "optimization.PGO.CoreCLR": "1.1.0-release-20161025"
+ },
+ "frameworks": {
+ "netstandard": {}
+ },
+ "runtimes": {
+ "win7-x64": {}
+ }
+}
diff --git a/src/dlls/mscoree/coreclr/CMakeLists.txt b/src/dlls/mscoree/coreclr/CMakeLists.txt
index cc14f9cbdca5..aa7bb0d9b98b 100644
--- a/src/dlls/mscoree/coreclr/CMakeLists.txt
+++ b/src/dlls/mscoree/coreclr/CMakeLists.txt
@@ -174,3 +174,6 @@ endif(WIN32)
# add the install targets
install_clr(coreclr)
+
+# Enable profile guided optimization
+add_pgo(coreclr)
diff --git a/src/jit/standalone/CMakeLists.txt b/src/jit/standalone/CMakeLists.txt
index b4efc30a8e09..2e6317098ee2 100644
--- a/src/jit/standalone/CMakeLists.txt
+++ b/src/jit/standalone/CMakeLists.txt
@@ -53,3 +53,6 @@ target_link_libraries(${JIT_BASE_NAME}
# add the install targets
install_clr(${JIT_BASE_NAME})
+
+# Enable profile guided optimization
+add_pgo(${JIT_BASE_NAME})