Justin Bogner | f8d7919 | 2014-03-21 17:24:48 +0000 | [diff] [blame] | 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" |
Justin Bogner | f8d7919 | 2014-03-21 17:24:48 +0000 | [diff] [blame] | 17 | |
| 18 | #include <cassert> |
| 19 | |
| 20 | using namespace llvm; |
| 21 | |
| 22 | error_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 | |
Duncan P. N. Exon Smith | 09a67f4 | 2014-03-21 20:42:31 +0000 | [diff] [blame] | 32 | // Create the reader. |
Duncan P. N. Exon Smith | 4680361 | 2014-03-23 03:38:12 +0000 | [diff] [blame] | 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))); |
Duncan P. N. Exon Smith | 24b4b65 | 2014-03-21 18:26:05 +0000 | [diff] [blame] | 37 | else |
Duncan P. N. Exon Smith | 4c5b7cb | 2014-03-21 20:42:34 +0000 | [diff] [blame] | 38 | Result.reset(new TextInstrProfReader(std::move(Buffer))); |
Duncan P. N. Exon Smith | 09a67f4 | 2014-03-21 20:42:31 +0000 | [diff] [blame] | 39 | |
| 40 | // Read the header and return the result. |
Duncan P. N. Exon Smith | 531bb48 | 2014-03-21 20:42:28 +0000 | [diff] [blame] | 41 | return Result->readHeader(); |
Justin Bogner | f8d7919 | 2014-03-21 17:24:48 +0000 | [diff] [blame] | 42 | } |
| 43 | |
| 44 | void InstrProfIterator::Increment() { |
| 45 | if (Reader->readNextRecord(Record)) |
| 46 | *this = InstrProfIterator(); |
| 47 | } |
| 48 | |
| 49 | error_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 | } |
Duncan P. N. Exon Smith | 24b4b65 | 2014-03-21 18:26:05 +0000 | [diff] [blame] | 89 | |
Duncan P. N. Exon Smith | 4680361 | 2014-03-23 03:38:12 +0000 | [diff] [blame] | 90 | template <class IntPtrT> |
| 91 | static uint64_t getRawMagic(); |
| 92 | |
| 93 | template <> |
| 94 | uint64_t getRawMagic<uint64_t>() { |
Duncan P. N. Exon Smith | 09a67f4 | 2014-03-21 20:42:31 +0000 | [diff] [blame] | 95 | return |
Duncan P. N. Exon Smith | 745a2bf | 2014-03-21 20:42:37 +0000 | [diff] [blame] | 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); |
Duncan P. N. Exon Smith | 09a67f4 | 2014-03-21 20:42:31 +0000 | [diff] [blame] | 104 | } |
| 105 | |
Duncan P. N. Exon Smith | 4680361 | 2014-03-23 03:38:12 +0000 | [diff] [blame] | 106 | template <> |
| 107 | uint64_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); |
Duncan P. N. Exon Smith | 09a67f4 | 2014-03-21 20:42:31 +0000 | [diff] [blame] | 117 | } |
| 118 | |
Duncan P. N. Exon Smith | 4680361 | 2014-03-23 03:38:12 +0000 | [diff] [blame] | 119 | template <class IntPtrT> |
| 120 | bool RawInstrProfReader<IntPtrT>::hasFormat(const MemoryBuffer &DataBuffer) { |
Duncan P. N. Exon Smith | d7d8347 | 2014-03-24 00:47:18 +0000 | [diff] [blame^] | 121 | if (DataBuffer.getBufferSize() < sizeof(uint64_t)) |
Duncan P. N. Exon Smith | 4680361 | 2014-03-23 03:38:12 +0000 | [diff] [blame] | 122 | return false; |
Duncan P. N. Exon Smith | d7d8347 | 2014-03-24 00:47:18 +0000 | [diff] [blame^] | 123 | uint64_t Magic = |
| 124 | *reinterpret_cast<const uint64_t *>(DataBuffer.getBufferStart()); |
| 125 | return getRawMagic<IntPtrT>() == Magic || |
| 126 | sys::SwapByteOrder(getRawMagic<IntPtrT>()) == Magic; |
Duncan P. N. Exon Smith | 4680361 | 2014-03-23 03:38:12 +0000 | [diff] [blame] | 127 | } |
| 128 | |
| 129 | template <class IntPtrT> |
| 130 | error_code RawInstrProfReader<IntPtrT>::readHeader() { |
Duncan P. N. Exon Smith | 09a67f4 | 2014-03-21 20:42:31 +0000 | [diff] [blame] | 131 | if (!hasFormat(*DataBuffer)) |
| 132 | return error(instrprof_error::bad_magic); |
Duncan P. N. Exon Smith | 24b4b65 | 2014-03-21 18:26:05 +0000 | [diff] [blame] | 133 | if (DataBuffer->getBufferSize() < sizeof(RawHeader)) |
Duncan P. N. Exon Smith | 531bb48 | 2014-03-21 20:42:28 +0000 | [diff] [blame] | 134 | return error(instrprof_error::bad_header); |
Duncan P. N. Exon Smith | d7d8347 | 2014-03-24 00:47:18 +0000 | [diff] [blame^] | 135 | auto *Header = |
| 136 | reinterpret_cast<const RawHeader *>(DataBuffer->getBufferStart()); |
Duncan P. N. Exon Smith | 4680361 | 2014-03-23 03:38:12 +0000 | [diff] [blame] | 137 | ShouldSwapBytes = Header->Magic != getRawMagic<IntPtrT>(); |
Duncan P. N. Exon Smith | 24b4b65 | 2014-03-21 18:26:05 +0000 | [diff] [blame] | 138 | return readHeader(*Header); |
| 139 | } |
| 140 | |
Duncan P. N. Exon Smith | 09a67f4 | 2014-03-21 20:42:31 +0000 | [diff] [blame] | 141 | static uint64_t getRawVersion() { |
| 142 | return 1; |
| 143 | } |
| 144 | |
Duncan P. N. Exon Smith | 4680361 | 2014-03-23 03:38:12 +0000 | [diff] [blame] | 145 | template <class IntPtrT> |
| 146 | error_code RawInstrProfReader<IntPtrT>::readHeader(const RawHeader &Header) { |
Duncan P. N. Exon Smith | 24b4b65 | 2014-03-21 18:26:05 +0000 | [diff] [blame] | 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()) |
Duncan P. N. Exon Smith | 531bb48 | 2014-03-21 20:42:28 +0000 | [diff] [blame] | 162 | return error(instrprof_error::bad_header); |
Duncan P. N. Exon Smith | 24b4b65 | 2014-03-21 18:26:05 +0000 | [diff] [blame] | 163 | |
Duncan P. N. Exon Smith | d7d8347 | 2014-03-24 00:47:18 +0000 | [diff] [blame^] | 164 | const char *Start = DataBuffer->getBufferStart(); |
| 165 | Data = reinterpret_cast<const ProfileData *>(Start + DataOffset); |
Duncan P. N. Exon Smith | 24b4b65 | 2014-03-21 18:26:05 +0000 | [diff] [blame] | 166 | DataEnd = Data + DataSize; |
Duncan P. N. Exon Smith | d7d8347 | 2014-03-24 00:47:18 +0000 | [diff] [blame^] | 167 | CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset); |
| 168 | NamesStart = Start + NamesOffset; |
Duncan P. N. Exon Smith | 24b4b65 | 2014-03-21 18:26:05 +0000 | [diff] [blame] | 169 | |
| 170 | return success(); |
| 171 | } |
| 172 | |
Duncan P. N. Exon Smith | 4680361 | 2014-03-23 03:38:12 +0000 | [diff] [blame] | 173 | template <class IntPtrT> |
| 174 | error_code |
| 175 | RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) { |
Duncan P. N. Exon Smith | 24b4b65 | 2014-03-21 18:26:05 +0000 | [diff] [blame] | 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. |
Duncan P. N. Exon Smith | d7d8347 | 2014-03-24 00:47:18 +0000 | [diff] [blame^] | 185 | auto *NamesStartAsCounter = reinterpret_cast<const uint64_t *>(NamesStart); |
Duncan P. N. Exon Smith | 24b4b65 | 2014-03-21 18:26:05 +0000 | [diff] [blame] | 186 | if (RawName.data() < NamesStart || |
| 187 | RawName.data() + RawName.size() > DataBuffer->getBufferEnd() || |
| 188 | RawCounts.data() < CountersStart || |
Duncan P. N. Exon Smith | d7d8347 | 2014-03-24 00:47:18 +0000 | [diff] [blame^] | 189 | RawCounts.data() + RawCounts.size() > NamesStartAsCounter) |
Duncan P. N. Exon Smith | 24b4b65 | 2014-03-21 18:26:05 +0000 | [diff] [blame] | 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 | } |
Duncan P. N. Exon Smith | 4680361 | 2014-03-23 03:38:12 +0000 | [diff] [blame] | 208 | |
| 209 | namespace llvm { |
| 210 | template class RawInstrProfReader<uint32_t>; |
| 211 | template class RawInstrProfReader<uint64_t>; |
| 212 | } |