Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,115 @@
CHECK_CXX_SOURCE_COMPILES("
#ifdef _MSC_VER
#include <Intrin.h> /* Workaround for PR19898. */
#include <windows.h>
#endif
int main() {
#ifdef _MSC_VER
volatile LONG val = 1;
MemoryBarrier();
InterlockedCompareExchange(&val, 0, 1);
InterlockedIncrement(&val);
InterlockedDecrement(&val);
#else
volatile unsigned long val = 1;
__sync_synchronize();
__sync_val_compare_and_swap(&val, 1, 0);
__sync_add_and_fetch(&val, 1);
__sync_sub_and_fetch(&val, 1);
#endif
return 0;
}
" COMPILER_RT_TARGET_HAS_ATOMICS)
CHECK_CXX_SOURCE_COMPILES("
#if defined(__linux__)
#include <unistd.h>
#endif
#include <fcntl.h>
int fd;
int main() {
struct flock s_flock;
s_flock.l_type = F_WRLCK;
fcntl(fd, F_SETLKW, &s_flock);
return 0;
}
" COMPILER_RT_TARGET_HAS_FCNTL_LCK)
CHECK_CXX_SOURCE_COMPILES("
#include <sys/utsname.h>
int main() {
return 0;
}
" COMPILER_RT_TARGET_HAS_UNAME)
add_compiler_rt_component(profile)
set(PROFILE_SOURCES
GCDAProfiling.c
InstrProfiling.c
InstrProfilingValue.c
InstrProfilingBuffer.c
InstrProfilingFile.c
InstrProfilingMerge.c
InstrProfilingMergeFile.c
InstrProfilingNameVar.c
InstrProfilingWriter.c
InstrProfilingPlatformDarwin.c
InstrProfilingPlatformLinux.c
InstrProfilingPlatformOther.c
InstrProfilingRuntime.cc
InstrProfilingUtil.c)
if(WIN32)
list(APPEND PROFILE_SOURCES WindowsMMap.c)
endif()
if(UNIX)
set(EXTRA_FLAGS
-fPIC
-Wno-pedantic)
endif()
if(COMPILER_RT_TARGET_HAS_ATOMICS)
set(EXTRA_FLAGS
${EXTRA_FLAGS}
-DCOMPILER_RT_HAS_ATOMICS=1)
endif()
if(COMPILER_RT_TARGET_HAS_FCNTL_LCK)
set(EXTRA_FLAGS
${EXTRA_FLAGS}
-DCOMPILER_RT_HAS_FCNTL_LCK=1)
endif()
if(COMPILER_RT_TARGET_HAS_UNAME)
set(EXTRA_FLAGS
${EXTRA_FLAGS}
-DCOMPILER_RT_HAS_UNAME=1)
endif()
# This appears to be a C-only warning banning the use of locals in aggregate
# initializers. All other compilers accept this, though.
# nonstandard extension used : 'identifier' : cannot be initialized using address of automatic variable
append_list_if(COMPILER_RT_HAS_WD4221_FLAG /wd4221 EXTRA_FLAGS)
if(APPLE)
add_compiler_rt_runtime(clang_rt.profile
STATIC
OS ${PROFILE_SUPPORTED_OS}
ARCHS ${PROFILE_SUPPORTED_ARCH}
CFLAGS ${EXTRA_FLAGS}
SOURCES ${PROFILE_SOURCES}
PARENT_TARGET profile)
else()
add_compiler_rt_runtime(clang_rt.profile
STATIC
ARCHS ${PROFILE_SUPPORTED_ARCH}
CFLAGS ${EXTRA_FLAGS}
SOURCES ${PROFILE_SOURCES}
PARENT_TARGET profile)
endif()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,81 @@
/*===- InstrProfiling.c - Support library for PGO instrumentation ---------===*\
|*
|* The LLVM Compiler Infrastructure
|*
|* This file is distributed under the University of Illinois Open Source
|* License. See LICENSE.TXT for details.
|*
\*===----------------------------------------------------------------------===*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "InstrProfiling.h"
#include "InstrProfilingInternal.h"
#define INSTR_PROF_VALUE_PROF_DATA
#include "InstrProfData.inc"
COMPILER_RT_WEAK uint64_t INSTR_PROF_RAW_VERSION_VAR = INSTR_PROF_RAW_VERSION;
COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_magic(void) {
return sizeof(void *) == sizeof(uint64_t) ? (INSTR_PROF_RAW_MAGIC_64)
: (INSTR_PROF_RAW_MAGIC_32);
}
static unsigned ProfileDumped = 0;
COMPILER_RT_VISIBILITY unsigned lprofProfileDumped() {
return ProfileDumped;
}
COMPILER_RT_VISIBILITY void lprofSetProfileDumped() {
ProfileDumped = 1;
}
/* Return the number of bytes needed to add to SizeInBytes to make it
* the result a multiple of 8.
*/
COMPILER_RT_VISIBILITY uint8_t
__llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes) {
return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t));
}
COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_version(void) {
return __llvm_profile_raw_version;
}
COMPILER_RT_VISIBILITY void __llvm_profile_reset_counters(void) {
uint64_t *I = __llvm_profile_begin_counters();
uint64_t *E = __llvm_profile_end_counters();
memset(I, 0, sizeof(uint64_t) * (E - I));
const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
const __llvm_profile_data *DI;
for (DI = DataBegin; DI < DataEnd; ++DI) {
uint64_t CurrentVSiteCount = 0;
uint32_t VKI, i;
if (!DI->Values)
continue;
ValueProfNode **ValueCounters = (ValueProfNode **)DI->Values;
for (VKI = IPVK_First; VKI <= IPVK_Last; ++VKI)
CurrentVSiteCount += DI->NumValueSites[VKI];
for (i = 0; i < CurrentVSiteCount; ++i) {
ValueProfNode *CurrentVNode = ValueCounters[i];
while (CurrentVNode) {
CurrentVNode->Count = 0;
CurrentVNode = CurrentVNode->Next;
}
}
}
ProfileDumped = 0;
}

View File

