[PGO] Update ldc-profdata-3.9 and profile-rt-39 to svn r273081

This commit is contained in:
Johan Engelen 2016-06-20 17:39:46 +02:00
parent 176961f325
commit 21c2c6dd4b
14 changed files with 723 additions and 198 deletions

View file

@ -57,6 +57,12 @@
* *
\*===----------------------------------------------------------------------===*/ \*===----------------------------------------------------------------------===*/
/* Functions marked with INSTR_PROF_VISIBILITY must have hidden visibility in
* the compiler runtime. */
#ifndef INSTR_PROF_VISIBILITY
#define INSTR_PROF_VISIBILITY
#endif
/* INSTR_PROF_DATA start. */ /* INSTR_PROF_DATA start. */
/* Definition of member fields of the per-function control structure. */ /* Definition of member fields of the per-function control structure. */
#ifndef INSTR_PROF_DATA #ifndef INSTR_PROF_DATA
@ -80,7 +86,7 @@ INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt64PtrTy(Ctx), CounterPtr, \
INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), FunctionPointer, \ INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt8PtrTy(Ctx), FunctionPointer, \
FunctionAddr) FunctionAddr)
INSTR_PROF_DATA(IntPtrT, llvm::Type::getInt8PtrTy(Ctx), Values, \ INSTR_PROF_DATA(IntPtrT, llvm::Type::getInt8PtrTy(Ctx), Values, \
ConstantPointerNull::get(Int8PtrTy)) ValuesPtrExpr)
INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NumCounters, \ INSTR_PROF_DATA(const uint32_t, llvm::Type::getInt32Ty(Ctx), NumCounters, \
ConstantInt::get(llvm::Type::getInt32Ty(Ctx), NumCounters)) ConstantInt::get(llvm::Type::getInt32Ty(Ctx), NumCounters))
INSTR_PROF_DATA(const uint16_t, Int16ArrayTy, NumValueSites[IPVK_Last+1], \ INSTR_PROF_DATA(const uint16_t, Int16ArrayTy, NumValueSites[IPVK_Last+1], \
@ -387,11 +393,14 @@ typedef struct ValueProfRecordClosure {
ValueProfData *(*AllocValueProfData)(size_t TotalSizeInBytes); ValueProfData *(*AllocValueProfData)(size_t TotalSizeInBytes);
} ValueProfRecordClosure; } ValueProfRecordClosure;
INSTR_PROF_VISIBILITY ValueProfRecord *
ValueProfRecord *getFirstValueProfRecord(ValueProfData *VPD); getFirstValueProfRecord(ValueProfData *VPD);
ValueProfRecord *getValueProfRecordNext(ValueProfRecord *VPR); INSTR_PROF_VISIBILITY ValueProfRecord *
InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *VPR); getValueProfRecordNext(ValueProfRecord *VPR);
uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites); INSTR_PROF_VISIBILITY InstrProfValueData *
getValueProfRecordValueData(ValueProfRecord *VPR);
INSTR_PROF_VISIBILITY uint32_t
getValueProfRecordHeaderSize(uint32_t NumValueSites);
#undef INSTR_PROF_VALUE_PROF_DATA #undef INSTR_PROF_VALUE_PROF_DATA
#endif /* INSTR_PROF_VALUE_PROF_DATA */ #endif /* INSTR_PROF_VALUE_PROF_DATA */
@ -415,7 +424,7 @@ uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites);
* \brief Return the \c ValueProfRecord header size including the * \brief Return the \c ValueProfRecord header size including the
* padding bytes. * padding bytes.
*/ */
INSTR_PROF_INLINE INSTR_PROF_VISIBILITY INSTR_PROF_INLINE
uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) { uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) {
uint32_t Size = offsetof(ValueProfRecord, SiteCountArray) + uint32_t Size = offsetof(ValueProfRecord, SiteCountArray) +
sizeof(uint8_t) * NumValueSites; sizeof(uint8_t) * NumValueSites;
@ -428,7 +437,7 @@ uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) {
* \brief Return the total size of the value profile record including the * \brief Return the total size of the value profile record including the
* header and the value data. * header and the value data.
*/ */
INSTR_PROF_INLINE INSTR_PROF_VISIBILITY INSTR_PROF_INLINE
uint32_t getValueProfRecordSize(uint32_t NumValueSites, uint32_t getValueProfRecordSize(uint32_t NumValueSites,
uint32_t NumValueData) { uint32_t NumValueData) {
return getValueProfRecordHeaderSize(NumValueSites) + return getValueProfRecordHeaderSize(NumValueSites) +
@ -438,7 +447,7 @@ uint32_t getValueProfRecordSize(uint32_t NumValueSites,
/*! /*!
* \brief Return the pointer to the start of value data array. * \brief Return the pointer to the start of value data array.
*/ */
INSTR_PROF_INLINE INSTR_PROF_VISIBILITY INSTR_PROF_INLINE
InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) { InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) {
return (InstrProfValueData *)((char *)This + getValueProfRecordHeaderSize( return (InstrProfValueData *)((char *)This + getValueProfRecordHeaderSize(
This->NumValueSites)); This->NumValueSites));
@ -447,7 +456,7 @@ InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) {
/*! /*!
* \brief Return the total number of value data for \c This record. * \brief Return the total number of value data for \c This record.
*/ */
INSTR_PROF_INLINE INSTR_PROF_VISIBILITY INSTR_PROF_INLINE
uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) { uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) {
uint32_t NumValueData = 0; uint32_t NumValueData = 0;
uint32_t I; uint32_t I;
@ -459,7 +468,7 @@ uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) {
/*! /*!
* \brief Use this method to advance to the next \c This \c ValueProfRecord. * \brief Use this method to advance to the next \c This \c ValueProfRecord.
*/ */
INSTR_PROF_INLINE INSTR_PROF_VISIBILITY INSTR_PROF_INLINE
ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) { ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) {
uint32_t NumValueData = getValueProfRecordNumValueData(This); uint32_t NumValueData = getValueProfRecordNumValueData(This);
return (ValueProfRecord *)((char *)This + return (ValueProfRecord *)((char *)This +
@ -470,7 +479,7 @@ ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) {
/*! /*!
* \brief Return the first \c ValueProfRecord instance. * \brief Return the first \c ValueProfRecord instance.
*/ */
INSTR_PROF_INLINE INSTR_PROF_VISIBILITY INSTR_PROF_INLINE
ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) { ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) {
return (ValueProfRecord *)((char *)This + sizeof(ValueProfData)); return (ValueProfRecord *)((char *)This + sizeof(ValueProfData));
} }
@ -481,7 +490,8 @@ ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) {
* Return the total size in bytes of the on-disk value profile data * Return the total size in bytes of the on-disk value profile data
* given the data stored in Record. * given the data stored in Record.
*/ */
uint32_t getValueProfDataSize(ValueProfRecordClosure *Closure) { INSTR_PROF_VISIBILITY uint32_t
getValueProfDataSize(ValueProfRecordClosure *Closure) {
uint32_t Kind; uint32_t Kind;
uint32_t TotalSize = sizeof(ValueProfData); uint32_t TotalSize = sizeof(ValueProfData);
const void *Record = Closure->Record; const void *Record = Closure->Record;
@ -500,9 +510,10 @@ uint32_t getValueProfDataSize(ValueProfRecordClosure *Closure) {
* Extract value profile data of a function for the profile kind \c ValueKind * Extract value profile data of a function for the profile kind \c ValueKind
* from the \c Closure and serialize the data into \c This record instance. * from the \c Closure and serialize the data into \c This record instance.
*/ */
void serializeValueProfRecordFrom(ValueProfRecord *This, INSTR_PROF_VISIBILITY void
ValueProfRecordClosure *Closure, serializeValueProfRecordFrom(ValueProfRecord *This,
uint32_t ValueKind, uint32_t NumValueSites) { ValueProfRecordClosure *Closure,
uint32_t ValueKind, uint32_t NumValueSites) {
uint32_t S; uint32_t S;
const void *Record = Closure->Record; const void *Record = Closure->Record;
This->Kind = ValueKind; This->Kind = ValueKind;
@ -524,8 +535,9 @@ void serializeValueProfRecordFrom(ValueProfRecord *This,
* DstData is not null, the caller is expected to set the TotalSize * DstData is not null, the caller is expected to set the TotalSize
* in DstData. * in DstData.
*/ */
ValueProfData *serializeValueProfDataFrom(ValueProfRecordClosure *Closure, INSTR_PROF_VISIBILITY ValueProfData *
ValueProfData *DstData) { serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
ValueProfData *DstData) {
uint32_t Kind; uint32_t Kind;
uint32_t TotalSize = uint32_t TotalSize =
DstData ? DstData->TotalSize : getValueProfDataSize(Closure); DstData ? DstData->TotalSize : getValueProfDataSize(Closure);
@ -597,6 +609,12 @@ ValueProfData *serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
#define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data #define INSTR_PROF_DATA_SECT_NAME __llvm_prf_data
#define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names #define INSTR_PROF_NAME_SECT_NAME __llvm_prf_names
#define INSTR_PROF_CNTS_SECT_NAME __llvm_prf_cnts #define INSTR_PROF_CNTS_SECT_NAME __llvm_prf_cnts
/* Array of pointers. Each pointer points to a list
* of value nodes associated with one value site.
*/
#define INSTR_PROF_VALS_SECT_NAME __llvm_prf_vals
/* Value profile nodes section. */
#define INSTR_PROF_VNODES_SECT_NAME __llvm_prf_vnds
#define INSTR_PROF_COVMAP_SECT_NAME __llvm_covmap #define INSTR_PROF_COVMAP_SECT_NAME __llvm_covmap
#define INSTR_PROF_DATA_SECT_NAME_STR \ #define INSTR_PROF_DATA_SECT_NAME_STR \
@ -607,6 +625,10 @@ ValueProfData *serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME) INSTR_PROF_QUOTE(INSTR_PROF_CNTS_SECT_NAME)
#define INSTR_PROF_COVMAP_SECT_NAME_STR \ #define INSTR_PROF_COVMAP_SECT_NAME_STR \
INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_SECT_NAME) INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_SECT_NAME)
#define INSTR_PROF_VALS_SECT_NAME_STR \
INSTR_PROF_QUOTE(INSTR_PROF_VALS_SECT_NAME)
#define INSTR_PROF_VNODES_SECT_NAME_STR \
INSTR_PROF_QUOTE(INSTR_PROF_VNODES_SECT_NAME)
/* Macros to define start/stop section symbol for a given /* Macros to define start/stop section symbol for a given
* section on Linux. For instance * section on Linux. For instance

View file

@ -11,6 +11,8 @@
#define PROFILE_INSTRPROFILING_H_ #define PROFILE_INSTRPROFILING_H_
#include "InstrProfilingPort.h" #include "InstrProfilingPort.h"
#define INSTR_PROF_VISIBILITY COMPILER_RT_VISIBILITY
#include "InstrProfData.inc" #include "InstrProfData.inc"
enum ValueKind { enum ValueKind {
@ -61,6 +63,8 @@ const char *__llvm_profile_begin_names(void);
const char *__llvm_profile_end_names(void); const char *__llvm_profile_end_names(void);
uint64_t *__llvm_profile_begin_counters(void); uint64_t *__llvm_profile_begin_counters(void);
uint64_t *__llvm_profile_end_counters(void); uint64_t *__llvm_profile_end_counters(void);
ValueProfNode *__llvm_profile_begin_vnodes();
ValueProfNode *__llvm_profile_end_vnodes();
/*! /*!
* \brief Clear profile counters to zero. * \brief Clear profile counters to zero.
@ -164,13 +168,7 @@ uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin,
* affect runtime initialization decision of the main program. * affect runtime initialization decision of the main program.
*/ */
COMPILER_RT_VISIBILITY extern int __llvm_profile_runtime; 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 * This variable is defined in InstrProfiling.c. Its main purpose is to
* encode the raw profile version value and other format related information * encode the raw profile version value and other format related information

View file

@ -15,12 +15,75 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifdef _MSC_VER #ifdef _MSC_VER
/* For _alloca */ /* For _alloca. */
#include <malloc.h> #include <malloc.h>
#endif #endif
#if defined(_WIN32)
#include "WindowsMMap.h"
/* For _chsize_s */
#include <io.h>
#else
#include <sys/file.h>
#include <sys/mman.h>
#include <unistd.h>
#if defined(__linux__)
#include <sys/types.h>
#endif
#endif
/* From where is profile name specified.
* The order the enumerators define their
* precedence. Re-order them may lead to
* runtime behavior change. */
typedef enum ProfileNameSpecifier {
PNS_unknown = 0,
PNS_default,
PNS_command_line,
PNS_environment,
PNS_runtime_api
} ProfileNameSpecifier;
#define UNCONST(ptr) ((void *)(uintptr_t)(ptr)) static const char *getPNSStr(ProfileNameSpecifier PNS) {
switch (PNS) {
case PNS_default:
return "default setting";
case PNS_command_line:
return "command line";
case PNS_environment:
return "environment variable";
case PNS_runtime_api:
return "runtime API";
default:
return "Unknown";
}
}
#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;
/* When in-process merging is enabled, this parameter specifies
* the total number of profile data files shared by all the processes
* spawned from the same binary. By default the value is 1. If merging
* is not enabled, its value should be 0. This parameter is specified
* by the %[0-9]m specifier. For instance %2m enables merging using
* 2 profile data files. %1m is equivalent to %m. Also %m specifier
* can only appear once at the end of the name pattern. */
unsigned MergePoolSize;
ProfileNameSpecifier PNS;
} lprofFilename;
lprofFilename lprofCurFilename = {0, {0}, {0}, 0, 0, 0, PNS_unknown};
int getpid(void);
static int getCurFilenameLength();
static const char *getCurFilename(char *FilenameBuf);
static unsigned doMerging() { return lprofCurFilename.MergePoolSize; }
/* Return 1 if there is an error, otherwise return 0. */ /* Return 1 if there is an error, otherwise return 0. */
static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
@ -52,44 +115,123 @@ static void setupIOBuffer() {
} }
} }
static int writeFile(FILE *File) { /* Read profile data in \c ProfileFile and merge with in-memory
FreeHook = &free; profile counters. Returns -1 if there is fatal error, otheriwse
setupIOBuffer(); 0 is returned.
return lprofWriteData(fileWriter, File, lprofGetVPDataReader()); */
static int doProfileMerging(FILE *ProfileFile) {
uint64_t ProfileFileSize;
char *ProfileBuffer;
if (fseek(ProfileFile, 0L, SEEK_END) == -1) {
PROF_ERR("Unable to merge profile data, unable to get size: %s\n",
strerror(errno));
return -1;
}
ProfileFileSize = ftell(ProfileFile);
/* Restore file offset. */
if (fseek(ProfileFile, 0L, SEEK_SET) == -1) {
PROF_ERR("Unable to merge profile data, unable to rewind: %s\n",
strerror(errno));
return -1;
}
/* Nothing to merge. */
if (ProfileFileSize < sizeof(__llvm_profile_header)) {
if (ProfileFileSize)
PROF_WARN("Unable to merge profile data: %s\n",
"source profile file is too small.");
return 0;
}
ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE,
fileno(ProfileFile), 0);
if (ProfileBuffer == MAP_FAILED) {
PROF_ERR("Unable to merge profile data, mmap failed: %s\n",
strerror(errno));
return -1;
}
if (__llvm_profile_check_compatibility(ProfileBuffer, ProfileFileSize)) {
(void)munmap(ProfileBuffer, ProfileFileSize);
PROF_WARN("Unable to merge profile data: %s\n",
"source profile file is not compatible.");
return 0;
}
/* Now start merging */
__llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize);
(void)munmap(ProfileBuffer, ProfileFileSize);
return 0;
} }
static int writeFileWithName(const char *OutputName) { /* Open the profile data for merging. It opens the file in r+b mode with
* file locking. If the file has content which is compatible with the
* current process, it also reads in the profile data in the file and merge
* it with in-memory counters. After the profile data is merged in memory,
* the original profile data is truncated and gets ready for the profile
* dumper. With profile merging enabled, each executable as well as any of
* its instrumented shared libraries dump profile data into their own data file.
*/
static FILE *openFileForMerging(const char *ProfileFileName) {
FILE *ProfileFile;
int rc;
ProfileFile = lprofOpenFileEx(ProfileFileName);
if (!ProfileFile)
return NULL;
rc = doProfileMerging(ProfileFile);
if (rc || COMPILER_RT_FTRUNCATE(ProfileFile, 0L) ||
fseek(ProfileFile, 0L, SEEK_SET) == -1) {
PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName,
strerror(errno));
fclose(ProfileFile);
return NULL;
}
fseek(ProfileFile, 0L, SEEK_SET);
return ProfileFile;
}
/* Write profile data to file \c OutputName. */
static int writeFile(const char *OutputName) {
int RetVal; int RetVal;
FILE *OutputFile; FILE *OutputFile;
if (!OutputName || !OutputName[0])
return -1;
/* Append to the file to support profiling multiple shared objects. */ if (!doMerging())
OutputFile = fopen(OutputName, "ab"); OutputFile = fopen(OutputName, "ab");
else
OutputFile = openFileForMerging(OutputName);
if (!OutputFile) if (!OutputFile)
return -1; return -1;
RetVal = writeFile(OutputFile); FreeHook = &free;
setupIOBuffer();
RetVal = lprofWriteData(fileWriter, OutputFile, lprofGetVPDataReader());
fclose(OutputFile); fclose(OutputFile);
return RetVal; return RetVal;
} }
COMPILER_RT_WEAK int __llvm_profile_OwnsFilename = 0;
COMPILER_RT_WEAK const char *__llvm_profile_CurrentFilename = NULL;
static void truncateCurrentFile(void) { static void truncateCurrentFile(void) {
const char *Filename; const char *Filename;
char *FilenameBuf;
FILE *File; FILE *File;
int Length;
Filename = __llvm_profile_CurrentFilename; Length = getCurFilenameLength();
if (!Filename || !Filename[0]) FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
Filename = getCurFilename(FilenameBuf);
if (!Filename)
return; return;
/* Create the directory holding the file, if needed. */ /* Create the directory holding the file, if needed. */
if (strchr(Filename, '/') || strchr(Filename, '\\')) { if (strchr(Filename, '/') || strchr(Filename, '\\')) {
char *Copy = (char *)COMPILER_RT_ALLOCA(strlen(Filename) + 1); char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1);
strcpy(Copy, Filename); strncpy(Copy, Filename, Length + 1);
__llvm_profile_recursive_mkdir(Copy); __llvm_profile_recursive_mkdir(Copy);
} }
@ -100,134 +242,237 @@ static void truncateCurrentFile(void) {
fclose(File); fclose(File);
} }
static void setFilename(const char *Filename, int OwnsFilename) { static const char *DefaultProfileName = "default.profraw";
/* Check if this is a new filename and therefore needs truncation. */ static void resetFilenameToDefault(void) {
int NewFile = !__llvm_profile_CurrentFilename || memset(&lprofCurFilename, 0, sizeof(lprofCurFilename));
(Filename && strcmp(Filename, __llvm_profile_CurrentFilename)); lprofCurFilename.FilenamePat = DefaultProfileName;
if (__llvm_profile_OwnsFilename) lprofCurFilename.PNS = PNS_default;
free(UNCONST(__llvm_profile_CurrentFilename));
__llvm_profile_CurrentFilename = Filename;
__llvm_profile_OwnsFilename = OwnsFilename;
/* If not a new file, append to support profiling multiple shared objects. */
if (NewFile)
truncateCurrentFile();
} }
static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); } static int containsMergeSpecifier(const char *FilenamePat, int I) {
return (FilenamePat[I] == 'm' ||
(FilenamePat[I] >= '1' && FilenamePat[I] <= '9' &&
/* If FilenamePat[I] is not '\0', the next byte is guaranteed
* to be in-bound as the string is null terminated. */
FilenamePat[I + 1] == 'm'));
}
int getpid(void); /* Parses the pattern string \p FilenamePat and stores the result to
static int setFilenamePossiblyWithPid(const char *Filename) { * lprofcurFilename structure. */
#define MAX_PID_SIZE 16 static int parseFilenamePattern(const char *FilenamePat) {
char PidChars[MAX_PID_SIZE] = {0}; int NumPids = 0, NumHosts = 0, I;
int NumPids = 0, PidLength = 0, NumHosts = 0, HostNameLength = 0; char *PidChars = &lprofCurFilename.PidChars[0];
char *Allocated; char *Hostname = &lprofCurFilename.Hostname[0];
int I, J; int MergingEnabled = 0;
char Hostname[COMPILER_RT_MAX_HOSTLEN];
/* Reset filename on NULL, except with env var which is checked by caller. */
if (!Filename) {
resetFilenameToDefault();
return 0;
}
lprofCurFilename.FilenamePat = FilenamePat;
/* Check the filename for "%p", which indicates a pid-substitution. */ /* Check the filename for "%p", which indicates a pid-substitution. */
for (I = 0; Filename[I]; ++I) for (I = 0; FilenamePat[I]; ++I)
if (Filename[I] == '%') { if (FilenamePat[I] == '%') {
if (Filename[++I] == 'p') { if (FilenamePat[++I] == 'p') {
if (!NumPids++) { if (!NumPids++) {
PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()); if (snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()) <= 0) {
if (PidLength <= 0) PROF_WARN(
"Unable to parse filename pattern %s. Using the default name.",
FilenamePat);
return -1; return -1;
}
} }
} else if (Filename[I] == 'h') { } else if (FilenamePat[I] == 'h') {
if (!NumHosts++) 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; return -1;
HostNameLength = strlen(Hostname); }
} else if (containsMergeSpecifier(FilenamePat, I)) {
if (MergingEnabled) {
PROF_WARN("%%m specifier can only be specified once in %s.\n",
FilenamePat);
return -1;
}
MergingEnabled = 1;
if (FilenamePat[I] == 'm')
lprofCurFilename.MergePoolSize = 1;
else {
lprofCurFilename.MergePoolSize = FilenamePat[I] - '0';
I++; /* advance to 'm' */
}
} }
} }
if (!(NumPids || NumHosts)) { lprofCurFilename.NumPids = NumPids;
setFilename(Filename, 0); lprofCurFilename.NumHosts = NumHosts;
return 0;
}
/* Allocate enough space for the substituted filename. */
Allocated = malloc(I + NumPids*(PidLength - 2) +
NumHosts*(HostNameLength - 2) + 1);
if (!Allocated)
return -1;
/* Construct the new filename. */
for (I = 0, J = 0; Filename[I]; ++I)
if (Filename[I] == '%') {
if (Filename[++I] == 'p') {
memcpy(Allocated + J, PidChars, PidLength);
J += PidLength;
}
else if (Filename[I] == 'h') {
memcpy(Allocated + J, Hostname, HostNameLength);
J += HostNameLength;
}
/* Drop any unknown substitutions. */
} else
Allocated[J++] = Filename[I];
Allocated[J] = 0;
/* Use the computed name. */
setFilename(Allocated, 1);
return 0; return 0;
} }
static int setFilenameFromEnvironment(void) { static void parseAndSetFilename(const char *FilenamePat,
const char *Filename = getenv("LLVM_PROFILE_FILE"); ProfileNameSpecifier PNS) {
if (!Filename || !Filename[0]) const char *OldFilenamePat = lprofCurFilename.FilenamePat;
return -1; ProfileNameSpecifier OldPNS = lprofCurFilename.PNS;
return setFilenamePossiblyWithPid(Filename); if (PNS < OldPNS)
}
static void setFilenameAutomatically(void) {
if (!setFilenameFromEnvironment())
return; return;
resetFilenameToDefault(); if (!FilenamePat)
FilenamePat = DefaultProfileName;
/* When -fprofile-instr-generate=<path> is specified on the
* command line, each module will be instrumented with runtime
* init call to __llvm_profile_init function which calls
* __llvm_profile_override_default_filename. In most of the cases,
* the path will be identical, so bypass the parsing completely.
*/
if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) {
lprofCurFilename.PNS = PNS;
return;
}
/* When PNS >= OldPNS, the last one wins. */
if (!FilenamePat || parseFilenamePattern(FilenamePat))
resetFilenameToDefault();
lprofCurFilename.PNS = PNS;
if (!OldFilenamePat) {
PROF_NOTE("Set profile file path to \"%s\" via %s.\n",
lprofCurFilename.FilenamePat, getPNSStr(PNS));
} else {
PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n",
OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat,
getPNSStr(PNS));
}
if (!lprofCurFilename.MergePoolSize)
truncateCurrentFile();
} }
/* Return buffer length that is required to store the current profile
* filename with PID and hostname substitutions. */
/* The length to hold uint64_t followed by 2 digit pool id including '_' */
#define SIGLEN 24
static int getCurFilenameLength() {
int Len;
if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
return 0;
if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
lprofCurFilename.MergePoolSize))
return strlen(lprofCurFilename.FilenamePat);
Len = strlen(lprofCurFilename.FilenamePat) +
lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) +
lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2);
if (lprofCurFilename.MergePoolSize)
Len += SIGLEN;
return Len;
}
/* 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 ||
lprofCurFilename.MergePoolSize))
return lprofCurFilename.FilenamePat;
PidLength = strlen(lprofCurFilename.PidChars);
HostNameLength = strlen(lprofCurFilename.Hostname);
/* Construct the new filename. */
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 (FilenamePat[I] == 'h') {
memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength);
J += HostNameLength;
} else if (containsMergeSpecifier(FilenamePat, I)) {
char LoadModuleSignature[SIGLEN];
int S;
int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize;
S = snprintf(LoadModuleSignature, SIGLEN, "%" PRIu64 "_%d",
lprofGetLoadModuleSignature(), ProfilePoolId);
if (S == -1 || S > SIGLEN)
S = SIGLEN;
memcpy(FilenameBuf + J, LoadModuleSignature, S);
J += S;
if (FilenamePat[I] != 'm')
I++;
}
/* Drop any unknown substitutions. */
} else
FilenameBuf[J++] = FilenamePat[I];
FilenameBuf[J] = 0;
return FilenameBuf;
}
/* 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;
return Filename;
}
/* 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
* environment variable can override this default value. */
COMPILER_RT_VISIBILITY COMPILER_RT_VISIBILITY
void __llvm_profile_initialize_file(void) { void __llvm_profile_initialize_file(void) {
/* Check if the filename has been initialized. */ const char *FilenamePat;
if (__llvm_profile_CurrentFilename)
return;
/* Detect the filename and truncate. */ FilenamePat = getFilenamePatFromEnv();
setFilenameAutomatically(); parseAndSetFilename(FilenamePat, FilenamePat ? PNS_environment : PNS_default);
} }
/* This API is directly called by the user application code. It has the
* highest precedence compared with LLVM_PROFILE_FILE environment variable
* and command line option -fprofile-instr-generate=<profile_name>.
*/
COMPILER_RT_VISIBILITY COMPILER_RT_VISIBILITY
void __llvm_profile_set_filename(const char *Filename) { void __llvm_profile_set_filename(const char *FilenamePat) {
setFilenamePossiblyWithPid(Filename); parseAndSetFilename(FilenamePat, PNS_runtime_api);
} }
/*
* 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 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. */ parseAndSetFilename(FilenamePat, PNS_command_line);
const char *Env_Filename = getenv("LLVM_PROFILE_FILE");
if (Env_Filename && Env_Filename[0])
return;
setFilenamePossiblyWithPid(Filename);
} }
/* 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 COMPILER_RT_VISIBILITY
int __llvm_profile_write_file(void) { 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. */ /* Check the filename. */
if (!__llvm_profile_CurrentFilename) { if (!Filename) {
PROF_ERR("Failed to write file : %s\n", "Filename not set"); PROF_ERR("Failed to write file : %s\n", "Filename not set");
return -1; return -1;
} }
@ -241,11 +486,10 @@ int __llvm_profile_write_file(void) {
return -1; return -1;
} }
/* Write the file. */ /* Write profile data to the file. */
rc = writeFileWithName(__llvm_profile_CurrentFilename); rc = writeFile(Filename);
if (rc) if (rc)
PROF_ERR("Failed to write file \"%s\": %s\n", PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
__llvm_profile_CurrentFilename, strerror(errno));
return rc; return rc;
} }

