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 29*fe6060f1SDimitry Andric // The following two parameters determine the threshold for a count to be 30*fe6060f1SDimitry Andric // considered hot/cold. These two parameters are percentile values (multiplied 31*fe6060f1SDimitry Andric // by 10000). If the counts are sorted in descending order, the minimum count to 32*fe6060f1SDimitry Andric // reach ProfileSummaryCutoffHot gives the threshold to determine a hot count. 33*fe6060f1SDimitry Andric // Similarly, the minimum count to reach ProfileSummaryCutoffCold gives the 34*fe6060f1SDimitry Andric // threshold for determining cold count (everything <= this threshold is 35*fe6060f1SDimitry Andric // considered cold). 36*fe6060f1SDimitry Andric cl::opt<int> ProfileSummaryCutoffHot( 37*fe6060f1SDimitry Andric "profile-summary-cutoff-hot", cl::Hidden, cl::init(990000), cl::ZeroOrMore, 38*fe6060f1SDimitry Andric cl::desc("A count is hot if it exceeds the minimum count to" 39*fe6060f1SDimitry Andric " reach this percentile of total counts.")); 40*fe6060f1SDimitry Andric 41*fe6060f1SDimitry Andric cl::opt<int> ProfileSummaryCutoffCold( 42*fe6060f1SDimitry Andric "profile-summary-cutoff-cold", cl::Hidden, cl::init(999999), cl::ZeroOrMore, 43*fe6060f1SDimitry Andric cl::desc("A count is cold if it is below the minimum count" 44*fe6060f1SDimitry Andric " to reach this percentile of total counts.")); 45*fe6060f1SDimitry Andric 46*fe6060f1SDimitry Andric cl::opt<unsigned> ProfileSummaryHugeWorkingSetSizeThreshold( 47*fe6060f1SDimitry Andric "profile-summary-huge-working-set-size-threshold", cl::Hidden, 48*fe6060f1SDimitry Andric cl::init(15000), cl::ZeroOrMore, 49*fe6060f1SDimitry Andric cl::desc("The code working set size is considered huge if the number of" 50*fe6060f1SDimitry Andric " blocks required to reach the -profile-summary-cutoff-hot" 51*fe6060f1SDimitry Andric " percentile exceeds this count.")); 52*fe6060f1SDimitry Andric 53*fe6060f1SDimitry Andric cl::opt<unsigned> ProfileSummaryLargeWorkingSetSizeThreshold( 54*fe6060f1SDimitry Andric "profile-summary-large-working-set-size-threshold", cl::Hidden, 55*fe6060f1SDimitry Andric cl::init(12500), cl::ZeroOrMore, 56*fe6060f1SDimitry Andric cl::desc("The code working set size is considered large if the number of" 57*fe6060f1SDimitry Andric " blocks required to reach the -profile-summary-cutoff-hot" 58*fe6060f1SDimitry Andric " percentile exceeds this count.")); 59*fe6060f1SDimitry Andric 60*fe6060f1SDimitry Andric // The next two options override the counts derived from summary computation and 61*fe6060f1SDimitry Andric // are useful for debugging purposes. 62*fe6060f1SDimitry Andric cl::opt<int> ProfileSummaryHotCount( 63*fe6060f1SDimitry Andric "profile-summary-hot-count", cl::ReallyHidden, cl::ZeroOrMore, 64*fe6060f1SDimitry Andric cl::desc("A fixed hot count that overrides the count derived from" 65*fe6060f1SDimitry Andric " profile-summary-cutoff-hot")); 66*fe6060f1SDimitry Andric 67*fe6060f1SDimitry Andric cl::opt<int> ProfileSummaryColdCount( 68*fe6060f1SDimitry Andric "profile-summary-cold-count", cl::ReallyHidden, cl::ZeroOrMore, 69*fe6060f1SDimitry Andric cl::desc("A fixed cold count that overrides the count derived from" 70*fe6060f1SDimitry Andric " profile-summary-cutoff-cold")); 71*fe6060f1SDimitry 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 & 835ffd83dbSDimitry Andric ProfileSummaryBuilder::getEntryForPercentile(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 } 114*fe6060f1SDimitry Andric for (const auto &I : FS.getBodySamples()) { 115*fe6060f1SDimitry Andric uint64_t Count = I.second.getSamples(); 116*fe6060f1SDimitry Andric addCount(Count); 117*fe6060f1SDimitry 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*fe6060f1SDimitry Andric uint64_t ProfileSummaryBuilder::getHotCountThreshold(SummaryEntryVector &DS) { 158*fe6060f1SDimitry Andric auto &HotEntry = 159*fe6060f1SDimitry Andric ProfileSummaryBuilder::getEntryForPercentile(DS, ProfileSummaryCutoffHot); 160*fe6060f1SDimitry Andric uint64_t HotCountThreshold = HotEntry.MinCount; 161*fe6060f1SDimitry Andric if (ProfileSummaryHotCount.getNumOccurrences() > 0) 162*fe6060f1SDimitry Andric HotCountThreshold = ProfileSummaryHotCount; 163*fe6060f1SDimitry Andric return HotCountThreshold; 164*fe6060f1SDimitry Andric } 165*fe6060f1SDimitry Andric 166*fe6060f1SDimitry Andric uint64_t ProfileSummaryBuilder::getColdCountThreshold(SummaryEntryVector &DS) { 167*fe6060f1SDimitry Andric auto &ColdEntry = ProfileSummaryBuilder::getEntryForPercentile( 168*fe6060f1SDimitry Andric DS, ProfileSummaryCutoffCold); 169*fe6060f1SDimitry Andric uint64_t ColdCountThreshold = ColdEntry.MinCount; 170*fe6060f1SDimitry Andric if (ProfileSummaryColdCount.getNumOccurrences() > 0) 171*fe6060f1SDimitry Andric ColdCountThreshold = ProfileSummaryColdCount; 172*fe6060f1SDimitry Andric return ColdCountThreshold; 173*fe6060f1SDimitry Andric } 174*fe6060f1SDimitry Andric 1750b57cec5SDimitry Andric std::unique_ptr<ProfileSummary> SampleProfileSummaryBuilder::getSummary() { 1760b57cec5SDimitry Andric computeDetailedSummary(); 1778bcb0991SDimitry Andric return std::make_unique<ProfileSummary>( 1780b57cec5SDimitry Andric ProfileSummary::PSK_Sample, DetailedSummary, TotalCount, MaxCount, 0, 1790b57cec5SDimitry Andric MaxFunctionCount, NumCounts, NumFunctions); 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric 182d409305fSDimitry Andric std::unique_ptr<ProfileSummary> 183d409305fSDimitry Andric SampleProfileSummaryBuilder::computeSummaryForProfiles( 184d409305fSDimitry Andric const StringMap<sampleprof::FunctionSamples> &Profiles) { 185d409305fSDimitry Andric assert(NumFunctions == 0 && 186d409305fSDimitry Andric "This can only be called on an empty summary builder"); 187d409305fSDimitry Andric StringMap<sampleprof::FunctionSamples> ContextLessProfiles; 188d409305fSDimitry Andric const StringMap<sampleprof::FunctionSamples> *ProfilesToUse = &Profiles; 189d409305fSDimitry Andric // For CSSPGO, context-sensitive profile effectively split a function profile 190d409305fSDimitry Andric // into many copies each representing the CFG profile of a particular calling 191d409305fSDimitry Andric // context. That makes the count distribution looks more flat as we now have 192d409305fSDimitry Andric // more function profiles each with lower counts, which in turn leads to lower 193d409305fSDimitry Andric // hot thresholds. To compensate for that, by defauly we merge context 194d409305fSDimitry Andric // profiles before coumputing profile summary. 195d409305fSDimitry Andric if (UseContextLessSummary || (sampleprof::FunctionSamples::ProfileIsCS && 196d409305fSDimitry Andric !UseContextLessSummary.getNumOccurrences())) { 197d409305fSDimitry Andric for (const auto &I : Profiles) { 198d409305fSDimitry Andric ContextLessProfiles[I.second.getName()].merge(I.second); 199d409305fSDimitry Andric } 200d409305fSDimitry Andric ProfilesToUse = &ContextLessProfiles; 201d409305fSDimitry Andric } 202d409305fSDimitry Andric 203d409305fSDimitry Andric for (const auto &I : *ProfilesToUse) { 204d409305fSDimitry Andric const sampleprof::FunctionSamples &Profile = I.second; 205d409305fSDimitry Andric addRecord(Profile); 206d409305fSDimitry Andric } 207d409305fSDimitry Andric 208d409305fSDimitry Andric return getSummary(); 209d409305fSDimitry Andric } 210d409305fSDimitry Andric 2110b57cec5SDimitry Andric std::unique_ptr<ProfileSummary> InstrProfSummaryBuilder::getSummary() { 2120b57cec5SDimitry Andric computeDetailedSummary(); 2138bcb0991SDimitry Andric return std::make_unique<ProfileSummary>( 2140b57cec5SDimitry Andric ProfileSummary::PSK_Instr, DetailedSummary, TotalCount, MaxCount, 2150b57cec5SDimitry Andric MaxInternalBlockCount, MaxFunctionCount, NumCounts, NumFunctions); 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric void InstrProfSummaryBuilder::addEntryCount(uint64_t Count) { 2190b57cec5SDimitry Andric NumFunctions++; 220e8d8bef9SDimitry Andric 221e8d8bef9SDimitry Andric // Skip invalid count. 222e8d8bef9SDimitry Andric if (Count == (uint64_t)-1) 223e8d8bef9SDimitry Andric return; 224e8d8bef9SDimitry Andric 225e8d8bef9SDimitry Andric addCount(Count); 2260b57cec5SDimitry Andric if (Count > MaxFunctionCount) 2270b57cec5SDimitry Andric MaxFunctionCount = Count; 2280b57cec5SDimitry Andric } 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric void InstrProfSummaryBuilder::addInternalCount(uint64_t Count) { 231e8d8bef9SDimitry Andric // Skip invalid count. 232e8d8bef9SDimitry Andric if (Count == (uint64_t)-1) 233e8d8bef9SDimitry Andric return; 234e8d8bef9SDimitry Andric 2350b57cec5SDimitry Andric addCount(Count); 2360b57cec5SDimitry Andric if (Count > MaxInternalBlockCount) 2370b57cec5SDimitry Andric MaxInternalBlockCount = Count; 2380b57cec5SDimitry Andric } 239