@@ -0,0 +1,209 @@
/*===- InstrProfiling.h- Support library for PGO instrumentation ----------===*\
|*
|* The LLVM Compiler Infrastructure
|*
|* This file is distributed under the University of Illinois Open Source
|* License. See LICENSE.TXT for details.
|*
\*===----------------------------------------------------------------------===*/
#ifndef PROFILE_INSTRPROFILING_H_
#define PROFILE_INSTRPROFILING_H_
#include "InstrProfilingPort.h"
#define INSTR_PROF_VISIBILITY COMPILER_RT_VISIBILITY
#include "InstrProfData.inc"
enum ValueKind {
#define VALUE_PROF_KIND(Enumerator, Value) Enumerator = Value,
#include "InstrProfData.inc"
};
typedef void *IntPtrT;
typedef struct COMPILER_RT_ALIGNAS(INSTR_PROF_DATA_ALIGNMENT)
__llvm_profile_data {
#define INSTR_PROF_DATA(Type, LLVMType, Name, Initializer) Type Name;
#include "InstrProfData.inc"
} __llvm_profile_data;
typedef struct __llvm_profile_header {
#define INSTR_PROF_RAW_HEADER(Type, Name, Initializer) Type Name;
#include "InstrProfData.inc"
} __llvm_profile_header;
typedef struct ValueProfNode * PtrToNodeT;
typedef struct ValueProfNode {
#define INSTR_PROF_VALUE_NODE(Type, LLVMType, Name, Initializer) Type Name;
#include "InstrProfData.inc"
} ValueProfNode;
/*!
* \brief Get number of bytes necessary to pad the argument to eight
* byte boundary.
*/
uint8_t __llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes);
/*!
* \brief Get required size for profile buffer.
*/
uint64_t __llvm_profile_get_size_for_buffer(void);
/*!
* \brief Write instrumentation data to the given buffer.
*
* \pre \c Buffer is the start of a buffer at least as big as \a
* __llvm_profile_get_size_for_buffer().
*/
int __llvm_profile_write_buffer(char *Buffer);
const __llvm_profile_data *__llvm_profile_begin_data(void);
const __llvm_profile_data *__llvm_profile_end_data(void);
const char *__llvm_profile_begin_names(void);
const char *__llvm_profile_end_names(void);
uint64_t *__llvm_profile_begin_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.
*
*/
void __llvm_profile_reset_counters(void);
/*!
* \brief Merge profile data from buffer.
*
* Read profile data form buffer \p Profile and merge with
* in-process profile counters. The client is expected to
* have checked or already knows the profile data in the
* buffer matches the in-process counter structure before
* calling it.
*/
void __llvm_profile_merge_from_buffer(const char *Profile, uint64_t Size);
/*! \brief Check if profile in buffer matches the current binary.
*
* Returns 0 (success) if the profile data in buffer \p Profile with size
* \p Size was generated by the same binary and therefore matches
* structurally the in-process counters. If the profile data in buffer is
* not compatible, the interface returns 1 (failure).
*/
int __llvm_profile_check_compatibility(const char *Profile,
uint64_t Size);
/*!
* \brief Counts the number of times a target value is seen.
*
* Records the target value for the CounterIndex if not seen before. Otherwise,
* increments the counter associated w/ the target value.
* void __llvm_profile_instrument_target(uint64_t TargetValue, void *Data,
* uint32_t CounterIndex);
*/
void INSTR_PROF_VALUE_PROF_FUNC(
#define VALUE_PROF_FUNC_PARAM(ArgType, ArgName, ArgLLVMType) ArgType ArgName
#include "InstrProfData.inc"
);
/*!
* \brief Write instrumentation data to the current file.
*
* Writes to the file with the last name given to \a *
* __llvm_profile_set_filename(),
* or if it hasn't been called, the \c LLVM_PROFILE_FILE environment variable,
* or if that's not set, the last name set to INSTR_PROF_PROFILE_NAME_VAR,
* or if that's not set, \c "default.profraw".
*/
int __llvm_profile_write_file(void);
/*!
* \brief this is a wrapper interface to \c __llvm_profile_write_file.
* After this interface is invoked, a arleady dumped flag will be set
* so that profile won't be dumped again during program exit.
* Invocation of interface __llvm_profile_reset_counters will clear
* the flag. This interface is designed to be used to collect profile
* data from user selected hot regions. The use model is
* __llvm_profile_reset_counters();
* ... hot region 1
* __llvm_profile_dump();
* .. some other code
* __llvm_profile_reset_counters();
* ... hot region 2
* __llvm_profile_dump();
*
* It is expected that on-line profile merging is on with \c %m specifier
* used in profile filename . If merging is not turned on, user is expected
* to invoke __llvm_profile_set_filename to specify different profile names
* for different regions before dumping to avoid profile write clobbering.
*/
int __llvm_profile_dump(void);
/*!
* \brief Set the filename for writing instrumentation data.
*
* Sets the filename to be used for subsequent calls to
* \a __llvm_profile_write_file().
*
* \c Name is not copied, so it must remain valid. Passing NULL resets the
* filename logic to the default behaviour.
*/
void __llvm_profile_set_filename(const char *Name);
/*! \brief Register to write instrumentation data to file at exit. */
int __llvm_profile_register_write_file_atexit(void);
/*! \brief Initialize file handling. */
void __llvm_profile_initialize_file(void);
/*!
* \brief Return path prefix (excluding the base filename) of the profile data.
* This is useful for users using \c -fprofile-generate=./path_prefix who do
* not care about the default raw profile name. It is also useful to collect
* more than more profile data files dumped in the same directory (Online
* merge mode is turned on for instrumented programs with shared libs).
* Side-effect: this API call will invoke malloc with dynamic memory allocation.
*/
const char *__llvm_profile_get_path_prefix();
/*! \brief Get the magic token for the file format. */
uint64_t __llvm_profile_get_magic(void);
/*! \brief Get the version of the file format. */
uint64_t __llvm_profile_get_version(void);
/*! \brief Get the number of entries in the profile data section. */
uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin,
const __llvm_profile_data *End);
/*!
* This variable is defined in InstrProfilingRuntime.cc as a hidden
* symbol. Its main purpose is to enable profile runtime user to
* bypass runtime initialization code -- if the client code explicitly
* define this variable, then InstProfileRuntime.o won't be linked in.
* Note that this variable's visibility needs to be hidden so that the
* definition of this variable in an instrumented shared library won't
* affect runtime initialization decision of the main program.
* __llvm_profile_profile_runtime. */
COMPILER_RT_VISIBILITY extern int INSTR_PROF_PROFILE_RUNTIME_VAR;
/*!
* This variable is defined in InstrProfiling.c. Its main purpose is to
* encode the raw profile version value and other format related information
* such as whether the profile is from IR based instrumentation. The variable
* is defined as weak so that compiler can emit an overriding definition
* depending on user option. Since we don't support mixing FE and IR based
* data in the same raw profile data file (in other words, shared libs and
* main program are expected to be instrumented in the same way), there is
* no need for this variable to be hidden.
*/
extern uint64_t INSTR_PROF_RAW_VERSION_VAR; /* __llvm_profile_raw_version */
/*!
* This variable is a weak symbol defined in InstrProfiling.c. It allows
* compiler instrumentation to provide overriding definition with value
* from compiler command line. This variable has default visibility.
*/
extern char INSTR_PROF_PROFILE_NAME_VAR[1]; /* __llvm_profile_filename. */
#endif /* PROFILE_INSTRPROFILING_H_ */

View File

@@ -0,0 +1,68 @@
/*===- InstrProfilingBuffer.c - Write instrumentation to a memory buffer --===*\
|*
|* The LLVM Compiler Infrastructure
|*
|* This file is distributed under the University of Illinois Open Source
|* License. See LICENSE.TXT for details.
|*
\*===----------------------------------------------------------------------===*/
#include "InstrProfiling.h"
#include "InstrProfilingInternal.h"
COMPILER_RT_VISIBILITY
uint64_t __llvm_profile_get_size_for_buffer(void) {
const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
const uint64_t *CountersBegin = __llvm_profile_begin_counters();
const uint64_t *CountersEnd = __llvm_profile_end_counters();
const char *NamesBegin = __llvm_profile_begin_names();
const char *NamesEnd = __llvm_profile_end_names();
return __llvm_profile_get_size_for_buffer_internal(
DataBegin, DataEnd, CountersBegin, CountersEnd, NamesBegin, NamesEnd);
}
COMPILER_RT_VISIBILITY
uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin,
const __llvm_profile_data *End) {
intptr_t BeginI = (intptr_t)Begin, EndI = (intptr_t)End;
return ((EndI + sizeof(__llvm_profile_data) - 1) - BeginI) /
sizeof(__llvm_profile_data);
}
COMPILER_RT_VISIBILITY
uint64_t __llvm_profile_get_size_for_buffer_internal(
const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
const uint64_t *CountersBegin, const uint64_t *CountersEnd,
const char *NamesBegin, const char *NamesEnd) {
/* Match logic in __llvm_profile_write_buffer(). */
const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char);
const uint8_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize);
return sizeof(__llvm_profile_header) +
(__llvm_profile_get_data_size(DataBegin, DataEnd) *
sizeof(__llvm_profile_data)) +
(CountersEnd - CountersBegin) * sizeof(uint64_t) + NamesSize + Padding;
}
COMPILER_RT_VISIBILITY
void initBufferWriter(ProfDataWriter *BufferWriter, char *Buffer) {
BufferWriter->Write = lprofBufferWriter;
BufferWriter->WriterCtx = Buffer;
}
COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer(char *Buffer) {
ProfDataWriter BufferWriter;
initBufferWriter(&BufferWriter, Buffer);
return lprofWriteData(&BufferWriter, 0, 0);
}
COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer_internal(
char *Buffer, const __llvm_profile_data *DataBegin,
const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin,
const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) {
ProfDataWriter BufferWriter;
initBufferWriter(&BufferWriter, Buffer);
return lprofWriteDataImpl(&BufferWriter, DataBegin, DataEnd, CountersBegin,
CountersEnd, 0, NamesBegin, NamesEnd, 0);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,190 @@
/*===- InstrProfiling.h- Support library for PGO instrumentation ----------===*\
|*
|* The LLVM Compiler Infrastructure
|*
|* This file is distributed under the University of Illinois Open Source
|* License. See LICENSE.TXT for details.
|*
\*===----------------------------------------------------------------------===*/
#ifndef PROFILE_INSTRPROFILING_INTERNALH_
#define PROFILE_INSTRPROFILING_INTERNALH_
#include <stddef.h>
#include "InstrProfiling.h"
/*!
* \brief Write instrumentation data to the given buffer, given explicit
* pointers to the live data in memory. This function is probably not what you
* want. Use __llvm_profile_get_size_for_buffer instead. Use this function if
* your program has a custom memory layout.
*/
uint64_t __llvm_profile_get_size_for_buffer_internal(
const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
const uint64_t *CountersBegin, const uint64_t *CountersEnd,
const char *NamesBegin, const char *NamesEnd);
/*!
* \brief Write instrumentation data to the given buffer, given explicit
* pointers to the live data in memory. This function is probably not what you
* want. Use __llvm_profile_write_buffer instead. Use this function if your
* program has a custom memory layout.
*
* \pre \c Buffer is the start of a buffer at least as big as \a
* __llvm_profile_get_size_for_buffer_internal().
*/
int __llvm_profile_write_buffer_internal(
char *Buffer, const __llvm_profile_data *DataBegin,
const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin,
const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd);
/*!
* The data structure describing the data to be written by the
* low level writer callback function.
*/
typedef struct ProfDataIOVec {
const void *Data;
size_t ElmSize;
size_t NumElm;
} ProfDataIOVec;
struct ProfDataWriter;
typedef uint32_t (*WriterCallback)(struct ProfDataWriter *This, ProfDataIOVec *,
uint32_t NumIOVecs);
typedef struct ProfDataWriter {
WriterCallback Write;
void *WriterCtx;
} ProfDataWriter;
/*!
* The data structure for buffered IO of profile data.
*/
typedef struct ProfBufferIO {
ProfDataWriter *FileWriter;
uint32_t OwnFileWriter;
/* The start of the buffer. */
uint8_t *BufferStart;
/* Total size of the buffer. */
uint32_t BufferSz;
/* Current byte offset from the start of the buffer. */
uint32_t CurOffset;
} ProfBufferIO;
/* The creator interface used by testing. */
ProfBufferIO *lprofCreateBufferIOInternal(void *File, uint32_t BufferSz);
/*!
* This is the interface to create a handle for buffered IO.
*/
ProfBufferIO *lprofCreateBufferIO(ProfDataWriter *FileWriter);
/*!
* The interface to destroy the bufferIO handle and reclaim
* the memory.
*/
void lprofDeleteBufferIO(ProfBufferIO *BufferIO);
/*!
* This is the interface to write \c Data of \c Size bytes through
* \c BufferIO. Returns 0 if successful, otherwise return -1.
*/
int lprofBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data,
uint32_t Size);
/*!
* The interface to flush the remaining data in the buffer.
* through the low level writer callback.
*/
int lprofBufferIOFlush(ProfBufferIO *BufferIO);
/* The low level interface to write data into a buffer. It is used as the
* callback by other high level writer methods such as buffered IO writer
* and profile data writer. */
uint32_t lprofBufferWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,
uint32_t NumIOVecs);
void initBufferWriter(ProfDataWriter *BufferWriter, char *Buffer);
struct ValueProfData;
struct ValueProfRecord;
struct InstrProfValueData;
struct ValueProfNode;
/*!
* The class that defines a set of methods to read value profile
* data for streaming/serialization from the instrumentation runtime.
*/
typedef struct VPDataReaderType {
uint32_t (*InitRTRecord)(const __llvm_profile_data *Data,
uint8_t *SiteCountArray[]);
/* Function pointer to getValueProfRecordHeader method. */
uint32_t (*GetValueProfRecordHeaderSize)(uint32_t NumSites);
/* Function pointer to getFristValueProfRecord method. */
struct ValueProfRecord *(*GetFirstValueProfRecord)(struct ValueProfData *);
/* Return the number of value data for site \p Site. */
uint32_t (*GetNumValueDataForSite)(uint32_t VK, uint32_t Site);
/* Return the total size of the value profile data of the
* current function. */
uint32_t (*GetValueProfDataSize)(void);
/*!
* Read the next \p N value data for site \p Site and store the data
* in \p Dst. \p StartNode is the first value node to start with if
* it is not null. The function returns the pointer to the value
* node pointer to be used as the \p StartNode of the next batch reading.
* If there is nothing left, it returns NULL.
*/
struct ValueProfNode *(*GetValueData)(uint32_t ValueKind, uint32_t Site,
struct InstrProfValueData *Dst,
struct ValueProfNode *StartNode,
uint32_t N);
} VPDataReaderType;
/* Write profile data to destinitation. If SkipNameDataWrite is set to 1,
the name data is already in destintation, we just skip over it. */
int lprofWriteData(ProfDataWriter *Writer, VPDataReaderType *VPDataReader,
int SkipNameDataWrite);
int lprofWriteDataImpl(ProfDataWriter *Writer,
const __llvm_profile_data *DataBegin,
const __llvm_profile_data *DataEnd,
const uint64_t *CountersBegin,
const uint64_t *CountersEnd,
VPDataReaderType *VPDataReader, const char *NamesBegin,
const char *NamesEnd, int SkipNameDataWrite);
/* Merge value profile data pointed to by SrcValueProfData into
* in-memory profile counters pointed by to DstData. */
void lprofMergeValueProfData(struct ValueProfData *SrcValueProfData,
__llvm_profile_data *DstData);
VPDataReaderType *lprofGetVPDataReader();
/* Internal interface used by test to reset the max number of
* tracked values per value site to be \p MaxVals.
*/
void lprofSetMaxValsPerSite(uint32_t MaxVals);
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();
/*
* Return non zero value if the profile data has already been
* dumped to the file.
*/
unsigned lprofProfileDumped();
void lprofSetProfileDumped();
COMPILER_RT_VISIBILITY extern void (*FreeHook)(void *);
COMPILER_RT_VISIBILITY extern uint8_t *DynamicBufferIOBuffer;
COMPILER_RT_VISIBILITY extern uint32_t VPBufferSize;
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 *);
#endif

