1 | //===-- ProfiledBinary.h - Binary decoder -----------------------*- C++ -*-===// |
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 | #ifndef LLVM_TOOLS_LLVM_PROFGEN_PROFILEDBINARY_H |
10 | #define LLVM_TOOLS_LLVM_PROFGEN_PROFILEDBINARY_H |
11 | |
12 | #include "CallContext.h" |
13 | #include "ErrorHandling.h" |
14 | #include "llvm/ADT/DenseMap.h" |
15 | #include "llvm/ADT/StringRef.h" |
16 | #include "llvm/ADT/StringSet.h" |
17 | #include "llvm/DebugInfo/DWARF/DWARFContext.h" |
18 | #include "llvm/DebugInfo/Symbolize/Symbolize.h" |
19 | #include "llvm/MC/MCAsmInfo.h" |
20 | #include "llvm/MC/MCContext.h" |
21 | #include "llvm/MC/MCDisassembler/MCDisassembler.h" |
22 | #include "llvm/MC/MCInst.h" |
23 | #include "llvm/MC/MCInstPrinter.h" |
24 | #include "llvm/MC/MCInstrAnalysis.h" |
25 | #include "llvm/MC/MCInstrInfo.h" |
26 | #include "llvm/MC/MCObjectFileInfo.h" |
27 | #include "llvm/MC/MCPseudoProbe.h" |
28 | #include "llvm/MC/MCRegisterInfo.h" |
29 | #include "llvm/MC/MCSubtargetInfo.h" |
30 | #include "llvm/MC/MCTargetOptions.h" |
31 | #include "llvm/Object/ELFObjectFile.h" |
32 | #include "llvm/ProfileData/SampleProf.h" |
33 | #include "llvm/Support/CommandLine.h" |
34 | #include "llvm/Support/Path.h" |
35 | #include "llvm/Transforms/IPO/SampleContextTracker.h" |
36 | #include <map> |
37 | #include <set> |
38 | #include <sstream> |
39 | #include <string> |
40 | #include <unordered_map> |
41 | #include <unordered_set> |
42 | #include <vector> |
43 | |
44 | namespace llvm { |
45 | extern cl::opt<bool> EnableCSPreInliner; |
46 | extern cl::opt<bool> UseContextCostForPreInliner; |
47 | } // namespace llvm |
48 | |
49 | using namespace llvm; |
50 | using namespace sampleprof; |
51 | using namespace llvm::object; |
52 | |
53 | namespace llvm { |
54 | namespace sampleprof { |
55 | |
56 | class ProfiledBinary; |
57 | class MissingFrameInferrer; |
58 | |
59 | struct InstructionPointer { |
60 | const ProfiledBinary *Binary; |
61 | // Address of the executable segment of the binary. |
62 | uint64_t Address; |
63 | // Index to the sorted code address array of the binary. |
64 | uint64_t Index = 0; |
65 | InstructionPointer(const ProfiledBinary *Binary, uint64_t Address, |
66 | bool RoundToNext = false); |
67 | bool advance(); |
68 | bool backward(); |
69 | void update(uint64_t Addr); |
70 | }; |
71 | |
72 | // The special frame addresses. |
73 | enum SpecialFrameAddr { |
74 | // Dummy root of frame trie. |
75 | DummyRoot = 0, |
76 | // Represent all the addresses outside of current binary. |
77 | // This's also used to indicate the call stack should be truncated since this |
78 | // isn't a real call context the compiler will see. |
79 | ExternalAddr = 1, |
80 | }; |
81 | |
82 | using RangesTy = std::vector<std::pair<uint64_t, uint64_t>>; |
83 | |
84 | struct BinaryFunction { |
85 | StringRef FuncName; |
86 | // End of range is an exclusive bound. |
87 | RangesTy Ranges; |
88 | |
89 | uint64_t getFuncSize() { |
90 | uint64_t Sum = 0; |
91 | for (auto &R : Ranges) { |
92 | Sum += R.second - R.first; |
93 | } |
94 | return Sum; |
95 | } |
96 | }; |
97 | |
98 | // Info about function range. A function can be split into multiple |
99 | // non-continuous ranges, each range corresponds to one FuncRange. |
100 | struct FuncRange { |
101 | uint64_t StartAddress; |
102 | // EndAddress is an exclusive bound. |
103 | uint64_t EndAddress; |
104 | // Function the range belongs to |
105 | BinaryFunction *Func; |
106 | // Whether the start address is the real entry of the function. |
107 | bool IsFuncEntry = false; |
108 | |
109 | StringRef getFuncName() { return Func->FuncName; } |
110 | }; |
111 | |
112 | // PrologEpilog address tracker, used to filter out broken stack samples |
113 | // Currently we use a heuristic size (two) to infer prolog and epilog |
114 | // based on the start address and return address. In the future, |
115 | // we will switch to Dwarf CFI based tracker |
116 | struct PrologEpilogTracker { |
117 | // A set of prolog and epilog addresses. Used by virtual unwinding. |
118 | std::unordered_set<uint64_t> PrologEpilogSet; |
119 | ProfiledBinary *Binary; |
120 | PrologEpilogTracker(ProfiledBinary *Bin) : Binary(Bin){}; |
121 | |
122 | // Take the two addresses from the start of function as prolog |
123 | void |
124 | inferPrologAddresses(std::map<uint64_t, FuncRange> &FuncStartAddressMap) { |
125 | for (auto I : FuncStartAddressMap) { |
126 | PrologEpilogSet.insert(x: I.first); |
127 | InstructionPointer IP(Binary, I.first); |
128 | if (!IP.advance()) |
129 | break; |
130 | PrologEpilogSet.insert(x: IP.Address); |
131 | } |
132 | } |
133 | |
134 | // Take the last two addresses before the return address as epilog |
135 | void inferEpilogAddresses(std::unordered_set<uint64_t> &RetAddrs) { |
136 | for (auto Addr : RetAddrs) { |
137 | PrologEpilogSet.insert(x: Addr); |
138 | InstructionPointer IP(Binary, Addr); |
139 | if (!IP.backward()) |
140 | break; |
141 | PrologEpilogSet.insert(x: IP.Address); |
142 | } |
143 | } |
144 | }; |
145 | |
146 | // Track function byte size under different context (outlined version as well as |
147 | // various inlined versions). It also provides query support to get function |
148 | // size with the best matching context, which is used to help pre-inliner use |
149 | // accurate post-optimization size to make decisions. |
150 | // TODO: If an inlinee is completely optimized away, ideally we should have zero |
151 | // for its context size, currently we would misss such context since it doesn't |
152 | // have instructions. To fix this, we need to mark all inlinee with entry probe |
153 | // but without instructions as having zero size. |
154 | class BinarySizeContextTracker { |
155 | public: |
156 | // Add instruction with given size to a context |
157 | void addInstructionForContext(const SampleContextFrameVector &Context, |
158 | uint32_t InstrSize); |
159 | |
160 | // Get function size with a specific context. When there's no exact match |
161 | // for the given context, try to retrieve the size of that function from |
162 | // closest matching context. |
163 | uint32_t getFuncSizeForContext(const ContextTrieNode *Context); |
164 | |
165 | // For inlinees that are full optimized away, we can establish zero size using |
166 | // their remaining probes. |
167 | void trackInlineesOptimizedAway(MCPseudoProbeDecoder &ProbeDecoder); |
168 | |
169 | using ProbeFrameStack = SmallVector<std::pair<StringRef, uint32_t>>; |
170 | void trackInlineesOptimizedAway(MCPseudoProbeDecoder &ProbeDecoder, |
171 | MCDecodedPseudoProbeInlineTree &ProbeNode, |
172 | ProbeFrameStack &Context); |
173 | |
174 | void dump() { RootContext.dumpTree(); } |
175 | |
176 | private: |
177 | // Root node for context trie tree, node that this is a reverse context trie |
178 | // with callee as parent and caller as child. This way we can traverse from |
179 | // root to find the best/longest matching context if an exact match does not |
180 | // exist. It gives us the best possible estimate for function's post-inline, |
181 | // post-optimization byte size. |
182 | ContextTrieNode RootContext; |
183 | }; |
184 | |
185 | using AddressRange = std::pair<uint64_t, uint64_t>; |
186 | |
187 | class ProfiledBinary { |
188 | // Absolute path of the executable binary. |
189 | std::string Path; |
190 | // Path of the debug info binary. |
191 | std::string DebugBinaryPath; |
192 | // The target triple. |
193 | Triple TheTriple; |
194 | // Path of symbolizer path which should be pointed to binary with debug info. |
195 | StringRef SymbolizerPath; |
196 | // Options used to configure the symbolizer |
197 | symbolize::LLVMSymbolizer::Options SymbolizerOpts; |
198 | // The runtime base address that the first executable segment is loaded at. |
199 | uint64_t BaseAddress = 0; |
200 | // The runtime base address that the first loadabe segment is loaded at. |
201 | uint64_t FirstLoadableAddress = 0; |
202 | // The preferred load address of each executable segment. |
203 | std::vector<uint64_t> PreferredTextSegmentAddresses; |
204 | // The file offset of each executable segment. |
205 | std::vector<uint64_t> TextSegmentOffsets; |
206 | |
207 | // Mutiple MC component info |
208 | std::unique_ptr<const MCRegisterInfo> MRI; |
209 | std::unique_ptr<const MCAsmInfo> AsmInfo; |
210 | std::unique_ptr<const MCSubtargetInfo> STI; |
211 | std::unique_ptr<const MCInstrInfo> MII; |
212 | std::unique_ptr<MCDisassembler> DisAsm; |
213 | std::unique_ptr<const MCInstrAnalysis> MIA; |
214 | std::unique_ptr<MCInstPrinter> IPrinter; |
215 | // A list of text sections sorted by start RVA and size. Used to check |
216 | // if a given RVA is a valid code address. |
217 | std::set<std::pair<uint64_t, uint64_t>> TextSections; |
218 | |
219 | // A map of mapping function name to BinaryFunction info. |
220 | std::unordered_map<std::string, BinaryFunction> BinaryFunctions; |
221 | |
222 | // Lookup BinaryFunctions using the function name's MD5 hash. Needed if the |
223 | // profile is using MD5. |
224 | std::unordered_map<uint64_t, BinaryFunction *> HashBinaryFunctions; |
225 | |
226 | // A list of binary functions that have samples. |
227 | std::unordered_set<const BinaryFunction *> ProfiledFunctions; |
228 | |
229 | // GUID to Elf symbol start address map |
230 | DenseMap<uint64_t, uint64_t> SymbolStartAddrs; |
231 | |
232 | // These maps are for temporary use of warning diagnosis. |
233 | DenseSet<int64_t> AddrsWithMultipleSymbols; |
234 | DenseSet<std::pair<uint64_t, uint64_t>> AddrsWithInvalidInstruction; |
235 | |
236 | // Start address to Elf symbol GUID map |
237 | std::unordered_multimap<uint64_t, uint64_t> StartAddrToSymMap; |
238 | |
239 | // An ordered map of mapping function's start address to function range |
240 | // relevant info. Currently to determine if the offset of ELF is the start of |
241 | // a real function, we leverage the function range info from DWARF. |
242 | std::map<uint64_t, FuncRange> StartAddrToFuncRangeMap; |
243 | |
244 | // Address to context location map. Used to expand the context. |
245 | std::unordered_map<uint64_t, SampleContextFrameVector> AddressToLocStackMap; |
246 | |
247 | // Address to instruction size map. Also used for quick Address lookup. |
248 | std::unordered_map<uint64_t, uint64_t> AddressToInstSizeMap; |
249 | |
250 | // An array of Addresses of all instructions sorted in increasing order. The |
251 | // sorting is needed to fast advance to the next forward/backward instruction. |
252 | std::vector<uint64_t> CodeAddressVec; |
253 | // A set of call instruction addresses. Used by virtual unwinding. |
254 | std::unordered_set<uint64_t> CallAddressSet; |
255 | // A set of return instruction addresses. Used by virtual unwinding. |
256 | std::unordered_set<uint64_t> RetAddressSet; |
257 | // An ordered set of unconditional branch instruction addresses. |
258 | std::set<uint64_t> UncondBranchAddrSet; |
259 | // A set of branch instruction addresses. |
260 | std::unordered_set<uint64_t> BranchAddressSet; |
261 | |
262 | // Estimate and track function prolog and epilog ranges. |
263 | PrologEpilogTracker ProEpilogTracker; |
264 | |
265 | // Infer missing frames due to compiler optimizations such as tail call |
266 | // elimination. |
267 | std::unique_ptr<MissingFrameInferrer> MissingContextInferrer; |
268 | |
269 | // Track function sizes under different context |
270 | BinarySizeContextTracker FuncSizeTracker; |
271 | |
272 | // The symbolizer used to get inline context for an instruction. |
273 | std::unique_ptr<symbolize::LLVMSymbolizer> Symbolizer; |
274 | |
275 | // String table owning function name strings created from the symbolizer. |
276 | std::unordered_set<std::string> NameStrings; |
277 | |
278 | // A collection of functions to print disassembly for. |
279 | StringSet<> DisassembleFunctionSet; |
280 | |
281 | // Pseudo probe decoder |
282 | MCPseudoProbeDecoder ProbeDecoder; |
283 | |
284 | // Function name to probe frame map for top-level outlined functions. |
285 | StringMap<MCDecodedPseudoProbeInlineTree *> TopLevelProbeFrameMap; |
286 | |
287 | bool UsePseudoProbes = false; |
288 | |
289 | bool UseFSDiscriminator = false; |
290 | |
291 | // Whether we need to symbolize all instructions to get function context size. |
292 | bool TrackFuncContextSize = false; |
293 | |
294 | // Whether this is a kernel image; |
295 | bool IsKernel = false; |
296 | |
297 | // Indicate if the base loading address is parsed from the mmap event or uses |
298 | // the preferred address |
299 | bool IsLoadedByMMap = false; |
300 | // Use to avoid redundant warning. |
301 | bool MissingMMapWarned = false; |
302 | |
303 | bool IsCOFF = false; |
304 | |
305 | void setPreferredTextSegmentAddresses(const ObjectFile *O); |
306 | |
307 | template <class ELFT> |
308 | void setPreferredTextSegmentAddresses(const ELFFile<ELFT> &Obj, |
309 | StringRef FileName); |
310 | void setPreferredTextSegmentAddresses(const COFFObjectFile *Obj, |
311 | StringRef FileName); |
312 | |
313 | void checkPseudoProbe(const ELFObjectFileBase *Obj); |
314 | |
315 | void decodePseudoProbe(const ELFObjectFileBase *Obj); |
316 | |
317 | void |
318 | checkUseFSDiscriminator(const ObjectFile *Obj, |
319 | std::map<SectionRef, SectionSymbolsTy> &AllSymbols); |
320 | |
321 | // Set up disassembler and related components. |
322 | void setUpDisassembler(const ObjectFile *Obj); |
323 | symbolize::LLVMSymbolizer::Options getSymbolizerOpts() const; |
324 | |
325 | // Load debug info of subprograms from DWARF section. |
326 | void loadSymbolsFromDWARF(ObjectFile &Obj); |
327 | |
328 | // Load debug info from DWARF unit. |
329 | void loadSymbolsFromDWARFUnit(DWARFUnit &CompilationUnit); |
330 | |
331 | // Create elf symbol to its start address mapping. |
332 | void populateElfSymbolAddressList(const ELFObjectFileBase *O); |
333 | |
334 | // A function may be spilt into multiple non-continuous address ranges. We use |
335 | // this to set whether start a function range is the real entry of the |
336 | // function and also set false to the non-function label. |
337 | void setIsFuncEntry(FuncRange *FRange, StringRef RangeSymName); |
338 | |
339 | // Warn if no entry range exists in the function. |
340 | void warnNoFuncEntry(); |
341 | |
342 | /// Dissassemble the text section and build various address maps. |
343 | void disassemble(const ObjectFile *O); |
344 | |
345 | /// Helper function to dissassemble the symbol and extract info for unwinding |
346 | bool dissassembleSymbol(std::size_t SI, ArrayRef<uint8_t> Bytes, |
347 | SectionSymbolsTy &Symbols, const SectionRef &Section); |
348 | /// Symbolize a given instruction pointer and return a full call context. |
349 | SampleContextFrameVector symbolize(const InstructionPointer &IP, |
350 | bool UseCanonicalFnName = false, |
351 | bool UseProbeDiscriminator = false); |
352 | /// Decode the interesting parts of the binary and build internal data |
353 | /// structures. On high level, the parts of interest are: |
354 | /// 1. Text sections, including the main code section and the PLT |
355 | /// entries that will be used to handle cross-module call transitions. |
356 | /// 2. The .debug_line section, used by Dwarf-based profile generation. |
357 | /// 3. Pseudo probe related sections, used by probe-based profile |
358 | /// generation. |
359 | void load(); |
360 | |
361 | public: |
362 | ProfiledBinary(const StringRef ExeBinPath, const StringRef DebugBinPath); |
363 | ~ProfiledBinary(); |
364 | |
365 | void decodePseudoProbe(); |
366 | |
367 | StringRef getPath() const { return Path; } |
368 | StringRef getName() const { return llvm::sys::path::filename(path: Path); } |
369 | uint64_t getBaseAddress() const { return BaseAddress; } |
370 | void setBaseAddress(uint64_t Address) { BaseAddress = Address; } |
371 | |
372 | bool isCOFF() const { return IsCOFF; } |
373 | |
374 | // Canonicalize to use preferred load address as base address. |
375 | uint64_t canonicalizeVirtualAddress(uint64_t Address) { |
376 | return Address - BaseAddress + getPreferredBaseAddress(); |
377 | } |
378 | // Return the preferred load address for the first executable segment. |
379 | uint64_t getPreferredBaseAddress() const { |
380 | return PreferredTextSegmentAddresses[0]; |
381 | } |
382 | // Return the preferred load address for the first loadable segment. |
383 | uint64_t getFirstLoadableAddress() const { return FirstLoadableAddress; } |
384 | // Return the file offset for the first executable segment. |
385 | uint64_t getTextSegmentOffset() const { return TextSegmentOffsets[0]; } |
386 | const std::vector<uint64_t> &getPreferredTextSegmentAddresses() const { |
387 | return PreferredTextSegmentAddresses; |
388 | } |
389 | const std::vector<uint64_t> &getTextSegmentOffsets() const { |
390 | return TextSegmentOffsets; |
391 | } |
392 | |
393 | uint64_t getInstSize(uint64_t Address) const { |
394 | auto I = AddressToInstSizeMap.find(x: Address); |
395 | if (I == AddressToInstSizeMap.end()) |
396 | return 0; |
397 | return I->second; |
398 | } |
399 | |
400 | bool addressIsCode(uint64_t Address) const { |
401 | return AddressToInstSizeMap.find(x: Address) != AddressToInstSizeMap.end(); |
402 | } |
403 | |
404 | bool addressIsCall(uint64_t Address) const { |
405 | return CallAddressSet.count(x: Address); |
406 | } |
407 | bool addressIsReturn(uint64_t Address) const { |
408 | return RetAddressSet.count(x: Address); |
409 | } |
410 | bool addressInPrologEpilog(uint64_t Address) const { |
411 | return ProEpilogTracker.PrologEpilogSet.count(x: Address); |
412 | } |
413 | |
414 | bool addressIsTransfer(uint64_t Address) { |
415 | return BranchAddressSet.count(x: Address) || RetAddressSet.count(x: Address) || |
416 | CallAddressSet.count(x: Address); |
417 | } |
418 | |
419 | bool rangeCrossUncondBranch(uint64_t Start, uint64_t End) { |
420 | if (Start >= End) |
421 | return false; |
422 | auto R = UncondBranchAddrSet.lower_bound(x: Start); |
423 | return R != UncondBranchAddrSet.end() && *R < End; |
424 | } |
425 | |
426 | uint64_t getAddressforIndex(uint64_t Index) const { |
427 | return CodeAddressVec[Index]; |
428 | } |
429 | |
430 | size_t getCodeAddrVecSize() const { return CodeAddressVec.size(); } |
431 | |
432 | bool usePseudoProbes() const { return UsePseudoProbes; } |
433 | bool useFSDiscriminator() const { return UseFSDiscriminator; } |
434 | bool isKernel() const { return IsKernel; } |
435 | |
436 | static bool isKernelImageName(StringRef BinaryName) { |
437 | return BinaryName == "[kernel.kallsyms]" || |
438 | BinaryName == "[kernel.kallsyms]_stext" || |
439 | BinaryName == "[kernel.kallsyms]_text" ; |
440 | } |
441 | |
442 | // Get the index in CodeAddressVec for the address |
443 | // As we might get an address which is not the code |
444 | // here it would round to the next valid code address by |
445 | // using lower bound operation |
446 | uint32_t getIndexForAddr(uint64_t Address) const { |
447 | auto Low = llvm::lower_bound(Range: CodeAddressVec, Value&: Address); |
448 | return Low - CodeAddressVec.begin(); |
449 | } |
450 | |
451 | uint64_t getCallAddrFromFrameAddr(uint64_t FrameAddr) const { |
452 | if (FrameAddr == ExternalAddr) |
453 | return ExternalAddr; |
454 | auto I = getIndexForAddr(Address: FrameAddr); |
455 | FrameAddr = I ? getAddressforIndex(Index: I - 1) : 0; |
456 | if (FrameAddr && addressIsCall(Address: FrameAddr)) |
457 | return FrameAddr; |
458 | return 0; |
459 | } |
460 | |
461 | FuncRange *findFuncRangeForStartAddr(uint64_t Address) { |
462 | auto I = StartAddrToFuncRangeMap.find(x: Address); |
463 | if (I == StartAddrToFuncRangeMap.end()) |
464 | return nullptr; |
465 | return &I->second; |
466 | } |
467 | |
468 | // Binary search the function range which includes the input address. |
469 | FuncRange *findFuncRange(uint64_t Address) { |
470 | auto I = StartAddrToFuncRangeMap.upper_bound(x: Address); |
471 | if (I == StartAddrToFuncRangeMap.begin()) |
472 | return nullptr; |
473 | I--; |
474 | |
475 | if (Address >= I->second.EndAddress) |
476 | return nullptr; |
477 | |
478 | return &I->second; |
479 | } |
480 | |
481 | // Get all ranges of one function. |
482 | RangesTy getRanges(uint64_t Address) { |
483 | auto *FRange = findFuncRange(Address); |
484 | // Ignore the range which falls into plt section or system lib. |
485 | if (!FRange) |
486 | return RangesTy(); |
487 | |
488 | return FRange->Func->Ranges; |
489 | } |
490 | |
491 | const std::unordered_map<std::string, BinaryFunction> & |
492 | getAllBinaryFunctions() { |
493 | return BinaryFunctions; |
494 | } |
495 | |
496 | std::unordered_set<const BinaryFunction *> &getProfiledFunctions() { |
497 | return ProfiledFunctions; |
498 | } |
499 | |
500 | void setProfiledFunctions(std::unordered_set<const BinaryFunction *> &Funcs) { |
501 | ProfiledFunctions = Funcs; |
502 | } |
503 | |
504 | BinaryFunction *getBinaryFunction(FunctionId FName) { |
505 | if (FName.isStringRef()) { |
506 | auto I = BinaryFunctions.find(x: FName.str()); |
507 | if (I == BinaryFunctions.end()) |
508 | return nullptr; |
509 | return &I->second; |
510 | } |
511 | auto I = HashBinaryFunctions.find(x: FName.getHashCode()); |
512 | if (I == HashBinaryFunctions.end()) |
513 | return nullptr; |
514 | return I->second; |
515 | } |
516 | |
517 | uint32_t getFuncSizeForContext(const ContextTrieNode *ContextNode) { |
518 | return FuncSizeTracker.getFuncSizeForContext(Context: ContextNode); |
519 | } |
520 | |
521 | void inferMissingFrames(const SmallVectorImpl<uint64_t> &Context, |
522 | SmallVectorImpl<uint64_t> &NewContext); |
523 | |
524 | // Load the symbols from debug table and populate into symbol list. |
525 | void populateSymbolListFromDWARF(ProfileSymbolList &SymbolList); |
526 | |
527 | SampleContextFrameVector |
528 | getFrameLocationStack(uint64_t Address, bool UseProbeDiscriminator = false) { |
529 | InstructionPointer IP(this, Address); |
530 | return symbolize(IP, UseCanonicalFnName: SymbolizerOpts.UseSymbolTable, UseProbeDiscriminator); |
531 | } |
532 | |
533 | const SampleContextFrameVector & |
534 | getCachedFrameLocationStack(uint64_t Address, |
535 | bool UseProbeDiscriminator = false) { |
536 | auto I = AddressToLocStackMap.emplace(args&: Address, args: SampleContextFrameVector()); |
537 | if (I.second) { |
538 | I.first->second = getFrameLocationStack(Address, UseProbeDiscriminator); |
539 | } |
540 | return I.first->second; |
541 | } |
542 | |
543 | std::optional<SampleContextFrame> getInlineLeafFrameLoc(uint64_t Address) { |
544 | const auto &Stack = getCachedFrameLocationStack(Address); |
545 | if (Stack.empty()) |
546 | return {}; |
547 | return Stack.back(); |
548 | } |
549 | |
550 | void flushSymbolizer() { Symbolizer.reset(); } |
551 | |
552 | MissingFrameInferrer *getMissingContextInferrer() { |
553 | return MissingContextInferrer.get(); |
554 | } |
555 | |
556 | // Compare two addresses' inline context |
557 | bool inlineContextEqual(uint64_t Add1, uint64_t Add2); |
558 | |
559 | // Get the full context of the current stack with inline context filled in. |
560 | // It will search the disassembling info stored in AddressToLocStackMap. This |
561 | // is used as the key of function sample map |
562 | SampleContextFrameVector |
563 | getExpandedContext(const SmallVectorImpl<uint64_t> &Stack, |
564 | bool &WasLeafInlined); |
565 | // Go through instructions among the given range and record its size for the |
566 | // inline context. |
567 | void computeInlinedContextSizeForRange(uint64_t StartAddress, |
568 | uint64_t EndAddress); |
569 | |
570 | void computeInlinedContextSizeForFunc(const BinaryFunction *Func); |
571 | |
572 | const MCDecodedPseudoProbe *getCallProbeForAddr(uint64_t Address) const { |
573 | return ProbeDecoder.getCallProbeForAddr(Address); |
574 | } |
575 | |
576 | void getInlineContextForProbe(const MCDecodedPseudoProbe *Probe, |
577 | SampleContextFrameVector &InlineContextStack, |
578 | bool IncludeLeaf = false) const { |
579 | SmallVector<MCPseudoProbeFrameLocation, 16> ProbeInlineContext; |
580 | ProbeDecoder.getInlineContextForProbe(Probe, InlineContextStack&: ProbeInlineContext, |
581 | IncludeLeaf); |
582 | for (uint32_t I = 0; I < ProbeInlineContext.size(); I++) { |
583 | auto &Callsite = ProbeInlineContext[I]; |
584 | // Clear the current context for an unknown probe. |
585 | if (Callsite.second == 0 && I != ProbeInlineContext.size() - 1) { |
586 | InlineContextStack.clear(); |
587 | continue; |
588 | } |
589 | InlineContextStack.emplace_back(Args: FunctionId(Callsite.first), |
590 | Args: LineLocation(Callsite.second, 0)); |
591 | } |
592 | } |
593 | const AddressProbesMap &getAddress2ProbesMap() const { |
594 | return ProbeDecoder.getAddress2ProbesMap(); |
595 | } |
596 | const MCPseudoProbeFuncDesc *getFuncDescForGUID(uint64_t GUID) { |
597 | return ProbeDecoder.getFuncDescForGUID(GUID); |
598 | } |
599 | |
600 | const MCPseudoProbeFuncDesc * |
601 | getInlinerDescForProbe(const MCDecodedPseudoProbe *Probe) { |
602 | return ProbeDecoder.getInlinerDescForProbe(Probe); |
603 | } |
604 | |
605 | bool getTrackFuncContextSize() { return TrackFuncContextSize; } |
606 | |
607 | bool getIsLoadedByMMap() { return IsLoadedByMMap; } |
608 | |
609 | void setIsLoadedByMMap(bool Value) { IsLoadedByMMap = Value; } |
610 | |
611 | bool getMissingMMapWarned() { return MissingMMapWarned; } |
612 | |
613 | void setMissingMMapWarned(bool Value) { MissingMMapWarned = Value; } |
614 | }; |
615 | |
616 | } // end namespace sampleprof |
617 | } // end namespace llvm |
618 | |
619 | #endif |
620 | |