blob: c423466fe75be6d3379b3368bc3b19386117ec5c [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- SampleProf.h - Sampling profiling format support ---------*- C++ -*-===//
2//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
7//===----------------------------------------------------------------------===//
8//
9// This file contains common definitions used in the reading and writing of
10// sample profile data.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_PROFILEDATA_SAMPLEPROF_H
15#define LLVM_PROFILEDATA_SAMPLEPROF_H
16
17#include "llvm/ADT/DenseSet.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/ADT/StringMap.h"
20#include "llvm/ADT/StringRef.h"
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020021#include "llvm/ADT/StringSet.h"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010022#include "llvm/IR/Function.h"
23#include "llvm/IR/GlobalValue.h"
24#include "llvm/IR/Module.h"
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020025#include "llvm/Support/Allocator.h"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010026#include "llvm/Support/Debug.h"
27#include "llvm/Support/ErrorOr.h"
28#include "llvm/Support/MathExtras.h"
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020029#include "llvm/Support/raw_ostream.h"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010030#include <algorithm>
31#include <cstdint>
32#include <map>
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020033#include <set>
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010034#include <string>
35#include <system_error>
36#include <utility>
37
38namespace llvm {
39
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010040const std::error_category &sampleprof_category();
41
42enum class sampleprof_error {
43 success = 0,
44 bad_magic,
45 unsupported_version,
46 too_large,
47 truncated,
48 malformed,
49 unrecognized_format,
50 unsupported_writing_format,
51 truncated_name_table,
52 not_implemented,
Andrew Scull0372a572018-11-16 15:47:06 +000053 counter_overflow,
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020054 ostream_seek_unsupported,
55 compress_failed,
56 uncompress_failed,
57 zlib_unavailable,
58 hash_mismatch
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010059};
60
61inline std::error_code make_error_code(sampleprof_error E) {
62 return std::error_code(static_cast<int>(E), sampleprof_category());
63}
64
65inline sampleprof_error MergeResult(sampleprof_error &Accumulator,
66 sampleprof_error Result) {
67 // Prefer first error encountered as later errors may be secondary effects of
68 // the initial problem.
69 if (Accumulator == sampleprof_error::success &&
70 Result != sampleprof_error::success)
71 Accumulator = Result;
72 return Accumulator;
73}
74
75} // end namespace llvm
76
77namespace std {
78
79template <>
80struct is_error_code_enum<llvm::sampleprof_error> : std::true_type {};
81
82} // end namespace std
83
84namespace llvm {
85namespace sampleprof {
86
Andrew Scullcdfcccc2018-10-05 20:58:37 +010087enum SampleProfileFormat {
88 SPF_None = 0,
89 SPF_Text = 0x1,
90 SPF_Compact_Binary = 0x2,
91 SPF_GCC = 0x3,
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020092 SPF_Ext_Binary = 0x4,
Andrew Scullcdfcccc2018-10-05 20:58:37 +010093 SPF_Binary = 0xff
94};
95
96static inline uint64_t SPMagic(SampleProfileFormat Format = SPF_Binary) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010097 return uint64_t('S') << (64 - 8) | uint64_t('P') << (64 - 16) |
98 uint64_t('R') << (64 - 24) | uint64_t('O') << (64 - 32) |
99 uint64_t('F') << (64 - 40) | uint64_t('4') << (64 - 48) |
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100100 uint64_t('2') << (64 - 56) | uint64_t(Format);
101}
102
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200103/// Get the proper representation of a string according to whether the
104/// current Format uses MD5 to represent the string.
105static inline StringRef getRepInFormat(StringRef Name, bool UseMD5,
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100106 std::string &GUIDBuf) {
107 if (Name.empty())
108 return Name;
109 GUIDBuf = std::to_string(Function::getGUID(Name));
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200110 return UseMD5 ? StringRef(GUIDBuf) : Name;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100111}
112
113static inline uint64_t SPVersion() { return 103; }
114
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200115// Section Type used by SampleProfileExtBinaryBaseReader and
116// SampleProfileExtBinaryBaseWriter. Never change the existing
117// value of enum. Only append new ones.
118enum SecType {
119 SecInValid = 0,
120 SecProfSummary = 1,
121 SecNameTable = 2,
122 SecProfileSymbolList = 3,
123 SecFuncOffsetTable = 4,
124 SecFuncMetadata = 5,
125 // marker for the first type of profile.
126 SecFuncProfileFirst = 32,
127 SecLBRProfile = SecFuncProfileFirst
128};
129
130static inline std::string getSecName(SecType Type) {
131 switch (Type) {
132 case SecInValid:
133 return "InvalidSection";
134 case SecProfSummary:
135 return "ProfileSummarySection";
136 case SecNameTable:
137 return "NameTableSection";
138 case SecProfileSymbolList:
139 return "ProfileSymbolListSection";
140 case SecFuncOffsetTable:
141 return "FuncOffsetTableSection";
142 case SecFuncMetadata:
143 return "FunctionMetadata";
144 case SecLBRProfile:
145 return "LBRProfileSection";
146 }
147 llvm_unreachable("A SecType has no name for output");
148}
149
150// Entry type of section header table used by SampleProfileExtBinaryBaseReader
151// and SampleProfileExtBinaryBaseWriter.
152struct SecHdrTableEntry {
153 SecType Type;
154 uint64_t Flags;
155 uint64_t Offset;
156 uint64_t Size;
157 // The index indicating the location of the current entry in
158 // SectionHdrLayout table.
159 uint32_t LayoutIndex;
160};
161
162// Flags common for all sections are defined here. In SecHdrTableEntry::Flags,
163// common flags will be saved in the lower 32bits and section specific flags
164// will be saved in the higher 32 bits.
165enum class SecCommonFlags : uint32_t {
166 SecFlagInValid = 0,
167 SecFlagCompress = (1 << 0)
168};
169
170// Section specific flags are defined here.
171// !!!Note: Everytime a new enum class is created here, please add
172// a new check in verifySecFlag.
173enum class SecNameTableFlags : uint32_t {
174 SecFlagInValid = 0,
175 SecFlagMD5Name = (1 << 0),
176 // Store MD5 in fixed length instead of ULEB128 so NameTable can be
177 // accessed like an array.
178 SecFlagFixedLengthMD5 = (1 << 1)
179};
180enum class SecProfSummaryFlags : uint32_t {
181 SecFlagInValid = 0,
182 /// SecFlagPartial means the profile is for common/shared code.
183 /// The common profile is usually merged from profiles collected
184 /// from running other targets.
185 SecFlagPartial = (1 << 0)
186};
187
188enum class SecFuncMetadataFlags : uint32_t {
189 SecFlagInvalid = 0,
190 SecFlagIsProbeBased = (1 << 0),
191};
192
193// Verify section specific flag is used for the correct section.
194template <class SecFlagType>
195static inline void verifySecFlag(SecType Type, SecFlagType Flag) {
196 // No verification is needed for common flags.
197 if (std::is_same<SecCommonFlags, SecFlagType>())
198 return;
199
200 // Verification starts here for section specific flag.
201 bool IsFlagLegal = false;
202 switch (Type) {
203 case SecNameTable:
204 IsFlagLegal = std::is_same<SecNameTableFlags, SecFlagType>();
205 break;
206 case SecProfSummary:
207 IsFlagLegal = std::is_same<SecProfSummaryFlags, SecFlagType>();
208 break;
209 case SecFuncMetadata:
210 IsFlagLegal = std::is_same<SecFuncMetadataFlags, SecFlagType>();
211 break;
212 default:
213 break;
214 }
215 if (!IsFlagLegal)
216 llvm_unreachable("Misuse of a flag in an incompatible section");
217}
218
219template <class SecFlagType>
220static inline void addSecFlag(SecHdrTableEntry &Entry, SecFlagType Flag) {
221 verifySecFlag(Entry.Type, Flag);
222 auto FVal = static_cast<uint64_t>(Flag);
223 bool IsCommon = std::is_same<SecCommonFlags, SecFlagType>();
224 Entry.Flags |= IsCommon ? FVal : (FVal << 32);
225}
226
227template <class SecFlagType>
228static inline void removeSecFlag(SecHdrTableEntry &Entry, SecFlagType Flag) {
229 verifySecFlag(Entry.Type, Flag);
230 auto FVal = static_cast<uint64_t>(Flag);
231 bool IsCommon = std::is_same<SecCommonFlags, SecFlagType>();
232 Entry.Flags &= ~(IsCommon ? FVal : (FVal << 32));
233}
234
235template <class SecFlagType>
236static inline bool hasSecFlag(const SecHdrTableEntry &Entry, SecFlagType Flag) {
237 verifySecFlag(Entry.Type, Flag);
238 auto FVal = static_cast<uint64_t>(Flag);
239 bool IsCommon = std::is_same<SecCommonFlags, SecFlagType>();
240 return Entry.Flags & (IsCommon ? FVal : (FVal << 32));
241}
242
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100243/// Represents the relative location of an instruction.
244///
245/// Instruction locations are specified by the line offset from the
246/// beginning of the function (marked by the line where the function
247/// header is) and the discriminator value within that line.
248///
249/// The discriminator value is useful to distinguish instructions
250/// that are on the same line but belong to different basic blocks
251/// (e.g., the two post-increment instructions in "if (p) x++; else y++;").
252struct LineLocation {
253 LineLocation(uint32_t L, uint32_t D) : LineOffset(L), Discriminator(D) {}
254
255 void print(raw_ostream &OS) const;
256 void dump() const;
257
258 bool operator<(const LineLocation &O) const {
259 return LineOffset < O.LineOffset ||
260 (LineOffset == O.LineOffset && Discriminator < O.Discriminator);
261 }
262
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200263 bool operator==(const LineLocation &O) const {
264 return LineOffset == O.LineOffset && Discriminator == O.Discriminator;
265 }
266
267 bool operator!=(const LineLocation &O) const {
268 return LineOffset != O.LineOffset || Discriminator != O.Discriminator;
269 }
270
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100271 uint32_t LineOffset;
272 uint32_t Discriminator;
273};
274
275raw_ostream &operator<<(raw_ostream &OS, const LineLocation &Loc);
276
277/// Representation of a single sample record.
278///
279/// A sample record is represented by a positive integer value, which
280/// indicates how frequently was the associated line location executed.
281///
282/// Additionally, if the associated location contains a function call,
283/// the record will hold a list of all the possible called targets. For
284/// direct calls, this will be the exact function being invoked. For
285/// indirect calls (function pointers, virtual table dispatch), this
286/// will be a list of one or more functions.
287class SampleRecord {
288public:
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200289 using CallTarget = std::pair<StringRef, uint64_t>;
290 struct CallTargetComparator {
291 bool operator()(const CallTarget &LHS, const CallTarget &RHS) const {
292 if (LHS.second != RHS.second)
293 return LHS.second > RHS.second;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100294
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200295 return LHS.first < RHS.first;
296 }
297 };
298
299 using SortedCallTargetSet = std::set<CallTarget, CallTargetComparator>;
300 using CallTargetMap = StringMap<uint64_t>;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100301 SampleRecord() = default;
302
303 /// Increment the number of samples for this record by \p S.
304 /// Optionally scale sample count \p S by \p Weight.
305 ///
306 /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
307 /// around unsigned integers.
308 sampleprof_error addSamples(uint64_t S, uint64_t Weight = 1) {
309 bool Overflowed;
310 NumSamples = SaturatingMultiplyAdd(S, Weight, NumSamples, &Overflowed);
311 return Overflowed ? sampleprof_error::counter_overflow
312 : sampleprof_error::success;
313 }
314
315 /// Add called function \p F with samples \p S.
316 /// Optionally scale sample count \p S by \p Weight.
317 ///
318 /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
319 /// around unsigned integers.
320 sampleprof_error addCalledTarget(StringRef F, uint64_t S,
321 uint64_t Weight = 1) {
322 uint64_t &TargetSamples = CallTargets[F];
323 bool Overflowed;
324 TargetSamples =
325 SaturatingMultiplyAdd(S, Weight, TargetSamples, &Overflowed);
326 return Overflowed ? sampleprof_error::counter_overflow
327 : sampleprof_error::success;
328 }
329
330 /// Return true if this sample record contains function calls.
331 bool hasCalls() const { return !CallTargets.empty(); }
332
333 uint64_t getSamples() const { return NumSamples; }
334 const CallTargetMap &getCallTargets() const { return CallTargets; }
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200335 const SortedCallTargetSet getSortedCallTargets() const {
336 return SortCallTargets(CallTargets);
337 }
338
339 /// Sort call targets in descending order of call frequency.
340 static const SortedCallTargetSet SortCallTargets(const CallTargetMap &Targets) {
341 SortedCallTargetSet SortedTargets;
342 for (const auto &I : Targets) {
343 SortedTargets.emplace(I.first(), I.second);
344 }
345 return SortedTargets;
346 }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100347
348 /// Merge the samples in \p Other into this record.
349 /// Optionally scale sample counts by \p Weight.
350 sampleprof_error merge(const SampleRecord &Other, uint64_t Weight = 1) {
351 sampleprof_error Result = addSamples(Other.getSamples(), Weight);
352 for (const auto &I : Other.getCallTargets()) {
353 MergeResult(Result, addCalledTarget(I.first(), I.second, Weight));
354 }
355 return Result;
356 }
357
358 void print(raw_ostream &OS, unsigned Indent) const;
359 void dump() const;
360
361private:
362 uint64_t NumSamples = 0;
363 CallTargetMap CallTargets;
364};
365
366raw_ostream &operator<<(raw_ostream &OS, const SampleRecord &Sample);
367
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200368// State of context associated with FunctionSamples
369enum ContextStateMask {
370 UnknownContext = 0x0, // Profile without context
371 RawContext = 0x1, // Full context profile from input profile
372 SyntheticContext = 0x2, // Synthetic context created for context promotion
373 InlinedContext = 0x4, // Profile for context that is inlined into caller
374 MergedContext = 0x8 // Profile for context merged into base profile
375};
376
377// Sample context for FunctionSamples. It consists of the calling context,
378// the function name and context state. Internally sample context is represented
379// using StringRef, which is also the input for constructing a `SampleContext`.
380// It can accept and represent both full context string as well as context-less
381// function name.
382// Example of full context string (note the wrapping `[]`):
383// `[main:3 @ _Z5funcAi:1 @ _Z8funcLeafi]`
384// Example of context-less function name (same as AutoFDO):
385// `_Z8funcLeafi`
386class SampleContext {
387public:
388 SampleContext() : State(UnknownContext) {}
389 SampleContext(StringRef ContextStr,
390 ContextStateMask CState = UnknownContext) {
391 setContext(ContextStr, CState);
392 }
393
394 // Promote context by removing top frames (represented by `ContextStrToRemove`).
395 // Note that with string representation of context, the promotion is effectively
396 // a substr operation with `ContextStrToRemove` removed from left.
397 void promoteOnPath(StringRef ContextStrToRemove) {
398 assert(FullContext.startswith(ContextStrToRemove));
399
400 // Remove leading context and frame separator " @ ".
401 FullContext = FullContext.substr(ContextStrToRemove.size() + 3);
402 CallingContext = CallingContext.substr(ContextStrToRemove.size() + 3);
403 }
404
405 // Split the top context frame (left-most substr) from context.
406 static std::pair<StringRef, StringRef>
407 splitContextString(StringRef ContextStr) {
408 return ContextStr.split(" @ ");
409 }
410
411 // Decode context string for a frame to get function name and location.
412 // `ContextStr` is in the form of `FuncName:StartLine.Discriminator`.
413 static void decodeContextString(StringRef ContextStr, StringRef &FName,
414 LineLocation &LineLoc) {
415 // Get function name
416 auto EntrySplit = ContextStr.split(':');
417 FName = EntrySplit.first;
418
419 LineLoc = {0, 0};
420 if (!EntrySplit.second.empty()) {
421 // Get line offset, use signed int for getAsInteger so string will
422 // be parsed as signed.
423 int LineOffset = 0;
424 auto LocSplit = EntrySplit.second.split('.');
425 LocSplit.first.getAsInteger(10, LineOffset);
426 LineLoc.LineOffset = LineOffset;
427
428 // Get discriminator
429 if (!LocSplit.second.empty())
430 LocSplit.second.getAsInteger(10, LineLoc.Discriminator);
431 }
432 }
433
434 operator StringRef() const { return FullContext; }
435 bool hasState(ContextStateMask S) { return State & (uint32_t)S; }
436 void setState(ContextStateMask S) { State |= (uint32_t)S; }
437 void clearState(ContextStateMask S) { State &= (uint32_t)~S; }
438 bool hasContext() const { return State != UnknownContext; }
439 bool isBaseContext() const { return CallingContext.empty(); }
440 StringRef getName() const { return Name; }
441 StringRef getCallingContext() const { return CallingContext; }
442 StringRef getNameWithContext() const { return FullContext; }
443
444private:
445 // Give a context string, decode and populate internal states like
446 // Function name, Calling context and context state. Example of input
447 // `ContextStr`: `[main:3 @ _Z5funcAi:1 @ _Z8funcLeafi]`
448 void setContext(StringRef ContextStr, ContextStateMask CState) {
449 assert(!ContextStr.empty());
450 // Note that `[]` wrapped input indicates a full context string, otherwise
451 // it's treated as context-less function name only.
452 bool HasContext = ContextStr.startswith("[");
453 if (!HasContext && CState == UnknownContext) {
454 State = UnknownContext;
455 Name = FullContext = ContextStr;
456 } else {
457 // Assume raw context profile if unspecified
458 if (CState == UnknownContext)
459 State = RawContext;
460 else
461 State = CState;
462
463 // Remove encapsulating '[' and ']' if any
464 if (HasContext)
465 FullContext = ContextStr.substr(1, ContextStr.size() - 2);
466 else
467 FullContext = ContextStr;
468
469 // Caller is to the left of callee in context string
470 auto NameContext = FullContext.rsplit(" @ ");
471 if (NameContext.second.empty()) {
472 Name = NameContext.first;
473 CallingContext = NameContext.second;
474 } else {
475 Name = NameContext.second;
476 CallingContext = NameContext.first;
477 }
478 }
479 }
480
481 // Full context string including calling context and leaf function name
482 StringRef FullContext;
483 // Function name for the associated sample profile
484 StringRef Name;
485 // Calling context (leaf function excluded) for the associated sample profile
486 StringRef CallingContext;
487 // State of the associated sample profile
488 uint32_t State;
489};
490
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100491class FunctionSamples;
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200492class SampleProfileReaderItaniumRemapper;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100493
494using BodySampleMap = std::map<LineLocation, SampleRecord>;
495// NOTE: Using a StringMap here makes parsed profiles consume around 17% more
496// memory, which is *very* significant for large profiles.
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200497using FunctionSamplesMap = std::map<std::string, FunctionSamples, std::less<>>;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100498using CallsiteSampleMap = std::map<LineLocation, FunctionSamplesMap>;
499
500/// Representation of the samples collected for a function.
501///
502/// This data structure contains all the collected samples for the body
503/// of a function. Each sample corresponds to a LineLocation instance
504/// within the body of the function.
505class FunctionSamples {
506public:
507 FunctionSamples() = default;
508
509 void print(raw_ostream &OS = dbgs(), unsigned Indent = 0) const;
510 void dump() const;
511
512 sampleprof_error addTotalSamples(uint64_t Num, uint64_t Weight = 1) {
513 bool Overflowed;
514 TotalSamples =
515 SaturatingMultiplyAdd(Num, Weight, TotalSamples, &Overflowed);
516 return Overflowed ? sampleprof_error::counter_overflow
517 : sampleprof_error::success;
518 }
519
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200520 void setTotalSamples(uint64_t Num) { TotalSamples = Num; }
521
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100522 sampleprof_error addHeadSamples(uint64_t Num, uint64_t Weight = 1) {
523 bool Overflowed;
524 TotalHeadSamples =
525 SaturatingMultiplyAdd(Num, Weight, TotalHeadSamples, &Overflowed);
526 return Overflowed ? sampleprof_error::counter_overflow
527 : sampleprof_error::success;
528 }
529
530 sampleprof_error addBodySamples(uint32_t LineOffset, uint32_t Discriminator,
531 uint64_t Num, uint64_t Weight = 1) {
532 return BodySamples[LineLocation(LineOffset, Discriminator)].addSamples(
533 Num, Weight);
534 }
535
536 sampleprof_error addCalledTargetSamples(uint32_t LineOffset,
537 uint32_t Discriminator,
538 StringRef FName, uint64_t Num,
539 uint64_t Weight = 1) {
540 return BodySamples[LineLocation(LineOffset, Discriminator)].addCalledTarget(
541 FName, Num, Weight);
542 }
543
544 /// Return the number of samples collected at the given location.
545 /// Each location is specified by \p LineOffset and \p Discriminator.
546 /// If the location is not found in profile, return error.
547 ErrorOr<uint64_t> findSamplesAt(uint32_t LineOffset,
548 uint32_t Discriminator) const {
549 const auto &ret = BodySamples.find(LineLocation(LineOffset, Discriminator));
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200550 if (ret == BodySamples.end()) {
551 // For CSSPGO, in order to conserve profile size, we no longer write out
552 // locations profile for those not hit during training, so we need to
553 // treat them as zero instead of error here.
554 if (ProfileIsCS)
555 return 0;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100556 return std::error_code();
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200557 // A missing counter for a probe likely means the probe was not executed.
558 // Treat it as a zero count instead of an unknown count to help edge
559 // weight inference.
560 if (FunctionSamples::ProfileIsProbeBased)
561 return 0;
562 return std::error_code();
563 } else {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100564 return ret->second.getSamples();
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200565 }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100566 }
567
568 /// Returns the call target map collected at a given location.
569 /// Each location is specified by \p LineOffset and \p Discriminator.
570 /// If the location is not found in profile, return error.
571 ErrorOr<SampleRecord::CallTargetMap>
572 findCallTargetMapAt(uint32_t LineOffset, uint32_t Discriminator) const {
573 const auto &ret = BodySamples.find(LineLocation(LineOffset, Discriminator));
574 if (ret == BodySamples.end())
575 return std::error_code();
576 return ret->second.getCallTargets();
577 }
578
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200579 /// Returns the call target map collected at a given location specified by \p
580 /// CallSite. If the location is not found in profile, return error.
581 ErrorOr<SampleRecord::CallTargetMap>
582 findCallTargetMapAt(const LineLocation &CallSite) const {
583 const auto &Ret = BodySamples.find(CallSite);
584 if (Ret == BodySamples.end())
585 return std::error_code();
586 return Ret->second.getCallTargets();
587 }
588
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100589 /// Return the function samples at the given callsite location.
590 FunctionSamplesMap &functionSamplesAt(const LineLocation &Loc) {
591 return CallsiteSamples[Loc];
592 }
593
594 /// Returns the FunctionSamplesMap at the given \p Loc.
595 const FunctionSamplesMap *
596 findFunctionSamplesMapAt(const LineLocation &Loc) const {
597 auto iter = CallsiteSamples.find(Loc);
598 if (iter == CallsiteSamples.end())
599 return nullptr;
600 return &iter->second;
601 }
602
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200603 /// Returns a pointer to FunctionSamples at the given callsite location
604 /// \p Loc with callee \p CalleeName. If no callsite can be found, relax
605 /// the restriction to return the FunctionSamples at callsite location
606 /// \p Loc with the maximum total sample count. If \p Remapper is not
607 /// nullptr, use \p Remapper to find FunctionSamples with equivalent name
608 /// as \p CalleeName.
609 const FunctionSamples *
610 findFunctionSamplesAt(const LineLocation &Loc, StringRef CalleeName,
611 SampleProfileReaderItaniumRemapper *Remapper) const;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100612
613 bool empty() const { return TotalSamples == 0; }
614
615 /// Return the total number of samples collected inside the function.
616 uint64_t getTotalSamples() const { return TotalSamples; }
617
618 /// Return the total number of branch samples that have the function as the
619 /// branch target. This should be equivalent to the sample of the first
620 /// instruction of the symbol. But as we directly get this info for raw
621 /// profile without referring to potentially inaccurate debug info, this
622 /// gives more accurate profile data and is preferred for standalone symbols.
623 uint64_t getHeadSamples() const { return TotalHeadSamples; }
624
625 /// Return the sample count of the first instruction of the function.
626 /// The function can be either a standalone symbol or an inlined function.
627 uint64_t getEntrySamples() const {
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200628 if (FunctionSamples::ProfileIsCS && getHeadSamples()) {
629 // For CS profile, if we already have more accurate head samples
630 // counted by branch sample from caller, use them as entry samples.
631 return getHeadSamples();
632 }
633 uint64_t Count = 0;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100634 // Use either BodySamples or CallsiteSamples which ever has the smaller
635 // lineno.
636 if (!BodySamples.empty() &&
637 (CallsiteSamples.empty() ||
638 BodySamples.begin()->first < CallsiteSamples.begin()->first))
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200639 Count = BodySamples.begin()->second.getSamples();
640 else if (!CallsiteSamples.empty()) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100641 // An indirect callsite may be promoted to several inlined direct calls.
642 // We need to get the sum of them.
643 for (const auto &N_FS : CallsiteSamples.begin()->second)
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200644 Count += N_FS.second.getEntrySamples();
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100645 }
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200646 // Return at least 1 if total sample is not 0.
647 return Count ? Count : TotalSamples > 0;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100648 }
649
650 /// Return all the samples collected in the body of the function.
651 const BodySampleMap &getBodySamples() const { return BodySamples; }
652
653 /// Return all the callsite samples collected in the body of the function.
654 const CallsiteSampleMap &getCallsiteSamples() const {
655 return CallsiteSamples;
656 }
657
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200658 /// Return the maximum of sample counts in a function body including functions
659 /// inlined in it.
660 uint64_t getMaxCountInside() const {
661 uint64_t MaxCount = 0;
662 for (const auto &L : getBodySamples())
663 MaxCount = std::max(MaxCount, L.second.getSamples());
664 for (const auto &C : getCallsiteSamples())
665 for (const FunctionSamplesMap::value_type &F : C.second)
666 MaxCount = std::max(MaxCount, F.second.getMaxCountInside());
667 return MaxCount;
668 }
669
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100670 /// Merge the samples in \p Other into this one.
671 /// Optionally scale samples by \p Weight.
672 sampleprof_error merge(const FunctionSamples &Other, uint64_t Weight = 1) {
673 sampleprof_error Result = sampleprof_error::success;
674 Name = Other.getName();
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200675 if (!GUIDToFuncNameMap)
676 GUIDToFuncNameMap = Other.GUIDToFuncNameMap;
677
678 if (FunctionHash == 0) {
679 // Set the function hash code for the target profile.
680 FunctionHash = Other.getFunctionHash();
681 } else if (FunctionHash != Other.getFunctionHash()) {
682 // The two profiles coming with different valid hash codes indicates
683 // either:
684 // 1. They are same-named static functions from different compilation
685 // units (without using -unique-internal-linkage-names), or
686 // 2. They are really the same function but from different compilations.
687 // Let's bail out in either case for now, which means one profile is
688 // dropped.
689 return sampleprof_error::hash_mismatch;
690 }
691
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100692 MergeResult(Result, addTotalSamples(Other.getTotalSamples(), Weight));
693 MergeResult(Result, addHeadSamples(Other.getHeadSamples(), Weight));
694 for (const auto &I : Other.getBodySamples()) {
695 const LineLocation &Loc = I.first;
696 const SampleRecord &Rec = I.second;
697 MergeResult(Result, BodySamples[Loc].merge(Rec, Weight));
698 }
699 for (const auto &I : Other.getCallsiteSamples()) {
700 const LineLocation &Loc = I.first;
701 FunctionSamplesMap &FSMap = functionSamplesAt(Loc);
702 for (const auto &Rec : I.second)
703 MergeResult(Result, FSMap[Rec.first].merge(Rec.second, Weight));
704 }
705 return Result;
706 }
707
708 /// Recursively traverses all children, if the total sample count of the
709 /// corresponding function is no less than \p Threshold, add its corresponding
710 /// GUID to \p S. Also traverse the BodySamples to add hot CallTarget's GUID
711 /// to \p S.
712 void findInlinedFunctions(DenseSet<GlobalValue::GUID> &S, const Module *M,
Andrew Scull0372a572018-11-16 15:47:06 +0000713 uint64_t Threshold) const {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100714 if (TotalSamples <= Threshold)
715 return;
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200716 auto isDeclaration = [](const Function *F) {
717 return !F || F->isDeclaration();
718 };
719 if (isDeclaration(M->getFunction(getFuncName()))) {
720 // Add to the import list only when it's defined out of module.
721 S.insert(getGUID(Name));
722 }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100723 // Import hot CallTargets, which may not be available in IR because full
724 // profile annotation cannot be done until backend compilation in ThinLTO.
725 for (const auto &BS : BodySamples)
726 for (const auto &TS : BS.second.getCallTargets())
727 if (TS.getValue() > Threshold) {
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200728 const Function *Callee = M->getFunction(getFuncName(TS.getKey()));
729 if (isDeclaration(Callee))
Andrew Scull0372a572018-11-16 15:47:06 +0000730 S.insert(getGUID(TS.getKey()));
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100731 }
732 for (const auto &CS : CallsiteSamples)
733 for (const auto &NameFS : CS.second)
Andrew Scull0372a572018-11-16 15:47:06 +0000734 NameFS.second.findInlinedFunctions(S, M, Threshold);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100735 }
736
737 /// Set the name of the function.
738 void setName(StringRef FunctionName) { Name = FunctionName; }
739
740 /// Return the function name.
Andrew Scull0372a572018-11-16 15:47:06 +0000741 StringRef getName() const { return Name; }
742
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200743 /// Return function name with context.
744 StringRef getNameWithContext() const {
745 return FunctionSamples::ProfileIsCS ? Context.getNameWithContext() : Name;
Andrew Scull0372a572018-11-16 15:47:06 +0000746 }
747
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200748 /// Return the original function name.
749 StringRef getFuncName() const { return getFuncName(Name); }
750
751 void setFunctionHash(uint64_t Hash) { FunctionHash = Hash; }
752
753 uint64_t getFunctionHash() const { return FunctionHash; }
754
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100755 /// Return the canonical name for a function, taking into account
756 /// suffix elision policy attributes.
757 static StringRef getCanonicalFnName(const Function &F) {
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100758 auto AttrName = "sample-profile-suffix-elision-policy";
759 auto Attr = F.getFnAttribute(AttrName).getValueAsString();
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200760 return getCanonicalFnName(F.getName(), Attr);
761 }
762
763 static StringRef getCanonicalFnName(StringRef FnName, StringRef Attr = "") {
764 static const char *knownSuffixes[] = { ".llvm.", ".part." };
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100765 if (Attr == "" || Attr == "all") {
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200766 return FnName.split('.').first;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100767 } else if (Attr == "selected") {
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200768 StringRef Cand(FnName);
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100769 for (const auto &Suf : knownSuffixes) {
770 StringRef Suffix(Suf);
771 auto It = Cand.rfind(Suffix);
772 if (It == StringRef::npos)
773 return Cand;
774 auto Dit = Cand.rfind('.');
775 if (Dit == It + Suffix.size() - 1)
776 Cand = Cand.substr(0, It);
777 }
778 return Cand;
779 } else if (Attr == "none") {
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200780 return FnName;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100781 } else {
782 assert(false && "internal error: unknown suffix elision policy");
783 }
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200784 return FnName;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100785 }
786
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200787 /// Translate \p Name into its original name.
788 /// When profile doesn't use MD5, \p Name needs no translation.
789 /// When profile uses MD5, \p Name in current FunctionSamples
790 /// is actually GUID of the original function name. getFuncName will
791 /// translate \p Name in current FunctionSamples into its original name
792 /// by looking up in the function map GUIDToFuncNameMap.
793 /// If the original name doesn't exist in the map, return empty StringRef.
794 StringRef getFuncName(StringRef Name) const {
795 if (!UseMD5)
Andrew Scull0372a572018-11-16 15:47:06 +0000796 return Name;
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200797
798 assert(GUIDToFuncNameMap && "GUIDToFuncNameMap needs to be popluated first");
799 return GUIDToFuncNameMap->lookup(std::stoull(Name.data()));
Andrew Scull0372a572018-11-16 15:47:06 +0000800 }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100801
802 /// Returns the line offset to the start line of the subprogram.
803 /// We assume that a single function will not exceed 65535 LOC.
804 static unsigned getOffset(const DILocation *DIL);
805
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200806 /// Returns a unique call site identifier for a given debug location of a call
807 /// instruction. This is wrapper of two scenarios, the probe-based profile and
808 /// regular profile, to hide implementation details from the sample loader and
809 /// the context tracker.
810 static LineLocation getCallSiteIdentifier(const DILocation *DIL);
811
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100812 /// Get the FunctionSamples of the inline instance where DIL originates
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100813 /// from.
814 ///
815 /// The FunctionSamples of the instruction (Machine or IR) associated to
816 /// \p DIL is the inlined instance in which that instruction is coming from.
817 /// We traverse the inline stack of that instruction, and match it with the
818 /// tree nodes in the profile.
819 ///
820 /// \returns the FunctionSamples pointer to the inlined instance.
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200821 /// If \p Remapper is not nullptr, it will be used to find matching
822 /// FunctionSamples with not exactly the same but equivalent name.
823 const FunctionSamples *findFunctionSamples(
824 const DILocation *DIL,
825 SampleProfileReaderItaniumRemapper *Remapper = nullptr) const;
826
827 static bool ProfileIsProbeBased;
828
829 static bool ProfileIsCS;
830
831 SampleContext &getContext() const { return Context; }
832
833 void setContext(const SampleContext &FContext) { Context = FContext; }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100834
Andrew Scull0372a572018-11-16 15:47:06 +0000835 static SampleProfileFormat Format;
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200836
837 /// Whether the profile uses MD5 to represent string.
838 static bool UseMD5;
839
Andrew Scull0372a572018-11-16 15:47:06 +0000840 /// GUIDToFuncNameMap saves the mapping from GUID to the symbol name, for
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200841 /// all the function symbols defined or declared in current module.
842 DenseMap<uint64_t, StringRef> *GUIDToFuncNameMap = nullptr;
Andrew Scull0372a572018-11-16 15:47:06 +0000843
844 // Assume the input \p Name is a name coming from FunctionSamples itself.
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200845 // If UseMD5 is true, the name is already a GUID and we
Andrew Scull0372a572018-11-16 15:47:06 +0000846 // don't want to return the GUID of GUID.
847 static uint64_t getGUID(StringRef Name) {
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200848 return UseMD5 ? std::stoull(Name.data()) : Function::getGUID(Name);
Andrew Scull0372a572018-11-16 15:47:06 +0000849 }
850
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200851 // Find all the names in the current FunctionSamples including names in
852 // all the inline instances and names of call targets.
853 void findAllNames(DenseSet<StringRef> &NameSet) const;
854
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100855private:
856 /// Mangled name of the function.
857 StringRef Name;
858
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200859 /// CFG hash value for the function.
860 uint64_t FunctionHash = 0;
861
862 /// Calling context for function profile
863 mutable SampleContext Context;
864
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100865 /// Total number of samples collected inside this function.
866 ///
867 /// Samples are cumulative, they include all the samples collected
868 /// inside this function and all its inlined callees.
869 uint64_t TotalSamples = 0;
870
871 /// Total number of samples collected at the head of the function.
872 /// This is an approximation of the number of calls made to this function
873 /// at runtime.
874 uint64_t TotalHeadSamples = 0;
875
876 /// Map instruction locations to collected samples.
877 ///
878 /// Each entry in this map contains the number of samples
879 /// collected at the corresponding line offset. All line locations
880 /// are an offset from the start of the function.
881 BodySampleMap BodySamples;
882
883 /// Map call sites to collected samples for the called function.
884 ///
885 /// Each entry in this map corresponds to all the samples
886 /// collected for the inlined function call at the given
887 /// location. For example, given:
888 ///
889 /// void foo() {
890 /// 1 bar();
891 /// ...
892 /// 8 baz();
893 /// }
894 ///
895 /// If the bar() and baz() calls were inlined inside foo(), this
896 /// map will contain two entries. One for all the samples collected
897 /// in the call to bar() at line offset 1, the other for all the samples
898 /// collected in the call to baz() at line offset 8.
899 CallsiteSampleMap CallsiteSamples;
900};
901
902raw_ostream &operator<<(raw_ostream &OS, const FunctionSamples &FS);
903
904/// Sort a LocationT->SampleT map by LocationT.
905///
906/// It produces a sorted list of <LocationT, SampleT> records by ascending
907/// order of LocationT.
908template <class LocationT, class SampleT> class SampleSorter {
909public:
910 using SamplesWithLoc = std::pair<const LocationT, SampleT>;
911 using SamplesWithLocList = SmallVector<const SamplesWithLoc *, 20>;
912
913 SampleSorter(const std::map<LocationT, SampleT> &Samples) {
914 for (const auto &I : Samples)
915 V.push_back(&I);
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100916 llvm::stable_sort(V, [](const SamplesWithLoc *A, const SamplesWithLoc *B) {
917 return A->first < B->first;
918 });
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100919 }
920
921 const SamplesWithLocList &get() const { return V; }
922
923private:
924 SamplesWithLocList V;
925};
926
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200927/// ProfileSymbolList records the list of function symbols shown up
928/// in the binary used to generate the profile. It is useful to
929/// to discriminate a function being so cold as not to shown up
930/// in the profile and a function newly added.
931class ProfileSymbolList {
932public:
933 /// copy indicates whether we need to copy the underlying memory
934 /// for the input Name.
935 void add(StringRef Name, bool copy = false) {
936 if (!copy) {
937 Syms.insert(Name);
938 return;
939 }
940 Syms.insert(Name.copy(Allocator));
941 }
942
943 bool contains(StringRef Name) { return Syms.count(Name); }
944
945 void merge(const ProfileSymbolList &List) {
946 for (auto Sym : List.Syms)
947 add(Sym, true);
948 }
949
950 unsigned size() { return Syms.size(); }
951
952 void setToCompress(bool TC) { ToCompress = TC; }
953 bool toCompress() { return ToCompress; }
954
955 std::error_code read(const uint8_t *Data, uint64_t ListSize);
956 std::error_code write(raw_ostream &OS);
957 void dump(raw_ostream &OS = dbgs()) const;
958
959private:
960 // Determine whether or not to compress the symbol list when
961 // writing it into profile. The variable is unused when the symbol
962 // list is read from an existing profile.
963 bool ToCompress = false;
964 DenseSet<StringRef> Syms;
965 BumpPtrAllocator Allocator;
966};
967
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100968} // end namespace sampleprof
969} // end namespace llvm
970
971#endif // LLVM_PROFILEDATA_SAMPLEPROF_H