10b57cec5SDimitry Andric //=-- ProfilesummaryBuilder.cpp - Profile summary computation ---------------=// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file contains support for computing profile summary data. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "llvm/IR/Attributes.h" 140b57cec5SDimitry Andric #include "llvm/IR/Function.h" 150b57cec5SDimitry Andric #include "llvm/IR/Metadata.h" 160b57cec5SDimitry Andric #include "llvm/IR/Type.h" 170b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProf.h" 180b57cec5SDimitry Andric #include "llvm/ProfileData/ProfileCommon.h" 190b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProf.h" 200b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 21d409305fSDimitry Andric #include "llvm/Support/CommandLine.h" 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric using namespace llvm; 240b57cec5SDimitry Andric 25d409305fSDimitry Andric cl::opt<bool> UseContextLessSummary( 26d409305fSDimitry Andric "profile-summary-contextless", cl::Hidden, cl::init(false), cl::ZeroOrMore, 27d409305fSDimitry Andric cl::desc("Merge context profiles before calculating thresholds.")); 28d409305fSDimitry Andric 29fe6060f1SDimitry Andric // The following two parameters determine the threshold for a count to be 30fe6060f1SDimitry Andric // considered hot/cold. These two parameters are percentile values (multiplied 31fe6060f1SDimitry Andric // by 10000). If the counts are sorted in descending order, the minimum count to 32fe6060f1SDimitry Andric // reach ProfileSummaryCutoffHot gives the threshold to determine a hot count. 33fe6060f1SDimitry Andric // Similarly, the minimum count to reach ProfileSummaryCutoffCold gives the 34fe6060f1SDimitry Andric // threshold for determining cold count (everything <= this threshold is 35fe6060f1SDimitry Andric // considered cold). 36fe6060f1SDimitry Andric cl::opt<int> ProfileSummaryCutoffHot( 37fe6060f1SDimitry Andric "profile-summary-cutoff-hot", cl::Hidden, cl::init(990000), cl::ZeroOrMore, 38fe6060f1SDimitry Andric cl::desc("A count is hot if it exceeds the minimum count to" 39fe6060f1SDimitry Andric " reach this percentile of total counts.")); 40fe6060f1SDimitry Andric 41fe6060f1SDimitry Andric cl::opt<int> ProfileSummaryCutoffCold( 42fe6060f1SDimitry Andric "profile-summary-cutoff-cold", cl::Hidden, cl::init(999999), cl::ZeroOrMore, 43fe6060f1SDimitry Andric cl::desc("A count is cold if it is below the minimum count" 44fe6060f1SDimitry Andric " to reach this percentile of total counts.")); 45fe6060f1SDimitry Andric 46fe6060f1SDimitry Andric cl::opt<unsigned> ProfileSummaryHugeWorkingSetSizeThreshold( 47fe6060f1SDimitry Andric "profile-summary-huge-working-set-size-threshold", cl::Hidden, 48fe6060f1SDimitry Andric cl::init(15000), cl::ZeroOrMore, 49fe6060f1SDimitry Andric cl::desc("The code working set size is considered huge if the number of" 50fe6060f1SDimitry Andric " blocks required to reach the -profile-summary-cutoff-hot" 51fe6060f1SDimitry Andric " percentile exceeds this count.")); 52fe6060f1SDimitry Andric 53fe6060f1SDimitry Andric cl::opt<unsigned> ProfileSummaryLargeWorkingSetSizeThreshold( 54fe6060f1SDimitry Andric "profile-summary-large-working-set-size-threshold", cl::Hidden, 55fe6060f1SDimitry Andric cl::init(12500), cl::ZeroOrMore, 56fe6060f1SDimitry Andric cl::desc("The code working set size is considered large if the number of" 57fe6060f1SDimitry Andric " blocks required to reach the -profile-summary-cutoff-hot" 58fe6060f1SDimitry Andric " percentile exceeds this count.")); 59fe6060f1SDimitry Andric 60fe6060f1SDimitry Andric // The next two options override the counts derived from summary computation and 61fe6060f1SDimitry Andric // are useful for debugging purposes. 62fe6060f1SDimitry Andric cl::opt<int> ProfileSummaryHotCount( 63fe6060f1SDimitry Andric "profile-summary-hot-count", cl::ReallyHidden, cl::ZeroOrMore, 64fe6060f1SDimitry Andric cl::desc("A fixed hot count that overrides the count derived from" 65fe6060f1SDimitry Andric " profile-summary-cutoff-hot")); 66fe6060f1SDimitry Andric 67fe6060f1SDimitry Andric cl::opt<int> ProfileSummaryColdCount( 68fe6060f1SDimitry Andric "profile-summary-cold-count", cl::ReallyHidden, cl::ZeroOrMore, 69fe6060f1SDimitry Andric cl::desc("A fixed cold count that overrides the count derived from" 70fe6060f1SDimitry Andric " profile-summary-cutoff-cold")); 71fe6060f1SDimitry Andric 720b57cec5SDimitry Andric // A set of cutoff values. Each value, when divided by ProfileSummary::Scale 730b57cec5SDimitry Andric // (which is 1000000) is a desired percentile of total counts. 740b57cec5SDimitry Andric static const uint32_t DefaultCutoffsData[] = { 750b57cec5SDimitry Andric 10000, /* 1% */ 760b57cec5SDimitry Andric 100000, /* 10% */ 770b57cec5SDimitry Andric 200000, 300000, 400000, 500000, 600000, 700000, 800000, 780b57cec5SDimitry Andric 900000, 950000, 990000, 999000, 999900, 999990, 999999}; 790b57cec5SDimitry Andric const ArrayRef<uint32_t> ProfileSummaryBuilder::DefaultCutoffs = 800b57cec5SDimitry Andric DefaultCutoffsData; 810b57cec5SDimitry Andric 825ffd83dbSDimitry Andric const ProfileSummaryEntry & 83*349cc55cSDimitry Andric ProfileSummaryBuilder::getEntryForPercentile(const SummaryEntryVector &DS, 845ffd83dbSDimitry Andric uint64_t Percentile) { 855ffd83dbSDimitry Andric auto It = partition_point(DS, [=](const ProfileSummaryEntry &Entry) { 865ffd83dbSDimitry Andric return Entry.Cutoff < Percentile; 875ffd83dbSDimitry Andric }); 885ffd83dbSDimitry Andric // The required percentile has to be <= one of the percentiles in the 895ffd83dbSDimitry Andric // detailed summary. 905ffd83dbSDimitry Andric if (It == DS.end()) 915ffd83dbSDimitry Andric report_fatal_error("Desired percentile exceeds the maximum cutoff"); 925ffd83dbSDimitry Andric return *It; 935ffd83dbSDimitry Andric } 945ffd83dbSDimitry Andric 950b57cec5SDimitry Andric void InstrProfSummaryBuilder::addRecord(const InstrProfRecord &R) { 960b57cec5SDimitry Andric // The first counter is not necessarily an entry count for IR 970b57cec5SDimitry Andric // instrumentation profiles. 980b57cec5SDimitry Andric // Eventually MaxFunctionCount will become obsolete and this can be 990b57cec5SDimitry Andric // removed. 1000b57cec5SDimitry Andric addEntryCount(R.Counts[0]); 1010b57cec5SDimitry Andric for (size_t I = 1, E = R.Counts.size(); I < E; ++I) 1020b57cec5SDimitry Andric addInternalCount(R.Counts[I]); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric // To compute the detailed summary, we consider each line containing samples as 1060b57cec5SDimitry Andric // equivalent to a block with a count in the instrumented profile. 1070b57cec5SDimitry Andric void SampleProfileSummaryBuilder::addRecord( 1080b57cec5SDimitry Andric const sampleprof::FunctionSamples &FS, bool isCallsiteSample) { 1090b57cec5SDimitry Andric if (!isCallsiteSample) { 1100b57cec5SDimitry Andric NumFunctions++; 1110b57cec5SDimitry Andric if (FS.getHeadSamples() > MaxFunctionCount) 1120b57cec5SDimitry Andric MaxFunctionCount = FS.getHeadSamples(); 1130b57cec5SDimitry Andric } 114fe6060f1SDimitry Andric for (const auto &I : FS.getBodySamples()) { 115fe6060f1SDimitry Andric uint64_t Count = I.second.getSamples(); 116fe6060f1SDimitry Andric addCount(Count); 117fe6060f1SDimitry Andric } 1180b57cec5SDimitry Andric for (const auto &I : FS.getCallsiteSamples()) 1190b57cec5SDimitry Andric for (const auto &CS : I.second) 1200b57cec5SDimitry Andric addRecord(CS.second, true); 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric // The argument to this method is a vector of cutoff percentages and the return 1240b57cec5SDimitry Andric // value is a vector of (Cutoff, MinCount, NumCounts) triplets. 1250b57cec5SDimitry Andric void ProfileSummaryBuilder::computeDetailedSummary() { 1260b57cec5SDimitry Andric if (DetailedSummaryCutoffs.empty()) 1270b57cec5SDimitry Andric return; 1280b57cec5SDimitry Andric llvm::sort(DetailedSummaryCutoffs); 1290b57cec5SDimitry Andric auto Iter = CountFrequencies.begin(); 1300b57cec5SDimitry Andric const auto End = CountFrequencies.end(); 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric uint32_t CountsSeen = 0; 1330b57cec5SDimitry Andric uint64_t CurrSum = 0, Count = 0; 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric for (const uint32_t Cutoff : DetailedSummaryCutoffs) { 1360b57cec5SDimitry Andric assert(Cutoff <= 999999); 1370b57cec5SDimitry Andric APInt Temp(128, TotalCount); 1380b57cec5SDimitry Andric APInt N(128, Cutoff); 1390b57cec5SDimitry Andric APInt D(128, ProfileSummary::Scale); 1400b57cec5SDimitry Andric Temp *= N; 1410b57cec5SDimitry Andric Temp = Temp.sdiv(D); 1420b57cec5SDimitry Andric uint64_t DesiredCount = Temp.getZExtValue(); 1430b57cec5SDimitry Andric assert(DesiredCount <= TotalCount); 1440b57cec5SDimitry Andric while (CurrSum < DesiredCount && Iter != End) { 1450b57cec5SDimitry Andric Count = Iter->first; 1460b57cec5SDimitry Andric uint32_t Freq = Iter->second; 1470b57cec5SDimitry Andric CurrSum += (Count * Freq); 1480b57cec5SDimitry Andric CountsSeen += Freq; 1490b57cec5SDimitry Andric Iter++; 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric assert(CurrSum >= DesiredCount); 1520b57cec5SDimitry Andric ProfileSummaryEntry PSE = {Cutoff, Count, CountsSeen}; 1530b57cec5SDimitry Andric DetailedSummary.push_back(PSE); 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric } 1560b57cec5SDimitry Andric 157*349cc55cSDimitry Andric uint64_t 158*349cc55cSDimitry Andric ProfileSummaryBuilder::getHotCountThreshold(const SummaryEntryVector &DS) { 159fe6060f1SDimitry Andric auto &HotEntry = 160fe6060f1SDimitry Andric ProfileSummaryBuilder::getEntryForPercentile(DS, ProfileSummaryCutoffHot); 161fe6060f1SDimitry Andric uint64_t HotCountThreshold = HotEntry.MinCount; 162fe6060f1SDimitry Andric if (ProfileSummaryHotCount.getNumOccurrences() > 0) 163fe6060f1SDimitry Andric HotCountThreshold = ProfileSummaryHotCount; 164fe6060f1SDimitry Andric return HotCountThreshold; 165fe6060f1SDimitry Andric } 166fe6060f1SDimitry Andric 167*349cc55cSDimitry Andric uint64_t 168*349cc55cSDimitry Andric ProfileSummaryBuilder::getColdCountThreshold(const SummaryEntryVector &DS) { 169fe6060f1SDimitry Andric auto &ColdEntry = ProfileSummaryBuilder::getEntryForPercentile( 170fe6060f1SDimitry Andric DS, ProfileSummaryCutoffCold); 171fe6060f1SDimitry Andric uint64_t ColdCountThreshold = ColdEntry.MinCount; 172fe6060f1SDimitry Andric if (ProfileSummaryColdCount.getNumOccurrences() > 0) 173fe6060f1SDimitry Andric ColdCountThreshold = ProfileSummaryColdCount; 174fe6060f1SDimitry Andric return ColdCountThreshold; 175fe6060f1SDimitry Andric } 176fe6060f1SDimitry Andric 1770b57cec5SDimitry Andric std::unique_ptr<ProfileSummary> SampleProfileSummaryBuilder::getSummary() { 1780b57cec5SDimitry Andric computeDetailedSummary(); 1798bcb0991SDimitry Andric return std::make_unique<ProfileSummary>( 1800b57cec5SDimitry Andric ProfileSummary::PSK_Sample, DetailedSummary, TotalCount, MaxCount, 0, 1810b57cec5SDimitry Andric MaxFunctionCount, NumCounts, NumFunctions); 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric 184d409305fSDimitry Andric std::unique_ptr<ProfileSummary> 185d409305fSDimitry Andric SampleProfileSummaryBuilder::computeSummaryForProfiles( 186*349cc55cSDimitry Andric const SampleProfileMap &Profiles) { 187d409305fSDimitry Andric assert(NumFunctions == 0 && 188d409305fSDimitry Andric "This can only be called on an empty summary builder"); 189*349cc55cSDimitry Andric sampleprof::SampleProfileMap ContextLessProfiles; 190*349cc55cSDimitry Andric const sampleprof::SampleProfileMap *ProfilesToUse = &Profiles; 191d409305fSDimitry Andric // For CSSPGO, context-sensitive profile effectively split a function profile 192d409305fSDimitry Andric // into many copies each representing the CFG profile of a particular calling 193d409305fSDimitry Andric // context. That makes the count distribution looks more flat as we now have 194d409305fSDimitry Andric // more function profiles each with lower counts, which in turn leads to lower 195*349cc55cSDimitry Andric // hot thresholds. To compensate for that, by default we merge context 196*349cc55cSDimitry Andric // profiles before computing profile summary. 197d409305fSDimitry Andric if (UseContextLessSummary || (sampleprof::FunctionSamples::ProfileIsCS && 198d409305fSDimitry Andric !UseContextLessSummary.getNumOccurrences())) { 199d409305fSDimitry Andric for (const auto &I : Profiles) { 200d409305fSDimitry Andric ContextLessProfiles[I.second.getName()].merge(I.second); 201d409305fSDimitry Andric } 202d409305fSDimitry Andric ProfilesToUse = &ContextLessProfiles; 203d409305fSDimitry Andric } 204d409305fSDimitry Andric 205d409305fSDimitry Andric for (const auto &I : *ProfilesToUse) { 206d409305fSDimitry Andric const sampleprof::FunctionSamples &Profile = I.second; 207d409305fSDimitry Andric addRecord(Profile); 208d409305fSDimitry Andric } 209d409305fSDimitry Andric 210d409305fSDimitry Andric return getSummary(); 211d409305fSDimitry Andric } 212d409305fSDimitry Andric 2130b57cec5SDimitry Andric std::unique_ptr<ProfileSummary> InstrProfSummaryBuilder::getSummary() { 2140b57cec5SDimitry Andric computeDetailedSummary(); 2158bcb0991SDimitry Andric return std::make_unique<ProfileSummary>( 2160b57cec5SDimitry Andric ProfileSummary::PSK_Instr, DetailedSummary, TotalCount, MaxCount, 2170b57cec5SDimitry Andric MaxInternalBlockCount, MaxFunctionCount, NumCounts, NumFunctions); 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric void InstrProfSummaryBuilder::addEntryCount(uint64_t Count) { 2210b57cec5SDimitry Andric NumFunctions++; 222e8d8bef9SDimitry Andric 223e8d8bef9SDimitry Andric // Skip invalid count. 224e8d8bef9SDimitry Andric if (Count == (uint64_t)-1) 225e8d8bef9SDimitry Andric return; 226e8d8bef9SDimitry Andric 227e8d8bef9SDimitry Andric addCount(Count); 2280b57cec5SDimitry Andric if (Count > MaxFunctionCount) 2290b57cec5SDimitry Andric MaxFunctionCount = Count; 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric void InstrProfSummaryBuilder::addInternalCount(uint64_t Count) { 233e8d8bef9SDimitry Andric // Skip invalid count. 234e8d8bef9SDimitry Andric if (Count == (uint64_t)-1) 235e8d8bef9SDimitry Andric return; 236e8d8bef9SDimitry Andric 2370b57cec5SDimitry Andric addCount(Count); 2380b57cec5SDimitry Andric if (Count > MaxInternalBlockCount) 2390b57cec5SDimitry Andric MaxInternalBlockCount = Count; 2400b57cec5SDimitry Andric } 241