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 1381ad6265SDimitry 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 21bdd1243dSDimitry Andric namespace llvm { 22d409305fSDimitry Andric cl::opt<bool> UseContextLessSummary( 2381ad6265SDimitry Andric "profile-summary-contextless", cl::Hidden, 24d409305fSDimitry Andric cl::desc("Merge context profiles before calculating thresholds.")); 25d409305fSDimitry Andric 26fe6060f1SDimitry Andric // The following two parameters determine the threshold for a count to be 27fe6060f1SDimitry Andric // considered hot/cold. These two parameters are percentile values (multiplied 28fe6060f1SDimitry Andric // by 10000). If the counts are sorted in descending order, the minimum count to 29fe6060f1SDimitry Andric // reach ProfileSummaryCutoffHot gives the threshold to determine a hot count. 30fe6060f1SDimitry Andric // Similarly, the minimum count to reach ProfileSummaryCutoffCold gives the 31fe6060f1SDimitry Andric // threshold for determining cold count (everything <= this threshold is 32fe6060f1SDimitry Andric // considered cold). 33fe6060f1SDimitry Andric cl::opt<int> ProfileSummaryCutoffHot( 3481ad6265SDimitry Andric "profile-summary-cutoff-hot", cl::Hidden, cl::init(990000), 35fe6060f1SDimitry Andric cl::desc("A count is hot if it exceeds the minimum count to" 36fe6060f1SDimitry Andric " reach this percentile of total counts.")); 37fe6060f1SDimitry Andric 38fe6060f1SDimitry Andric cl::opt<int> ProfileSummaryCutoffCold( 3981ad6265SDimitry Andric "profile-summary-cutoff-cold", cl::Hidden, cl::init(999999), 40fe6060f1SDimitry Andric cl::desc("A count is cold if it is below the minimum count" 41fe6060f1SDimitry Andric " to reach this percentile of total counts.")); 42fe6060f1SDimitry Andric 43fe6060f1SDimitry Andric cl::opt<unsigned> ProfileSummaryHugeWorkingSetSizeThreshold( 44fe6060f1SDimitry Andric "profile-summary-huge-working-set-size-threshold", cl::Hidden, 4581ad6265SDimitry Andric cl::init(15000), 46fe6060f1SDimitry Andric cl::desc("The code working set size is considered huge if the number of" 47fe6060f1SDimitry Andric " blocks required to reach the -profile-summary-cutoff-hot" 48fe6060f1SDimitry Andric " percentile exceeds this count.")); 49fe6060f1SDimitry Andric 50fe6060f1SDimitry Andric cl::opt<unsigned> ProfileSummaryLargeWorkingSetSizeThreshold( 51fe6060f1SDimitry Andric "profile-summary-large-working-set-size-threshold", cl::Hidden, 5281ad6265SDimitry Andric cl::init(12500), 53fe6060f1SDimitry Andric cl::desc("The code working set size is considered large if the number of" 54fe6060f1SDimitry Andric " blocks required to reach the -profile-summary-cutoff-hot" 55fe6060f1SDimitry Andric " percentile exceeds this count.")); 56fe6060f1SDimitry Andric 57fe6060f1SDimitry Andric // The next two options override the counts derived from summary computation and 58fe6060f1SDimitry Andric // are useful for debugging purposes. 5981ad6265SDimitry Andric cl::opt<uint64_t> ProfileSummaryHotCount( 6081ad6265SDimitry Andric "profile-summary-hot-count", cl::ReallyHidden, 61fe6060f1SDimitry Andric cl::desc("A fixed hot count that overrides the count derived from" 62fe6060f1SDimitry Andric " profile-summary-cutoff-hot")); 63fe6060f1SDimitry Andric 6481ad6265SDimitry Andric cl::opt<uint64_t> ProfileSummaryColdCount( 6581ad6265SDimitry Andric "profile-summary-cold-count", cl::ReallyHidden, 66fe6060f1SDimitry Andric cl::desc("A fixed cold count that overrides the count derived from" 67fe6060f1SDimitry Andric " profile-summary-cutoff-cold")); 68bdd1243dSDimitry Andric } // namespace llvm 69fe6060f1SDimitry Andric 700b57cec5SDimitry Andric // A set of cutoff values. Each value, when divided by ProfileSummary::Scale 710b57cec5SDimitry Andric // (which is 1000000) is a desired percentile of total counts. 720b57cec5SDimitry Andric static const uint32_t DefaultCutoffsData[] = { 730b57cec5SDimitry Andric 10000, /* 1% */ 740b57cec5SDimitry Andric 100000, /* 10% */ 750b57cec5SDimitry Andric 200000, 300000, 400000, 500000, 600000, 700000, 800000, 760b57cec5SDimitry Andric 900000, 950000, 990000, 999000, 999900, 999990, 999999}; 770b57cec5SDimitry Andric const ArrayRef<uint32_t> ProfileSummaryBuilder::DefaultCutoffs = 780b57cec5SDimitry Andric DefaultCutoffsData; 790b57cec5SDimitry Andric 805ffd83dbSDimitry Andric const ProfileSummaryEntry & 81349cc55cSDimitry Andric ProfileSummaryBuilder::getEntryForPercentile(const SummaryEntryVector &DS, 825ffd83dbSDimitry Andric uint64_t Percentile) { 835ffd83dbSDimitry Andric auto It = partition_point(DS, [=](const ProfileSummaryEntry &Entry) { 845ffd83dbSDimitry Andric return Entry.Cutoff < Percentile; 855ffd83dbSDimitry Andric }); 865ffd83dbSDimitry Andric // The required percentile has to be <= one of the percentiles in the 875ffd83dbSDimitry Andric // detailed summary. 885ffd83dbSDimitry Andric if (It == DS.end()) 895ffd83dbSDimitry Andric report_fatal_error("Desired percentile exceeds the maximum cutoff"); 905ffd83dbSDimitry Andric return *It; 915ffd83dbSDimitry Andric } 925ffd83dbSDimitry Andric 930b57cec5SDimitry Andric void InstrProfSummaryBuilder::addRecord(const InstrProfRecord &R) { 940b57cec5SDimitry Andric // The first counter is not necessarily an entry count for IR 950b57cec5SDimitry Andric // instrumentation profiles. 960b57cec5SDimitry Andric // Eventually MaxFunctionCount will become obsolete and this can be 970b57cec5SDimitry Andric // removed. 98bdd1243dSDimitry Andric 99bdd1243dSDimitry Andric if (R.getCountPseudoKind() != InstrProfRecord::NotPseudo) 100bdd1243dSDimitry Andric return; 101bdd1243dSDimitry Andric 1020b57cec5SDimitry Andric addEntryCount(R.Counts[0]); 1030b57cec5SDimitry Andric for (size_t I = 1, E = R.Counts.size(); I < E; ++I) 1040b57cec5SDimitry Andric addInternalCount(R.Counts[I]); 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric // To compute the detailed summary, we consider each line containing samples as 1080b57cec5SDimitry Andric // equivalent to a block with a count in the instrumented profile. 1090b57cec5SDimitry Andric void SampleProfileSummaryBuilder::addRecord( 1100b57cec5SDimitry Andric const sampleprof::FunctionSamples &FS, bool isCallsiteSample) { 1110b57cec5SDimitry Andric if (!isCallsiteSample) { 1120b57cec5SDimitry Andric NumFunctions++; 1130b57cec5SDimitry Andric if (FS.getHeadSamples() > MaxFunctionCount) 1140b57cec5SDimitry Andric MaxFunctionCount = FS.getHeadSamples(); 11581ad6265SDimitry Andric } else if (FS.getContext().hasAttribute( 11681ad6265SDimitry Andric sampleprof::ContextDuplicatedIntoBase)) { 11781ad6265SDimitry Andric // Do not recount callee samples if they are already merged into their base 11881ad6265SDimitry Andric // profiles. This can happen to CS nested profile. 11981ad6265SDimitry Andric return; 1200b57cec5SDimitry Andric } 12181ad6265SDimitry Andric 122fe6060f1SDimitry Andric for (const auto &I : FS.getBodySamples()) { 123fe6060f1SDimitry Andric uint64_t Count = I.second.getSamples(); 124fe6060f1SDimitry Andric addCount(Count); 125fe6060f1SDimitry Andric } 1260b57cec5SDimitry Andric for (const auto &I : FS.getCallsiteSamples()) 1270b57cec5SDimitry Andric for (const auto &CS : I.second) 1280b57cec5SDimitry Andric addRecord(CS.second, true); 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric // The argument to this method is a vector of cutoff percentages and the return 1320b57cec5SDimitry Andric // value is a vector of (Cutoff, MinCount, NumCounts) triplets. 1330b57cec5SDimitry Andric void ProfileSummaryBuilder::computeDetailedSummary() { 1340b57cec5SDimitry Andric if (DetailedSummaryCutoffs.empty()) 1350b57cec5SDimitry Andric return; 1360b57cec5SDimitry Andric llvm::sort(DetailedSummaryCutoffs); 1370b57cec5SDimitry Andric auto Iter = CountFrequencies.begin(); 1380b57cec5SDimitry Andric const auto End = CountFrequencies.end(); 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric uint32_t CountsSeen = 0; 1410b57cec5SDimitry Andric uint64_t CurrSum = 0, Count = 0; 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric for (const uint32_t Cutoff : DetailedSummaryCutoffs) { 1440b57cec5SDimitry Andric assert(Cutoff <= 999999); 1450b57cec5SDimitry Andric APInt Temp(128, TotalCount); 1460b57cec5SDimitry Andric APInt N(128, Cutoff); 1470b57cec5SDimitry Andric APInt D(128, ProfileSummary::Scale); 1480b57cec5SDimitry Andric Temp *= N; 1490b57cec5SDimitry Andric Temp = Temp.sdiv(D); 1500b57cec5SDimitry Andric uint64_t DesiredCount = Temp.getZExtValue(); 1510b57cec5SDimitry Andric assert(DesiredCount <= TotalCount); 1520b57cec5SDimitry Andric while (CurrSum < DesiredCount && Iter != End) { 1530b57cec5SDimitry Andric Count = Iter->first; 1540b57cec5SDimitry Andric uint32_t Freq = Iter->second; 1550b57cec5SDimitry Andric CurrSum += (Count * Freq); 1560b57cec5SDimitry Andric CountsSeen += Freq; 1570b57cec5SDimitry Andric Iter++; 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric assert(CurrSum >= DesiredCount); 1600b57cec5SDimitry Andric ProfileSummaryEntry PSE = {Cutoff, Count, CountsSeen}; 1610b57cec5SDimitry Andric DetailedSummary.push_back(PSE); 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric 165349cc55cSDimitry Andric uint64_t 166349cc55cSDimitry Andric ProfileSummaryBuilder::getHotCountThreshold(const SummaryEntryVector &DS) { 167fe6060f1SDimitry Andric auto &HotEntry = 168fe6060f1SDimitry Andric ProfileSummaryBuilder::getEntryForPercentile(DS, ProfileSummaryCutoffHot); 169fe6060f1SDimitry Andric uint64_t HotCountThreshold = HotEntry.MinCount; 170fe6060f1SDimitry Andric if (ProfileSummaryHotCount.getNumOccurrences() > 0) 171fe6060f1SDimitry Andric HotCountThreshold = ProfileSummaryHotCount; 172fe6060f1SDimitry Andric return HotCountThreshold; 173fe6060f1SDimitry Andric } 174fe6060f1SDimitry Andric 175349cc55cSDimitry Andric uint64_t 176349cc55cSDimitry Andric ProfileSummaryBuilder::getColdCountThreshold(const SummaryEntryVector &DS) { 177fe6060f1SDimitry Andric auto &ColdEntry = ProfileSummaryBuilder::getEntryForPercentile( 178fe6060f1SDimitry Andric DS, ProfileSummaryCutoffCold); 179fe6060f1SDimitry Andric uint64_t ColdCountThreshold = ColdEntry.MinCount; 180fe6060f1SDimitry Andric if (ProfileSummaryColdCount.getNumOccurrences() > 0) 181fe6060f1SDimitry Andric ColdCountThreshold = ProfileSummaryColdCount; 182fe6060f1SDimitry Andric return ColdCountThreshold; 183fe6060f1SDimitry Andric } 184fe6060f1SDimitry Andric 1850b57cec5SDimitry Andric std::unique_ptr<ProfileSummary> SampleProfileSummaryBuilder::getSummary() { 1860b57cec5SDimitry Andric computeDetailedSummary(); 1878bcb0991SDimitry Andric return std::make_unique<ProfileSummary>( 1880b57cec5SDimitry Andric ProfileSummary::PSK_Sample, DetailedSummary, TotalCount, MaxCount, 0, 1890b57cec5SDimitry Andric MaxFunctionCount, NumCounts, NumFunctions); 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric 192d409305fSDimitry Andric std::unique_ptr<ProfileSummary> 193d409305fSDimitry Andric SampleProfileSummaryBuilder::computeSummaryForProfiles( 194349cc55cSDimitry Andric const SampleProfileMap &Profiles) { 195d409305fSDimitry Andric assert(NumFunctions == 0 && 196d409305fSDimitry Andric "This can only be called on an empty summary builder"); 197349cc55cSDimitry Andric sampleprof::SampleProfileMap ContextLessProfiles; 198349cc55cSDimitry Andric const sampleprof::SampleProfileMap *ProfilesToUse = &Profiles; 199d409305fSDimitry Andric // For CSSPGO, context-sensitive profile effectively split a function profile 200d409305fSDimitry Andric // into many copies each representing the CFG profile of a particular calling 201d409305fSDimitry Andric // context. That makes the count distribution looks more flat as we now have 202d409305fSDimitry Andric // more function profiles each with lower counts, which in turn leads to lower 203349cc55cSDimitry Andric // hot thresholds. To compensate for that, by default we merge context 204349cc55cSDimitry Andric // profiles before computing profile summary. 20581ad6265SDimitry Andric if (UseContextLessSummary || (sampleprof::FunctionSamples::ProfileIsCS && 206d409305fSDimitry Andric !UseContextLessSummary.getNumOccurrences())) { 207*5f757f3fSDimitry Andric ProfileConverter::flattenProfile(Profiles, ContextLessProfiles, true); 208d409305fSDimitry Andric ProfilesToUse = &ContextLessProfiles; 209d409305fSDimitry Andric } 210d409305fSDimitry Andric 211d409305fSDimitry Andric for (const auto &I : *ProfilesToUse) { 212d409305fSDimitry Andric const sampleprof::FunctionSamples &Profile = I.second; 213d409305fSDimitry Andric addRecord(Profile); 214d409305fSDimitry Andric } 215d409305fSDimitry Andric 216d409305fSDimitry Andric return getSummary(); 217d409305fSDimitry Andric } 218d409305fSDimitry Andric 2190b57cec5SDimitry Andric std::unique_ptr<ProfileSummary> InstrProfSummaryBuilder::getSummary() { 2200b57cec5SDimitry Andric computeDetailedSummary(); 2218bcb0991SDimitry Andric return std::make_unique<ProfileSummary>( 2220b57cec5SDimitry Andric ProfileSummary::PSK_Instr, DetailedSummary, TotalCount, MaxCount, 2230b57cec5SDimitry Andric MaxInternalBlockCount, MaxFunctionCount, NumCounts, NumFunctions); 2240b57cec5SDimitry Andric } 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric void InstrProfSummaryBuilder::addEntryCount(uint64_t Count) { 227bdd1243dSDimitry Andric assert(Count <= getInstrMaxCountValue() && 228bdd1243dSDimitry Andric "Count value should be less than the max count value."); 2290b57cec5SDimitry Andric NumFunctions++; 230e8d8bef9SDimitry Andric addCount(Count); 2310b57cec5SDimitry Andric if (Count > MaxFunctionCount) 2320b57cec5SDimitry Andric MaxFunctionCount = Count; 2330b57cec5SDimitry Andric } 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric void InstrProfSummaryBuilder::addInternalCount(uint64_t Count) { 236bdd1243dSDimitry Andric assert(Count <= getInstrMaxCountValue() && 237bdd1243dSDimitry Andric "Count value should be less than the max count value."); 2380b57cec5SDimitry Andric addCount(Count); 2390b57cec5SDimitry Andric if (Count > MaxInternalBlockCount) 2400b57cec5SDimitry Andric MaxInternalBlockCount = Count; 2410b57cec5SDimitry Andric } 242