diff options
| author | Duncan P. N. Exon Smith <dexonsmith@apple.com> | 2014-05-17 01:27:30 +0000 |
|---|---|---|
| committer | Duncan P. N. Exon Smith <dexonsmith@apple.com> | 2014-05-17 01:27:30 +0000 |
| commit | 55e4d66f0c427d916c6cc66d18b54be2e87aa847 (patch) | |
| tree | b913efce7e8c3eb551c11632bd6dab42bd0504c6 /compiler-rt/lib/profile/InstrProfilingFile.c | |
| parent | b0869036c1143d53bb5b585ce06258463e7de1b2 (diff) | |
| download | bcm5719-llvm-55e4d66f0c427d916c6cc66d18b54be2e87aa847.tar.gz bcm5719-llvm-55e4d66f0c427d916c6cc66d18b54be2e87aa847.zip | |
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>
llvm-svn: 209053
Diffstat (limited to 'compiler-rt/lib/profile/InstrProfilingFile.c')
| -rw-r--r-- | compiler-rt/lib/profile/InstrProfilingFile.c | 166 |
1 files changed, 91 insertions, 75 deletions
diff --git a/compiler-rt/lib/profile/InstrProfilingFile.c b/compiler-rt/lib/profile/InstrProfilingFile.c index 5ed32d56267..779a68225c3 100644 --- a/compiler-rt/lib/profile/InstrProfilingFile.c +++ b/compiler-rt/lib/profile/InstrProfilingFile.c @@ -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_write_file(void) { 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) |