View File

@@ -0,0 +1,132 @@
/*===- InstrProfilingMerge.c - Profile in-process Merging ---------------===*\
|*
|* The LLVM Compiler Infrastructure
|*
|* This file is distributed under the University of Illinois Open Source
|* License. See LICENSE.TXT for details.
|*
|*===----------------------------------------------------------------------===*
|* This file defines the API needed for in-process merging of profile data
|* stored in memory buffer.
\*===---------------------------------------------------------------------===*/
#include "InstrProfiling.h"
#include "InstrProfilingInternal.h"
#include "InstrProfilingUtil.h"
#define INSTR_PROF_VALUE_PROF_DATA
#include "InstrProfData.inc"
COMPILER_RT_WEAK void (*VPMergeHook)(ValueProfData *,
__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. */
COMPILER_RT_VISIBILITY
int __llvm_profile_check_compatibility(const char *ProfileData,
uint64_t ProfileSize) {
/* Check profile header only for now */
__llvm_profile_header *Header = (__llvm_profile_header *)ProfileData;
__llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData;
SrcDataStart =
(__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header));
SrcDataEnd = SrcDataStart + Header->DataSize;
if (ProfileSize < sizeof(__llvm_profile_header))
return 1;
/* Check the header first. */
if (Header->Magic != __llvm_profile_get_magic() ||
Header->Version != __llvm_profile_get_version() ||
Header->DataSize !=
__llvm_profile_get_data_size(__llvm_profile_begin_data(),
__llvm_profile_end_data()) ||
Header->CountersSize != (uint64_t)(__llvm_profile_end_counters() -
__llvm_profile_begin_counters()) ||
Header->NamesSize != (uint64_t)(__llvm_profile_end_names() -
__llvm_profile_begin_names()) ||
Header->ValueKindLast != IPVK_Last)
return 1;
if (ProfileSize < sizeof(__llvm_profile_header) +
Header->DataSize * sizeof(__llvm_profile_data) +
Header->NamesSize + Header->CountersSize)
return 1;
for (SrcData = SrcDataStart,
DstData = (__llvm_profile_data *)__llvm_profile_begin_data();
SrcData < SrcDataEnd; ++SrcData, ++DstData) {
if (SrcData->NameRef != DstData->NameRef ||
SrcData->FuncHash != DstData->FuncHash ||
SrcData->NumCounters != DstData->NumCounters)
return 1;
}
/* Matched! */
return 0;
}
COMPILER_RT_VISIBILITY
void __llvm_profile_merge_from_buffer(const char *ProfileData,
uint64_t ProfileSize) {
__llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData;
__llvm_profile_header *Header = (__llvm_profile_header *)ProfileData;
uint64_t *SrcCountersStart;
const char *SrcNameStart;
ValueProfData *SrcValueProfDataStart, *SrcValueProfData;
SrcDataStart =
(__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header));
SrcDataEnd = SrcDataStart + Header->DataSize;
SrcCountersStart = (uint64_t *)SrcDataEnd;
SrcNameStart = (const char *)(SrcCountersStart + Header->CountersSize);
SrcValueProfDataStart =
(ValueProfData *)(SrcNameStart + Header->NamesSize +
__llvm_profile_get_num_padding_bytes(
Header->NamesSize));
for (SrcData = SrcDataStart,
DstData = (__llvm_profile_data *)__llvm_profile_begin_data(),
SrcValueProfData = SrcValueProfDataStart;
SrcData < SrcDataEnd; ++SrcData, ++DstData) {
uint64_t *SrcCounters;
uint64_t *DstCounters = (uint64_t *)DstData->CounterPtr;
unsigned I, NC, NVK = 0;
NC = SrcData->NumCounters;
SrcCounters = SrcCountersStart +
((size_t)SrcData->CounterPtr - Header->CountersDelta) /
sizeof(uint64_t);
for (I = 0; I < NC; I++)
DstCounters[I] += SrcCounters[I];
/* Now merge value profile data. */
if (!VPMergeHook)
continue;
for (I = 0; I <= IPVK_Last; I++)
NVK += (SrcData->NumValueSites[I] != 0);
if (!NVK)
continue;
VPMergeHook(SrcValueProfData, DstData);
SrcValueProfData = (ValueProfData *)((char *)SrcValueProfData +
SrcValueProfData->TotalSize);
}
}

View File

