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 13*81ad6265SDimitry Andric #include "llvm/IR/ProfileSummary.h" 140b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProf.h" 150b57cec5SDimitry Andric #include "llvm/ProfileData/ProfileCommon.h" 160b57cec5SDimitry Andric #include "llvm/ProfileData/SampleProf.h" 17d409305fSDimitry Andric #include "llvm/Support/CommandLine.h" 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric using namespace llvm; 200b57cec5SDimitry Andric 21d409305fSDimitry Andric cl::opt<bool> UseContextLessSummary( 22*81ad6265SDimitry Andric "profile-summary-contextless", cl::Hidden, 23d409305fSDimitry Andric cl::desc("Merge context profiles before calculating thresholds.")); 24d409305fSDimitry Andric 25fe6060f1SDimitry Andric // The following two parameters determine the threshold for a count to be 26fe6060f1SDimitry Andric // considered hot/cold. These two parameters are percentile values (multiplied 27fe6060f1SDimitry Andric // by 10000). If the counts are sorted in descending order, the minimum count to 28fe6060f1SDimitry Andric // reach ProfileSummaryCutoffHot gives the threshold to determine a hot count. 29fe6060f1SDimitry Andric // Similarly, the minimum count to reach ProfileSummaryCutoffCold gives the 30fe6060f1SDimitry Andric // threshold for determining cold count (everything <= this threshold is 31fe6060f1SDimitry Andric // considered cold). 32fe6060f1SDimitry Andric cl::opt<int> ProfileSummaryCutoffHot( 33*81ad6265SDimitry Andric "profile-summary-cutoff-hot", cl::Hidden, cl::init(990000), 34fe6060f1SDimitry Andric cl::desc("A count is hot if it exceeds the minimum count to" 35fe6060f1SDimitry Andric " reach this percentile of total counts.")); 36fe6060f1SDimitry Andric 37fe6060f1SDimitry Andric cl::opt<int> ProfileSummaryCutoffCold( 38*81ad6265SDimitry Andric "profile-summary-cutoff-cold", cl::Hidden, cl::init(999999), 39fe6060f1SDimitry Andric cl::desc("A count is cold if it is below the minimum count" 40fe6060f1SDimitry Andric " to reach this percentile of total counts.")); 41fe6060f1SDimitry Andric 42fe6060f1SDimitry Andric cl::opt<unsigned> ProfileSummaryHugeWorkingSetSizeThreshold( 43fe6060f1SDimitry Andric "profile-summary-huge-working-set-size-threshold", cl::Hidden, 44*81ad6265SDimitry Andric cl::init(15000), 45fe6060f1SDimitry Andric cl::desc("The code working set size is considered huge if the number of" 46fe6060f1SDimitry Andric " blocks required to reach the -profile-summary-cutoff-hot" 47fe6060f1SDimitry Andric " percentile exceeds this count.")); 48fe6060f1SDimitry Andric 49fe6060f1SDimitry Andric cl::opt<unsigned> ProfileSummaryLargeWorkingSetSizeThreshold( 50fe6060f1SDimitry Andric "profile-summary-large-working-set-size-threshold", cl::Hidden, 51*81ad6265SDimitry Andric cl::init(12500), 52fe6060f1SDimitry Andric cl::desc("The code working set size is considered large if the number of" 53fe6060f1SDimitry Andric " blocks required to reach the -profile-summary-cutoff-hot" 54fe6060f1SDimitry Andric " percentile exceeds this count.")); 55fe6060f1SDimitry Andric 56fe6060f1SDimitry Andric // The next two options override the counts derived from summary computation and 57fe6060f1SDimitry Andric // are useful for debugging purposes. 58*81ad6265SDimitry Andric cl::opt<uint64_t> ProfileSummaryHotCount( 59*81ad6265SDimitry Andric "profile-summary-hot-count", cl::ReallyHidden, 60fe6060f1SDimitry Andric cl::desc("A fixed hot count that overrides the count derived from" 61fe6060f1SDimitry Andric " profile-summary-cutoff-hot")); 62fe6060f1SDimitry Andric 63*81ad6265SDimitry Andric cl::opt<uint64_t> ProfileSummaryColdCount( 64*81ad6265SDimitry Andric "profile-summary-cold-count", cl::ReallyHidden, 65fe6060f1SDimitry Andric cl::desc("A fixed cold count that overrides the count derived from" 66fe6060f1SDimitry Andric " profile-summary-cutoff-cold")); 67fe6060f1SDimitry Andric 680b57cec5SDimitry Andric // A set of cutoff values. Each value, when divided by ProfileSummary::Scale 690b57cec5SDimitry Andric // (which is 1000000) is a desired percentile of total counts. 700b57cec5SDimitry Andric static const uint32_t DefaultCutoffsData[] = { 710b57cec5SDimitry Andric 10000, /* 1% */ 720b57cec5SDimitry Andric 100000, /* 10% */ 730b57cec5SDimitry Andric 200000, 300000, 400000, 500000, 600000, 700000, 800000, 740b57cec5SDimitry Andric 900000, 950000, 990000, 999000, 999900, 999990, 999999}; 750b57cec5SDimitry Andric const ArrayRef<uint32_t> ProfileSummaryBuilder::DefaultCutoffs = 760b57cec5SDimitry Andric DefaultCutoffsData; 770b57cec5SDimitry Andric 785ffd83dbSDimitry Andric const ProfileSummaryEntry & 79349cc55cSDimitry Andric ProfileSummaryBuilder::getEntryForPercentile(const SummaryEntryVector &DS, 805ffd83dbSDimitry Andric uint64_t Percentile) { 815ffd83dbSDimitry Andric auto It = partition_point(DS, [=](const ProfileSummaryEntry &Entry) { 825ffd83dbSDimitry Andric return Entry.Cutoff < Percentile; 835ffd83dbSDimitry Andric }); 845ffd83dbSDimitry Andric // The required percentile has to be <= one of the percentiles in the 855ffd83dbSDimitry Andric // detailed summary. 865ffd83dbSDimitry Andric if (It == DS.end()) 875ffd83dbSDimitry Andric report_fatal_error("Desired percentile exceeds the maximum cutoff"); 885ffd83dbSDimitry Andric return *It; 895ffd83dbSDimitry Andric } 905ffd83dbSDimitry Andric 910b57cec5SDimitry Andric void InstrProfSummaryBuilder::addRecord(const InstrProfRecord &R) { 920b57cec5SDimitry Andric // The first counter is not necessarily an entry count for IR 930b57cec5SDimitry Andric // instrumentation profiles. 940b57cec5SDimitry Andric // Eventually MaxFunctionCount will become obsolete and this can be 950b57cec5SDimitry Andric // removed. 960b57cec5SDimitry Andric addEntryCount(R.Counts[0]); 970b57cec5SDimitry Andric for (size_t I = 1, E = R.Counts.size(); I < E; ++I) 980b57cec5SDimitry Andric addInternalCount(R.Counts[I]); 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric // To compute the detailed summary, we consider each line containing samples as 1020b57cec5SDimitry Andric // equivalent to a block with a count in the instrumented profile. 1030b57cec5SDimitry Andric void SampleProfileSummaryBuilder::addRecord( 1040b57cec5SDimitry Andric const sampleprof::FunctionSamples &FS, bool isCallsiteSample) { 1050b57cec5SDimitry Andric if (!isCallsiteSample) { 1060b57cec5SDimitry Andric NumFunctions++; 1070b57cec5SDimitry Andric if (FS.getHeadSamples() > MaxFunctionCount) 1080b57cec5SDimitry Andric MaxFunctionCount = FS.getHeadSamples(); 109*81ad6265SDimitry Andric } else if (FS.getContext().hasAttribute( 110*81ad6265SDimitry Andric sampleprof::ContextDuplicatedIntoBase)) { 111*81ad6265SDimitry Andric // Do not recount callee samples if they are already merged into their base 112*81ad6265SDimitry Andric // profiles. This can happen to CS nested profile. 113*81ad6265SDimitry Andric return; 1140b57cec5SDimitry Andric } 115*81ad6265SDimitry Andric 116fe6060f1SDimitry Andric for (const auto &I : FS.getBodySamples()) { 117fe6060f1SDimitry Andric uint64_t Count = I.second.getSamples(); 118fe6060f1SDimitry Andric addCount(Count); 119fe6060f1SDimitry Andric } 1200b57cec5SDimitry Andric for (const auto &I : FS.getCallsiteSamples()) 1210b57cec5SDimitry Andric for (const auto &CS : I.second) 1220b57cec5SDimitry Andric addRecord(CS.second, true); 1230b57cec5SDimitry Andric } 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric // The argument to this method is a vector of cutoff percentages and the return 1260b57cec5SDimitry Andric // value is a vector of (Cutoff, MinCount, NumCounts) triplets. 1270b57cec5SDimitry Andric void ProfileSummaryBuilder::computeDetailedSummary() { 1280b57cec5SDimitry Andric if (DetailedSummaryCutoffs.empty()) 1290b57cec5SDimitry Andric return; 1300b57cec5SDimitry Andric llvm::sort(DetailedSummaryCutoffs); 1310b57cec5SDimitry Andric auto Iter = CountFrequencies.begin(); 1320b57cec5SDimitry Andric const auto End = CountFrequencies.end(); 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric uint32_t CountsSeen = 0; 1350b57cec5SDimitry Andric uint64_t CurrSum = 0, Count = 0; 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric for (const uint32_t Cutoff : DetailedSummaryCutoffs) { 1380b57cec5SDimitry Andric assert(Cutoff <= 999999); 1390b57cec5SDimitry Andric APInt Temp(128, TotalCount); 1400b57cec5SDimitry Andric APInt N(128, Cutoff); 1410b57cec5SDimitry Andric APInt D(128, ProfileSummary::Scale); 1420b57cec5SDimitry Andric Temp *= N; 1430b57cec5SDimitry Andric Temp = Temp.sdiv(D); 1440b57cec5SDimitry Andric uint64_t DesiredCount = Temp.getZExtValue(); 1450b57cec5SDimitry Andric assert(DesiredCount <= TotalCount); 1460b57cec5SDimitry Andric while (CurrSum < DesiredCount && Iter != End) { 1470b57cec5SDimitry Andric Count = Iter->first; 1480b57cec5SDimitry Andric uint32_t Freq = Iter->second; 1490b57cec5SDimitry Andric CurrSum += (Count * Freq); 1500b57cec5SDimitry Andric CountsSeen += Freq; 1510b57cec5SDimitry Andric Iter++; 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric assert(CurrSum >= DesiredCount); 1540b57cec5SDimitry Andric ProfileSummaryEntry PSE = {Cutoff, Count, CountsSeen}; 1550b57cec5SDimitry Andric DetailedSummary.push_back(PSE); 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 159349cc55cSDimitry Andric uint64_t 160349cc55cSDimitry Andric ProfileSummaryBuilder::getHotCountThreshold(const SummaryEntryVector &DS) { 161fe6060f1SDimitry Andric auto &HotEntry = 162fe6060f1SDimitry Andric ProfileSummaryBuilder::getEntryForPercentile(DS, ProfileSummaryCutoffHot); 163fe6060f1SDimitry Andric uint64_t HotCountThreshold = HotEntry.MinCount; 164fe6060f1SDimitry Andric if (ProfileSummaryHotCount.getNumOccurrences() > 0) 165fe6060f1SDimitry Andric HotCountThreshold = ProfileSummaryHotCount; 166fe6060f1SDimitry Andric return HotCountThreshold; 167fe6060f1SDimitry Andric } 168fe6060f1SDimitry Andric 169349cc55cSDimitry Andric uint64_t 170349cc55cSDimitry Andric ProfileSummaryBuilder::getColdCountThreshold(const SummaryEntryVector &DS) { 171fe6060f1SDimitry Andric auto &ColdEntry = ProfileSummaryBuilder::getEntryForPercentile( 172fe6060f1SDimitry Andric DS, ProfileSummaryCutoffCold); 173fe6060f1SDimitry Andric uint64_t ColdCountThreshold = ColdEntry.MinCount; 174fe6060f1SDimitry Andric if (ProfileSummaryColdCount.getNumOccurrences() > 0) 175fe6060f1SDimitry Andric ColdCountThreshold = ProfileSummaryColdCount; 176fe6060f1SDimitry Andric return ColdCountThreshold; 177fe6060f1SDimitry Andric } 178fe6060f1SDimitry Andric 1790b57cec5SDimitry Andric std::unique_ptr<ProfileSummary> SampleProfileSummaryBuilder::getSummary() { 1800b57cec5SDimitry Andric computeDetailedSummary(); 1818bcb0991SDimitry Andric return std::make_unique<ProfileSummary>( 1820b57cec5SDimitry Andric ProfileSummary::PSK_Sample, DetailedSummary, TotalCount, MaxCount, 0, 1830b57cec5SDimitry Andric MaxFunctionCount, NumCounts, NumFunctions); 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric 186d409305fSDimitry Andric std::unique_ptr<ProfileSummary> 187d409305fSDimitry Andric SampleProfileSummaryBuilder::computeSummaryForProfiles( 188349cc55cSDimitry Andric const SampleProfileMap &Profiles) { 189d409305fSDimitry Andric assert(NumFunctions == 0 && 190d409305fSDimitry Andric "This can only be called on an empty summary builder"); 191349cc55cSDimitry Andric sampleprof::SampleProfileMap ContextLessProfiles; 192349cc55cSDimitry Andric const sampleprof::SampleProfileMap *ProfilesToUse = &Profiles; 193d409305fSDimitry Andric // For CSSPGO, context-sensitive profile effectively split a function profile 194d409305fSDimitry Andric // into many copies each representing the CFG profile of a particular calling 195d409305fSDimitry Andric // context. That makes the count distribution looks more flat as we now have 196d409305fSDimitry Andric // more function profiles each with lower counts, which in turn leads to lower 197349cc55cSDimitry Andric // hot thresholds. To compensate for that, by default we merge context 198349cc55cSDimitry Andric // profiles before computing profile summary. 199*81ad6265SDimitry Andric if (UseContextLessSummary || (sampleprof::FunctionSamples::ProfileIsCS && 200d409305fSDimitry Andric !UseContextLessSummary.getNumOccurrences())) { 201d409305fSDimitry Andric for (const auto &I : Profiles) { 202d409305fSDimitry Andric ContextLessProfiles[I.second.getName()].merge(I.second); 203d409305fSDimitry Andric } 204d409305fSDimitry Andric ProfilesToUse = &ContextLessProfiles; 205d409305fSDimitry Andric } 206d409305fSDimitry Andric 207d409305fSDimitry Andric for (const auto &I : *ProfilesToUse) { 208d409305fSDimitry Andric const sampleprof::FunctionSamples &Profile = I.second; 209d409305fSDimitry Andric addRecord(Profile); 210d409305fSDimitry Andric } 211d409305fSDimitry Andric 212d409305fSDimitry Andric return getSummary(); 213d409305fSDimitry Andric } 214d409305fSDimitry Andric 2150b57cec5SDimitry Andric std::unique_ptr<ProfileSummary> InstrProfSummaryBuilder::getSummary() { 2160b57cec5SDimitry Andric computeDetailedSummary(); 2178bcb0991SDimitry Andric return std::make_unique<ProfileSummary>( 2180b57cec5SDimitry Andric ProfileSummary::PSK_Instr, DetailedSummary, TotalCount, MaxCount, 2190b57cec5SDimitry Andric MaxInternalBlockCount, MaxFunctionCount, NumCounts, NumFunctions); 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric void InstrProfSummaryBuilder::addEntryCount(uint64_t Count) { 2230b57cec5SDimitry Andric NumFunctions++; 224e8d8bef9SDimitry Andric 225e8d8bef9SDimitry Andric // Skip invalid count. 226e8d8bef9SDimitry Andric if (Count == (uint64_t)-1) 227e8d8bef9SDimitry Andric return; 228e8d8bef9SDimitry Andric 229e8d8bef9SDimitry Andric addCount(Count); 2300b57cec5SDimitry Andric if (Count > MaxFunctionCount) 2310b57cec5SDimitry Andric MaxFunctionCount = Count; 2320b57cec5SDimitry Andric } 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric void InstrProfSummaryBuilder::addInternalCount(uint64_t Count) { 235e8d8bef9SDimitry Andric // Skip invalid count. 236e8d8bef9SDimitry Andric if (Count == (uint64_t)-1) 237e8d8bef9SDimitry Andric return; 238e8d8bef9SDimitry Andric 2390b57cec5SDimitry Andric addCount(Count); 2400b57cec5SDimitry Andric if (Count > MaxInternalBlockCount) 2410b57cec5SDimitry Andric MaxInternalBlockCount = Count; 2420b57cec5SDimitry Andric } 243