brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.5 KiB · f7ae6ad Raw
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