View file

@ -156,11 +156,21 @@ VPDataReaderType *lprofGetVPDataReader();
void lprofSetMaxValsPerSite(uint32_t MaxVals); void lprofSetMaxValsPerSite(uint32_t MaxVals);
void lprofSetupValueProfiler(); void lprofSetupValueProfiler();
/* Return the profile header 'signature' value associated with the current
* executable or shared library. The signature value can be used to for
* a profile name that is unique to this load module so that it does not
* collide with profiles from other binaries. It also allows shared libraries
* to dump merged profile data into its own profile file. */
uint64_t lprofGetLoadModuleSignature();
COMPILER_RT_VISIBILITY extern char *(*GetEnvHook)(const char *); COMPILER_RT_VISIBILITY extern char *(*GetEnvHook)(const char *);
COMPILER_RT_VISIBILITY extern void (*FreeHook)(void *); COMPILER_RT_VISIBILITY extern void (*FreeHook)(void *);
COMPILER_RT_VISIBILITY extern uint8_t *DynamicBufferIOBuffer; COMPILER_RT_VISIBILITY extern uint8_t *DynamicBufferIOBuffer;
COMPILER_RT_VISIBILITY extern uint32_t VPBufferSize; COMPILER_RT_VISIBILITY extern uint32_t VPBufferSize;
COMPILER_RT_VISIBILITY extern uint32_t VPMaxNumValsPerSite; COMPILER_RT_VISIBILITY extern uint32_t VPMaxNumValsPerSite;
/* Pointer to the start of static value counters to be allocted. */
COMPILER_RT_VISIBILITY extern ValueProfNode *CurrentVNode;
COMPILER_RT_VISIBILITY extern ValueProfNode *EndVNode;
extern void (*VPMergeHook)(struct ValueProfData *, __llvm_profile_data *); extern void (*VPMergeHook)(struct ValueProfData *, __llvm_profile_data *);
#endif #endif

