]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
feat: Add support for -fprofile-prefix-path gcc option (#1515)
authorDavid <jdavidpeter@gmail.com>
Sun, 22 Sep 2024 12:29:28 +0000 (14:29 +0200)
committerGitHub <noreply@github.com>
Sun, 22 Sep 2024 12:29:28 +0000 (14:29 +0200)
src/ccache/argprocessing.cpp
src/ccache/argsinfo.hpp
src/ccache/ccache.cpp
test/CMakeLists.txt
test/suites/profiling_gcc_10+.bash [new file with mode: 0644]

index 6255a92d52f33e6965c81b2ed45a8e5a78b9dc8a..10f4d7ac19b9c9365f33a1ddfc712c1f9979bc33 100644 (file)
@@ -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;
 
index d71d66f80eab4664f60dd11b34411d3b54a1e818..d8f673e463a9eaf64b3c5316cf1f910024535e7a 100644 (file)
@@ -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;
index 10b399b320547d80dfbf9d63e24251f2102651fd..b23e731a12f9baba8ce85b8fe10b5d5131f33b17 100644 (file)
@@ -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)) {
index 939a220c9f1f30d686be97d886e6b15c904ac884..8e5b07370719968e9f6a5aacd7a909cf0695e298 100644 (file)
@@ -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 (file)
index 0000000..1661673
--- /dev/null
@@ -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"
+}
+