InstrProfilingWriter.c revision 302408
1204076Spjd/*===- InstrProfilingWriter.c - Write instrumentation to a file or buffer -===*\ 2204076Spjd|* 3219351Spjd|* The LLVM Compiler Infrastructure 4204076Spjd|* 5204076Spjd|* This file is distributed under the University of Illinois Open Source 6204076Spjd|* License. See LICENSE.TXT for details. 7204076Spjd|* 8204076Spjd\*===----------------------------------------------------------------------===*/ 9204076Spjd 10204076Spjd#include "InstrProfiling.h" 11204076Spjd#include "InstrProfilingInternal.h" 12204076Spjd#include <string.h> 13204076Spjd 14204076Spjd#define INSTR_PROF_VALUE_PROF_DATA 15204076Spjd#include "InstrProfData.inc" 16204076Spjdvoid (*FreeHook)(void *) = NULL; 17204076Spjdvoid* (*CallocHook)(size_t, size_t) = NULL; 18204076Spjduint32_t VPBufferSize = 0; 19204076Spjd 20204076Spjd/* The buffer writer is reponsponsible in keeping writer state 21204076Spjd * across the call. 22204076Spjd */ 23204076SpjdCOMPILER_RT_VISIBILITY uint32_t llvmBufferWriter(ProfDataIOVec *IOVecs, 24204076Spjd uint32_t NumIOVecs, 25204076Spjd void **WriterCtx) { 26204076Spjd uint32_t I; 27204076Spjd char **Buffer = (char **)WriterCtx; 28204076Spjd for (I = 0; I < NumIOVecs; I++) { 29204076Spjd size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm; 30204076Spjd memcpy(*Buffer, IOVecs[I].Data, Length); 31204076Spjd *Buffer += Length; 32204076Spjd } 33204076Spjd return 0; 34204076Spjd} 35204076Spjd 36204076Spjdstatic void llvmInitBufferIO(ProfBufferIO *BufferIO, WriterCallback FileWriter, 37204076Spjd void *File, uint8_t *Buffer, uint32_t BufferSz) { 38204076Spjd BufferIO->File = File; 39204076Spjd BufferIO->FileWriter = FileWriter; 40204076Spjd BufferIO->BufferStart = Buffer; 41204076Spjd BufferIO->BufferSz = BufferSz; 42204076Spjd BufferIO->CurOffset = 0; 43204076Spjd} 44204076Spjd 45204076SpjdCOMPILER_RT_VISIBILITY ProfBufferIO * 46204076SpjdllvmCreateBufferIO(WriterCallback FileWriter, void *File, uint32_t BufferSz) { 47204076Spjd ProfBufferIO *BufferIO = (ProfBufferIO *)CallocHook(1, sizeof(ProfBufferIO)); 48204076Spjd uint8_t *Buffer = (uint8_t *)CallocHook(1, BufferSz); 49204076Spjd if (!Buffer) { 50204076Spjd FreeHook(BufferIO); 51204076Spjd return 0; 52211882Spjd } 53211882Spjd llvmInitBufferIO(BufferIO, FileWriter, File, Buffer, BufferSz); 54211882Spjd return BufferIO; 55211882Spjd} 56211882Spjd 57211882SpjdCOMPILER_RT_VISIBILITY void llvmDeleteBufferIO(ProfBufferIO *BufferIO) { 58204076Spjd FreeHook(BufferIO->BufferStart); 59204076Spjd FreeHook(BufferIO); 60204076Spjd} 61204076Spjd 62204076SpjdCOMPILER_RT_VISIBILITY int 63204076SpjdllvmBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size) { 64204076Spjd /* Buffer is not large enough, it is time to flush. */ 65204076Spjd if (Size + BufferIO->CurOffset > BufferIO->BufferSz) { 66204076Spjd if (llvmBufferIOFlush(BufferIO) != 0) 67204076Spjd return -1; 68204076Spjd } 69204076Spjd /* Special case, bypass the buffer completely. */ 70204076Spjd ProfDataIOVec IO[] = {{Data, sizeof(uint8_t), Size}}; 71204076Spjd if (Size > BufferIO->BufferSz) { 72204076Spjd if (BufferIO->FileWriter(IO, 1, &BufferIO->File)) 73204076Spjd return -1; 74204076Spjd } else { 75204076Spjd /* Write the data to buffer */ 76204076Spjd uint8_t *Buffer = BufferIO->BufferStart + BufferIO->CurOffset; 77204076Spjd llvmBufferWriter(IO, 1, (void **)&Buffer); 78204076Spjd BufferIO->CurOffset = Buffer - BufferIO->BufferStart; 79204076Spjd } 80204076Spjd return 0; 81204076Spjd} 82204076Spjd 83211882SpjdCOMPILER_RT_VISIBILITY int llvmBufferIOFlush(ProfBufferIO *BufferIO) { 84204076Spjd if (BufferIO->CurOffset) { 85222108Spjd ProfDataIOVec IO[] = { 86222108Spjd {BufferIO->BufferStart, sizeof(uint8_t), BufferIO->CurOffset}}; 87222108Spjd if (BufferIO->FileWriter(IO, 1, &BufferIO->File)) 88222108Spjd return -1; 89222108Spjd BufferIO->CurOffset = 0; 90222108Spjd } 91222108Spjd return 0; 92204076Spjd} 93204076Spjd 94204076SpjdCOMPILER_RT_VISIBILITY int llvmWriteProfData(WriterCallback Writer, 95204076Spjd void *WriterCtx, 96204076Spjd ValueProfData **ValueDataArray, 97204076Spjd const uint64_t ValueDataSize) { 98204076Spjd /* Match logic in __llvm_profile_write_buffer(). */ 99204076Spjd const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); 100204076Spjd const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); 101219721Strociny const uint64_t *CountersBegin = __llvm_profile_begin_counters(); 102219721Strociny const uint64_t *CountersEnd = __llvm_profile_end_counters(); 103219721Strociny const char *NamesBegin = __llvm_profile_begin_names(); 104222108Spjd const char *NamesEnd = __llvm_profile_end_names(); 105222108Spjd return llvmWriteProfDataImpl(Writer, WriterCtx, DataBegin, DataEnd, 106222108Spjd CountersBegin, CountersEnd, ValueDataArray, 107222108Spjd ValueDataSize, NamesBegin, NamesEnd); 108222108Spjd} 109222108Spjd 110222108Spjd#define VP_BUFFER_SIZE 8 * 1024 111222108Spjdstatic int writeValueProfData(WriterCallback Writer, void *WriterCtx, 112204076Spjd ValueProfData **ValueDataBegin, 113204076Spjd uint64_t NumVData) { 114204076Spjd ProfBufferIO *BufferIO; 115204076Spjd uint32_t I = 0, BufferSz; 116204076Spjd 117217969Spjd if (!ValueDataBegin) 118217969Spjd return 0; 119222108Spjd 120222108Spjd BufferSz = VPBufferSize ? VPBufferSize : VP_BUFFER_SIZE; 121204076Spjd BufferIO = llvmCreateBufferIO(Writer, WriterCtx, BufferSz); 122204076Spjd 123204076Spjd for (I = 0; I < NumVData; I++) { 124204076Spjd ValueProfData *CurVData = ValueDataBegin[I]; 125204076Spjd if (!CurVData) 126204076Spjd continue; 127204076Spjd if (llvmBufferIOWrite(BufferIO, (const uint8_t *)CurVData, 128204076Spjd CurVData->TotalSize) != 0) 129219354Spjd return -1; 130219354Spjd } 131219354Spjd 132219354Spjd if (llvmBufferIOFlush(BufferIO) != 0) 133219351Spjd return -1; 134219351Spjd llvmDeleteBufferIO(BufferIO); 135219351Spjd 136219351Spjd return 0; 137204076Spjd} 138204076Spjd 139204076SpjdCOMPILER_RT_VISIBILITY int llvmWriteProfDataImpl( 140204076Spjd WriterCallback Writer, void *WriterCtx, 141204076Spjd const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd, 142204076Spjd const uint64_t *CountersBegin, const uint64_t *CountersEnd, 143204076Spjd ValueProfData **ValueDataBegin, const uint64_t ValueDataSize, 144204076Spjd const char *NamesBegin, const char *NamesEnd) { 145204076Spjd 146204076Spjd /* Calculate size of sections. */ 147204076Spjd const uint64_t DataSize = DataEnd - DataBegin; 148204076Spjd const uint64_t CountersSize = CountersEnd - CountersBegin; 149204076Spjd const uint64_t NamesSize = NamesEnd - NamesBegin; 150204076Spjd const uint64_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize); 151211886Spjd 152211886Spjd /* Enough zeroes for padding. */ 153219354Spjd const char Zeroes[sizeof(uint64_t)] = {0}; 154219354Spjd 155219351Spjd /* Create the header. */ 156219351Spjd __llvm_profile_header Header; 157204076Spjd 158204076Spjd if (!DataSize) 159204076Spjd return 0; 160204076Spjd 161204076Spjd /* Initialize header struture. */ 162204076Spjd#define INSTR_PROF_RAW_HEADER(Type, Name, Init) Header.Name = Init; 163204076Spjd#include "InstrProfData.inc" 164204076Spjd 165204076Spjd /* Write the data. */ 166204076Spjd ProfDataIOVec IOVec[] = {{&Header, sizeof(__llvm_profile_header), 1}, 167204076Spjd {DataBegin, sizeof(__llvm_profile_data), DataSize}, 168204076Spjd {CountersBegin, sizeof(uint64_t), CountersSize}, 169204076Spjd {NamesBegin, sizeof(uint8_t), NamesSize}, 170204076Spjd {Zeroes, sizeof(uint8_t), Padding}}; 171204076Spjd if (Writer(IOVec, sizeof(IOVec) / sizeof(*IOVec), &WriterCtx)) 172204076Spjd return -1; 173204076Spjd 174204076Spjd return writeValueProfData(Writer, WriterCtx, ValueDataBegin, DataSize); 175204076Spjd} 176204076Spjd