1*7397905aSRong Xu //===- SampleProfileLoaderBaseUtil.cpp - Profile loader Util func ---------===// 2*7397905aSRong Xu // 3*7397905aSRong Xu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*7397905aSRong Xu // See https://llvm.org/LICENSE.txt for license information. 5*7397905aSRong Xu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*7397905aSRong Xu // 7*7397905aSRong Xu //===----------------------------------------------------------------------===// 8*7397905aSRong Xu // 9*7397905aSRong Xu // This file implements the SampleProfileLoader base utility functions. 10*7397905aSRong Xu // 11*7397905aSRong Xu //===----------------------------------------------------------------------===// 12*7397905aSRong Xu 13*7397905aSRong Xu #include "llvm/Transforms/Utils/SampleProfileLoaderBaseUtil.h" 14*7397905aSRong Xu 15*7397905aSRong Xu namespace llvm { 16*7397905aSRong Xu 17*7397905aSRong Xu cl::opt<unsigned> SampleProfileMaxPropagateIterations( 18*7397905aSRong Xu "sample-profile-max-propagate-iterations", cl::init(100), 19*7397905aSRong Xu cl::desc("Maximum number of iterations to go through when propagating " 20*7397905aSRong Xu "sample block/edge weights through the CFG.")); 21*7397905aSRong Xu 22*7397905aSRong Xu cl::opt<unsigned> SampleProfileRecordCoverage( 23*7397905aSRong Xu "sample-profile-check-record-coverage", cl::init(0), cl::value_desc("N"), 24*7397905aSRong Xu cl::desc("Emit a warning if less than N% of records in the input profile " 25*7397905aSRong Xu "are matched to the IR.")); 26*7397905aSRong Xu 27*7397905aSRong Xu cl::opt<unsigned> SampleProfileSampleCoverage( 28*7397905aSRong Xu "sample-profile-check-sample-coverage", cl::init(0), cl::value_desc("N"), 29*7397905aSRong Xu cl::desc("Emit a warning if less than N% of samples in the input profile " 30*7397905aSRong Xu "are matched to the IR.")); 31*7397905aSRong Xu 32*7397905aSRong Xu cl::opt<bool> NoWarnSampleUnused( 33*7397905aSRong Xu "no-warn-sample-unused", cl::init(false), cl::Hidden, 34*7397905aSRong Xu cl::desc("Use this option to turn off/on warnings about function with " 35*7397905aSRong Xu "samples but without debug information to use those samples. ")); 36*7397905aSRong Xu 37*7397905aSRong Xu namespace sampleprofutil { 38*7397905aSRong Xu 39*7397905aSRong Xu /// Return true if the given callsite is hot wrt to hot cutoff threshold. 40*7397905aSRong Xu /// 41*7397905aSRong Xu /// Functions that were inlined in the original binary will be represented 42*7397905aSRong Xu /// in the inline stack in the sample profile. If the profile shows that 43*7397905aSRong Xu /// the original inline decision was "good" (i.e., the callsite is executed 44*7397905aSRong Xu /// frequently), then we will recreate the inline decision and apply the 45*7397905aSRong Xu /// profile from the inlined callsite. 46*7397905aSRong Xu /// 47*7397905aSRong Xu /// To decide whether an inlined callsite is hot, we compare the callsite 48*7397905aSRong Xu /// sample count with the hot cutoff computed by ProfileSummaryInfo, it is 49*7397905aSRong Xu /// regarded as hot if the count is above the cutoff value. 50*7397905aSRong Xu /// 51*7397905aSRong Xu /// When ProfileAccurateForSymsInList is enabled and profile symbol list 52*7397905aSRong Xu /// is present, functions in the profile symbol list but without profile will 53*7397905aSRong Xu /// be regarded as cold and much less inlining will happen in CGSCC inlining 54*7397905aSRong Xu /// pass, so we tend to lower the hot criteria here to allow more early 55*7397905aSRong Xu /// inlining to happen for warm callsites and it is helpful for performance. 56*7397905aSRong Xu bool callsiteIsHot(const FunctionSamples *CallsiteFS, ProfileSummaryInfo *PSI, 57*7397905aSRong Xu bool ProfAccForSymsInList) { 58*7397905aSRong Xu if (!CallsiteFS) 59*7397905aSRong Xu return false; // The callsite was not inlined in the original binary. 60*7397905aSRong Xu 61*7397905aSRong Xu assert(PSI && "PSI is expected to be non null"); 62*7397905aSRong Xu uint64_t CallsiteTotalSamples = CallsiteFS->getTotalSamples(); 63*7397905aSRong Xu if (ProfAccForSymsInList) 64*7397905aSRong Xu return !PSI->isColdCount(CallsiteTotalSamples); 65*7397905aSRong Xu else 66*7397905aSRong Xu return PSI->isHotCount(CallsiteTotalSamples); 67*7397905aSRong Xu } 68*7397905aSRong Xu 69*7397905aSRong Xu /// Mark as used the sample record for the given function samples at 70*7397905aSRong Xu /// (LineOffset, Discriminator). 71*7397905aSRong Xu /// 72*7397905aSRong Xu /// \returns true if this is the first time we mark the given record. 73*7397905aSRong Xu bool SampleCoverageTracker::markSamplesUsed(const FunctionSamples *FS, 74*7397905aSRong Xu uint32_t LineOffset, 75*7397905aSRong Xu uint32_t Discriminator, 76*7397905aSRong Xu uint64_t Samples) { 77*7397905aSRong Xu LineLocation Loc(LineOffset, Discriminator); 78*7397905aSRong Xu unsigned &Count = SampleCoverage[FS][Loc]; 79*7397905aSRong Xu bool FirstTime = (++Count == 1); 80*7397905aSRong Xu if (FirstTime) 81*7397905aSRong Xu TotalUsedSamples += Samples; 82*7397905aSRong Xu return FirstTime; 83*7397905aSRong Xu } 84*7397905aSRong Xu 85*7397905aSRong Xu /// Return the number of sample records that were applied from this profile. 86*7397905aSRong Xu /// 87*7397905aSRong Xu /// This count does not include records from cold inlined callsites. 88*7397905aSRong Xu unsigned 89*7397905aSRong Xu SampleCoverageTracker::countUsedRecords(const FunctionSamples *FS, 90*7397905aSRong Xu ProfileSummaryInfo *PSI) const { 91*7397905aSRong Xu auto I = SampleCoverage.find(FS); 92*7397905aSRong Xu 93*7397905aSRong Xu // The size of the coverage map for FS represents the number of records 94*7397905aSRong Xu // that were marked used at least once. 95*7397905aSRong Xu unsigned Count = (I != SampleCoverage.end()) ? I->second.size() : 0; 96*7397905aSRong Xu 97*7397905aSRong Xu // If there are inlined callsites in this function, count the samples found 98*7397905aSRong Xu // in the respective bodies. However, do not bother counting callees with 0 99*7397905aSRong Xu // total samples, these are callees that were never invoked at runtime. 100*7397905aSRong Xu for (const auto &I : FS->getCallsiteSamples()) 101*7397905aSRong Xu for (const auto &J : I.second) { 102*7397905aSRong Xu const FunctionSamples *CalleeSamples = &J.second; 103*7397905aSRong Xu if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList)) 104*7397905aSRong Xu Count += countUsedRecords(CalleeSamples, PSI); 105*7397905aSRong Xu } 106*7397905aSRong Xu 107*7397905aSRong Xu return Count; 108*7397905aSRong Xu } 109*7397905aSRong Xu 110*7397905aSRong Xu /// Return the number of sample records in the body of this profile. 111*7397905aSRong Xu /// 112*7397905aSRong Xu /// This count does not include records from cold inlined callsites. 113*7397905aSRong Xu unsigned 114*7397905aSRong Xu SampleCoverageTracker::countBodyRecords(const FunctionSamples *FS, 115*7397905aSRong Xu ProfileSummaryInfo *PSI) const { 116*7397905aSRong Xu unsigned Count = FS->getBodySamples().size(); 117*7397905aSRong Xu 118*7397905aSRong Xu // Only count records in hot callsites. 119*7397905aSRong Xu for (const auto &I : FS->getCallsiteSamples()) 120*7397905aSRong Xu for (const auto &J : I.second) { 121*7397905aSRong Xu const FunctionSamples *CalleeSamples = &J.second; 122*7397905aSRong Xu if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList)) 123*7397905aSRong Xu Count += countBodyRecords(CalleeSamples, PSI); 124*7397905aSRong Xu } 125*7397905aSRong Xu 126*7397905aSRong Xu return Count; 127*7397905aSRong Xu } 128*7397905aSRong Xu 129*7397905aSRong Xu /// Return the number of samples collected in the body of this profile. 130*7397905aSRong Xu /// 131*7397905aSRong Xu /// This count does not include samples from cold inlined callsites. 132*7397905aSRong Xu uint64_t 133*7397905aSRong Xu SampleCoverageTracker::countBodySamples(const FunctionSamples *FS, 134*7397905aSRong Xu ProfileSummaryInfo *PSI) const { 135*7397905aSRong Xu uint64_t Total = 0; 136*7397905aSRong Xu for (const auto &I : FS->getBodySamples()) 137*7397905aSRong Xu Total += I.second.getSamples(); 138*7397905aSRong Xu 139*7397905aSRong Xu // Only count samples in hot callsites. 140*7397905aSRong Xu for (const auto &I : FS->getCallsiteSamples()) 141*7397905aSRong Xu for (const auto &J : I.second) { 142*7397905aSRong Xu const FunctionSamples *CalleeSamples = &J.second; 143*7397905aSRong Xu if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList)) 144*7397905aSRong Xu Total += countBodySamples(CalleeSamples, PSI); 145*7397905aSRong Xu } 146*7397905aSRong Xu 147*7397905aSRong Xu return Total; 148*7397905aSRong Xu } 149*7397905aSRong Xu 150*7397905aSRong Xu /// Return the fraction of sample records used in this profile. 151*7397905aSRong Xu /// 152*7397905aSRong Xu /// The returned value is an unsigned integer in the range 0-100 indicating 153*7397905aSRong Xu /// the percentage of sample records that were used while applying this 154*7397905aSRong Xu /// profile to the associated function. 155*7397905aSRong Xu unsigned SampleCoverageTracker::computeCoverage(unsigned Used, 156*7397905aSRong Xu unsigned Total) const { 157*7397905aSRong Xu assert(Used <= Total && 158*7397905aSRong Xu "number of used records cannot exceed the total number of records"); 159*7397905aSRong Xu return Total > 0 ? Used * 100 / Total : 100; 160*7397905aSRong Xu } 161*7397905aSRong Xu 162*7397905aSRong Xu } // end of namespace sampleprofutil 163*7397905aSRong Xu } // end of namespace llvm 164