Index: lib/profile/InstrProfiling.h =================================================================== --- lib/profile/InstrProfiling.h +++ lib/profile/InstrProfiling.h @@ -118,6 +118,28 @@ int __llvm_profile_write_file(void); /*! + * \brief this is a wrapper interface to \c __llvm_profile_write_file. + * After this interface is invoked, a arleady dumped flag will be set + * so that profile won't be dumped again during program exit. + * Invocation of interface __llvm_profile_reset_counters will clear + * the flag. This interface is designed to be used to collect profile + * data from user selected hot regions. The use model is + * __llvm_profile_reset_counters(); + * ... hot region 1 + * __llvm_profile_dump(); + * .. some other code + * __llvm_profile_reset_counters(); + * ... hot region 2 + * __llvm_profile_dump(); + * + * It is expected that on-line profile merging is on. If merging is + * not turned on, user is expected to invoke __llvm_profile_set_filename + * to specify different profile names for different regions before + * dumping to avoid profile write clobbering. + */ +int __llvm_profile_dump(void); + +/*! * \brief Set the filename for writing instrumentation data. * * Sets the filename to be used for subsequent calls to Index: lib/profile/InstrProfiling.c =================================================================== --- lib/profile/InstrProfiling.c +++ lib/profile/InstrProfiling.c @@ -27,6 +27,16 @@ : (INSTR_PROF_RAW_MAGIC_32); } +static unsigned ProfileDumped = 0; + +COMPILER_RT_VISIBILITY unsigned lprofProfileDumped() { + return ProfileDumped; +} + +COMPILER_RT_VISIBILITY void lprofSetProfileDumped() { + ProfileDumped = 1; +} + /* Return the number of bytes needed to add to SizeInBytes to make it * the result a multiple of 8. */ @@ -68,4 +78,5 @@ } } } + ProfileDumped = 0; } Index: lib/profile/InstrProfilingFile.c =================================================================== --- lib/profile/InstrProfilingFile.c +++ lib/profile/InstrProfilingFile.c @@ -522,6 +522,12 @@ const char *Filename; char *FilenameBuf; + if (lprofProfileDumped()) { + PROF_NOTE("Profile data not written to file: %s.\n", + "already written"); + return 0; + } + Length = getCurFilenameLength(); FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); Filename = getCurFilename(FilenameBuf); @@ -548,6 +554,18 @@ return rc; } +COMPILER_RT_VISIBILITY +int __llvm_profile_dump(void) { + if (!doMerging()) + PROF_WARN("Later invocation of __llvm_profile_dump can lead to clobbering " + " of previously dumped profile data : %s. Either use \%m " + "in profile name or change profile name before dumping.\n", + "online profile merging is not on"); + int rc = __llvm_profile_write_file(); + lprofSetProfileDumped(); + return rc; +} + static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); } COMPILER_RT_VISIBILITY Index: lib/profile/InstrProfilingInternal.h =================================================================== --- lib/profile/InstrProfilingInternal.h +++ lib/profile/InstrProfilingInternal.h @@ -163,6 +163,13 @@ * to dump merged profile data into its own profile file. */ uint64_t lprofGetLoadModuleSignature(); +/* + * Return non zero value if the profile data has already been + * dumped to the file. + */ +unsigned lprofProfileDumped(); +void lprofSetProfileDumped(); + COMPILER_RT_VISIBILITY extern char *(*GetEnvHook)(const char *); COMPILER_RT_VISIBILITY extern void (*FreeHook)(void *); COMPILER_RT_VISIBILITY extern uint8_t *DynamicBufferIOBuffer; Index: test/profile/instrprof-dump.c =================================================================== --- test/profile/instrprof-dump.c +++ test/profile/instrprof-dump.c @@ -0,0 +1,62 @@ +/* +RUN: rm -fr %t.profdir +RUN: %clang_profgen=%t.profdir/default_%m.profraw -o %t -O2 %s +RUN: %run %t 2>&1 | FileCheck %s --check-prefix=NO_EXIT_WRITE +RUN: llvm-profdata merge -o %t.profdata %t.profdir +RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s --check-prefix=PROF + +NO_EXIT_WRITE: Profile data not written to file: already written +*/ + +int __llvm_profile_dump(void); +void __llvm_profile_reset_counters(void); +int foo(int); +int bar(int); +int skip(int); + +int main(int argc, const char *argv[]) { + int Ret = foo(0); /* region 1 */ + __llvm_profile_dump(); + + /* not profiled -- cleared later. */ + skip(0); /* skipped region */ + + __llvm_profile_reset_counters(); + Ret += bar(0); /* region 2 */ + __llvm_profile_dump(); + + skip(1); + + __llvm_profile_reset_counters(); + /* foo's profile will be merged. */ + foo(1); /* region 3 */ + __llvm_profile_dump(); + + return Ret; +} + +__attribute__((noinline)) int foo(int X) { + /* PROF: define {{.*}} @foo({{.*}}!prof ![[ENT:[0-9]+]] + PROF: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]] + */ + return X <= 0 ? -X : X; +} + +__attribute__((noinline)) int skip(int X) { + /* PROF: define {{.*}} @skip( + PROF: br i1 %{{.*}}, label %{{.*}}, label %{{[^,]+$}} + */ + return X <= 0 ? -X : X; +} + +__attribute__((noinline)) int bar(int X) { + /* PROF-LABEL: define {{.*}} @bar( + PROF: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD2:[0-9]+]] + */ + return X <= 0 ? -X : X; +} + +/* +PROF: ![[ENT]] = !{!"function_entry_count", i64 2} +PROF: ![[PD1]] = !{!"branch_weights", i32 2, i32 2} +*/