blob: 8a529a000c537de6f558c01a52672ab92f986b54 [file] [log] [blame]
Justin Bognerf8d79192014-03-21 17:24:48 +00001//=-- 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"
Justin Bognerb7aa2632014-04-18 21:48:40 +000016#include "InstrProfIndexed.h"
Benjamin Kramer0a446fd2015-03-01 21:28:53 +000017#include "llvm/ADT/STLExtras.h"
Justin Bognerf8d79192014-03-21 17:24:48 +000018#include <cassert>
19
20using namespace llvm;
21
Diego Novillofcd55602014-11-03 00:51:45 +000022static ErrorOr<std::unique_ptr<MemoryBuffer>>
23setupMemoryBuffer(std::string Path) {
Rafael Espindolaadf21f22014-07-06 17:43:13 +000024 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
25 MemoryBuffer::getFileOrSTDIN(Path);
26 if (std::error_code EC = BufferOrErr.getError())
Justin Bognerf8d79192014-03-21 17:24:48 +000027 return EC;
Justin Bogner2b6c5372015-02-18 01:58:17 +000028 return std::move(BufferOrErr.get());
Justin Bognerb7aa2632014-04-18 21:48:40 +000029}
30
Rafael Espindoladb4ed0b2014-06-13 02:24:39 +000031static std::error_code initializeReader(InstrProfReader &Reader) {
Justin Bognerb7aa2632014-04-18 21:48:40 +000032 return Reader.readHeader();
33}
34
Diego Novillofcd55602014-11-03 00:51:45 +000035ErrorOr<std::unique_ptr<InstrProfReader>>
36InstrProfReader::create(std::string Path) {
Justin Bognerb7aa2632014-04-18 21:48:40 +000037 // Set up the buffer to read.
Diego Novillofcd55602014-11-03 00:51:45 +000038 auto BufferOrError = setupMemoryBuffer(Path);
39 if (std::error_code EC = BufferOrError.getError())
Justin Bognerb7aa2632014-04-18 21:48:40 +000040 return EC;
Justin Bogner2b6c5372015-02-18 01:58:17 +000041 return InstrProfReader::create(std::move(BufferOrError.get()));
42}
Justin Bognerf8d79192014-03-21 17:24:48 +000043
Justin Bogner2b6c5372015-02-18 01:58:17 +000044ErrorOr<std::unique_ptr<InstrProfReader>>
45InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) {
46 // Sanity check the buffer.
47 if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
48 return instrprof_error::too_large;
49
Diego Novillofcd55602014-11-03 00:51:45 +000050 std::unique_ptr<InstrProfReader> Result;
Duncan P. N. Exon Smith09a67f42014-03-21 20:42:31 +000051 // Create the reader.
Justin Bognerb7aa2632014-04-18 21:48:40 +000052 if (IndexedInstrProfReader::hasFormat(*Buffer))
53 Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
54 else if (RawInstrProfReader64::hasFormat(*Buffer))
Duncan P. N. Exon Smith46803612014-03-23 03:38:12 +000055 Result.reset(new RawInstrProfReader64(std::move(Buffer)));
56 else if (RawInstrProfReader32::hasFormat(*Buffer))
57 Result.reset(new RawInstrProfReader32(std::move(Buffer)));
Duncan P. N. Exon Smith24b4b652014-03-21 18:26:05 +000058 else
Duncan P. N. Exon Smith4c5b7cb2014-03-21 20:42:34 +000059 Result.reset(new TextInstrProfReader(std::move(Buffer)));
Duncan P. N. Exon Smith09a67f42014-03-21 20:42:31 +000060
Justin Bognerb7aa2632014-04-18 21:48:40 +000061 // Initialize the reader and return the result.
Diego Novillofcd55602014-11-03 00:51:45 +000062 if (std::error_code EC = initializeReader(*Result))
63 return EC;
64
65 return std::move(Result);
Justin Bognerb7aa2632014-04-18 21:48:40 +000066}
67
Justin Bognerab89ed72015-02-16 21:28:58 +000068ErrorOr<std::unique_ptr<IndexedInstrProfReader>>
69IndexedInstrProfReader::create(std::string Path) {
Justin Bognerb7aa2632014-04-18 21:48:40 +000070 // Set up the buffer to read.
Diego Novillofcd55602014-11-03 00:51:45 +000071 auto BufferOrError = setupMemoryBuffer(Path);
72 if (std::error_code EC = BufferOrError.getError())
Justin Bognerb7aa2632014-04-18 21:48:40 +000073 return EC;
Justin Bogner2b6c5372015-02-18 01:58:17 +000074 return IndexedInstrProfReader::create(std::move(BufferOrError.get()));
75}
Justin Bognerb7aa2632014-04-18 21:48:40 +000076
Justin Bogner2b6c5372015-02-18 01:58:17 +000077
78ErrorOr<std::unique_ptr<IndexedInstrProfReader>>
79IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) {
80 // Sanity check the buffer.
81 if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
82 return instrprof_error::too_large;
Justin Bognerab89ed72015-02-16 21:28:58 +000083
Justin Bognerb7aa2632014-04-18 21:48:40 +000084 // Create the reader.
85 if (!IndexedInstrProfReader::hasFormat(*Buffer))
86 return instrprof_error::bad_magic;
Justin Bogner2b6c5372015-02-18 01:58:17 +000087 auto Result = llvm::make_unique<IndexedInstrProfReader>(std::move(Buffer));
Justin Bognerb7aa2632014-04-18 21:48:40 +000088
89 // Initialize the reader and return the result.
Justin Bognerab89ed72015-02-16 21:28:58 +000090 if (std::error_code EC = initializeReader(*Result))
91 return EC;
92
93 return std::move(Result);
Justin Bognerf8d79192014-03-21 17:24:48 +000094}
95
96void InstrProfIterator::Increment() {
97 if (Reader->readNextRecord(Record))
98 *this = InstrProfIterator();
99}
100
Rafael Espindoladb4ed0b2014-06-13 02:24:39 +0000101std::error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) {
Justin Bognercf36a362014-07-29 22:29:23 +0000102 // Skip empty lines and comments.
103 while (!Line.is_at_end() && (Line->empty() || Line->startswith("#")))
Justin Bognerf8d79192014-03-21 17:24:48 +0000104 ++Line;
105 // If we hit EOF while looking for a name, we're done.
106 if (Line.is_at_end())
107 return error(instrprof_error::eof);
108
109 // Read the function name.
110 Record.Name = *Line++;
111
112 // Read the function hash.
113 if (Line.is_at_end())
114 return error(instrprof_error::truncated);
Justin Bognerf95ca072015-03-09 18:54:49 +0000115 if ((Line++)->getAsInteger(0, Record.Hash))
Justin Bognerf8d79192014-03-21 17:24:48 +0000116 return error(instrprof_error::malformed);
117
118 // Read the number of counters.
119 uint64_t NumCounters;
120 if (Line.is_at_end())
121 return error(instrprof_error::truncated);
122 if ((Line++)->getAsInteger(10, NumCounters))
123 return error(instrprof_error::malformed);
Justin Bognerb59d7c72014-04-25 02:45:33 +0000124 if (NumCounters == 0)
125 return error(instrprof_error::malformed);
Justin Bognerf8d79192014-03-21 17:24:48 +0000126
127 // Read each counter and fill our internal storage with the values.
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000128 Record.Counts.clear();
129 Record.Counts.reserve(NumCounters);
Justin Bognerf8d79192014-03-21 17:24:48 +0000130 for (uint64_t I = 0; I < NumCounters; ++I) {
131 if (Line.is_at_end())
132 return error(instrprof_error::truncated);
133 uint64_t Count;
134 if ((Line++)->getAsInteger(10, Count))
135 return error(instrprof_error::malformed);
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000136 Record.Counts.push_back(Count);
Justin Bognerf8d79192014-03-21 17:24:48 +0000137 }
Justin Bognerf8d79192014-03-21 17:24:48 +0000138
139 return success();
140}
Duncan P. N. Exon Smith24b4b652014-03-21 18:26:05 +0000141
Duncan P. N. Exon Smith46803612014-03-23 03:38:12 +0000142template <class IntPtrT>
143static uint64_t getRawMagic();
144
145template <>
146uint64_t getRawMagic<uint64_t>() {
Duncan P. N. Exon Smith09a67f42014-03-21 20:42:31 +0000147 return
Duncan P. N. Exon Smith745a2bf2014-03-21 20:42:37 +0000148 uint64_t(255) << 56 |
149 uint64_t('l') << 48 |
150 uint64_t('p') << 40 |
151 uint64_t('r') << 32 |
152 uint64_t('o') << 24 |
153 uint64_t('f') << 16 |
154 uint64_t('r') << 8 |
155 uint64_t(129);
Duncan P. N. Exon Smith09a67f42014-03-21 20:42:31 +0000156}
157
Duncan P. N. Exon Smith46803612014-03-23 03:38:12 +0000158template <>
159uint64_t getRawMagic<uint32_t>() {
160 return
161 uint64_t(255) << 56 |
162 uint64_t('l') << 48 |
163 uint64_t('p') << 40 |
164 uint64_t('r') << 32 |
165 uint64_t('o') << 24 |
166 uint64_t('f') << 16 |
167 uint64_t('R') << 8 |
168 uint64_t(129);
Duncan P. N. Exon Smith09a67f42014-03-21 20:42:31 +0000169}
170
Duncan P. N. Exon Smith46803612014-03-23 03:38:12 +0000171template <class IntPtrT>
172bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) {
Duncan P. N. Exon Smithd7d83472014-03-24 00:47:18 +0000173 if (DataBuffer.getBufferSize() < sizeof(uint64_t))
Duncan P. N. Exon Smith46803612014-03-23 03:38:12 +0000174 return false;
Duncan P. N. Exon Smithd7d83472014-03-24 00:47:18 +0000175 uint64_t Magic =
176 *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart());
177 return getRawMagic<IntPtrT>() == Magic ||
Artyom Skrobovef5e8672014-06-14 11:36:01 +0000178 sys::getSwappedBytes(getRawMagic<IntPtrT>()) == Magic;
Duncan P. N. Exon Smith46803612014-03-23 03:38:12 +0000179}
180
181template <class IntPtrT>
Rafael Espindoladb4ed0b2014-06-13 02:24:39 +0000182std::error_code RawInstrProfReader<IntPtrT>::readHeader() {
Duncan P. N. Exon Smith09a67f42014-03-21 20:42:31 +0000183 if (!hasFormat(*DataBuffer))
184 return error(instrprof_error::bad_magic);
Duncan P. N. Exon Smith24b4b652014-03-21 18:26:05 +0000185 if (DataBuffer->getBufferSize() < sizeof(RawHeader))
Duncan P. N. Exon Smith531bb482014-03-21 20:42:28 +0000186 return error(instrprof_error::bad_header);
Duncan P. N. Exon Smithd7d83472014-03-24 00:47:18 +0000187 auto *Header =
188 reinterpret_cast<const RawHeader *>(DataBuffer->getBufferStart());
Duncan P. N. Exon Smith46803612014-03-23 03:38:12 +0000189 ShouldSwapBytes = Header->Magic != getRawMagic<IntPtrT>();
Duncan P. N. Exon Smith24b4b652014-03-21 18:26:05 +0000190 return readHeader(*Header);
191}
192
Justin Bognera119f322014-05-16 00:38:00 +0000193template <class IntPtrT>
Rafael Espindoladb4ed0b2014-06-13 02:24:39 +0000194std::error_code
195RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
Justin Bognera119f322014-05-16 00:38:00 +0000196 const char *End = DataBuffer->getBufferEnd();
197 // Skip zero padding between profiles.
198 while (CurrentPos != End && *CurrentPos == 0)
199 ++CurrentPos;
200 // If there's nothing left, we're done.
201 if (CurrentPos == End)
202 return instrprof_error::eof;
203 // If there isn't enough space for another header, this is probably just
204 // garbage at the end of the file.
205 if (CurrentPos + sizeof(RawHeader) > End)
206 return instrprof_error::malformed;
Justin Bogner54b11282014-09-12 21:22:55 +0000207 // The writer ensures each profile is padded to start at an aligned address.
208 if (reinterpret_cast<size_t>(CurrentPos) % alignOf<uint64_t>())
209 return instrprof_error::malformed;
Justin Bognera119f322014-05-16 00:38:00 +0000210 // The magic should have the same byte order as in the previous header.
211 uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
212 if (Magic != swap(getRawMagic<IntPtrT>()))
213 return instrprof_error::bad_magic;
214
215 // There's another profile to read, so we need to process the header.
216 auto *Header = reinterpret_cast<const RawHeader *>(CurrentPos);
217 return readHeader(*Header);
218}
219
Duncan P. N. Exon Smith09a67f42014-03-21 20:42:31 +0000220static uint64_t getRawVersion() {
221 return 1;
222}
223
Duncan P. N. Exon Smith46803612014-03-23 03:38:12 +0000224template <class IntPtrT>
Rafael Espindoladb4ed0b2014-06-13 02:24:39 +0000225std::error_code
226RawInstrProfReader<IntPtrT>::readHeader(const RawHeader &Header) {
Duncan P. N. Exon Smith24b4b652014-03-21 18:26:05 +0000227 if (swap(Header.Version) != getRawVersion())
228 return error(instrprof_error::unsupported_version);
229
230 CountersDelta = swap(Header.CountersDelta);
231 NamesDelta = swap(Header.NamesDelta);
232 auto DataSize = swap(Header.DataSize);
233 auto CountersSize = swap(Header.CountersSize);
234 auto NamesSize = swap(Header.NamesSize);
235
236 ptrdiff_t DataOffset = sizeof(RawHeader);
237 ptrdiff_t CountersOffset = DataOffset + sizeof(ProfileData) * DataSize;
238 ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize;
Justin Bognera119f322014-05-16 00:38:00 +0000239 size_t ProfileSize = NamesOffset + sizeof(char) * NamesSize;
Duncan P. N. Exon Smith24b4b652014-03-21 18:26:05 +0000240
Justin Bognera119f322014-05-16 00:38:00 +0000241 auto *Start = reinterpret_cast<const char *>(&Header);
242 if (Start + ProfileSize > DataBuffer->getBufferEnd())
Duncan P. N. Exon Smith531bb482014-03-21 20:42:28 +0000243 return error(instrprof_error::bad_header);
Duncan P. N. Exon Smith24b4b652014-03-21 18:26:05 +0000244
Duncan P. N. Exon Smithd7d83472014-03-24 00:47:18 +0000245 Data = reinterpret_cast<const ProfileData *>(Start + DataOffset);
Duncan P. N. Exon Smith24b4b652014-03-21 18:26:05 +0000246 DataEnd = Data + DataSize;
Duncan P. N. Exon Smithd7d83472014-03-24 00:47:18 +0000247 CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset);
248 NamesStart = Start + NamesOffset;
Justin Bognera119f322014-05-16 00:38:00 +0000249 ProfileEnd = Start + ProfileSize;
Duncan P. N. Exon Smith24b4b652014-03-21 18:26:05 +0000250
251 return success();
252}
253
Duncan P. N. Exon Smith46803612014-03-23 03:38:12 +0000254template <class IntPtrT>
Rafael Espindoladb4ed0b2014-06-13 02:24:39 +0000255std::error_code
Duncan P. N. Exon Smith46803612014-03-23 03:38:12 +0000256RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) {
Duncan P. N. Exon Smith24b4b652014-03-21 18:26:05 +0000257 if (Data == DataEnd)
Rafael Espindoladb4ed0b2014-06-13 02:24:39 +0000258 if (std::error_code EC = readNextHeader(ProfileEnd))
Justin Bognera119f322014-05-16 00:38:00 +0000259 return EC;
Duncan P. N. Exon Smith24b4b652014-03-21 18:26:05 +0000260
261 // Get the raw data.
262 StringRef RawName(getName(Data->NamePtr), swap(Data->NameSize));
Justin Bognerb59d7c72014-04-25 02:45:33 +0000263 uint32_t NumCounters = swap(Data->NumCounters);
264 if (NumCounters == 0)
265 return error(instrprof_error::malformed);
266 auto RawCounts = makeArrayRef(getCounter(Data->CounterPtr), NumCounters);
Duncan P. N. Exon Smith24b4b652014-03-21 18:26:05 +0000267
268 // Check bounds.
Duncan P. N. Exon Smithd7d83472014-03-24 00:47:18 +0000269 auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart);
Duncan P. N. Exon Smith24b4b652014-03-21 18:26:05 +0000270 if (RawName.data() < NamesStart ||
271 RawName.data() + RawName.size() > DataBuffer->getBufferEnd() ||
272 RawCounts.data() < CountersStart ||
Duncan P. N. Exon Smithd7d83472014-03-24 00:47:18 +0000273 RawCounts.data() + RawCounts.size() > NamesStartAsCounter)
Duncan P. N. Exon Smith24b4b652014-03-21 18:26:05 +0000274 return error(instrprof_error::malformed);
275
276 // Store the data in Record, byte-swapping as necessary.
277 Record.Hash = swap(Data->FuncHash);
278 Record.Name = RawName;
279 if (ShouldSwapBytes) {
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000280 Record.Counts.clear();
281 Record.Counts.reserve(RawCounts.size());
Duncan P. N. Exon Smith24b4b652014-03-21 18:26:05 +0000282 for (uint64_t Count : RawCounts)
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000283 Record.Counts.push_back(swap(Count));
Duncan P. N. Exon Smith24b4b652014-03-21 18:26:05 +0000284 } else
285 Record.Counts = RawCounts;
286
287 // Iterate.
288 ++Data;
289 return success();
290}
Duncan P. N. Exon Smith46803612014-03-23 03:38:12 +0000291
292namespace llvm {
293template class RawInstrProfReader<uint32_t>;
294template class RawInstrProfReader<uint64_t>;
295}
Justin Bognerb7aa2632014-04-18 21:48:40 +0000296
Justin Bognerb5d368e2014-04-18 22:00:22 +0000297InstrProfLookupTrait::hash_value_type
298InstrProfLookupTrait::ComputeHash(StringRef K) {
299 return IndexedInstrProf::ComputeHash(HashType, K);
300}
301
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000302typedef InstrProfLookupTrait::data_type data_type;
303typedef InstrProfLookupTrait::offset_type offset_type;
304
305data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D,
306 offset_type N) {
307
308 // Check if the data is corrupt. If so, don't try to read it.
309 if (N % sizeof(uint64_t))
310 return data_type();
311
312 DataBuffer.clear();
313 uint64_t NumCounts;
314 uint64_t NumEntries = N / sizeof(uint64_t);
315 std::vector<uint64_t> CounterBuffer;
316 for (uint64_t I = 0; I < NumEntries; I += NumCounts) {
317 using namespace support;
318 // The function hash comes first.
319 uint64_t Hash = endian::readNext<uint64_t, little, unaligned>(D);
320
321 if (++I >= NumEntries)
322 return data_type();
323
324 // In v1, we have at least one count.
325 // Later, we have the number of counts.
326 NumCounts = (1 == FormatVersion)
327 ? NumEntries - I
328 : endian::readNext<uint64_t, little, unaligned>(D);
329 if (1 != FormatVersion)
330 ++I;
331
332 // If we have more counts than data, this is bogus.
333 if (I + NumCounts > NumEntries)
334 return data_type();
335
336 CounterBuffer.clear();
337 for (unsigned J = 0; J < NumCounts; ++J)
338 CounterBuffer.push_back(endian::readNext<uint64_t, little, unaligned>(D));
339
340 DataBuffer.push_back(InstrProfRecord(K, Hash, std::move(CounterBuffer)));
341 }
342 return DataBuffer;
343}
344
Justin Bognerb7aa2632014-04-18 21:48:40 +0000345bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) {
346 if (DataBuffer.getBufferSize() < 8)
347 return false;
348 using namespace support;
349 uint64_t Magic =
350 endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart());
351 return Magic == IndexedInstrProf::Magic;
352}
353
Rafael Espindoladb4ed0b2014-06-13 02:24:39 +0000354std::error_code IndexedInstrProfReader::readHeader() {
Aaron Ballmana7c9ed52014-05-01 17:16:24 +0000355 const unsigned char *Start =
356 (const unsigned char *)DataBuffer->getBufferStart();
Justin Bognerb7aa2632014-04-18 21:48:40 +0000357 const unsigned char *Cur = Start;
Aaron Ballmana7c9ed52014-05-01 17:16:24 +0000358 if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
Justin Bognerb7aa2632014-04-18 21:48:40 +0000359 return error(instrprof_error::truncated);
360
361 using namespace support;
362
363 // Check the magic number.
364 uint64_t Magic = endian::readNext<uint64_t, little, unaligned>(Cur);
365 if (Magic != IndexedInstrProf::Magic)
366 return error(instrprof_error::bad_magic);
367
368 // Read the version.
Justin Bogner821d7472014-08-01 22:50:07 +0000369 FormatVersion = endian::readNext<uint64_t, little, unaligned>(Cur);
370 if (FormatVersion > IndexedInstrProf::Version)
Justin Bognerb7aa2632014-04-18 21:48:40 +0000371 return error(instrprof_error::unsupported_version);
372
373 // Read the maximal function count.
374 MaxFunctionCount = endian::readNext<uint64_t, little, unaligned>(Cur);
375
376 // Read the hash type and start offset.
377 IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>(
378 endian::readNext<uint64_t, little, unaligned>(Cur));
379 if (HashType > IndexedInstrProf::HashT::Last)
380 return error(instrprof_error::unsupported_hash_type);
381 uint64_t HashOffset = endian::readNext<uint64_t, little, unaligned>(Cur);
382
383 // The rest of the file is an on disk hash table.
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000384 Index.reset(InstrProfReaderIndex::Create(
385 Start + HashOffset, Cur, Start,
386 InstrProfLookupTrait(HashType, FormatVersion)));
Justin Bognerb7aa2632014-04-18 21:48:40 +0000387 // Set up our iterator for readNextRecord.
388 RecordIterator = Index->data_begin();
389
390 return success();
391}
392
Rafael Espindoladb4ed0b2014-06-13 02:24:39 +0000393std::error_code IndexedInstrProfReader::getFunctionCounts(
Justin Bogner821d7472014-08-01 22:50:07 +0000394 StringRef FuncName, uint64_t FuncHash, std::vector<uint64_t> &Counts) {
395 auto Iter = Index->find(FuncName);
Justin Bognerb7aa2632014-04-18 21:48:40 +0000396 if (Iter == Index->end())
397 return error(instrprof_error::unknown_function);
398
Justin Bogner821d7472014-08-01 22:50:07 +0000399 // Found it. Look for counters with the right hash.
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000400 ArrayRef<InstrProfRecord> Data = (*Iter);
401 if (Data.empty())
402 return error(instrprof_error::malformed);
403
404 for (unsigned I = 0, E = Data.size(); I < E; ++I) {
Justin Bogner821d7472014-08-01 22:50:07 +0000405 // Check for a match and fill the vector if there is one.
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000406 if (Data[I].Hash == FuncHash) {
407 Counts = Data[I].Counts;
Justin Bogner821d7472014-08-01 22:50:07 +0000408 return success();
409 }
410 }
411 return error(instrprof_error::hash_mismatch);
Justin Bognerb7aa2632014-04-18 21:48:40 +0000412}
413
Rafael Espindoladb4ed0b2014-06-13 02:24:39 +0000414std::error_code
415IndexedInstrProfReader::readNextRecord(InstrProfRecord &Record) {
Justin Bognerb7aa2632014-04-18 21:48:40 +0000416 // Are we out of records?
417 if (RecordIterator == Index->data_end())
418 return error(instrprof_error::eof);
419
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000420 if ((*RecordIterator).empty())
Justin Bognerfefdac12015-06-20 01:37:56 +0000421 return error(instrprof_error::malformed);
Justin Bognerfefdac12015-06-20 01:37:56 +0000422
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000423 static unsigned RecordIndex = 0;
424 ArrayRef<InstrProfRecord> Data = (*RecordIterator);
425 Record = Data[RecordIndex++];
426 if (RecordIndex >= Data.size()) {
Justin Bogner821d7472014-08-01 22:50:07 +0000427 ++RecordIterator;
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000428 RecordIndex = 0;
Justin Bogner821d7472014-08-01 22:50:07 +0000429 }
Justin Bognerb7aa2632014-04-18 21:48:40 +0000430 return success();
431}