@@ -0,0 +1,41 @@
/*===- InstrProfilingMergeFile.c - Profile in-process Merging ------------===*\
|*
|* The LLVM Compiler Infrastructure
|*
|* This file is distributed under the University of Illinois Open Source
|* License. See LICENSE.TXT for details.
|*
|*===----------------------------------------------------------------------===
|* This file defines APIs needed to support in-process merging for profile data
|* stored in files.
\*===----------------------------------------------------------------------===*/
#include "InstrProfiling.h"
#include "InstrProfilingInternal.h"
#include "InstrProfilingUtil.h"
#define INSTR_PROF_VALUE_PROF_DATA
#include "InstrProfData.inc"
void (*VPMergeHook)(ValueProfData *,
__llvm_profile_data *) = &lprofMergeValueProfData;
/* Merge value profile data pointed to by SrcValueProfData into
* in-memory profile counters pointed by to DstData. */
void lprofMergeValueProfData(ValueProfData *SrcValueProfData,
__llvm_profile_data *DstData) {
unsigned I, S, V, C;
InstrProfValueData *VData;
ValueProfRecord *VR = getFirstValueProfRecord(SrcValueProfData);
for (I = 0; I < SrcValueProfData->NumValueKinds; I++) {
VData = getValueProfRecordValueData(VR);
for (S = 0; S < VR->NumValueSites; S++) {
uint8_t NV = VR->SiteCountArray[S];
for (V = 0; V < NV; V++) {
for (C = 0; C < VData[V].Count; C++)
__llvm_profile_instrument_target(VData[V].Value, DstData, S);
}
}
VR = getValueProfRecordNext(VR);
}
}

View File

@@ -0,0 +1,18 @@
/*===- InstrProfilingNameVar.c - profile name variable setup -------------===*\
|*
|* The LLVM Compiler Infrastructure
|*
|* This file is distributed under the University of Illinois Open Source
|* License. See LICENSE.TXT for details.
|*
\*===----------------------------------------------------------------------===*/
#include "InstrProfiling.h"
/* char __llvm_profile_filename[1]
*
* The runtime should only provide its own definition of this symbol when the
* user has not specified one. Set this up by moving the runtime's copy of this
* symbol to an object file within the archive.
*/
COMPILER_RT_WEAK char INSTR_PROF_PROFILE_NAME_VAR[1] = {0};

View File

@@ -0,0 +1,63 @@
/*===- InstrProfilingPlatformDarwin.c - Profile data on Darwin ------------===*\
|*
|* The LLVM Compiler Infrastructure
|*
|* This file is distributed under the University of Illinois Open Source
|* License. See LICENSE.TXT for details.
|*
\*===----------------------------------------------------------------------===*/
#include "InstrProfiling.h"
#if defined(__APPLE__)
/* Use linker magic to find the bounds of the Data section. */
COMPILER_RT_VISIBILITY
extern __llvm_profile_data
DataStart __asm("section$start$__DATA$" INSTR_PROF_DATA_SECT_NAME_STR);
COMPILER_RT_VISIBILITY
extern __llvm_profile_data
DataEnd __asm("section$end$__DATA$" INSTR_PROF_DATA_SECT_NAME_STR);
COMPILER_RT_VISIBILITY
extern char
NamesStart __asm("section$start$__DATA$" INSTR_PROF_NAME_SECT_NAME_STR);
COMPILER_RT_VISIBILITY
extern char NamesEnd __asm("section$end$__DATA$" INSTR_PROF_NAME_SECT_NAME_STR);
COMPILER_RT_VISIBILITY
extern uint64_t
CountersStart __asm("section$start$__DATA$" INSTR_PROF_CNTS_SECT_NAME_STR);
COMPILER_RT_VISIBILITY
extern uint64_t
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
const __llvm_profile_data *__llvm_profile_begin_data(void) {
return &DataStart;
}
COMPILER_RT_VISIBILITY
const __llvm_profile_data *__llvm_profile_end_data(void) { return &DataEnd; }
COMPILER_RT_VISIBILITY
const char *__llvm_profile_begin_names(void) { return &NamesStart; }
COMPILER_RT_VISIBILITY
const char *__llvm_profile_end_names(void) { return &NamesEnd; }
COMPILER_RT_VISIBILITY
uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart; }
COMPILER_RT_VISIBILITY
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

View File

