LLVM 20.0.0git
CtxProfAnalysis.cpp
Go to the documentation of this file.
1//===- CtxProfAnalysis.cpp - contextual profile analysis ------------------===//
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// Implementation of the contextual profile analysis, which maintains contextual
10// profiling info through IPO passes.
11//
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/IR/Analysis.h"
18#include "llvm/IR/Module.h"
19#include "llvm/IR/PassManager.h"
22#include "llvm/Support/JSON.h"
24
25#define DEBUG_TYPE "ctx_prof"
26
27using namespace llvm;
29 UseCtxProfile("use-ctx-profile", cl::init(""), cl::Hidden,
30 cl::desc("Use the specified contextual profile file"));
31
32namespace llvm {
33namespace json {
35 Object Ret;
36 Ret["Guid"] = P.guid();
37 Ret["Counters"] = Array(P.counters());
38 if (P.callsites().empty())
39 return Ret;
40 auto AllCS =
41 ::llvm::map_range(P.callsites(), [](const auto &P) { return P.first; });
42 auto MaxIt = ::llvm::max_element(AllCS);
43 assert(MaxIt != AllCS.end() && "We should have a max value because the "
44 "callsites collection is not empty.");
45 Array CSites;
46 // Iterate to, and including, the maximum index.
47 for (auto I = 0U, Max = *MaxIt; I <= Max; ++I) {
48 CSites.push_back(Array());
49 Array &Targets = *CSites.back().getAsArray();
50 if (P.hasCallsite(I))
51 for (const auto &[_, Ctx] : P.callsite(I))
52 Targets.push_back(toJSON(Ctx));
53 }
54 Ret["Callsites"] = std::move(CSites);
55
56 return Ret;
57}
58
60 Array Ret;
61 for (const auto &[_, Ctx] : P)
62 Ret.push_back(toJSON(Ctx));
63 return Ret;
64}
65} // namespace json
66} // namespace llvm
67
68const char *AssignGUIDPass::GUIDMetadataName = "guid";
69
71 for (auto &F : M.functions()) {
72 if (F.isDeclaration())
73 continue;
74 if (F.getMetadata(GUIDMetadataName))
75 continue;
76 const GlobalValue::GUID GUID = F.getGUID();
77 F.setMetadata(GUIDMetadataName,
78 MDNode::get(M.getContext(),
79 {ConstantAsMetadata::get(ConstantInt::get(
80 Type::getInt64Ty(M.getContext()), GUID))}));
81 }
83}
84
86 if (F.isDeclaration()) {
88 return GlobalValue::getGUID(F.getGlobalIdentifier());
89 }
90 auto *MD = F.getMetadata(GUIDMetadataName);
91 assert(MD && "guid not found for defined function");
92 return cast<ConstantInt>(cast<ConstantAsMetadata>(MD->getOperand(0))
93 ->getValue()
94 ->stripPointerCasts())
95 ->getZExtValue();
96}
98
100 : Profile(Profile.empty() ? UseCtxProfile : Profile) {}
101
105 if (auto EC = MB.getError()) {
106 M.getContext().emitError("could not open contextual profile file: " +
107 EC.message());
108 return {};
109 }
110 PGOCtxProfileReader Reader(MB.get()->getBuffer());
111 auto MaybeCtx = Reader.loadContexts();
112 if (!MaybeCtx) {
113 M.getContext().emitError("contextual profile file is invalid: " +
114 toString(MaybeCtx.takeError()));
115 return {};
116 }
117
119
120 for (const auto &F : M) {
121 if (F.isDeclaration())
122 continue;
123 auto GUID = AssignGUIDPass::getGUID(F);
124 assert(GUID && "guid not found for defined function");
125 const auto &Entry = F.begin();
126 uint32_t MaxCounters = 0; // we expect at least a counter.
127 for (const auto &I : *Entry)
128 if (auto *C = dyn_cast<InstrProfIncrementInst>(&I)) {
129 MaxCounters =
130 static_cast<uint32_t>(C->getNumCounters()->getZExtValue());
131 break;
132 }
133 if (!MaxCounters)
134 continue;
135 uint32_t MaxCallsites = 0;
136 for (const auto &BB : F)
137 for (const auto &I : BB)
138 if (auto *C = dyn_cast<InstrProfCallsite>(&I)) {
139 MaxCallsites =
140 static_cast<uint32_t>(C->getNumCounters()->getZExtValue());
141 break;
142 }
143 auto [It, Ins] = Result.FuncInfo.insert(
144 {GUID, PGOContextualProfile::FunctionInfo(F.getName())});
145 (void)Ins;
146 assert(Ins);
147 It->second.NextCallsiteIndex = MaxCallsites;
148 It->second.NextCounterIndex = MaxCounters;
149 }
150 // If we made it this far, the Result is valid - which we mark by setting
151 // .Profiles.
152 // Trim first the roots that aren't in this module.
153 DenseSet<GlobalValue::GUID> ProfiledGUIDs;
154 for (auto &[RootGuid, _] : llvm::make_early_inc_range(*MaybeCtx))
155 if (!Result.FuncInfo.contains(RootGuid))
156 MaybeCtx->erase(RootGuid);
157 Result.Profiles = std::move(*MaybeCtx);
158 return Result;
159}
160
162PGOContextualProfile::getDefinedFunctionGUID(const Function &F) const {
163 if (auto It = FuncInfo.find(AssignGUIDPass::getGUID(F)); It != FuncInfo.end())
164 return It->first;
165 return 0;
166}
167
171 if (!C) {
172 M.getContext().emitError("Invalid CtxProfAnalysis");
173 return PreservedAnalyses::all();
174 }
175
176 OS << "Function Info:\n";
177 for (const auto &[Guid, FuncInfo] : C.FuncInfo)
178 OS << Guid << " : " << FuncInfo.Name
179 << ". MaxCounterID: " << FuncInfo.NextCounterIndex
180 << ". MaxCallsiteID: " << FuncInfo.NextCallsiteIndex << "\n";
181
182 const auto JSONed = ::llvm::json::toJSON(C.profiles());
183
184 OS << "\nCurrent Profile:\n";
185 OS << formatv("{0:2}", JSONed);
186 OS << "\n";
187 OS << "\nFlat Profile:\n";
188 auto Flat = C.flatten();
189 for (const auto &[Guid, Counters] : Flat) {
190 OS << Guid << " : ";
191 for (auto V : Counters)
192 OS << V << " ";
193 OS << "\n";
194 }
195 return PreservedAnalyses::all();
196}
197
199 while (auto *Prev = CB.getPrevNode())
200 if (auto *IPC = dyn_cast<InstrProfCallsite>(Prev))
201 return IPC;
202 return nullptr;
203}
204
206 for (auto &I : BB)
207 if (auto *Incr = dyn_cast<InstrProfIncrementInst>(&I))
208 return Incr;
209 return nullptr;
210}
211
212static void
214 function_ref<void(const PGOCtxProfContext &)> Visitor) {
215 std::function<void(const PGOCtxProfContext &)> Traverser =
216 [&](const auto &Ctx) {
217 Visitor(Ctx);
218 for (const auto &[_, SubCtxSet] : Ctx.callsites())
219 for (const auto &[__, Subctx] : SubCtxSet)
220 Traverser(Subctx);
221 };
222 for (const auto &[_, P] : Profiles)
223 Traverser(P);
224}
225
227 assert(Profiles.has_value());
229 preorderVisit(*Profiles, [&](const PGOCtxProfContext &Ctx) {
230 auto [It, Ins] = Flat.insert({Ctx.guid(), {}});
231 if (Ins) {
232 llvm::append_range(It->second, Ctx.counters());
233 return;
234 }
235 assert(It->second.size() == Ctx.counters().size() &&
236 "All contexts corresponding to a function should have the exact "
237 "same number of counters.");
238 for (size_t I = 0, E = It->second.size(); I < E; ++I)
239 It->second[I] += Ctx.counters()[I];
240 });
241 return Flat;
242}
cl::opt< std::string > UseCtxProfile("use-ctx-profile", cl::init(""), cl::Hidden, cl::desc("Use the specified contextual profile file"))
static void preorderVisit(const PGOCtxProfContext::CallTargetMapTy &Profiles, function_ref< void(const PGOCtxProfContext &)> Visitor)
#define _
This file supports working with JSON data.
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
Load MIR Sample Profile
Module.h This file contains the declarations for the Module class.
#define P(N)
Reader for contextual iFDO profile, which comes in bitstream format.
ModuleAnalysisManager MAM
This header defines various interfaces for pass management in LLVM.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains some templates that are useful if you are working with the STL at all.
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:253
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:405
static uint64_t getGUID(const Function &F)
static const char * GUIDMetadataName
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
Assign a GUID if one is not already assign, as a function metadata named GUIDMetadataName.
LLVM Basic Block Representation.
Definition: BasicBlock.h:61
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Definition: InstrTypes.h:1236
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
PGOContextualProfile run(Module &M, ModuleAnalysisManager &MAM)
static InstrProfIncrementInst * getBBInstrumentation(BasicBlock &BB)
Get the instruction instrumenting a BB, or nullptr if not present.
CtxProfAnalysis(StringRef Profile="")
static InstrProfCallsite * getCallsiteInstrumentation(CallBase &CB)
Get the instruction instrumenting a callsite, or nullptr if that cannot be found.
static AnalysisKey Key
PGOContextualProfile Result
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: DenseMap.h:211
Implements a dense probed hash-table based set.
Definition: DenseSet.h:271
Represents either an error or a value T.
Definition: ErrorOr.h:56
reference get()
Definition: ErrorOr.h:149
std::error_code getError() const
Definition: ErrorOr.h:152
GUID getGUID() const
Return a 64-bit global unique ID constructed from global value name (i.e.
Definition: GlobalValue.h:595
static bool isExternalLinkage(LinkageTypes Linkage)
Definition: GlobalValue.h:376
This represents the llvm.instrprof.callsite intrinsic.
This represents the llvm.instrprof.increment intrinsic.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition: Metadata.h:1542
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
The instrumented contextual profile, produced by the CtxProfAnalysis.
const CtxProfFlatProfile flatten() const
A node (context) in the loaded contextual profile, suitable for mutation during IPO passes.
GlobalValue::GUID guid() const
const SmallVectorImpl< uint64_t > & counters() const
std::map< GlobalValue::GUID, PGOCtxProfContext > CallTargetMapTy
Expected< std::map< GlobalValue::GUID, PGOCtxProfContext > > loadContexts()
A set of analyses that are preserved following a run of a transformation pass.
Definition: Analysis.h:111
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition: Analysis.h:114
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: Analysis.h:117
size_t size() const
Definition: SmallVector.h:91
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
bool erase(const ValueT &V)
Definition: DenseSet.h:101
An efficient, type-erasing, non-owning reference to a callable.
An Array is a JSON array, which contains heterogeneous JSON values.
Definition: JSON.h:164
void push_back(const Value &E)
Definition: JSON.h:552
Value & back()
Definition: JSON.h:537
An Object is a JSON object, which maps strings to heterogenous JSON values.
Definition: JSON.h:98
A Value is an JSON value of unknown type.
Definition: JSON.h:288
const json::Array * getAsArray() const
Definition: JSON.h:468
Pass manager infrastructure for declaring and invalidating analyses.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:443
std::optional< const char * > toString(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract a string value from it.
Value toJSON(const std::optional< T > &Opt)
Definition: JSON.h:827
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto formatv(const char *Fmt, Ts &&...Vals) -> formatv_object< decltype(std::make_tuple(support::detail::build_format_adapter(std::forward< Ts >(Vals))...))>
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition: STLExtras.h:2098
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition: STLExtras.h:656
auto map_range(ContainerTy &&C, FuncTy F)
Definition: STLExtras.h:377
auto max_element(R &&Range)
Provide wrappers to std::max_element which take ranges instead of having to pass begin/end explicitly...
Definition: STLExtras.h:1997
A special type used by analysis passes to provide an address that identifies that particular analysis...
Definition: Analysis.h:28