blob: 8ad50615a25080440cf74e84975ecdf921a47f1d [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
Justin Bogner9e9a0572015-09-29 22:13:58 +0000305bool InstrProfLookupTrait::ReadValueProfilingData(
306 const unsigned char *&D, const unsigned char *const End) {
307
308 using namespace support;
309 // Read number of value kinds with value sites.
310 if (D + sizeof(uint64_t) > End)
311 return false;
312 uint64_t ValueKindCount = endian::readNext<uint64_t, little, unaligned>(D);
313
314 for (uint32_t Kind = 0; Kind < ValueKindCount; ++Kind) {
315
316 // Read value kind and number of value sites for kind.
317 if (D + 2 * sizeof(uint64_t) > End)
318 return false;
319 uint64_t ValueKind = endian::readNext<uint64_t, little, unaligned>(D);
320 uint64_t ValueSiteCount = endian::readNext<uint64_t, little, unaligned>(D);
321
322 std::vector<InstrProfValueSiteRecord> &ValueSites =
323 DataBuffer.back().getValueSitesForKind(ValueKind);
324 ValueSites.reserve(ValueSiteCount);
325 for (uint64_t VSite = 0; VSite < ValueSiteCount; ++VSite) {
326 // Read number of value data pairs at value site.
327 if (D + sizeof(uint64_t) > End)
328 return false;
329 uint64_t ValueDataCount =
330 endian::readNext<uint64_t, little, unaligned>(D);
331
332 // Check if there are as many ValueDataPairs as ValueDataCount in memory.
333 if (D + (ValueDataCount << 1) * sizeof(uint64_t) > End)
334 return false;
335
336 InstrProfValueSiteRecord VSiteRecord;
337 for (uint64_t VCount = 0; VCount < ValueDataCount; ++VCount) {
338 uint64_t Value = endian::readNext<uint64_t, little, unaligned>(D);
339 uint64_t NumTaken = endian::readNext<uint64_t, little, unaligned>(D);
340 switch (ValueKind) {
341 case IPVK_IndirectCallTarget: {
342 auto Result =
343 std::lower_bound(HashKeys.begin(), HashKeys.end(), Value,
344 [](const std::pair<uint64_t, const char *> &LHS,
345 uint64_t RHS) { return LHS.first < RHS; });
346 assert(Result != HashKeys.end() &&
347 "Hash does not match any known keys\n");
348 Value = (uint64_t)Result->second;
349 break;
350 }
351 }
352 VSiteRecord.ValueData.push_back(std::make_pair(Value, NumTaken));
353 }
354 ValueSites.push_back(std::move(VSiteRecord));
355 }
356 }
357 return true;
358}
359
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000360data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D,
361 offset_type N) {
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000362 // Check if the data is corrupt. If so, don't try to read it.
363 if (N % sizeof(uint64_t))
364 return data_type();
365
366 DataBuffer.clear();
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000367 std::vector<uint64_t> CounterBuffer;
Justin Bogner9e9a0572015-09-29 22:13:58 +0000368
369 using namespace support;
370 const unsigned char *End = D + N;
371 while (D < End) {
Xinliang David Lic7583872015-10-13 16:35:59 +0000372 // Read hash.
Justin Bogner9e9a0572015-09-29 22:13:58 +0000373 if (D + sizeof(uint64_t) >= End)
374 return data_type();
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000375 uint64_t Hash = endian::readNext<uint64_t, little, unaligned>(D);
376
Xinliang David Lic7583872015-10-13 16:35:59 +0000377 // Initialize number of counters for FormatVersion == 1.
Justin Bogner9e9a0572015-09-29 22:13:58 +0000378 uint64_t CountsSize = N / sizeof(uint64_t) - 1;
Xinliang David Lic7583872015-10-13 16:35:59 +0000379 // If format version is different then read the number of counters.
Justin Bogner9e9a0572015-09-29 22:13:58 +0000380 if (FormatVersion != 1) {
381 if (D + sizeof(uint64_t) > End)
382 return data_type();
383 CountsSize = endian::readNext<uint64_t, little, unaligned>(D);
384 }
Xinliang David Lic7583872015-10-13 16:35:59 +0000385 // Read counter values.
Justin Bogner9e9a0572015-09-29 22:13:58 +0000386 if (D + CountsSize * sizeof(uint64_t) > End)
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000387 return data_type();
388
389 CounterBuffer.clear();
Justin Bogner9e9a0572015-09-29 22:13:58 +0000390 CounterBuffer.reserve(CountsSize);
391 for (uint64_t J = 0; J < CountsSize; ++J)
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000392 CounterBuffer.push_back(endian::readNext<uint64_t, little, unaligned>(D));
393
394 DataBuffer.push_back(InstrProfRecord(K, Hash, std::move(CounterBuffer)));
Justin Bogner9e9a0572015-09-29 22:13:58 +0000395
Xinliang David Lic7583872015-10-13 16:35:59 +0000396 // Read value profiling data.
Justin Bogner9e9a0572015-09-29 22:13:58 +0000397 if (FormatVersion > 2 && !ReadValueProfilingData(D, End)) {
398 DataBuffer.clear();
399 return data_type();
400 }
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000401 }
402 return DataBuffer;
403}
404
Justin Bognerb7aa2632014-04-18 21:48:40 +0000405bool IndexedInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) {
406 if (DataBuffer.getBufferSize() < 8)
407 return false;
408 using namespace support;
409 uint64_t Magic =
410 endian::read<uint64_t, little, aligned>(DataBuffer.getBufferStart());
Xinliang David Lic7583872015-10-13 16:35:59 +0000411 // Verify that it's magical.
Justin Bognerb7aa2632014-04-18 21:48:40 +0000412 return Magic == IndexedInstrProf::Magic;
413}
414
Rafael Espindoladb4ed0b2014-06-13 02:24:39 +0000415std::error_code IndexedInstrProfReader::readHeader() {
Aaron Ballmana7c9ed52014-05-01 17:16:24 +0000416 const unsigned char *Start =
417 (const unsigned char *)DataBuffer->getBufferStart();
Justin Bognerb7aa2632014-04-18 21:48:40 +0000418 const unsigned char *Cur = Start;
Aaron Ballmana7c9ed52014-05-01 17:16:24 +0000419 if ((const unsigned char *)DataBuffer->getBufferEnd() - Cur < 24)
Justin Bognerb7aa2632014-04-18 21:48:40 +0000420 return error(instrprof_error::truncated);
421
422 using namespace support;
423
424 // Check the magic number.
425 uint64_t Magic = endian::readNext<uint64_t, little, unaligned>(Cur);
426 if (Magic != IndexedInstrProf::Magic)
427 return error(instrprof_error::bad_magic);
428
429 // Read the version.
Justin Bogner821d7472014-08-01 22:50:07 +0000430 FormatVersion = endian::readNext<uint64_t, little, unaligned>(Cur);
431 if (FormatVersion > IndexedInstrProf::Version)
Justin Bognerb7aa2632014-04-18 21:48:40 +0000432 return error(instrprof_error::unsupported_version);
433
434 // Read the maximal function count.
435 MaxFunctionCount = endian::readNext<uint64_t, little, unaligned>(Cur);
436
437 // Read the hash type and start offset.
438 IndexedInstrProf::HashT HashType = static_cast<IndexedInstrProf::HashT>(
439 endian::readNext<uint64_t, little, unaligned>(Cur));
440 if (HashType > IndexedInstrProf::HashT::Last)
441 return error(instrprof_error::unsupported_hash_type);
442 uint64_t HashOffset = endian::readNext<uint64_t, little, unaligned>(Cur);
443
444 // The rest of the file is an on disk hash table.
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000445 Index.reset(InstrProfReaderIndex::Create(
446 Start + HashOffset, Cur, Start,
447 InstrProfLookupTrait(HashType, FormatVersion)));
Justin Bogner9e9a0572015-09-29 22:13:58 +0000448
449 // Form the map of hash values to const char* keys in profiling data.
450 std::vector<std::pair<uint64_t, const char *>> HashKeys;
451 for (auto Key : Index->keys()) {
452 const char *KeyTableRef = StringTable.insertString(Key);
453 HashKeys.push_back(std::make_pair(ComputeHash(HashType, Key), KeyTableRef));
454 }
455 std::sort(HashKeys.begin(), HashKeys.end(), less_first());
Justin Bogner9e9a0572015-09-29 22:13:58 +0000456 HashKeys.erase(std::unique(HashKeys.begin(), HashKeys.end()), HashKeys.end());
457 // Set the hash key map for the InstrLookupTrait
458 Index->getInfoObj().setHashKeys(std::move(HashKeys));
Justin Bognerb7aa2632014-04-18 21:48:40 +0000459 // Set up our iterator for readNextRecord.
460 RecordIterator = Index->data_begin();
461
462 return success();
463}
464
Rafael Espindoladb4ed0b2014-06-13 02:24:39 +0000465std::error_code IndexedInstrProfReader::getFunctionCounts(
Justin Bogner821d7472014-08-01 22:50:07 +0000466 StringRef FuncName, uint64_t FuncHash, std::vector<uint64_t> &Counts) {
467 auto Iter = Index->find(FuncName);
Justin Bognerb7aa2632014-04-18 21:48:40 +0000468 if (Iter == Index->end())
469 return error(instrprof_error::unknown_function);
470
Justin Bogner821d7472014-08-01 22:50:07 +0000471 // Found it. Look for counters with the right hash.
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000472 ArrayRef<InstrProfRecord> Data = (*Iter);
473 if (Data.empty())
474 return error(instrprof_error::malformed);
475
476 for (unsigned I = 0, E = Data.size(); I < E; ++I) {
Justin Bogner821d7472014-08-01 22:50:07 +0000477 // Check for a match and fill the vector if there is one.
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000478 if (Data[I].Hash == FuncHash) {
479 Counts = Data[I].Counts;
Justin Bogner821d7472014-08-01 22:50:07 +0000480 return success();
481 }
482 }
483 return error(instrprof_error::hash_mismatch);
Justin Bognerb7aa2632014-04-18 21:48:40 +0000484}
485
Rafael Espindoladb4ed0b2014-06-13 02:24:39 +0000486std::error_code
487IndexedInstrProfReader::readNextRecord(InstrProfRecord &Record) {
Justin Bognerb7aa2632014-04-18 21:48:40 +0000488 // Are we out of records?
489 if (RecordIterator == Index->data_end())
490 return error(instrprof_error::eof);
491
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000492 if ((*RecordIterator).empty())
Justin Bognerfefdac12015-06-20 01:37:56 +0000493 return error(instrprof_error::malformed);
Justin Bognerfefdac12015-06-20 01:37:56 +0000494
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000495 static unsigned RecordIndex = 0;
496 ArrayRef<InstrProfRecord> Data = (*RecordIterator);
497 Record = Data[RecordIndex++];
498 if (RecordIndex >= Data.size()) {
Justin Bogner821d7472014-08-01 22:50:07 +0000499 ++RecordIterator;
Justin Bogner3a7d44c2015-06-22 23:58:05 +0000500 RecordIndex = 0;
Justin Bogner821d7472014-08-01 22:50:07 +0000501 }
Justin Bognerb7aa2632014-04-18 21:48:40 +0000502 return success();
503}