@@ -0,0 +1,77 @@
/*===- InstrProfilingPlatformLinux.c - Profile data Linux platform ------===*\
|*
|* The LLVM Compiler Infrastructure
|*
|* This file is distributed under the University of Illinois Open Source
|* License. See LICENSE.TXT for details.
|*
\*===----------------------------------------------------------------------===*/
#if defined(__linux__) || defined(__FreeBSD__) || \
(defined(__sun__) && defined(__svr4__))
#include <stdlib.h>
#include "InstrProfiling.h"
#define PROF_DATA_START INSTR_PROF_SECT_START(INSTR_PROF_DATA_SECT_NAME)
#define PROF_DATA_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_DATA_SECT_NAME)
#define PROF_NAME_START INSTR_PROF_SECT_START(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_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
* generated by compiler instrumentation.
*/
extern __llvm_profile_data PROF_DATA_START COMPILER_RT_VISIBILITY;
extern __llvm_profile_data PROF_DATA_STOP COMPILER_RT_VISIBILITY;
extern uint64_t PROF_CNTS_START COMPILER_RT_VISIBILITY;
extern uint64_t PROF_CNTS_STOP COMPILER_RT_VISIBILITY;
extern char PROF_NAME_START 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. */
__llvm_profile_data
__prof_data_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_DATA_SECT_NAME_STR);
uint64_t
__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);
ValueProfNode __prof_vnodes_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_VNODES_SECT_NAME_STR);
COMPILER_RT_VISIBILITY const __llvm_profile_data *
__llvm_profile_begin_data(void) {
return &PROF_DATA_START;
}
COMPILER_RT_VISIBILITY const __llvm_profile_data *
__llvm_profile_end_data(void) {
return &PROF_DATA_STOP;
}
COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_names(void) {
return &PROF_NAME_START;
}
COMPILER_RT_VISIBILITY const char *__llvm_profile_end_names(void) {
return &PROF_NAME_STOP;
}
COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_begin_counters(void) {
return &PROF_CNTS_START;
}
COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_end_counters(void) {
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

View File

@@ -0,0 +1,95 @@
/*===- InstrProfilingPlatformOther.c - Profile data default platform ------===*\
|*
|* The LLVM Compiler Infrastructure
|*
|* This file is distributed under the University of Illinois Open Source
|* License. See LICENSE.TXT for details.
|*
\*===----------------------------------------------------------------------===*/
#if !defined(__APPLE__) && !defined(__linux__) && !defined(__FreeBSD__) && \
!(defined(__sun__) && defined(__svr4__))
#include <stdlib.h>
#include "InstrProfiling.h"
static const __llvm_profile_data *DataFirst = NULL;
static const __llvm_profile_data *DataLast = NULL;
static const char *NamesFirst = NULL;
static const char *NamesLast = NULL;
static uint64_t *CountersFirst = NULL;
static uint64_t *CountersLast = NULL;
static const void *getMinAddr(const void *A1, const void *A2) {
return A1 < A2 ? A1 : A2;
}
static const void *getMaxAddr(const void *A1, const void *A2) {
return A1 > A2 ? A1 : A2;
}
/*!
* \brief Register an instrumented function.
*
* Calls to this are emitted by clang with -fprofile-instr-generate. Such
* calls are only required (and only emitted) on targets where we haven't
* implemented linker magic to find the bounds of the sections.
*/
COMPILER_RT_VISIBILITY
void __llvm_profile_register_function(void *Data_) {
/* TODO: Only emit this function if we can't use linker magic. */
const __llvm_profile_data *Data = (__llvm_profile_data *)Data_;
if (!DataFirst) {
DataFirst = Data;
DataLast = Data + 1;
CountersFirst = Data->CounterPtr;
CountersLast = (uint64_t *)Data->CounterPtr + Data->NumCounters;
return;
}
DataFirst = (const __llvm_profile_data *)getMinAddr(DataFirst, Data);
CountersFirst = (uint64_t *)getMinAddr(CountersFirst, Data->CounterPtr);
DataLast = (const __llvm_profile_data *)getMaxAddr(DataLast, Data + 1);
CountersLast = (uint64_t *)getMaxAddr(
CountersLast, (uint64_t *)Data->CounterPtr + Data->NumCounters);
}
COMPILER_RT_VISIBILITY
void __llvm_profile_register_names_function(void *NamesStart,
uint64_t NamesSize) {
if (!NamesFirst) {
NamesFirst = (const char *)NamesStart;
NamesLast = (const char *)NamesStart + NamesSize;
return;
}
NamesFirst = (const char *)getMinAddr(NamesFirst, NamesStart);
NamesLast =
(const char *)getMaxAddr(NamesLast, (const char *)NamesStart + NamesSize);
}
COMPILER_RT_VISIBILITY
const __llvm_profile_data *__llvm_profile_begin_data(void) { return DataFirst; }
COMPILER_RT_VISIBILITY
const __llvm_profile_data *__llvm_profile_end_data(void) { return DataLast; }
COMPILER_RT_VISIBILITY
const char *__llvm_profile_begin_names(void) { return NamesFirst; }
COMPILER_RT_VISIBILITY
const char *__llvm_profile_end_names(void) { return NamesLast; }
COMPILER_RT_VISIBILITY
uint64_t *__llvm_profile_begin_counters(void) { return CountersFirst; }
COMPILER_RT_VISIBILITY
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

View File

@@ -0,0 +1,130 @@
/*===- InstrProfilingPort.h- Support library for PGO instrumentation ------===*\
|*
|* The LLVM Compiler Infrastructure
|*
|* This file is distributed under the University of Illinois Open Source
|* License. See LICENSE.TXT for details.
|*
\*===----------------------------------------------------------------------===*/
/* This header must be included after all others so it can provide fallback
definitions for stuff missing in system headers. */
#ifndef PROFILE_INSTRPROFILING_PORT_H_
#define PROFILE_INSTRPROFILING_PORT_H_
#ifdef _MSC_VER
#define COMPILER_RT_ALIGNAS(x) __declspec(align(x))
#define COMPILER_RT_VISIBILITY
/* FIXME: selectany does not have the same semantics as weak. */
#define COMPILER_RT_WEAK __declspec(selectany)
/* Need to include <windows.h> */
#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__
#define COMPILER_RT_ALIGNAS(x) __attribute__((aligned(x)))
#define COMPILER_RT_VISIBILITY __attribute__((visibility("hidden")))
#define COMPILER_RT_WEAK __attribute__((weak))
#define COMPILER_RT_ALLOCA __builtin_alloca
#define COMPILER_RT_FTRUNCATE(f,l) ftruncate(fileno(f),l)
#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)))
#endif
#define COMPILER_RT_MAX_HOSTLEN 128
#ifdef __ORBIS__
#define COMPILER_RT_GETHOSTNAME(Name, Len) ((void)(Name), (void)(Len), (-1))
#else
#define COMPILER_RT_GETHOSTNAME(Name, Len) lprofGetHostName(Name, Len)
#endif
#if COMPILER_RT_HAS_ATOMICS == 1
#ifdef _MSC_VER
#include <windows.h>
#if _MSC_VER < 1900
#define snprintf _snprintf
#endif
#if defined(_WIN64)
#define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \
(InterlockedCompareExchange64((LONGLONG volatile *)Ptr, (LONGLONG)NewV, \
(LONGLONG)OldV) == (LONGLONG)OldV)
#define COMPILER_RT_PTR_FETCH_ADD(DomType, PtrVar, PtrIncr) \
(DomType *)InterlockedExchangeAdd64((LONGLONG volatile *)&PtrVar, \
(LONGLONG)sizeof(DomType) * PtrIncr)
#else /* !defined(_WIN64) */
#define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \
(InterlockedCompareExchange((LONG volatile *)Ptr, (LONG)NewV, (LONG)OldV) == \
(LONG)OldV)
#define COMPILER_RT_PTR_FETCH_ADD(DomType, PtrVar, PtrIncr) \
(DomType *)InterlockedExchangeAdd((LONG volatile *)&PtrVar, \
(LONG)sizeof(DomType) * PtrIncr)
#endif
#else /* !defined(_MSC_VER) */
#define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \
__sync_bool_compare_and_swap(Ptr, OldV, NewV)
#define COMPILER_RT_PTR_FETCH_ADD(DomType, PtrVar, PtrIncr) \
(DomType *)__sync_fetch_and_add((long *)&PtrVar, sizeof(DomType) * PtrIncr)
#endif
#else /* COMPILER_RT_HAS_ATOMICS != 1 */
#include "InstrProfilingUtil.h"
#define COMPILER_RT_BOOL_CMPXCHG(Ptr, OldV, NewV) \
lprofBoolCmpXchg((void **)Ptr, OldV, NewV)
#define COMPILER_RT_PTR_FETCH_ADD(DomType, PtrVar, PtrIncr) \
(DomType *)lprofPtrFetchAdd((void **)&PtrVar, sizeof(DomType) * PtrIncr)
#endif
#if defined(_WIN32)
#define DIR_SEPARATOR '\\'
#define DIR_SEPARATOR_2 '/'
#else
#define DIR_SEPARATOR '/'
#endif
#ifndef DIR_SEPARATOR_2
#define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
#else /* DIR_SEPARATOR_2 */
#define IS_DIR_SEPARATOR(ch) \
(((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
#endif /* DIR_SEPARATOR_2 */
#define PROF_ERR(Format, ...) \
fprintf(stderr, "LLVM Profile Error: " Format, __VA_ARGS__);
#define PROF_WARN(Format, ...) \
fprintf(stderr, "LLVM Profile Warning: " Format, __VA_ARGS__);
#define PROF_NOTE(Format, ...) \
fprintf(stderr, "LLVM Profile Note: " Format, __VA_ARGS__);
#ifndef MAP_FILE
#define MAP_FILE 0
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
#if defined(__FreeBSD__)
#include <inttypes.h>
#include <sys/types.h>
#else /* defined(__FreeBSD__) */
#include <inttypes.h>
#include <stdint.h>
#endif /* defined(__FreeBSD__) && defined(__i386__) */
#endif /* PROFILE_INSTRPROFILING_PORT_H_ */

View File

@@ -0,0 +1,30 @@
//===- InstrProfilingRuntime.cpp - PGO runtime initialization -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
extern "C" {
#include "InstrProfiling.h"
/* int __llvm_profile_runtime */
COMPILER_RT_VISIBILITY int INSTR_PROF_PROFILE_RUNTIME_VAR;
}
namespace {
class RegisterRuntime {
public:
RegisterRuntime() {
__llvm_profile_register_write_file_atexit();
__llvm_profile_initialize_file();
}
};
RegisterRuntime Registration;
}

View File

@@ -0,0 +1,283 @@
/*===- InstrProfilingUtil.c - Support library for PGO instrumentation -----===*\
|*
|* The LLVM Compiler Infrastructure
|*
|* This file is distributed under the University of Illinois Open Source
|* License. See LICENSE.TXT for details.
|*
\*===----------------------------------------------------------------------===*/
#ifdef _WIN32
#include <direct.h>
#include <process.h>
#include <windows.h>
#include "WindowsMMap.h"
#else
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#endif
#ifdef COMPILER_RT_HAS_UNAME
#include <sys/utsname.h>
#endif
#include <stdlib.h>
#include <string.h>
#if defined(__linux__)
#include <signal.h>
#include <sys/prctl.h>
#endif
#include "InstrProfiling.h"
#include "InstrProfilingUtil.h"
COMPILER_RT_VISIBILITY
void __llvm_profile_recursive_mkdir(char *path) {
int i;
for (i = 1; path[i] != '\0'; ++i) {
char save = path[i];
if (!IS_DIR_SEPARATOR(path[i]))
continue;
path[i] = '\0';
#ifdef _WIN32
_mkdir(path);
#else
mkdir(path, 0755); /* Some of these will fail, ignore it. */
#endif
path[i] = save;
}
}
#if COMPILER_RT_HAS_ATOMICS != 1
COMPILER_RT_VISIBILITY
uint32_t lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV) {
void *R = *Ptr;
if (R == OldV) {
*Ptr = NewV;
return 1;
}
return 0;
}
COMPILER_RT_VISIBILITY
void *lprofPtrFetchAdd(void **Mem, long ByteIncr) {
void *Old = *Mem;
*((char **)Mem) += ByteIncr;
return Old;
}
#endif
#ifdef _MSC_VER
COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
WCHAR Buffer[COMPILER_RT_MAX_HOSTLEN];
DWORD BufferSize = sizeof(Buffer);
BOOL Result =
GetComputerNameExW(ComputerNameDnsFullyQualified, Buffer, &BufferSize);
if (!Result)
return -1;
if (WideCharToMultiByte(CP_UTF8, 0, Buffer, -1, Name, Len, NULL, NULL) == 0)
return -1;
return 0;
}
#elif defined(COMPILER_RT_HAS_UNAME)
COMPILER_RT_VISIBILITY int lprofGetHostName(char *Name, int Len) {
struct utsname N;
int R = uname(&N);
if (R >= 0) {
strncpy(Name, N.nodename, Len);
return 0;
}
return R;
}
#endif
COMPILER_RT_VISIBILITY int lprofLockFd(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;
while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
if (errno != EINTR) {
if (errno == ENOLCK) {
return -1;
}
break;
}
}
return 0;
#else
flock(fd, LOCK_EX);
return 0;
#endif
}
COMPILER_RT_VISIBILITY int lprofUnlockFd(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_UNLCK;
while (fcntl(fd, F_SETLKW, &s_flock) == -1) {
if (errno != EINTR) {
if (errno == ENOLCK) {
return -1;
}
break;
}
}
return 0;
#else
flock(fd, LOCK_UN);
return 0;
#endif
}
COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) {
FILE *f;
int fd;
#ifdef COMPILER_RT_HAS_FCNTL_LCK
fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
if (fd < 0)
return NULL;
if (lprofLockFd(fd) != 0)
PROF_WARN("Data may be corrupted during profile merging : %s\n",
"Fail to obtain file lock due to system limit.");
f = fdopen(fd, "r+b");
#elif defined(_WIN32)
// FIXME: Use the wide variants to handle Unicode filenames.
HANDLE h = CreateFileA(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;
}
COMPILER_RT_VISIBILITY const char *lprofGetPathPrefix(int *PrefixStrip,
size_t *PrefixLen) {
const char *Prefix = getenv("GCOV_PREFIX");
const char *PrefixStripStr = getenv("GCOV_PREFIX_STRIP");
*PrefixLen = 0;
*PrefixStrip = 0;
if (Prefix == NULL || Prefix[0] == '\0')
return NULL;
if (PrefixStripStr) {
*PrefixStrip = atoi(PrefixStripStr);
/* Negative GCOV_PREFIX_STRIP values are ignored */
if (*PrefixStrip < 0)
*PrefixStrip = 0;
} else {
*PrefixStrip = 0;
}
*PrefixLen = strlen(Prefix);
return Prefix;
}
COMPILER_RT_VISIBILITY void
lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix,
size_t PrefixLen, int PrefixStrip) {
const char *Ptr;
int Level;
const char *StrippedPathStr = PathStr;
for (Level = 0, Ptr = PathStr + 1; Level < PrefixStrip; ++Ptr) {
if (*Ptr == '\0')
break;
if (!IS_DIR_SEPARATOR(*Ptr))
continue;
StrippedPathStr = Ptr;
++Level;
}
memcpy(Dest, Prefix, PrefixLen);
if (!IS_DIR_SEPARATOR(Prefix[PrefixLen - 1]))
Dest[PrefixLen++] = DIR_SEPARATOR;
memcpy(Dest + PrefixLen, StrippedPathStr, strlen(StrippedPathStr) + 1);
}
COMPILER_RT_VISIBILITY const char *
lprofFindFirstDirSeparator(const char *Path) {
const char *Sep;
Sep = strchr(Path, DIR_SEPARATOR);
if (Sep)
return Sep;
#if defined(DIR_SEPARATOR_2)
Sep = strchr(Path, DIR_SEPARATOR_2);
#endif
return Sep;
}
COMPILER_RT_VISIBILITY const char *lprofFindLastDirSeparator(const char *Path) {
const char *Sep;
Sep = strrchr(Path, DIR_SEPARATOR);
if (Sep)
return Sep;
#if defined(DIR_SEPARATOR_2)
Sep = strrchr(Path, DIR_SEPARATOR_2);
#endif
return Sep;
}
COMPILER_RT_VISIBILITY int lprofSuspendSigKill() {
#if defined(__linux__)
int PDeachSig = 0;
/* Temporarily suspend getting SIGKILL upon exit of the parent process. */
if (prctl(PR_GET_PDEATHSIG, &PDeachSig) == 0 && PDeachSig == SIGKILL)
prctl(PR_SET_PDEATHSIG, 0);
return (PDeachSig == SIGKILL);
#else
return 0;
#endif
}
COMPILER_RT_VISIBILITY void lprofRestoreSigKill() {
#if defined(__linux__)
prctl(PR_SET_PDEATHSIG, SIGKILL);
#endif
}

