]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Improve handling of profiling options
authorJoel Rosdahl <joel@rosdahl.net>
Thu, 30 Apr 2020 06:29:31 +0000 (08:29 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Fri, 1 May 2020 12:44:47 +0000 (14:44 +0200)
Handling of -fprofile-{generate,use}[=path] was implemented in PR #2
(2011). ccache has since then gained support for Clang, which is not
GCC-compatible for -fprofile-{generate,use}[=path]. Furthermore, GCC 9
changed the semantics of -fprofile-{generate,use}=path, making it
incompatible with ccache’s original implementation.

One crucial problem with the implementation is that there is no error
handling when the expected profiling data file cannot be found. This
means that there will be false positives cache hits for Clang and GCC
9+.

Fix this by:

* Checking for different profiling data file locations to handle
  different compilers and versions.
* Bailing out if no profiling data file can be found.

Also:

* Implemented support for Clang’s -fprofile-instr-{generate,use}[=path]
  options.
* Implemented support for -fauto-profile[=path].
* Removed the conversion of absolute path to the profile directory.
  91a2954e says that the directory is rewritten to increase the hit
  rate, but I don’t understand how that could be the case.
* Added tests for the profiling options. Exception:
  -fauto-profile[=path], since that would require running the perf tool.

Fixes #582.

src/ccache.c
src/compopt.c
test/run
test/suites/profiling.bash [new file with mode: 0644]
test/suites/profiling_clang.bash [new file with mode: 0644]
test/suites/profiling_gcc.bash [new file with mode: 0644]
unittest/test_argument_processing.c

index 0e66468f2facdabc7172dab05cab0bb037dba450..8fe62aa55bccf8ebe1f736d6e9377781d302d635 100644 (file)
@@ -222,9 +222,6 @@ static size_t debug_prefix_maps_len = 0;
 // Is the compiler being asked to output coverage data (.gcda) at runtime?
 static bool profile_arcs;
 
-// Name of the custom profile directory (default: object dirname).
-static char *profile_dir;
-
 // The name of the temporary preprocessed file.
 static char *i_tmpfile;
 
@@ -249,7 +246,7 @@ bool output_is_precompiled_header = false;
 enum guessed_compiler guessed_compiler = GUESSED_UNKNOWN;
 
 // Profile generation / usage information.
-static char *profile_dir = NULL;
+static char *profile_path = NULL; // directory (GCC/Clang) or file (Clang)
 static bool profile_use = false;
 static bool profile_generate = false;
 
@@ -1953,8 +1950,8 @@ calculate_common_hash(struct args *args, struct hash *hash)
        // Possibly hash the coverage data file path.
        if (generating_coverage && profile_arcs) {
                char *dir = dirname(output_obj);
-               if (profile_dir) {
-                       dir = x_strdup(profile_dir);
+               if (profile_path) {
+                       dir = x_strdup(profile_path);
                } else {
                        char *real_dir = x_realpath(dir);
                        free(dir);
@@ -2011,6 +2008,51 @@ calculate_common_hash(struct args *args, struct hash *hash)
        }
 }
 
+static bool
+hash_profile_data_file(const char *path, struct hash *hash)
+{
+       assert(path);
+
+       char *base_name = remove_extension(output_obj);
+       char *hashified_cwd = get_cwd();
+       for (char *p = hashified_cwd; *p; ++p) {
+               if (*p == '/') {
+                       *p = '#';
+               }
+       }
+       char *paths_to_try[] = {
+               // -fprofile-use[=dir]/-fbranch-probabilities (GCC <9)
+               format("%s/%s.gcda", path, base_name),
+               // -fprofile-use[=dir]/-fbranch-probabilities (GCC >=9)
+               format("%s/%s#%s.gcda", path, hashified_cwd, base_name),
+               // -fprofile(-instr)-use=file (Clang), -fauto-profile=file (GCC >=5)
+               x_strdup(path),
+               // -fprofile(-instr)-use=dir (Clang)
+               format("%s/default.profdata", path),
+               // -fauto-profile (GCC >=5)
+               x_strdup("fbdata.afdo"), // -fprofile-dir is not used
+               NULL
+       };
+       free(hashified_cwd);
+       free(base_name);
+
+       bool found = false;
+       for (char **p = paths_to_try; *p; ++p) {
+               cc_log("Checking for profile data file %s", *p);
+               struct stat st;
+               if (stat(*p, &st) == 0 && !S_ISDIR(st.st_mode)) {
+                       cc_log("Adding profile data %s to the hash", *p);
+                       hash_delimiter(hash, "-fprofile-use");
+                       if (hash_file(hash, *p)) {
+                               found = true;
+                       }
+               }
+               free(*p);
+       }
+
+       return found;
+}
+
 // Update a hash sum with information specific to the direct and preprocessor
 // modes and calculate the object hash. Returns the object hash on success,
 // otherwise NULL. Caller frees.
@@ -2177,39 +2219,25 @@ calculate_object_hash(struct args *args, struct args *preprocessor_args,
                hash_nvcc_host_compiler(hash, NULL, NULL);
        }
 
-       // For profile generation (-fprofile-arcs, -fprofile-generate):
-       // - hash profile directory
+       // For profile generation (-fprofile(-instr)-generate[=path])
+       // - hash profile path
        //
-       // For profile usage (-fprofile-use):
+       // For profile usage (-fprofile(-instr)-use, -fbranch-probabilities):
        // - hash profile data
        //
-       // -fbranch-probabilities and -fvpt usage is covered by
-       // -fprofile-generate/-fprofile-use.
-       //
        // The profile directory can be specified as an argument to
-       // -fprofile-generate=, -fprofile-use= or -fprofile-dir=.
+       // -fprofile(-instr)-generate=, -fprofile(-instr)-use= or -fprofile-dir=.
        if (profile_generate) {
-               if (!profile_dir) {
-                       profile_dir = get_cwd();
-               }
-               cc_log("Adding profile directory %s to our hash", profile_dir);
+               assert(profile_path);
+               cc_log("Adding profile directory %s to our hash", profile_path);
                hash_delimiter(hash, "-fprofile-dir");
-               hash_string(hash, profile_dir);
+               hash_string(hash, profile_path);
        }
 
-       if (profile_use) {
-               // Calculate gcda name.
-               if (!profile_dir) {
-                       profile_dir = get_cwd();
-               }
-               char *base_name = remove_extension(output_obj);
-               char *gcda_name = format("%s/%s.gcda", profile_dir, base_name);
-               cc_log("Adding profile data %s to our hash", gcda_name);
-               // Add the gcda to our hash.
-               hash_delimiter(hash, "-fprofile-use");
-               hash_file(hash, gcda_name);
-               free(base_name);
-               free(gcda_name);
+       if (profile_use && !hash_profile_data_file(profile_path, hash)) {
+               cc_log("No profile data file found");
+               stats_update(STATS_NOINPUT);
+               failed();
        }
 
        // Adding -arch to hash since cpp output is affected.
@@ -2530,6 +2558,72 @@ detect_pch(const char *option, const char *arg, bool *found_pch)
        return true;
 }
 
+static bool
+process_profiling_option(const char *arg)
+{
+       char *new_profile_path = NULL;
+       bool new_profile_use = false;
+
+       if (str_startswith(arg, "-fprofile-dir=")) {
+               new_profile_path = x_strdup(strchr(arg, '=') + 1);
+       } else if (str_eq(arg, "-fprofile-generate")
+                        || str_eq(arg, "-fprofile-instr-generate")) {
+               profile_generate = true;
+               if (guessed_compiler == GUESSED_CLANG) {
+                       new_profile_path = x_strdup(".");
+               } else {
+                       // GCC uses $PWD/$(basename $obj).
+                       new_profile_path = get_cwd();
+               }
+       } else if (str_startswith(arg, "-fprofile-generate=")
+                        || str_startswith(arg, "-fprofile-instr-generate=")) {
+               profile_generate = true;
+               new_profile_path = x_strdup(strchr(arg, '=') + 1);
+       } else if (str_eq(arg, "-fprofile-use")
+                  || str_eq(arg, "-fprofile-instr-use")
+                  || str_eq(arg, "-fbranch-probabilities")
+                  || str_eq(arg, "-fauto-profile")) {
+               new_profile_use = true;
+               if (!profile_path) {
+                       new_profile_path = x_strdup(".");
+               }
+       } else if (str_startswith(arg, "-fprofile-use=")
+                        || str_startswith(arg, "-fprofile-instr-use=")
+                        || str_startswith(arg, "-fauto-profile=")) {
+               new_profile_use = true;
+               new_profile_path = x_strdup(strchr(arg, '=') + 1);
+       } else {
+               cc_log("Unknown profiling option: %s", arg);
+               stats_update(STATS_UNSUPPORTED_OPTION);
+               return false;
+       }
+
+       if (new_profile_use) {
+               if (profile_use) {
+                       free(new_profile_path);
+                       cc_log("Multiple profiling options not supported");
+                       stats_update(STATS_UNSUPPORTED_OPTION);
+                       return false;
+               }
+               profile_use = true;
+       }
+
+       if (new_profile_path) {
+               free(profile_path);
+               profile_path = new_profile_path;
+               cc_log("Set profile directory to %s", profile_path);
+       }
+
+       if (profile_generate && profile_use) {
+               // Too hard to figure out what the compiler will do.
+               cc_log("Both generating and using profile info, giving up");
+               stats_update(STATS_UNSUPPORTED_OPTION);
+               return false;
+       }
+
+       return true;
+}
+
 // Process the compiler options into options suitable for passing to the
 // preprocessor and the real compiler. preprocessor_args doesn't include -E;
 // this is added later. extra_args_to_hash are the arguments that are not
@@ -2698,7 +2792,7 @@ cc_process_args(struct args *args,
 
                // -Xarch_* options are too hard.
                if (str_startswith(argv[i], "-Xarch_")) {
-                       cc_log("Unsupported compiler option :%s", argv[i]);
+                       cc_log("Unsupported compiler option%s", argv[i]);
                        stats_update(STATS_UNSUPPORTED_OPTION);
                        result = false;
                        goto out;
@@ -2948,10 +3042,16 @@ cc_process_args(struct args *args,
                        args_add(common_args, argv[i]);
                        continue;
                }
-               if (str_startswith(argv[i], "-fprofile-dir=")) {
-                       profile_dir = x_strdup(argv[i] + 14);
-                       args_add(common_args, argv[i]);
-                       continue;
+               if (str_startswith(argv[i], "-fprofile-")
+                   || str_startswith(argv[i], "-fauto-profile")
+                   || str_eq(argv[i], "-fbranch-probabilities")) {
+                       if (process_profiling_option(argv[i])) {
+                               args_add(common_args, argv[i]);
+                               continue;
+                       } else {
+                               result = false;
+                               goto out;
+                       }
                }
                if (str_startswith(argv[i], "-fsanitize-blacklist=")) {
                        sanitize_blacklists = x_realloc(
@@ -3074,60 +3174,6 @@ cc_process_args(struct args *args,
                        continue;
                }
 
-               if (str_startswith(argv[i], "-fprofile-")) {
-                       char *arg = x_strdup(argv[i]);
-                       const char *arg_profile_dir = strchr(argv[i], '=');
-                       if (arg_profile_dir) {
-                               // Convert to absolute path.
-                               char *dir = x_realpath(arg_profile_dir + 1);
-                               if (!dir) {
-                                       // Directory doesn't exist.
-                                       dir = x_strdup(arg_profile_dir + 1);
-                               }
-
-                               // We can get a better hit rate by using the real path here.
-                               free(arg);
-                               char *option = x_strndup(argv[i], arg_profile_dir - argv[i]);
-                               arg = format("%s=%s", option, dir);
-                               cc_log("Rewriting %s to %s", argv[i], arg);
-                               free(option);
-                               free(dir);
-                       }
-
-                       bool supported_profile_option = false;
-                       if (str_startswith(argv[i], "-fprofile-generate")
-                           || str_eq(argv[i], "-fprofile-arcs")) {
-                               profile_generate = true;
-                               supported_profile_option = true;
-                       } else if (str_startswith(argv[i], "-fprofile-use")
-                                  || str_eq(argv[i], "-fbranch-probabilities")) {
-                               profile_use = true;
-                               supported_profile_option = true;
-                       } else if (str_eq(argv[i], "-fprofile-dir")) {
-                               supported_profile_option = true;
-                       }
-
-                       if (supported_profile_option) {
-                               args_add(common_args, arg);
-                               free(arg);
-
-                               // If the profile directory has already been set, give up... Hard to
-                               // know what the user means, and what the compiler will do.
-                               if (arg_profile_dir && profile_dir) {
-                                       cc_log("Profile directory already set; giving up");
-                                       stats_update(STATS_UNSUPPORTED_OPTION);
-                                       result = false;
-                                       goto out;
-                               } else if (arg_profile_dir) {
-                                       cc_log("Setting profile directory to %s", arg_profile_dir);
-                                       profile_dir = x_strdup(arg_profile_dir);
-                               }
-                               continue;
-                       }
-                       cc_log("Unknown profile option: %s", argv[i]);
-                       free(arg);
-               }
-
                if (str_eq(argv[i], "-fcolor-diagnostics")
                    || str_eq(argv[i], "-fno-color-diagnostics")
                    || str_eq(argv[i], "-fdiagnostics-color")
@@ -3852,7 +3898,9 @@ cc_reset(void)
        }
        free(debug_prefix_maps); debug_prefix_maps = NULL;
        debug_prefix_maps_len = 0;
-       free(profile_dir); profile_dir = NULL;
+       free(profile_path); profile_path = NULL;
+       profile_use = false;
+       profile_generate = false;
        for (size_t i = 0; i < sanitize_blacklists_len; i++) {
                free(sanitize_blacklists[i]);
                sanitize_blacklists[i] = NULL;
@@ -3895,7 +3943,6 @@ cc_reset(void)
        generating_coverage = false;
        generating_stackusage = false;
        profile_arcs = false;
-       free(profile_dir); profile_dir = NULL;
        i_tmpfile = NULL;
        direct_i_file = false;
        free(cpp_stderr); cpp_stderr = NULL;
index 9b42fd1b5178d3406acdad09c68218a10e79cb1c..11dec6b2320a40991bda82b1c47d107c95424e29 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2010-2019 Joel Rosdahl
+// Copyright (C) 2010-2020 Joel Rosdahl
 //
 // This program is free software; you can redistribute it and/or modify it
 // under the terms of the GNU General Public License as published by the Free
index d506c4657ee46219cc88c2a9dde9f99803cef32d..6b1ec7edc187a6438d70cb7aaeb872c4ad8428fd 100755 (executable)
--- a/test/run
+++ b/test/run
@@ -322,6 +322,7 @@ case $compiler_version in
         ;;
     *clang*)
         COMPILER_TYPE_CLANG=true
+        CLANG_VERSION_SUFFIX=$(echo $COMPILER | sed -r 's/.*clang//')
         ;;
     *)
         echo "WARNING: Compiler $COMPILER not supported (version: $compiler_version) -- not running tests" >&2
@@ -394,6 +395,9 @@ multi_arch
 serialize_diagnostics
 sanitize_blacklist
 debug_prefix_map
+profiling
+profiling_gcc
+profiling_clang
 split_dwarf
 masquerading
 hardlink
diff --git a/test/suites/profiling.bash b/test/suites/profiling.bash
new file mode 100644 (file)
index 0000000..553f908
--- /dev/null
@@ -0,0 +1,103 @@
+SUITE_profiling_PROBE() {
+    touch test.c
+    if ! $COMPILER -fprofile-generate -c test.c 2>/dev/null; then
+        echo "compiler does not support profiling"
+    fi
+    if $COMPILER_TYPE_CLANG && ! which llvm-profdata$CLANG_VERSION_SUFFIX >/dev/null 2>/dev/null; then
+        echo "llvm-profdata$CLANG_VERSION_SUFFIX tool not found"
+    fi
+}
+
+SUITE_profiling_SETUP() {
+    echo 'int main(void) { return 0; }' >test.c
+    unset CCACHE_NODIRECT
+}
+
+SUITE_profiling() {
+    # -------------------------------------------------------------------------
+    TEST "-fprofile-use, missing file"
+
+    $CCACHE_COMPILE -fprofile-use -c test.c 2>/dev/null
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 0
+    expect_stat 'no input file' 1
+
+    # -------------------------------------------------------------------------
+    TEST "-fbranch-probabilities, missing file"
+
+    $CCACHE_COMPILE -fbranch-probabilities -c test.c 2>/dev/null
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 0
+    expect_stat 'no input file' 1
+
+    # -------------------------------------------------------------------------
+    TEST "-fprofile-use=file, missing file"
+
+    $CCACHE_COMPILE -fprofile-use=data.gcda -c test.c 2>/dev/null
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 0
+    expect_stat 'no input file' 1
+
+    # -------------------------------------------------------------------------
+    TEST "-fprofile-use"
+
+    $CCACHE_COMPILE -fprofile-generate -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 1
+
+    $COMPILER -fprofile-generate test.o -o test
+
+    ./test
+    merge_profiling_data .
+
+    $CCACHE_COMPILE -fprofile-use -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 2
+
+    $CCACHE_COMPILE -fprofile-use -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 2
+
+    ./test
+    merge_profiling_data .
+
+    $CCACHE_COMPILE -fprofile-use -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 3
+
+    # -------------------------------------------------------------------------
+    TEST "-fprofile-use=dir"
+
+    mkdir data
+
+    $CCACHE_COMPILE -fprofile-generate=data -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 1
+
+    $COMPILER -fprofile-generate=data test.o -o test
+
+    ./test
+    merge_profiling_data data
+
+    $CCACHE_COMPILE -fprofile-use=data -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 2
+
+    $CCACHE_COMPILE -fprofile-use=data -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 2
+
+    ./test
+    merge_profiling_data data
+
+    $CCACHE_COMPILE -fprofile-use=data -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 3
+}
+
+merge_profiling_data() {
+    local dir=$1
+    if $COMPILER_TYPE_CLANG; then
+        llvm-profdata$CLANG_VERSION_SUFFIX merge -output $dir/default.profdata $dir/*.profraw
+    fi
+}
diff --git a/test/suites/profiling_clang.bash b/test/suites/profiling_clang.bash
new file mode 100644 (file)
index 0000000..4344f7d
--- /dev/null
@@ -0,0 +1,98 @@
+SUITE_profiling_clang_PROBE() {
+    if ! $COMPILER_TYPE_CLANG; then
+        echo "compiler is not Clang"
+    fi
+    if ! which llvm-profdata$CLANG_VERSION_SUFFIX >/dev/null 2>/dev/null; then
+        echo "llvm-profdata$CLANG_VERSION_SUFFIX tool not found"
+    fi
+}
+
+SUITE_profiling_clang_SETUP() {
+    echo 'int main(void) { return 0; }' >test.c
+    unset CCACHE_NODIRECT
+}
+
+SUITE_profiling_clang() {
+    # -------------------------------------------------------------------------
+    TEST "-fprofile-use=file"
+
+    mkdir data
+
+    $CCACHE_COMPILE -fprofile-generate=data -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 1
+
+    $COMPILER -fprofile-generate=data test.o -o test
+
+    ./test
+    llvm-profdata$CLANG_VERSION_SUFFIX merge -output foo.profdata data/default_*.profraw
+
+    $CCACHE_COMPILE -fprofile-use=foo.profdata -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 2
+
+    $CCACHE_COMPILE -fprofile-use=foo.profdata -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 2
+
+    ./test
+    llvm-profdata$CLANG_VERSION_SUFFIX merge -output foo.profdata data/default_*.profraw
+
+    $CCACHE_COMPILE -fprofile-use=foo.profdata -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 3
+
+    # -------------------------------------------------------------------------
+    TEST "-fprofile-instr-use"
+
+    mkdir data
+
+    $CCACHE_COMPILE -fprofile-instr-generate -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 1
+
+    $COMPILER -fprofile-instr-generate test.o -o test
+
+    ./test
+    llvm-profdata$CLANG_VERSION_SUFFIX merge -output default.profdata default.profraw
+
+    $CCACHE_COMPILE -fprofile-instr-use -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 2
+
+    $CCACHE_COMPILE -fprofile-instr-use -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 2
+
+    echo >>default.profdata  # Dummy change to trigger modification
+
+    $CCACHE_COMPILE -fprofile-instr-use -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 3
+
+    # -------------------------------------------------------------------------
+    TEST "-fprofile-instr-use=file"
+
+    $CCACHE_COMPILE -fprofile-instr-generate=foo.profraw -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 1
+
+    $COMPILER -fprofile-instr-generate=data=foo.profraw test.o -o test
+
+    ./test
+    llvm-profdata$CLANG_VERSION_SUFFIX merge -output foo.profdata foo.profraw
+
+    $CCACHE_COMPILE -fprofile-instr-use=foo.profdata -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 2
+
+    $CCACHE_COMPILE -fprofile-instr-use=foo.profdata -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 2
+
+    echo >>foo.profdata  # Dummy change to trigger modification
+
+    $CCACHE_COMPILE -fprofile-instr-use=foo.profdata -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 3
+}
diff --git a/test/suites/profiling_gcc.bash b/test/suites/profiling_gcc.bash
new file mode 100644 (file)
index 0000000..fe61109
--- /dev/null
@@ -0,0 +1,118 @@
+SUITE_profiling_gcc_PROBE() {
+    if ! $COMPILER_TYPE_GCC; then
+        echo "compiler is not GCC"
+    fi
+}
+
+SUITE_profiling_gcc_SETUP() {
+    echo 'int main(void) { return 0; }' >test.c
+    unset CCACHE_NODIRECT
+}
+
+SUITE_profiling_gcc() {
+    # -------------------------------------------------------------------------
+    TEST "-fbranch-probabilities"
+
+    $CCACHE_COMPILE -fprofile-generate -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 1
+
+    $COMPILER -fprofile-generate test.o -o test
+
+    ./test
+
+    $CCACHE_COMPILE -fbranch-probabilities -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 2
+
+    $CCACHE_COMPILE -fbranch-probabilities -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 2
+
+    ./test
+
+    $CCACHE_COMPILE -fbranch-probabilities -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 3
+
+    # -------------------------------------------------------------------------
+    TEST "-fprofile-dir=dir + -fprofile-use"
+
+    mkdir data
+
+    $CCACHE_COMPILE -fprofile-dir=data -fprofile-generate -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 1
+
+    $COMPILER -fprofile-dir=data -fprofile-generate test.o -o test
+
+    ./test
+
+    $CCACHE_COMPILE -fprofile-dir=data -fprofile-use -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 2
+
+    $CCACHE_COMPILE -fprofile-dir=data -fprofile-use -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 2
+
+    ./test
+
+    $CCACHE_COMPILE -fprofile-dir=data -fprofile-use -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 3
+
+    # -------------------------------------------------------------------------
+    TEST "-fprofile-use + -fprofile-dir=dir"
+
+    mkdir data
+
+    $CCACHE_COMPILE -fprofile-generate -fprofile-dir=data -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 1
+
+    $COMPILER -fprofile-generate -fprofile-dir=data test.o -o test
+
+    ./test
+
+    $CCACHE_COMPILE -fprofile-use -fprofile-dir=data -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 2
+
+    $CCACHE_COMPILE -fprofile-use -fprofile-dir=data -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 2
+
+    ./test
+
+    $CCACHE_COMPILE -fprofile-use -fprofile-dir=data -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 3
+
+    # -------------------------------------------------------------------------
+    TEST "-fprofile-dir=path1 + -fprofile-use=path2"
+
+    mkdir data
+
+    $CCACHE_COMPILE -fprofile-dir=data2 -fprofile-generate=data -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 1
+
+    $COMPILER -fprofile-dir=data2 -fprofile-generate=data test.o -o test
+
+    ./test
+
+    $CCACHE_COMPILE -fprofile-dir=data2 -fprofile-use=data -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache miss' 2
+
+    $CCACHE_COMPILE -fprofile-dir=data2 -fprofile-use=data -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 2
+
+    ./test
+
+    $CCACHE_COMPILE -fprofile-dir=data2 -fprofile-use=data -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache miss' 3
+}
index c0504bee1d8949c8b1f246570af00bc62d040aec..665423f13474c50efac7fa9738c7ce8e2c67e984 100644 (file)
@@ -354,52 +354,6 @@ TEST(MT_flag_with_immediate_argument_should_not_add_MQobj)
        args_free(orig);
 }
 
-TEST(fprofile_flag_with_existing_dir_should_be_rewritten_to_real_path)
-{
-       struct args *orig = args_init_from_string(
-               "gcc -c -fprofile-generate=some/dir foo.c");
-       struct args *exp_cpp = args_init_from_string("gcc");
-       struct args *exp_cc = args_init_from_string("gcc");
-       struct args *act_cpp = NULL, *act_cc = NULL;
-       char *s, *path;
-
-       create_file("foo.c", "");
-       mkdir("some", 0777);
-       mkdir("some/dir", 0777);
-       path = x_realpath("some/dir");
-       s = format("-fprofile-generate=%s", path);
-       free(path);
-       args_add(exp_cpp, s);
-       args_add(exp_cc, s);
-       args_add(exp_cc, "-c");
-       free(s);
-
-       CHECK(cc_process_args(orig, &act_cpp, NULL, &act_cc));
-       CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
-       CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
-       args_free(orig);
-}
-
-TEST(fprofile_flag_with_nonexistent_dir_should_not_be_rewritten)
-{
-       struct args *orig = args_init_from_string(
-               "gcc -c -fprofile-generate=some/dir foo.c");
-       struct args *exp_cpp = args_init_from_string(
-               "gcc -fprofile-generate=some/dir");
-       struct args *exp_cc = args_init_from_string(
-               "gcc -fprofile-generate=some/dir -c");
-       struct args *act_cpp = NULL, *act_cc = NULL;
-
-       create_file("foo.c", "");
-
-       CHECK(cc_process_args(orig, &act_cpp, NULL, &act_cc));
-       CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
-       CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
-
-       args_free(orig);
-}
-
 TEST(isystem_flag_with_separate_arg_should_be_rewritten_if_basedir_is_used)
 {
        extern char *current_working_dir;