Index: compiler-rt/trunk/lib/profile/InstrProfiling.h =================================================================== --- compiler-rt/trunk/lib/profile/InstrProfiling.h +++ compiler-rt/trunk/lib/profile/InstrProfiling.h @@ -148,6 +148,16 @@ /*! \brief Initialize file handling. */ void __llvm_profile_initialize_file(void); +/*! + * \brief Return path prefix (excluding the base filename) of the profile data. + * This is useful for users using \c -fprofile-generate=./path_prefix who do + * not care about the default raw profile name. It is also useful to collect + * more than more profile data files dumped in the same directory (Online + * merge mode is turned on for instrumented programs with shared libs). + * Side-effect: this API call will invoke malloc with dynamic memory allocation. + */ +const char *__llvm_profile_get_path_prefix(); + /*! \brief Get the magic token for the file format. */ uint64_t __llvm_profile_get_magic(void); Index: compiler-rt/trunk/lib/profile/InstrProfilingFile.c =================================================================== --- compiler-rt/trunk/lib/profile/InstrProfilingFile.c +++ compiler-rt/trunk/lib/profile/InstrProfilingFile.c @@ -63,6 +63,7 @@ typedef struct lprofFilename { /* File name string possibly with %p or %h specifiers. */ const char *FilenamePat; + const char *ProfilePathPrefix; char PidChars[MAX_PID_SIZE]; char Hostname[COMPILER_RT_MAX_HOSTLEN]; unsigned NumPids; @@ -78,7 +79,7 @@ ProfileNameSpecifier PNS; } lprofFilename; -lprofFilename lprofCurFilename = {0, {0}, {0}, 0, 0, 0, PNS_unknown}; +lprofFilename lprofCurFilename = {0, 0, {0}, {0}, 0, 0, 0, PNS_unknown}; int getpid(void); static int getCurFilenameLength(); @@ -344,6 +345,12 @@ getPNSStr(PNS)); } + /* Clean up cached prefix. */ + if (lprofCurFilename.ProfilePathPrefix) { + free((void*)lprofCurFilename.ProfilePathPrefix); + lprofCurFilename.ProfilePathPrefix = NULL; + } + if (!lprofCurFilename.MergePoolSize) truncateCurrentFile(); } @@ -425,6 +432,37 @@ return Filename; } +COMPILER_RT_VISIBILITY +const char *__llvm_profile_get_path_prefix(void) { + int Length; + char *FilenameBuf, *Prefix; + const char *Filename, *PrefixEnd; + + if (lprofCurFilename.ProfilePathPrefix) + return lprofCurFilename.ProfilePathPrefix; + + Length = getCurFilenameLength(); + FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); + Filename = getCurFilename(FilenameBuf); + if (!Filename) + return "\0"; + + PrefixEnd = lprofFindLastDirSeparator(Filename); + if (!PrefixEnd) + return "\0"; + + Length = PrefixEnd - Filename + 1; + Prefix = (char *)malloc(Length + 1); + if (!Prefix) { + PROF_ERR("Failed to %s\n", "allocate memory."); + return "\0"; + } + memcpy(Prefix, Filename, Length); + Prefix[Length] = '\0'; + lprofCurFilename.ProfilePathPrefix = Prefix; + return Prefix; +} + /* This method is invoked by the runtime initialization hook * InstrProfilingRuntime.o if it is linked in. Both user specified * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE Index: compiler-rt/trunk/test/profile/instrprof-path.c =================================================================== --- compiler-rt/trunk/test/profile/instrprof-path.c +++ compiler-rt/trunk/test/profile/instrprof-path.c @@ -0,0 +1,39 @@ +// RUN: %clang_pgogen -O2 -o %t.0 %s +// RUN: %clang_pgogen=%t.d1 -O2 -o %t.1 %s +// RUN: %clang_pgogen=%t.d1/%t.d2 -O2 -o %t.2 %s +// +// RUN: %run %t.0 "" +// RUN: env LLVM_PROFILE_FILE=%t.d1/default.profraw %run %t.0 %t.d1/ +// RUN: env LLVM_PROFILE_FILE=%t.d1/%t.d2/default.profraw %run %t.0 %t.d1/%t.d2/ +// RUN: %run %t.1 %t.d1/ +// RUN: %run %t.2 %t.d1/%t.d2/ +// RUN: %run %t.2 %t.d1/%t.d2/ %t.d1/%t.d2/%t.d3/blah.profraw %t.d1/%t.d2/%t.d3/ + +#include + +const char *__llvm_profile_get_path_prefix(); +void __llvm_profile_set_filanem(const char*); + +int main(int argc, const char *argv[]) { + int i; + const char *expected; + const char *prefix; + if (argc < 2) + return 1; + + expected = argv[1]; + prefix = __llvm_profile_get_path_prefix(); + + if (strcmp(prefix, expected)) + return 1; + + if (argc == 4) { + __llvm_profile_set_filename(argv[2]); + prefix = __llvm_profile_get_path_prefix(); + expected = argv[3]; + if (strcmp(prefix, expected)) + return 1; + } + + return 0; +}