View File

@@ -0,0 +1,65 @@
/*===- InstrProfilingUtil.h - Support library for PGO instrumentation -----===*\
|*
|* The LLVM Compiler Infrastructure
|*
|* This file is distributed under the University of Illinois Open Source
|* License. See LICENSE.TXT for details.
|*
\*===----------------------------------------------------------------------===*/
#ifndef PROFILE_INSTRPROFILINGUTIL_H
#define PROFILE_INSTRPROFILINGUTIL_H
#include <stddef.h>
#include <stdio.h>
/*! \brief Create a directory tree. */
void __llvm_profile_recursive_mkdir(char *Pathname);
int lprofLockFd(int fd);
int lprofUnlockFd(int fd);
/*! 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. */
#if __ORBIS__
static inline char *getenv(const char *name) { return NULL; }
#endif /* #if __ORBIS__ */
/* GCOV_PREFIX and GCOV_PREFIX_STRIP support */
/* Return the path prefix specified by GCOV_PREFIX environment variable.
* If GCOV_PREFIX_STRIP is also specified, the strip level (integer value)
* is returned via \c *PrefixStrip. The prefix length is stored in *PrefixLen.
*/
const char *lprofGetPathPrefix(int *PrefixStrip, size_t *PrefixLen);
/* Apply the path prefix specified in \c Prefix to path string in \c PathStr,
* and store the result to buffer pointed to by \c Buffer. If \c PrefixStrip
* is not zero, path prefixes are stripped from \c PathStr (the level of
* stripping is specified by \c PrefixStrip) before \c Prefix is added.
*/
void lprofApplyPathPrefix(char *Dest, const char *PathStr, const char *Prefix,
size_t PrefixLen, int PrefixStrip);
/* Returns a pointer to the first occurrence of \c DIR_SEPARATOR char in
* the string \c Path, or NULL if the char is not found. */
const char *lprofFindFirstDirSeparator(const char *Path);
/* Returns a pointer to the last occurrence of \c DIR_SEPARATOR char in
* the string \c Path, or NULL if the char is not found. */
const char *lprofFindLastDirSeparator(const char *Path);
int lprofGetHostName(char *Name, int Len);
unsigned lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV);
void *lprofPtrFetchAdd(void **Mem, long ByteIncr);
/* Temporarily suspend SIGKILL. Return value of 1 means a restore is needed.
* Other return values mean no restore is needed.
*/
int lprofSuspendSigKill();
/* Restore previously suspended SIGKILL. */
void lprofRestoreSigKill();
#endif /* PROFILE_INSTRPROFILINGUTIL_H */

View File

