Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/IPO/SyntheticCountsPropagation.cpp
35294 views
//=- SyntheticCountsPropagation.cpp - Propagate function counts --*- C++ -*-=//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements a transformation that synthesizes entry counts for9// functions and attaches !prof metadata to functions with the synthesized10// counts. The presence of !prof metadata with counter name set to11// 'synthesized_function_entry_count' indicate that the value of the counter is12// an estimation of the likely execution count of the function. This transform13// is applied only in non PGO mode as functions get 'real' profile-based14// function entry counts in the PGO mode.15//16// The transformation works by first assigning some initial values to the entry17// counts of all functions and then doing a top-down traversal of the18// callgraph-scc to propagate the counts. For each function the set of callsites19// and their relative block frequency is gathered. The relative block frequency20// multiplied by the entry count of the caller and added to the callee's entry21// count. For non-trivial SCCs, the new counts are computed from the previous22// counts and updated in one shot.23//24//===----------------------------------------------------------------------===//2526#include "llvm/Transforms/IPO/SyntheticCountsPropagation.h"27#include "llvm/Analysis/BlockFrequencyInfo.h"28#include "llvm/Analysis/CallGraph.h"29#include "llvm/Analysis/SyntheticCountsUtils.h"30#include "llvm/IR/Function.h"31#include "llvm/IR/Instructions.h"32#include "llvm/IR/Module.h"33#include "llvm/Support/CommandLine.h"3435using namespace llvm;36using Scaled64 = ScaledNumber<uint64_t>;37using ProfileCount = Function::ProfileCount;3839#define DEBUG_TYPE "synthetic-counts-propagation"4041namespace llvm {42cl::opt<int>43InitialSyntheticCount("initial-synthetic-count", cl::Hidden, cl::init(10),44cl::desc("Initial value of synthetic entry count"));45} // namespace llvm4647/// Initial synthetic count assigned to inline functions.48static cl::opt<int> InlineSyntheticCount(49"inline-synthetic-count", cl::Hidden, cl::init(15),50cl::desc("Initial synthetic entry count for inline functions."));5152/// Initial synthetic count assigned to cold functions.53static cl::opt<int> ColdSyntheticCount(54"cold-synthetic-count", cl::Hidden, cl::init(5),55cl::desc("Initial synthetic entry count for cold functions."));5657// Assign initial synthetic entry counts to functions.58static void59initializeCounts(Module &M, function_ref<void(Function *, uint64_t)> SetCount) {60auto MayHaveIndirectCalls = [](Function &F) {61for (auto *U : F.users()) {62if (!isa<CallInst>(U) && !isa<InvokeInst>(U))63return true;64}65return false;66};6768for (Function &F : M) {69uint64_t InitialCount = InitialSyntheticCount;70if (F.isDeclaration())71continue;72if (F.hasFnAttribute(Attribute::AlwaysInline) ||73F.hasFnAttribute(Attribute::InlineHint)) {74// Use a higher value for inline functions to account for the fact that75// these are usually beneficial to inline.76InitialCount = InlineSyntheticCount;77} else if (F.hasLocalLinkage() && !MayHaveIndirectCalls(F)) {78// Local functions without inline hints get counts only through79// propagation.80InitialCount = 0;81} else if (F.hasFnAttribute(Attribute::Cold) ||82F.hasFnAttribute(Attribute::NoInline)) {83// Use a lower value for noinline and cold functions.84InitialCount = ColdSyntheticCount;85}86SetCount(&F, InitialCount);87}88}8990PreservedAnalyses SyntheticCountsPropagation::run(Module &M,91ModuleAnalysisManager &MAM) {92FunctionAnalysisManager &FAM =93MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();94DenseMap<Function *, Scaled64> Counts;95// Set initial entry counts.96initializeCounts(97M, [&](Function *F, uint64_t Count) { Counts[F] = Scaled64(Count, 0); });9899// Edge includes information about the source. Hence ignore the first100// parameter.101auto GetCallSiteProfCount = [&](const CallGraphNode *,102const CallGraphNode::CallRecord &Edge) {103std::optional<Scaled64> Res;104if (!Edge.first)105return Res;106CallBase &CB = *cast<CallBase>(*Edge.first);107Function *Caller = CB.getCaller();108auto &BFI = FAM.getResult<BlockFrequencyAnalysis>(*Caller);109110// Now compute the callsite count from relative frequency and111// entry count:112BasicBlock *CSBB = CB.getParent();113Scaled64 EntryFreq(BFI.getEntryFreq().getFrequency(), 0);114Scaled64 BBCount(BFI.getBlockFreq(CSBB).getFrequency(), 0);115BBCount /= EntryFreq;116BBCount *= Counts[Caller];117return std::optional<Scaled64>(BBCount);118};119120CallGraph CG(M);121// Propgate the entry counts on the callgraph.122SyntheticCountsUtils<const CallGraph *>::propagate(123&CG, GetCallSiteProfCount, [&](const CallGraphNode *N, Scaled64 New) {124auto F = N->getFunction();125if (!F || F->isDeclaration())126return;127128Counts[F] += New;129});130131// Set the counts as metadata.132for (auto Entry : Counts) {133Entry.first->setEntryCount(ProfileCount(134Entry.second.template toInt<uint64_t>(), Function::PCT_Synthetic));135}136137return PreservedAnalyses::all();138}139140141