[profile] Add %t LLVM_PROFILE_FILE option to substitute $TMPDIR

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
This commit is contained in:
Vedant Kumar 2020-09-08 14:45:41 -07:00
parent 2d128b04d9
commit 62c372770d
3 changed files with 46 additions and 6 deletions

View 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

View 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;

View File

@ -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; }