Index: lib/profile/InstrProfiling.h =================================================================== --- lib/profile/InstrProfiling.h +++ lib/profile/InstrProfiling.h @@ -62,7 +62,9 @@ * * Writes to the file with the last name given to \a __llvm_profile_set_filename(), * or if it hasn't been called, the \c LLVM_PROFILE_FILE environment variable, - * or if that's not set, \c "default.profdata". + * or if that's not set, the last name given to + * \a __llvm_profile_override_default_filename(), or if that's not set, + * \c "default.profdata". */ int __llvm_profile_write_file(void); @@ -77,6 +79,19 @@ */ void __llvm_profile_set_filename(const char *Name); +/*! + * \brief Set the filename for writing instrumentation data, unless the + * \c LLVM_PROFILE_FILE environment variable was set. + * + * Unless overridden, sets the filename to be used for subsequent calls to + * \a __llvm_profile_write_file(). + * + * \c Name is not copied, so it must remain valid. Passing NULL resets the + * filename logic to the default behaviour (unless the \c LLVM_PROFILE_FILE + * was set in which case it has no effect). + */ +void __llvm_profile_override_default_filename(const char *Name); + /*! \brief Register to write instrumentation data to file at exit. */ int __llvm_profile_register_write_file_atexit(void); Index: lib/profile/InstrProfilingFile.c =================================================================== --- lib/profile/InstrProfilingFile.c +++ lib/profile/InstrProfilingFile.c @@ -76,14 +76,6 @@ __attribute__((weak)) int __llvm_profile_OwnsFilename = 0; __attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL; -static void setFilename(const char *Filename, int OwnsFilename) { - if (__llvm_profile_OwnsFilename) - free(UNCONST(__llvm_profile_CurrentFilename)); - - __llvm_profile_CurrentFilename = Filename; - __llvm_profile_OwnsFilename = OwnsFilename; -} - static void truncateCurrentFile(void) { const char *Filename; FILE *File; @@ -99,19 +91,36 @@ fclose(File); } -static void setDefaultFilename(void) { setFilename("default.profraw", 0); } +static void setFilename(const char *Filename, int OwnsFilename) { + /* Check if this is a new filename and therefore needs truncation. */ + int NewFile = !__llvm_profile_CurrentFilename || + (Filename && strcmp(Filename, __llvm_profile_CurrentFilename)); + if (__llvm_profile_OwnsFilename) + free(UNCONST(__llvm_profile_CurrentFilename)); + + __llvm_profile_CurrentFilename = Filename; + __llvm_profile_OwnsFilename = OwnsFilename; + + /* If not a new file, append to support profiling multiple shared objects. */ + if (NewFile) + truncateCurrentFile(); +} + +static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); } int getpid(void); -static int setFilenameFromEnvironment(void) { - const char *Filename = getenv("LLVM_PROFILE_FILE"); +static int setFilenamePossiblyWithPid(const char *Filename) { #define MAX_PID_SIZE 16 char PidChars[MAX_PID_SIZE] = {0}; int NumPids = 0, PidLength = 0; char *Allocated; int I, J; - if (!Filename || !Filename[0]) - return -1; + /* Reset filename on NULL, except with env var which is checked by caller. */ + if (!Filename) { + resetFilenameToDefault(); + return 0; + } /* Check the filename for "%p", which indicates a pid-substitution. */ for (I = 0; Filename[I]; ++I) @@ -148,11 +157,20 @@ return 0; } +static int setFilenameFromEnvironment(void) { + const char *Filename = getenv("LLVM_PROFILE_FILE"); + + if (!Filename || !Filename[0]) + return -1; + + return setFilenamePossiblyWithPid(Filename); +} + static void setFilenameAutomatically(void) { if (!setFilenameFromEnvironment()) return; - setDefaultFilename(); + resetFilenameToDefault(); } __attribute__((visibility("hidden"))) @@ -163,13 +181,20 @@ /* Detect the filename and truncate. */ setFilenameAutomatically(); - truncateCurrentFile(); } __attribute__((visibility("hidden"))) void __llvm_profile_set_filename(const char *Filename) { - setFilename(Filename, 0); - truncateCurrentFile(); + setFilenamePossiblyWithPid(Filename); +} + +__attribute__((visibility("hidden"))) +void __llvm_profile_override_default_filename(const char *Filename) { + /* If the env var is set, skip setting filename from argument. */ + const char *Env_Filename = getenv("LLVM_PROFILE_FILE"); + if (Env_Filename && Env_Filename[0]) + return; + setFilenamePossiblyWithPid(Filename); } __attribute__((visibility("hidden"))) Index: test/profile/instrprof-override-filename-then-reset-default.c =================================================================== --- /dev/null +++ test/profile/instrprof-override-filename-then-reset-default.c @@ -0,0 +1,15 @@ +// RUN: %clang_profgen -o %t -O3 %s +// RUN: %run %t %t.profraw +// RUN: llvm-profdata merge -o %t.profdata default.profraw +// RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s + +void __llvm_profile_override_default_filename(const char *); +int main(int argc, const char *argv[]) { + // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]] + if (argc < 2) + return 1; + __llvm_profile_override_default_filename(argv[1]); + __llvm_profile_override_default_filename(0); + return 0; +} +// CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2} Index: test/profile/instrprof-override-filename-with-env.c =================================================================== --- /dev/null +++ test/profile/instrprof-override-filename-with-env.c @@ -0,0 +1,14 @@ +// RUN: %clang_profgen -o %t -O3 %s +// RUN: env LLVM_PROFILE_FILE=%t.good.profraw %run %t %t.bad.profraw +// RUN: llvm-profdata merge -o %t.profdata %t.good.profraw +// RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s + +void __llvm_profile_override_default_filename(const char *); +int main(int argc, const char *argv[]) { + // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]] + if (argc < 2) + return 1; + __llvm_profile_override_default_filename(argv[1]); + return 0; +} +// CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2} Index: test/profile/instrprof-override-filename.c =================================================================== --- /dev/null +++ test/profile/instrprof-override-filename.c @@ -0,0 +1,14 @@ +// RUN: %clang_profgen -o %t -O3 %s +// RUN: %run %t %t.profraw +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s + +void __llvm_profile_override_default_filename(const char *); +int main(int argc, const char *argv[]) { + // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]] + if (argc < 2) + return 1; + __llvm_profile_override_default_filename(argv[1]); + return 0; +} +// CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2} Index: test/profile/instrprof-set-filename-then-reset-default.c =================================================================== --- /dev/null +++ test/profile/instrprof-set-filename-then-reset-default.c @@ -0,0 +1,15 @@ +// RUN: %clang_profgen -o %t -O3 %s +// RUN: %run %t %t.profraw +// RUN: llvm-profdata merge -o %t.profdata default.profraw +// RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s + +void __llvm_profile_set_filename(const char *); +int main(int argc, const char *argv[]) { + // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]] + if (argc < 2) + return 1; + __llvm_profile_set_filename(argv[1]); + __llvm_profile_set_filename(0); + return 0; +} +// CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2}