2015-11-19 05:08:03 +08:00
|
|
|
/*===- 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.
|
|
|
|
|*
|
|
|
|
\*===----------------------------------------------------------------------===*/
|
|
|
|
|
|
|
|
#include "InstrProfiling.h"
|
|
|
|
#include "InstrProfilingInternal.h"
|
2015-12-23 02:57:15 +08:00
|
|
|
#include <string.h>
|
|
|
|
|
2015-12-29 15:13:59 +08:00
|
|
|
#define INSTR_PROF_VALUE_PROF_DATA
|
|
|
|
#include "InstrProfData.inc"
|
2016-05-10 03:01:19 +08:00
|
|
|
COMPILER_RT_VISIBILITY void (*FreeHook)(void *) = NULL;
|
|
|
|
COMPILER_RT_VISIBILITY void *(*CallocHook)(size_t, size_t) = NULL;
|
2015-12-29 15:13:59 +08:00
|
|
|
uint32_t VPBufferSize = 0;
|
|
|
|
|
2015-12-23 02:57:15 +08:00
|
|
|
/* The buffer writer is reponsponsible in keeping writer state
|
|
|
|
* across the call.
|
|
|
|
*/
|
2016-03-06 12:18:13 +08:00
|
|
|
COMPILER_RT_VISIBILITY uint32_t lprofBufferWriter(ProfDataIOVec *IOVecs,
|
|
|
|
uint32_t NumIOVecs,
|
|
|
|
void **WriterCtx) {
|
2015-12-23 02:57:15 +08:00
|
|
|
uint32_t I;
|
|
|
|
char **Buffer = (char **)WriterCtx;
|
|
|
|
for (I = 0; I < NumIOVecs; I++) {
|
|
|
|
size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm;
|
|
|
|
memcpy(*Buffer, IOVecs[I].Data, Length);
|
|
|
|
*Buffer += Length;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2015-11-19 05:08:03 +08:00
|
|
|
|
2015-12-30 07:54:41 +08:00
|
|
|
static void llvmInitBufferIO(ProfBufferIO *BufferIO, WriterCallback FileWriter,
|
|
|
|
void *File, uint8_t *Buffer, uint32_t BufferSz) {
|
|
|
|
BufferIO->File = File;
|
|
|
|
BufferIO->FileWriter = FileWriter;
|
|
|
|
BufferIO->BufferStart = Buffer;
|
|
|
|
BufferIO->BufferSz = BufferSz;
|
|
|
|
BufferIO->CurOffset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
COMPILER_RT_VISIBILITY ProfBufferIO *
|
2016-03-06 12:18:13 +08:00
|
|
|
lprofCreateBufferIO(WriterCallback FileWriter, void *File, uint32_t BufferSz) {
|
2015-12-30 07:54:41 +08:00
|
|
|
ProfBufferIO *BufferIO = (ProfBufferIO *)CallocHook(1, sizeof(ProfBufferIO));
|
|
|
|
uint8_t *Buffer = (uint8_t *)CallocHook(1, BufferSz);
|
|
|
|
if (!Buffer) {
|
|
|
|
FreeHook(BufferIO);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
llvmInitBufferIO(BufferIO, FileWriter, File, Buffer, BufferSz);
|
|
|
|
return BufferIO;
|
|
|
|
}
|
|
|
|
|
2016-03-06 12:18:13 +08:00
|
|
|
COMPILER_RT_VISIBILITY void lprofDeleteBufferIO(ProfBufferIO *BufferIO) {
|
2015-12-30 07:54:41 +08:00
|
|
|
FreeHook(BufferIO->BufferStart);
|
|
|
|
FreeHook(BufferIO);
|
|
|
|
}
|
|
|
|
|
|
|
|
COMPILER_RT_VISIBILITY int
|
2016-03-06 12:18:13 +08:00
|
|
|
lprofBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size) {
|
2015-12-30 07:54:41 +08:00
|
|
|
/* Buffer is not large enough, it is time to flush. */
|
|
|
|
if (Size + BufferIO->CurOffset > BufferIO->BufferSz) {
|
2016-03-06 12:18:13 +08:00
|
|
|
if (lprofBufferIOFlush(BufferIO) != 0)
|
|
|
|
return -1;
|
2015-12-30 07:54:41 +08:00
|
|
|
}
|
|
|
|
/* Special case, bypass the buffer completely. */
|
|
|
|
ProfDataIOVec IO[] = {{Data, sizeof(uint8_t), Size}};
|
|
|
|
if (Size > BufferIO->BufferSz) {
|
|
|
|
if (BufferIO->FileWriter(IO, 1, &BufferIO->File))
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
/* Write the data to buffer */
|
|
|
|
uint8_t *Buffer = BufferIO->BufferStart + BufferIO->CurOffset;
|
2016-03-06 12:18:13 +08:00
|
|
|
lprofBufferWriter(IO, 1, (void **)&Buffer);
|
2015-12-30 07:54:41 +08:00
|
|
|
BufferIO->CurOffset = Buffer - BufferIO->BufferStart;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-06 12:18:13 +08:00
|
|
|
COMPILER_RT_VISIBILITY int lprofBufferIOFlush(ProfBufferIO *BufferIO) {
|
2015-12-30 07:54:41 +08:00
|
|
|
if (BufferIO->CurOffset) {
|
|
|
|
ProfDataIOVec IO[] = {
|
|
|
|
{BufferIO->BufferStart, sizeof(uint8_t), BufferIO->CurOffset}};
|
|
|
|
if (BufferIO->FileWriter(IO, 1, &BufferIO->File))
|
|
|
|
return -1;
|
|
|
|
BufferIO->CurOffset = 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-05-08 04:07:09 +08:00
|
|
|
COMPILER_RT_VISIBILITY int lprofWriteData(WriterCallback Writer,
|
|
|
|
void *WriterCtx,
|
|
|
|
ValueProfData **ValueDataArray,
|
|
|
|
const uint64_t ValueDataSize) {
|
|
|
|
/* 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, WriterCtx, DataBegin, DataEnd,
|
|
|
|
CountersBegin, CountersEnd, ValueDataArray,
|
|
|
|
ValueDataSize, NamesBegin, NamesEnd);
|
|
|
|
}
|
|
|
|
|
2015-12-29 15:13:59 +08:00
|
|
|
#define VP_BUFFER_SIZE 8 * 1024
|
|
|
|
static int writeValueProfData(WriterCallback Writer, void *WriterCtx,
|
2016-05-08 04:07:09 +08:00
|
|
|
ValueProfData **ValueDataBegin,
|
|
|
|
uint64_t NumVData) {
|
2015-12-30 07:54:41 +08:00
|
|
|
ProfBufferIO *BufferIO;
|
2016-05-08 04:07:09 +08:00
|
|
|
uint32_t I = 0, BufferSz;
|
2015-12-29 15:13:59 +08:00
|
|
|
|
2016-05-08 04:07:09 +08:00
|
|
|
if (!ValueDataBegin)
|
2015-12-29 15:13:59 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
BufferSz = VPBufferSize ? VPBufferSize : VP_BUFFER_SIZE;
|
2016-03-06 12:18:13 +08:00
|
|
|
BufferIO = lprofCreateBufferIO(Writer, WriterCtx, BufferSz);
|
2015-12-29 15:13:59 +08:00
|
|
|
|
2016-05-08 04:07:09 +08:00
|
|
|
for (I = 0; I < NumVData; I++) {
|
|
|
|
ValueProfData *CurVData = ValueDataBegin[I];
|
2015-12-30 07:54:41 +08:00
|
|
|
if (!CurVData)
|
2015-12-29 15:13:59 +08:00
|
|
|
continue;
|
2016-03-06 12:18:13 +08:00
|
|
|
if (lprofBufferIOWrite(BufferIO, (const uint8_t *)CurVData,
|
|
|
|
CurVData->TotalSize) != 0)
|
2015-12-29 15:13:59 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-03-06 12:18:13 +08:00
|
|
|
if (lprofBufferIOFlush(BufferIO) != 0)
|
2015-12-30 07:54:41 +08:00
|
|
|
return -1;
|
2016-03-06 12:18:13 +08:00
|
|
|
lprofDeleteBufferIO(BufferIO);
|
2015-12-30 07:54:41 +08:00
|
|
|
|
2015-12-29 15:13:59 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-06 12:18:13 +08:00
|
|
|
COMPILER_RT_VISIBILITY int
|
|
|
|
lprofWriteDataImpl(WriterCallback Writer, void *WriterCtx,
|
|
|
|
const __llvm_profile_data *DataBegin,
|
|
|
|
const __llvm_profile_data *DataEnd,
|
|
|
|
const uint64_t *CountersBegin, const uint64_t *CountersEnd,
|
2016-05-08 04:07:09 +08:00
|
|
|
ValueProfData **ValueDataBegin, const uint64_t ValueDataSize,
|
|
|
|
const char *NamesBegin, const char *NamesEnd) {
|
2015-11-19 05:08:03 +08:00
|
|
|
|
|
|
|
/* Calculate size of sections. */
|
2016-02-26 10:49:41 +08:00
|
|
|
const uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
|
2015-11-19 05:08:03 +08:00
|
|
|
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;
|
|
|
|
|
2016-05-08 04:07:09 +08:00
|
|
|
/* Initialize header struture. */
|
2015-11-24 02:36:40 +08:00
|
|
|
#define INSTR_PROF_RAW_HEADER(Type, Name, Init) Header.Name = Init;
|
|
|
|
#include "InstrProfData.inc"
|
2015-11-19 05:08:03 +08:00
|
|
|
|
2015-11-21 12:16:42 +08:00
|
|
|
/* Write the data. */
|
2015-12-29 15:13:59 +08:00
|
|
|
ProfDataIOVec IOVec[] = {{&Header, sizeof(__llvm_profile_header), 1},
|
|
|
|
{DataBegin, sizeof(__llvm_profile_data), DataSize},
|
|
|
|
{CountersBegin, sizeof(uint64_t), CountersSize},
|
|
|
|
{NamesBegin, sizeof(uint8_t), NamesSize},
|
|
|
|
{Zeroes, sizeof(uint8_t), Padding}};
|
2015-12-04 08:40:07 +08:00
|
|
|
if (Writer(IOVec, sizeof(IOVec) / sizeof(*IOVec), &WriterCtx))
|
2015-11-21 12:16:42 +08:00
|
|
|
return -1;
|
2015-12-29 15:13:59 +08:00
|
|
|
|
2016-05-08 04:07:09 +08:00
|
|
|
return writeValueProfData(Writer, WriterCtx, ValueDataBegin, DataSize);
|
2015-11-19 05:08:03 +08:00
|
|
|
}
|