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/ADT/STLExtras.h" 17 #include <cassert> 18 19 using namespace llvm; 20 21 static ErrorOr<std::unique_ptr<MemoryBuffer>> 22 setupMemoryBuffer(std::string Path) { 23 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = 24 MemoryBuffer::getFileOrSTDIN(Path); 25 if (std::error_code EC = BufferOrErr.getError()) 26 return EC; 27 return std::move(BufferOrErr.get()); 28 } 29 30 static std::error_code initializeReader(InstrProfReader &Reader) { 31 return Reader.readHeader(); 32 } 33 34 ErrorOr<std::unique_ptr<InstrProfReader>> 35 InstrProfReader::create(std::string Path) { 36 // Set up the buffer to read. 37 auto BufferOrError = setupMemoryBuffer(Path); 38 if (std::error_code EC = BufferOrError.getError()) 39 return EC; 40 return InstrProfReader::create(std::move(BufferOrError.get())); 41 } 42 43 ErrorOr<std::unique_ptr<InstrProfReader>> 44 InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) { 45 // Sanity check the buffer. 46 if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max()) 47 return instrprof_error::too_large; 48 49 std::unique_ptr<InstrProfReader> Result; 50 // Create the reader. 51 if (IndexedInstrProfReader::hasFormat(*Buffer)) 52 Result.reset(new IndexedInstrProfReader(std::move(Buffer))); 53 else if (RawInstrProfReader64::hasFormat(*Buffer)) 54 Result.reset(new RawInstrProfReader64(std::move(Buffer))); 55 else if (RawInstrProfReader32::hasFormat(*Buffer)) 56 Result.reset(new RawInstrProfReader32(std::move(Buffer))); 57 else if (TextInstrProfReader::hasFormat(*Buffer)) 58 Result.reset(new TextInstrProfReader(std::move(Buffer))); 59 else 60 return instrprof_error::unrecognized_format; 61 62 // Initialize the reader and return the result. 63 if (std::error_code EC = initializeReader(*Result)) 64 return EC; 65 66 return std::move(Result); 67 } 68 69 ErrorOr<std::unique_ptr<IndexedInstrProfReader>> 70 IndexedInstrProfReader::create(std::string Path) { 71 // Set up the buffer to read. 72 auto BufferOrError = setupMemoryBuffer(Path); 73 if (std::error_code EC = BufferOrError.getError()) 74 return EC; 75 return IndexedInstrProfReader::create(std::move(BufferOrError.get())); 76 } 77 78 79 ErrorOr<std::unique_ptr<IndexedInstrProfReader>> 80 IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) { 81 // Sanity check the buffer. 82 if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max()) 83 return instrprof_error::too_large; 84 85 // Create the reader. 86 if (!IndexedInstrProfReader::hasFormat(*Buffer)) 87 return instrprof_error::bad_magic; 88 auto Result = llvm::make_unique<IndexedInstrProfReader>(std::move(Buffer)); 89 90 // Initialize the reader and return the result. 91 if (std::error_code EC = initializeReader(*Result)) 92 return EC; 93 94 return std::move(Result); 95 } 96 97 void InstrProfIterator::Increment() { 98 if (Reader->readNextRecord(Record)) 99 *this = InstrProfIterator(); 100 } 101 102 bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) { 103 // Verify that this really looks like plain ASCII text by checking a 104 // 'reasonable' number of characters (up to profile magic size). 105 size_t count = std::min(Buffer.getBufferSize(), sizeof(uint64_t)); 106 StringRef buffer = Buffer.getBufferStart(); 107 return count == 0 || 108 std::all_of(buffer.begin(), buffer.begin() + count, 109 [](char c) { return ::isprint(c) || ::isspace(c); }); 110 } 111 112 std::error_code TextInstrProfReader::readHeader() { 113 Symtab.reset(new InstrProfSymtab()); 114 return success(); 115 } 116 117 std::error_code 118 TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) { 119 120 #define CHECK_LINE_END(Line) \ 121 if (Line.is_at_end()) \ 122 return error(instrprof_error::truncated); 123 #define READ_NUM(Str, Dst) \ 124 if ((Str).getAsInteger(10, (Dst))) \ 125 return error(instrprof_error::malformed); 126 #define VP_READ_ADVANCE(Val) \ 127 CHECK_LINE_END(Line); \ 128 uint32_t Val; \ 129 READ_NUM((*Line), (Val)); \ 130 Line++; 131 132 if (Line.is_at_end()) 133 return success(); 134 135 uint32_t NumValueKinds; 136 if (Line->getAsInteger(10, NumValueKinds)) { 137 // No value profile data 138 return success(); 139 } 140 if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1) 141 return error(instrprof_error::malformed); 142 Line++; 143 144 for (uint32_t VK = 0; VK < NumValueKinds; VK++) { 145 VP_READ_ADVANCE(ValueKind); 146 if (ValueKind > IPVK_Last) 147 return error(instrprof_error::malformed); 148 VP_READ_ADVANCE(NumValueSites); 149 if (!NumValueSites) 150 continue; 151 152 Record.reserveSites(VK, NumValueSites); 153 for (uint32_t S = 0; S < NumValueSites; S++) { 154 VP_READ_ADVANCE(NumValueData); 155 156 std::vector<InstrProfValueData> CurrentValues; 157 for (uint32_t V = 0; V < NumValueData; V++) { 158 CHECK_LINE_END(Line); 159 std::pair<StringRef, StringRef> VD = Line->split(':'); 160 uint64_t TakenCount, Value; 161 if (VK == IPVK_IndirectCallTarget) { 162 Symtab->addFuncName(VD.first); 163 Value = IndexedInstrProf::ComputeHash(VD.first); 164 } else { 165 READ_NUM(VD.first, Value); 166 } 167 READ_NUM(VD.second, TakenCount); 168 CurrentValues.push_back({Value, TakenCount}); 169 Line++; 170 } 171 Record.addValueData(VK, S, CurrentValues.data(), NumValueData, nullptr); 172 } 173 } 174 return success(); 175 176 #undef CHECK_LINE_END 177 #undef READ_NUM 178 #undef VP_READ_ADVANCE 179 } 180 181 std::error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) { 182 // Skip empty lines and comments. 183 while (!Line.is_at_end() && (Line->empty() || Line->startswith("#"))) 184 ++Line; 185 // If we hit EOF while looking for a name, we're done. 186 if (Line.is_at_end()) { 187 Symtab->finalizeSymtab(); 188 return error(instrprof_error::eof); 189 } 190 191 // Read the function name. 192 Record.Name = *Line++; 193 Symtab->addFuncName(Record.Name); 194 195 // Read the function hash. 196 if (Line.is_at_end()) 197 return error(instrprof_error::truncated); 198 if ((Line++)->getAsInteger(0, Record.Hash)) 199 return error(instrprof_error::malformed); 200 201 // Read the number of counters. 202 uint64_t NumCounters; 203 if (Line.is_at_end()) 204 return error(instrprof_error::truncated); 205 if ((Line++)->getAsInteger(10, NumCounters)) 206 return error(instrprof_error::malformed); 207 if (NumCounters == 0) 208 return error(instrprof_error::malformed); 209 210 // Read each counter and fill our internal storage with the values. 211 Record.Counts.clear(); 212 Record.Counts.reserve(NumCounters); 213 for (uint64_t I = 0; I < NumCounters; ++I) { 214 if (Line.is_at_end()) 215 return error(instrprof_error::truncated); 216 uint64_t Count; 217 if ((Line++)->getAsInteger(10, Count)) 218 return error(instrprof_error::malformed); 219 Record.Counts.push_back(Count); 220 } 221 222 // Check if value profile data exists and read it if so. 223 if (std::error_code EC = readValueProfileData(Record)) 224 return EC; 225 226 // This is needed to avoid two pass parsing because llvm-profdata 227 // does dumping while reading. 228 Symtab->finalizeSymtab(); 229 return success(); 230 } 231 232 template <class IntPtrT> 233 bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) { 234 if (DataBuffer.getBufferSize() < sizeof(uint64_t)) 235 return false; 236 uint64_t Magic = 237 *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart()); 238 return RawInstrProf::getMagic<IntPtrT>() == Magic || 239 sys::getSwappedBytes(RawInstrProf::getMagic<IntPtrT>()) == Magic; 240 } 241 242 template <class IntPtrT> 243 std::error_code RawInstrProfReader<IntPtrT>::readHeader() { 244 if (!hasFormat(*DataBuffer)) 245 return error(instrprof_error::bad_magic); 246 if (DataBuffer->getBufferSize() < sizeof(RawInstrProf::Header)) 247 return error(instrprof_error::bad_header); 248 auto *Header = reinterpret_cast<const RawInstrProf::Header *>( 249 DataBuffer->getBufferStart()); 250 ShouldSwapBytes = Header->Magic != RawInstrProf::getMagic<IntPtrT>(); 251 return readHeader(*Header); 252 } 253 254 template <class IntPtrT> 255 std::error_code 256 RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) { 257 const char *End = DataBuffer->getBufferEnd(); 258 // Skip zero padding between profiles. 259 while (CurrentPos != End && *CurrentPos == 0) 260 ++CurrentPos; 261 // If there's nothing left, we're done. 262 if (CurrentPos == End) 263 return instrprof_error::eof; 264 // If there isn't enough space for another header, this is probably just 265 // garbage at the end of the file. 266 if (CurrentPos + sizeof(RawInstrProf::Header) > End) 267 return instrprof_error::malformed; 268 // The writer ensures each profile is padded to start at an aligned address. 269 if (reinterpret_cast<size_t>(CurrentPos) % alignOf<uint64_t>()) 270 return instrprof_error::malformed; 271 // The magic should have the same byte order as in the previous header. 272 uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos); 273 if (Magic != swap(RawInstrProf::getMagic<IntPtrT>())) 274 return instrprof_error::bad_magic; 275 276 // There's another profile to read, so we need to process the header. 277 auto *Header = reinterpret_cast<const RawInstrProf::Header *>(CurrentPos); 278 return readHeader(*Header); 279 } 280 281 template <class IntPtrT> 282 void RawInstrProfReader<IntPtrT>::createSymtab(InstrProfSymtab &Symtab) { 283 for (const RawInstrProf::ProfileData<IntPtrT> *I = Data; I != DataEnd; ++I) { 284 StringRef FunctionName(getName(I->NamePtr), swap(I->NameSize)); 285 Symtab.addFuncName(FunctionName); 286 const IntPtrT FPtr = swap(I->FunctionPointer); 287 if (!FPtr) 288 continue; 289 Symtab.mapAddress(FPtr, IndexedInstrProf::ComputeHash(FunctionName)); 290 } 291 Symtab.finalizeSymtab(); 292 } 293 294 template <class IntPtrT> 295 std::error_code 296 RawInstrProfReader<IntPtrT>::readHeader(const RawInstrProf::Header &Header) { 297 if (swap(Header.Version) != RawInstrProf::Version) 298 return error(instrprof_error::unsupported_version); 299 300 CountersDelta = swap(Header.CountersDelta); 301 NamesDelta = swap(Header.NamesDelta); 302 auto DataSize = swap(Header.DataSize); 303 auto CountersSize = swap(Header.CountersSize); 304 auto NamesSize = swap(Header.NamesSize); 305 auto ValueDataSize = swap(Header.ValueDataSize); 306 ValueKindLast = swap(Header.ValueKindLast); 307 308 auto DataSizeInBytes = DataSize * sizeof(RawInstrProf::ProfileData<IntPtrT>); 309 auto PaddingSize = getNumPaddingBytes(NamesSize); 310 311 ptrdiff_t DataOffset = sizeof(RawInstrProf::Header); 312 ptrdiff_t CountersOffset = DataOffset + DataSizeInBytes; 313 ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize; 314 ptrdiff_t ValueDataOffset = NamesOffset + NamesSize + PaddingSize; 315 size_t ProfileSize = ValueDataOffset + ValueDataSize; 316 317 auto *Start = reinterpret_cast<const char *>(&Header); 318 if (Start + ProfileSize > DataBuffer->getBufferEnd()) 319 return error(instrprof_error::bad_header); 320 321 Data = reinterpret_cast<const RawInstrProf::ProfileData<IntPtrT> *>( 322 Start + DataOffset); 323 DataEnd = Data + DataSize; 324 CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset); 325 NamesStart = Start + NamesOffset; 326 ValueDataStart = reinterpret_cast<const uint8_t *>(Start + ValueDataOffset); 327 ProfileEnd = Start + ProfileSize; 328 329 std::unique_ptr<InstrProfSymtab> NewSymtab = make_unique<InstrProfSymtab>(); 330 createSymtab(*NewSymtab.get()); 331 Symtab = std::move(NewSymtab); 332 return success(); 333 } 334 335 template <class IntPtrT> 336 std::error_code RawInstrProfReader<IntPtrT>::readName(InstrProfRecord &Record) { 337 Record.Name = StringRef(getName(Data->NamePtr), swap(Data->NameSize)); 338 if (Record.Name.data() < NamesStart || 339 Record.Name.data() + Record.Name.size() > 340 reinterpret_cast<const char *>(ValueDataStart)) 341 return error(instrprof_error::malformed); 342 return success(); 343 } 344 345 template <class IntPtrT> 346 std::error_code RawInstrProfReader<IntPtrT>::readFuncHash( 347 InstrProfRecord &Record) { 348 Record.Hash = swap(Data->FuncHash); 349 return success(); 350 } 351 352 template <class IntPtrT> 353 std::error_code RawInstrProfReader<IntPtrT>::readRawCounts( 354 InstrProfRecord &Record) { 355 uint32_t NumCounters = swap(Data->NumCounters); 356 IntPtrT CounterPtr = Data->CounterPtr; 357 if (NumCounters == 0) 358 return error(instrprof_error::malformed); 359 360 auto RawCounts = makeArrayRef(getCounter(CounterPtr), NumCounters); 361 auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart); 362 363 // Check bounds. 364 if (RawCounts.data() < CountersStart || 365 RawCounts.data() + RawCounts.size() > NamesStartAsCounter) 366 return error(instrprof_error::malformed); 367 368 if (ShouldSwapBytes) { 369 Record.Counts.clear(); 370 Record.Counts.reserve(RawCounts.size()); 371 for (uint64_t Count : RawCounts) 372 Record.Counts.push_back(swap(Count)); 373 } else 374 Record.Counts = RawCounts; 375 376 return success(); 377 } 378 379 template <class IntPtrT> 380 std::error_code 381 RawInstrProfReader<IntPtrT>::readValueProfilingData(InstrProfRecord &Record) { 382 383 Record.clearValueData(); 384 CurValueDataSize = 0; 385 // Need to match the logic in value profile dumper code in compiler-rt: 386 uint32_t NumValueKinds = 0; 387 for (uint32_t I = 0; I < IPVK_Last + 1; I++) 388 NumValueKinds += (Data->NumValueSites[I] != 0); 389 390 if (!NumValueKinds) 391 return success(); 392 393 ErrorOr<std::unique_ptr<ValueProfData>> VDataPtrOrErr = 394 ValueProfData::getValueProfData(ValueDataStart, 395 (const unsigned char *)ProfileEnd, 396 getDataEndianness()); 397 398 if (VDataPtrOrErr.getError()) 399 return VDataPtrOrErr.getError(); 400 401 VDataPtrOrErr.get()->deserializeTo(Record, &Symtab->getAddrHashMap()); 402 CurValueDataSize = VDataPtrOrErr.get()->getSize(); 403 return success(); 404 } 405 406 template <class IntPtrT> 407 std::error_code 408 RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) { 409 if (atEnd()) 410 if (std::error_code EC = readNextHeader(ProfileEnd)) 411 return EC; 412 413 // Read name ad set it in Record. 414 if (std::error_code EC = readName(Record)) 415 return EC; 416 417 // Read FuncHash and set it in Record. 418 if (std::error_code EC = readFuncHash(Record)) 419 return EC; 420 421 // Read raw counts and set Record. 422 if (std::error_code EC = readRawCounts(Record)) 423 return EC; 424 425 // Read value data and set Record. 426 if (std::error_code EC = readValueProfilingData(Record)) 427 return EC; 428 429 // Iterate. 430 advanceData(); 431 return success(); 432 } 433 434 namespace llvm { 435 template class RawInstrProfReader<uint32_t>; 436 template class RawInstrProfReader<uint64_t>; 437 } 438 439 InstrProfLookupTrait::hash_value_type 440 InstrProfLookupTrait::ComputeHash(StringRef K) { 441 return IndexedInstrProf::ComputeHash(HashType, K); 442 } 443 444 typedef InstrProfLookupTrait::data_type data_type; 445 typedef InstrProfLookupTrait::offset_type offset_type; 446 447 bool InstrProfLookupTrait::readValueProfilingData( 448 const unsigned char *&D, const unsigned char *const End) { 449 ErrorOr<std::unique_ptr<ValueProfData>> VDataPtrOrErr = 450 ValueProfData::getValueProfData(D, End, ValueProfDataEndianness); 451 452 if (VDataPtrOrErr.getError()) 453 return false; 454 455 VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), nullptr); 456 D += VDataPtrOrErr.get()->TotalSize; 457 458 return true; 459 } 460 461 data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D, 462 offset_type N) { 463 // Check if the data is corrupt. If so, don't try to read it. 464 if (N % sizeof(uint64_t)) 465 return data_type(); 466 467 DataBuffer.clear(); 468 std::vector<uint64_t> CounterBuffer; 469 470 using namespace support; 471 const unsigned char *End = D + N; 472 while (D < End) { 473 // Read hash. 474 if (D + sizeof(uint64_t) >= End) 475 return data_type(); 476 uint64_t Hash = endian::readNext<uint64_t, little, unaligned>(D); 477 478 // Initialize number of counters for FormatVersion == 1. 479 uint64_t CountsSize = N / sizeof(uint64_t) - 1; 480 // If format version is different then read the number of counters. 481 if (FormatVersion != IndexedInstrProf::ProfVersion::Version1) { 482 if (D + sizeof(uint64_t) > End) 483 return data_type(); 484 CountsSize = endian::readNext<uint64_t, little, unaligned>(D); 485 } 486 // Read counter values. 487 if (D + CountsSize * sizeof(uint64_t) > End) 488 return data_type(); 489 490 CounterBuffer.clear(); 491 CounterBuffer.reserve(CountsSize); 492 for (uint64_t J = 0; J < CountsSize; ++J) 493 CounterBuffer.push_back(endian::readNext<uint64_t, little, unaligned>(D)); 494 495 DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer)); 496 497 // Read value profiling data. 498 if (FormatVersion > IndexedInstrProf::ProfVersion::Version2 && 499 !readValueProfilingData(D, End)) { 500 DataBuffer.clear(); 501 return data_type(); 502 } 503 } 504 return DataBuffer; 505 } 506 507 template <typename HashTableImpl> 508 std::error_code InstrProfReaderIndex<HashTableImpl>::getRecords( 509 StringRef FuncName, ArrayRef<InstrProfRecord> &Data) { 510 auto Iter = HashTable->find(FuncName); 511 if (Iter == HashTable->end()) 512 return instrprof_error::unknown_function; 513 514 Data = (*Iter); 515 if (Data.empty()) 516 return instrprof_error::malformed; 517 518 return instrprof_error::success; 519 } 520 521 template <typename HashTableImpl> 522 std::error_code InstrProfReaderIndex<HashTableImpl>::getRecords( 523 ArrayRef<InstrProfRecord> &Data) { 524 if (atEnd()) 525 return instrprof_error::eof; 526 527 Data = *RecordIterator; 528 529 if (Data.empty()) 530 return instrprof_error::malformed; 531 532 return instrprof_error::success; 533 } 534 535 template <typename HashTableImpl> 536 InstrProfReaderIndex<HashTableImpl>::InstrProfReaderIndex( 537 const unsigned char *Buckets, const unsigned char *const Payload, 538 const unsigned char *const Base, IndexedInstrProf::HashT HashType, 539 uint64_t Version) { 540 FormatVersion = Version; 541 HashTable.reset(HashTableImpl::Create( 542 Buckets, Payload, Base, 543 typename HashTableImpl::InfoType(HashType, Version))); 544 RecordIterator = HashTable->data_begin(); 545 } 546 547 bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) { 548 if (DataBuffer.getBufferSize() < 8) 549 return false; 550 using namespace support; 551 uint64_t Magic = 552 endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart()); 553 // Verify that it's magical. 554 return Magic == IndexedInstrProf::Magic; 555 } 556 557 std::error_code IndexedInstrProfReader::readHeader() { 558 const unsigned char *Start = 559 (const unsigned char *)DataBuffer->getBufferStart(); 560 const unsigned char *Cur = Start; 561 if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24) 562 return error(instrprof_error::truncated); 563 564 using namespace support; 565 566 auto *Header = reinterpret_cast<const IndexedInstrProf::Header *>(Cur); 567 Cur += sizeof(IndexedInstrProf::Header); 568 569 // Check the magic number. 570 uint64_t Magic = endian::byte_swap<uint64_t, little>(Header->Magic); 571 if (Magic != IndexedInstrProf::Magic) 572 return error(instrprof_error::bad_magic); 573 574 // Read the version. 575 uint64_t FormatVersion = endian::byte_swap<uint64_t, little>(Header->Version); 576 if (FormatVersion > IndexedInstrProf::ProfVersion::CurrentVersion) 577 return error(instrprof_error::unsupported_version); 578 579 // Read the maximal function count. 580 MaxFunctionCount = 581 endian::byte_swap<uint64_t, little>(Header->MaxFunctionCount); 582 583 // Read the hash type and start offset. 584 IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>( 585 endian::byte_swap<uint64_t, little>(Header->HashType)); 586 if (HashType > IndexedInstrProf::HashT::Last) 587 return error(instrprof_error::unsupported_hash_type); 588 589 uint64_t HashOffset = endian::byte_swap<uint64_t, little>(Header->HashOffset); 590 591 // The rest of the file is an on disk hash table. 592 InstrProfReaderIndexBase *IndexPtr = nullptr; 593 IndexPtr = new InstrProfReaderIndex<OnDiskHashTableImplV3>( 594 Start + HashOffset, Cur, Start, HashType, FormatVersion); 595 Index.reset(IndexPtr); 596 return success(); 597 } 598 599 InstrProfSymtab &IndexedInstrProfReader::getSymtab() { 600 if (Symtab.get()) 601 return *Symtab.get(); 602 603 std::unique_ptr<InstrProfSymtab> NewSymtab = make_unique<InstrProfSymtab>(); 604 Index->populateSymtab(*NewSymtab.get()); 605 606 Symtab = std::move(NewSymtab); 607 return *Symtab.get(); 608 } 609 610 ErrorOr<InstrProfRecord> 611 IndexedInstrProfReader::getInstrProfRecord(StringRef FuncName, 612 uint64_t FuncHash) { 613 ArrayRef<InstrProfRecord> Data; 614 std::error_code EC = Index->getRecords(FuncName, Data); 615 if (EC != instrprof_error::success) 616 return EC; 617 // Found it. Look for counters with the right hash. 618 for (unsigned I = 0, E = Data.size(); I < E; ++I) { 619 // Check for a match and fill the vector if there is one. 620 if (Data[I].Hash == FuncHash) { 621 return std::move(Data[I]); 622 } 623 } 624 return error(instrprof_error::hash_mismatch); 625 } 626 627 std::error_code 628 IndexedInstrProfReader::getFunctionCounts(StringRef FuncName, uint64_t FuncHash, 629 std::vector<uint64_t> &Counts) { 630 ErrorOr<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash); 631 if (std::error_code EC = Record.getError()) 632 return EC; 633 634 Counts = Record.get().Counts; 635 return success(); 636 } 637 638 std::error_code IndexedInstrProfReader::readNextRecord( 639 InstrProfRecord &Record) { 640 static unsigned RecordIndex = 0; 641 642 ArrayRef<InstrProfRecord> Data; 643 644 std::error_code EC = Index->getRecords(Data); 645 if (EC != instrprof_error::success) 646 return error(EC); 647 648 Record = Data[RecordIndex++]; 649 if (RecordIndex >= Data.size()) { 650 Index->advanceToNextKey(); 651 RecordIndex = 0; 652 } 653 return success(); 654 } 655