[compiler-rt] r209053 - InstrProf: Support profiling dlopen'd shared libraries
Duncan P. N. Exon Smith
dexonsmith at apple.com
Fri May 16 18:27:31 PDT 2014
Author: dexonsmith
Date: Fri May 16 20:27:30 2014
New Revision: 209053
URL: http://llvm.org/viewvc/llvm-project?rev=209053&view=rev
Log:
InstrProf: Support profiling dlopen'd shared libraries
Shared objects are hard. After this commit, we do the right thing when
profiling two separate shared objects that have been dlopen'd with
`RTLD_LOCAL`, when the main executable is *not* being profiled.
This mainly simplifies the writer logic.
- At initialization, determine the output filename and truncate the
file. Depending on whether shared objects can see each other, this
may happen multiple times.
- At exit, each executable writes its own profile in append mode.
<rdar://problem/16918688>
Added:
compiler-rt/trunk/test/profile/Inputs/instrprof-dlopen-func.c
compiler-rt/trunk/test/profile/Inputs/instrprof-dlopen-func2.c
compiler-rt/trunk/test/profile/Inputs/instrprof-dlopen-main.c
compiler-rt/trunk/test/profile/instrprof-dlopen.test
Modified:
compiler-rt/trunk/lib/profile/InstrProfiling.h
compiler-rt/trunk/lib/profile/InstrProfilingFile.c
compiler-rt/trunk/lib/profile/InstrProfilingRuntime.cc
Modified: compiler-rt/trunk/lib/profile/InstrProfiling.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/profile/InstrProfiling.h?rev=209053&r1=209052&r2=209053&view=diff
==============================================================================
--- compiler-rt/trunk/lib/profile/InstrProfiling.h (original)
+++ compiler-rt/trunk/lib/profile/InstrProfiling.h Fri May 16 20:27:30 2014
@@ -83,8 +83,8 @@ void __llvm_profile_set_filename(const c
/*! \brief Register to write instrumentation data to file at exit. */
int __llvm_profile_register_write_file_atexit(void);
-/*! \brief Register the write file function for this executable. */
-void __llvm_profile_register_write_file(void);
+/*! \brief Initialize file handling. */
+void __llvm_profile_initialize_file(void);
/*! \brief Get the magic token for the file format. */
uint64_t __llvm_profile_get_magic(void);
Modified: compiler-rt/trunk/lib/profile/InstrProfilingFile.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/profile/InstrProfilingFile.c?rev=209053&r1=209052&r2=209053&view=diff
==============================================================================
--- compiler-rt/trunk/lib/profile/InstrProfilingFile.c (original)
+++ compiler-rt/trunk/lib/profile/InstrProfilingFile.c Fri May 16 20:27:30 2014
@@ -53,75 +53,60 @@ static int writeFile(FILE *File) {
return 0;
}
-typedef struct __llvm_profile_writer {
- struct __llvm_profile_writer *Next;
- int (*Data)(FILE *);
-} __llvm_profile_writer;
-
-__attribute__((weak)) __llvm_profile_writer *__llvm_profile_HeadWriter = NULL;
-static __llvm_profile_writer Writer = {NULL, writeFile};
-
-__attribute__((visibility("hidden")))
-void __llvm_profile_register_write_file(void) {
- static int HasBeenRegistered = 0;
-
- if (HasBeenRegistered)
- return;
-
- HasBeenRegistered = 1;
- Writer.Next = __llvm_profile_HeadWriter;
- __llvm_profile_HeadWriter = &Writer;
-}
-
static int writeFileWithName(const char *OutputName) {
int RetVal;
FILE *OutputFile;
if (!OutputName || !OutputName[0])
return -1;
- OutputFile = fopen(OutputName, "w");
+
+ /* Append to the file to support profiling multiple shared objects. */
+ OutputFile = fopen(OutputName, "a");
if (!OutputFile)
return -1;
- __llvm_profile_writer *Writer = __llvm_profile_HeadWriter;
- if (Writer)
- for (; Writer; Writer = Writer->Next) {
- RetVal = Writer->Data(OutputFile);
- if (RetVal != 0)
- break;
- }
- else
- // Default to calling this executable's writeFile.
- RetVal = writeFile(OutputFile);
+ RetVal = writeFile(OutputFile);
fclose(OutputFile);
return RetVal;
}
+__attribute__((weak)) int __llvm_profile_OwnsFilename = 0;
__attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL;
-__attribute__((weak)) void __llvm_profile_set_filename(const char *Filename) {
+
+static void setFilename(const char *Filename, int OwnsFilename) {
+ if (__llvm_profile_OwnsFilename)
+ free((char *)__llvm_profile_CurrentFilename);
+
__llvm_profile_CurrentFilename = Filename;
+ __llvm_profile_OwnsFilename = OwnsFilename;
}
-int getpid(void);
-__attribute__((weak)) int __llvm_profile_write_file(void) {
- char *AllocatedFilename = NULL;
- int I, J;
- int RetVal;
+static void truncateCurrentFile(void) {
+ const char *Filename = __llvm_profile_CurrentFilename;
+ if (!Filename || !Filename[0])
+ return;
-#define MAX_PID_SIZE 16
- char PidChars[MAX_PID_SIZE] = { 0 };
- int PidLength = 0;
- int NumPids = 0;
+ /* Truncate the file. Later we'll reopen and append. */
+ FILE *File = fopen(Filename, "w");
+ if (!File)
+ return;
+ fclose(File);
+}
- /* Get the filename. */
- const char *Filename = __llvm_profile_CurrentFilename;
-#define UPDATE_FILENAME(NextFilename) \
- if (!Filename || !Filename[0]) Filename = NextFilename
- UPDATE_FILENAME(getenv("LLVM_PROFILE_FILE"));
- UPDATE_FILENAME("default.profraw");
-#undef UPDATE_FILENAME
+static void setDefaultFilename(void) { setFilename("default.profraw", 0); }
+
+int getpid(void);
+static int setFilenameFromEnvironment(void) {
+ const char *Filename = getenv("LLVM_PROFILE_FILE");
+ if (!Filename || !Filename[0])
+ return -1;
/* Check the filename for "%p", which indicates a pid-substitution. */
+#define MAX_PID_SIZE 16
+ char PidChars[MAX_PID_SIZE] = {0};
+ int NumPids = 0;
+ int PidLength = 0;
+ int I;
for (I = 0; Filename[I]; ++I)
if (Filename[I] == '%' && Filename[++I] == 'p')
if (!NumPids++) {
@@ -129,43 +114,74 @@ __attribute__((weak)) int __llvm_profile
if (PidLength <= 0)
return -1;
}
- if (NumPids) {
- /* Allocate enough space for the substituted filename. */
- AllocatedFilename = (char*)malloc(I + NumPids*(PidLength - 2) + 1);
- if (!AllocatedFilename)
- return -1;
-
- /* Construct the new filename. */
- for (I = 0, J = 0; Filename[I]; ++I)
- if (Filename[I] == '%') {
- if (Filename[++I] == 'p') {
- memcpy(AllocatedFilename + J, PidChars, PidLength);
- J += PidLength;
- }
- /* Drop any unknown substitutions. */
- } else
- AllocatedFilename[J++] = Filename[I];
- AllocatedFilename[J] = 0;
-
- /* Actually use the computed name. */
- Filename = AllocatedFilename;
+ if (!NumPids) {
+ setFilename(Filename, 0);
+ return 0;
}
- /* Write the file. */
- RetVal = writeFileWithName(Filename);
+ /* Allocate enough space for the substituted filename. */
+ char *Allocated = (char*)malloc(I + NumPids*(PidLength - 2) + 1);
+ if (!Allocated)
+ return -1;
- /* Free the filename. */
- if (AllocatedFilename)
- free(AllocatedFilename);
+ /* Construct the new filename. */
+ int J;
+ for (I = 0, J = 0; Filename[I]; ++I)
+ if (Filename[I] == '%') {
+ if (Filename[++I] == 'p') {
+ memcpy(Allocated + J, PidChars, PidLength);
+ J += PidLength;
+ }
+ /* Drop any unknown substitutions. */
+ } else
+ Allocated[J++] = Filename[I];
+ Allocated[J] = 0;
- return RetVal;
+ /* Use the computed name. */
+ setFilename(Allocated, 1);
+ return 0;
+}
+
+static void setFilenameAutomatically(void) {
+ if (!setFilenameFromEnvironment())
+ return;
+
+ setDefaultFilename();
+}
+
+__attribute__((visibility("hidden")))
+void __llvm_profile_initialize_file(void) {
+ /* Check if the filename has been initialized. */
+ if (__llvm_profile_CurrentFilename)
+ return;
+
+ /* Detect the filename and truncate. */
+ setFilenameAutomatically();
+ truncateCurrentFile();
+}
+
+__attribute__((visibility("hidden")))
+void __llvm_profile_set_filename(const char *Filename) {
+ setFilename(Filename, 0);
+ truncateCurrentFile();
+}
+
+__attribute__((visibility("hidden")))
+int __llvm_profile_write_file(void) {
+ /* Check the filename. */
+ if (!__llvm_profile_CurrentFilename)
+ return -1;
+
+ /* Write the file. */
+ return writeFileWithName(__llvm_profile_CurrentFilename);
}
static void writeFileWithoutReturn(void) {
__llvm_profile_write_file();
}
-__attribute__((weak)) int __llvm_profile_register_write_file_atexit(void) {
+__attribute__((visibility("hidden")))
+int __llvm_profile_register_write_file_atexit(void) {
static int HasBeenRegistered = 0;
if (HasBeenRegistered)
Modified: compiler-rt/trunk/lib/profile/InstrProfilingRuntime.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/profile/InstrProfilingRuntime.cc?rev=209053&r1=209052&r2=209053&view=diff
==============================================================================
--- compiler-rt/trunk/lib/profile/InstrProfilingRuntime.cc (original)
+++ compiler-rt/trunk/lib/profile/InstrProfilingRuntime.cc Fri May 16 20:27:30 2014
@@ -21,7 +21,7 @@ class RegisterRuntime {
public:
RegisterRuntime() {
__llvm_profile_register_write_file_atexit();
- __llvm_profile_register_write_file();
+ __llvm_profile_initialize_file();
}
};
Added: compiler-rt/trunk/test/profile/Inputs/instrprof-dlopen-func.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/profile/Inputs/instrprof-dlopen-func.c?rev=209053&view=auto
==============================================================================
--- compiler-rt/trunk/test/profile/Inputs/instrprof-dlopen-func.c (added)
+++ compiler-rt/trunk/test/profile/Inputs/instrprof-dlopen-func.c Fri May 16 20:27:30 2014
@@ -0,0 +1 @@
+void func(int K) { if (K) {} }
Added: compiler-rt/trunk/test/profile/Inputs/instrprof-dlopen-func2.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/profile/Inputs/instrprof-dlopen-func2.c?rev=209053&view=auto
==============================================================================
--- compiler-rt/trunk/test/profile/Inputs/instrprof-dlopen-func2.c (added)
+++ compiler-rt/trunk/test/profile/Inputs/instrprof-dlopen-func2.c Fri May 16 20:27:30 2014
@@ -0,0 +1 @@
+void func2(int K) { if (K) {} }
Added: compiler-rt/trunk/test/profile/Inputs/instrprof-dlopen-main.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/profile/Inputs/instrprof-dlopen-main.c?rev=209053&view=auto
==============================================================================
--- compiler-rt/trunk/test/profile/Inputs/instrprof-dlopen-main.c (added)
+++ compiler-rt/trunk/test/profile/Inputs/instrprof-dlopen-main.c Fri May 16 20:27:30 2014
@@ -0,0 +1,18 @@
+#ifdef DLOPEN_FUNC_DIR
+#include <dlfcn.h>
+#else
+void func(int K);
+void func2(int K);
+#endif
+
+int main(int argc, char *argv[]) {
+#ifdef DLOPEN_FUNC_DIR
+ void *f1_handle = dlopen(DLOPEN_FUNC_DIR"/func.shared", DLOPEN_FLAGS);
+ void (*func)(int) = (void (*)(int))dlsym(f1_handle, "func");
+ void *f2_handle = dlopen(DLOPEN_FUNC_DIR"/func2.shared", DLOPEN_FLAGS);
+ void (*func2)(int) = (void (*)(int))dlsym(f2_handle, "func2");
+#endif
+ func(1);
+ func2(0);
+ return 0;
+}
Added: compiler-rt/trunk/test/profile/instrprof-dlopen.test
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/profile/instrprof-dlopen.test?rev=209053&view=auto
==============================================================================
--- compiler-rt/trunk/test/profile/instrprof-dlopen.test (added)
+++ compiler-rt/trunk/test/profile/instrprof-dlopen.test Fri May 16 20:27:30 2014
@@ -0,0 +1,34 @@
+RUN: mkdir -p %t.d
+RUN: %clang_profgen -o %t.d/func.shared -fPIC -shared %S/Inputs/instrprof-dlopen-func.c
+RUN: %clang_profgen -o %t.d/func2.shared -fPIC -shared %S/Inputs/instrprof-dlopen-func2.c
+RUN: %clang -o %t-local -fPIC -DDLOPEN_FUNC_DIR=\"%t.d\" -DDLOPEN_FLAGS=RTLD_LOCAL %S/Inputs/instrprof-dlopen-main.c
+RUN: %clang -o %t-global -fPIC -DDLOPEN_FUNC_DIR=\"%t.d\" -DDLOPEN_FLAGS=RTLD_GLOBAL %S/Inputs/instrprof-dlopen-main.c
+
+RUN: %clang -c -o %t.d/main.o %S/Inputs/instrprof-dlopen-main.c
+RUN: %clang_profgen -o %t-static %S/Inputs/instrprof-dlopen-func.c %S/Inputs/instrprof-dlopen-func2.c %t.d/main.o
+
+RUN: env LLVM_PROFILE_FILE=%t-static.profraw %run %t-static
+RUN: env LLVM_PROFILE_FILE=%t-local.profraw %run %t-local
+RUN: env LLVM_PROFILE_FILE=%t-global.profraw %run %t-global
+
+RUN: llvm-profdata merge -o %t-static.profdata %t-static.profraw
+RUN: llvm-profdata merge -o %t-local.profdata %t-local.profraw
+RUN: llvm-profdata merge -o %t-global.profdata %t-global.profraw
+
+RUN: %clang_profuse=%t-static.profdata -o %t-func.static.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-func.c
+RUN: %clang_profuse=%t-local.profdata -o %t-func.local.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-func.c
+RUN: %clang_profuse=%t-global.profdata -o %t-func.global.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-func.c
+RUN: diff %t-func.static.ll %t-func.local.ll
+RUN: diff %t-func.static.ll %t-func.global.ll
+
+RUN: %clang_profuse=%t-static.profdata -o %t-func2.static.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-func2.c
+RUN: %clang_profuse=%t-local.profdata -o %t-func2.local.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-func2.c
+RUN: %clang_profuse=%t-global.profdata -o %t-func2.global.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-func2.c
+RUN: diff %t-func2.static.ll %t-func2.local.ll
+RUN: diff %t-func2.static.ll %t-func2.global.ll
+
+RUN: %clang_profuse=%t-static.profdata -o %t-main.static.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-main.c
+RUN: %clang_profuse=%t-local.profdata -o %t-main.local.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-main.c
+RUN: %clang_profuse=%t-local.profdata -o %t-main.global.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-main.c
+RUN: diff %t-main.static.ll %t-main.local.ll
+RUN: diff %t-main.static.ll %t-main.global.ll
More information about the llvm-commits
mailing list