Path: blob/main/contrib/llvm-project/compiler-rt/lib/profile/InstrProfilingWriter.c
35233 views
/*===- InstrProfilingWriter.c - Write instrumentation to a file or buffer -===*\1|*2|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3|* See https://llvm.org/LICENSE.txt for license information.4|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5|*6\*===----------------------------------------------------------------------===*/78// Note: This is linked into the Darwin kernel, and must remain compatible9// with freestanding compilation. See `darwin_add_builtin_libraries`.1011#ifdef _MSC_VER12/* For _alloca */13#include <malloc.h>14#endif15#include <string.h>1617#include "InstrProfiling.h"18#include "InstrProfilingInternal.h"19#include "InstrProfilingPort.h"2021#define INSTR_PROF_VALUE_PROF_DATA22#include "profile/InstrProfData.inc"2324COMPILER_RT_VISIBILITY void (*FreeHook)(void *) = NULL;25static ProfBufferIO TheBufferIO;26#define VP_BUFFER_SIZE 8 * 102427static uint8_t BufferIOBuffer[VP_BUFFER_SIZE];28static InstrProfValueData VPDataArray[16];29static uint32_t VPDataArraySize = sizeof(VPDataArray) / sizeof(*VPDataArray);3031COMPILER_RT_VISIBILITY uint8_t *DynamicBufferIOBuffer = 0;32COMPILER_RT_VISIBILITY uint32_t VPBufferSize = 0;3334/* The buffer writer is responsible in keeping writer state35* across the call.36*/37COMPILER_RT_VISIBILITY uint32_t lprofBufferWriter(ProfDataWriter *This,38ProfDataIOVec *IOVecs,39uint32_t NumIOVecs) {40uint32_t I;41char **Buffer = (char **)&This->WriterCtx;42for (I = 0; I < NumIOVecs; I++) {43size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm;44if (IOVecs[I].Data)45memcpy(*Buffer, IOVecs[I].Data, Length);46else if (IOVecs[I].UseZeroPadding) {47/* Allocating the buffer should zero fill. */48}49*Buffer += Length;50}51return 0;52}5354static void llvmInitBufferIO(ProfBufferIO *BufferIO, ProfDataWriter *FileWriter,55uint8_t *Buffer, uint32_t BufferSz) {56BufferIO->FileWriter = FileWriter;57BufferIO->OwnFileWriter = 0;58BufferIO->BufferStart = Buffer;59BufferIO->BufferSz = BufferSz;60BufferIO->CurOffset = 0;61}6263COMPILER_RT_VISIBILITY ProfBufferIO *64lprofCreateBufferIO(ProfDataWriter *FileWriter) {65uint8_t *Buffer = DynamicBufferIOBuffer;66uint32_t BufferSize = VPBufferSize;67if (!Buffer) {68Buffer = &BufferIOBuffer[0];69BufferSize = sizeof(BufferIOBuffer);70}71llvmInitBufferIO(&TheBufferIO, FileWriter, Buffer, BufferSize);72return &TheBufferIO;73}7475COMPILER_RT_VISIBILITY void lprofDeleteBufferIO(ProfBufferIO *BufferIO) {76if (BufferIO->OwnFileWriter)77FreeHook(BufferIO->FileWriter);78if (DynamicBufferIOBuffer) {79FreeHook(DynamicBufferIOBuffer);80DynamicBufferIOBuffer = 0;81VPBufferSize = 0;82}83}8485COMPILER_RT_VISIBILITY int86lprofBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size) {87/* Buffer is not large enough, it is time to flush. */88if (Size + BufferIO->CurOffset > BufferIO->BufferSz) {89if (lprofBufferIOFlush(BufferIO) != 0)90return -1;91}92/* Special case, bypass the buffer completely. */93ProfDataIOVec IO[] = {{Data, sizeof(uint8_t), Size, 0}};94if (Size > BufferIO->BufferSz) {95if (BufferIO->FileWriter->Write(BufferIO->FileWriter, IO, 1))96return -1;97} else {98/* Write the data to buffer */99uint8_t *Buffer = BufferIO->BufferStart + BufferIO->CurOffset;100ProfDataWriter BufferWriter;101initBufferWriter(&BufferWriter, (char *)Buffer);102lprofBufferWriter(&BufferWriter, IO, 1);103BufferIO->CurOffset =104(uint8_t *)BufferWriter.WriterCtx - BufferIO->BufferStart;105}106return 0;107}108109COMPILER_RT_VISIBILITY int lprofBufferIOFlush(ProfBufferIO *BufferIO) {110if (BufferIO->CurOffset) {111ProfDataIOVec IO[] = {112{BufferIO->BufferStart, sizeof(uint8_t), BufferIO->CurOffset, 0}};113if (BufferIO->FileWriter->Write(BufferIO->FileWriter, IO, 1))114return -1;115BufferIO->CurOffset = 0;116}117return 0;118}119120/* Write out value profile data for function specified with \c Data.121* The implementation does not use the method \c serializeValueProfData122* which depends on dynamic memory allocation. In this implementation,123* value profile data is written out to \c BufferIO piecemeal.124*/125static int writeOneValueProfData(ProfBufferIO *BufferIO,126VPDataReaderType *VPDataReader,127const __llvm_profile_data *Data) {128unsigned I, NumValueKinds = 0;129ValueProfData VPHeader;130uint8_t *SiteCountArray[IPVK_Last + 1];131132for (I = 0; I <= IPVK_Last; I++) {133if (!Data->NumValueSites[I])134SiteCountArray[I] = 0;135else {136uint32_t Sz =137VPDataReader->GetValueProfRecordHeaderSize(Data->NumValueSites[I]) -138offsetof(ValueProfRecord, SiteCountArray);139/* Only use alloca for this small byte array to avoid excessive140* stack growth. */141SiteCountArray[I] = (uint8_t *)COMPILER_RT_ALLOCA(Sz);142memset(SiteCountArray[I], 0, Sz);143}144}145146/* If NumValueKinds returned is 0, there is nothing to write, report147success and return. This should match the raw profile reader's behavior. */148if (!(NumValueKinds = VPDataReader->InitRTRecord(Data, SiteCountArray)))149return 0;150151/* First write the header structure. */152VPHeader.TotalSize = VPDataReader->GetValueProfDataSize();153VPHeader.NumValueKinds = NumValueKinds;154if (lprofBufferIOWrite(BufferIO, (const uint8_t *)&VPHeader,155sizeof(ValueProfData)))156return -1;157158/* Make sure nothing else needs to be written before value profile159* records. */160if ((void *)VPDataReader->GetFirstValueProfRecord(&VPHeader) !=161(void *)(&VPHeader + 1))162return -1;163164/* Write out the value profile record for each value kind165* one by one. */166for (I = 0; I <= IPVK_Last; I++) {167uint32_t J;168ValueProfRecord RecordHeader;169/* The size of the value prof record header without counting the170* site count array .*/171uint32_t RecordHeaderSize = offsetof(ValueProfRecord, SiteCountArray);172uint32_t SiteCountArraySize;173174if (!Data->NumValueSites[I])175continue;176177/* Write out the record header. */178RecordHeader.Kind = I;179RecordHeader.NumValueSites = Data->NumValueSites[I];180if (lprofBufferIOWrite(BufferIO, (const uint8_t *)&RecordHeader,181RecordHeaderSize))182return -1;183184/* Write out the site value count array including padding space. */185SiteCountArraySize =186VPDataReader->GetValueProfRecordHeaderSize(Data->NumValueSites[I]) -187RecordHeaderSize;188if (lprofBufferIOWrite(BufferIO, SiteCountArray[I], SiteCountArraySize))189return -1;190191/* Write out the value profile data for each value site. */192for (J = 0; J < Data->NumValueSites[I]; J++) {193uint32_t NRead, NRemain;194ValueProfNode *NextStartNode = 0;195NRemain = VPDataReader->GetNumValueDataForSite(I, J);196if (!NRemain)197continue;198/* Read and write out value data in small chunks till it is done. */199do {200NRead = (NRemain > VPDataArraySize ? VPDataArraySize : NRemain);201NextStartNode =202VPDataReader->GetValueData(I, /* ValueKind */203J, /* Site */204&VPDataArray[0], NextStartNode, NRead);205if (lprofBufferIOWrite(BufferIO, (const uint8_t *)&VPDataArray[0],206NRead * sizeof(InstrProfValueData)))207return -1;208NRemain -= NRead;209} while (NRemain != 0);210}211}212/* All done report success. */213return 0;214}215216static int writeValueProfData(ProfDataWriter *Writer,217VPDataReaderType *VPDataReader,218const __llvm_profile_data *DataBegin,219const __llvm_profile_data *DataEnd) {220ProfBufferIO *BufferIO;221const __llvm_profile_data *DI = 0;222223if (!VPDataReader)224return 0;225226BufferIO = lprofCreateBufferIO(Writer);227228for (DI = DataBegin; DI < DataEnd; DI++) {229if (writeOneValueProfData(BufferIO, VPDataReader, DI))230return -1;231}232233if (lprofBufferIOFlush(BufferIO) != 0)234return -1;235lprofDeleteBufferIO(BufferIO);236237return 0;238}239240COMPILER_RT_VISIBILITY int lprofWriteData(ProfDataWriter *Writer,241VPDataReaderType *VPDataReader,242int SkipNameDataWrite) {243/* Match logic in __llvm_profile_write_buffer(). */244const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();245const __llvm_profile_data *DataEnd = __llvm_profile_end_data();246const char *CountersBegin = __llvm_profile_begin_counters();247const char *CountersEnd = __llvm_profile_end_counters();248const char *BitmapBegin = __llvm_profile_begin_bitmap();249const char *BitmapEnd = __llvm_profile_end_bitmap();250const char *NamesBegin = __llvm_profile_begin_names();251const char *NamesEnd = __llvm_profile_end_names();252const VTableProfData *VTableBegin = __llvm_profile_begin_vtables();253const VTableProfData *VTableEnd = __llvm_profile_end_vtables();254const char *VNamesBegin = __llvm_profile_begin_vtabnames();255const char *VNamesEnd = __llvm_profile_end_vtabnames();256return lprofWriteDataImpl(Writer, DataBegin, DataEnd, CountersBegin,257CountersEnd, BitmapBegin, BitmapEnd, VPDataReader,258NamesBegin, NamesEnd, VTableBegin, VTableEnd,259VNamesBegin, VNamesEnd, SkipNameDataWrite);260}261262COMPILER_RT_VISIBILITY int263lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin,264const __llvm_profile_data *DataEnd,265const char *CountersBegin, const char *CountersEnd,266const char *BitmapBegin, const char *BitmapEnd,267VPDataReaderType *VPDataReader, const char *NamesBegin,268const char *NamesEnd, const VTableProfData *VTableBegin,269const VTableProfData *VTableEnd, const char *VNamesBegin,270const char *VNamesEnd, int SkipNameDataWrite) {271/* Calculate size of sections. */272const uint64_t DataSectionSize =273__llvm_profile_get_data_size(DataBegin, DataEnd);274const uint64_t NumData = __llvm_profile_get_num_data(DataBegin, DataEnd);275const uint64_t CountersSectionSize =276__llvm_profile_get_counters_size(CountersBegin, CountersEnd);277const uint64_t NumCounters =278__llvm_profile_get_num_counters(CountersBegin, CountersEnd);279const uint64_t NumBitmapBytes =280__llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd);281const uint64_t NamesSize = __llvm_profile_get_name_size(NamesBegin, NamesEnd);282const uint64_t NumVTables =283__llvm_profile_get_num_vtable(VTableBegin, VTableEnd);284const uint64_t VTableSectionSize =285__llvm_profile_get_vtable_section_size(VTableBegin, VTableEnd);286const uint64_t VNamesSize =287__llvm_profile_get_name_size(VNamesBegin, VNamesEnd);288289/* Create the header. */290__llvm_profile_header Header;291292/* Determine how much padding is needed before/after the counters and after293* the names. */294uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,295PaddingBytesAfterBitmapBytes, PaddingBytesAfterNames,296PaddingBytesAfterVTable, PaddingBytesAfterVNames;297if (__llvm_profile_get_padding_sizes_for_counters(298DataSectionSize, CountersSectionSize, NumBitmapBytes, NamesSize,299VTableSectionSize, VNamesSize, &PaddingBytesBeforeCounters,300&PaddingBytesAfterCounters, &PaddingBytesAfterBitmapBytes,301&PaddingBytesAfterNames, &PaddingBytesAfterVTable,302&PaddingBytesAfterVNames) == -1)303return -1;304305{306/* Initialize header structure. */307#define INSTR_PROF_RAW_HEADER(Type, Name, Init) Header.Name = Init;308#include "profile/InstrProfData.inc"309}310311/* On WIN64, label differences are truncated 32-bit values. Truncate312* CountersDelta to match. */313#ifdef _WIN64314Header.CountersDelta = (uint32_t)Header.CountersDelta;315Header.BitmapDelta = (uint32_t)Header.BitmapDelta;316#endif317318/* The data and names sections are omitted in lightweight mode. */319if (NumData == 0 && NamesSize == 0) {320Header.CountersDelta = 0;321Header.NamesDelta = 0;322}323324/* Write the profile header. */325ProfDataIOVec IOVec[] = {{&Header, sizeof(__llvm_profile_header), 1, 0}};326if (Writer->Write(Writer, IOVec, sizeof(IOVec) / sizeof(*IOVec)))327return -1;328329/* Write the binary id lengths and data. */330if (__llvm_write_binary_ids(Writer) == -1)331return -1;332333/* Write the profile data. */334ProfDataIOVec IOVecData[] = {335{DataBegin, sizeof(uint8_t), DataSectionSize, 0},336{NULL, sizeof(uint8_t), PaddingBytesBeforeCounters, 1},337{CountersBegin, sizeof(uint8_t), CountersSectionSize, 0},338{NULL, sizeof(uint8_t), PaddingBytesAfterCounters, 1},339{BitmapBegin, sizeof(uint8_t), NumBitmapBytes, 0},340{NULL, sizeof(uint8_t), PaddingBytesAfterBitmapBytes, 1},341{SkipNameDataWrite ? NULL : NamesBegin, sizeof(uint8_t), NamesSize, 0},342{NULL, sizeof(uint8_t), PaddingBytesAfterNames, 1},343{VTableBegin, sizeof(uint8_t), VTableSectionSize, 0},344{NULL, sizeof(uint8_t), PaddingBytesAfterVTable, 1},345{SkipNameDataWrite ? NULL : VNamesBegin, sizeof(uint8_t), VNamesSize, 0},346{NULL, sizeof(uint8_t), PaddingBytesAfterVNames, 1}};347if (Writer->Write(Writer, IOVecData, sizeof(IOVecData) / sizeof(*IOVecData)))348return -1;349350/* Value profiling is not yet supported in continuous mode and profile351* correlation mode. */352if (__llvm_profile_is_continuous_mode_enabled() ||353(NumData == 0 && NamesSize == 0))354return 0;355356return writeValueProfData(Writer, VPDataReader, DataBegin, DataEnd);357}358359/*360* Write binary id length and then its data, because binary id does not361* have a fixed length.362*/363COMPILER_RT_VISIBILITY364int lprofWriteOneBinaryId(ProfDataWriter *Writer, uint64_t BinaryIdLen,365const uint8_t *BinaryIdData,366uint64_t BinaryIdPadding) {367ProfDataIOVec BinaryIdIOVec[] = {368{&BinaryIdLen, sizeof(uint64_t), 1, 0},369{BinaryIdData, sizeof(uint8_t), BinaryIdLen, 0},370{NULL, sizeof(uint8_t), BinaryIdPadding, 1},371};372if (Writer->Write(Writer, BinaryIdIOVec,373sizeof(BinaryIdIOVec) / sizeof(*BinaryIdIOVec)))374return -1;375376/* Successfully wrote binary id, report success. */377return 0;378}379380381