From 3b2c002c6d37887e4eb219e7e605d17ba52702d6 Mon Sep 17 00:00:00 2001 From: Xinliang David Li Date: Tue, 9 Aug 2016 04:21:14 +0000 Subject: [PATCH] [Profile] Implement new API __llvm_profile_dump The API is intended to be used by user to do fine grained (per-region) control of profile dumping. Differential Revision: http://reviews.llvm.org/D23106 llvm-svn: 278092 --- compiler-rt/lib/profile/InstrProfiling.c | 11 ++++ compiler-rt/lib/profile/InstrProfiling.h | 22 +++++++ compiler-rt/lib/profile/InstrProfilingFile.c | 18 ++++++ .../lib/profile/InstrProfilingInternal.h | 7 +++ compiler-rt/test/profile/instrprof-dump.c | 62 +++++++++++++++++++ 5 files changed, 120 insertions(+) create mode 100644 compiler-rt/test/profile/instrprof-dump.c diff --git a/compiler-rt/lib/profile/InstrProfiling.c b/compiler-rt/lib/profile/InstrProfiling.c index b7ba25f30f8dc..1dcd05b64481d 100644 --- a/compiler-rt/lib/profile/InstrProfiling.c +++ b/compiler-rt/lib/profile/InstrProfiling.c @@ -27,6 +27,16 @@ COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_magic(void) { : (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 @@ COMPILER_RT_VISIBILITY void __llvm_profile_reset_counters(void) { } } } + ProfileDumped = 0; } diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h index 0ffb402f3d019..945f1c4ac38d8 100644 --- a/compiler-rt/lib/profile/InstrProfiling.h +++ b/compiler-rt/lib/profile/InstrProfiling.h @@ -117,6 +117,28 @@ void INSTR_PROF_VALUE_PROF_FUNC( */ 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 with \c %m specifier + * used in profile filename . 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. * diff --git a/compiler-rt/lib/profile/InstrProfilingFile.c b/compiler-rt/lib/profile/InstrProfilingFile.c index 70953ac2c173e..70102f3248bec 100644 --- a/compiler-rt/lib/profile/InstrProfilingFile.c +++ b/compiler-rt/lib/profile/InstrProfilingFile.c @@ -522,6 +522,12 @@ int __llvm_profile_write_file(void) { 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 @@ int __llvm_profile_write_file(void) { 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 diff --git a/compiler-rt/lib/profile/InstrProfilingInternal.h b/compiler-rt/lib/profile/InstrProfilingInternal.h index bcbe29a032d50..21590d5c43c21 100644 --- a/compiler-rt/lib/profile/InstrProfilingInternal.h +++ b/compiler-rt/lib/profile/InstrProfilingInternal.h @@ -163,6 +163,13 @@ void lprofSetupValueProfiler(); * 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; diff --git a/compiler-rt/test/profile/instrprof-dump.c b/compiler-rt/test/profile/instrprof-dump.c new file mode 100644 index 0000000000000..93c3c46f69160 --- /dev/null +++ b/compiler-rt/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} +*/