[compiler-rt] r270617 - [profile] clean up profile file handling code

Xinliang David Li via llvm-commits llvm-commits at lists.llvm.org
Tue May 24 14:29:19 PDT 2016


Author: davidxl
Date: Tue May 24 16:29:18 2016
New Revision: 270617

URL: http://llvm.org/viewvc/llvm-project?rev=270617&view=rev
Log:
[profile] clean up profile file handling code


Differentianl Revision: http://reviews.llvm.org/D20572


Modified:
    compiler-rt/trunk/lib/profile/InstrProfiling.h
    compiler-rt/trunk/lib/profile/InstrProfilingFile.c

Modified: compiler-rt/trunk/lib/profile/InstrProfiling.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/profile/InstrProfiling.h?rev=270617&r1=270616&r2=270617&view=diff
==============================================================================
--- compiler-rt/trunk/lib/profile/InstrProfiling.h (original)
+++ compiler-rt/trunk/lib/profile/InstrProfiling.h Tue May 24 16:29:18 2016
@@ -166,13 +166,7 @@ uint64_t __llvm_profile_get_data_size(co
  * affect runtime initialization decision of the main program.
  */
 COMPILER_RT_VISIBILITY extern int __llvm_profile_runtime;
-/*!
- * This variable is defined in InstrProfilingFile.c. Its visibility is
- * not hidden so that instrumented shared libraries and the main program
- * can share the raw data file with the same name.
- */
-extern int __llvm_profile_OwnsFilename;
-extern const char *__llvm_profile_CurrentFilename;
+
 /*!
  * This variable is defined in InstrProfiling.c. Its main purpose is to
  * encode the raw profile version value and other format related information

Modified: compiler-rt/trunk/lib/profile/InstrProfilingFile.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/profile/InstrProfilingFile.c?rev=270617&r1=270616&r2=270617&view=diff
==============================================================================
--- compiler-rt/trunk/lib/profile/InstrProfilingFile.c (original)
+++ compiler-rt/trunk/lib/profile/InstrProfilingFile.c Tue May 24 16:29:18 2016
@@ -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;
 
-#define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
+lprofFilename lprofCurFilename = {0};
+
+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(vo
  * 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;
 }
 




More information about the llvm-commits mailing list