diff options
author | Xinliang David Li <davidxl@google.com> | 2016-05-24 21:29:18 +0000 |
---|---|---|
committer | Xinliang David Li <davidxl@google.com> | 2016-05-24 21:29:18 +0000 |
commit | a0f78dd9c1b9699258bbd392412fad201d3865b0 (patch) | |
tree | a5389dbd86c981caf1391b807ef09251a94bd0a1 /lib/profile/InstrProfilingFile.c | |
parent | c79548625a1f07fc40f317c6c6d1f92dd750a2a3 (diff) |
[profile] clean up profile file handling code
Differentianl Revision: http://reviews.llvm.org/D20572
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@270617 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/profile/InstrProfilingFile.c')
-rw-r--r-- | lib/profile/InstrProfilingFile.c | 225 |
1 files changed, 138 insertions, 87 deletions
diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c index a27dd113a..12d145d9c 100644 --- a/lib/profile/InstrProfilingFile.c +++ b/lib/profile/InstrProfilingFile.c @@ -15,12 +15,26 @@ #include <stdlib.h> #include <string.h> #ifdef _MSC_VER -/* For _alloca */ +/* For _alloca. */ #include <malloc.h> #endif +#define MAX_PID_SIZE 16 +/* Data structure holding the result of parsed filename pattern. */ +typedef struct lprofFilename { + /* File name string possibly with %p or %h specifiers. */ + const char *FilenamePat; + char PidChars[MAX_PID_SIZE]; + char Hostname[COMPILER_RT_MAX_HOSTLEN]; + unsigned NumPids; + unsigned NumHosts; +} lprofFilename; + +lprofFilename lprofCurFilename = {0}; -#define UNCONST(ptr) ((void *)(uintptr_t)(ptr)) +int getpid(void); +static int getCurFilenameLength(); +static const char *getCurFilename(char *FilenameBuf); /* Return 1 if there is an error, otherwise return 0. */ static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, @@ -52,44 +66,40 @@ static void setupIOBuffer() { } } -static int writeFile(FILE *File) { - FreeHook = &free; - setupIOBuffer(); - return lprofWriteData(fileWriter, File, lprofGetVPDataReader()); -} - -static int writeFileWithName(const char *OutputName) { +/* Write profile data to file \c OutputName. */ +static int writeFile(const char *OutputName) { int RetVal; FILE *OutputFile; - if (!OutputName || !OutputName[0]) - return -1; /* Append to the file to support profiling multiple shared objects. */ OutputFile = fopen(OutputName, "ab"); if (!OutputFile) return -1; - RetVal = writeFile(OutputFile); + FreeHook = &free; + setupIOBuffer(); + RetVal = lprofWriteData(fileWriter, OutputFile, lprofGetVPDataReader()); fclose(OutputFile); return RetVal; } -COMPILER_RT_WEAK int __llvm_profile_OwnsFilename = 0; -COMPILER_RT_WEAK const char *__llvm_profile_CurrentFilename = NULL; - static void truncateCurrentFile(void) { const char *Filename; + char *FilenameBuf; FILE *File; + int Length; - Filename = __llvm_profile_CurrentFilename; - if (!Filename || !Filename[0]) + Length = getCurFilenameLength(); + FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); + Filename = getCurFilename(FilenameBuf); + if (!Filename) return; /* Create the directory holding the file, if needed. */ if (strchr(Filename, '/') || strchr(Filename, '\\')) { - char *Copy = (char *)COMPILER_RT_ALLOCA(strlen(Filename) + 1); - strcpy(Copy, Filename); + char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1); + strncpy(Copy, Filename, Length + 1); __llvm_profile_recursive_mkdir(Copy); } @@ -100,88 +110,119 @@ static void truncateCurrentFile(void) { fclose(File); } -static void setFilename(const char *Filename, int OwnsFilename) { +/* Set the result of the file name parsing. If \p FilenamePat pattern is seen + * the first time, also truncate the file associated with that name. + */ +static void setFilename(const char *FilenamePat, const char *PidStr, + unsigned NumPids, const char *HostStr, + unsigned NumHosts) { /* Check if this is a new filename and therefore needs truncation. */ - int NewFile = !__llvm_profile_CurrentFilename || - (Filename && strcmp(Filename, __llvm_profile_CurrentFilename)); - if (__llvm_profile_OwnsFilename) - free(UNCONST(__llvm_profile_CurrentFilename)); - - __llvm_profile_CurrentFilename = Filename; - __llvm_profile_OwnsFilename = OwnsFilename; + int NewFile = + !lprofCurFilename.FilenamePat || + (FilenamePat && strcmp(FilenamePat, lprofCurFilename.FilenamePat)); + + lprofCurFilename.FilenamePat = FilenamePat; + lprofCurFilename.NumPids = NumPids; + if (NumPids) + strncpy(lprofCurFilename.PidChars, PidStr, MAX_PID_SIZE); + lprofCurFilename.NumHosts = NumHosts; + if (NumHosts) + strncpy(lprofCurFilename.Hostname, HostStr, COMPILER_RT_MAX_HOSTLEN); /* If not a new file, append to support profiling multiple shared objects. */ if (NewFile) truncateCurrentFile(); } -static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); } +static void resetFilenameToDefault(void) { + setFilename("default.profraw", 0, 0, 0, 0); +} -int getpid(void); -static int setFilenamePossiblyWithPid(const char *Filename) { -#define MAX_PID_SIZE 16 - char PidChars[MAX_PID_SIZE] = {0}; - int NumPids = 0, PidLength = 0, NumHosts = 0, HostNameLength = 0; - char *Allocated; - int I, J; +/* Parses the pattern string \p FilenamePat and store the result to + * lprofcurFilename structure. */ +static int parseFilenamePattern(const char *FilenamePat) { + int NumPids = 0, NumHosts = 0, I; + char PidChars[MAX_PID_SIZE]; char Hostname[COMPILER_RT_MAX_HOSTLEN]; - /* Reset filename on NULL, except with env var which is checked by caller. */ - if (!Filename) { - resetFilenameToDefault(); - return 0; - } - /* Check the filename for "%p", which indicates a pid-substitution. */ - for (I = 0; Filename[I]; ++I) - if (Filename[I] == '%') { - if (Filename[++I] == 'p') { + for (I = 0; FilenamePat[I]; ++I) + if (FilenamePat[I] == '%') { + if (FilenamePat[++I] == 'p') { if (!NumPids++) { - PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()); - if (PidLength <= 0) + if (snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()) <= 0) { + PROF_WARN( + "Unable to parse filename pattern %s. Using the default name.", + FilenamePat); return -1; + } } - } else if (Filename[I] == 'h') { + } else if (FilenamePat[I] == 'h') { if (!NumHosts++) - if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) + if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) { + PROF_WARN( + "Unable to parse filename pattern %s. Using the default name.", + FilenamePat); return -1; - HostNameLength = strlen(Hostname); + } } } - if (!(NumPids || NumHosts)) { - setFilename(Filename, 0); + setFilename(FilenamePat, PidChars, NumPids, Hostname, NumHosts); + return 0; +} + +/* Return buffer length that is required to store the current profile + * filename with PID and hostname substitutions. */ +static int getCurFilenameLength() { + if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) return 0; - } - /* Allocate enough space for the substituted filename. */ - Allocated = malloc(I + NumPids*(PidLength - 2) + - NumHosts*(HostNameLength - 2) + 1); - if (!Allocated) - return -1; + if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts)) + return strlen(lprofCurFilename.FilenamePat); + + return strlen(lprofCurFilename.FilenamePat) + + lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) + + lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2); +} +/* Return the pointer to the current profile file name (after substituting + * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer + * to store the resulting filename. If no substitution is needed, the + * current filename pattern string is directly returned. */ +static const char *getCurFilename(char *FilenameBuf) { + int I, J, PidLength, HostNameLength; + const char *FilenamePat = lprofCurFilename.FilenamePat; + + if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) + return 0; + + if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts)) + return lprofCurFilename.FilenamePat; + + PidLength = strlen(lprofCurFilename.PidChars); + HostNameLength = strlen(lprofCurFilename.Hostname); /* Construct the new filename. */ - for (I = 0, J = 0; Filename[I]; ++I) - if (Filename[I] == '%') { - if (Filename[++I] == 'p') { - memcpy(Allocated + J, PidChars, PidLength); + for (I = 0, J = 0; FilenamePat[I]; ++I) + if (FilenamePat[I] == '%') { + if (FilenamePat[++I] == 'p') { + memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength); J += PidLength; - } - else if (Filename[I] == 'h') { - memcpy(Allocated + J, Hostname, HostNameLength); + } else if (FilenamePat[I] == 'h') { + memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength); J += HostNameLength; } /* Drop any unknown substitutions. */ } else - Allocated[J++] = Filename[I]; - Allocated[J] = 0; + FilenameBuf[J++] = FilenamePat[I]; + FilenameBuf[J] = 0; - /* Use the computed name. */ - setFilename(Allocated, 1); - return 0; + return FilenameBuf; } -static const char *getFilenameFromEnv(void) { +/* Returns the pointer to the environment variable + * string. Returns null if the env var is not set. */ +static const char *getFilenamePatFromEnv(void) { const char *Filename = getenv("LLVM_PROFILE_FILE"); if (!Filename || !Filename[0]) return 0; @@ -194,14 +235,14 @@ static const char *getFilenameFromEnv(void) { * environment variable can override this default value. */ COMPILER_RT_VISIBILITY void __llvm_profile_initialize_file(void) { - const char *Filename; + const char *FilenamePat; /* Check if the filename has been initialized. */ - if (__llvm_profile_CurrentFilename) + if (lprofCurFilename.FilenamePat) return; /* Detect the filename and truncate. */ - Filename = getFilenameFromEnv(); - if (!Filename || setFilenamePossiblyWithPid(Filename)) + FilenamePat = getFilenamePatFromEnv(); + if (!FilenamePat || parseFilenamePattern(FilenamePat)) resetFilenameToDefault(); } @@ -210,32 +251,43 @@ void __llvm_profile_initialize_file(void) { * and command line option -fprofile-instr-generate=<profile_name>. */ COMPILER_RT_VISIBILITY -void __llvm_profile_set_filename(const char *Filename) { - setFilenamePossiblyWithPid(Filename); +void __llvm_profile_set_filename(const char *FilenamePat) { + if (!FilenamePat || parseFilenamePattern(FilenamePat)) + resetFilenameToDefault(); } -/* +/* * This API is invoked by the global initializers emitted by Clang/LLVM when * -fprofile-instr-generate=<..> is specified (vs -fprofile-instr-generate * without an argument). This option has lower precedence than the * LLVM_PROFILE_FILE environment variable. */ COMPILER_RT_VISIBILITY -void __llvm_profile_override_default_filename(const char *Filename) { +void __llvm_profile_override_default_filename(const char *FilenamePat) { /* If the env var is set, skip setting filename from argument. */ - const char *Env_Filename = getFilenameFromEnv(); + const char *Env_Filename = getFilenamePatFromEnv(); if (Env_Filename) return; - setFilenamePossiblyWithPid(Filename); + if (!FilenamePat || parseFilenamePattern(FilenamePat)) + resetFilenameToDefault(); } +/* The public API for writing profile data into the file with name + * set by previous calls to __llvm_profile_set_filename or + * __llvm_profile_override_default_filename or + * __llvm_profile_initialize_file. */ COMPILER_RT_VISIBILITY int __llvm_profile_write_file(void) { - int rc; + int rc, Length; + const char *Filename; + char *FilenameBuf; + + Length = getCurFilenameLength(); + FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); + Filename = getCurFilename(FilenameBuf); - GetEnvHook = &getenv; /* Check the filename. */ - if (!__llvm_profile_CurrentFilename) { + if (!Filename) { PROF_ERR("Failed to write file : %s\n", "Filename not set"); return -1; } @@ -249,11 +301,10 @@ int __llvm_profile_write_file(void) { return -1; } - /* Write the file. */ - rc = writeFileWithName(__llvm_profile_CurrentFilename); + /* Write profile data to the file. */ + rc = writeFile(Filename); if (rc) - PROF_ERR("Failed to write file \"%s\": %s\n", - __llvm_profile_CurrentFilename, strerror(errno)); + PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); return rc; } |