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 "InstrProfIndexed.h" 19 20 #include <cassert> 21 22 using namespace llvm; 23 24 static error_code setupMemoryBuffer(std::string Path, 25 std::unique_ptr<MemoryBuffer> &Buffer) { 26 if (error_code EC = MemoryBuffer::getFileOrSTDIN(Path, Buffer)) 27 return EC; 28 29 // Sanity check the file. 30 if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max()) 31 return instrprof_error::too_large; 32 return instrprof_error::success; 33 } 34 35 static error_code initializeReader(InstrProfReader &Reader) { 36 return Reader.readHeader(); 37 } 38 39 error_code InstrProfReader::create(std::string Path, 40 std::unique_ptr<InstrProfReader> &Result) { 41 // Set up the buffer to read. 42 std::unique_ptr<MemoryBuffer> Buffer; 43 if (error_code EC = setupMemoryBuffer(Path, Buffer)) 44 return EC; 45 46 // Create the reader. 47 if (IndexedInstrProfReader::hasFormat(*Buffer)) 48 Result.reset(new IndexedInstrProfReader(std::move(Buffer))); 49 else if (RawInstrProfReader64::hasFormat(*Buffer)) 50 Result.reset(new RawInstrProfReader64(std::move(Buffer))); 51 else if (RawInstrProfReader32::hasFormat(*Buffer)) 52 Result.reset(new RawInstrProfReader32(std::move(Buffer))); 53 else 54 Result.reset(new TextInstrProfReader(std::move(Buffer))); 55 56 // Initialize the reader and return the result. 57 return initializeReader(*Result); 58 } 59 60 error_code IndexedInstrProfReader::create( 61 std::string Path, std::unique_ptr<IndexedInstrProfReader> &Result) { 62 // Set up the buffer to read. 63 std::unique_ptr<MemoryBuffer> Buffer; 64 if (error_code EC = setupMemoryBuffer(Path, Buffer)) 65 return EC; 66 67 // Create the reader. 68 if (!IndexedInstrProfReader::hasFormat(*Buffer)) 69 return instrprof_error::bad_magic; 70 Result.reset(new IndexedInstrProfReader(std::move(Buffer))); 71 72 // Initialize the reader and return the result. 73 return initializeReader(*Result); 74 } 75 76 void InstrProfIterator::Increment() { 77 if (Reader->readNextRecord(Record)) 78 *this = InstrProfIterator(); 79 } 80 81 error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) { 82 // Skip empty lines. 83 while (!Line.is_at_end() && Line->empty()) 84 ++Line; 85 // If we hit EOF while looking for a name, we're done. 86 if (Line.is_at_end()) 87 return error(instrprof_error::eof); 88 89 // Read the function name. 90 Record.Name = *Line++; 91 92 // Read the function hash. 93 if (Line.is_at_end()) 94 return error(instrprof_error::truncated); 95 if ((Line++)->getAsInteger(10, Record.Hash)) 96 return error(instrprof_error::malformed); 97 98 // Read the number of counters. 99 uint64_t NumCounters; 100 if (Line.is_at_end()) 101 return error(instrprof_error::truncated); 102 if ((Line++)->getAsInteger(10, NumCounters)) 103 return error(instrprof_error::malformed); 104 if (NumCounters == 0) 105 return error(instrprof_error::malformed); 106 107 // Read each counter and fill our internal storage with the values. 108 Counts.clear(); 109 Counts.reserve(NumCounters); 110 for (uint64_t I = 0; I < NumCounters; ++I) { 111 if (Line.is_at_end()) 112 return error(instrprof_error::truncated); 113 uint64_t Count; 114 if ((Line++)->getAsInteger(10, Count)) 115 return error(instrprof_error::malformed); 116 Counts.push_back(Count); 117 } 118 // Give the record a reference to our internal counter storage. 119 Record.Counts = Counts; 120 121 return success(); 122 } 123 124 template <class IntPtrT> 125 static uint64_t getRawMagic(); 126 127 template <> 128 uint64_t getRawMagic<uint64_t>() { 129 return 130 uint64_t(255) << 56 | 131 uint64_t('l') << 48 | 132 uint64_t('p') << 40 | 133 uint64_t('r') << 32 | 134 uint64_t('o') << 24 | 135 uint64_t('f') << 16 | 136 uint64_t('r') << 8 | 137 uint64_t(129); 138 } 139 140 template <> 141 uint64_t getRawMagic<uint32_t>() { 142 return 143 uint64_t(255) << 56 | 144 uint64_t('l') << 48 | 145 uint64_t('p') << 40 | 146 uint64_t('r') << 32 | 147 uint64_t('o') << 24 | 148 uint64_t('f') << 16 | 149 uint64_t('R') << 8 | 150 uint64_t(129); 151 } 152 153 template <class IntPtrT> 154 bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) { 155 if (DataBuffer.getBufferSize() < sizeof(uint64_t)) 156 return false; 157 uint64_t Magic = 158 *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart()); 159 return getRawMagic<IntPtrT>() == Magic || 160 sys::SwapByteOrder(getRawMagic<IntPtrT>()) == Magic; 161 } 162 163 template <class IntPtrT> 164 error_code RawInstrProfReader<IntPtrT>::readHeader() { 165 if (!hasFormat(*DataBuffer)) 166 return error(instrprof_error::bad_magic); 167 if (DataBuffer->getBufferSize() < sizeof(RawHeader)) 168 return error(instrprof_error::bad_header); 169 auto *Header = 170 reinterpret_cast<const RawHeader *>(DataBuffer->getBufferStart()); 171 ShouldSwapBytes = Header->Magic != getRawMagic<IntPtrT>(); 172 return readHeader(*Header); 173 } 174 175 static uint64_t getRawVersion() { 176 return 1; 177 } 178 179 template <class IntPtrT> 180 error_code RawInstrProfReader<IntPtrT>::readHeader(const RawHeader &Header) { 181 if (swap(Header.Version) != getRawVersion()) 182 return error(instrprof_error::unsupported_version); 183 184 CountersDelta = swap(Header.CountersDelta); 185 NamesDelta = swap(Header.NamesDelta); 186 auto DataSize = swap(Header.DataSize); 187 auto CountersSize = swap(Header.CountersSize); 188 auto NamesSize = swap(Header.NamesSize); 189 190 ptrdiff_t DataOffset = sizeof(RawHeader); 191 ptrdiff_t CountersOffset = DataOffset + sizeof(ProfileData) * DataSize; 192 ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize; 193 size_t FileSize = NamesOffset + sizeof(char) * NamesSize; 194 195 if (FileSize != DataBuffer->getBufferSize()) 196 return error(instrprof_error::bad_header); 197 198 const char *Start = DataBuffer->getBufferStart(); 199 Data = reinterpret_cast<const ProfileData *>(Start + DataOffset); 200 DataEnd = Data + DataSize; 201 CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset); 202 NamesStart = Start + NamesOffset; 203 204 return success(); 205 } 206 207 template <class IntPtrT> 208 error_code 209 RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) { 210 if (Data == DataEnd) 211 return error(instrprof_error::eof); 212 213 // Get the raw data. 214 StringRef RawName(getName(Data->NamePtr), swap(Data->NameSize)); 215 uint32_t NumCounters = swap(Data->NumCounters); 216 if (NumCounters == 0) 217 return error(instrprof_error::malformed); 218 auto RawCounts = makeArrayRef(getCounter(Data->CounterPtr), NumCounters); 219 220 // Check bounds. 221 auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart); 222 if (RawName.data() < NamesStart || 223 RawName.data() + RawName.size() > DataBuffer->getBufferEnd() || 224 RawCounts.data() < CountersStart || 225 RawCounts.data() + RawCounts.size() > NamesStartAsCounter) 226 return error(instrprof_error::malformed); 227 228 // Store the data in Record, byte-swapping as necessary. 229 Record.Hash = swap(Data->FuncHash); 230 Record.Name = RawName; 231 if (ShouldSwapBytes) { 232 Counts.clear(); 233 Counts.reserve(RawCounts.size()); 234 for (uint64_t Count : RawCounts) 235 Counts.push_back(swap(Count)); 236 Record.Counts = Counts; 237 } else 238 Record.Counts = RawCounts; 239 240 // Iterate. 241 ++Data; 242 return success(); 243 } 244 245 namespace llvm { 246 template class RawInstrProfReader<uint32_t>; 247 template class RawInstrProfReader<uint64_t>; 248 } 249 250 InstrProfLookupTrait::hash_value_type 251 InstrProfLookupTrait::ComputeHash(StringRef K) { 252 return IndexedInstrProf::ComputeHash(HashType, K); 253 } 254 255 bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) { 256 if (DataBuffer.getBufferSize() < 8) 257 return false; 258 using namespace support; 259 uint64_t Magic = 260 endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart()); 261 return Magic == IndexedInstrProf::Magic; 262 } 263 264 error_code IndexedInstrProfReader::readHeader() { 265 const unsigned char *Start = 266 (const unsigned char *)DataBuffer->getBufferStart(); 267 const unsigned char *Cur = Start; 268 if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24) 269 return error(instrprof_error::truncated); 270 271 using namespace support; 272 273 // Check the magic number. 274 uint64_t Magic = endian::readNext<uint64_t, little, unaligned>(Cur); 275 if (Magic != IndexedInstrProf::Magic) 276 return error(instrprof_error::bad_magic); 277 278 // Read the version. 279 uint64_t Version = endian::readNext<uint64_t, little, unaligned>(Cur); 280 if (Version != IndexedInstrProf::Version) 281 return error(instrprof_error::unsupported_version); 282 283 // Read the maximal function count. 284 MaxFunctionCount = endian::readNext<uint64_t, little, unaligned>(Cur); 285 286 // Read the hash type and start offset. 287 IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>( 288 endian::readNext<uint64_t, little, unaligned>(Cur)); 289 if (HashType > IndexedInstrProf::HashT::Last) 290 return error(instrprof_error::unsupported_hash_type); 291 uint64_t HashOffset = endian::readNext<uint64_t, little, unaligned>(Cur); 292 293 // The rest of the file is an on disk hash table. 294 Index.reset(InstrProfReaderIndex::Create(Start + HashOffset, Cur, Start, 295 InstrProfLookupTrait(HashType))); 296 // Set up our iterator for readNextRecord. 297 RecordIterator = Index->data_begin(); 298 299 return success(); 300 } 301 302 error_code IndexedInstrProfReader::getFunctionCounts( 303 StringRef FuncName, uint64_t &FuncHash, std::vector<uint64_t> &Counts) { 304 const auto &Iter = Index->find(FuncName); 305 if (Iter == Index->end()) 306 return error(instrprof_error::unknown_function); 307 308 // Found it. Make sure it's valid before giving back a result. 309 const InstrProfRecord &Record = *Iter; 310 if (Record.Name.empty()) 311 return error(instrprof_error::malformed); 312 FuncHash = Record.Hash; 313 Counts = Record.Counts; 314 return success(); 315 } 316 317 error_code IndexedInstrProfReader::readNextRecord(InstrProfRecord &Record) { 318 // Are we out of records? 319 if (RecordIterator == Index->data_end()) 320 return error(instrprof_error::eof); 321 322 // Read the next one. 323 Record = *RecordIterator; 324 ++RecordIterator; 325 if (Record.Name.empty()) 326 return error(instrprof_error::malformed); 327 return success(); 328 } 329