LLVM 24.0.0git
MIRSampleProfile.cpp
Go to the documentation of this file.
1//===-------- MIRSampleProfile.cpp: MIRSampleFDO (For FSAFDO) -------------===//
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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file provides the implementation of the MIRSampleProfile loader, mainly
10// for flow sensitive SampleFDO.
11//
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/DenseMap.h"
16#include "llvm/ADT/DenseSet.h"
27#include "llvm/CodeGen/Passes.h"
28#include "llvm/IR/Function.h"
29#include "llvm/IR/PseudoProbe.h"
32#include "llvm/Support/Debug.h"
37#include <optional>
38
39using namespace llvm;
40using namespace sampleprof;
41using namespace llvm::sampleprofutil;
42
43#define DEBUG_TYPE "fs-profile-loader"
44
46 "show-fs-branchprob", cl::Hidden, cl::init(false),
47 cl::desc("Print setting flow sensitive branch probabilities"));
49 "fs-profile-debug-prob-diff-threshold", cl::init(10),
51 "Only show debug message if the branch probability is greater than "
52 "this value (in percentage)."));
53
55 "fs-profile-debug-bw-threshold", cl::init(10000),
56 cl::desc("Only show debug message if the source branch weight is greater "
57 " than this value."));
58
59static cl::opt<bool> ViewBFIBefore("fs-viewbfi-before", cl::Hidden,
60 cl::init(false),
61 cl::desc("View BFI before MIR loader"));
62static cl::opt<bool> ViewBFIAfter("fs-viewbfi-after", cl::Hidden,
63 cl::init(false),
64 cl::desc("View BFI after MIR loader"));
65
67
69 "Load MIR Sample Profile",
70 /* cfg = */ false, /* is_analysis = */ false)
77 /* cfg = */ false, /* is_analysis = */ false)
78
80
82llvm::createMIRProfileLoaderPass(std::string File, std::string RemappingFile,
84 IntrusiveRefCntPtr<vfs::FileSystem> FS) {
85 return new MIRProfileLoaderPass(File, RemappingFile, P, std::move(FS));
86}
87
88namespace llvm {
89
90// Internal option used to control BFI display only after MBP pass.
91// Defined in CodeGen/MachineBlockFrequencyInfo.cpp:
92// -view-block-layout-with-bfi={none | fraction | integer | count}
94
95std::optional<PseudoProbe> extractProbe(const MachineInstr &MI) {
96 if (MI.isPseudoProbe()) {
97 PseudoProbe Probe;
98 Probe.Id = MI.getOperand(1).getImm();
99 Probe.Type = MI.getOperand(2).getImm();
100 Probe.Attr = MI.getOperand(3).getImm();
101 Probe.Factor = 1;
102 DILocation *DebugLoc = MI.getDebugLoc();
103 Probe.Discriminator = DebugLoc ? DebugLoc->getDiscriminator() : 0;
104 return Probe;
105 }
106
107 // Ignore callsite probes since they do not have FS discriminators.
108 return std::nullopt;
109}
110
111namespace afdo_detail {
139} // namespace afdo_detail
140
142 : public SampleProfileLoaderBaseImpl<MachineFunction> {
143public:
147 DT = MDT;
148 PDT = MPDT;
149 LI = MLI;
150 BFI = MBFI;
151 ORE = MORE;
152 }
154 P = Pass;
157 assert(LowBit < HighBit && "HighBit needs to be greater than Lowbit");
158 }
159
162 : SampleProfileLoaderBaseImpl(std::string(Name), std::string(RemapName),
163 std::move(FS)) {}
164
167 bool doInitialization(Module &M);
168 bool isValid() const { return ProfileIsValid; }
169
170protected:
172
173 /// Hold the information of the basic block frequency.
175
176 /// PassNum is the sequence number this pass is called, start from 1.
178
179 // LowBit in the FS discriminator used by this instance. Note the number is
180 // 0-based. Base discrimnator use bit 0 to bit 11.
181 unsigned LowBit;
182 // HighwBit in the FS discriminator used by this instance. Note the number
183 // is 0-based.
184 unsigned HighBit;
185
186 bool ProfileIsValid = true;
189 return getProbeWeight(MI);
190 if (ImprovedFSDiscriminator && MI.isMetaInstruction())
191 return std::error_code();
192 return getInstWeightImpl(MI);
193 }
194};
195
196template <>
199
201 LLVM_DEBUG(dbgs() << "\nPropagation complete. Setting branch probs\n");
202 for (auto &BI : F) {
203 MachineBasicBlock *BB = &BI;
204 if (BB->succ_size() < 2)
205 continue;
206 const MachineBasicBlock *EC = EquivalenceClass[BB];
207 uint64_t BBWeight = BlockWeights[EC];
208 uint64_t SumEdgeWeight = 0;
209 for (MachineBasicBlock *Succ : BB->successors()) {
210 Edge E = std::make_pair(BB, Succ);
211 SumEdgeWeight += EdgeWeights[E];
212 }
213
214 if (BBWeight != SumEdgeWeight) {
215 LLVM_DEBUG(dbgs() << "BBweight is not equal to SumEdgeWeight: BBWWeight="
216 << BBWeight << " SumEdgeWeight= " << SumEdgeWeight
217 << "\n");
218 BBWeight = SumEdgeWeight;
219 }
220 if (BBWeight == 0) {
221 LLVM_DEBUG(dbgs() << "SKIPPED. All branch weights are zero.\n");
222 continue;
223 }
224
225#ifndef NDEBUG
226 uint64_t BBWeightOrig = BBWeight;
227#endif
228 uint32_t MaxWeight = std::numeric_limits<uint32_t>::max();
229 uint32_t Factor = 1;
230 if (BBWeight > MaxWeight) {
231 Factor = BBWeight / MaxWeight + 1;
232 BBWeight /= Factor;
233 LLVM_DEBUG(dbgs() << "Scaling weights by " << Factor << "\n");
234 }
235
237 SE = BB->succ_end();
238 SI != SE; ++SI) {
239 MachineBasicBlock *Succ = *SI;
240 Edge E = std::make_pair(BB, Succ);
241 uint64_t EdgeWeight = EdgeWeights[E];
242 EdgeWeight /= Factor;
243
244 assert(BBWeight >= EdgeWeight &&
245 "BBweight is larger than EdgeWeight -- should not happen.\n");
246
248 BranchProbability NewProb(EdgeWeight, BBWeight);
249 if (OldProb == NewProb)
250 continue;
251 BB->setSuccProbability(SI, NewProb);
252#ifndef NDEBUG
253 if (!ShowFSBranchProb)
254 continue;
255 bool Show = false;
257 if (OldProb > NewProb)
258 Diff = OldProb - NewProb;
259 else
260 Diff = NewProb - OldProb;
262 Show &= (BBWeightOrig >= FSProfileDebugBWThreshold);
263
264 auto DIL = BB->findBranchDebugLoc();
265 auto SuccDIL = Succ->findBranchDebugLoc();
266 if (Show) {
267 dbgs() << "Set branch fs prob: MBB (" << BB->getNumber() << " -> "
268 << Succ->getNumber() << "): ";
269 if (DIL)
270 dbgs() << DIL->getFilename() << ":" << DIL->getLine() << ":"
271 << DIL->getColumn();
272 if (SuccDIL)
273 dbgs() << "-->" << SuccDIL->getFilename() << ":" << SuccDIL->getLine()
274 << ":" << SuccDIL->getColumn();
275 dbgs() << " W=" << BBWeightOrig << " " << OldProb << " --> " << NewProb
276 << "\n";
277 }
278#endif
279 }
280 }
281}
282
284 auto &Ctx = M.getContext();
285
287 Filename, Ctx, *FS, P, RemappingFilename);
288 if (std::error_code EC = ReaderOrErr.getError()) {
289 std::string Msg = "Could not open profile: " + EC.message();
291 return false;
292 }
293
294 Reader = std::move(ReaderOrErr.get());
295 Reader->setModule(&M);
297
298 // Load pseudo probe descriptors for probe-based function samples.
299 if (Reader->profileIsProbeBased()) {
300 ProbeManager = std::make_unique<PseudoProbeManager>(M);
301 if (!ProbeManager->moduleIsProbed(M)) {
302 return false;
303 }
304 }
305
306 return true;
307}
308
310 // Do not load non-FS profiles. A line or probe can get a zero-valued
311 // discriminator at certain pass which could result in accidentally loading
312 // the corresponding base counter in the non-FS profile, while a non-zero
313 // discriminator would end up getting zero samples. This could in turn undo
314 // the sample distribution effort done by previous BFI maintenance and the
315 // probe distribution factor work for pseudo probes.
316 if (!Reader->profileIsFS())
317 return false;
318
319 Function &Func = MF.getFunction();
320 clearFunctionData(false);
321 Samples = Reader->getSamplesFor(Func);
322 if (!Samples || Samples->empty())
323 return false;
324
326 if (!ProbeManager->profileIsValid(MF.getFunction(), *Samples))
327 return false;
328 } else {
329 if (getFunctionLoc(MF) == 0)
330 return false;
331 }
332
333 DenseSet<GlobalValue::GUID> InlinedGUIDs;
334 bool Changed = computeAndPropagateWeights(MF, InlinedGUIDs);
335
336 // Set the new BPI, BFI.
337 setBranchProbs(MF);
338
339 return Changed;
340}
341
342} // namespace llvm
343
345 std::string FileName, std::string RemappingFileName, FSDiscriminatorPass P,
347 : MachineFunctionPass(ID), ProfileFileName(FileName), P(P) {
348 LowBit = getFSPassBitBegin(P);
349 HighBit = getFSPassBitEnd(P);
350
351 auto VFS = FS ? std::move(FS) : vfs::getRealFileSystem();
352 MIRSampleLoader = std::make_unique<MIRProfileLoader>(
353 FileName, RemappingFileName, std::move(VFS));
354 assert(LowBit < HighBit && "HighBit needs to be greater than Lowbit");
355}
356
357bool MIRProfileLoaderPass::runOnMachineFunction(MachineFunction &MF) {
358 if (!MIRSampleLoader->isValid())
359 return false;
360
361 LLVM_DEBUG(dbgs() << "MIRProfileLoader pass working on Func: "
362 << MF.getFunction().getName() << "\n");
364 auto *MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
365 auto *MPDT =
367
368 MF.RenumberBlocks();
369
370 MIRSampleLoader->setInitVals(
371 MDT, MPDT, &getAnalysis<MachineLoopInfoWrapperPass>().getLI(), MBFI,
373
374 StringRef ViewFuncName =
377 (ViewFuncName.empty() || MF.getFunction().getName() == ViewFuncName)) {
378 MBFI->view("MIR_Prof_loader_b." + MF.getName(), false);
379 }
380
381 bool Changed = MIRSampleLoader->runOnFunction(MF);
382 if (Changed) {
384 MCI.compute(MF);
385 MBFI->calculate(MF, *MBFI->getMBPI(), MCI);
386 }
387
389 (ViewFuncName.empty() || MF.getFunction().getName() == ViewFuncName)) {
390 MBFI->view("MIR_prof_loader_a." + MF.getName(), false);
391 }
392
393 return Changed;
394}
395
396bool MIRProfileLoaderPass::doInitialization(Module &M) {
397 LLVM_DEBUG(dbgs() << "MIRProfileLoader pass working on Module " << M.getName()
398 << "\n");
399
400 MIRSampleLoader->setFSPass(P);
401 return MIRSampleLoader->doInitialization(M);
402}
403
404void MIRProfileLoaderPass::getAnalysisUsage(AnalysisUsage &AU) const {
405 AU.setPreservesAll();
406 AU.addRequired<MachineBlockFrequencyInfoWrapperPass>();
407 AU.addRequired<MachineDominatorTreeWrapperPass>();
408 AU.addRequired<MachinePostDominatorTreeWrapperPass>();
409 AU.addRequiredTransitive<MachineLoopInfoWrapperPass>();
410 AU.addRequired<MachineOptimizationRemarkEmitterPass>();
412}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
#define DEBUG_TYPE
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
static cl::opt< bool > ShowFSBranchProb("show-fs-branchprob", cl::Hidden, cl::init(false), cl::desc("Print setting flow sensitive branch probabilities"))
static cl::opt< bool > ViewBFIAfter("fs-viewbfi-after", cl::Hidden, cl::init(false), cl::desc("View BFI after MIR loader"))
static cl::opt< unsigned > FSProfileDebugBWThreshold("fs-profile-debug-bw-threshold", cl::init(10000), cl::desc("Only show debug message if the source branch weight is greater " " than this value."))
static cl::opt< unsigned > FSProfileDebugProbDiffThreshold("fs-profile-debug-prob-diff-threshold", cl::init(10), cl::desc("Only show debug message if the branch probability is greater than " "this value (in percentage)."))
static cl::opt< bool > ViewBFIBefore("fs-viewbfi-before", cl::Hidden, cl::init(false), cl::desc("View BFI before MIR loader"))
===- MachineOptimizationRemarkEmitter.h - Opt Diagnostics -*- C++ -*-—===//
#define P(N)
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
const char * Msg
This file provides the interface for the sampled PGO profile loader base implementation.
This file provides the utility functions for the sampled PGO loader base implementation.
#define LLVM_DEBUG(...)
Definition Debug.h:119
Defines the virtual file system interface vfs::FileSystem.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
void setPreservesAll()
Set by analyses that do not transform their input at all.
AnalysisUsage & addRequiredTransitive()
A debug info location.
Definition DebugLoc.h:126
Implements a dense probed hash-table based set.
Definition DenseSet.h:281
Diagnostic information for the sample profiler.
Represents either an error or a value T.
Definition ErrorOr.h:56
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:352
void compute(FunctionT &F)
Compute the cycle info for a function.
A smart pointer to a reference-counted object that inherits from RefCountedBase or ThreadSafeRefCount...
MIRProfileLoaderPass(std::string FileName="", std::string RemappingFileName="", FSDiscriminatorPass P=FSDiscriminatorPass::Pass1, IntrusiveRefCntPtr< vfs::FileSystem > FS=nullptr)
FS bits will only use the '1' bits in the Mask.
MIRProfileLoader(StringRef Name, StringRef RemapName, IntrusiveRefCntPtr< vfs::FileSystem > FS)
void setBranchProbs(MachineFunction &F)
ErrorOr< uint64_t > getInstWeight(const MachineInstr &MI) override
bool runOnFunction(MachineFunction &F)
MachineBlockFrequencyInfo * BFI
Hold the information of the basic block frequency.
FSDiscriminatorPass P
PassNum is the sequence number this pass is called, start from 1.
bool doInitialization(Module &M)
void setInitVals(MachineDominatorTree *MDT, MachinePostDominatorTree *MPDT, MachineLoopInfo *MLI, MachineBlockFrequencyInfo *MBFI, MachineOptimizationRemarkEmitter *MORE)
void setFSPass(FSDiscriminatorPass Pass)
LLVM_ABI BranchProbability getSuccProbability(const_succ_iterator Succ) const
Return probability of the edge from this block to MBB.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
LLVM_ABI void setSuccProbability(succ_iterator I, BranchProbability Prob)
Set successor probability of a given iterator.
SmallVectorImpl< MachineBasicBlock * >::iterator succ_iterator
LLVM_ABI DebugLoc findBranchDebugLoc()
Find and return the merged DebugLoc of the branch instructions of the block.
iterator_range< succ_iterator > successors()
iterator_range< pred_iterator > predecessors()
MachineBlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate machine basic b...
LLVM_ABI void view(const Twine &Name, bool isSimple=true) const
Pop up a ghostview window with the current block frequency propagation rendered using dot.
LLVM_ABI const MachineBranchProbabilityInfo * getMBPI() const
LLVM_ABI void calculate(const MachineFunction &F, const MachineBranchProbabilityInfo &MBPI, const MachineCycleInfo &MCI)
calculate - compute block frequency info for the given function.
Analysis pass which computes a MachineDominatorTree.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
Function & getFunction()
Return the LLVM function that this machine code represents.
void RenumberBlocks(MachineBasicBlock *MBBFrom=nullptr)
RenumberBlocks - This discards all of the MachineBasicBlock numbers and recomputes them.
Representation of each machine instruction.
Diagnostic information for optimization analysis remarks.
MachinePostDominatorTree - an analysis pass wrapper for DominatorTree used to compute the post-domina...
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
Pass interface - Implemented by all 'passes'.
Definition Pass.h:97
AnalysisType & getAnalysis() const
getAnalysis<AnalysisType>() - This function is used by subclasses to get to the analysis information ...
bool computeAndPropagateWeights(FunctionT &F, const DenseSet< GlobalValue::GUID > &InlinedGUIDs)
void computeDominanceAndLoopInfo(FunctionT &F)
ErrorOr< uint64_t > getInstWeightImpl(const InstructionT &Inst)
SampleProfileLoaderBaseImpl(std::string Name, std::string RemapName, IntrusiveRefCntPtr< vfs::FileSystem > FS)
virtual ErrorOr< uint64_t > getProbeWeight(const InstructionT &Inst)
std::pair< const BasicBlockT *, const BasicBlockT * > Edge
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:315
A range adaptor for a pair of iterators.
static LLVM_ABI std::atomic< bool > ProfileIsProbeBased
static LLVM_ABI ErrorOr< std::unique_ptr< SampleProfileReader > > create(StringRef Filename, LLVMContext &C, vfs::FileSystem &FS, FSDiscriminatorPass P=FSDiscriminatorPass::Base, StringRef RemapFilename="")
Create a sample profile reader appropriate to the file format.
initializer< Ty > init(const Ty &Val)
LLVM_ABI IntrusiveRefCntPtr< FileSystem > getRealFileSystem()
Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.
This is an optimization pass for GlobalISel generic memory operations.
static unsigned getFSPassBitBegin(sampleprof::FSDiscriminatorPass P)
LLVM_ABI cl::opt< bool > ImprovedFSDiscriminator
LLVM_ABI char & MIRProfileLoaderPassID
This pass reads flow sensitive profile.
static unsigned getFSPassBitEnd(sampleprof::FSDiscriminatorPass P)
LLVM_ABI std::optional< PseudoProbe > extractProbe(const Instruction &Inst)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
cl::opt< GVDAGType > ViewBlockLayoutWithBFI("view-block-layout-with-bfi", cl::Hidden, cl::desc("Pop up a window to show a dag displaying MBP layout and associated " "block frequencies of the CFG."), cl::values(clEnumValN(GVDT_None, "none", "do not display graphs."), clEnumValN(GVDT_Fraction, "fraction", "display a graph using the " "fractional block frequency representation."), clEnumValN(GVDT_Integer, "integer", "display a graph using the raw " "integer fractional block frequency representation."), clEnumValN(GVDT_Count, "count", "display a graph using the real " "profile count if available.")))
LLVM_ABI FunctionPass * createMIRProfileLoaderPass(std::string File, std::string RemappingFile, sampleprof::FSDiscriminatorPass P, IntrusiveRefCntPtr< vfs::FileSystem > FS)
Read Flow Sensitive Profile.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1933
LLVM_ABI StringRef getViewBlockFreqFuncName(const LLVMContext &C)
Return -view-bfi-func-name.
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878
#define MORE()
Definition regcomp.c:247
uint32_t Discriminator
MachineOptimizationRemarkEmitter OptRemarkEmitterT
static PredRangeT getPredecessors(MachineBasicBlock *BB)
MachineOptimizationRemarkAnalysis OptRemarkAnalysisT
iterator_range< SmallVectorImpl< MachineBasicBlock * >::iterator > SuccRangeT
static SuccRangeT getSuccessors(MachineBasicBlock *BB)
static const MachineBasicBlock * getEntryBB(const MachineFunction *F)
iterator_range< SmallVectorImpl< MachineBasicBlock * >::iterator > PredRangeT
static Function & getFunction(MachineFunction &F)