[profile] Add %t LLVM_PROFILE_FILE option to substitute $TMPDIR
authorVedant Kumar <vsk@apple.com>
Tue, 8 Sep 2020 21:45:41 +0000 (14:45 -0700)
committerVedant Kumar <vsk@apple.com>
Fri, 25 Sep 2020 16:39:40 +0000 (09:39 -0700)
Add support for expanding the %t filename specifier in LLVM_PROFILE_FILE
to the TMPDIR environment variable. This is supported on all platforms.

On Darwin, TMPDIR is used to specify a temporary application-specific
scratch directory. When testing apps on remote devices, it can be
challenging for the host device to determine the correct TMPDIR, so it's
helpful to have the runtime do this work.

rdar://68524185

Differential Revision: https://reviews.llvm.org/D87332

clang/docs/SourceBasedCodeCoverage.rst
compiler-rt/lib/profile/InstrProfilingFile.c
compiler-rt/test/profile/instrprof-tmpdir.c [new file with mode: 0644]

index 0e9c364..f5b3d05 100644 (file)
@@ -79,6 +79,9 @@ directory structure will be created.  Additionally, the following special
 
 * "%h" expands out to the hostname of the machine running the program.
 
+* "%t" expands out to the value of the ``TMPDIR`` environment variable. On
+  Darwin, this is typically set to a temporary scratch directory.
+
 * "%Nm" expands out to the instrumented binary's signature. When this pattern
   is specified, the runtime creates a pool of N raw profiles which are used for
   on-line profile merging. The runtime takes care of selecting a raw profile
index 8c7bb0c..b43f917 100644 (file)
@@ -72,6 +72,7 @@ typedef struct lprofFilename {
   unsigned OwnsFilenamePat;
   const char *ProfilePathPrefix;
   char PidChars[MAX_PID_SIZE];
+  char *TmpDir;
   char Hostname[COMPILER_RT_MAX_HOSTLEN];
   unsigned NumPids;
   unsigned NumHosts;
@@ -86,8 +87,8 @@ typedef struct lprofFilename {
   ProfileNameSpecifier PNS;
 } lprofFilename;
 
-static lprofFilename lprofCurFilename = {0, 0, 0, {0},        {0},
-                                         0, 0, 0, PNS_unknown};
+static lprofFilename lprofCurFilename = {0,   0, 0, {0}, NULL,
+                                         {0}, 0, 0, 0,   PNS_unknown};
 
 static int ProfileMergeRequested = 0;
 static int isProfileMergeRequested() { return ProfileMergeRequested; }
@@ -744,6 +745,14 @@ static int parseFilenamePattern(const char *FilenamePat,
                       FilenamePat);
             return -1;
           }
+      } else if (FilenamePat[I] == 't') {
+        lprofCurFilename.TmpDir = getenv("TMPDIR");
+        if (!lprofCurFilename.TmpDir) {
+          PROF_WARN("Unable to get the TMPDIR environment variable, referenced "
+                    "in %s. Using the default path.",
+                    FilenamePat);
+          return -1;
+        }
       } else if (FilenamePat[I] == 'c') {
         if (__llvm_profile_is_continuous_mode_enabled()) {
           PROF_WARN("%%c specifier can only be specified once in %s.\n",
@@ -827,12 +836,13 @@ static int getCurFilenameLength() {
     return 0;
 
   if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
-        lprofCurFilename.MergePoolSize))
+        lprofCurFilename.TmpDir || lprofCurFilename.MergePoolSize))
     return strlen(lprofCurFilename.FilenamePat);
 
   Len = strlen(lprofCurFilename.FilenamePat) +
         lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) +
-        lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2);
+        lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2) +
+        (lprofCurFilename.TmpDir ? (strlen(lprofCurFilename.TmpDir) - 1) : 0);
   if (lprofCurFilename.MergePoolSize)
     Len += SIGLEN;
   return Len;
@@ -844,14 +854,14 @@ static int getCurFilenameLength() {
  * current filename pattern string is directly returned, unless ForceUseBuf
  * is enabled. */
 static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) {
-  int I, J, PidLength, HostNameLength, FilenamePatLength;
+  int I, J, PidLength, HostNameLength, TmpDirLength, FilenamePatLength;
   const char *FilenamePat = lprofCurFilename.FilenamePat;
 
   if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
     return 0;
 
   if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
-        lprofCurFilename.MergePoolSize ||
+        lprofCurFilename.TmpDir || lprofCurFilename.MergePoolSize ||
         __llvm_profile_is_continuous_mode_enabled())) {
     if (!ForceUseBuf)
       return lprofCurFilename.FilenamePat;
@@ -864,6 +874,7 @@ static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) {
 
   PidLength = strlen(lprofCurFilename.PidChars);
   HostNameLength = strlen(lprofCurFilename.Hostname);
+  TmpDirLength = lprofCurFilename.TmpDir ? strlen(lprofCurFilename.TmpDir) : 0;
   /* Construct the new filename. */
   for (I = 0, J = 0; FilenamePat[I]; ++I)
     if (FilenamePat[I] == '%') {
@@ -873,6 +884,10 @@ static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) {
       } else if (FilenamePat[I] == 'h') {
         memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength);
         J += HostNameLength;
+      } else if (FilenamePat[I] == 't') {
+        memcpy(FilenameBuf + J, lprofCurFilename.TmpDir, TmpDirLength);
+        FilenameBuf[J + TmpDirLength] = DIR_SEPARATOR;
+        J += TmpDirLength + 1;
       } else {
         if (!getMergePoolSize(FilenamePat, &I))
           continue;
diff --git a/compiler-rt/test/profile/instrprof-tmpdir.c b/compiler-rt/test/profile/instrprof-tmpdir.c
new file mode 100644 (file)
index 0000000..0363138
--- /dev/null
@@ -0,0 +1,22 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: cd %t
+// RUN: %clang_profgen -o %t/binary %s
+//
+// Check that a dir separator is appended after %t is subsituted.
+// RUN: env TMPDIR="%t" LLVM_PROFILE_FILE="%%traw1.profraw" %run ./binary
+// RUN: llvm-profdata show ./raw1.profraw | FileCheck %s -check-prefix TMPDIR
+//
+// Check that substitution works even if a redundant dir separator is added.
+// RUN: env TMPDIR="%t" LLVM_PROFILE_FILE="%%t/raw2.profraw" %run ./binary
+// RUN: llvm-profdata show ./raw2.profraw | FileCheck %s -check-prefix TMPDIR
+//
+// Check that we fall back to the default path if TMPDIR is missing.
+// RUN: env -u TMPDIR LLVM_PROFILE_FILE="%%t/raw3.profraw" %run ./binary 2>&1 | FileCheck %s -check-prefix MISSING
+// RUN: llvm-profdata show ./default.profraw | FileCheck %s -check-prefix TMPDIR
+
+// TMPDIR: Maximum function count: 1
+
+// MISSING: Unable to get the TMPDIR environment variable, referenced in {{.*}}raw3.profraw. Using the default path.
+
+int main() { return 0; }