mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-06 19:06:02 +03:00
[PGO] Update ldc-profdata-3.9 and profile-rt-39 to svn r273081
This commit is contained in:
parent
176961f325
commit
21c2c6dd4b
14 changed files with 723 additions and 198 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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() ||
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue