186 lines · cpp
1//===- SampleProfileLoaderBaseUtil.cpp - Profile loader Util func ---------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the SampleProfileLoader base utility functions.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/Transforms/Utils/SampleProfileLoaderBaseUtil.h"14#include "llvm/Analysis/ProfileSummaryInfo.h"15#include "llvm/IR/Constants.h"16#include "llvm/IR/Module.h"17#include "llvm/Transforms/Utils/ModuleUtils.h"18 19namespace llvm {20 21cl::opt<unsigned> SampleProfileMaxPropagateIterations(22 "sample-profile-max-propagate-iterations", cl::init(100),23 cl::desc("Maximum number of iterations to go through when propagating "24 "sample block/edge weights through the CFG."));25 26cl::opt<unsigned> SampleProfileRecordCoverage(27 "sample-profile-check-record-coverage", cl::init(0), cl::value_desc("N"),28 cl::desc("Emit a warning if less than N% of records in the input profile "29 "are matched to the IR."));30 31cl::opt<unsigned> SampleProfileSampleCoverage(32 "sample-profile-check-sample-coverage", cl::init(0), cl::value_desc("N"),33 cl::desc("Emit a warning if less than N% of samples in the input profile "34 "are matched to the IR."));35 36cl::opt<bool> NoWarnSampleUnused(37 "no-warn-sample-unused", cl::init(false), cl::Hidden,38 cl::desc("Use this option to turn off/on warnings about function with "39 "samples but without debug information to use those samples. "));40 41cl::opt<bool> SampleProfileUseProfi(42 "sample-profile-use-profi", cl::Hidden,43 cl::desc("Use profi to infer block and edge counts."));44 45namespace sampleprofutil {46 47/// Return true if the given callsite is hot wrt to hot cutoff threshold.48///49/// Functions that were inlined in the original binary will be represented50/// in the inline stack in the sample profile. If the profile shows that51/// the original inline decision was "good" (i.e., the callsite is executed52/// frequently), then we will recreate the inline decision and apply the53/// profile from the inlined callsite.54///55/// To decide whether an inlined callsite is hot, we compare the callsite56/// sample count with the hot cutoff computed by ProfileSummaryInfo, it is57/// regarded as hot if the count is above the cutoff value.58///59/// When ProfileAccurateForSymsInList is enabled and profile symbol list60/// is present, functions in the profile symbol list but without profile will61/// be regarded as cold and much less inlining will happen in CGSCC inlining62/// pass, so we tend to lower the hot criteria here to allow more early63/// inlining to happen for warm callsites and it is helpful for performance.64bool callsiteIsHot(const FunctionSamples *CallsiteFS, ProfileSummaryInfo *PSI,65 bool ProfAccForSymsInList) {66 if (!CallsiteFS)67 return false; // The callsite was not inlined in the original binary.68 69 assert(PSI && "PSI is expected to be non null");70 uint64_t CallsiteTotalSamples = CallsiteFS->getTotalSamples();71 if (ProfAccForSymsInList)72 return !PSI->isColdCount(CallsiteTotalSamples);73 else74 return PSI->isHotCount(CallsiteTotalSamples);75}76 77/// Mark as used the sample record for the given function samples at78/// (LineOffset, Discriminator).79///80/// \returns true if this is the first time we mark the given record.81bool SampleCoverageTracker::markSamplesUsed(const FunctionSamples *FS,82 uint32_t LineOffset,83 uint32_t Discriminator,84 uint64_t Samples) {85 LineLocation Loc(LineOffset, Discriminator);86 unsigned &Count = SampleCoverage[FS][Loc];87 bool FirstTime = (++Count == 1);88 if (FirstTime)89 TotalUsedSamples += Samples;90 return FirstTime;91}92 93/// Return the number of sample records that were applied from this profile.94///95/// This count does not include records from cold inlined callsites.96unsigned97SampleCoverageTracker::countUsedRecords(const FunctionSamples *FS,98 ProfileSummaryInfo *PSI) const {99 auto I = SampleCoverage.find(FS);100 101 // The size of the coverage map for FS represents the number of records102 // that were marked used at least once.103 unsigned Count = (I != SampleCoverage.end()) ? I->second.size() : 0;104 105 // If there are inlined callsites in this function, count the samples found106 // in the respective bodies. However, do not bother counting callees with 0107 // total samples, these are callees that were never invoked at runtime.108 for (const auto &I : FS->getCallsiteSamples())109 for (const auto &J : I.second) {110 const FunctionSamples *CalleeSamples = &J.second;111 if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList))112 Count += countUsedRecords(CalleeSamples, PSI);113 }114 115 return Count;116}117 118/// Return the number of sample records in the body of this profile.119///120/// This count does not include records from cold inlined callsites.121unsigned122SampleCoverageTracker::countBodyRecords(const FunctionSamples *FS,123 ProfileSummaryInfo *PSI) const {124 unsigned Count = FS->getBodySamples().size();125 126 // Only count records in hot callsites.127 for (const auto &I : FS->getCallsiteSamples())128 for (const auto &J : I.second) {129 const FunctionSamples *CalleeSamples = &J.second;130 if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList))131 Count += countBodyRecords(CalleeSamples, PSI);132 }133 134 return Count;135}136 137/// Return the number of samples collected in the body of this profile.138///139/// This count does not include samples from cold inlined callsites.140uint64_t141SampleCoverageTracker::countBodySamples(const FunctionSamples *FS,142 ProfileSummaryInfo *PSI) const {143 uint64_t Total = 0;144 for (const auto &I : FS->getBodySamples())145 Total += I.second.getSamples();146 147 // Only count samples in hot callsites.148 for (const auto &I : FS->getCallsiteSamples())149 for (const auto &J : I.second) {150 const FunctionSamples *CalleeSamples = &J.second;151 if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList))152 Total += countBodySamples(CalleeSamples, PSI);153 }154 155 return Total;156}157 158/// Return the fraction of sample records used in this profile.159///160/// The returned value is an unsigned integer in the range 0-100 indicating161/// the percentage of sample records that were used while applying this162/// profile to the associated function.163unsigned SampleCoverageTracker::computeCoverage(unsigned Used,164 unsigned Total) const {165 assert(Used <= Total &&166 "number of used records cannot exceed the total number of records");167 return Total > 0 ? Used * 100 / Total : 100;168}169 170/// Create a global variable to flag FSDiscriminators are used.171void createFSDiscriminatorVariable(Module *M) {172 const char *FSDiscriminatorVar = "__llvm_fs_discriminator__";173 if (M->getGlobalVariable(FSDiscriminatorVar))174 return;175 176 auto &Context = M->getContext();177 // Place this variable to llvm.used so it won't be GC'ed.178 appendToUsed(*M, {new GlobalVariable(*M, Type::getInt1Ty(Context), true,179 GlobalValue::WeakODRLinkage,180 ConstantInt::getTrue(Context),181 FSDiscriminatorVar)});182}183 184} // end of namespace sampleprofutil185} // end of namespace llvm186