xref: /llvm-project/llvm/include/llvm/MC/MCPseudoProbe.h (revision 7ec682b16b49c754d5b4aa6347f8f5a00bd7dd78)
1 //===- MCPseudoProbe.h - Pseudo probe encoding support ---------*- 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 // This file contains the declaration of the MCPseudoProbe to support the pseudo
10 // probe encoding for AutoFDO. Pseudo probes together with their inline context
11 // are encoded in a DFS recursive way in the .pseudoprobe sections. For each
12 // .pseudoprobe section, the encoded binary data consist of a single or mutiple
13 // function records each for one outlined function. A function record has the
14 // following format :
15 //
16 // FUNCTION BODY (one for each outlined function present in the text section)
17 //    GUID (uint64)
18 //        GUID of the function's source name which may be different from the
19 //        actual binary linkage name. This GUID will be used to decode and
20 //        generate a profile against the source function name.
21 //    NPROBES (ULEB128)
22 //        Number of probes originating from this function.
23 //    NUM_INLINED_FUNCTIONS (ULEB128)
24 //        Number of callees inlined into this function, aka number of
25 //        first-level inlinees
26 //    PROBE RECORDS
27 //        A list of NPROBES entries. Each entry contains:
28 //          INDEX (ULEB128)
29 //          TYPE (uint4)
30 //            0 - block probe, 1 - indirect call, 2 - direct call
31 //          ATTRIBUTE (uint3)
32 //            1 - reserved
33 //            2 - Sentinel
34 //            4 - HasDiscriminator
35 //          ADDRESS_TYPE (uint1)
36 //            0 - code address for regular probes (for downwards compatibility)
37 //              - GUID of linkage name for sentinel probes
38 //            1 - address delta
39 //          CODE_ADDRESS (uint64 or ULEB128)
40 //            code address or address delta, depending on ADDRESS_TYPE
41 //          DISCRIMINATOR (ULEB128) if HasDiscriminator
42 //    INLINED FUNCTION RECORDS
43 //        A list of NUM_INLINED_FUNCTIONS entries describing each of the inlined
44 //        callees.  Each record contains:
45 //          INLINE SITE
46 //            ID of the callsite probe (ULEB128)
47 //          FUNCTION BODY
48 //            A FUNCTION BODY entry describing the inlined function.
49 //
50 // TODO: retire the ADDRESS_TYPE encoding for code addresses once compatibility
51 // is no longer an issue.
52 //===----------------------------------------------------------------------===//
53 
54 #ifndef LLVM_MC_MCPSEUDOPROBE_H
55 #define LLVM_MC_MCPSEUDOPROBE_H
56 
57 #include "llvm/ADT/ArrayRef.h"
58 #include "llvm/ADT/DenseMap.h"
59 #include "llvm/ADT/DenseSet.h"
60 #include "llvm/ADT/SmallVector.h"
61 #include "llvm/ADT/StringRef.h"
62 #include "llvm/ADT/iterator.h"
63 #include "llvm/IR/PseudoProbe.h"
64 #include "llvm/Support/Allocator.h"
65 #include "llvm/Support/ErrorOr.h"
66 #include <functional>
67 #include <memory>
68 #include <string>
69 #include <tuple>
70 #include <type_traits>
71 #include <unordered_map>
72 #include <vector>
73 
74 namespace llvm {
75 
76 class MCSymbol;
77 class MCObjectStreamer;
78 class raw_ostream;
79 
80 enum class MCPseudoProbeFlag {
81   // If set, indicates that the probe is encoded as an address delta
82   // instead of a real code address.
83   AddressDelta = 0x1,
84 };
85 
86 // Function descriptor decoded from .pseudo_probe_desc section
87 struct MCPseudoProbeFuncDesc {
88   uint64_t FuncGUID = 0;
89   uint64_t FuncHash = 0;
90   StringRef FuncName;
91 
92   MCPseudoProbeFuncDesc(uint64_t GUID, uint64_t Hash, StringRef Name)
93       : FuncGUID(GUID), FuncHash(Hash), FuncName(Name){};
94 
95   void print(raw_ostream &OS);
96 };
97 
98 class MCDecodedPseudoProbe;
99 
100 // An inline frame has the form <CalleeGuid, ProbeID>
101 using InlineSite = std::tuple<uint64_t, uint32_t>;
102 using MCPseudoProbeInlineStack = SmallVector<InlineSite, 8>;
103 // GUID to PseudoProbeFuncDesc map
104 class GUIDProbeFunctionMap : public std::vector<MCPseudoProbeFuncDesc> {
105 public:
106   auto find(uint64_t GUID) const {
107     auto CompareDesc = [](const MCPseudoProbeFuncDesc &Desc, uint64_t GUID) {
108       return Desc.FuncGUID < GUID;
109     };
110     auto It = llvm::lower_bound(*this, GUID, CompareDesc);
111     if (It->FuncGUID != GUID)
112       return end();
113     return It;
114   }
115 };
116 
117 class MCDecodedPseudoProbeInlineTree;
118 
119 class MCPseudoProbeBase {
120 protected:
121   uint32_t Index;
122   uint32_t Discriminator;
123   uint8_t Attributes;
124   uint8_t Type;
125   // The value should be equal to PseudoProbeReservedId::Last + 1 which is
126   // defined in SampleProfileProbe.h. The header file is not included here to
127   // reduce the dependency from MC to IPO.
128   const static uint32_t PseudoProbeFirstId = 1;
129 
130 public:
131   MCPseudoProbeBase(uint64_t I, uint64_t At, uint8_t T, uint32_t D)
132       : Index(I), Discriminator(D), Attributes(At), Type(T) {}
133 
134   bool isEntry() const { return Index == PseudoProbeFirstId; }
135 
136   uint32_t getIndex() const { return Index; }
137 
138   uint32_t getDiscriminator() const { return Discriminator; }
139 
140   uint8_t getAttributes() const { return Attributes; }
141 
142   uint8_t getType() const { return Type; }
143 
144   bool isBlock() const {
145     return Type == static_cast<uint8_t>(PseudoProbeType::Block);
146   }
147 
148   bool isIndirectCall() const {
149     return Type == static_cast<uint8_t>(PseudoProbeType::IndirectCall);
150   }
151 
152   bool isDirectCall() const {
153     return Type == static_cast<uint8_t>(PseudoProbeType::DirectCall);
154   }
155 
156   bool isCall() const { return isIndirectCall() || isDirectCall(); }
157 
158   void setAttributes(uint8_t Attr) { Attributes = Attr; }
159 };
160 
161 /// Instances of this class represent a pseudo probe instance for a pseudo probe
162 /// table entry, which is created during a machine instruction is assembled and
163 /// uses an address from a temporary label created at the current address in the
164 /// current section.
165 class MCPseudoProbe : public MCPseudoProbeBase {
166   uint64_t Guid;
167   MCSymbol *Label;
168 
169 public:
170   MCPseudoProbe(MCSymbol *Label, uint64_t Guid, uint64_t Index, uint64_t Type,
171                 uint64_t Attributes, uint32_t Discriminator)
172       : MCPseudoProbeBase(Index, Attributes, Type, Discriminator), Guid(Guid),
173         Label(Label) {
174     assert(Type <= 0xFF && "Probe type too big to encode, exceeding 2^8");
175     assert(Attributes <= 0xFF &&
176            "Probe attributes too big to encode, exceeding 2^16");
177   }
178 
179   uint64_t getGuid() const { return Guid; };
180   MCSymbol *getLabel() const { return Label; }
181   void emit(MCObjectStreamer *MCOS, const MCPseudoProbe *LastProbe) const;
182 };
183 
184 // Represents a callsite with caller function name and probe id
185 using MCPseudoProbeFrameLocation = std::pair<StringRef, uint32_t>;
186 
187 class MCDecodedPseudoProbe : public MCPseudoProbeBase {
188   uint64_t Address;
189   MCDecodedPseudoProbeInlineTree *InlineTree;
190 
191 public:
192   MCDecodedPseudoProbe(uint64_t Ad, uint32_t I, PseudoProbeType K, uint8_t At,
193                        uint32_t D, MCDecodedPseudoProbeInlineTree *Tree)
194       : MCPseudoProbeBase(I, At, static_cast<uint8_t>(K), D), Address(Ad),
195         InlineTree(Tree){};
196   uint64_t getGuid() const;
197 
198   uint64_t getAddress() const { return Address; }
199 
200   void setAddress(uint64_t Addr) { Address = Addr; }
201 
202   MCDecodedPseudoProbeInlineTree *getInlineTreeNode() const {
203     return InlineTree;
204   }
205 
206   // Get the inlined context by traversing current inline tree backwards,
207   // each tree node has its InlineSite which is taken as the context.
208   // \p ContextStack is populated in root to leaf order
209   void
210   getInlineContext(SmallVectorImpl<MCPseudoProbeFrameLocation> &ContextStack,
211                    const GUIDProbeFunctionMap &GUID2FuncMAP) const;
212 
213   // Helper function to get the string from context stack
214   std::string
215   getInlineContextStr(const GUIDProbeFunctionMap &GUID2FuncMAP) const;
216 
217   // Print pseudo probe while disassembling
218   void print(raw_ostream &OS, const GUIDProbeFunctionMap &GUID2FuncMAP,
219              bool ShowName) const;
220 };
221 
222 // Address to pseudo probes map.
223 class AddressProbesMap
224     : public std::vector<std::reference_wrapper<MCDecodedPseudoProbe>> {
225   auto getIt(uint64_t Addr) const {
226     auto CompareProbe = [](const MCDecodedPseudoProbe &Probe, uint64_t Addr) {
227       return Probe.getAddress() < Addr;
228     };
229     return llvm::lower_bound(*this, Addr, CompareProbe);
230   }
231 
232 public:
233   // Returns range of probes within [\p From, \p To) address range.
234   auto find(uint64_t From, uint64_t To) const {
235     return llvm::make_range(getIt(From), getIt(To));
236   }
237   // Returns range of probes with given \p Address.
238   auto find(uint64_t Address) const {
239     auto FromIt = getIt(Address);
240     if (FromIt == end() || FromIt->get().getAddress() != Address)
241       return llvm::make_range(end(), end());
242     auto ToIt = getIt(Address + 1);
243     return llvm::make_range(FromIt, ToIt);
244   }
245 };
246 
247 template <typename ProbesType, typename DerivedProbeInlineTreeType,
248           typename InlinedProbeTreeMap>
249 class MCPseudoProbeInlineTreeBase {
250 protected:
251   // Track children (e.g. inlinees) of current context
252   InlinedProbeTreeMap Children;
253   // Set of probes that come with the function.
254   ProbesType Probes;
255   MCPseudoProbeInlineTreeBase() {
256     static_assert(std::is_base_of<MCPseudoProbeInlineTreeBase,
257                                   DerivedProbeInlineTreeType>::value,
258                   "DerivedProbeInlineTreeType must be subclass of "
259                   "MCPseudoProbeInlineTreeBase");
260   }
261 
262 public:
263   uint64_t Guid = 0;
264 
265   // Root node has a GUID 0.
266   bool isRoot() const { return Guid == 0; }
267   InlinedProbeTreeMap &getChildren() { return Children; }
268   const InlinedProbeTreeMap &getChildren() const { return Children; }
269   const ProbesType &getProbes() const { return Probes; }
270   // Caller node of the inline site
271   MCPseudoProbeInlineTreeBase<ProbesType, DerivedProbeInlineTreeType,
272                               InlinedProbeTreeMap> *Parent = nullptr;
273   DerivedProbeInlineTreeType *getOrAddNode(const InlineSite &Site) {
274     auto Ret = Children.emplace(
275         Site, std::make_unique<DerivedProbeInlineTreeType>(Site));
276     Ret.first->second->Parent = this;
277     return Ret.first->second.get();
278   };
279 };
280 
281 // A Tri-tree based data structure to group probes by inline stack.
282 // A tree is allocated for a standalone .text section. A fake
283 // instance is created as the root of a tree.
284 // A real instance of this class is created for each function, either a
285 // not inlined function that has code in .text section or an inlined function.
286 struct InlineSiteHash {
287   uint64_t operator()(const InlineSite &Site) const {
288     return std::get<0>(Site) ^ std::get<1>(Site);
289   }
290 };
291 class MCPseudoProbeInlineTree
292     : public MCPseudoProbeInlineTreeBase<
293           std::vector<MCPseudoProbe>, MCPseudoProbeInlineTree,
294           std::unordered_map<InlineSite,
295                              std::unique_ptr<MCPseudoProbeInlineTree>,
296                              InlineSiteHash>> {
297 public:
298   MCPseudoProbeInlineTree() = default;
299   MCPseudoProbeInlineTree(uint64_t Guid) { this->Guid = Guid; }
300   MCPseudoProbeInlineTree(const InlineSite &Site) {
301     this->Guid = std::get<0>(Site);
302   }
303 
304   // MCPseudoProbeInlineTree method based on Inlinees
305   void addPseudoProbe(const MCPseudoProbe &Probe,
306                       const MCPseudoProbeInlineStack &InlineStack);
307   void emit(MCObjectStreamer *MCOS, const MCPseudoProbe *&LastProbe);
308 };
309 
310 // inline tree node for the decoded pseudo probe
311 class MCDecodedPseudoProbeInlineTree
312     : public MCPseudoProbeInlineTreeBase<
313           MCDecodedPseudoProbe *, MCDecodedPseudoProbeInlineTree,
314           MutableArrayRef<MCDecodedPseudoProbeInlineTree>> {
315   uint32_t NumProbes = 0;
316   uint32_t ProbeId = 0;
317 
318 public:
319   MCDecodedPseudoProbeInlineTree() = default;
320   MCDecodedPseudoProbeInlineTree(const InlineSite &Site,
321                                  MCDecodedPseudoProbeInlineTree *Parent)
322       : ProbeId(std::get<1>(Site)) {
323     this->Guid = std::get<0>(Site);
324     this->Parent = Parent;
325   }
326 
327   // Return false if it's a dummy inline site
328   bool hasInlineSite() const { return !isRoot() && !Parent->isRoot(); }
329   InlineSite getInlineSite() const { return InlineSite(Guid, ProbeId); }
330   void setProbes(MutableArrayRef<MCDecodedPseudoProbe> ProbesRef) {
331     Probes = ProbesRef.data();
332     NumProbes = ProbesRef.size();
333   }
334   auto getProbes() const {
335     return MutableArrayRef<MCDecodedPseudoProbe>(Probes, NumProbes);
336   }
337 };
338 
339 /// Instances of this class represent the pseudo probes inserted into a compile
340 /// unit.
341 class MCPseudoProbeSections {
342 public:
343   void addPseudoProbe(MCSymbol *FuncSym, const MCPseudoProbe &Probe,
344                       const MCPseudoProbeInlineStack &InlineStack) {
345     MCProbeDivisions[FuncSym].addPseudoProbe(Probe, InlineStack);
346   }
347 
348   // The addresses of MCPseudoProbeInlineTree are used by the tree structure and
349   // need to be stable.
350   using MCProbeDivisionMap = std::unordered_map<MCSymbol *, MCPseudoProbeInlineTree>;
351 
352 private:
353   // A collection of MCPseudoProbe for each function. The MCPseudoProbes are
354   // grouped by GUIDs due to inlining that can bring probes from different
355   // functions into one function.
356   MCProbeDivisionMap MCProbeDivisions;
357 
358 public:
359   const MCProbeDivisionMap &getMCProbes() const { return MCProbeDivisions; }
360 
361   bool empty() const { return MCProbeDivisions.empty(); }
362 
363   void emit(MCObjectStreamer *MCOS);
364 };
365 
366 class MCPseudoProbeTable {
367   // A collection of MCPseudoProbe in the current module grouped by
368   // functions. MCPseudoProbes will be encoded into a corresponding
369   // .pseudoprobe section. With functions emitted as separate comdats,
370   // a text section really only contains the code of a function solely, and the
371   // probes associated with the text section will be emitted into a standalone
372   // .pseudoprobe section that shares the same comdat group with the function.
373   MCPseudoProbeSections MCProbeSections;
374 
375 public:
376   static void emit(MCObjectStreamer *MCOS);
377 
378   MCPseudoProbeSections &getProbeSections() { return MCProbeSections; }
379 
380 #ifndef NDEBUG
381   static int DdgPrintIndent;
382 #endif
383 };
384 
385 class MCPseudoProbeDecoder {
386   // Decoded pseudo probes vector.
387   std::vector<MCDecodedPseudoProbe> PseudoProbeVec;
388   // Injected pseudo probes, identified by the containing inline tree node.
389   // Need to keep injected probes separately for two reasons:
390   // 1) Probes cannot be added to the PseudoProbeVec: appending may cause
391   //    reallocation so that pointers to its elements will become invalid.
392   // 2) Probes belonging to function record must be contiguous in PseudoProbeVec
393   //    as owning InlineTree references them with an ArrayRef to save space.
394   std::unordered_map<const MCDecodedPseudoProbeInlineTree *,
395                      std::vector<MCDecodedPseudoProbe>>
396       InjectedProbeMap;
397   // Decoded inline records vector.
398   std::vector<MCDecodedPseudoProbeInlineTree> InlineTreeVec;
399 
400   // GUID to PseudoProbeFuncDesc map.
401   GUIDProbeFunctionMap GUID2FuncDescMap;
402 
403   BumpPtrAllocator FuncNameAllocator;
404 
405   // Address to probes map.
406   AddressProbesMap Address2ProbesMap;
407 
408   // The dummy root of the inline trie, all the outlined function will directly
409   // be the children of the dummy root, all the inlined function will be the
410   // children of its inlineer. So the relation would be like:
411   // DummyRoot --> OutlinedFunc --> InlinedFunc1 --> InlinedFunc2
412   MCDecodedPseudoProbeInlineTree DummyInlineRoot;
413 
414   /// Points to the current location in the buffer.
415   const uint8_t *Data = nullptr;
416 
417   /// Points to the end of the buffer.
418   const uint8_t *End = nullptr;
419 
420   /// Whether encoding is based on a starting probe with absolute code address.
421   bool EncodingIsAddrBased = false;
422 
423   // Decoding helper function
424   template <typename T> ErrorOr<T> readUnencodedNumber();
425   template <typename T> ErrorOr<T> readUnsignedNumber();
426   template <typename T> ErrorOr<T> readSignedNumber();
427   ErrorOr<StringRef> readString(uint32_t Size);
428 
429 public:
430   using Uint64Set = DenseSet<uint64_t>;
431   using Uint64Map = DenseMap<uint64_t, uint64_t>;
432 
433   // Decode pseudo_probe_desc section to build GUID to PseudoProbeFuncDesc map.
434   // If pseudo_probe_desc section is mapped to memory and \p IsMMapped is true,
435   // uses StringRefs pointing to the section.
436   bool buildGUID2FuncDescMap(const uint8_t *Start, std::size_t Size,
437                              bool IsMMapped = false);
438 
439   // Decode pseudo_probe section to count the number of probes and inlined
440   // function records for each function record.
441   template <bool IsTopLevelFunc>
442   bool countRecords(bool &Discard, uint32_t &ProbeCount, uint32_t &InlinedCount,
443                     const Uint64Set &GuidFilter);
444 
445   // Decode pseudo_probe section to build address to probes map for specifed
446   // functions only.
447   bool buildAddress2ProbeMap(const uint8_t *Start, std::size_t Size,
448                              const Uint64Set &GuildFilter,
449                              const Uint64Map &FuncStartAddrs);
450 
451   // Print pseudo_probe_desc section info
452   void printGUID2FuncDescMap(raw_ostream &OS);
453 
454   // Print pseudo_probe section info, used along with show-disassembly
455   void printProbeForAddress(raw_ostream &OS, uint64_t Address);
456 
457   // do printProbeForAddress for all addresses
458   void printProbesForAllAddresses(raw_ostream &OS);
459 
460   // Look up the probe of a call for the input address
461   const MCDecodedPseudoProbe *getCallProbeForAddr(uint64_t Address) const;
462 
463   const MCPseudoProbeFuncDesc *getFuncDescForGUID(uint64_t GUID) const;
464 
465   // Helper function to populate one probe's inline stack into
466   // \p InlineContextStack.
467   // Current leaf location info will be added if IncludeLeaf is true
468   // Example:
469   //  Current probe(bar:3) inlined at foo:2 then inlined at main:1
470   //  IncludeLeaf = true,  Output: [main:1, foo:2, bar:3]
471   //  IncludeLeaf = false, Output: [main:1, foo:2]
472   void getInlineContextForProbe(
473       const MCDecodedPseudoProbe *Probe,
474       SmallVectorImpl<MCPseudoProbeFrameLocation> &InlineContextStack,
475       bool IncludeLeaf) const;
476 
477   const AddressProbesMap &getAddress2ProbesMap() const {
478     return Address2ProbesMap;
479   }
480 
481   AddressProbesMap &getAddress2ProbesMap() { return Address2ProbesMap; }
482 
483   const GUIDProbeFunctionMap &getGUID2FuncDescMap() const {
484     return GUID2FuncDescMap;
485   }
486 
487   const MCPseudoProbeFuncDesc *
488   getInlinerDescForProbe(const MCDecodedPseudoProbe *Probe) const;
489 
490   const MCDecodedPseudoProbeInlineTree &getDummyInlineRoot() const {
491     return DummyInlineRoot;
492   }
493 
494   void addInjectedProbe(const MCDecodedPseudoProbe &Probe, uint64_t Address) {
495     const MCDecodedPseudoProbeInlineTree *Parent = Probe.getInlineTreeNode();
496     InjectedProbeMap[Parent].emplace_back(Probe).setAddress(Address);
497   }
498 
499   size_t
500   getNumInjectedProbes(const MCDecodedPseudoProbeInlineTree *Parent) const {
501     auto It = InjectedProbeMap.find(Parent);
502     if (It == InjectedProbeMap.end())
503       return 0;
504     return It->second.size();
505   }
506 
507   auto getInjectedProbes(MCDecodedPseudoProbeInlineTree *Parent) {
508     auto It = InjectedProbeMap.find(Parent);
509     assert(It != InjectedProbeMap.end());
510     return iterator_range(It->second);
511   }
512 
513   const ArrayRef<MCDecodedPseudoProbeInlineTree> getInlineTreeVec() const {
514     return InlineTreeVec;
515   }
516 
517 private:
518   // Recursively parse an inlining tree encoded in pseudo_probe section. Returns
519   // whether the the top-level node should be skipped.
520   template <bool IsTopLevelFunc>
521   bool buildAddress2ProbeMap(MCDecodedPseudoProbeInlineTree *Cur,
522                              uint64_t &LastAddr, const Uint64Set &GuildFilter,
523                              const Uint64Map &FuncStartAddrs,
524                              const uint32_t CurChildIndex);
525 };
526 
527 } // end namespace llvm
528 
529 #endif // LLVM_MC_MCPSEUDOPROBE_H
530