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" 14*a494ae43Sserge-sans-paille #include "llvm/Analysis/ProfileSummaryInfo.h" 15*a494ae43Sserge-sans-paille #include "llvm/IR/Constants.h" 16*a494ae43Sserge-sans-paille #include "llvm/IR/Module.h" 17*a494ae43Sserge-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 457397905aSRong Xu namespace sampleprofutil { 467397905aSRong Xu 477397905aSRong Xu /// Return true if the given callsite is hot wrt to hot cutoff threshold. 487397905aSRong Xu /// 497397905aSRong Xu /// Functions that were inlined in the original binary will be represented 507397905aSRong Xu /// in the inline stack in the sample profile. If the profile shows that 517397905aSRong Xu /// the original inline decision was "good" (i.e., the callsite is executed 527397905aSRong Xu /// frequently), then we will recreate the inline decision and apply the 537397905aSRong Xu /// profile from the inlined callsite. 547397905aSRong Xu /// 557397905aSRong Xu /// To decide whether an inlined callsite is hot, we compare the callsite 567397905aSRong Xu /// sample count with the hot cutoff computed by ProfileSummaryInfo, it is 577397905aSRong Xu /// regarded as hot if the count is above the cutoff value. 587397905aSRong Xu /// 597397905aSRong Xu /// When ProfileAccurateForSymsInList is enabled and profile symbol list 607397905aSRong Xu /// is present, functions in the profile symbol list but without profile will 617397905aSRong Xu /// be regarded as cold and much less inlining will happen in CGSCC inlining 627397905aSRong Xu /// pass, so we tend to lower the hot criteria here to allow more early 637397905aSRong Xu /// inlining to happen for warm callsites and it is helpful for performance. 647397905aSRong Xu bool callsiteIsHot(const FunctionSamples *CallsiteFS, ProfileSummaryInfo *PSI, 657397905aSRong Xu bool ProfAccForSymsInList) { 667397905aSRong Xu if (!CallsiteFS) 677397905aSRong Xu return false; // The callsite was not inlined in the original binary. 687397905aSRong Xu 697397905aSRong Xu assert(PSI && "PSI is expected to be non null"); 707397905aSRong Xu uint64_t CallsiteTotalSamples = CallsiteFS->getTotalSamples(); 717397905aSRong Xu if (ProfAccForSymsInList) 727397905aSRong Xu return !PSI->isColdCount(CallsiteTotalSamples); 737397905aSRong Xu else 747397905aSRong Xu return PSI->isHotCount(CallsiteTotalSamples); 757397905aSRong Xu } 767397905aSRong Xu 777397905aSRong Xu /// Mark as used the sample record for the given function samples at 787397905aSRong Xu /// (LineOffset, Discriminator). 797397905aSRong Xu /// 807397905aSRong Xu /// \returns true if this is the first time we mark the given record. 817397905aSRong Xu bool SampleCoverageTracker::markSamplesUsed(const FunctionSamples *FS, 827397905aSRong Xu uint32_t LineOffset, 837397905aSRong Xu uint32_t Discriminator, 847397905aSRong Xu uint64_t Samples) { 857397905aSRong Xu LineLocation Loc(LineOffset, Discriminator); 867397905aSRong Xu unsigned &Count = SampleCoverage[FS][Loc]; 877397905aSRong Xu bool FirstTime = (++Count == 1); 887397905aSRong Xu if (FirstTime) 897397905aSRong Xu TotalUsedSamples += Samples; 907397905aSRong Xu return FirstTime; 917397905aSRong Xu } 927397905aSRong Xu 937397905aSRong Xu /// Return the number of sample records that were applied from this profile. 947397905aSRong Xu /// 957397905aSRong Xu /// This count does not include records from cold inlined callsites. 967397905aSRong Xu unsigned 977397905aSRong Xu SampleCoverageTracker::countUsedRecords(const FunctionSamples *FS, 987397905aSRong Xu ProfileSummaryInfo *PSI) const { 997397905aSRong Xu auto I = SampleCoverage.find(FS); 1007397905aSRong Xu 1017397905aSRong Xu // The size of the coverage map for FS represents the number of records 1027397905aSRong Xu // that were marked used at least once. 1037397905aSRong Xu unsigned Count = (I != SampleCoverage.end()) ? I->second.size() : 0; 1047397905aSRong Xu 1057397905aSRong Xu // If there are inlined callsites in this function, count the samples found 1067397905aSRong Xu // in the respective bodies. However, do not bother counting callees with 0 1077397905aSRong Xu // total samples, these are callees that were never invoked at runtime. 1087397905aSRong Xu for (const auto &I : FS->getCallsiteSamples()) 1097397905aSRong Xu for (const auto &J : I.second) { 1107397905aSRong Xu const FunctionSamples *CalleeSamples = &J.second; 1117397905aSRong Xu if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList)) 1127397905aSRong Xu Count += countUsedRecords(CalleeSamples, PSI); 1137397905aSRong Xu } 1147397905aSRong Xu 1157397905aSRong Xu return Count; 1167397905aSRong Xu } 1177397905aSRong Xu 1187397905aSRong Xu /// Return the number of sample records in the body of this profile. 1197397905aSRong Xu /// 1207397905aSRong Xu /// This count does not include records from cold inlined callsites. 1217397905aSRong Xu unsigned 1227397905aSRong Xu SampleCoverageTracker::countBodyRecords(const FunctionSamples *FS, 1237397905aSRong Xu ProfileSummaryInfo *PSI) const { 1247397905aSRong Xu unsigned Count = FS->getBodySamples().size(); 1257397905aSRong Xu 1267397905aSRong Xu // Only count records in hot callsites. 1277397905aSRong Xu for (const auto &I : FS->getCallsiteSamples()) 1287397905aSRong Xu for (const auto &J : I.second) { 1297397905aSRong Xu const FunctionSamples *CalleeSamples = &J.second; 1307397905aSRong Xu if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList)) 1317397905aSRong Xu Count += countBodyRecords(CalleeSamples, PSI); 1327397905aSRong Xu } 1337397905aSRong Xu 1347397905aSRong Xu return Count; 1357397905aSRong Xu } 1367397905aSRong Xu 1377397905aSRong Xu /// Return the number of samples collected in the body of this profile. 1387397905aSRong Xu /// 1397397905aSRong Xu /// This count does not include samples from cold inlined callsites. 1407397905aSRong Xu uint64_t 1417397905aSRong Xu SampleCoverageTracker::countBodySamples(const FunctionSamples *FS, 1427397905aSRong Xu ProfileSummaryInfo *PSI) const { 1437397905aSRong Xu uint64_t Total = 0; 1447397905aSRong Xu for (const auto &I : FS->getBodySamples()) 1457397905aSRong Xu Total += I.second.getSamples(); 1467397905aSRong Xu 1477397905aSRong Xu // Only count samples in hot callsites. 1487397905aSRong Xu for (const auto &I : FS->getCallsiteSamples()) 1497397905aSRong Xu for (const auto &J : I.second) { 1507397905aSRong Xu const FunctionSamples *CalleeSamples = &J.second; 1517397905aSRong Xu if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList)) 1527397905aSRong Xu Total += countBodySamples(CalleeSamples, PSI); 1537397905aSRong Xu } 1547397905aSRong Xu 1557397905aSRong Xu return Total; 1567397905aSRong Xu } 1577397905aSRong Xu 1587397905aSRong Xu /// Return the fraction of sample records used in this profile. 1597397905aSRong Xu /// 1607397905aSRong Xu /// The returned value is an unsigned integer in the range 0-100 indicating 1617397905aSRong Xu /// the percentage of sample records that were used while applying this 1627397905aSRong Xu /// profile to the associated function. 1637397905aSRong Xu unsigned SampleCoverageTracker::computeCoverage(unsigned Used, 1647397905aSRong Xu unsigned Total) const { 1657397905aSRong Xu assert(Used <= Total && 1667397905aSRong Xu "number of used records cannot exceed the total number of records"); 1677397905aSRong Xu return Total > 0 ? Used * 100 / Total : 100; 1687397905aSRong Xu } 1697397905aSRong Xu 17082a0bb1aSRong Xu /// Create a global variable to flag FSDiscriminators are used. 17182a0bb1aSRong Xu void createFSDiscriminatorVariable(Module *M) { 17282a0bb1aSRong Xu const char *FSDiscriminatorVar = "__llvm_fs_discriminator__"; 17382a0bb1aSRong Xu if (M->getGlobalVariable(FSDiscriminatorVar)) 17482a0bb1aSRong Xu return; 17582a0bb1aSRong Xu 17682a0bb1aSRong Xu auto &Context = M->getContext(); 17782a0bb1aSRong Xu // Place this variable to llvm.used so it won't be GC'ed. 17882a0bb1aSRong Xu appendToUsed(*M, {new GlobalVariable(*M, Type::getInt1Ty(Context), true, 17982a0bb1aSRong Xu GlobalValue::WeakODRLinkage, 18082a0bb1aSRong Xu ConstantInt::getTrue(Context), 18182a0bb1aSRong Xu FSDiscriminatorVar)}); 18282a0bb1aSRong Xu } 18382a0bb1aSRong Xu 1847397905aSRong Xu } // end of namespace sampleprofutil 1857397905aSRong Xu } // end of namespace llvm 186