diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Transforms/Utils/SampleProfileLoaderBaseUtil.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/Transforms/Utils/SampleProfileLoaderBaseUtil.cpp | 189 | 
1 files changed, 189 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Transforms/Utils/SampleProfileLoaderBaseUtil.cpp b/contrib/llvm-project/llvm/lib/Transforms/Utils/SampleProfileLoaderBaseUtil.cpp new file mode 100644 index 000000000000..a2588b8cec7d --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Transforms/Utils/SampleProfileLoaderBaseUtil.cpp @@ -0,0 +1,189 @@ +//===- SampleProfileLoaderBaseUtil.cpp - Profile loader Util func ---------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the SampleProfileLoader base utility functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Utils/SampleProfileLoaderBaseUtil.h" +#include "llvm/Analysis/ProfileSummaryInfo.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Module.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" + +namespace llvm { + +cl::opt<unsigned> SampleProfileMaxPropagateIterations( +    "sample-profile-max-propagate-iterations", cl::init(100), +    cl::desc("Maximum number of iterations to go through when propagating " +             "sample block/edge weights through the CFG.")); + +cl::opt<unsigned> SampleProfileRecordCoverage( +    "sample-profile-check-record-coverage", cl::init(0), cl::value_desc("N"), +    cl::desc("Emit a warning if less than N% of records in the input profile " +             "are matched to the IR.")); + +cl::opt<unsigned> SampleProfileSampleCoverage( +    "sample-profile-check-sample-coverage", cl::init(0), cl::value_desc("N"), +    cl::desc("Emit a warning if less than N% of samples in the input profile " +             "are matched to the IR.")); + +cl::opt<bool> NoWarnSampleUnused( +    "no-warn-sample-unused", cl::init(false), cl::Hidden, +    cl::desc("Use this option to turn off/on warnings about function with " +             "samples but without debug information to use those samples. ")); + +cl::opt<bool> SampleProfileUseProfi( +    "sample-profile-use-profi", cl::Hidden, +    cl::desc("Use profi to infer block and edge counts.")); + +cl::opt<bool> SampleProfileInferEntryCount( +    "sample-profile-infer-entry-count", cl::init(true), cl::Hidden, +    cl::desc("Use profi to infer function entry count.")); + +namespace sampleprofutil { + +/// Return true if the given callsite is hot wrt to hot cutoff threshold. +/// +/// Functions that were inlined in the original binary will be represented +/// in the inline stack in the sample profile. If the profile shows that +/// the original inline decision was "good" (i.e., the callsite is executed +/// frequently), then we will recreate the inline decision and apply the +/// profile from the inlined callsite. +/// +/// To decide whether an inlined callsite is hot, we compare the callsite +/// sample count with the hot cutoff computed by ProfileSummaryInfo, it is +/// regarded as hot if the count is above the cutoff value. +/// +/// When ProfileAccurateForSymsInList is enabled and profile symbol list +/// is present, functions in the profile symbol list but without profile will +/// be regarded as cold and much less inlining will happen in CGSCC inlining +/// pass, so we tend to lower the hot criteria here to allow more early +/// inlining to happen for warm callsites and it is helpful for performance. +bool callsiteIsHot(const FunctionSamples *CallsiteFS, ProfileSummaryInfo *PSI, +                   bool ProfAccForSymsInList) { +  if (!CallsiteFS) +    return false; // The callsite was not inlined in the original binary. + +  assert(PSI && "PSI is expected to be non null"); +  uint64_t CallsiteTotalSamples = CallsiteFS->getTotalSamples(); +  if (ProfAccForSymsInList) +    return !PSI->isColdCount(CallsiteTotalSamples); +  else +    return PSI->isHotCount(CallsiteTotalSamples); +} + +/// Mark as used the sample record for the given function samples at +/// (LineOffset, Discriminator). +/// +/// \returns true if this is the first time we mark the given record. +bool SampleCoverageTracker::markSamplesUsed(const FunctionSamples *FS, +                                            uint32_t LineOffset, +                                            uint32_t Discriminator, +                                            uint64_t Samples) { +  LineLocation Loc(LineOffset, Discriminator); +  unsigned &Count = SampleCoverage[FS][Loc]; +  bool FirstTime = (++Count == 1); +  if (FirstTime) +    TotalUsedSamples += Samples; +  return FirstTime; +} + +/// Return the number of sample records that were applied from this profile. +/// +/// This count does not include records from cold inlined callsites. +unsigned +SampleCoverageTracker::countUsedRecords(const FunctionSamples *FS, +                                        ProfileSummaryInfo *PSI) const { +  auto I = SampleCoverage.find(FS); + +  // The size of the coverage map for FS represents the number of records +  // that were marked used at least once. +  unsigned Count = (I != SampleCoverage.end()) ? I->second.size() : 0; + +  // If there are inlined callsites in this function, count the samples found +  // in the respective bodies. However, do not bother counting callees with 0 +  // total samples, these are callees that were never invoked at runtime. +  for (const auto &I : FS->getCallsiteSamples()) +    for (const auto &J : I.second) { +      const FunctionSamples *CalleeSamples = &J.second; +      if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList)) +        Count += countUsedRecords(CalleeSamples, PSI); +    } + +  return Count; +} + +/// Return the number of sample records in the body of this profile. +/// +/// This count does not include records from cold inlined callsites. +unsigned +SampleCoverageTracker::countBodyRecords(const FunctionSamples *FS, +                                        ProfileSummaryInfo *PSI) const { +  unsigned Count = FS->getBodySamples().size(); + +  // Only count records in hot callsites. +  for (const auto &I : FS->getCallsiteSamples()) +    for (const auto &J : I.second) { +      const FunctionSamples *CalleeSamples = &J.second; +      if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList)) +        Count += countBodyRecords(CalleeSamples, PSI); +    } + +  return Count; +} + +/// Return the number of samples collected in the body of this profile. +/// +/// This count does not include samples from cold inlined callsites. +uint64_t +SampleCoverageTracker::countBodySamples(const FunctionSamples *FS, +                                        ProfileSummaryInfo *PSI) const { +  uint64_t Total = 0; +  for (const auto &I : FS->getBodySamples()) +    Total += I.second.getSamples(); + +  // Only count samples in hot callsites. +  for (const auto &I : FS->getCallsiteSamples()) +    for (const auto &J : I.second) { +      const FunctionSamples *CalleeSamples = &J.second; +      if (callsiteIsHot(CalleeSamples, PSI, ProfAccForSymsInList)) +        Total += countBodySamples(CalleeSamples, PSI); +    } + +  return Total; +} + +/// Return the fraction of sample records used in this profile. +/// +/// The returned value is an unsigned integer in the range 0-100 indicating +/// the percentage of sample records that were used while applying this +/// profile to the associated function. +unsigned SampleCoverageTracker::computeCoverage(unsigned Used, +                                                unsigned Total) const { +  assert(Used <= Total && +         "number of used records cannot exceed the total number of records"); +  return Total > 0 ? Used * 100 / Total : 100; +} + +/// Create a global variable to flag FSDiscriminators are used. +void createFSDiscriminatorVariable(Module *M) { +  const char *FSDiscriminatorVar = "__llvm_fs_discriminator__"; +  if (M->getGlobalVariable(FSDiscriminatorVar)) +    return; + +  auto &Context = M->getContext(); +  // Place this variable to llvm.used so it won't be GC'ed. +  appendToUsed(*M, {new GlobalVariable(*M, Type::getInt1Ty(Context), true, +                                       GlobalValue::WeakODRLinkage, +                                       ConstantInt::getTrue(Context), +                                       FSDiscriminatorVar)}); +} + +} // end of namespace sampleprofutil +} // end of namespace llvm  | 