@@ -0,0 +1,358 @@
/*===- InstrProfilingValue.c - Support library for PGO instrumentation ----===*\
|*
|* The LLVM Compiler Infrastructure
|*
|* This file is distributed under the University of Illinois Open Source
|* License. See LICENSE.TXT for details.
|*
\*===----------------------------------------------------------------------===*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "InstrProfiling.h"
#include "InstrProfilingInternal.h"
#include "InstrProfilingUtil.h"
#define INSTR_PROF_VALUE_PROF_DATA
#define INSTR_PROF_COMMON_API_IMPL
#include "InstrProfData.inc"
static int hasStaticCounters = 1;
static int OutOfNodesWarnings = 0;
static int hasNonDefaultValsPerSite = 0;
#define INSTR_PROF_MAX_VP_WARNS 10
#define INSTR_PROF_DEFAULT_NUM_VAL_PER_SITE 16
#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 =
INSTR_PROF_DEFAULT_NUM_VAL_PER_SITE;
COMPILER_RT_VISIBILITY void lprofSetupValueProfiler() {
const char *Str = 0;
Str = getenv("LLVM_VP_MAX_NUM_VALS_PER_SITE");
if (Str && Str[0]) {
VPMaxNumValsPerSite = atoi(Str);
hasNonDefaultValsPerSite = 1;
}
if (VPMaxNumValsPerSite > INSTR_PROF_MAX_NUM_VAL_PER_SITE)
VPMaxNumValsPerSite = INSTR_PROF_MAX_NUM_VAL_PER_SITE;
}
COMPILER_RT_VISIBILITY void lprofSetMaxValsPerSite(uint32_t MaxVals) {
VPMaxNumValsPerSite = MaxVals;
hasNonDefaultValsPerSite = 1;
}
/* This method is only used in value profiler mock testing. */
COMPILER_RT_VISIBILITY void
__llvm_profile_set_num_value_sites(__llvm_profile_data *Data,
uint32_t ValueKind, uint16_t NumValueSites) {
*((uint16_t *)&Data->NumValueSites[ValueKind]) = NumValueSites;
}
/* This method is only used in value profiler mock testing. */
COMPILER_RT_VISIBILITY const __llvm_profile_data *
__llvm_profile_iterate_data(const __llvm_profile_data *Data) {
return Data + 1;
}
/* This method is only used in value profiler mock testing. */
COMPILER_RT_VISIBILITY void *
__llvm_get_function_addr(const __llvm_profile_data *Data) {
return Data->FunctionPointer;
}
/* Allocate an array that holds the pointers to the linked lists of
* value profile counter nodes. The number of element of the array
* is the total number of value profile sites instrumented. Returns
* 0 if allocation fails.
*/
static int allocateValueProfileCounters(__llvm_profile_data *Data) {
uint64_t NumVSites = 0;
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)
NumVSites += Data->NumValueSites[VKI];
ValueProfNode **Mem =
(ValueProfNode **)calloc(NumVSites, sizeof(ValueProfNode *));
if (!Mem)
return 0;
if (!COMPILER_RT_BOOL_CMPXCHG(&Data->Values, 0, Mem)) {
free(Mem);
return 0;
}
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
__llvm_profile_instrument_target(uint64_t TargetValue, void *Data,
uint32_t CounterIndex) {
__llvm_profile_data *PData = (__llvm_profile_data *)Data;
if (!PData)
return;
if (!PData->Values) {
if (!allocateValueProfileCounters(PData))
return;
}
ValueProfNode **ValueCounters = (ValueProfNode **)PData->Values;
ValueProfNode *PrevVNode = NULL;
ValueProfNode *MinCountVNode = NULL;
ValueProfNode *CurVNode = ValueCounters[CounterIndex];
uint64_t MinCount = UINT64_MAX;
uint8_t VDataCount = 0;
while (CurVNode) {
if (TargetValue == CurVNode->Value) {
CurVNode->Count++;
return;
}
if (CurVNode->Count < MinCount) {
MinCount = CurVNode->Count;
MinCountVNode = CurVNode;
}
PrevVNode = CurVNode;
CurVNode = CurVNode->Next;
++VDataCount;
}
if (VDataCount >= VPMaxNumValsPerSite) {
/* Bump down the min count node's count. If it reaches 0,
* evict it. This eviction/replacement policy makes hot
* targets more sticky while cold targets less so. In other
* words, it makes it less likely for the hot targets to be
* prematurally evicted during warmup/establishment period,
* when their counts are still low. In a special case when
* the number of values tracked is reduced to only one, this
* policy will guarantee that the dominating target with >50%
* total count will survive in the end. Note that this scheme
* allows the runtime to track the min count node in an adaptive
* manner. It can correct previous mistakes and eventually
* lock on a cold target that is alread in stable state.
*
* In very rare cases, this replacement scheme may still lead
* to target loss. For instance, out of \c N value slots, \c N-1
* slots are occupied by luke warm targets during the warmup
* period and the remaining one slot is competed by two or more
* very hot targets. If those hot targets occur in an interleaved
* way, none of them will survive (gain enough weight to throw out
* other established entries) due to the ping-pong effect.
* To handle this situation, user can choose to increase the max
* number of tracked values per value site. Alternatively, a more
* expensive eviction mechanism can be implemented. It requires
* the runtime to track the total number of evictions per-site.
* When the total number of evictions reaches certain threshold,
* the runtime can wipe out more than one lowest count entries
* to give space for hot targets.
*/
if (!MinCountVNode->Count || !(--MinCountVNode->Count)) {
CurVNode = MinCountVNode;
CurVNode->Value = TargetValue;
CurVNode->Count++;
}
return;
}
CurVNode = allocateOneNode(PData, CounterIndex, TargetValue);
if (!CurVNode)
return;
CurVNode->Value = TargetValue;
CurVNode->Count++;
uint32_t Success = 0;
if (!ValueCounters[CounterIndex])
Success =
COMPILER_RT_BOOL_CMPXCHG(&ValueCounters[CounterIndex], 0, CurVNode);
else if (PrevVNode && !PrevVNode->Next)
Success = COMPILER_RT_BOOL_CMPXCHG(&(PrevVNode->Next), 0, CurVNode);
if (!Success && !hasStaticCounters) {
free(CurVNode);
return;
}
}
/*
* The target values are partitioned into multiple regions/ranges. There is one
* contiguous region which is precise -- every value in the range is tracked
* individually. A value outside the precise region will be collapsed into one
* value depending on the region it falls in.
*
* There are three regions:
* 1. (-inf, PreciseRangeStart) and (PreciseRangeLast, LargeRangeValue) belong
* to one region -- all values here should be mapped to one value of
* "PreciseRangeLast + 1".
* 2. [PreciseRangeStart, PreciseRangeLast]
* 3. Large values: [LargeValue, +inf) maps to one value of LargeValue.
*
* The range for large values is optional. The default value of INT64_MIN
* indicates it is not specified.
*/
COMPILER_RT_VISIBILITY void __llvm_profile_instrument_range(
uint64_t TargetValue, void *Data, uint32_t CounterIndex,
int64_t PreciseRangeStart, int64_t PreciseRangeLast, int64_t LargeValue) {
if (LargeValue != INT64_MIN && (int64_t)TargetValue >= LargeValue)
TargetValue = LargeValue;
else if ((int64_t)TargetValue < PreciseRangeStart ||
(int64_t)TargetValue > PreciseRangeLast)
TargetValue = PreciseRangeLast + 1;
__llvm_profile_instrument_target(TargetValue, Data, CounterIndex);
}
/*
* A wrapper struct that represents value profile runtime data.
* Like InstrProfRecord class which is used by profiling host tools,
* ValueProfRuntimeRecord also implements the abstract intefaces defined in
* ValueProfRecordClosure so that the runtime data can be serialized using
* shared C implementation.
*/
typedef struct ValueProfRuntimeRecord {
const __llvm_profile_data *Data;
ValueProfNode **NodesKind[IPVK_Last + 1];
uint8_t **SiteCountArray;
} ValueProfRuntimeRecord;
/* ValueProfRecordClosure Interface implementation. */
static uint32_t getNumValueSitesRT(const void *R, uint32_t VK) {
return ((const ValueProfRuntimeRecord *)R)->Data->NumValueSites[VK];
}
static uint32_t getNumValueDataRT(const void *R, uint32_t VK) {
uint32_t S = 0, I;
const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R;
if (Record->SiteCountArray[VK] == INSTR_PROF_NULLPTR)
return 0;
for (I = 0; I < Record->Data->NumValueSites[VK]; I++)
S += Record->SiteCountArray[VK][I];
return S;
}
static uint32_t getNumValueDataForSiteRT(const void *R, uint32_t VK,
uint32_t S) {
const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R;
return Record->SiteCountArray[VK][S];
}
static ValueProfRuntimeRecord RTRecord;
static ValueProfRecordClosure RTRecordClosure = {
&RTRecord, INSTR_PROF_NULLPTR, /* GetNumValueKinds */
getNumValueSitesRT, getNumValueDataRT, getNumValueDataForSiteRT,
INSTR_PROF_NULLPTR, /* RemapValueData */
INSTR_PROF_NULLPTR, /* GetValueForSite, */
INSTR_PROF_NULLPTR /* AllocValueProfData */
};
static uint32_t
initializeValueProfRuntimeRecord(const __llvm_profile_data *Data,
uint8_t *SiteCountArray[]) {
unsigned I, J, S = 0, NumValueKinds = 0;
ValueProfNode **Nodes = (ValueProfNode **)Data->Values;
RTRecord.Data = Data;
RTRecord.SiteCountArray = SiteCountArray;
for (I = 0; I <= IPVK_Last; I++) {
uint16_t N = Data->NumValueSites[I];
if (!N)
continue;
NumValueKinds++;
RTRecord.NodesKind[I] = Nodes ? &Nodes[S] : INSTR_PROF_NULLPTR;
for (J = 0; J < N; J++) {
/* Compute value count for each site. */
uint32_t C = 0;
ValueProfNode *Site =
Nodes ? RTRecord.NodesKind[I][J] : INSTR_PROF_NULLPTR;
while (Site) {
C++;
Site = Site->Next;
}
if (C > UCHAR_MAX)
C = UCHAR_MAX;
RTRecord.SiteCountArray[I][J] = C;
}
S += N;
}
return NumValueKinds;
}
static ValueProfNode *getNextNValueData(uint32_t VK, uint32_t Site,
InstrProfValueData *Dst,
ValueProfNode *StartNode, uint32_t N) {
unsigned I;
ValueProfNode *VNode = StartNode ? StartNode : RTRecord.NodesKind[VK][Site];
for (I = 0; I < N; I++) {
Dst[I].Value = VNode->Value;
Dst[I].Count = VNode->Count;
VNode = VNode->Next;
}
return VNode;
}
static uint32_t getValueProfDataSizeWrapper(void) {
return getValueProfDataSize(&RTRecordClosure);
}
static uint32_t getNumValueDataForSiteWrapper(uint32_t VK, uint32_t S) {
return getNumValueDataForSiteRT(&RTRecord, VK, S);
}
static VPDataReaderType TheVPDataReader = {
initializeValueProfRuntimeRecord, getValueProfRecordHeaderSize,
getFirstValueProfRecord, getNumValueDataForSiteWrapper,
getValueProfDataSizeWrapper, getNextNValueData};
COMPILER_RT_VISIBILITY VPDataReaderType *lprofGetVPDataReader() {
return &TheVPDataReader;
}

View File

