InstrProfReader.cpp revision 36b56886974eae4f9c5ebc96befd3e7bfe5de338
1//=-- InstrProfReader.cpp - Instrumented profiling reader -------------------=// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file contains support for reading profiling data for clang's 11// instrumentation based PGO and coverage. 12// 13//===----------------------------------------------------------------------===// 14 15#include "llvm/ProfileData/InstrProfReader.h" 16#include "llvm/ProfileData/InstrProf.h" 17 18#include <cassert> 19 20using namespace llvm; 21 22error_code InstrProfReader::create(std::string Path, 23 std::unique_ptr<InstrProfReader> &Result) { 24 std::unique_ptr<MemoryBuffer> Buffer; 25 if (error_code EC = MemoryBuffer::getFileOrSTDIN(Path, Buffer)) 26 return EC; 27 28 // Sanity check the file. 29 if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max()) 30 return instrprof_error::too_large; 31 32 // Create the reader. 33 if (RawInstrProfReader64::hasFormat(*Buffer)) 34 Result.reset(new RawInstrProfReader64(std::move(Buffer))); 35 else if (RawInstrProfReader32::hasFormat(*Buffer)) 36 Result.reset(new RawInstrProfReader32(std::move(Buffer))); 37 else 38 Result.reset(new TextInstrProfReader(std::move(Buffer))); 39 40 // Read the header and return the result. 41 return Result->readHeader(); 42} 43 44void InstrProfIterator::Increment() { 45 if (Reader->readNextRecord(Record)) 46 *this = InstrProfIterator(); 47} 48 49error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) { 50 // Skip empty lines. 51 while (!Line.is_at_end() && Line->empty()) 52 ++Line; 53 // If we hit EOF while looking for a name, we're done. 54 if (Line.is_at_end()) 55 return error(instrprof_error::eof); 56 57 // Read the function name. 58 Record.Name = *Line++; 59 60 // Read the function hash. 61 if (Line.is_at_end()) 62 return error(instrprof_error::truncated); 63 if ((Line++)->getAsInteger(10, Record.Hash)) 64 return error(instrprof_error::malformed); 65 66 // Read the number of counters. 67 uint64_t NumCounters; 68 if (Line.is_at_end()) 69 return error(instrprof_error::truncated); 70 if ((Line++)->getAsInteger(10, NumCounters)) 71 return error(instrprof_error::malformed); 72 73 // Read each counter and fill our internal storage with the values. 74 Counts.clear(); 75 Counts.reserve(NumCounters); 76 for (uint64_t I = 0; I < NumCounters; ++I) { 77 if (Line.is_at_end()) 78 return error(instrprof_error::truncated); 79 uint64_t Count; 80 if ((Line++)->getAsInteger(10, Count)) 81 return error(instrprof_error::malformed); 82 Counts.push_back(Count); 83 } 84 // Give the record a reference to our internal counter storage. 85 Record.Counts = Counts; 86 87 return success(); 88} 89 90template <class IntPtrT> 91static uint64_t getRawMagic(); 92 93template <> 94uint64_t getRawMagic<uint64_t>() { 95 return 96 uint64_t(255) << 56 | 97 uint64_t('l') << 48 | 98 uint64_t('p') << 40 | 99 uint64_t('r') << 32 | 100 uint64_t('o') << 24 | 101 uint64_t('f') << 16 | 102 uint64_t('r') << 8 | 103 uint64_t(129); 104} 105 106template <> 107uint64_t getRawMagic<uint32_t>() { 108 return 109 uint64_t(255) << 56 | 110 uint64_t('l') << 48 | 111 uint64_t('p') << 40 | 112 uint64_t('r') << 32 | 113 uint64_t('o') << 24 | 114 uint64_t('f') << 16 | 115 uint64_t('R') << 8 | 116 uint64_t(129); 117} 118 119template <class IntPtrT> 120bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) { 121 if (DataBuffer.getBufferSize() < sizeof(uint64_t)) 122 return false; 123 uint64_t Magic = 124 *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart()); 125 return getRawMagic<IntPtrT>() == Magic || 126 sys::SwapByteOrder(getRawMagic<IntPtrT>()) == Magic; 127} 128 129template <class IntPtrT> 130error_code RawInstrProfReader<IntPtrT>::readHeader() { 131 if (!hasFormat(*DataBuffer)) 132 return error(instrprof_error::bad_magic); 133 if (DataBuffer->getBufferSize() < sizeof(RawHeader)) 134 return error(instrprof_error::bad_header); 135 auto *Header = 136 reinterpret_cast<const RawHeader *>(DataBuffer->getBufferStart()); 137 ShouldSwapBytes = Header->Magic != getRawMagic<IntPtrT>(); 138 return readHeader(*Header); 139} 140 141static uint64_t getRawVersion() { 142 return 1; 143} 144 145template <class IntPtrT> 146error_code RawInstrProfReader<IntPtrT>::readHeader(const RawHeader &Header) { 147 if (swap(Header.Version) != getRawVersion()) 148 return error(instrprof_error::unsupported_version); 149 150 CountersDelta = swap(Header.CountersDelta); 151 NamesDelta = swap(Header.NamesDelta); 152 auto DataSize = swap(Header.DataSize); 153 auto CountersSize = swap(Header.CountersSize); 154 auto NamesSize = swap(Header.NamesSize); 155 156 ptrdiff_t DataOffset = sizeof(RawHeader); 157 ptrdiff_t CountersOffset = DataOffset + sizeof(ProfileData) * DataSize; 158 ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize; 159 size_t FileSize = NamesOffset + sizeof(char) * NamesSize; 160 161 if (FileSize != DataBuffer->getBufferSize()) 162 return error(instrprof_error::bad_header); 163 164 const char *Start = DataBuffer->getBufferStart(); 165 Data = reinterpret_cast<const ProfileData *>(Start + DataOffset); 166 DataEnd = Data + DataSize; 167 CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset); 168 NamesStart = Start + NamesOffset; 169 170 return success(); 171} 172 173template <class IntPtrT> 174error_code 175RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) { 176 if (Data == DataEnd) 177 return error(instrprof_error::eof); 178 179 // Get the raw data. 180 StringRef RawName(getName(Data->NamePtr), swap(Data->NameSize)); 181 auto RawCounts = makeArrayRef(getCounter(Data->CounterPtr), 182 swap(Data->NumCounters)); 183 184 // Check bounds. 185 auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart); 186 if (RawName.data() < NamesStart || 187 RawName.data() + RawName.size() > DataBuffer->getBufferEnd() || 188 RawCounts.data() < CountersStart || 189 RawCounts.data() + RawCounts.size() > NamesStartAsCounter) 190 return error(instrprof_error::malformed); 191 192 // Store the data in Record, byte-swapping as necessary. 193 Record.Hash = swap(Data->FuncHash); 194 Record.Name = RawName; 195 if (ShouldSwapBytes) { 196 Counts.clear(); 197 Counts.reserve(RawCounts.size()); 198 for (uint64_t Count : RawCounts) 199 Counts.push_back(swap(Count)); 200 Record.Counts = Counts; 201 } else 202 Record.Counts = RawCounts; 203 204 // Iterate. 205 ++Data; 206 return success(); 207} 208 209namespace llvm { 210template class RawInstrProfReader<uint32_t>; 211template class RawInstrProfReader<uint64_t>; 212} 213