17397905aSRong Xu //===- SampleProfileLoaderBaseUtil.cpp - Profile loader Util func ---------===// 27397905aSRong Xu // 37397905aSRong Xu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 47397905aSRong Xu // See https://llvm.org/LICENSE.txt for license information. 57397905aSRong Xu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 67397905aSRong Xu // 77397905aSRong Xu //===----------------------------------------------------------------------===// 87397905aSRong Xu // 97397905aSRong Xu // This file implements the SampleProfileLoader base utility functions. 107397905aSRong Xu // 117397905aSRong Xu //===----------------------------------------------------------------------===// 127397905aSRong Xu 137397905aSRong Xu #include "llvm/Transforms/Utils/SampleProfileLoaderBaseUtil.h" 14a494ae43Sserge-sans-paille #include "llvm/Analysis/ProfileSummaryInfo.h" 15a494ae43Sserge-sans-paille #include "llvm/IR/Constants.h" 16a494ae43Sserge-sans-paille #include "llvm/IR/Module.h" 17a494ae43Sserge-sans-paille #include "llvm/Transforms/Utils/ModuleUtils.h" 187397905aSRong Xu 197397905aSRong Xu namespace llvm { 207397905aSRong Xu 217397905aSRong Xu cl::opt<unsigned> SampleProfileMaxPropagateIterations( 227397905aSRong Xu "sample-profile-max-propagate-iterations", cl::init(100), 237397905aSRong Xu cl::desc("Maximum number of iterations to go through when propagating " 247397905aSRong Xu "sample block/edge weights through the CFG.")); 257397905aSRong Xu 267397905aSRong Xu cl::opt<unsigned> SampleProfileRecordCoverage( 277397905aSRong Xu "sample-profile-check-record-coverage", cl::init(0), cl::value_desc("N"), 287397905aSRong Xu cl::desc("Emit a warning if less than N% of records in the input profile " 297397905aSRong Xu "are matched to the IR.")); 307397905aSRong Xu 317397905aSRong Xu cl::opt<unsigned> SampleProfileSampleCoverage( 327397905aSRong Xu "sample-profile-check-sample-coverage", cl::init(0), cl::value_desc("N"), 337397905aSRong Xu cl::desc("Emit a warning if less than N% of samples in the input profile " 347397905aSRong Xu "are matched to the IR.")); 357397905aSRong Xu 367397905aSRong Xu cl::opt<bool> NoWarnSampleUnused( 377397905aSRong Xu "no-warn-sample-unused", cl::init(false), cl::Hidden, 387397905aSRong Xu cl::desc("Use this option to turn off/on warnings about function with " 397397905aSRong Xu "samples but without debug information to use those samples. ")); 407397905aSRong Xu 417cc2493dSspupyrev cl::opt<bool> SampleProfileUseProfi( 427cc2493dSspupyrev "sample-profile-use-profi", cl::init(false), cl::Hidden, cl::ZeroOrMore, 437cc2493dSspupyrev cl::desc("Use profi to infer block and edge counts.")); 447cc2493dSspupyrev 45*81aedab7Sspupyrev cl::opt<bool> SampleProfileInferEntryCount( 46*81aedab7Sspupyrev "sample-profile-infer-entry-count", cl::init(true), cl::Hidden, 47*81aedab7Sspupyrev cl::ZeroOrMore, cl::desc("Use profi to infer function entry count.")); 48*81aedab7Sspupyrev 497397905aSRong Xu namespace sampleprofutil { 507397905aSRong Xu 517397905aSRong Xu /// Return true if the given callsite is hot wrt to hot cutoff threshold. 527397905aSRong Xu /// 537397905aSRong Xu /// Functions that were inlined in the original binary will be represented 547397905aSRong Xu /// in the inline stack in the sample profile. If the profile shows that 557397905aSRong Xu /// the original inline decision was "good" (i.e., the callsite is executed 567397905aSRong Xu /// frequently), then we will recreate the inline decision and apply the 577397905aSRong Xu /// profile from the inlined callsite. 587397905aSRong Xu /// 597397905aSRong Xu /// To decide whether an inlined callsite is hot, we compare the callsite 607397905aSRong Xu /// sample count with the hot cutoff computed by ProfileSummaryInfo, it is 617397905aSRong Xu /// regarded as hot if the count is above the cutoff value. 627397905aSRong Xu /// 637397905aSRong Xu /// When ProfileAccurateForSymsInList is enabled and profile symbol list 647397905aSRong Xu /// is present, functions in the profile symbol list but without profile will 657397905aSRong Xu /// be regarded as cold and much less inlining will happen in CGSCC inlining 667397905aSRong Xu /// pass, so we tend to lower the hot criteria here to allow more early 677397905aSRong Xu /// inlining to happen for warm callsites and it is helpful for performance. 687397905aSRong Xu bool callsiteIsHot(const FunctionSamples *CallsiteFS, ProfileSummaryInfo *PSI, 697397905aSRong Xu bool ProfAccForSymsInList) { 707397905aSRong Xu if (!CallsiteFS) 717397905aSRong Xu return false; // The callsite was not inlined in the original binary. 727397905aSRong Xu 737397905aSRong Xu assert(PSI && "PSI is expected to be non null"); 747397905aSRong Xu uint64_t CallsiteTotalSamples = CallsiteFS->getTotalSamples(); 757397905aSRong Xu if (ProfAccForSymsInList) 767397905aSRong Xu return !PSI->isColdCount(CallsiteTotalSamples); 777397905aSRong Xu else 787397905aSRong Xu return PSI->isHotCount(CallsiteTotalSamples); 797397905aSRong Xu } 807397905aSRong Xu 817397905aSRong Xu /// Mark as used the sample record for the given function samples at 827397905aSRong Xu /// (LineOffset, Discriminator). 837397905aSRong Xu /// 847397905aSRong Xu /// \returns true if this is the first time we mark the given record. 857397905aSRong Xu bool SampleCoverageTracker::markSamplesUsed(const FunctionSamples *FS, 867397905aSRong Xu uint32_t LineOffset, 877397905aSRong Xu uint32_t Discriminator, 887397905aSRong Xu uint64_t Samples) { 897397905aSRong Xu LineLocation Loc(LineOffset, Discriminator); 907397905aSRong Xu unsigned &Count = SampleCoverage[FS][Loc]; 917397905aSRong Xu bool FirstTime = (++Count == 1); 927397905aSRong Xu if (FirstTime) 937397905aSRong Xu TotalUsedSamples += Samples; 947397905aSRong Xu return FirstTime; 957397905aSRong Xu } 967397905aSRong Xu 977397905aSRong Xu /// Return the number of sample records that were applied from this profile. 987397905aSRong Xu /// 997397905aSRong Xu /// This count does not include records from cold inlined callsites. 1007397905aSRong Xu unsigned 1017397905aSRong Xu SampleCoverageTracker::countUsedRecords(const FunctionSamples *FS, 1027397905aSRong Xu ProfileSummaryInfo *PSI) const { 1037397905aSRong Xu auto I = SampleCoverage.find(FS); 1047397905aSRong Xu 1057397905aSRong Xu // The size of the coverage map for FS represents the number of records 1067397905aSRong Xu // that were marked used at least once. 1077397905aSRong Xu unsigned Count = (I != SampleCoverage.end()) ? I->second.size() : 0; 1087397905aSRong Xu 1097397905aSRong Xu // If there are inlined callsites in this function, count the samples found 1107397905aSRong Xu // in the respective bodies. However, do not bother counting callees with 0 1117397905aSRong Xu // total samples, these are callees that were never invoked at runtime. 1127397905aSRong Xu for (const auto &I : FS->getCallsiteSamples()) 1137397905aSRong Xu for (const auto &J : I.second) { 1147397905aSRong Xu const FunctionSamples *CalleeSamples = &J.second; 1157397905aSRong Xu if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList)) 1167397905aSRong Xu Count += countUsedRecords(CalleeSamples, PSI); 1177397905aSRong Xu } 1187397905aSRong Xu 1197397905aSRong Xu return Count; 1207397905aSRong Xu } 1217397905aSRong Xu 1227397905aSRong Xu /// Return the number of sample records in the body of this profile. 1237397905aSRong Xu /// 1247397905aSRong Xu /// This count does not include records from cold inlined callsites. 1257397905aSRong Xu unsigned 1267397905aSRong Xu SampleCoverageTracker::countBodyRecords(const FunctionSamples *FS, 1277397905aSRong Xu ProfileSummaryInfo *PSI) const { 1287397905aSRong Xu unsigned Count = FS->getBodySamples().size(); 1297397905aSRong Xu 1307397905aSRong Xu // Only count records in hot callsites. 1317397905aSRong Xu for (const auto &I : FS->getCallsiteSamples()) 1327397905aSRong Xu for (const auto &J : I.second) { 1337397905aSRong Xu const FunctionSamples *CalleeSamples = &J.second; 1347397905aSRong Xu if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList)) 1357397905aSRong Xu Count += countBodyRecords(CalleeSamples, PSI); 1367397905aSRong Xu } 1377397905aSRong Xu 1387397905aSRong Xu return Count; 1397397905aSRong Xu } 1407397905aSRong Xu 1417397905aSRong Xu /// Return the number of samples collected in the body of this profile. 1427397905aSRong Xu /// 1437397905aSRong Xu /// This count does not include samples from cold inlined callsites. 1447397905aSRong Xu uint64_t 1457397905aSRong Xu SampleCoverageTracker::countBodySamples(const FunctionSamples *FS, 1467397905aSRong Xu ProfileSummaryInfo *PSI) const { 1477397905aSRong Xu uint64_t Total = 0; 1487397905aSRong Xu for (const auto &I : FS->getBodySamples()) 1497397905aSRong Xu Total += I.second.getSamples(); 1507397905aSRong Xu 1517397905aSRong Xu // Only count samples in hot callsites. 1527397905aSRong Xu for (const auto &I : FS->getCallsiteSamples()) 1537397905aSRong Xu for (const auto &J : I.second) { 1547397905aSRong Xu const FunctionSamples *CalleeSamples = &J.second; 1557397905aSRong Xu if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList)) 1567397905aSRong Xu Total += countBodySamples(CalleeSamples, PSI); 1577397905aSRong Xu } 1587397905aSRong Xu 1597397905aSRong Xu return Total; 1607397905aSRong Xu } 1617397905aSRong Xu 1627397905aSRong Xu /// Return the fraction of sample records used in this profile. 1637397905aSRong Xu /// 1647397905aSRong Xu /// The returned value is an unsigned integer in the range 0-100 indicating 1657397905aSRong Xu /// the percentage of sample records that were used while applying this 1667397905aSRong Xu /// profile to the associated function. 1677397905aSRong Xu unsigned SampleCoverageTracker::computeCoverage(unsigned Used, 1687397905aSRong Xu unsigned Total) const { 1697397905aSRong Xu assert(Used <= Total && 1707397905aSRong Xu "number of used records cannot exceed the total number of records"); 1717397905aSRong Xu return Total > 0 ? Used * 100 / Total : 100; 1727397905aSRong Xu } 1737397905aSRong Xu 17482a0bb1aSRong Xu /// Create a global variable to flag FSDiscriminators are used. 17582a0bb1aSRong Xu void createFSDiscriminatorVariable(Module *M) { 17682a0bb1aSRong Xu const char *FSDiscriminatorVar = "__llvm_fs_discriminator__"; 17782a0bb1aSRong Xu if (M->getGlobalVariable(FSDiscriminatorVar)) 17882a0bb1aSRong Xu return; 17982a0bb1aSRong Xu 18082a0bb1aSRong Xu auto &Context = M->getContext(); 18182a0bb1aSRong Xu // Place this variable to llvm.used so it won't be GC'ed. 18282a0bb1aSRong Xu appendToUsed(*M, {new GlobalVariable(*M, Type::getInt1Ty(Context), true, 18382a0bb1aSRong Xu GlobalValue::WeakODRLinkage, 18482a0bb1aSRong Xu ConstantInt::getTrue(Context), 18582a0bb1aSRong Xu FSDiscriminatorVar)}); 18682a0bb1aSRong Xu } 18782a0bb1aSRong Xu 1887397905aSRong Xu } // end of namespace sampleprofutil 1897397905aSRong Xu } // end of namespace llvm 190