View file

@ -19,6 +19,22 @@
COMPILER_RT_WEAK void (*VPMergeHook)(ValueProfData *, COMPILER_RT_WEAK void (*VPMergeHook)(ValueProfData *,
__llvm_profile_data *) = NULL; __llvm_profile_data *) = NULL;
COMPILER_RT_VISIBILITY
uint64_t lprofGetLoadModuleSignature() {
/* A very fast way to compute a module signature. */
uint64_t CounterSize = (uint64_t)(__llvm_profile_end_counters() -
__llvm_profile_begin_counters());
uint64_t DataSize = __llvm_profile_get_data_size(__llvm_profile_begin_data(),
__llvm_profile_end_data());
uint64_t NamesSize =
(uint64_t)(__llvm_profile_end_names() - __llvm_profile_begin_names());
uint64_t NumVnodes =
(uint64_t)(__llvm_profile_end_vnodes() - __llvm_profile_begin_vnodes());
const __llvm_profile_data *FirstD = __llvm_profile_begin_data();
return (NamesSize << 40) + (CounterSize << 30) + (DataSize << 20) +
(NumVnodes << 10) + (DataSize > 0 ? FirstD->NameRef : 0);
}
/* Returns 1 if profile is not structurally compatible. */ /* Returns 1 if profile is not structurally compatible. */
COMPILER_RT_VISIBILITY COMPILER_RT_VISIBILITY
@ -31,6 +47,9 @@ int __llvm_profile_check_compatibility(const char *ProfileData,
(__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header)); (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header));
SrcDataEnd = SrcDataStart + Header->DataSize; SrcDataEnd = SrcDataStart + Header->DataSize;
if (ProfileSize < sizeof(__llvm_profile_header))
return 1;
/* Check the header first. */ /* Check the header first. */
if (Header->Magic != __llvm_profile_get_magic() || if (Header->Magic != __llvm_profile_get_magic() ||
Header->Version != __llvm_profile_get_version() || Header->Version != __llvm_profile_get_version() ||

View file

@ -29,6 +29,13 @@ COMPILER_RT_VISIBILITY
extern uint64_t extern uint64_t
CountersEnd __asm("section$end$__DATA$" INSTR_PROF_CNTS_SECT_NAME_STR); CountersEnd __asm("section$end$__DATA$" INSTR_PROF_CNTS_SECT_NAME_STR);
COMPILER_RT_VISIBILITY
extern ValueProfNode
VNodesStart __asm("section$start$__DATA$" INSTR_PROF_VNODES_SECT_NAME_STR);
COMPILER_RT_VISIBILITY
extern ValueProfNode
VNodesEnd __asm("section$end$__DATA$" INSTR_PROF_VNODES_SECT_NAME_STR);
COMPILER_RT_VISIBILITY COMPILER_RT_VISIBILITY
const __llvm_profile_data *__llvm_profile_begin_data(void) { const __llvm_profile_data *__llvm_profile_begin_data(void) {
return &DataStart; return &DataStart;
@ -43,4 +50,14 @@ COMPILER_RT_VISIBILITY
uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart; } uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart; }
COMPILER_RT_VISIBILITY COMPILER_RT_VISIBILITY
uint64_t *__llvm_profile_end_counters(void) { return &CountersEnd; } uint64_t *__llvm_profile_end_counters(void) { return &CountersEnd; }
COMPILER_RT_VISIBILITY
ValueProfNode *__llvm_profile_begin_vnodes(void) {
return &VNodesStart;
}
COMPILER_RT_VISIBILITY
ValueProfNode *__llvm_profile_end_vnodes(void) { return &VNodesEnd; }
COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = &VNodesStart;
COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = &VNodesEnd;
#endif #endif

View file

@ -18,6 +18,8 @@
#define PROF_NAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_NAME_SECT_NAME) #define PROF_NAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_NAME_SECT_NAME)
#define PROF_CNTS_START INSTR_PROF_SECT_START(INSTR_PROF_CNTS_SECT_NAME) #define PROF_CNTS_START INSTR_PROF_SECT_START(INSTR_PROF_CNTS_SECT_NAME)
#define PROF_CNTS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_CNTS_SECT_NAME) #define PROF_CNTS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_CNTS_SECT_NAME)
#define PROF_VNODES_START INSTR_PROF_SECT_START(INSTR_PROF_VNODES_SECT_NAME)
#define PROF_VNODES_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_VNODES_SECT_NAME)
/* Declare section start and stop symbols for various sections /* Declare section start and stop symbols for various sections
* generated by compiler instrumentation. * generated by compiler instrumentation.
@ -28,6 +30,8 @@ extern uint64_t PROF_CNTS_START COMPILER_RT_VISIBILITY;
extern uint64_t PROF_CNTS_STOP COMPILER_RT_VISIBILITY; extern uint64_t PROF_CNTS_STOP COMPILER_RT_VISIBILITY;
extern char PROF_NAME_START COMPILER_RT_VISIBILITY; extern char PROF_NAME_START COMPILER_RT_VISIBILITY;
extern char PROF_NAME_STOP COMPILER_RT_VISIBILITY; extern char PROF_NAME_STOP COMPILER_RT_VISIBILITY;
extern ValueProfNode PROF_VNODES_START COMPILER_RT_VISIBILITY;
extern ValueProfNode PROF_VNODES_STOP COMPILER_RT_VISIBILITY;
/* Add dummy data to ensure the section is always created. */ /* Add dummy data to ensure the section is always created. */
__llvm_profile_data __llvm_profile_data
@ -35,6 +39,7 @@ __llvm_profile_data
uint64_t uint64_t
__prof_cnts_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_CNTS_SECT_NAME_STR); __prof_cnts_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_CNTS_SECT_NAME_STR);
char __prof_nms_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_NAME_SECT_NAME_STR); char __prof_nms_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_NAME_SECT_NAME_STR);
ValueProfNode __prof_vnodes_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_VNODES_SECT_NAME_STR);
COMPILER_RT_VISIBILITY const __llvm_profile_data * COMPILER_RT_VISIBILITY const __llvm_profile_data *
__llvm_profile_begin_data(void) { __llvm_profile_begin_data(void) {
@ -56,4 +61,15 @@ COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_begin_counters(void) {
COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_end_counters(void) { COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_end_counters(void) {
return &PROF_CNTS_STOP; return &PROF_CNTS_STOP;
} }
COMPILER_RT_VISIBILITY ValueProfNode *
__llvm_profile_begin_vnodes(void) {
return &PROF_VNODES_START;
}
COMPILER_RT_VISIBILITY ValueProfNode *__llvm_profile_end_vnodes(void) {
return &PROF_VNODES_STOP;
}
COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = &PROF_VNODES_START;
COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = &PROF_VNODES_STOP;
#endif #endif

View file

@ -80,4 +80,15 @@ COMPILER_RT_VISIBILITY
uint64_t *__llvm_profile_begin_counters(void) { return CountersFirst; } uint64_t *__llvm_profile_begin_counters(void) { return CountersFirst; }
COMPILER_RT_VISIBILITY COMPILER_RT_VISIBILITY
uint64_t *__llvm_profile_end_counters(void) { return CountersLast; } uint64_t *__llvm_profile_end_counters(void) { return CountersLast; }
COMPILER_RT_VISIBILITY
ValueProfNode *__llvm_profile_begin_vnodes(void) {
return 0;
}
COMPILER_RT_VISIBILITY
ValueProfNode *__llvm_profile_end_vnodes(void) { return 0; }
COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = 0;
COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = 0;
#endif #endif

View file

@ -13,22 +13,37 @@
#ifdef _MSC_VER #ifdef _MSC_VER
#define COMPILER_RT_ALIGNAS(x) __declspec(align(x)) #define COMPILER_RT_ALIGNAS(x) __declspec(align(x))
#define COMPILER_RT_VISIBILITY #define COMPILER_RT_VISIBILITY
/* FIXME: selectany does not have the same semantics as weak. */
#define COMPILER_RT_WEAK __declspec(selectany) #define COMPILER_RT_WEAK __declspec(selectany)
/* Need to include <windows.h> */
#define COMPILER_RT_ALLOCA _alloca #define COMPILER_RT_ALLOCA _alloca
/* Need to include <stdio.h> and <io.h> */
#define COMPILER_RT_FTRUNCATE(f,l) _chsize(_fileno(f),l)
#elif __GNUC__ #elif __GNUC__
#define COMPILER_RT_ALIGNAS(x) __attribute__((aligned(x))) #define COMPILER_RT_ALIGNAS(x) __attribute__((aligned(x)))
#define COMPILER_RT_VISIBILITY __attribute__((visibility("hidden"))) #define COMPILER_RT_VISIBILITY __attribute__((visibility("hidden")))
#define COMPILER_RT_WEAK __attribute__((weak)) #define COMPILER_RT_WEAK __attribute__((weak))
#define COMPILER_RT_ALLOCA __builtin_alloca #define COMPILER_RT_ALLOCA __builtin_alloca
#define COMPILER_RT_FTRUNCATE(f,l) ftruncate(fileno(f),l)
#endif #endif
#if defined(__APPLE__)
#define COMPILER_RT_SEG "__DATA,"
#else
#define COMPILER_RT_SEG ""
#endif
#ifdef _MSC_VER
#define COMPILER_RT_SECTION(Sect) __declspec(allocate(Sect))
#else
#define COMPILER_RT_SECTION(Sect) __attribute__((section(Sect))) #define COMPILER_RT_SECTION(Sect) __attribute__((section(Sect)))
#endif
#define COMPILER_RT_MAX_HOSTLEN 128 #define COMPILER_RT_MAX_HOSTLEN 128
#ifdef _MSC_VER #ifdef _MSC_VER
#define COMPILER_RT_GETHOSTNAME(Name, Len) gethostname(Name, Len) #define COMPILER_RT_GETHOSTNAME(Name, Len) gethostname(Name, Len)
#elif defined(__ORBIS__) #elif defined(__ORBIS__)
#define COMPILER_RT_GETHOSTNAME(Name, Len) (-1) #define COMPILER_RT_GETHOSTNAME(Name, Len) ((void)(Name), (void)(Len), (-1))
#else #else
#define COMPILER_RT_GETHOSTNAME(Name, Len) lprofGetHostName(Name, Len) #define COMPILER_RT_GETHOSTNAME(Name, Len) lprofGetHostName(Name, Len)
#define COMPILER_RT_HAS_UNAME 1 #define COMPILER_RT_HAS_UNAME 1
@ -75,6 +90,9 @@
#define PROF_WARN(Format, ...) \ #define PROF_WARN(Format, ...) \
fprintf(stderr, "LLVM Profile Warning: " Format, __VA_ARGS__); fprintf(stderr, "LLVM Profile Warning: " Format, __VA_ARGS__);
#define PROF_NOTE(Format, ...) \
fprintf(stderr, "LLVM Profile Note: " Format, __VA_ARGS__);
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
#include <inttypes.h> #include <inttypes.h>

View file

@ -12,9 +12,14 @@
#ifdef _WIN32 #ifdef _WIN32
#include <direct.h> #include <direct.h>
#include <io.h>
#include <windows.h>
#else #else
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#endif #endif
#ifdef COMPILER_RT_HAS_UNAME #ifdef COMPILER_RT_HAS_UNAME
@ -35,7 +40,7 @@ void __llvm_profile_recursive_mkdir(char *path) {
#ifdef _WIN32 #ifdef _WIN32
_mkdir(path); _mkdir(path);
#else #else
mkdir(path, 0755); /* Some of these will fail, ignore it. */ mkdir(path, 0755); /* Some of these will fail, ignore it. */
#endif #endif
path[i] = save; path[i] = save;
} }
@ -61,7 +66,7 @@ void *lprofPtrFetchAdd(void **Mem, long ByteIncr) {
#endif #endif
#ifdef COMPILER_RT_HAS_UNAME #ifdef COMPILER_RT_HAS_UNAME
int lprofGetHostName(char *Name, int Len) { COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
struct utsname N; struct utsname N;
int R; int R;
if (!(R = uname(&N))) if (!(R = uname(&N)))
@ -70,4 +75,59 @@ int lprofGetHostName(char *Name, int Len) {
} }
#endif #endif
COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) {
FILE *f;
int fd;
#ifdef COMPILER_RT_HAS_FCNTL_LCK
struct flock s_flock;
s_flock.l_whence = SEEK_SET;
s_flock.l_start = 0;
s_flock.l_len = 0; /* Until EOF. */
s_flock.l_pid = getpid();
s_flock.l_type = F_WRLCK;
fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
if (fd < 0)
return NULL;
while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
if (errno != EINTR) {
if (errno == ENOLCK) {
PROF_WARN("Data may be corrupted during profile merging : %s\n",
"Fail to obtain file lock due to system limit.");
}
break;
}
}
f = fdopen(fd, "r+b");
#elif defined(_WIN32)
HANDLE h = CreateFile(ProfileName, GENERIC_READ | GENERIC_WRITE, 0, 0,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (h == INVALID_HANDLE_VALUE)
return NULL;
fd = _open_osfhandle((intptr_t)h, 0);
if (fd == -1) {
CloseHandle(h);
return NULL;
}
f = _fdopen(fd, "r+b");
if (f == 0) {
CloseHandle(h);
return NULL;
}
#else
/* Worst case no locking applied. */
PROF_WARN("Concurrent file access is not supported : %s\n",
"lack file locking");
fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
if (fd < 0)
return NULL;
f = fdopen(fd, "r+b");
#endif
return f;
}

View file

@ -11,10 +11,15 @@
#define PROFILE_INSTRPROFILINGUTIL_H #define PROFILE_INSTRPROFILINGUTIL_H
#include <stddef.h> #include <stddef.h>
#include <stdio.h>
/*! \brief Create a directory tree. */ /*! \brief Create a directory tree. */
void __llvm_profile_recursive_mkdir(char *Pathname); void __llvm_profile_recursive_mkdir(char *Pathname);
/*! Open file \c Filename for read+write with write
* lock for exclusive access. The caller will block
* if the lock is already held by another process. */
FILE *lprofOpenFileEx(const char *Filename);
/* PS4 doesn't have getenv. Define a shim. */ /* PS4 doesn't have getenv. Define a shim. */
#if __ORBIS__ #if __ORBIS__
static inline char *getenv(const char *name) { return NULL; } static inline char *getenv(const char *name) { return NULL; }

View file

@ -18,27 +18,38 @@
#define INSTR_PROF_COMMON_API_IMPL #define INSTR_PROF_COMMON_API_IMPL
#include "InstrProfData.inc" #include "InstrProfData.inc"
#define PROF_OOM(Msg) PROF_ERR(Msg ":%s\n", "Out of memory"); static int hasStaticCounters = 1;
#define PROF_OOM_RETURN(Msg) \ static int OutOfNodesWarnings = 0;
{ \ static int hasNonDefaultValsPerSite = 0;
PROF_OOM(Msg) \ #define INSTR_PROF_MAX_VP_WARNS 10
return NULL; \ #define INSTR_PROF_DEFAULT_NUM_VAL_PER_SITE 8
} #define INSTR_PROF_VNODE_POOL_SIZE 1024
#ifndef _MSC_VER
/* A shared static pool in addition to the vnodes statically
* allocated by the compiler. */
COMPILER_RT_VISIBILITY ValueProfNode
lprofValueProfNodes[INSTR_PROF_VNODE_POOL_SIZE] COMPILER_RT_SECTION(
COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME_STR);
#endif
COMPILER_RT_VISIBILITY uint32_t VPMaxNumValsPerSite = COMPILER_RT_VISIBILITY uint32_t VPMaxNumValsPerSite =
INSTR_PROF_MAX_NUM_VAL_PER_SITE; INSTR_PROF_DEFAULT_NUM_VAL_PER_SITE;
COMPILER_RT_VISIBILITY void lprofSetupValueProfiler() { COMPILER_RT_VISIBILITY void lprofSetupValueProfiler() {
const char *Str = 0; const char *Str = 0;
Str = getenv("LLVM_VP_MAX_NUM_VALS_PER_SITE"); Str = getenv("LLVM_VP_MAX_NUM_VALS_PER_SITE");
if (Str && Str[0]) if (Str && Str[0]) {
VPMaxNumValsPerSite = atoi(Str); VPMaxNumValsPerSite = atoi(Str);
hasNonDefaultValsPerSite = 1;
}
if (VPMaxNumValsPerSite > INSTR_PROF_MAX_NUM_VAL_PER_SITE) if (VPMaxNumValsPerSite > INSTR_PROF_MAX_NUM_VAL_PER_SITE)
VPMaxNumValsPerSite = INSTR_PROF_MAX_NUM_VAL_PER_SITE; VPMaxNumValsPerSite = INSTR_PROF_MAX_NUM_VAL_PER_SITE;
} }
COMPILER_RT_VISIBILITY void lprofSetMaxValsPerSite(uint32_t MaxVals) { COMPILER_RT_VISIBILITY void lprofSetMaxValsPerSite(uint32_t MaxVals) {
VPMaxNumValsPerSite = MaxVals; VPMaxNumValsPerSite = MaxVals;
hasNonDefaultValsPerSite = 1;
} }
/* This method is only used in value profiler mock testing. */ /* This method is only used in value profiler mock testing. */
@ -69,6 +80,15 @@ __llvm_get_function_addr(const __llvm_profile_data *Data) {
static int allocateValueProfileCounters(__llvm_profile_data *Data) { static int allocateValueProfileCounters(__llvm_profile_data *Data) {
uint64_t NumVSites = 0; uint64_t NumVSites = 0;
uint32_t VKI; uint32_t VKI;
/* This function will never be called when value site array is allocated
statically at compile time. */
hasStaticCounters = 0;
/* When dynamic allocation is enabled, allow tracking the max number of
* values allowd. */
if (!hasNonDefaultValsPerSite)
VPMaxNumValsPerSite = INSTR_PROF_MAX_NUM_VAL_PER_SITE;
for (VKI = IPVK_First; VKI <= IPVK_Last; ++VKI) for (VKI = IPVK_First; VKI <= IPVK_Last; ++VKI)
NumVSites += Data->NumValueSites[VKI]; NumVSites += Data->NumValueSites[VKI];
@ -83,10 +103,36 @@ static int allocateValueProfileCounters(__llvm_profile_data *Data) {
return 1; return 1;
} }
static ValueProfNode *allocateOneNode(__llvm_profile_data *Data, uint32_t Index,
uint64_t Value) {
ValueProfNode *Node;
if (!hasStaticCounters)
return (ValueProfNode *)calloc(1, sizeof(ValueProfNode));
/* Early check to avoid value wrapping around. */
if (CurrentVNode + 1 > EndVNode) {
if (OutOfNodesWarnings++ < INSTR_PROF_MAX_VP_WARNS) {
PROF_WARN("Unable to track new values: %s. "
" Consider using option -mllvm -vp-counters-per-site=<n> to "
"allocate more"
" value profile counters at compile time. \n",
"Running out of static counters");
}
return 0;
}
Node = COMPILER_RT_PTR_FETCH_ADD(ValueProfNode, CurrentVNode, 1);
/* Due to section padding, EndVNode point to a byte which is one pass
* an incomplete VNode, so we need to skip the last incomplete node. */
if (Node + 1 > EndVNode)
return 0;
return Node;
}
COMPILER_RT_VISIBILITY void COMPILER_RT_VISIBILITY void
__llvm_profile_instrument_target(uint64_t TargetValue, void *Data, __llvm_profile_instrument_target(uint64_t TargetValue, void *Data,
uint32_t CounterIndex) { uint32_t CounterIndex) {
__llvm_profile_data *PData = (__llvm_profile_data *)Data; __llvm_profile_data *PData = (__llvm_profile_data *)Data;
if (!PData) if (!PData)
return; return;
@ -99,21 +145,21 @@ __llvm_profile_instrument_target(uint64_t TargetValue, void *Data,
ValueProfNode **ValueCounters = (ValueProfNode **)PData->Values; ValueProfNode **ValueCounters = (ValueProfNode **)PData->Values;
ValueProfNode *PrevVNode = NULL; ValueProfNode *PrevVNode = NULL;
ValueProfNode *MinCountVNode = NULL; ValueProfNode *MinCountVNode = NULL;
ValueProfNode *CurrentVNode = ValueCounters[CounterIndex]; ValueProfNode *CurVNode = ValueCounters[CounterIndex];
uint64_t MinCount = UINT64_MAX; uint64_t MinCount = UINT64_MAX;
uint8_t VDataCount = 0; uint8_t VDataCount = 0;
while (CurrentVNode) { while (CurVNode) {
if (TargetValue == CurrentVNode->Value) { if (TargetValue == CurVNode->Value) {
CurrentVNode->Count++; CurVNode->Count++;
return; return;
} }
if (CurrentVNode->Count < MinCount) { if (CurVNode->Count < MinCount) {
MinCount = CurrentVNode->Count; MinCount = CurVNode->Count;
MinCountVNode = CurrentVNode; MinCountVNode = CurVNode;
} }
PrevVNode = CurrentVNode; PrevVNode = CurVNode;
CurrentVNode = CurrentVNode->Next; CurVNode = CurVNode->Next;
++VDataCount; ++VDataCount;
} }
@ -147,29 +193,28 @@ __llvm_profile_instrument_target(uint64_t TargetValue, void *Data,
* to give space for hot targets. * to give space for hot targets.
*/ */
if (!(--MinCountVNode->Count)) { if (!(--MinCountVNode->Count)) {
CurrentVNode = MinCountVNode; CurVNode = MinCountVNode;
CurrentVNode->Value = TargetValue; CurVNode->Value = TargetValue;
CurrentVNode->Count++; CurVNode->Count++;
} }
return; return;
} }
CurrentVNode = (ValueProfNode *)calloc(1, sizeof(ValueProfNode)); CurVNode = allocateOneNode(PData, CounterIndex, TargetValue);
if (!CurrentVNode) if (!CurVNode)
return; return;
CurVNode->Value = TargetValue;
CurrentVNode->Value = TargetValue; CurVNode->Count++;
CurrentVNode->Count++;
uint32_t Success = 0; uint32_t Success = 0;
if (!ValueCounters[CounterIndex]) if (!ValueCounters[CounterIndex])
Success = Success =
COMPILER_RT_BOOL_CMPXCHG(&ValueCounters[CounterIndex], 0, CurrentVNode); COMPILER_RT_BOOL_CMPXCHG(&ValueCounters[CounterIndex], 0, CurVNode);
else if (PrevVNode && !PrevVNode->Next) else if (PrevVNode && !PrevVNode->Next)
Success = COMPILER_RT_BOOL_CMPXCHG(&(PrevVNode->Next), 0, CurrentVNode); Success = COMPILER_RT_BOOL_CMPXCHG(&(PrevVNode->Next), 0, CurVNode);
if (!Success) { if (!Success && !hasStaticCounters) {
free(CurrentVNode); free(CurVNode);
return; return;
} }
} }
@ -264,7 +309,7 @@ static ValueProfNode *getNextNValueData(uint32_t VK, uint32_t Site,
return VNode; return VNode;
} }
static uint32_t getValueProfDataSizeWrapper() { static uint32_t getValueProfDataSizeWrapper(void) {
return getValueProfDataSize(&RTRecordClosure); return getValueProfDataSize(&RTRecordClosure);
} }

View file

@ -21,13 +21,7 @@
*/ */
#define PROT_READ 0x1 #define PROT_READ 0x1
#define PROT_WRITE 0x2 #define PROT_WRITE 0x2
/* This flag is only available in WinXP+ */ #define PROT_EXEC 0x0
#ifdef FILE_MAP_EXECUTE
#define PROT_EXEC 0x4
#else
#define PROT_EXEC 0x0
#define FILE_MAP_EXECUTE 0
#endif
#define MAP_FILE 0x00 #define MAP_FILE 0x00
#define MAP_SHARED 0x01 #define MAP_SHARED 0x01

View file

@ -223,11 +223,53 @@ static WeightedFile parseWeightedFile(const StringRef &WeightedFilename) {
return WeightedFile(FileName, Weight); return WeightedFile(FileName, Weight);
} }
static std::unique_ptr<MemoryBuffer>
getInputFilenamesFileBuf(const StringRef &InputFilenamesFile) {
if (InputFilenamesFile == "")
return {};
auto BufOrError = MemoryBuffer::getFileOrSTDIN(InputFilenamesFile);
if (!BufOrError)
exitWithErrorCode(BufOrError.getError(), InputFilenamesFile);
return std::move(*BufOrError);
}
static void parseInputFilenamesFile(MemoryBuffer *Buffer,
WeightedFileVector &WFV) {
if (!Buffer)
return;
SmallVector<StringRef, 8> Entries;
StringRef Data = Buffer->getBuffer();
Data.split(Entries, '\n', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
for (const StringRef &FileWeightEntry : Entries) {
StringRef SanitizedEntry = FileWeightEntry.trim(" \t\v\f\r");
// Skip comments.
if (SanitizedEntry.startswith("#"))
continue;
// If there's no comma, it's an unweighted profile.
else if (SanitizedEntry.find(',') == StringRef::npos)
WFV.emplace_back(SanitizedEntry, 1);
else
WFV.emplace_back(parseWeightedFile(SanitizedEntry));
}
}
static int merge_main(int argc, const char *argv[]) { static int merge_main(int argc, const char *argv[]) {
cl::list<std::string> InputFilenames(cl::Positional, cl::list<std::string> InputFilenames(cl::Positional,
cl::desc("<filename...>")); cl::desc("<filename...>"));
cl::list<std::string> WeightedInputFilenames("weighted-input", cl::list<std::string> WeightedInputFilenames("weighted-input",
cl::desc("<weight>,<filename>")); cl::desc("<weight>,<filename>"));
cl::opt<std::string> InputFilenamesFile(
"input-files", cl::init(""),
cl::desc("Path to file containing newline-separated "
"[<weight>,]<filename> entries"));
cl::alias InputFilenamesFileA("f", cl::desc("Alias for --input-files"),
cl::aliasopt(InputFilenamesFile));
cl::opt<bool> DumpInputFileList(
"dump-input-file-list", cl::init(false), cl::Hidden,
cl::desc("Dump the list of input files and their weights, then exit"));
cl::opt<std::string> OutputFilename("output", cl::value_desc("output"), cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
cl::init("-"), cl::Required, cl::init("-"), cl::Required,
cl::desc("Output file")); cl::desc("Output file"));
@ -237,7 +279,6 @@ static int merge_main(int argc, const char *argv[]) {
cl::desc("Profile kind:"), cl::init(instr), cl::desc("Profile kind:"), cl::init(instr),
cl::values(clEnumVal(instr, "Instrumentation profile (default)"), cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
clEnumVal(sample, "Sample profile"), clEnumValEnd)); clEnumVal(sample, "Sample profile"), clEnumValEnd));
cl::opt<ProfileFormat> OutputFormat( cl::opt<ProfileFormat> OutputFormat(
cl::desc("Format of output profile"), cl::init(PF_Binary), cl::desc("Format of output profile"), cl::init(PF_Binary),
cl::values(clEnumValN(PF_Binary, "binary", "Binary encoding (default)"), cl::values(clEnumValN(PF_Binary, "binary", "Binary encoding (default)"),
@ -245,21 +286,31 @@ static int merge_main(int argc, const char *argv[]) {
clEnumValN(PF_GCC, "gcc", clEnumValN(PF_GCC, "gcc",
"GCC encoding (only meaningful for -sample)"), "GCC encoding (only meaningful for -sample)"),
clEnumValEnd)); clEnumValEnd));
cl::opt<bool> OutputSparse("sparse", cl::init(false), cl::opt<bool> OutputSparse("sparse", cl::init(false),
cl::desc("Generate a sparse profile (only meaningful for -instr)")); cl::desc("Generate a sparse profile (only meaningful for -instr)"));
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
if (InputFilenames.empty() && WeightedInputFilenames.empty()) WeightedFileVector WeightedInputs;
for (StringRef Filename : InputFilenames)
WeightedInputs.emplace_back(Filename, 1);
for (StringRef WeightedFilename : WeightedInputFilenames)
WeightedInputs.emplace_back(parseWeightedFile(WeightedFilename));
// Make sure that the file buffer stays alive for the duration of the
// weighted input vector's lifetime.
auto Buffer = getInputFilenamesFileBuf(InputFilenamesFile);
parseInputFilenamesFile(Buffer.get(), WeightedInputs);
if (WeightedInputs.empty())
exitWithError("No input files specified. See " + exitWithError("No input files specified. See " +
sys::path::filename(argv[0]) + " -help"); sys::path::filename(argv[0]) + " -help");
WeightedFileVector WeightedInputs; if (DumpInputFileList) {
for (StringRef Filename : InputFilenames) for (auto &WF : WeightedInputs)
WeightedInputs.push_back(WeightedFile(Filename, 1)); outs() << WF.Weight << "," << WF.Filename << "\n";
for (StringRef WeightedFilename : WeightedInputFilenames) return 0;
WeightedInputs.push_back(parseWeightedFile(WeightedFilename)); }
if (ProfileKind == instr) if (ProfileKind == instr)
mergeInstrProfile(WeightedInputs, OutputFilename, OutputFormat, mergeInstrProfile(WeightedInputs, OutputFilename, OutputFormat,
@ -270,24 +321,28 @@ static int merge_main(int argc, const char *argv[]) {
return 0; return 0;
} }
static int showInstrProfile(std::string Filename, bool ShowCounts, static int showInstrProfile(const std::string &Filename, bool ShowCounts,
bool ShowIndirectCallTargets, bool ShowIndirectCallTargets,
bool ShowDetailedSummary, bool ShowDetailedSummary,
std::vector<uint32_t> DetailedSummaryCutoffs, std::vector<uint32_t> DetailedSummaryCutoffs,
bool ShowAllFunctions, std::string ShowFunction, bool ShowAllFunctions,
bool TextFormat, raw_fd_ostream &OS) { const std::string &ShowFunction, bool TextFormat,
raw_fd_ostream &OS) {
auto ReaderOrErr = InstrProfReader::create(Filename); auto ReaderOrErr = InstrProfReader::create(Filename);
std::vector<uint32_t> Cutoffs(DetailedSummaryCutoffs); std::vector<uint32_t> Cutoffs = std::move(DetailedSummaryCutoffs);
if (ShowDetailedSummary && DetailedSummaryCutoffs.empty()) { if (ShowDetailedSummary && Cutoffs.empty()) {
Cutoffs = {800000, 900000, 950000, 990000, 999000, 999900, 999990}; Cutoffs = {800000, 900000, 950000, 990000, 999000, 999900, 999990};
} }
InstrProfSummaryBuilder Builder(Cutoffs); InstrProfSummaryBuilder Builder(std::move(Cutoffs));
if (Error E = ReaderOrErr.takeError()) if (Error E = ReaderOrErr.takeError())
exitWithError(std::move(E), Filename); exitWithError(std::move(E), Filename);
auto Reader = std::move(ReaderOrErr.get()); auto Reader = std::move(ReaderOrErr.get());
bool IsIRInstr = Reader->isIRLevelProfile(); bool IsIRInstr = Reader->isIRLevelProfile();
size_t ShownFunctions = 0; size_t ShownFunctions = 0;
uint64_t TotalNumValueSites = 0;
uint64_t TotalNumValueSitesWithValueProfile = 0;
uint64_t TotalNumValues = 0;
for (const auto &Func : *Reader) { for (const auto &Func : *Reader) {
bool Show = bool Show =
ShowAllFunctions || (!ShowFunction.empty() && ShowAllFunctions || (!ShowFunction.empty() &&
@ -334,10 +389,14 @@ static int showInstrProfile(std::string Filename, bool ShowCounts,
InstrProfSymtab &Symtab = Reader->getSymtab(); InstrProfSymtab &Symtab = Reader->getSymtab();
uint32_t NS = Func.getNumValueSites(IPVK_IndirectCallTarget); uint32_t NS = Func.getNumValueSites(IPVK_IndirectCallTarget);
OS << " Indirect Target Results: \n"; OS << " Indirect Target Results: \n";
TotalNumValueSites += NS;
for (size_t I = 0; I < NS; ++I) { for (size_t I = 0; I < NS; ++I) {
uint32_t NV = Func.getNumValueDataForSite(IPVK_IndirectCallTarget, I); uint32_t NV = Func.getNumValueDataForSite(IPVK_IndirectCallTarget, I);
std::unique_ptr<InstrProfValueData[]> VD = std::unique_ptr<InstrProfValueData[]> VD =
Func.getValueForSite(IPVK_IndirectCallTarget, I); Func.getValueForSite(IPVK_IndirectCallTarget, I);
TotalNumValues += NV;
if (NV)
TotalNumValueSitesWithValueProfile++;
for (uint32_t V = 0; V < NV; V++) { for (uint32_t V = 0; V < NV; V++) {
OS << "\t[ " << I << ", "; OS << "\t[ " << I << ", ";
OS << Symtab.getFuncName(VD[V].Value) << ", " << VD[V].Count OS << Symtab.getFuncName(VD[V].Value) << ", " << VD[V].Count
@ -347,7 +406,6 @@ static int showInstrProfile(std::string Filename, bool ShowCounts,
} }
} }
} }
if (Reader->hasError()) if (Reader->hasError())
exitWithError(Reader->getError(), Filename); exitWithError(Reader->getError(), Filename);
@ -359,6 +417,13 @@ static int showInstrProfile(std::string Filename, bool ShowCounts,
OS << "Total functions: " << PS->getNumFunctions() << "\n"; OS << "Total functions: " << PS->getNumFunctions() << "\n";
OS << "Maximum function count: " << PS->getMaxFunctionCount() << "\n"; OS << "Maximum function count: " << PS->getMaxFunctionCount() << "\n";
OS << "Maximum internal block count: " << PS->getMaxInternalCount() << "\n"; OS << "Maximum internal block count: " << PS->getMaxInternalCount() << "\n";
if (ShownFunctions && ShowIndirectCallTargets) {
OS << "Total Number of Indirect Call Sites : " << TotalNumValueSites
<< "\n";
OS << "Total Number of Sites With Values : "
<< TotalNumValueSitesWithValueProfile << "\n";
OS << "Total Number of Profiled Values : " << TotalNumValues << "\n";
}
if (ShowDetailedSummary) { if (ShowDetailedSummary) {
OS << "Detailed summary:\n"; OS << "Detailed summary:\n";
@ -374,8 +439,9 @@ static int showInstrProfile(std::string Filename, bool ShowCounts,
return 0; return 0;
} }
static int showSampleProfile(std::string Filename, bool ShowCounts, static int showSampleProfile(const std::string &Filename, bool ShowCounts,
bool ShowAllFunctions, std::string ShowFunction, bool ShowAllFunctions,
const std::string &ShowFunction,
raw_fd_ostream &OS) { raw_fd_ostream &OS) {
using namespace sampleprof; using namespace sampleprof;
LLVMContext Context; LLVMContext Context;
@ -454,7 +520,7 @@ static int show_main(int argc, const char *argv[]) {
int main(int argc, const char *argv[]) { int main(int argc, const char *argv[]) {
// Print a stack trace if we signal out. // Print a stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal(); sys::PrintStackTraceOnErrorSignal(argv[0]);
PrettyStackTraceProgram X(argc, argv); PrettyStackTraceProgram X(argc, argv);
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.