File indexing completed on 2026-05-10 08:44:24
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef LLVM_PROFILEDATA_SAMPLEPROF_H
0015 #define LLVM_PROFILEDATA_SAMPLEPROF_H
0016
0017 #include "llvm/ADT/DenseSet.h"
0018 #include "llvm/ADT/SmallVector.h"
0019 #include "llvm/ADT/StringExtras.h"
0020 #include "llvm/ADT/StringRef.h"
0021 #include "llvm/IR/Function.h"
0022 #include "llvm/IR/GlobalValue.h"
0023 #include "llvm/ProfileData/FunctionId.h"
0024 #include "llvm/Support/Allocator.h"
0025 #include "llvm/Support/Debug.h"
0026 #include "llvm/Support/ErrorOr.h"
0027 #include "llvm/Support/MathExtras.h"
0028 #include "llvm/ProfileData/HashKeyMap.h"
0029 #include <algorithm>
0030 #include <cstdint>
0031 #include <list>
0032 #include <map>
0033 #include <set>
0034 #include <sstream>
0035 #include <string>
0036 #include <system_error>
0037 #include <unordered_map>
0038 #include <utility>
0039
0040 namespace llvm {
0041
0042 class DILocation;
0043 class raw_ostream;
0044
0045 const std::error_category &sampleprof_category();
0046
0047 enum class sampleprof_error {
0048 success = 0,
0049 bad_magic,
0050 unsupported_version,
0051 too_large,
0052 truncated,
0053 malformed,
0054 unrecognized_format,
0055 unsupported_writing_format,
0056 truncated_name_table,
0057 not_implemented,
0058 counter_overflow,
0059 ostream_seek_unsupported,
0060 uncompress_failed,
0061 zlib_unavailable,
0062 hash_mismatch
0063 };
0064
0065 inline std::error_code make_error_code(sampleprof_error E) {
0066 return std::error_code(static_cast<int>(E), sampleprof_category());
0067 }
0068
0069 inline sampleprof_error mergeSampleProfErrors(sampleprof_error &Accumulator,
0070 sampleprof_error Result) {
0071
0072
0073 if (Accumulator == sampleprof_error::success &&
0074 Result != sampleprof_error::success)
0075 Accumulator = Result;
0076 return Accumulator;
0077 }
0078
0079 }
0080
0081 namespace std {
0082
0083 template <>
0084 struct is_error_code_enum<llvm::sampleprof_error> : std::true_type {};
0085
0086 }
0087
0088 namespace llvm {
0089 namespace sampleprof {
0090
0091 enum SampleProfileFormat {
0092 SPF_None = 0,
0093 SPF_Text = 0x1,
0094 SPF_Compact_Binary = 0x2,
0095 SPF_GCC = 0x3,
0096 SPF_Ext_Binary = 0x4,
0097 SPF_Binary = 0xff
0098 };
0099
0100 enum SampleProfileLayout {
0101 SPL_None = 0,
0102 SPL_Nest = 0x1,
0103 SPL_Flat = 0x2,
0104 };
0105
0106 static inline uint64_t SPMagic(SampleProfileFormat Format = SPF_Binary) {
0107 return uint64_t('S') << (64 - 8) | uint64_t('P') << (64 - 16) |
0108 uint64_t('R') << (64 - 24) | uint64_t('O') << (64 - 32) |
0109 uint64_t('F') << (64 - 40) | uint64_t('4') << (64 - 48) |
0110 uint64_t('2') << (64 - 56) | uint64_t(Format);
0111 }
0112
0113 static inline uint64_t SPVersion() { return 103; }
0114
0115
0116
0117
0118 enum SecType {
0119 SecInValid = 0,
0120 SecProfSummary = 1,
0121 SecNameTable = 2,
0122 SecProfileSymbolList = 3,
0123 SecFuncOffsetTable = 4,
0124 SecFuncMetadata = 5,
0125 SecCSNameTable = 6,
0126
0127 SecFuncProfileFirst = 32,
0128 SecLBRProfile = SecFuncProfileFirst
0129 };
0130
0131 static inline std::string getSecName(SecType Type) {
0132 switch (static_cast<int>(Type)) {
0133 case SecInValid:
0134 return "InvalidSection";
0135 case SecProfSummary:
0136 return "ProfileSummarySection";
0137 case SecNameTable:
0138 return "NameTableSection";
0139 case SecProfileSymbolList:
0140 return "ProfileSymbolListSection";
0141 case SecFuncOffsetTable:
0142 return "FuncOffsetTableSection";
0143 case SecFuncMetadata:
0144 return "FunctionMetadata";
0145 case SecCSNameTable:
0146 return "CSNameTableSection";
0147 case SecLBRProfile:
0148 return "LBRProfileSection";
0149 default:
0150 return "UnknownSection";
0151 }
0152 }
0153
0154
0155
0156 struct SecHdrTableEntry {
0157 SecType Type;
0158 uint64_t Flags;
0159 uint64_t Offset;
0160 uint64_t Size;
0161
0162
0163 uint64_t LayoutIndex;
0164 };
0165
0166
0167
0168
0169 enum class SecCommonFlags : uint32_t {
0170 SecFlagInValid = 0,
0171 SecFlagCompress = (1 << 0),
0172
0173 SecFlagFlat = (1 << 1)
0174 };
0175
0176
0177
0178
0179 enum class SecNameTableFlags : uint32_t {
0180 SecFlagInValid = 0,
0181 SecFlagMD5Name = (1 << 0),
0182
0183
0184 SecFlagFixedLengthMD5 = (1 << 1),
0185
0186
0187 SecFlagUniqSuffix = (1 << 2)
0188 };
0189 enum class SecProfSummaryFlags : uint32_t {
0190 SecFlagInValid = 0,
0191
0192
0193
0194 SecFlagPartial = (1 << 0),
0195
0196
0197 SecFlagFullContext = (1 << 1),
0198
0199
0200 SecFlagFSDiscriminator = (1 << 2),
0201
0202
0203 SecFlagIsPreInlined = (1 << 4),
0204 };
0205
0206 enum class SecFuncMetadataFlags : uint32_t {
0207 SecFlagInvalid = 0,
0208 SecFlagIsProbeBased = (1 << 0),
0209 SecFlagHasAttribute = (1 << 1),
0210 };
0211
0212 enum class SecFuncOffsetFlags : uint32_t {
0213 SecFlagInvalid = 0,
0214
0215
0216 SecFlagOrdered = (1 << 0),
0217 };
0218
0219
0220 template <class SecFlagType>
0221 static inline void verifySecFlag(SecType Type, SecFlagType Flag) {
0222
0223 if (std::is_same<SecCommonFlags, SecFlagType>())
0224 return;
0225
0226
0227 bool IsFlagLegal = false;
0228 switch (Type) {
0229 case SecNameTable:
0230 IsFlagLegal = std::is_same<SecNameTableFlags, SecFlagType>();
0231 break;
0232 case SecProfSummary:
0233 IsFlagLegal = std::is_same<SecProfSummaryFlags, SecFlagType>();
0234 break;
0235 case SecFuncMetadata:
0236 IsFlagLegal = std::is_same<SecFuncMetadataFlags, SecFlagType>();
0237 break;
0238 default:
0239 case SecFuncOffsetTable:
0240 IsFlagLegal = std::is_same<SecFuncOffsetFlags, SecFlagType>();
0241 break;
0242 }
0243 if (!IsFlagLegal)
0244 llvm_unreachable("Misuse of a flag in an incompatible section");
0245 }
0246
0247 template <class SecFlagType>
0248 static inline void addSecFlag(SecHdrTableEntry &Entry, SecFlagType Flag) {
0249 verifySecFlag(Entry.Type, Flag);
0250 auto FVal = static_cast<uint64_t>(Flag);
0251 bool IsCommon = std::is_same<SecCommonFlags, SecFlagType>();
0252 Entry.Flags |= IsCommon ? FVal : (FVal << 32);
0253 }
0254
0255 template <class SecFlagType>
0256 static inline void removeSecFlag(SecHdrTableEntry &Entry, SecFlagType Flag) {
0257 verifySecFlag(Entry.Type, Flag);
0258 auto FVal = static_cast<uint64_t>(Flag);
0259 bool IsCommon = std::is_same<SecCommonFlags, SecFlagType>();
0260 Entry.Flags &= ~(IsCommon ? FVal : (FVal << 32));
0261 }
0262
0263 template <class SecFlagType>
0264 static inline bool hasSecFlag(const SecHdrTableEntry &Entry, SecFlagType Flag) {
0265 verifySecFlag(Entry.Type, Flag);
0266 auto FVal = static_cast<uint64_t>(Flag);
0267 bool IsCommon = std::is_same<SecCommonFlags, SecFlagType>();
0268 return Entry.Flags & (IsCommon ? FVal : (FVal << 32));
0269 }
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280 struct LineLocation {
0281 LineLocation(uint32_t L, uint32_t D) : LineOffset(L), Discriminator(D) {}
0282
0283 void print(raw_ostream &OS) const;
0284 void dump() const;
0285
0286 bool operator<(const LineLocation &O) const {
0287 return LineOffset < O.LineOffset ||
0288 (LineOffset == O.LineOffset && Discriminator < O.Discriminator);
0289 }
0290
0291 bool operator==(const LineLocation &O) const {
0292 return LineOffset == O.LineOffset && Discriminator == O.Discriminator;
0293 }
0294
0295 bool operator!=(const LineLocation &O) const {
0296 return LineOffset != O.LineOffset || Discriminator != O.Discriminator;
0297 }
0298
0299 uint64_t getHashCode() const {
0300 return ((uint64_t) Discriminator << 32) | LineOffset;
0301 }
0302
0303 uint32_t LineOffset;
0304 uint32_t Discriminator;
0305 };
0306
0307 struct LineLocationHash {
0308 uint64_t operator()(const LineLocation &Loc) const {
0309 return Loc.getHashCode();
0310 }
0311 };
0312
0313 raw_ostream &operator<<(raw_ostream &OS, const LineLocation &Loc);
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325 class SampleRecord {
0326 public:
0327 using CallTarget = std::pair<FunctionId, uint64_t>;
0328 struct CallTargetComparator {
0329 bool operator()(const CallTarget &LHS, const CallTarget &RHS) const {
0330 if (LHS.second != RHS.second)
0331 return LHS.second > RHS.second;
0332
0333 return LHS.first < RHS.first;
0334 }
0335 };
0336
0337 using SortedCallTargetSet = std::set<CallTarget, CallTargetComparator>;
0338 using CallTargetMap = std::unordered_map<FunctionId, uint64_t>;
0339 SampleRecord() = default;
0340
0341
0342
0343
0344
0345
0346 sampleprof_error addSamples(uint64_t S, uint64_t Weight = 1) {
0347 bool Overflowed;
0348 NumSamples = SaturatingMultiplyAdd(S, Weight, NumSamples, &Overflowed);
0349 return Overflowed ? sampleprof_error::counter_overflow
0350 : sampleprof_error::success;
0351 }
0352
0353
0354
0355 uint64_t removeSamples(uint64_t S) {
0356 if (S > NumSamples)
0357 S = NumSamples;
0358 NumSamples -= S;
0359 return S;
0360 }
0361
0362
0363
0364
0365
0366
0367 sampleprof_error addCalledTarget(FunctionId F, uint64_t S,
0368 uint64_t Weight = 1) {
0369 uint64_t &TargetSamples = CallTargets[F];
0370 bool Overflowed;
0371 TargetSamples =
0372 SaturatingMultiplyAdd(S, Weight, TargetSamples, &Overflowed);
0373 return Overflowed ? sampleprof_error::counter_overflow
0374 : sampleprof_error::success;
0375 }
0376
0377
0378
0379 uint64_t removeCalledTarget(FunctionId F) {
0380 uint64_t Count = 0;
0381 auto I = CallTargets.find(F);
0382 if (I != CallTargets.end()) {
0383 Count = I->second;
0384 CallTargets.erase(I);
0385 }
0386 return Count;
0387 }
0388
0389
0390 bool hasCalls() const { return !CallTargets.empty(); }
0391
0392 uint64_t getSamples() const { return NumSamples; }
0393 const CallTargetMap &getCallTargets() const { return CallTargets; }
0394 const SortedCallTargetSet getSortedCallTargets() const {
0395 return sortCallTargets(CallTargets);
0396 }
0397
0398 uint64_t getCallTargetSum() const {
0399 uint64_t Sum = 0;
0400 for (const auto &I : CallTargets)
0401 Sum += I.second;
0402 return Sum;
0403 }
0404
0405
0406 static const SortedCallTargetSet
0407 sortCallTargets(const CallTargetMap &Targets) {
0408 SortedCallTargetSet SortedTargets;
0409 for (const auto &[Target, Frequency] : Targets) {
0410 SortedTargets.emplace(Target, Frequency);
0411 }
0412 return SortedTargets;
0413 }
0414
0415
0416 static const CallTargetMap adjustCallTargets(const CallTargetMap &Targets,
0417 float DistributionFactor) {
0418 CallTargetMap AdjustedTargets;
0419 for (const auto &[Target, Frequency] : Targets) {
0420 AdjustedTargets[Target] = Frequency * DistributionFactor;
0421 }
0422 return AdjustedTargets;
0423 }
0424
0425
0426
0427 sampleprof_error merge(const SampleRecord &Other, uint64_t Weight = 1);
0428 void print(raw_ostream &OS, unsigned Indent) const;
0429 void dump() const;
0430
0431 bool operator==(const SampleRecord &Other) const {
0432 return NumSamples == Other.NumSamples && CallTargets == Other.CallTargets;
0433 }
0434
0435 bool operator!=(const SampleRecord &Other) const {
0436 return !(*this == Other);
0437 }
0438
0439 private:
0440 uint64_t NumSamples = 0;
0441 CallTargetMap CallTargets;
0442 };
0443
0444 raw_ostream &operator<<(raw_ostream &OS, const SampleRecord &Sample);
0445
0446
0447 enum ContextStateMask {
0448 UnknownContext = 0x0,
0449 RawContext = 0x1,
0450 SyntheticContext = 0x2,
0451 InlinedContext = 0x4,
0452 MergedContext = 0x8
0453 };
0454
0455
0456 enum ContextAttributeMask {
0457 ContextNone = 0x0,
0458 ContextWasInlined = 0x1,
0459 ContextShouldBeInlined = 0x2,
0460 ContextDuplicatedIntoBase =
0461 0x4,
0462 };
0463
0464
0465 struct SampleContextFrame {
0466 FunctionId Func;
0467 LineLocation Location;
0468
0469 SampleContextFrame() : Location(0, 0) {}
0470
0471 SampleContextFrame(FunctionId Func, LineLocation Location)
0472 : Func(Func), Location(Location) {}
0473
0474 bool operator==(const SampleContextFrame &That) const {
0475 return Location == That.Location && Func == That.Func;
0476 }
0477
0478 bool operator!=(const SampleContextFrame &That) const {
0479 return !(*this == That);
0480 }
0481
0482 std::string toString(bool OutputLineLocation) const {
0483 std::ostringstream OContextStr;
0484 OContextStr << Func.str();
0485 if (OutputLineLocation) {
0486 OContextStr << ":" << Location.LineOffset;
0487 if (Location.Discriminator)
0488 OContextStr << "." << Location.Discriminator;
0489 }
0490 return OContextStr.str();
0491 }
0492
0493 uint64_t getHashCode() const {
0494 uint64_t NameHash = Func.getHashCode();
0495 uint64_t LocId = Location.getHashCode();
0496 return NameHash + (LocId << 5) + LocId;
0497 }
0498 };
0499
0500 static inline hash_code hash_value(const SampleContextFrame &arg) {
0501 return arg.getHashCode();
0502 }
0503
0504 using SampleContextFrameVector = SmallVector<SampleContextFrame, 1>;
0505 using SampleContextFrames = ArrayRef<SampleContextFrame>;
0506
0507 struct SampleContextFrameHash {
0508 uint64_t operator()(const SampleContextFrameVector &S) const {
0509 return hash_combine_range(S.begin(), S.end());
0510 }
0511 };
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523 class SampleContext {
0524 public:
0525 SampleContext() : State(UnknownContext), Attributes(ContextNone) {}
0526
0527 SampleContext(StringRef Name)
0528 : Func(Name), State(UnknownContext), Attributes(ContextNone) {
0529 assert(!Name.empty() && "Name is empty");
0530 }
0531
0532 SampleContext(FunctionId Func)
0533 : Func(Func), State(UnknownContext), Attributes(ContextNone) {}
0534
0535 SampleContext(SampleContextFrames Context,
0536 ContextStateMask CState = RawContext)
0537 : Attributes(ContextNone) {
0538 assert(!Context.empty() && "Context is empty");
0539 setContext(Context, CState);
0540 }
0541
0542
0543
0544
0545 SampleContext(StringRef ContextStr,
0546 std::list<SampleContextFrameVector> &CSNameTable,
0547 ContextStateMask CState = RawContext)
0548 : Attributes(ContextNone) {
0549 assert(!ContextStr.empty());
0550
0551
0552 bool HasContext = ContextStr.starts_with("[");
0553 if (!HasContext) {
0554 State = UnknownContext;
0555 Func = FunctionId(ContextStr);
0556 } else {
0557 CSNameTable.emplace_back();
0558 SampleContextFrameVector &Context = CSNameTable.back();
0559 createCtxVectorFromStr(ContextStr, Context);
0560 setContext(Context, CState);
0561 }
0562 }
0563
0564
0565
0566 static void createCtxVectorFromStr(StringRef ContextStr,
0567 SampleContextFrameVector &Context) {
0568
0569 ContextStr = ContextStr.substr(1, ContextStr.size() - 2);
0570 StringRef ContextRemain = ContextStr;
0571 StringRef ChildContext;
0572 FunctionId Callee;
0573 while (!ContextRemain.empty()) {
0574 auto ContextSplit = ContextRemain.split(" @ ");
0575 ChildContext = ContextSplit.first;
0576 ContextRemain = ContextSplit.second;
0577 LineLocation CallSiteLoc(0, 0);
0578 decodeContextString(ChildContext, Callee, CallSiteLoc);
0579 Context.emplace_back(Callee, CallSiteLoc);
0580 }
0581 }
0582
0583
0584
0585 static void decodeContextString(StringRef ContextStr,
0586 FunctionId &Func,
0587 LineLocation &LineLoc) {
0588
0589 auto EntrySplit = ContextStr.split(':');
0590 Func = FunctionId(EntrySplit.first);
0591
0592 LineLoc = {0, 0};
0593 if (!EntrySplit.second.empty()) {
0594
0595
0596 int LineOffset = 0;
0597 auto LocSplit = EntrySplit.second.split('.');
0598 LocSplit.first.getAsInteger(10, LineOffset);
0599 LineLoc.LineOffset = LineOffset;
0600
0601
0602 if (!LocSplit.second.empty())
0603 LocSplit.second.getAsInteger(10, LineLoc.Discriminator);
0604 }
0605 }
0606
0607 operator SampleContextFrames() const { return FullContext; }
0608 bool hasAttribute(ContextAttributeMask A) { return Attributes & (uint32_t)A; }
0609 void setAttribute(ContextAttributeMask A) { Attributes |= (uint32_t)A; }
0610 uint32_t getAllAttributes() { return Attributes; }
0611 void setAllAttributes(uint32_t A) { Attributes = A; }
0612 bool hasState(ContextStateMask S) { return State & (uint32_t)S; }
0613 void setState(ContextStateMask S) { State |= (uint32_t)S; }
0614 void clearState(ContextStateMask S) { State &= (uint32_t)~S; }
0615 bool hasContext() const { return State != UnknownContext; }
0616 bool isBaseContext() const { return FullContext.size() == 1; }
0617 FunctionId getFunction() const { return Func; }
0618 SampleContextFrames getContextFrames() const { return FullContext; }
0619
0620 static std::string getContextString(SampleContextFrames Context,
0621 bool IncludeLeafLineLocation = false) {
0622 std::ostringstream OContextStr;
0623 for (uint32_t I = 0; I < Context.size(); I++) {
0624 if (OContextStr.str().size()) {
0625 OContextStr << " @ ";
0626 }
0627 OContextStr << Context[I].toString(I != Context.size() - 1 ||
0628 IncludeLeafLineLocation);
0629 }
0630 return OContextStr.str();
0631 }
0632
0633 std::string toString() const {
0634 if (!hasContext())
0635 return Func.str();
0636 return getContextString(FullContext, false);
0637 }
0638
0639 uint64_t getHashCode() const {
0640 if (hasContext())
0641 return hash_value(getContextFrames());
0642 return getFunction().getHashCode();
0643 }
0644
0645
0646 void setFunction(FunctionId NewFunctionID) {
0647 Func = NewFunctionID;
0648 FullContext = SampleContextFrames();
0649 State = UnknownContext;
0650 }
0651
0652 void setContext(SampleContextFrames Context,
0653 ContextStateMask CState = RawContext) {
0654 assert(CState != UnknownContext);
0655 FullContext = Context;
0656 Func = Context.back().Func;
0657 State = CState;
0658 }
0659
0660 bool operator==(const SampleContext &That) const {
0661 return State == That.State && Func == That.Func &&
0662 FullContext == That.FullContext;
0663 }
0664
0665 bool operator!=(const SampleContext &That) const { return !(*this == That); }
0666
0667 bool operator<(const SampleContext &That) const {
0668 if (State != That.State)
0669 return State < That.State;
0670
0671 if (!hasContext()) {
0672 return Func < That.Func;
0673 }
0674
0675 uint64_t I = 0;
0676 while (I < std::min(FullContext.size(), That.FullContext.size())) {
0677 auto &Context1 = FullContext[I];
0678 auto &Context2 = That.FullContext[I];
0679 auto V = Context1.Func.compare(Context2.Func);
0680 if (V)
0681 return V < 0;
0682 if (Context1.Location != Context2.Location)
0683 return Context1.Location < Context2.Location;
0684 I++;
0685 }
0686
0687 return FullContext.size() < That.FullContext.size();
0688 }
0689
0690 struct Hash {
0691 uint64_t operator()(const SampleContext &Context) const {
0692 return Context.getHashCode();
0693 }
0694 };
0695
0696 bool isPrefixOf(const SampleContext &That) const {
0697 auto ThisContext = FullContext;
0698 auto ThatContext = That.FullContext;
0699 if (ThatContext.size() < ThisContext.size())
0700 return false;
0701 ThatContext = ThatContext.take_front(ThisContext.size());
0702
0703 if (ThisContext.back().Func != ThatContext.back().Func)
0704 return false;
0705
0706 return ThisContext.drop_back() == ThatContext.drop_back();
0707 }
0708
0709 private:
0710
0711
0712 FunctionId Func;
0713
0714 SampleContextFrames FullContext;
0715
0716 uint32_t State;
0717
0718 uint32_t Attributes;
0719 };
0720
0721 static inline hash_code hash_value(const SampleContext &Context) {
0722 return Context.getHashCode();
0723 }
0724
0725 inline raw_ostream &operator<<(raw_ostream &OS, const SampleContext &Context) {
0726 return OS << Context.toString();
0727 }
0728
0729 class FunctionSamples;
0730 class SampleProfileReaderItaniumRemapper;
0731
0732 using BodySampleMap = std::map<LineLocation, SampleRecord>;
0733
0734
0735 using FunctionSamplesMap = std::map<FunctionId, FunctionSamples>;
0736 using CallsiteSampleMap = std::map<LineLocation, FunctionSamplesMap>;
0737 using LocToLocMap =
0738 std::unordered_map<LineLocation, LineLocation, LineLocationHash>;
0739
0740
0741
0742
0743
0744
0745 class FunctionSamples {
0746 public:
0747 FunctionSamples() = default;
0748
0749 void print(raw_ostream &OS = dbgs(), unsigned Indent = 0) const;
0750 void dump() const;
0751
0752 sampleprof_error addTotalSamples(uint64_t Num, uint64_t Weight = 1) {
0753 bool Overflowed;
0754 TotalSamples =
0755 SaturatingMultiplyAdd(Num, Weight, TotalSamples, &Overflowed);
0756 return Overflowed ? sampleprof_error::counter_overflow
0757 : sampleprof_error::success;
0758 }
0759
0760 void removeTotalSamples(uint64_t Num) {
0761 if (TotalSamples < Num)
0762 TotalSamples = 0;
0763 else
0764 TotalSamples -= Num;
0765 }
0766
0767 void setTotalSamples(uint64_t Num) { TotalSamples = Num; }
0768
0769 void setHeadSamples(uint64_t Num) { TotalHeadSamples = Num; }
0770
0771 sampleprof_error addHeadSamples(uint64_t Num, uint64_t Weight = 1) {
0772 bool Overflowed;
0773 TotalHeadSamples =
0774 SaturatingMultiplyAdd(Num, Weight, TotalHeadSamples, &Overflowed);
0775 return Overflowed ? sampleprof_error::counter_overflow
0776 : sampleprof_error::success;
0777 }
0778
0779 sampleprof_error addBodySamples(uint32_t LineOffset, uint32_t Discriminator,
0780 uint64_t Num, uint64_t Weight = 1) {
0781 return BodySamples[LineLocation(LineOffset, Discriminator)].addSamples(
0782 Num, Weight);
0783 }
0784
0785 sampleprof_error addCalledTargetSamples(uint32_t LineOffset,
0786 uint32_t Discriminator,
0787 FunctionId Func,
0788 uint64_t Num,
0789 uint64_t Weight = 1) {
0790 return BodySamples[LineLocation(LineOffset, Discriminator)].addCalledTarget(
0791 Func, Num, Weight);
0792 }
0793
0794 sampleprof_error addSampleRecord(LineLocation Location,
0795 const SampleRecord &SampleRecord,
0796 uint64_t Weight = 1) {
0797 return BodySamples[Location].merge(SampleRecord, Weight);
0798 }
0799
0800
0801
0802 uint64_t removeCalledTargetAndBodySample(uint32_t LineOffset,
0803 uint32_t Discriminator,
0804 FunctionId Func) {
0805 uint64_t Count = 0;
0806 auto I = BodySamples.find(LineLocation(LineOffset, Discriminator));
0807 if (I != BodySamples.end()) {
0808 Count = I->second.removeCalledTarget(Func);
0809 Count = I->second.removeSamples(Count);
0810 if (!I->second.getSamples())
0811 BodySamples.erase(I);
0812 }
0813 return Count;
0814 }
0815
0816
0817
0818 void removeAllCallsiteSamples() {
0819 CallsiteSamples.clear();
0820 }
0821
0822
0823 void updateCallsiteSamples() {
0824 for (auto &I : BodySamples) {
0825 uint64_t TargetSamples = I.second.getCallTargetSum();
0826
0827
0828
0829
0830 if (TargetSamples > I.second.getSamples())
0831 I.second.addSamples(TargetSamples - I.second.getSamples());
0832 }
0833 }
0834
0835
0836 void updateTotalSamples() {
0837 setTotalSamples(0);
0838 for (const auto &I : BodySamples)
0839 addTotalSamples(I.second.getSamples());
0840
0841 for (auto &I : CallsiteSamples) {
0842 for (auto &CS : I.second) {
0843 CS.second.updateTotalSamples();
0844 addTotalSamples(CS.second.getTotalSamples());
0845 }
0846 }
0847 }
0848
0849
0850 void setContextSynthetic() {
0851 Context.setState(SyntheticContext);
0852 for (auto &I : CallsiteSamples) {
0853 for (auto &CS : I.second) {
0854 CS.second.setContextSynthetic();
0855 }
0856 }
0857 }
0858
0859
0860 const LineLocation &mapIRLocToProfileLoc(const LineLocation &IRLoc) const {
0861
0862
0863 if (!IRToProfileLocationMap)
0864 return IRLoc;
0865 const auto &ProfileLoc = IRToProfileLocationMap->find(IRLoc);
0866 if (ProfileLoc != IRToProfileLocationMap->end())
0867 return ProfileLoc->second;
0868 return IRLoc;
0869 }
0870
0871
0872
0873
0874 ErrorOr<uint64_t> findSamplesAt(uint32_t LineOffset,
0875 uint32_t Discriminator) const {
0876 const auto &Ret = BodySamples.find(
0877 mapIRLocToProfileLoc(LineLocation(LineOffset, Discriminator)));
0878 if (Ret == BodySamples.end())
0879 return std::error_code();
0880 return Ret->second.getSamples();
0881 }
0882
0883
0884
0885
0886 ErrorOr<const SampleRecord::CallTargetMap &>
0887 findCallTargetMapAt(uint32_t LineOffset, uint32_t Discriminator) const {
0888 const auto &Ret = BodySamples.find(
0889 mapIRLocToProfileLoc(LineLocation(LineOffset, Discriminator)));
0890 if (Ret == BodySamples.end())
0891 return std::error_code();
0892 return Ret->second.getCallTargets();
0893 }
0894
0895
0896
0897 ErrorOr<const SampleRecord::CallTargetMap &>
0898 findCallTargetMapAt(const LineLocation &CallSite) const {
0899 const auto &Ret = BodySamples.find(mapIRLocToProfileLoc(CallSite));
0900 if (Ret == BodySamples.end())
0901 return std::error_code();
0902 return Ret->second.getCallTargets();
0903 }
0904
0905
0906 FunctionSamplesMap &functionSamplesAt(const LineLocation &Loc) {
0907 return CallsiteSamples[mapIRLocToProfileLoc(Loc)];
0908 }
0909
0910
0911 const FunctionSamplesMap *
0912 findFunctionSamplesMapAt(const LineLocation &Loc) const {
0913 auto Iter = CallsiteSamples.find(mapIRLocToProfileLoc(Loc));
0914 if (Iter == CallsiteSamples.end())
0915 return nullptr;
0916 return &Iter->second;
0917 }
0918
0919
0920
0921
0922
0923
0924
0925 const FunctionSamples *findFunctionSamplesAt(
0926 const LineLocation &Loc, StringRef CalleeName,
0927 SampleProfileReaderItaniumRemapper *Remapper,
0928 const HashKeyMap<std::unordered_map, FunctionId, FunctionId>
0929 *FuncNameToProfNameMap = nullptr) const;
0930
0931 bool empty() const { return TotalSamples == 0; }
0932
0933
0934 uint64_t getTotalSamples() const { return TotalSamples; }
0935
0936
0937
0938
0939
0940
0941
0942 uint64_t getHeadSamples() const { return TotalHeadSamples; }
0943
0944
0945
0946
0947
0948
0949 uint64_t getHeadSamplesEstimate() const {
0950 if (FunctionSamples::ProfileIsCS && getHeadSamples()) {
0951
0952
0953 return getHeadSamples();
0954 }
0955 uint64_t Count = 0;
0956
0957
0958 if (!BodySamples.empty() &&
0959 (CallsiteSamples.empty() ||
0960 BodySamples.begin()->first < CallsiteSamples.begin()->first))
0961 Count = BodySamples.begin()->second.getSamples();
0962 else if (!CallsiteSamples.empty()) {
0963
0964
0965 for (const auto &FuncSamples : CallsiteSamples.begin()->second)
0966 Count += FuncSamples.second.getHeadSamplesEstimate();
0967 }
0968
0969 return Count ? Count : TotalSamples > 0;
0970 }
0971
0972
0973 const BodySampleMap &getBodySamples() const { return BodySamples; }
0974
0975
0976 const CallsiteSampleMap &getCallsiteSamples() const {
0977 return CallsiteSamples;
0978 }
0979
0980
0981
0982
0983
0984 uint64_t getMaxCountInside(bool SkipCallSite = false) const {
0985 uint64_t MaxCount = 0;
0986 for (const auto &L : getBodySamples())
0987 MaxCount = std::max(MaxCount, L.second.getSamples());
0988 if (SkipCallSite)
0989 return MaxCount;
0990 for (const auto &C : getCallsiteSamples())
0991 for (const FunctionSamplesMap::value_type &F : C.second)
0992 MaxCount = std::max(MaxCount, F.second.getMaxCountInside());
0993 return MaxCount;
0994 }
0995
0996
0997
0998 sampleprof_error merge(const FunctionSamples &Other, uint64_t Weight = 1) {
0999 sampleprof_error Result = sampleprof_error::success;
1000 if (!GUIDToFuncNameMap)
1001 GUIDToFuncNameMap = Other.GUIDToFuncNameMap;
1002 if (Context.getFunction().empty())
1003 Context = Other.getContext();
1004 if (FunctionHash == 0) {
1005
1006 FunctionHash = Other.getFunctionHash();
1007 } else if (FunctionHash != Other.getFunctionHash()) {
1008
1009
1010
1011
1012
1013
1014
1015 return sampleprof_error::hash_mismatch;
1016 }
1017
1018 mergeSampleProfErrors(Result,
1019 addTotalSamples(Other.getTotalSamples(), Weight));
1020 mergeSampleProfErrors(Result,
1021 addHeadSamples(Other.getHeadSamples(), Weight));
1022 for (const auto &I : Other.getBodySamples()) {
1023 const LineLocation &Loc = I.first;
1024 const SampleRecord &Rec = I.second;
1025 mergeSampleProfErrors(Result, BodySamples[Loc].merge(Rec, Weight));
1026 }
1027 for (const auto &I : Other.getCallsiteSamples()) {
1028 const LineLocation &Loc = I.first;
1029 FunctionSamplesMap &FSMap = functionSamplesAt(Loc);
1030 for (const auto &Rec : I.second)
1031 mergeSampleProfErrors(Result,
1032 FSMap[Rec.first].merge(Rec.second, Weight));
1033 }
1034 return Result;
1035 }
1036
1037
1038
1039
1040
1041 void findInlinedFunctions(DenseSet<GlobalValue::GUID> &S,
1042 const HashKeyMap<std::unordered_map, FunctionId,
1043 Function *> &SymbolMap,
1044 uint64_t Threshold) const {
1045 if (TotalSamples <= Threshold)
1046 return;
1047 auto IsDeclaration = [](const Function *F) {
1048 return !F || F->isDeclaration();
1049 };
1050 if (IsDeclaration(SymbolMap.lookup(getFunction()))) {
1051
1052 S.insert(getGUID());
1053 }
1054
1055
1056 for (const auto &BS : BodySamples)
1057 for (const auto &TS : BS.second.getCallTargets())
1058 if (TS.second > Threshold) {
1059 const Function *Callee = SymbolMap.lookup(TS.first);
1060 if (IsDeclaration(Callee))
1061 S.insert(TS.first.getHashCode());
1062 }
1063 for (const auto &CS : CallsiteSamples)
1064 for (const auto &NameFS : CS.second)
1065 NameFS.second.findInlinedFunctions(S, SymbolMap, Threshold);
1066 }
1067
1068
1069 void setFunction(FunctionId NewFunctionID) {
1070 Context.setFunction(NewFunctionID);
1071 }
1072
1073
1074 FunctionId getFunction() const { return Context.getFunction(); }
1075
1076
1077 StringRef getFuncName() const { return getFuncName(getFunction()); }
1078
1079 void setFunctionHash(uint64_t Hash) { FunctionHash = Hash; }
1080
1081 uint64_t getFunctionHash() const { return FunctionHash; }
1082
1083 void setIRToProfileLocationMap(const LocToLocMap *LTLM) {
1084 assert(IRToProfileLocationMap == nullptr && "this should be set only once");
1085 IRToProfileLocationMap = LTLM;
1086 }
1087
1088
1089
1090 static StringRef getCanonicalFnName(const Function &F) {
1091 const char *AttrName = "sample-profile-suffix-elision-policy";
1092 auto Attr = F.getFnAttribute(AttrName).getValueAsString();
1093 return getCanonicalFnName(F.getName(), Attr);
1094 }
1095
1096
1097
1098 static constexpr const char *LLVMSuffix = ".llvm.";
1099 static constexpr const char *PartSuffix = ".part.";
1100 static constexpr const char *UniqSuffix = ".__uniq.";
1101
1102 static StringRef getCanonicalFnName(StringRef FnName,
1103 StringRef Attr = "selected") {
1104
1105
1106
1107 const char *KnownSuffixes[] = {LLVMSuffix, PartSuffix, UniqSuffix};
1108 if (Attr == "" || Attr == "all")
1109 return FnName.split('.').first;
1110 if (Attr == "selected") {
1111 StringRef Cand(FnName);
1112 for (const auto &Suf : KnownSuffixes) {
1113 StringRef Suffix(Suf);
1114
1115
1116 if (Suffix == UniqSuffix && FunctionSamples::HasUniqSuffix)
1117 continue;
1118 auto It = Cand.rfind(Suffix);
1119 if (It == StringRef::npos)
1120 continue;
1121 auto Dit = Cand.rfind('.');
1122 if (Dit == It + Suffix.size() - 1)
1123 Cand = Cand.substr(0, It);
1124 }
1125 return Cand;
1126 }
1127 if (Attr == "none")
1128 return FnName;
1129 assert(false && "internal error: unknown suffix elision policy");
1130 return FnName;
1131 }
1132
1133
1134
1135
1136
1137
1138
1139
1140 StringRef getFuncName(FunctionId Func) const {
1141 if (!UseMD5)
1142 return Func.stringRef();
1143
1144 assert(GUIDToFuncNameMap && "GUIDToFuncNameMap needs to be populated first");
1145 return GUIDToFuncNameMap->lookup(Func.getHashCode());
1146 }
1147
1148
1149
1150 static unsigned getOffset(const DILocation *DIL);
1151
1152
1153
1154
1155
1156 static LineLocation getCallSiteIdentifier(const DILocation *DIL,
1157 bool ProfileIsFS = false);
1158
1159
1160
1161
1162
1163 static uint64_t getCallSiteHash(FunctionId Callee,
1164 const LineLocation &Callsite) {
1165 return SampleContextFrame(Callee, Callsite).getHashCode();
1166 }
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180 const FunctionSamples *findFunctionSamples(
1181 const DILocation *DIL,
1182 SampleProfileReaderItaniumRemapper *Remapper = nullptr,
1183 const HashKeyMap<std::unordered_map, FunctionId, FunctionId>
1184 *FuncNameToProfNameMap = nullptr) const;
1185
1186 static bool ProfileIsProbeBased;
1187
1188 static bool ProfileIsCS;
1189
1190 static bool ProfileIsPreInlined;
1191
1192 SampleContext &getContext() const { return Context; }
1193
1194 void setContext(const SampleContext &FContext) { Context = FContext; }
1195
1196
1197 static bool UseMD5;
1198
1199
1200 static bool HasUniqSuffix;
1201
1202
1203 static bool ProfileIsFS;
1204
1205
1206
1207 DenseMap<uint64_t, StringRef> *GUIDToFuncNameMap = nullptr;
1208
1209
1210
1211 uint64_t getGUID() const {
1212 return getFunction().getHashCode();
1213 }
1214
1215
1216
1217 void findAllNames(DenseSet<FunctionId> &NameSet) const;
1218
1219 bool operator==(const FunctionSamples &Other) const {
1220 return (GUIDToFuncNameMap == Other.GUIDToFuncNameMap ||
1221 (GUIDToFuncNameMap && Other.GUIDToFuncNameMap &&
1222 *GUIDToFuncNameMap == *Other.GUIDToFuncNameMap)) &&
1223 FunctionHash == Other.FunctionHash && Context == Other.Context &&
1224 TotalSamples == Other.TotalSamples &&
1225 TotalHeadSamples == Other.TotalHeadSamples &&
1226 BodySamples == Other.BodySamples &&
1227 CallsiteSamples == Other.CallsiteSamples;
1228 }
1229
1230 bool operator!=(const FunctionSamples &Other) const {
1231 return !(*this == Other);
1232 }
1233
1234 private:
1235
1236 uint64_t FunctionHash = 0;
1237
1238
1239 mutable SampleContext Context;
1240
1241
1242
1243
1244
1245 uint64_t TotalSamples = 0;
1246
1247
1248
1249
1250 uint64_t TotalHeadSamples = 0;
1251
1252
1253
1254
1255
1256
1257 BodySampleMap BodySamples;
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275 CallsiteSampleMap CallsiteSamples;
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294 const LocToLocMap *IRToProfileLocationMap = nullptr;
1295 };
1296
1297
1298
1299 static inline FunctionId getRepInFormat(StringRef Name) {
1300 if (Name.empty() || !FunctionSamples::UseMD5)
1301 return FunctionId(Name);
1302 return FunctionId(Function::getGUID(Name));
1303 }
1304
1305 raw_ostream &operator<<(raw_ostream &OS, const FunctionSamples &FS);
1306
1307
1308
1309
1310
1311
1312 class SampleProfileMap
1313 : public HashKeyMap<std::unordered_map, SampleContext, FunctionSamples> {
1314 public:
1315
1316
1317 mapped_type &create(const SampleContext &Ctx) {
1318 auto Ret = try_emplace(Ctx, FunctionSamples());
1319 if (Ret.second)
1320 Ret.first->second.setContext(Ctx);
1321 return Ret.first->second;
1322 }
1323
1324 iterator find(const SampleContext &Ctx) {
1325 return HashKeyMap<std::unordered_map, SampleContext, FunctionSamples>::find(
1326 Ctx);
1327 }
1328
1329 const_iterator find(const SampleContext &Ctx) const {
1330 return HashKeyMap<std::unordered_map, SampleContext, FunctionSamples>::find(
1331 Ctx);
1332 }
1333
1334 size_t erase(const SampleContext &Ctx) {
1335 return HashKeyMap<std::unordered_map, SampleContext, FunctionSamples>::
1336 erase(Ctx);
1337 }
1338
1339 size_t erase(const key_type &Key) { return base_type::erase(Key); }
1340
1341 iterator erase(iterator It) { return base_type::erase(It); }
1342 };
1343
1344 using NameFunctionSamples = std::pair<hash_code, const FunctionSamples *>;
1345
1346 void sortFuncProfiles(const SampleProfileMap &ProfileMap,
1347 std::vector<NameFunctionSamples> &SortedProfiles);
1348
1349
1350
1351
1352
1353 template <class LocationT, class SampleT> class SampleSorter {
1354 public:
1355 using SamplesWithLoc = std::pair<const LocationT, SampleT>;
1356 using SamplesWithLocList = SmallVector<const SamplesWithLoc *, 20>;
1357
1358 SampleSorter(const std::map<LocationT, SampleT> &Samples) {
1359 for (const auto &I : Samples)
1360 V.push_back(&I);
1361 llvm::stable_sort(V, [](const SamplesWithLoc *A, const SamplesWithLoc *B) {
1362 return A->first < B->first;
1363 });
1364 }
1365
1366 const SamplesWithLocList &get() const { return V; }
1367
1368 private:
1369 SamplesWithLocList V;
1370 };
1371
1372
1373
1374
1375 class SampleContextTrimmer {
1376 public:
1377 SampleContextTrimmer(SampleProfileMap &Profiles) : ProfileMap(Profiles){};
1378
1379
1380
1381
1382
1383
1384
1385 void trimAndMergeColdContextProfiles(uint64_t ColdCountThreshold,
1386 bool TrimColdContext,
1387 bool MergeColdContext,
1388 uint32_t ColdContextFrameLength,
1389 bool TrimBaseProfileOnly);
1390
1391 private:
1392 SampleProfileMap &ProfileMap;
1393 };
1394
1395
1396
1397
1398
1399 class ProfileConverter {
1400 public:
1401 ProfileConverter(SampleProfileMap &Profiles);
1402
1403
1404 void convertCSProfiles();
1405 struct FrameNode {
1406 FrameNode(FunctionId FName = FunctionId(),
1407 FunctionSamples *FSamples = nullptr,
1408 LineLocation CallLoc = {0, 0})
1409 : FuncName(FName), FuncSamples(FSamples), CallSiteLoc(CallLoc){};
1410
1411
1412 std::map<uint64_t, FrameNode> AllChildFrames;
1413
1414 FunctionId FuncName;
1415
1416 FunctionSamples *FuncSamples;
1417
1418 LineLocation CallSiteLoc;
1419
1420 FrameNode *getOrCreateChildFrame(const LineLocation &CallSite,
1421 FunctionId CalleeName);
1422 };
1423
1424 static void flattenProfile(SampleProfileMap &ProfileMap,
1425 bool ProfileIsCS = false) {
1426 SampleProfileMap TmpProfiles;
1427 flattenProfile(ProfileMap, TmpProfiles, ProfileIsCS);
1428 ProfileMap = std::move(TmpProfiles);
1429 }
1430
1431 static void flattenProfile(const SampleProfileMap &InputProfiles,
1432 SampleProfileMap &OutputProfiles,
1433 bool ProfileIsCS = false) {
1434 if (ProfileIsCS) {
1435 for (const auto &I : InputProfiles) {
1436
1437
1438 FunctionSamples &FS = OutputProfiles.create(I.second.getFunction());
1439 FS.merge(I.second);
1440 }
1441 } else {
1442 for (const auto &I : InputProfiles)
1443 flattenNestedProfile(OutputProfiles, I.second);
1444 }
1445 }
1446
1447 private:
1448 static void flattenNestedProfile(SampleProfileMap &OutputProfiles,
1449 const FunctionSamples &FS) {
1450
1451
1452 SampleContext &Context = FS.getContext();
1453 auto Ret = OutputProfiles.try_emplace(Context, FS);
1454 FunctionSamples &Profile = Ret.first->second;
1455 if (Ret.second) {
1456
1457
1458 Profile.removeAllCallsiteSamples();
1459
1460 Profile.setTotalSamples(0);
1461 } else {
1462 for (const auto &[LineLocation, SampleRecord] : FS.getBodySamples()) {
1463 Profile.addSampleRecord(LineLocation, SampleRecord);
1464 }
1465 }
1466
1467 assert(Profile.getCallsiteSamples().empty() &&
1468 "There should be no inlinees' profiles after flattening.");
1469
1470
1471
1472
1473
1474 uint64_t TotalSamples = FS.getTotalSamples();
1475
1476 for (const auto &I : FS.getCallsiteSamples()) {
1477 for (const auto &Callee : I.second) {
1478 const auto &CalleeProfile = Callee.second;
1479
1480 Profile.addBodySamples(I.first.LineOffset, I.first.Discriminator,
1481 CalleeProfile.getHeadSamplesEstimate());
1482
1483 Profile.addCalledTargetSamples(
1484 I.first.LineOffset, I.first.Discriminator,
1485 CalleeProfile.getFunction(),
1486 CalleeProfile.getHeadSamplesEstimate());
1487
1488 TotalSamples = TotalSamples >= CalleeProfile.getTotalSamples()
1489 ? TotalSamples - CalleeProfile.getTotalSamples()
1490 : 0;
1491 TotalSamples += CalleeProfile.getHeadSamplesEstimate();
1492
1493 flattenNestedProfile(OutputProfiles, CalleeProfile);
1494 }
1495 }
1496 Profile.addTotalSamples(TotalSamples);
1497
1498 Profile.setHeadSamples(Profile.getHeadSamplesEstimate());
1499 }
1500
1501
1502 void convertCSProfiles(FrameNode &Node);
1503 FrameNode *getOrCreateContextPath(const SampleContext &Context);
1504
1505 SampleProfileMap &ProfileMap;
1506 FrameNode RootFrame;
1507 };
1508
1509
1510
1511
1512
1513 class ProfileSymbolList {
1514 public:
1515
1516
1517 void add(StringRef Name, bool Copy = false) {
1518 if (!Copy) {
1519 Syms.insert(Name);
1520 return;
1521 }
1522 Syms.insert(Name.copy(Allocator));
1523 }
1524
1525 bool contains(StringRef Name) { return Syms.count(Name); }
1526
1527 void merge(const ProfileSymbolList &List) {
1528 for (auto Sym : List.Syms)
1529 add(Sym, true);
1530 }
1531
1532 unsigned size() { return Syms.size(); }
1533
1534 void setToCompress(bool TC) { ToCompress = TC; }
1535 bool toCompress() { return ToCompress; }
1536
1537 std::error_code read(const uint8_t *Data, uint64_t ListSize);
1538 std::error_code write(raw_ostream &OS);
1539 void dump(raw_ostream &OS = dbgs()) const;
1540
1541 private:
1542
1543
1544
1545 bool ToCompress = false;
1546 DenseSet<StringRef> Syms;
1547 BumpPtrAllocator Allocator;
1548 };
1549
1550 }
1551
1552 using namespace sampleprof;
1553
1554 template <> struct DenseMapInfo<SampleContext> {
1555 static inline SampleContext getEmptyKey() { return SampleContext(); }
1556
1557 static inline SampleContext getTombstoneKey() {
1558 return SampleContext(FunctionId(~1ULL));
1559 }
1560
1561 static unsigned getHashValue(const SampleContext &Val) {
1562 return Val.getHashCode();
1563 }
1564
1565 static bool isEqual(const SampleContext &LHS, const SampleContext &RHS) {
1566 return LHS == RHS;
1567 }
1568 };
1569
1570
1571
1572
1573
1574
1575 inline std::string getUniqueInternalLinkagePostfix(const StringRef &FName) {
1576 llvm::MD5 Md5;
1577 Md5.update(FName);
1578 llvm::MD5::MD5Result R;
1579 Md5.final(R);
1580 SmallString<32> Str;
1581 llvm::MD5::stringifyResult(R, Str);
1582
1583
1584 llvm::APInt IntHash(128, Str.str(), 16);
1585 return toString(IntHash, 10, false)
1586 .insert(0, FunctionSamples::UniqSuffix);
1587 }
1588
1589 }
1590
1591 #endif