diff --git a/CMakeLists.txt b/CMakeLists.txt index 5160997f0516..3495194c5d63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -582,6 +582,23 @@ if ("${YB_BUILD_TYPE}" MATCHES "^(asan|tsan)$") endif() set(BUILD_SHARED_LIBS ON) +if ("${YB_BUILD_TYPE}" STREQUAL "prof_gen") + ADD_CXX_FLAGS("-fprofile-instr-generate -DYB_PROFGEN") +endif () + +if ("${YB_BUILD_TYPE}" STREQUAL "prof_use") + if (NOT YB_PGO_DATA_PATH) + message (SEND_ERROR "Pgo data path is not set.") + endif() + ADD_CXX_FLAGS("-fprofile-instr-use=${YB_PGO_DATA_PATH}") + # Even with the fresh profile data we might get warnings like + # warning: Function control flow change detected (hash mismatch) + # [-Wbackend-plugin] + # Silencing it for now. + ADD_CXX_FLAGS("-Wno-backend-plugin") + ADD_CXX_FLAGS("-Wno-profile-instr-unprofiled") + ADD_CXX_FLAGS("-Wno-profile-instr-out-of-date") +endif () # Position independent code is only necessary when producing shared objects. ADD_CXX_FLAGS(-fPIC) diff --git a/build-support/common-build-env.sh b/build-support/common-build-env.sh index 7ab6ded7ce46..d06b49c8e088 100644 --- a/build-support/common-build-env.sh +++ b/build-support/common-build-env.sh @@ -159,6 +159,8 @@ readonly -a VALID_BUILD_TYPES=( tsan tsan_slow pvs + prof_gen + prof_use ) make_regex_from_list VALID_BUILD_TYPES "${VALID_BUILD_TYPES[@]}" @@ -344,7 +346,7 @@ decide_whether_to_use_linuxbrew() { fi elif [[ -n ${YB_LINUXBREW_DIR:-} || ( ${YB_COMPILER_TYPE} =~ ^clang[0-9]+$ && - $build_type == "release" && + $build_type =~ ^(release|prof_(gen|use))$ && "$( uname -m )" == "x86_64" ) ]]; then YB_USE_LINUXBREW=1 fi @@ -643,6 +645,9 @@ set_cmake_build_type_and_compiler_type() { tsan_slow) cmake_build_type=debug ;; + prof_gen|prof_use) + cmake_build_type=release + ;; *) cmake_build_type=$build_type esac @@ -655,11 +660,16 @@ set_cmake_build_type_and_compiler_type() { readonly YB_COMPILER_TYPE export YB_COMPILER_TYPE - if [[ $build_type =~ ^asan|tsan|tsan_slow$ && $YB_COMPILER_TYPE == gcc* ]]; then + if [[ $build_type =~ ^(asan|tsan|tsan_slow)$ && $YB_COMPILER_TYPE == gcc* ]]; then fatal "Build type $build_type not supported with compiler type $YB_COMPILER_TYPE." \ "Sanitizers are only supported with Clang." fi + if [[ $build_type =~ ^(prof_gen|prof_use)$ && $YB_COMPILER_TYPE == gcc* ]]; then + fatal "Build type $build_type not supported with compiler type $YB_COMPILER_TYPE." \ + "PGO works only with Clang for now." + fi + # We need to set CMAKE_C_COMPILER and CMAKE_CXX_COMPILER outside of CMake. We used to do that from # CMakeLists.txt, and got into an infinite loop where CMake kept saying: # diff --git a/build-support/tserver_lto.sh b/build-support/tserver_lto.sh index d62637a6f737..d9b6d7a0c311 100755 --- a/build-support/tserver_lto.sh +++ b/build-support/tserver_lto.sh @@ -5,15 +5,39 @@ activate_virtualenv set_pythonpath +# usage: +# for release build : ./tserver_lto.sh +# for prof_gen build : ./tserver_lto.sh prof_gen +# for prof_use build : ./tserver_lto.sh prof_use path/to/pgo/data + +if [[ $# -gt 0 ]]; then + build_type=$1 + validate_build_type "$build_type" + shift + if [[ $build_type == "prof_use" ]]; then + expect_num_args 1 "$@" + pgo_data_path="$1" + shift + fi +else + build_type="release" +fi + if [[ $( uname -m ) == "x86_64" ]]; then - build_root_basename=release-clang12-linuxbrew-full-lto-ninja + build_root_basename="$build_type-clang13-linuxbrew-full-lto-ninja" else - build_root_basename=release-clang12-full-lto-ninja + build_root_basename="$build_type-clang12-full-lto-ninja" +fi + +dep_graph_cmd=( + "${YB_SRC_ROOT}/python/yb/dependency_graph.py" + "--build-root=${YB_SRC_ROOT}/build/${build_root_basename}" + "--file-regex=^.*/yb-tserver$" + ) +if [[ $build_type == "prof_use" ]]; then + dep_graph_cmd+=( "--build-args=--pgo-data-path ${pgo_data_path}" ) fi +dep_graph_cmd+=( link-whole-program "$@" ) set -x -"$YB_SRC_ROOT/python/yb/dependency_graph.py" \ - --build-root "$YB_SRC_ROOT/build/${build_root_basename}" \ - --file-regex "^.*/yb-tserver$" \ - link-whole-program \ - "$@" +"${dep_graph_cmd[@]}" diff --git a/src/yb/tserver/tablet_server_main.cc b/src/yb/tserver/tablet_server_main.cc index d2def4567986..a097560f4635 100644 --- a/src/yb/tserver/tablet_server_main.cc +++ b/src/yb/tserver/tablet_server_main.cc @@ -75,6 +75,13 @@ #include "yb/tserver/server_main_util.h" +#if defined(YB_PROFGEN) && defined(__clang__) +extern "C" int __llvm_profile_write_file(void); +extern "C" void __llvm_profile_set_filename(const char *); +extern "C" void __llvm_profile_reset_counters(); +#endif + + using namespace std::placeholders; using yb::redisserver::RedisServer; @@ -159,6 +166,18 @@ void SetProxyAddresses() { SetProxyAddress(&FLAGS_pgsql_proxy_bind_address, "YSQL", PgProcessConf::kDefaultPort); } +#if defined(YB_PROFGEN) && defined(__clang__) +// Force profile dumping +void PeriodicDumpLLVMProfileFile() { + __llvm_profile_set_filename("tserver-%p-%m.profraw"); + while (true) { + __llvm_profile_write_file(); + __llvm_profile_reset_counters(); + SleepFor(MonoDelta::FromSeconds(60)); + } +} +#endif + int TabletServerMain(int argc, char** argv) { #ifndef NDEBUG HybridTime::TEST_SetPrettyToString(true); @@ -274,6 +293,13 @@ int TabletServerMain(int argc, char** argv) { LOG(INFO) << "Redis server successfully started."; } +#if defined(YB_PROFGEN) && defined(__clang__) + // TODO After the TODO below is fixed the call of + // PeriodicDumpLLVMProfileFile can be moved to the infinite while loop + // at the end of the function. + std::thread llvm_profile_dump_thread(PeriodicDumpLLVMProfileFile); +#endif + // TODO(neil): After CQL server is starting, it blocks this thread from moving on. // This should be fixed such that all processes or service by tablet server are treated equally // by using different threads for each process. @@ -310,6 +336,11 @@ int TabletServerMain(int argc, char** argv) { SleepFor(MonoDelta::FromSeconds(60)); } +#if defined(YB_PROFGEN) && defined(__clang__) + // Currently unreachable + llvm_profile_dump_thread.join(); +#endif + return 0; } diff --git a/yb_build.sh b/yb_build.sh index 2312268a71d8..57152a112445 100755 --- a/yb_build.sh +++ b/yb_build.sh @@ -720,6 +720,7 @@ java_only=false cmake_only=false run_python_tests=false cmake_extra_args="" +pgo_data_path="" predefined_build_root="" java_test_name="" show_report=true @@ -1041,6 +1042,14 @@ while [[ $# -gt 0 ]]; do cmake_extra_args+=$2 shift ;; + --pgo-data-path) + ensure_option_has_arg "$@" + pgo_data_path=$(realpath "$2") + shift + if [[ ! -f $pgo_data_path ]]; then + fatal "Profile data file doesn't exist: $pgo_data_path" + fi + ;; --make-ninja-extra-args) ensure_option_has_arg "$@" if [[ -n $make_ninja_extra_args ]]; then @@ -1354,6 +1363,10 @@ if ! "$build_java" && "$resolve_java_dependencies"; then fatal "--resolve-java-dependencies is not allowed if not building Java code" fi +if [[ $build_type == "prof_use" ]] && [[ $pgo_data_path == "" ]]; then + fatal "Please set --pgo-data-path path/to/pgo/data" +fi + # End of post-processing and validating command-line arguments. # ------------------------------------------------------------------------------------------------- @@ -1524,6 +1537,10 @@ if "$no_tcmalloc"; then cmake_opts+=( -DYB_TCMALLOC_ENABLED=0 ) fi +if [[ $pgo_data_path != "" ]]; then + cmake_opts+=( "-DYB_PGO_DATA_PATH=$pgo_data_path" ) +fi + detect_num_cpus_and_set_make_parallelism if "$build_cxx"; then log "Using make parallelism of $YB_MAKE_PARALLELISM" \