1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
################
# PGO (profile guided optimization)
if(CMAKE_ARGC AND CMAKE_ARGV2 MATCHES "PGO.cmake")
# Script mode, run as ``/path/to/cmake -P /path/to/PGO.cmake subcommand [args...]''
if(CMAKE_ARGV3 STREQUAL write-timestamp-header)
# cmake -P PGO.cmake write-timestamp-header PGO_HEADER_FILE [PGO_OUTPUT_FILE]
set(PGO_HEADER_FILE "${CMAKE_ARGV4}")
set(PGO_OUTPUT_FILE "${CMAKE_ARGV5}")
if(PGO_OUTPUT_FILE)
file(TIMESTAMP "${PGO_OUTPUT_FILE}" PGO_GEN_TIMESTAMP)
endif()
configure_file("${CMAKE_CURRENT_LIST_DIR}/pgo-timestamp.h.in" "${PGO_HEADER_FILE}" ESCAPE_QUOTES)
else()
message(FATAL_ERROR "PGO subcommand ${CMAKE_ARGV3} not recognized")
endif()
return()
endif()
set(PGO_SCRIPT ${CMAKE_CURRENT_LIST_FILE})
set(PGO_PROGRAM ${CMAKE_SOURCE_DIR}/bench/run.pl
CACHE STRING
"Program to use for Profile Guided Optimization")
set(PGO_SWIPL_OPTIONS -f none --no-packs --no-threads -O
CACHE STRING
"Prolog options for PGO run")
set(PGO_PROGRAM_OPTIONS --speedup=10
CACHE STRING
"Options to give to the benchmark script")
set(PGO_DIR ${CMAKE_BINARY_DIR}/PGO-data
CACHE PATH
"Directory to store PGO data in")
function(prepare_pgo_target t is_generate)
# This function is a no-op by default, but may be overridden
# by compiler-specific code in configure_pgo()
endfunction()
macro(configure_pgo pgo_tag)
set(PGO_TAG ${pgo_tag})
if(PGO_TAG)
message(STATUS "PGO: configuring instrumented build")
set(PGO_SUFFIX "-${PGO_TAG}")
# Re-run the current CMakeLists to pull in all the same target definitions
# The variable PGO_SUFFIX will be set, append all targets with it
include(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt)
set(PGO_RUN_STAMP ${PGO_DIR}/pgo-run.stamp)
add_custom_command(OUTPUT ${PGO_RUN_STAMP}
COMMAND ${CMAKE_COMMAND} -E remove_directory "${PGO_DIR}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${PGO_DIR}"
COMMENT "Collecting profile data..."
USES_TERMINAL
VERBATIM)
endif()
# Set compiler-specific PGO parameters
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
set(PGO_OUTPUT_FILE ${PGO_DIR}/swipl.profdata)
set(PGO_GENERATE_FLAGS -fprofile-generate=${PGO_DIR})
set(PGO_USE_FLAGS -fprofile-use=${PGO_OUTPUT_FILE})
get_filename_component(CMAKE_C_COMPILER_DIR ${CMAKE_C_COMPILER} DIRECTORY)
set(PROFDATA_NAMES llvm-profdata)
get_filename_component(CMAKE_C_COMPILER_NAME ${CMAKE_C_COMPILER} NAME_WE)
if(CMAKE_C_COMPILER_NAME MATCHES "-[0-9]+$")
string(REGEX MATCH "-[0-9]+$" LLVM_VERSION_SUFFIX "${CMAKE_C_COMPILER_NAME}")
list(APPEND PROFDATA_NAMES "llvm-profdata${LLVM_VERSION_SUFFIX}")
endif()
find_program(LLVM_PROFDATA NAMES ${PROFDATA_NAMES}
HINTS ${CMAKE_C_COMPILER_DIR})
add_custom_command(OUTPUT ${PGO_OUTPUT_FILE}
DEPENDS ${PGO_RUN_STAMP}
COMMAND ${LLVM_PROFDATA} merge -output=${PGO_OUTPUT_FILE} ${PGO_DIR}/*.profraw)
else()
set(PGO_CFLAGS_EXTRA -Wno-maybe-uninitialized "-fprofile-dir=${PGO_DIR}")
set(PGO_GENERATE_FLAGS -fprofile-generate ${PGO_CFLAGS_EXTRA})
set(PGO_USE_FLAGS -fprofile-use ${PGO_CFLAGS_EXTRA})
if(PGO_TAG)
set(PGO_OUTPUT_FILE ${PGO_RUN_STAMP})
function(prepare_pgo_target t is_generate)
# GCC identifies static functions by keying them on the path that the
# *object* file is compiled to, rather than the path of the source file.
# The wrapper here allows Ninja to pass the -o location in the instrumentation
# directory, as it expects (and requires, to support building the same library
# twice from the same build file), but the wrapper translates it to a -o
# location in the NON-instrumented directory and, assuming the compilation
# is successful, moves the object file to its final resting place afterwards.
set(PGO_COMPILER_LAUNCHER ${PROG_WRAPGCC} ${PGO_SUFFIX})
if(is_generate)
set_target_properties(${t} PROPERTIES C_COMPILER_LAUNCHER "${PGO_COMPILER_LAUNCHER}")
add_dependencies(${t} ${TARGET_WRAPGCC})
endif()
endfunction()
endif(PGO_TAG)
endif()
set(PGO_HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/pgo-timestamp.h)
add_custom_command(OUTPUT ${PGO_HEADER_FILE}
DEPENDS ${PGO_OUTPUT_FILE}
COMMAND ${CMAKE_COMMAND} -P ${PGO_SCRIPT} write-timestamp-header ${PGO_HEADER_FILE} ${PGO_OUTPUT_FILE}
VERBATIM)
set(PGO_USE_FLAGS ${PGO_USE_FLAGS} -include "${PGO_HEADER_FILE}")
add_custom_target(pgo_data DEPENDS ${PGO_HEADER_FILE})
endmacro()
function(generate_pgo_data) # generate_pgo_data(targets...)
string(REPLACE ";" " " gen_flags "${PGO_GENERATE_FLAGS}")
foreach(t IN LISTS ARGV)
set(tinstr "${t}${PGO_SUFFIX}")
target_compile_options(${tinstr} PRIVATE ${PGO_GENERATE_FLAGS})
if(${CMAKE_VERSION} VERSION_GREATER 3.12)
target_link_options(${tinstr} PRIVATE ${PGO_GENERATE_FLAGS})
else()
set_target_properties(${tinstr} PROPERTIES LINK_FLAGS "${gen_flags}")
endif()
prepare_pgo_target(${tinstr} true)
endforeach()
endfunction()
function(add_pgo_dependency) # add_pgo_dependency(targets...)
add_dependencies(pgo_data ${ARGN})
endfunction()
function(run_pgo_program exec_target) # run_pgo_program(exec_target [args...])
if(CMAKE_CROSSCOMPILING AND CMAKE_CROSSCOMPILING_EMULATOR)
set(executable ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:${exec_target}${PGO_SUFFIX}>)
else()
set(executable "${exec_target}${PGO_SUFFIX}")
endif()
add_custom_command(OUTPUT ${PGO_RUN_STAMP} APPEND
DEPENDS "${exec_target}${PGO_SUFFIX}"
COMMAND ${executable} ${ARGN}
VERBATIM)
# if we rebuild the binary, we have to clear the pgo data
add_custom_command(TARGET "${exec_target}${PGO_SUFFIX}"
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E remove_directory ${PGO_DIR}
COMMENT "Clearing PGO data..."
VERBATIM)
endfunction()
function(use_pgo_data) # use_pgo_data(targets...)
if(PGO_RUN_STAMP)
add_custom_command(OUTPUT ${PGO_RUN_STAMP} APPEND
COMMAND ${CMAKE_COMMAND} -E touch ${PGO_RUN_STAMP}
VERBATIM)
endif()
string(REPLACE ";" " " use_flags "${PGO_USE_FLAGS}")
foreach(t IN LISTS ARGV)
target_compile_options(${t} PRIVATE ${PGO_USE_FLAGS})
if(${CMAKE_VERSION} VERSION_GREATER 3.12)
target_link_options(${t} PRIVATE ${PGO_USE_FLAGS})
else()
set_target_properties(${t} PROPERTIES LINK_FLAGS "${use_flags}")
endif()
add_dependencies(${t} pgo_data)
prepare_pgo_target(${t} false)
endforeach()
endfunction()
|