10b57cec5SDimitry Andric //=- SyntheticCountsPropagation.cpp - Propagate function counts --*- C++ -*-=// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements a transformation that synthesizes entry counts for 100b57cec5SDimitry Andric // functions and attaches !prof metadata to functions with the synthesized 110b57cec5SDimitry Andric // counts. The presence of !prof metadata with counter name set to 120b57cec5SDimitry Andric // 'synthesized_function_entry_count' indicate that the value of the counter is 130b57cec5SDimitry Andric // an estimation of the likely execution count of the function. This transform 140b57cec5SDimitry Andric // is applied only in non PGO mode as functions get 'real' profile-based 150b57cec5SDimitry Andric // function entry counts in the PGO mode. 160b57cec5SDimitry Andric // 170b57cec5SDimitry Andric // The transformation works by first assigning some initial values to the entry 180b57cec5SDimitry Andric // counts of all functions and then doing a top-down traversal of the 190b57cec5SDimitry Andric // callgraph-scc to propagate the counts. For each function the set of callsites 200b57cec5SDimitry Andric // and their relative block frequency is gathered. The relative block frequency 210b57cec5SDimitry Andric // multiplied by the entry count of the caller and added to the callee's entry 220b57cec5SDimitry Andric // count. For non-trivial SCCs, the new counts are computed from the previous 230b57cec5SDimitry Andric // counts and updated in one shot. 240b57cec5SDimitry Andric // 250b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric #include "llvm/Transforms/IPO/SyntheticCountsPropagation.h" 280b57cec5SDimitry Andric #include "llvm/Analysis/BlockFrequencyInfo.h" 290b57cec5SDimitry Andric #include "llvm/Analysis/CallGraph.h" 300b57cec5SDimitry Andric #include "llvm/Analysis/SyntheticCountsUtils.h" 310b57cec5SDimitry Andric #include "llvm/IR/Function.h" 320b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 330b57cec5SDimitry Andric #include "llvm/IR/Module.h" 340b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric using namespace llvm; 370b57cec5SDimitry Andric using Scaled64 = ScaledNumber<uint64_t>; 380b57cec5SDimitry Andric using ProfileCount = Function::ProfileCount; 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric #define DEBUG_TYPE "synthetic-counts-propagation" 410b57cec5SDimitry Andric 42fe6060f1SDimitry Andric namespace llvm { 430b57cec5SDimitry Andric cl::opt<int> 440b57cec5SDimitry Andric InitialSyntheticCount("initial-synthetic-count", cl::Hidden, cl::init(10), 45fe6060f1SDimitry Andric cl::desc("Initial value of synthetic entry count")); 46fe6060f1SDimitry Andric } // namespace llvm 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric /// Initial synthetic count assigned to inline functions. 490b57cec5SDimitry Andric static cl::opt<int> InlineSyntheticCount( 5081ad6265SDimitry Andric "inline-synthetic-count", cl::Hidden, cl::init(15), 510b57cec5SDimitry Andric cl::desc("Initial synthetic entry count for inline functions.")); 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric /// Initial synthetic count assigned to cold functions. 540b57cec5SDimitry Andric static cl::opt<int> ColdSyntheticCount( 5581ad6265SDimitry Andric "cold-synthetic-count", cl::Hidden, cl::init(5), 560b57cec5SDimitry Andric cl::desc("Initial synthetic entry count for cold functions.")); 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric // Assign initial synthetic entry counts to functions. 590b57cec5SDimitry Andric static void 600b57cec5SDimitry Andric initializeCounts(Module &M, function_ref<void(Function *, uint64_t)> SetCount) { 610b57cec5SDimitry Andric auto MayHaveIndirectCalls = [](Function &F) { 620b57cec5SDimitry Andric for (auto *U : F.users()) { 630b57cec5SDimitry Andric if (!isa<CallInst>(U) && !isa<InvokeInst>(U)) 640b57cec5SDimitry Andric return true; 650b57cec5SDimitry Andric } 660b57cec5SDimitry Andric return false; 670b57cec5SDimitry Andric }; 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric for (Function &F : M) { 700b57cec5SDimitry Andric uint64_t InitialCount = InitialSyntheticCount; 710b57cec5SDimitry Andric if (F.isDeclaration()) 720b57cec5SDimitry Andric continue; 730b57cec5SDimitry Andric if (F.hasFnAttribute(Attribute::AlwaysInline) || 740b57cec5SDimitry Andric F.hasFnAttribute(Attribute::InlineHint)) { 750b57cec5SDimitry Andric // Use a higher value for inline functions to account for the fact that 760b57cec5SDimitry Andric // these are usually beneficial to inline. 770b57cec5SDimitry Andric InitialCount = InlineSyntheticCount; 780b57cec5SDimitry Andric } else if (F.hasLocalLinkage() && !MayHaveIndirectCalls(F)) { 790b57cec5SDimitry Andric // Local functions without inline hints get counts only through 800b57cec5SDimitry Andric // propagation. 810b57cec5SDimitry Andric InitialCount = 0; 820b57cec5SDimitry Andric } else if (F.hasFnAttribute(Attribute::Cold) || 830b57cec5SDimitry Andric F.hasFnAttribute(Attribute::NoInline)) { 840b57cec5SDimitry Andric // Use a lower value for noinline and cold functions. 850b57cec5SDimitry Andric InitialCount = ColdSyntheticCount; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric SetCount(&F, InitialCount); 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric PreservedAnalyses SyntheticCountsPropagation::run(Module &M, 920b57cec5SDimitry Andric ModuleAnalysisManager &MAM) { 930b57cec5SDimitry Andric FunctionAnalysisManager &FAM = 940b57cec5SDimitry Andric MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); 950b57cec5SDimitry Andric DenseMap<Function *, Scaled64> Counts; 960b57cec5SDimitry Andric // Set initial entry counts. 970b57cec5SDimitry Andric initializeCounts( 980b57cec5SDimitry Andric M, [&](Function *F, uint64_t Count) { Counts[F] = Scaled64(Count, 0); }); 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric // Edge includes information about the source. Hence ignore the first 1010b57cec5SDimitry Andric // parameter. 1020b57cec5SDimitry Andric auto GetCallSiteProfCount = [&](const CallGraphNode *, 1030b57cec5SDimitry Andric const CallGraphNode::CallRecord &Edge) { 104bdd1243dSDimitry Andric std::optional<Scaled64> Res; 1050b57cec5SDimitry Andric if (!Edge.first) 1060b57cec5SDimitry Andric return Res; 1075ffd83dbSDimitry Andric CallBase &CB = *cast<CallBase>(*Edge.first); 1085ffd83dbSDimitry Andric Function *Caller = CB.getCaller(); 1090b57cec5SDimitry Andric auto &BFI = FAM.getResult<BlockFrequencyAnalysis>(*Caller); 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric // Now compute the callsite count from relative frequency and 1120b57cec5SDimitry Andric // entry count: 1135ffd83dbSDimitry Andric BasicBlock *CSBB = CB.getParent(); 114*5f757f3fSDimitry Andric Scaled64 EntryFreq(BFI.getEntryFreq().getFrequency(), 0); 1150b57cec5SDimitry Andric Scaled64 BBCount(BFI.getBlockFreq(CSBB).getFrequency(), 0); 1160b57cec5SDimitry Andric BBCount /= EntryFreq; 1170b57cec5SDimitry Andric BBCount *= Counts[Caller]; 118bdd1243dSDimitry Andric return std::optional<Scaled64>(BBCount); 1190b57cec5SDimitry Andric }; 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric CallGraph CG(M); 1220b57cec5SDimitry Andric // Propgate the entry counts on the callgraph. 1230b57cec5SDimitry Andric SyntheticCountsUtils<const CallGraph *>::propagate( 1240b57cec5SDimitry Andric &CG, GetCallSiteProfCount, [&](const CallGraphNode *N, Scaled64 New) { 1250b57cec5SDimitry Andric auto F = N->getFunction(); 1260b57cec5SDimitry Andric if (!F || F->isDeclaration()) 1270b57cec5SDimitry Andric return; 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric Counts[F] += New; 1300b57cec5SDimitry Andric }); 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric // Set the counts as metadata. 1330b57cec5SDimitry Andric for (auto Entry : Counts) { 1340b57cec5SDimitry Andric Entry.first->setEntryCount(ProfileCount( 1350b57cec5SDimitry Andric Entry.second.template toInt<uint64_t>(), Function::PCT_Synthetic)); 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric return PreservedAnalyses::all(); 1390b57cec5SDimitry Andric } 140