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
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)) {
--- /dev/null
+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"
+}
+