@@ -0,0 +1,287 @@
/*===- InstrProfilingWriter.c - Write instrumentation to a file or buffer -===*\
|*
|* The LLVM Compiler Infrastructure
|*
|* This file is distributed under the University of Illinois Open Source
|* License. See LICENSE.TXT for details.
|*
\*===----------------------------------------------------------------------===*/
#ifdef _MSC_VER
/* For _alloca */
#include <malloc.h>
#endif
#include <string.h>
#include "InstrProfiling.h"
#include "InstrProfilingInternal.h"
#define INSTR_PROF_VALUE_PROF_DATA
#include "InstrProfData.inc"
COMPILER_RT_VISIBILITY void (*FreeHook)(void *) = NULL;
static ProfBufferIO TheBufferIO;
#define VP_BUFFER_SIZE 8 * 1024
static uint8_t BufferIOBuffer[VP_BUFFER_SIZE];
static InstrProfValueData VPDataArray[16];
static uint32_t VPDataArraySize = sizeof(VPDataArray) / sizeof(*VPDataArray);
COMPILER_RT_VISIBILITY uint8_t *DynamicBufferIOBuffer = 0;
COMPILER_RT_VISIBILITY uint32_t VPBufferSize = 0;
/* The buffer writer is reponsponsible in keeping writer state
* across the call.
*/
COMPILER_RT_VISIBILITY uint32_t lprofBufferWriter(ProfDataWriter *This,
ProfDataIOVec *IOVecs,
uint32_t NumIOVecs) {
uint32_t I;
char **Buffer = (char **)&This->WriterCtx;
for (I = 0; I < NumIOVecs; I++) {
size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm;
if (IOVecs[I].Data)
memcpy(*Buffer, IOVecs[I].Data, Length);
*Buffer += Length;
}
return 0;
}
static void llvmInitBufferIO(ProfBufferIO *BufferIO, ProfDataWriter *FileWriter,
uint8_t *Buffer, uint32_t BufferSz) {
BufferIO->FileWriter = FileWriter;
BufferIO->OwnFileWriter = 0;
BufferIO->BufferStart = Buffer;
BufferIO->BufferSz = BufferSz;
BufferIO->CurOffset = 0;
}
COMPILER_RT_VISIBILITY ProfBufferIO *
lprofCreateBufferIO(ProfDataWriter *FileWriter) {
uint8_t *Buffer = DynamicBufferIOBuffer;
uint32_t BufferSize = VPBufferSize;
if (!Buffer) {
Buffer = &BufferIOBuffer[0];
BufferSize = sizeof(BufferIOBuffer);
}
llvmInitBufferIO(&TheBufferIO, FileWriter, Buffer, BufferSize);
return &TheBufferIO;
}
COMPILER_RT_VISIBILITY void lprofDeleteBufferIO(ProfBufferIO *BufferIO) {
if (BufferIO->OwnFileWriter)
FreeHook(BufferIO->FileWriter);
if (DynamicBufferIOBuffer) {
FreeHook(DynamicBufferIOBuffer);
DynamicBufferIOBuffer = 0;
VPBufferSize = 0;
}
}
COMPILER_RT_VISIBILITY int
lprofBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size) {
/* Buffer is not large enough, it is time to flush. */
if (Size + BufferIO->CurOffset > BufferIO->BufferSz) {
if (lprofBufferIOFlush(BufferIO) != 0)
return -1;
}
/* Special case, bypass the buffer completely. */
ProfDataIOVec IO[] = {{Data, sizeof(uint8_t), Size}};
if (Size > BufferIO->BufferSz) {
if (BufferIO->FileWriter->Write(BufferIO->FileWriter, IO, 1))
return -1;
} else {
/* Write the data to buffer */
uint8_t *Buffer = BufferIO->BufferStart + BufferIO->CurOffset;
ProfDataWriter BufferWriter;
initBufferWriter(&BufferWriter, (char *)Buffer);
lprofBufferWriter(&BufferWriter, IO, 1);
BufferIO->CurOffset =
(uint8_t *)BufferWriter.WriterCtx - BufferIO->BufferStart;
}
return 0;
}
COMPILER_RT_VISIBILITY int lprofBufferIOFlush(ProfBufferIO *BufferIO) {
if (BufferIO->CurOffset) {
ProfDataIOVec IO[] = {
{BufferIO->BufferStart, sizeof(uint8_t), BufferIO->CurOffset}};
if (BufferIO->FileWriter->Write(BufferIO->FileWriter, IO, 1))
return -1;
BufferIO->CurOffset = 0;
}
return 0;
}
/* Write out value profile data for function specified with \c Data.
* The implementation does not use the method \c serializeValueProfData
* which depends on dynamic memory allocation. In this implementation,
* value profile data is written out to \c BufferIO piecemeal.
*/
static int writeOneValueProfData(ProfBufferIO *BufferIO,
VPDataReaderType *VPDataReader,
const __llvm_profile_data *Data) {
unsigned I, NumValueKinds = 0;
ValueProfData VPHeader;
uint8_t *SiteCountArray[IPVK_Last + 1];
for (I = 0; I <= IPVK_Last; I++) {
if (!Data->NumValueSites[I])
SiteCountArray[I] = 0;
else {
uint32_t Sz =
VPDataReader->GetValueProfRecordHeaderSize(Data->NumValueSites[I]) -
offsetof(ValueProfRecord, SiteCountArray);
/* Only use alloca for this small byte array to avoid excessive
* stack growth. */
SiteCountArray[I] = (uint8_t *)COMPILER_RT_ALLOCA(Sz);
memset(SiteCountArray[I], 0, Sz);
}
}
/* If NumValueKinds returned is 0, there is nothing to write, report
success and return. This should match the raw profile reader's behavior. */
if (!(NumValueKinds = VPDataReader->InitRTRecord(Data, SiteCountArray)))
return 0;
/* First write the header structure. */
VPHeader.TotalSize = VPDataReader->GetValueProfDataSize();
VPHeader.NumValueKinds = NumValueKinds;
if (lprofBufferIOWrite(BufferIO, (const uint8_t *)&VPHeader,
sizeof(ValueProfData)))
return -1;
/* Make sure nothing else needs to be written before value profile
* records. */
if ((void *)VPDataReader->GetFirstValueProfRecord(&VPHeader) !=
(void *)(&VPHeader + 1))
return -1;
/* Write out the value profile record for each value kind
* one by one. */
for (I = 0; I <= IPVK_Last; I++) {
uint32_t J;
ValueProfRecord RecordHeader;
/* The size of the value prof record header without counting the
* site count array .*/
uint32_t RecordHeaderSize = offsetof(ValueProfRecord, SiteCountArray);
uint32_t SiteCountArraySize;
if (!Data->NumValueSites[I])
continue;
/* Write out the record header. */
RecordHeader.Kind = I;
RecordHeader.NumValueSites = Data->NumValueSites[I];
if (lprofBufferIOWrite(BufferIO, (const uint8_t *)&RecordHeader,
RecordHeaderSize))
return -1;
/* Write out the site value count array including padding space. */
SiteCountArraySize =
VPDataReader->GetValueProfRecordHeaderSize(Data->NumValueSites[I]) -
RecordHeaderSize;
if (lprofBufferIOWrite(BufferIO, SiteCountArray[I], SiteCountArraySize))
return -1;
/* Write out the value profile data for each value site. */
for (J = 0; J < Data->NumValueSites[I]; J++) {
uint32_t NRead, NRemain;
ValueProfNode *NextStartNode = 0;
NRemain = VPDataReader->GetNumValueDataForSite(I, J);
if (!NRemain)
continue;
/* Read and write out value data in small chunks till it is done. */
do {
NRead = (NRemain > VPDataArraySize ? VPDataArraySize : NRemain);
NextStartNode =
VPDataReader->GetValueData(I, /* ValueKind */
J, /* Site */
&VPDataArray[0], NextStartNode, NRead);
if (lprofBufferIOWrite(BufferIO, (const uint8_t *)&VPDataArray[0],
NRead * sizeof(InstrProfValueData)))
return -1;
NRemain -= NRead;
} while (NRemain != 0);
}
}
/* All done report success. */
return 0;
}
static int writeValueProfData(ProfDataWriter *Writer,
VPDataReaderType *VPDataReader,
const __llvm_profile_data *DataBegin,
const __llvm_profile_data *DataEnd) {
ProfBufferIO *BufferIO;
const __llvm_profile_data *DI = 0;
if (!VPDataReader)
return 0;
BufferIO = lprofCreateBufferIO(Writer);
for (DI = DataBegin; DI < DataEnd; DI++) {
if (writeOneValueProfData(BufferIO, VPDataReader, DI))
return -1;
}
if (lprofBufferIOFlush(BufferIO) != 0)
return -1;
lprofDeleteBufferIO(BufferIO);
return 0;
}
COMPILER_RT_VISIBILITY int lprofWriteData(ProfDataWriter *Writer,
VPDataReaderType *VPDataReader,
int SkipNameDataWrite) {
/* Match logic in __llvm_profile_write_buffer(). */
const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
const uint64_t *CountersBegin = __llvm_profile_begin_counters();
const uint64_t *CountersEnd = __llvm_profile_end_counters();
const char *NamesBegin = __llvm_profile_begin_names();
const char *NamesEnd = __llvm_profile_end_names();
return lprofWriteDataImpl(Writer, DataBegin, DataEnd, CountersBegin,
CountersEnd, VPDataReader, NamesBegin, NamesEnd,
SkipNameDataWrite);
}
COMPILER_RT_VISIBILITY int
lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin,
const __llvm_profile_data *DataEnd,
const uint64_t *CountersBegin, const uint64_t *CountersEnd,
VPDataReaderType *VPDataReader, const char *NamesBegin,
const char *NamesEnd, int SkipNameDataWrite) {
/* Calculate size of sections. */
const uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
const uint64_t CountersSize = CountersEnd - CountersBegin;
const uint64_t NamesSize = NamesEnd - NamesBegin;
const uint64_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize);
/* Enough zeroes for padding. */
const char Zeroes[sizeof(uint64_t)] = {0};
/* Create the header. */
__llvm_profile_header Header;
if (!DataSize)
return 0;
/* Initialize header structure. */
#define INSTR_PROF_RAW_HEADER(Type, Name, Init) Header.Name = Init;
#include "InstrProfData.inc"
/* Write the data. */
ProfDataIOVec IOVec[] = {
{&Header, sizeof(__llvm_profile_header), 1},
{DataBegin, sizeof(__llvm_profile_data), DataSize},
{CountersBegin, sizeof(uint64_t), CountersSize},
{SkipNameDataWrite ? NULL : NamesBegin, sizeof(uint8_t), NamesSize},
{Zeroes, sizeof(uint8_t), Padding}};
if (Writer->Write(Writer, IOVec, sizeof(IOVec) / sizeof(*IOVec)))
return -1;
return writeValueProfData(Writer, VPDataReader, DataBegin, DataEnd);
}

Some files were not shown because too many files have changed in this diff Show More