From: David Date: Sun, 22 Sep 2024 12:29:28 +0000 (+0200) Subject: feat: Add support for -fprofile-prefix-path gcc option (#1515) X-Git-Tag: v4.11~73 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1e8688688f6087725e80ad85a2b513c0202fd3d1;p=thirdparty%2Fccache.git feat: Add support for -fprofile-prefix-path gcc option (#1515) --- diff --git a/src/ccache/argprocessing.cpp b/src/ccache/argprocessing.cpp index 6255a92d..10f4d7ac 100644 --- a/src/ccache/argprocessing.cpp +++ b/src/ccache/argprocessing.cpp @@ -254,6 +254,13 @@ process_profiling_option(const Context& ctx, return true; } + if (util::starts_with(arg, "-fprofile-prefix-path=")) { + std::filesystem::path profile_prefix_path = arg.substr(arg.find('=') + 1); + args_info.profile_prefix_path = profile_prefix_path; + LOG("Set profile prefix path to {}", args_info.profile_prefix_path); + return true; + } + std::filesystem::path new_profile_path; bool new_profile_use = false; diff --git a/src/ccache/argsinfo.hpp b/src/ccache/argsinfo.hpp index d71d66f8..d8f673e4 100644 --- a/src/ccache/argsinfo.hpp +++ b/src/ccache/argsinfo.hpp @@ -131,6 +131,11 @@ struct ArgsInfo // Name of the custom profile directory or file. std::filesystem::path profile_path; + // Path to the root of the source tree during a profile build. + // This path will be stripped from the beginning of the mangled absolute paths + // in the gcda file name + std::filesystem::path profile_prefix_path; + // Profile generation / usage information. bool profile_use = false; bool profile_generate = false; diff --git a/src/ccache/ccache.cpp b/src/ccache/ccache.cpp index 10b399b3..b23e731a 100644 --- a/src/ccache/ccache.cpp +++ b/src/ccache/ccache.cpp @@ -1613,10 +1613,39 @@ hash_common_info(const Context& ctx, if (ctx.args_info.profile_arcs) { // When using -fprofile-arcs (including implicitly via --coverage) the // object file contains a .gcda path based on the absolute object file path. - LOG_RAW("Hashing absolute object filename due to -fprofile-arcs"); - hash.hash_delimiter("Absolute object file path"); - // -fprofile-arcs stores "apparent absolute path" for some reason. - hash.hash(ctx.apparent_cwd / ctx.args_info.output_obj); + // This absolute path can be trimmed using the -fprofile-prefix-path=path + // option. + fs::path apparent_absolute_path = + ctx.apparent_cwd / ctx.args_info.output_obj; + if (ctx.args_info.profile_prefix_path.empty()) { + LOG_RAW("Hashing absolute object filename due to -fprofile-arcs"); + hash.hash_delimiter("Absolute object file path"); + // -fprofile-arcs stores "apparent absolute path" for .gcda file + // names/paths. + hash.hash(apparent_absolute_path); + } else { + if (util::path_starts_with(apparent_absolute_path, + ctx.args_info.profile_prefix_path)) { + LOG_RAW( + "Hashing trimmed absolute object filename due to -fprofile-arcs and " + "-fprofile-prefix-path=path"); + std::string trimmed_absolute_path = apparent_absolute_path.string(); + const std::string profile_prefix_path = + util::pstr(ctx.args_info.profile_prefix_path).str(); + // Remove ctx.args_info.profile_prefix_path including the last path + // delimiter from the beginning of apparent_absolute_path + trimmed_absolute_path.erase(0, profile_prefix_path.size() + 1); + hash.hash_delimiter("Trimmed absolute object file path"); + hash.hash(trimmed_absolute_path); + } else { + LOG_RAW( + "Hashing absolute object filename due to -fprofile-arcs and " + "-fprofile-prefix-path=path not being a prefix to the absolute " + "filename."); + hash.hash_delimiter("Absolute object file path"); + hash.hash(apparent_absolute_path); + } + } } if (ctx.args_info.generating_coverage @@ -1780,6 +1809,13 @@ hash_argument(const Context& ctx, hash.hash("-fmacro-prefix-map="); return {}; } + // -fprofile-prefix-path can also be used to reuse ccache results + // across different directories + if (util::starts_with(args[i], "-fprofile-prefix-path=")) { + hash.hash_delimiter("arg"); + hash.hash("-fprofile-prefix-path="); + return {}; + } if (util::starts_with(args[i], "-frandom-seed=") && ctx.config.sloppiness().contains(core::Sloppy::random_seed)) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 939a220c..8e5b0737 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -49,6 +49,7 @@ addtest(pch) addtest(profiling) addtest(profiling_clang) addtest(profiling_gcc) +addtest(profiling_gcc_10+) addtest(profiling_hip_clang) addtest(readonly) addtest(readonly_direct) diff --git a/test/suites/profiling_gcc_10+.bash b/test/suites/profiling_gcc_10+.bash new file mode 100644 index 00000000..16616731 --- /dev/null +++ b/test/suites/profiling_gcc_10+.bash @@ -0,0 +1,104 @@ +gcda_cycle() { + export CCACHE_BASEDIR="$(pwd)" + $CCACHE_COMPILE --coverage "$@" -c test.c -o test.o + $COMPILER --coverage -o test test.o + chmod a+x ./test + ./test +} + +SUITE_profiling_gcc_10+_PROBE() { + echo 'int main(void) { return 0; }' >test.c + $COMPILER --coverage -fprofile-prefix-path=. -c test.c + if ! $COMPILER_TYPE_GCC; then + echo "compiler is not GCC" + fi + if ! $RUN_WIN_XFAIL; then + echo "this suite does not work on Windows" + fi + if ! $COMPILER --coverage -fprofile-prefix-path=. -c test.c 2>/dev/null; then + echo "compiler does not support -fprofile-prefix-path=path" + fi + if ! $COMPILER --coverage -fprofile-dir=. -c test.c 2>/dev/null; then + echo "compiler does not support -fprofile-prefix-path=path" + fi +} + +SUITE_profiling_gcc_10+_SETUP() { + echo 'int main(void) { return 0; }' >test.c + unset CCACHE_NODIRECT +} + +SUITE_profiling_gcc_10+() { + # ------------------------------------------------------------------------- + TEST "-fprofile-prefirx-path=path, gcc coverage build" + # When using a relative path for -fprofile-dir in gcc 9+, absolute object file path will be mangled in the .gcda filename + CCACHE_SLOPPINESS_OLD="$CCACHE_SLOPPINESS" + export CCACHE_SLOPPINESS="$CCACHE_SLOPPINESS gcno_cwd" + + for dir in obj1 obj2; do + mkdir "$dir" + cp test.c "$dir/test.c" + done + + cd obj1 + gcda_cycle -fprofile-dir=. + expect_stat direct_cache_hit 0 + expect_stat cache_miss 1 + + cd ../obj2 + gcda_cycle -fprofile-dir=. + expect_stat direct_cache_hit 0 + expect_stat cache_miss 2 + + export CCACHE_SLOPPINESS="$CCACHE_SLOPPINESS_OLD" + + # ------------------------------------------------------------------------- + TEST "-fprofile-prefirx-path=pwd, -fprofile-dir=., gcc coverage build" + # GCC 10 and newer allows to lstrip the mangled absolute path in the generated gcda file name + # This doesn't effect the absolute cwd path in the gcno file (but there's sloppiness for that) + CCACHE_SLOPPINESS_OLD="$CCACHE_SLOPPINESS" + export CCACHE_SLOPPINESS="$CCACHE_SLOPPINESS gcno_cwd" + + for dir in obj1 obj2; do + mkdir "$dir" + cp test.c "$dir/test.c" + done + + cd obj1 + gcda_cycle -fprofile-prefix-path=$(pwd) -fprofile-dir=. + expect_exists test.gcda + expect_stat direct_cache_hit 0 + expect_stat cache_miss 1 + + cd ../obj2 + gcda_cycle -fprofile-prefix-path=$(pwd) -fprofile-dir=. + expect_exists test.gcda + expect_stat direct_cache_hit 1 + expect_stat cache_miss 1 + + export CCACHE_SLOPPINESS="$CCACHE_SLOPPINESS_OLD" + + # ------------------------------------------------------------------------- + TEST "-fprofile-prefirx-path=dummy, -fprofile-dir=., gcc coverage build" + # lstripping the mangled .gcda filename only works with a correct -fprofile-prefirx-path + CCACHE_SLOPPINESS_OLD="$CCACHE_SLOPPINESS" + export CCACHE_SLOPPINESS="$CCACHE_SLOPPINESS gcno_cwd" + + for dir in obj1 obj2; do + mkdir "$dir" + cp test.c "$dir/test.c" + done + + cd obj1 + gcda_cycle -fprofile-prefix-path=/you/shall/not/pass -fprofile-dir=. + expect_stat direct_cache_hit 0 + expect_stat cache_miss 1 + + cd ../obj2 + gcda_cycle -fprofile-prefix-path=/you/shall/not/pass -fprofile-dir=. + expect_stat direct_cache_hit 0 + expect_stat cache_miss 2 + + export CCACHE_SLOPPINESS="$CCACHE_SLOPPINESS_OLD" +} +