/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/ProfileData/SampleProfReader.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- SampleProfReader.cpp - Read LLVM sample profile data ---------------===// |
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 implements the class that reads LLVM sample profiles. It |
11 | | // supports three file formats: text, binary and gcov. |
12 | | // |
13 | | // The textual representation is useful for debugging and testing purposes. The |
14 | | // binary representation is more compact, resulting in smaller file sizes. |
15 | | // |
16 | | // The gcov encoding is the one generated by GCC's AutoFDO profile creation |
17 | | // tool (https://github.com/google/autofdo) |
18 | | // |
19 | | // All three encodings can be used interchangeably as an input sample profile. |
20 | | // |
21 | | //===----------------------------------------------------------------------===// |
22 | | |
23 | | #include "llvm/ProfileData/SampleProfReader.h" |
24 | | #include "llvm/ADT/DenseMap.h" |
25 | | #include "llvm/ADT/STLExtras.h" |
26 | | #include "llvm/ADT/StringRef.h" |
27 | | #include "llvm/IR/ProfileSummary.h" |
28 | | #include "llvm/ProfileData/ProfileCommon.h" |
29 | | #include "llvm/ProfileData/SampleProf.h" |
30 | | #include "llvm/Support/ErrorOr.h" |
31 | | #include "llvm/Support/LEB128.h" |
32 | | #include "llvm/Support/LineIterator.h" |
33 | | #include "llvm/Support/MemoryBuffer.h" |
34 | | #include "llvm/Support/raw_ostream.h" |
35 | | #include <algorithm> |
36 | | #include <cstddef> |
37 | | #include <cstdint> |
38 | | #include <limits> |
39 | | #include <memory> |
40 | | #include <system_error> |
41 | | #include <vector> |
42 | | |
43 | | using namespace llvm; |
44 | | using namespace sampleprof; |
45 | | |
46 | | /// \brief Dump the function profile for \p FName. |
47 | | /// |
48 | | /// \param FName Name of the function to print. |
49 | | /// \param OS Stream to emit the output to. |
50 | | void SampleProfileReader::dumpFunctionProfile(StringRef FName, |
51 | 22 | raw_ostream &OS) { |
52 | 22 | OS << "Function: " << FName << ": " << Profiles[FName]; |
53 | 22 | } |
54 | | |
55 | | /// \brief Dump all the function profiles found on stream \p OS. |
56 | 11 | void SampleProfileReader::dump(raw_ostream &OS) { |
57 | 11 | for (const auto &I : Profiles) |
58 | 21 | dumpFunctionProfile(I.getKey(), OS); |
59 | 11 | } |
60 | | |
61 | | /// \brief Parse \p Input as function head. |
62 | | /// |
63 | | /// Parse one line of \p Input, and update function name in \p FName, |
64 | | /// function's total sample count in \p NumSamples, function's entry |
65 | | /// count in \p NumHeadSamples. |
66 | | /// |
67 | | /// \returns true if parsing is successful. |
68 | | static bool ParseHead(const StringRef &Input, StringRef &FName, |
69 | 217 | uint64_t &NumSamples, uint64_t &NumHeadSamples) { |
70 | 217 | if (Input[0] == ' ') |
71 | 0 | return false; |
72 | 217 | size_t n2 = Input.rfind(':'); |
73 | 217 | size_t n1 = Input.rfind(':', n2 - 1); |
74 | 217 | FName = Input.substr(0, n1); |
75 | 217 | if (Input.substr(n1 + 1, n2 - n1 - 1).getAsInteger(10, NumSamples)) |
76 | 3 | return false; |
77 | 214 | if (214 Input.substr(n2 + 1).getAsInteger(10, NumHeadSamples)214 ) |
78 | 2 | return false; |
79 | 212 | return true; |
80 | 212 | } |
81 | | |
82 | | /// \brief Returns true if line offset \p L is legal (only has 16 bits). |
83 | 495 | static bool isOffsetLegal(unsigned L) { return (L & 0xffff) == L; } |
84 | | |
85 | | /// \brief Parse \p Input as line sample. |
86 | | /// |
87 | | /// \param Input input line. |
88 | | /// \param IsCallsite true if the line represents an inlined callsite. |
89 | | /// \param Depth the depth of the inline stack. |
90 | | /// \param NumSamples total samples of the line/inlined callsite. |
91 | | /// \param LineOffset line offset to the start of the function. |
92 | | /// \param Discriminator discriminator of the line. |
93 | | /// \param TargetCountMap map from indirect call target to count. |
94 | | /// |
95 | | /// returns true if parsing is successful. |
96 | | static bool ParseLine(const StringRef &Input, bool &IsCallsite, uint32_t &Depth, |
97 | | uint64_t &NumSamples, uint32_t &LineOffset, |
98 | | uint32_t &Discriminator, StringRef &CalleeName, |
99 | 524 | DenseMap<StringRef, uint64_t> &TargetCountMap) { |
100 | 1.22k | for (Depth = 0; Input[Depth] == ' '1.22k ; Depth++696 ) |
101 | 696 | ; |
102 | 524 | if (Depth == 0) |
103 | 0 | return false; |
104 | 524 | |
105 | 524 | size_t n1 = Input.find(':'); |
106 | 524 | StringRef Loc = Input.substr(Depth, n1 - Depth); |
107 | 524 | size_t n2 = Loc.find('.'); |
108 | 524 | if (n2 == StringRef::npos524 ) { |
109 | 377 | if (Loc.getAsInteger(10, LineOffset) || 377 !isOffsetLegal(LineOffset)377 ) |
110 | 0 | return false; |
111 | 377 | Discriminator = 0; |
112 | 524 | } else { |
113 | 147 | if (Loc.substr(0, n2).getAsInteger(10, LineOffset)) |
114 | 0 | return false; |
115 | 147 | if (147 Loc.substr(n2 + 1).getAsInteger(10, Discriminator)147 ) |
116 | 2 | return false; |
117 | 522 | } |
118 | 522 | |
119 | 522 | StringRef Rest = Input.substr(n1 + 2); |
120 | 522 | if (Rest[0] >= '0' && 522 Rest[0] <= '9'520 ) { |
121 | 447 | IsCallsite = false; |
122 | 447 | size_t n3 = Rest.find(' '); |
123 | 447 | if (n3 == StringRef::npos447 ) { |
124 | 410 | if (Rest.getAsInteger(10, NumSamples)) |
125 | 0 | return false; |
126 | 37 | } else { |
127 | 37 | if (Rest.substr(0, n3).getAsInteger(10, NumSamples)) |
128 | 0 | return false; |
129 | 447 | } |
130 | 493 | while (447 n3 != StringRef::npos493 ) { |
131 | 46 | n3 += Rest.substr(n3).find_first_not_of(' '); |
132 | 46 | Rest = Rest.substr(n3); |
133 | 46 | n3 = Rest.find(' '); |
134 | 46 | StringRef pair = Rest; |
135 | 46 | if (n3 != StringRef::npos46 ) { |
136 | 9 | pair = Rest.substr(0, n3); |
137 | 9 | } |
138 | 46 | size_t n4 = pair.find(':'); |
139 | 46 | uint64_t count; |
140 | 46 | if (pair.substr(n4 + 1).getAsInteger(10, count)) |
141 | 0 | return false; |
142 | 46 | TargetCountMap[pair.substr(0, n4)] = count; |
143 | 46 | } |
144 | 522 | } else { |
145 | 75 | IsCallsite = true; |
146 | 75 | size_t n3 = Rest.find_last_of(':'); |
147 | 75 | CalleeName = Rest.substr(0, n3); |
148 | 75 | if (Rest.substr(n3 + 1).getAsInteger(10, NumSamples)) |
149 | 4 | return false; |
150 | 518 | } |
151 | 518 | return true; |
152 | 518 | } |
153 | | |
154 | | /// \brief Load samples from a text file. |
155 | | /// |
156 | | /// See the documentation at the top of the file for an explanation of |
157 | | /// the expected format. |
158 | | /// |
159 | | /// \returns true if the file was loaded successfully, false otherwise. |
160 | 85 | std::error_code SampleProfileReaderText::read() { |
161 | 85 | line_iterator LineIt(*Buffer, /*SkipBlanks=*/true, '#'); |
162 | 85 | sampleprof_error Result = sampleprof_error::success; |
163 | 85 | |
164 | 85 | InlineCallStack InlineStack; |
165 | 85 | |
166 | 734 | for (; !LineIt.is_at_eof()734 ; ++LineIt649 ) { |
167 | 657 | if ((*LineIt)[(*LineIt).find_first_not_of(' ')] == '#') |
168 | 4 | continue; |
169 | 653 | // Read the header of each function. |
170 | 653 | // |
171 | 653 | // Note that for function identifiers we are actually expecting |
172 | 653 | // mangled names, but we may not always get them. This happens when |
173 | 653 | // the compiler decides not to emit the function (e.g., it was inlined |
174 | 653 | // and removed). In this case, the binary will not have the linkage |
175 | 653 | // name for the function, so the profiler will emit the function's |
176 | 653 | // unmangled name, which may contain characters like ':' and '>' in its |
177 | 653 | // name (member functions, templates, etc). |
178 | 653 | // |
179 | 653 | // The only requirement we place on the identifier, then, is that it |
180 | 653 | // should not begin with a number. |
181 | 653 | if (653 (*LineIt)[0] != ' '653 ) { |
182 | 129 | uint64_t NumSamples, NumHeadSamples; |
183 | 129 | StringRef FName; |
184 | 129 | if (!ParseHead(*LineIt, FName, NumSamples, NumHeadSamples)129 ) { |
185 | 2 | reportError(LineIt.line_number(), |
186 | 2 | "Expected 'mangled_name:NUM:NUM', found " + *LineIt); |
187 | 2 | return sampleprof_error::malformed; |
188 | 2 | } |
189 | 127 | Profiles[FName] = FunctionSamples(); |
190 | 127 | FunctionSamples &FProfile = Profiles[FName]; |
191 | 127 | FProfile.setName(FName); |
192 | 127 | MergeResult(Result, FProfile.addTotalSamples(NumSamples)); |
193 | 127 | MergeResult(Result, FProfile.addHeadSamples(NumHeadSamples)); |
194 | 127 | InlineStack.clear(); |
195 | 127 | InlineStack.push_back(&FProfile); |
196 | 653 | } else { |
197 | 524 | uint64_t NumSamples; |
198 | 524 | StringRef FName; |
199 | 524 | DenseMap<StringRef, uint64_t> TargetCountMap; |
200 | 524 | bool IsCallsite; |
201 | 524 | uint32_t Depth, LineOffset, Discriminator; |
202 | 524 | if (!ParseLine(*LineIt, IsCallsite, Depth, NumSamples, LineOffset, |
203 | 524 | Discriminator, FName, TargetCountMap)) { |
204 | 6 | reportError(LineIt.line_number(), |
205 | 6 | "Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " + |
206 | 6 | *LineIt); |
207 | 6 | return sampleprof_error::malformed; |
208 | 6 | } |
209 | 518 | if (518 IsCallsite518 ) { |
210 | 99 | while (InlineStack.size() > Depth99 ) { |
211 | 28 | InlineStack.pop_back(); |
212 | 28 | } |
213 | 71 | FunctionSamples &FSamples = InlineStack.back()->functionSamplesAt( |
214 | 71 | LineLocation(LineOffset, Discriminator))[FName]; |
215 | 71 | FSamples.setName(FName); |
216 | 71 | MergeResult(Result, FSamples.addTotalSamples(NumSamples)); |
217 | 71 | InlineStack.push_back(&FSamples); |
218 | 518 | } else { |
219 | 447 | while (InlineStack.size() > Depth447 ) { |
220 | 0 | InlineStack.pop_back(); |
221 | 0 | } |
222 | 447 | FunctionSamples &FProfile = *InlineStack.back(); |
223 | 46 | for (const auto &name_count : TargetCountMap) { |
224 | 46 | MergeResult(Result, FProfile.addCalledTargetSamples( |
225 | 46 | LineOffset, Discriminator, name_count.first, |
226 | 46 | name_count.second)); |
227 | 46 | } |
228 | 447 | MergeResult(Result, FProfile.addBodySamples(LineOffset, Discriminator, |
229 | 447 | NumSamples)); |
230 | 447 | } |
231 | 524 | } |
232 | 657 | } |
233 | 77 | if (77 Result == sampleprof_error::success77 ) |
234 | 77 | computeSummary(); |
235 | 77 | |
236 | 77 | return Result; |
237 | 85 | } |
238 | | |
239 | 88 | bool SampleProfileReaderText::hasFormat(const MemoryBuffer &Buffer) { |
240 | 88 | bool result = false; |
241 | 88 | |
242 | 88 | // Check that the first non-comment line is a valid function header. |
243 | 88 | line_iterator LineIt(Buffer, /*SkipBlanks=*/true, '#'); |
244 | 88 | if (!LineIt.is_at_eof()88 ) { |
245 | 88 | if ((*LineIt)[0] != ' '88 ) { |
246 | 88 | uint64_t NumSamples, NumHeadSamples; |
247 | 88 | StringRef FName; |
248 | 88 | result = ParseHead(*LineIt, FName, NumSamples, NumHeadSamples); |
249 | 88 | } |
250 | 88 | } |
251 | 88 | |
252 | 88 | return result; |
253 | 88 | } |
254 | | |
255 | 1.51k | template <typename T> ErrorOr<T> SampleProfileReaderBinary::readNumber() { |
256 | 1.51k | unsigned NumBytesRead = 0; |
257 | 1.51k | std::error_code EC; |
258 | 1.51k | uint64_t Val = decodeULEB128(Data, &NumBytesRead); |
259 | 1.51k | |
260 | 1.51k | if (Val > std::numeric_limits<T>::max()) |
261 | 0 | EC = sampleprof_error::malformed; |
262 | 1.51k | else if (1.51k Data + NumBytesRead > End1.51k ) |
263 | 0 | EC = sampleprof_error::truncated; |
264 | 1.51k | else |
265 | 1.51k | EC = sampleprof_error::success; |
266 | 1.51k | |
267 | 1.51k | if (EC1.51k ) { |
268 | 0 | reportError(0, EC.message()); |
269 | 0 | return EC; |
270 | 0 | } |
271 | 1.51k | |
272 | 1.51k | Data += NumBytesRead; |
273 | 1.51k | return static_cast<T>(Val); |
274 | 1.51k | } llvm::ErrorOr<unsigned int> llvm::sampleprof::SampleProfileReaderBinary::readNumber<unsigned int>() Line | Count | Source | 255 | 287 | template <typename T> ErrorOr<T> SampleProfileReaderBinary::readNumber() { | 256 | 287 | unsigned NumBytesRead = 0; | 257 | 287 | std::error_code EC; | 258 | 287 | uint64_t Val = decodeULEB128(Data, &NumBytesRead); | 259 | 287 | | 260 | 287 | if (Val > std::numeric_limits<T>::max()) | 261 | 0 | EC = sampleprof_error::malformed; | 262 | 287 | else if (287 Data + NumBytesRead > End287 ) | 263 | 0 | EC = sampleprof_error::truncated; | 264 | 287 | else | 265 | 287 | EC = sampleprof_error::success; | 266 | 287 | | 267 | 287 | if (EC287 ) { | 268 | 0 | reportError(0, EC.message()); | 269 | 0 | return EC; | 270 | 0 | } | 271 | 287 | | 272 | 287 | Data += NumBytesRead; | 273 | 287 | return static_cast<T>(Val); | 274 | 287 | } |
llvm::ErrorOr<unsigned long long> llvm::sampleprof::SampleProfileReaderBinary::readNumber<unsigned long long>() Line | Count | Source | 255 | 1.22k | template <typename T> ErrorOr<T> SampleProfileReaderBinary::readNumber() { | 256 | 1.22k | unsigned NumBytesRead = 0; | 257 | 1.22k | std::error_code EC; | 258 | 1.22k | uint64_t Val = decodeULEB128(Data, &NumBytesRead); | 259 | 1.22k | | 260 | 1.22k | if (Val > std::numeric_limits<T>::max()) | 261 | 0 | EC = sampleprof_error::malformed; | 262 | 1.22k | else if (1.22k Data + NumBytesRead > End1.22k ) | 263 | 0 | EC = sampleprof_error::truncated; | 264 | 1.22k | else | 265 | 1.22k | EC = sampleprof_error::success; | 266 | 1.22k | | 267 | 1.22k | if (EC1.22k ) { | 268 | 0 | reportError(0, EC.message()); | 269 | 0 | return EC; | 270 | 0 | } | 271 | 1.22k | | 272 | 1.22k | Data += NumBytesRead; | 273 | 1.22k | return static_cast<T>(Val); | 274 | 1.22k | } |
|
275 | | |
276 | 39 | ErrorOr<StringRef> SampleProfileReaderBinary::readString() { |
277 | 39 | std::error_code EC; |
278 | 39 | StringRef Str(reinterpret_cast<const char *>(Data)); |
279 | 39 | if (Data + Str.size() + 1 > End39 ) { |
280 | 0 | EC = sampleprof_error::truncated; |
281 | 0 | reportError(0, EC.message()); |
282 | 0 | return EC; |
283 | 0 | } |
284 | 39 | |
285 | 39 | Data += Str.size() + 1; |
286 | 39 | return Str; |
287 | 39 | } |
288 | | |
289 | 61 | ErrorOr<StringRef> SampleProfileReaderBinary::readStringFromTable() { |
290 | 61 | std::error_code EC; |
291 | 61 | auto Idx = readNumber<uint32_t>(); |
292 | 61 | if (std::error_code EC = Idx.getError()) |
293 | 0 | return EC; |
294 | 61 | if (61 *Idx >= NameTable.size()61 ) |
295 | 0 | return sampleprof_error::truncated_name_table; |
296 | 61 | return NameTable[*Idx]; |
297 | 61 | } |
298 | | |
299 | | std::error_code |
300 | 48 | SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) { |
301 | 48 | auto NumSamples = readNumber<uint64_t>(); |
302 | 48 | if (std::error_code EC = NumSamples.getError()) |
303 | 0 | return EC; |
304 | 48 | FProfile.addTotalSamples(*NumSamples); |
305 | 48 | |
306 | 48 | // Read the samples in the body. |
307 | 48 | auto NumRecords = readNumber<uint32_t>(); |
308 | 48 | if (std::error_code EC = NumRecords.getError()) |
309 | 0 | return EC; |
310 | 48 | |
311 | 166 | for (uint32_t I = 0; 48 I < *NumRecords166 ; ++I118 ) { |
312 | 118 | auto LineOffset = readNumber<uint64_t>(); |
313 | 118 | if (std::error_code EC = LineOffset.getError()) |
314 | 0 | return EC; |
315 | 118 | |
316 | 118 | if (118 !isOffsetLegal(*LineOffset)118 ) { |
317 | 0 | return std::error_code(); |
318 | 0 | } |
319 | 118 | |
320 | 118 | auto Discriminator = readNumber<uint64_t>(); |
321 | 118 | if (std::error_code EC = Discriminator.getError()) |
322 | 0 | return EC; |
323 | 118 | |
324 | 118 | auto NumSamples = readNumber<uint64_t>(); |
325 | 118 | if (std::error_code EC = NumSamples.getError()) |
326 | 0 | return EC; |
327 | 118 | |
328 | 118 | auto NumCalls = readNumber<uint32_t>(); |
329 | 118 | if (std::error_code EC = NumCalls.getError()) |
330 | 0 | return EC; |
331 | 118 | |
332 | 131 | for (uint32_t J = 0; 118 J < *NumCalls131 ; ++J13 ) { |
333 | 13 | auto CalledFunction(readStringFromTable()); |
334 | 13 | if (std::error_code EC = CalledFunction.getError()) |
335 | 0 | return EC; |
336 | 13 | |
337 | 13 | auto CalledFunctionSamples = readNumber<uint64_t>(); |
338 | 13 | if (std::error_code EC = CalledFunctionSamples.getError()) |
339 | 0 | return EC; |
340 | 13 | |
341 | 13 | FProfile.addCalledTargetSamples(*LineOffset, *Discriminator, |
342 | 13 | *CalledFunction, *CalledFunctionSamples); |
343 | 13 | } |
344 | 118 | |
345 | 118 | FProfile.addBodySamples(*LineOffset, *Discriminator, *NumSamples); |
346 | 118 | } |
347 | 48 | |
348 | 48 | // Read all the samples for inlined function calls. |
349 | 48 | auto NumCallsites = readNumber<uint32_t>(); |
350 | 48 | if (std::error_code EC = NumCallsites.getError()) |
351 | 0 | return EC; |
352 | 48 | |
353 | 69 | for (uint32_t J = 0; 48 J < *NumCallsites69 ; ++J21 ) { |
354 | 21 | auto LineOffset = readNumber<uint64_t>(); |
355 | 21 | if (std::error_code EC = LineOffset.getError()) |
356 | 0 | return EC; |
357 | 21 | |
358 | 21 | auto Discriminator = readNumber<uint64_t>(); |
359 | 21 | if (std::error_code EC = Discriminator.getError()) |
360 | 0 | return EC; |
361 | 21 | |
362 | 21 | auto FName(readStringFromTable()); |
363 | 21 | if (std::error_code EC = FName.getError()) |
364 | 0 | return EC; |
365 | 21 | |
366 | 21 | FunctionSamples &CalleeProfile = FProfile.functionSamplesAt( |
367 | 21 | LineLocation(*LineOffset, *Discriminator))[*FName]; |
368 | 21 | CalleeProfile.setName(*FName); |
369 | 21 | if (std::error_code EC = readProfile(CalleeProfile)) |
370 | 0 | return EC; |
371 | 21 | } |
372 | 48 | |
373 | 48 | return sampleprof_error::success; |
374 | 48 | } |
375 | | |
376 | 12 | std::error_code SampleProfileReaderBinary::read() { |
377 | 39 | while (!at_eof()39 ) { |
378 | 27 | auto NumHeadSamples = readNumber<uint64_t>(); |
379 | 27 | if (std::error_code EC = NumHeadSamples.getError()) |
380 | 0 | return EC; |
381 | 27 | |
382 | 27 | auto FName(readStringFromTable()); |
383 | 27 | if (std::error_code EC = FName.getError()) |
384 | 0 | return EC; |
385 | 27 | |
386 | 27 | Profiles[*FName] = FunctionSamples(); |
387 | 27 | FunctionSamples &FProfile = Profiles[*FName]; |
388 | 27 | FProfile.setName(*FName); |
389 | 27 | |
390 | 27 | FProfile.addHeadSamples(*NumHeadSamples); |
391 | 27 | |
392 | 27 | if (std::error_code EC = readProfile(FProfile)) |
393 | 0 | return EC; |
394 | 27 | } |
395 | 12 | |
396 | 12 | return sampleprof_error::success; |
397 | 12 | } |
398 | | |
399 | 12 | std::error_code SampleProfileReaderBinary::readHeader() { |
400 | 12 | Data = reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()); |
401 | 12 | End = Data + Buffer->getBufferSize(); |
402 | 12 | |
403 | 12 | // Read and check the magic identifier. |
404 | 12 | auto Magic = readNumber<uint64_t>(); |
405 | 12 | if (std::error_code EC = Magic.getError()) |
406 | 0 | return EC; |
407 | 12 | else if (12 *Magic != SPMagic()12 ) |
408 | 0 | return sampleprof_error::bad_magic; |
409 | 12 | |
410 | 12 | // Read the version number. |
411 | 12 | auto Version = readNumber<uint64_t>(); |
412 | 12 | if (std::error_code EC = Version.getError()) |
413 | 0 | return EC; |
414 | 12 | else if (12 *Version != SPVersion()12 ) |
415 | 0 | return sampleprof_error::unsupported_version; |
416 | 12 | |
417 | 12 | if (std::error_code 12 EC12 = readSummary()) |
418 | 0 | return EC; |
419 | 12 | |
420 | 12 | // Read the name table. |
421 | 12 | auto Size = readNumber<uint32_t>(); |
422 | 12 | if (std::error_code EC = Size.getError()) |
423 | 0 | return EC; |
424 | 12 | NameTable.reserve(*Size); |
425 | 51 | for (uint32_t I = 0; I < *Size51 ; ++I39 ) { |
426 | 39 | auto Name(readString()); |
427 | 39 | if (std::error_code EC = Name.getError()) |
428 | 0 | return EC; |
429 | 39 | NameTable.push_back(*Name); |
430 | 39 | } |
431 | 12 | |
432 | 12 | return sampleprof_error::success; |
433 | 12 | } |
434 | | |
435 | | std::error_code SampleProfileReaderBinary::readSummaryEntry( |
436 | 216 | std::vector<ProfileSummaryEntry> &Entries) { |
437 | 216 | auto Cutoff = readNumber<uint64_t>(); |
438 | 216 | if (std::error_code EC = Cutoff.getError()) |
439 | 0 | return EC; |
440 | 216 | |
441 | 216 | auto MinBlockCount = readNumber<uint64_t>(); |
442 | 216 | if (std::error_code EC = MinBlockCount.getError()) |
443 | 0 | return EC; |
444 | 216 | |
445 | 216 | auto NumBlocks = readNumber<uint64_t>(); |
446 | 216 | if (std::error_code EC = NumBlocks.getError()) |
447 | 0 | return EC; |
448 | 216 | |
449 | 216 | Entries.emplace_back(*Cutoff, *MinBlockCount, *NumBlocks); |
450 | 216 | return sampleprof_error::success; |
451 | 216 | } |
452 | | |
453 | 12 | std::error_code SampleProfileReaderBinary::readSummary() { |
454 | 12 | auto TotalCount = readNumber<uint64_t>(); |
455 | 12 | if (std::error_code EC = TotalCount.getError()) |
456 | 0 | return EC; |
457 | 12 | |
458 | 12 | auto MaxBlockCount = readNumber<uint64_t>(); |
459 | 12 | if (std::error_code EC = MaxBlockCount.getError()) |
460 | 0 | return EC; |
461 | 12 | |
462 | 12 | auto MaxFunctionCount = readNumber<uint64_t>(); |
463 | 12 | if (std::error_code EC = MaxFunctionCount.getError()) |
464 | 0 | return EC; |
465 | 12 | |
466 | 12 | auto NumBlocks = readNumber<uint64_t>(); |
467 | 12 | if (std::error_code EC = NumBlocks.getError()) |
468 | 0 | return EC; |
469 | 12 | |
470 | 12 | auto NumFunctions = readNumber<uint64_t>(); |
471 | 12 | if (std::error_code EC = NumFunctions.getError()) |
472 | 0 | return EC; |
473 | 12 | |
474 | 12 | auto NumSummaryEntries = readNumber<uint64_t>(); |
475 | 12 | if (std::error_code EC = NumSummaryEntries.getError()) |
476 | 0 | return EC; |
477 | 12 | |
478 | 12 | std::vector<ProfileSummaryEntry> Entries; |
479 | 228 | for (unsigned i = 0; i < *NumSummaryEntries228 ; i++216 ) { |
480 | 216 | std::error_code EC = readSummaryEntry(Entries); |
481 | 216 | if (EC != sampleprof_error::success) |
482 | 0 | return EC; |
483 | 216 | } |
484 | 12 | Summary = llvm::make_unique<ProfileSummary>( |
485 | 12 | ProfileSummary::PSK_Sample, Entries, *TotalCount, *MaxBlockCount, 0, |
486 | 12 | *MaxFunctionCount, *NumBlocks, *NumFunctions); |
487 | 12 | |
488 | 12 | return sampleprof_error::success; |
489 | 12 | } |
490 | | |
491 | 108 | bool SampleProfileReaderBinary::hasFormat(const MemoryBuffer &Buffer) { |
492 | 108 | const uint8_t *Data = |
493 | 108 | reinterpret_cast<const uint8_t *>(Buffer.getBufferStart()); |
494 | 108 | uint64_t Magic = decodeULEB128(Data); |
495 | 108 | return Magic == SPMagic(); |
496 | 108 | } |
497 | | |
498 | 24 | std::error_code SampleProfileReaderGCC::skipNextWord() { |
499 | 24 | uint32_t dummy; |
500 | 24 | if (!GcovBuffer.readInt(dummy)) |
501 | 0 | return sampleprof_error::truncated; |
502 | 24 | return sampleprof_error::success; |
503 | 24 | } |
504 | | |
505 | | template <typename T> ErrorOr<T> SampleProfileReaderGCC::readNumber() { |
506 | | if (sizeof(T) <= sizeof(uint32_t)) { |
507 | | uint32_t Val; |
508 | | if (GcovBuffer.readInt(Val) && Val <= std::numeric_limits<T>::max()) |
509 | | return static_cast<T>(Val); |
510 | | } else if (sizeof(T) <= sizeof(uint64_t)) { |
511 | | uint64_t Val; |
512 | | if (GcovBuffer.readInt64(Val) && Val <= std::numeric_limits<T>::max()) |
513 | | return static_cast<T>(Val); |
514 | | } |
515 | | |
516 | | std::error_code EC = sampleprof_error::malformed; |
517 | | reportError(0, EC.message()); |
518 | | return EC; |
519 | | } |
520 | | |
521 | 0 | ErrorOr<StringRef> SampleProfileReaderGCC::readString() { |
522 | 0 | StringRef Str; |
523 | 0 | if (!GcovBuffer.readString(Str)) |
524 | 0 | return sampleprof_error::truncated; |
525 | 0 | return Str; |
526 | 0 | } |
527 | | |
528 | 8 | std::error_code SampleProfileReaderGCC::readHeader() { |
529 | 8 | // Read the magic identifier. |
530 | 8 | if (!GcovBuffer.readGCDAFormat()) |
531 | 0 | return sampleprof_error::unrecognized_format; |
532 | 8 | |
533 | 8 | // Read the version number. Note - the GCC reader does not validate this |
534 | 8 | // version, but the profile creator generates v704. |
535 | 8 | GCOV::GCOVVersion version; |
536 | 8 | if (!GcovBuffer.readGCOVVersion(version)) |
537 | 0 | return sampleprof_error::unrecognized_format; |
538 | 8 | |
539 | 8 | if (8 version != GCOV::V7048 ) |
540 | 0 | return sampleprof_error::unsupported_version; |
541 | 8 | |
542 | 8 | // Skip the empty integer. |
543 | 8 | if (std::error_code 8 EC8 = skipNextWord()) |
544 | 0 | return EC; |
545 | 8 | |
546 | 8 | return sampleprof_error::success; |
547 | 8 | } |
548 | | |
549 | 16 | std::error_code SampleProfileReaderGCC::readSectionTag(uint32_t Expected) { |
550 | 16 | uint32_t Tag; |
551 | 16 | if (!GcovBuffer.readInt(Tag)) |
552 | 0 | return sampleprof_error::truncated; |
553 | 16 | |
554 | 16 | if (16 Tag != Expected16 ) |
555 | 0 | return sampleprof_error::malformed; |
556 | 16 | |
557 | 16 | if (std::error_code 16 EC16 = skipNextWord()) |
558 | 0 | return EC; |
559 | 16 | |
560 | 16 | return sampleprof_error::success; |
561 | 16 | } |
562 | | |
563 | 8 | std::error_code SampleProfileReaderGCC::readNameTable() { |
564 | 8 | if (std::error_code EC = readSectionTag(GCOVTagAFDOFileNames)) |
565 | 0 | return EC; |
566 | 8 | |
567 | 8 | uint32_t Size; |
568 | 8 | if (!GcovBuffer.readInt(Size)) |
569 | 0 | return sampleprof_error::truncated; |
570 | 8 | |
571 | 38 | for (uint32_t I = 0; 8 I < Size38 ; ++I30 ) { |
572 | 30 | StringRef Str; |
573 | 30 | if (!GcovBuffer.readString(Str)) |
574 | 0 | return sampleprof_error::truncated; |
575 | 30 | Names.push_back(Str); |
576 | 30 | } |
577 | 8 | |
578 | 8 | return sampleprof_error::success; |
579 | 8 | } |
580 | | |
581 | 8 | std::error_code SampleProfileReaderGCC::readFunctionProfiles() { |
582 | 8 | if (std::error_code EC = readSectionTag(GCOVTagAFDOFunction)) |
583 | 0 | return EC; |
584 | 8 | |
585 | 8 | uint32_t NumFunctions; |
586 | 8 | if (!GcovBuffer.readInt(NumFunctions)) |
587 | 0 | return sampleprof_error::truncated; |
588 | 8 | |
589 | 8 | InlineCallStack Stack; |
590 | 18 | for (uint32_t I = 0; I < NumFunctions18 ; ++I10 ) |
591 | 10 | if (std::error_code 10 EC10 = readOneFunctionProfile(Stack, true, 0)) |
592 | 0 | return EC; |
593 | 8 | |
594 | 8 | computeSummary(); |
595 | 8 | return sampleprof_error::success; |
596 | 8 | } |
597 | | |
598 | | std::error_code SampleProfileReaderGCC::readOneFunctionProfile( |
599 | 30 | const InlineCallStack &InlineStack, bool Update, uint32_t Offset) { |
600 | 30 | uint64_t HeadCount = 0; |
601 | 30 | if (InlineStack.size() == 0) |
602 | 10 | if (10 !GcovBuffer.readInt64(HeadCount)10 ) |
603 | 0 | return sampleprof_error::truncated; |
604 | 30 | |
605 | 30 | uint32_t NameIdx; |
606 | 30 | if (!GcovBuffer.readInt(NameIdx)) |
607 | 0 | return sampleprof_error::truncated; |
608 | 30 | |
609 | 30 | StringRef Name(Names[NameIdx]); |
610 | 30 | |
611 | 30 | uint32_t NumPosCounts; |
612 | 30 | if (!GcovBuffer.readInt(NumPosCounts)) |
613 | 0 | return sampleprof_error::truncated; |
614 | 30 | |
615 | 30 | uint32_t NumCallsites; |
616 | 30 | if (!GcovBuffer.readInt(NumCallsites)) |
617 | 0 | return sampleprof_error::truncated; |
618 | 30 | |
619 | 30 | FunctionSamples *FProfile = nullptr; |
620 | 30 | if (InlineStack.size() == 030 ) { |
621 | 10 | // If this is a top function that we have already processed, do not |
622 | 10 | // update its profile again. This happens in the presence of |
623 | 10 | // function aliases. Since these aliases share the same function |
624 | 10 | // body, there will be identical replicated profiles for the |
625 | 10 | // original function. In this case, we simply not bother updating |
626 | 10 | // the profile of the original function. |
627 | 10 | FProfile = &Profiles[Name]; |
628 | 10 | FProfile->addHeadSamples(HeadCount); |
629 | 10 | if (FProfile->getTotalSamples() > 0) |
630 | 0 | Update = false; |
631 | 30 | } else { |
632 | 20 | // Otherwise, we are reading an inlined instance. The top of the |
633 | 20 | // inline stack contains the profile of the caller. Insert this |
634 | 20 | // callee in the caller's CallsiteMap. |
635 | 20 | FunctionSamples *CallerProfile = InlineStack.front(); |
636 | 20 | uint32_t LineOffset = Offset >> 16; |
637 | 20 | uint32_t Discriminator = Offset & 0xffff; |
638 | 20 | FProfile = &CallerProfile->functionSamplesAt( |
639 | 20 | LineLocation(LineOffset, Discriminator))[Name]; |
640 | 20 | } |
641 | 30 | FProfile->setName(Name); |
642 | 30 | |
643 | 144 | for (uint32_t I = 0; I < NumPosCounts144 ; ++I114 ) { |
644 | 114 | uint32_t Offset; |
645 | 114 | if (!GcovBuffer.readInt(Offset)) |
646 | 0 | return sampleprof_error::truncated; |
647 | 114 | |
648 | 114 | uint32_t NumTargets; |
649 | 114 | if (!GcovBuffer.readInt(NumTargets)) |
650 | 0 | return sampleprof_error::truncated; |
651 | 114 | |
652 | 114 | uint64_t Count; |
653 | 114 | if (!GcovBuffer.readInt64(Count)) |
654 | 0 | return sampleprof_error::truncated; |
655 | 114 | |
656 | 114 | // The line location is encoded in the offset as: |
657 | 114 | // high 16 bits: line offset to the start of the function. |
658 | 114 | // low 16 bits: discriminator. |
659 | 114 | uint32_t LineOffset = Offset >> 16; |
660 | 114 | uint32_t Discriminator = Offset & 0xffff; |
661 | 114 | |
662 | 114 | InlineCallStack NewStack; |
663 | 114 | NewStack.push_back(FProfile); |
664 | 114 | NewStack.insert(NewStack.end(), InlineStack.begin(), InlineStack.end()); |
665 | 114 | if (Update114 ) { |
666 | 114 | // Walk up the inline stack, adding the samples on this line to |
667 | 114 | // the total sample count of the callers in the chain. |
668 | 114 | for (auto CallerProfile : NewStack) |
669 | 189 | CallerProfile->addTotalSamples(Count); |
670 | 114 | |
671 | 114 | // Update the body samples for the current profile. |
672 | 114 | FProfile->addBodySamples(LineOffset, Discriminator, Count); |
673 | 114 | } |
674 | 114 | |
675 | 114 | // Process the list of functions called at an indirect call site. |
676 | 114 | // These are all the targets that a function pointer (or virtual |
677 | 114 | // function) resolved at runtime. |
678 | 118 | for (uint32_t J = 0; J < NumTargets118 ; J++4 ) { |
679 | 4 | uint32_t HistVal; |
680 | 4 | if (!GcovBuffer.readInt(HistVal)) |
681 | 0 | return sampleprof_error::truncated; |
682 | 4 | |
683 | 4 | if (4 HistVal != HIST_TYPE_INDIR_CALL_TOPN4 ) |
684 | 0 | return sampleprof_error::malformed; |
685 | 4 | |
686 | 4 | uint64_t TargetIdx; |
687 | 4 | if (!GcovBuffer.readInt64(TargetIdx)) |
688 | 0 | return sampleprof_error::truncated; |
689 | 4 | StringRef TargetName(Names[TargetIdx]); |
690 | 4 | |
691 | 4 | uint64_t TargetCount; |
692 | 4 | if (!GcovBuffer.readInt64(TargetCount)) |
693 | 0 | return sampleprof_error::truncated; |
694 | 4 | |
695 | 4 | if (4 Update4 ) |
696 | 4 | FProfile->addCalledTargetSamples(LineOffset, Discriminator, |
697 | 4 | TargetName, TargetCount); |
698 | 4 | } |
699 | 114 | } |
700 | 30 | |
701 | 30 | // Process all the inlined callers into the current function. These |
702 | 30 | // are all the callsites that were inlined into this function. |
703 | 50 | for (uint32_t I = 0; 30 I < NumCallsites50 ; I++20 ) { |
704 | 20 | // The offset is encoded as: |
705 | 20 | // high 16 bits: line offset to the start of the function. |
706 | 20 | // low 16 bits: discriminator. |
707 | 20 | uint32_t Offset; |
708 | 20 | if (!GcovBuffer.readInt(Offset)) |
709 | 0 | return sampleprof_error::truncated; |
710 | 20 | InlineCallStack NewStack; |
711 | 20 | NewStack.push_back(FProfile); |
712 | 20 | NewStack.insert(NewStack.end(), InlineStack.begin(), InlineStack.end()); |
713 | 20 | if (std::error_code EC = readOneFunctionProfile(NewStack, Update, Offset)) |
714 | 0 | return EC; |
715 | 20 | } |
716 | 30 | |
717 | 30 | return sampleprof_error::success; |
718 | 30 | } |
719 | | |
720 | | /// \brief Read a GCC AutoFDO profile. |
721 | | /// |
722 | | /// This format is generated by the Linux Perf conversion tool at |
723 | | /// https://github.com/google/autofdo. |
724 | 8 | std::error_code SampleProfileReaderGCC::read() { |
725 | 8 | // Read the string table. |
726 | 8 | if (std::error_code EC = readNameTable()) |
727 | 0 | return EC; |
728 | 8 | |
729 | 8 | // Read the source profile. |
730 | 8 | if (std::error_code 8 EC8 = readFunctionProfiles()) |
731 | 0 | return EC; |
732 | 8 | |
733 | 8 | return sampleprof_error::success; |
734 | 8 | } |
735 | | |
736 | 96 | bool SampleProfileReaderGCC::hasFormat(const MemoryBuffer &Buffer) { |
737 | 96 | StringRef Magic(reinterpret_cast<const char *>(Buffer.getBufferStart())); |
738 | 96 | return Magic == "adcg*704"; |
739 | 96 | } |
740 | | |
741 | | /// \brief Prepare a memory buffer for the contents of \p Filename. |
742 | | /// |
743 | | /// \returns an error code indicating the status of the buffer. |
744 | | static ErrorOr<std::unique_ptr<MemoryBuffer>> |
745 | 108 | setupMemoryBuffer(const Twine &Filename) { |
746 | 108 | auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(Filename); |
747 | 108 | if (std::error_code EC = BufferOrErr.getError()) |
748 | 2 | return EC; |
749 | 106 | auto Buffer = std::move(BufferOrErr.get()); |
750 | 106 | |
751 | 106 | // Sanity check the file. |
752 | 106 | if (Buffer->getBufferSize() > std::numeric_limits<uint32_t>::max()) |
753 | 0 | return sampleprof_error::too_large; |
754 | 106 | |
755 | 106 | return std::move(Buffer); |
756 | 106 | } |
757 | | |
758 | | /// \brief Create a sample profile reader based on the format of the input file. |
759 | | /// |
760 | | /// \param Filename The file to open. |
761 | | /// |
762 | | /// \param Reader The reader to instantiate according to \p Filename's format. |
763 | | /// |
764 | | /// \param C The LLVM context to use to emit diagnostics. |
765 | | /// |
766 | | /// \returns an error code indicating the status of the created reader. |
767 | | ErrorOr<std::unique_ptr<SampleProfileReader>> |
768 | 108 | SampleProfileReader::create(const Twine &Filename, LLVMContext &C) { |
769 | 108 | auto BufferOrError = setupMemoryBuffer(Filename); |
770 | 108 | if (std::error_code EC = BufferOrError.getError()) |
771 | 2 | return EC; |
772 | 106 | return create(BufferOrError.get(), C); |
773 | 106 | } |
774 | | |
775 | | /// \brief Create a sample profile reader based on the format of the input data. |
776 | | /// |
777 | | /// \param B The memory buffer to create the reader from (assumes ownership). |
778 | | /// |
779 | | /// \param Reader The reader to instantiate according to \p Filename's format. |
780 | | /// |
781 | | /// \param C The LLVM context to use to emit diagnostics. |
782 | | /// |
783 | | /// \returns an error code indicating the status of the created reader. |
784 | | ErrorOr<std::unique_ptr<SampleProfileReader>> |
785 | 108 | SampleProfileReader::create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C) { |
786 | 108 | std::unique_ptr<SampleProfileReader> Reader; |
787 | 108 | if (SampleProfileReaderBinary::hasFormat(*B)) |
788 | 12 | Reader.reset(new SampleProfileReaderBinary(std::move(B), C)); |
789 | 96 | else if (96 SampleProfileReaderGCC::hasFormat(*B)96 ) |
790 | 8 | Reader.reset(new SampleProfileReaderGCC(std::move(B), C)); |
791 | 88 | else if (88 SampleProfileReaderText::hasFormat(*B)88 ) |
792 | 85 | Reader.reset(new SampleProfileReaderText(std::move(B), C)); |
793 | 88 | else |
794 | 3 | return sampleprof_error::unrecognized_format; |
795 | 105 | |
796 | 105 | if (std::error_code 105 EC105 = Reader->readHeader()) |
797 | 0 | return EC; |
798 | 105 | |
799 | 105 | return std::move(Reader); |
800 | 105 | } |
801 | | |
802 | | // For text and GCC file formats, we compute the summary after reading the |
803 | | // profile. Binary format has the profile summary in its header. |
804 | 85 | void SampleProfileReader::computeSummary() { |
805 | 85 | SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs); |
806 | 129 | for (const auto &I : Profiles) { |
807 | 129 | const FunctionSamples &Profile = I.second; |
808 | 129 | Builder.addRecord(Profile); |
809 | 129 | } |
810 | 85 | Summary = Builder.getSummary(); |
811 | 85 | } |