Home | History | Annotate | Line # | Download | only in llvm-profgen
      1 //===--- PseudoProbe.h - Pseudo probe decoding utilities ---------*- 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 #ifndef LLVM_TOOLS_LLVM_PROFGEN_PSEUDOPROBE_H
      9 #define LLVM_TOOLS_LLVM_PROFGEN_PSEUDOPROBE_H
     10 
     11 #include "llvm/ADT/StringRef.h"
     12 #include "llvm/ADT/Twine.h"
     13 #include "llvm/IR/PseudoProbe.h"
     14 #include "llvm/Support/raw_ostream.h"
     15 #include "llvm/Transforms/IPO/SampleProfileProbe.h"
     16 #include <algorithm>
     17 #include <set>
     18 #include <sstream>
     19 #include <string>
     20 #include <unordered_map>
     21 #include <unordered_set>
     22 #include <vector>
     23 
     24 namespace llvm {
     25 namespace sampleprof {
     26 
     27 enum PseudoProbeAttributes { TAILCALL = 1, DANGLING = 2 };
     28 
     29 // Use func GUID and index as the location info of the inline site
     30 using InlineSite = std::tuple<uint64_t, uint32_t>;
     31 
     32 struct PseudoProbe;
     33 
     34 // Tree node to represent the inline relation and its inline site, we use a
     35 // dummy root in the PseudoProbeDecoder to lead the tree, the outlined
     36 // function will directly be the children of the dummy root. For the inlined
     37 // function, all the inlinee will be connected to its inlineer, then further to
     38 // its outlined function. Pseudo probes originating from the function stores the
     39 // tree's leaf node which we can process backwards to get its inline context
     40 class PseudoProbeInlineTree {
     41   std::vector<PseudoProbe *> ProbeVector;
     42 
     43   struct InlineSiteHash {
     44     uint64_t operator()(const InlineSite &Site) const {
     45       return std::get<0>(Site) ^ std::get<1>(Site);
     46     }
     47   };
     48   using InlinedProbeTreeMap =
     49       std::unordered_map<InlineSite, std::unique_ptr<PseudoProbeInlineTree>,
     50                          InlineSiteHash>;
     51   InlinedProbeTreeMap Children;
     52 
     53 public:
     54   // Inlinee function GUID
     55   uint64_t GUID = 0;
     56   // Inline site to indicate the location in its inliner. As the node could also
     57   // be an outlined function, it will use a dummy InlineSite whose GUID and
     58   // Index is 0 connected to the dummy root
     59   InlineSite ISite;
     60   // Used for decoding
     61   uint32_t ChildrenToProcess = 0;
     62   // Caller node of the inline site
     63   PseudoProbeInlineTree *Parent;
     64 
     65   PseudoProbeInlineTree(){};
     66   PseudoProbeInlineTree(const InlineSite &Site) : ISite(Site){};
     67 
     68   PseudoProbeInlineTree *getOrAddNode(const InlineSite &Site) {
     69     auto Ret =
     70         Children.emplace(Site, std::make_unique<PseudoProbeInlineTree>(Site));
     71     Ret.first->second->Parent = this;
     72     return Ret.first->second.get();
     73   }
     74 
     75   InlinedProbeTreeMap &getChildren() { return Children; }
     76   std::vector<PseudoProbe *> &getProbes() { return ProbeVector; }
     77   void addProbes(PseudoProbe *Probe) { ProbeVector.push_back(Probe); }
     78   // Return false if it's a dummy inline site
     79   bool hasInlineSite() const { return std::get<0>(ISite) != 0; }
     80 };
     81 
     82 // Function descriptor decoded from .pseudo_probe_desc section
     83 struct PseudoProbeFuncDesc {
     84   uint64_t FuncGUID = 0;
     85   uint64_t FuncHash = 0;
     86   std::string FuncName;
     87 
     88   PseudoProbeFuncDesc(uint64_t GUID, uint64_t Hash, StringRef Name)
     89       : FuncGUID(GUID), FuncHash(Hash), FuncName(Name){};
     90 
     91   void print(raw_ostream &OS);
     92 };
     93 
     94 // GUID to PseudoProbeFuncDesc map
     95 using GUIDProbeFunctionMap = std::unordered_map<uint64_t, PseudoProbeFuncDesc>;
     96 // Address to pseudo probes map.
     97 using AddressProbesMap = std::unordered_map<uint64_t, std::list<PseudoProbe>>;
     98 
     99 /*
    100 A pseudo probe has the format like below:
    101   INDEX (ULEB128)
    102   TYPE (uint4)
    103     0 - block probe, 1 - indirect call, 2 - direct call
    104   ATTRIBUTE (uint3)
    105     1 - tail call, 2 - dangling
    106   ADDRESS_TYPE (uint1)
    107     0 - code address, 1 - address delta
    108   CODE_ADDRESS (uint64 or ULEB128)
    109   code address or address delta, depending on Flag
    110 */
    111 struct PseudoProbe {
    112   uint64_t Address;
    113   uint64_t GUID;
    114   uint32_t Index;
    115   PseudoProbeType Type;
    116   uint8_t Attribute;
    117   PseudoProbeInlineTree *InlineTree;
    118   const static uint32_t PseudoProbeFirstId =
    119       static_cast<uint32_t>(PseudoProbeReservedId::Last) + 1;
    120 
    121   PseudoProbe(uint64_t Ad, uint64_t G, uint32_t I, PseudoProbeType K,
    122               uint8_t At, PseudoProbeInlineTree *Tree)
    123       : Address(Ad), GUID(G), Index(I), Type(K), Attribute(At),
    124         InlineTree(Tree){};
    125 
    126   bool isEntry() const { return Index == PseudoProbeFirstId; }
    127 
    128   bool isDangling() const {
    129     return Attribute & static_cast<uint8_t>(PseudoProbeAttributes::DANGLING);
    130   }
    131 
    132   bool isTailCall() const {
    133     return Attribute & static_cast<uint8_t>(PseudoProbeAttributes::TAILCALL);
    134   }
    135 
    136   bool isBlock() const { return Type == PseudoProbeType::Block; }
    137   bool isIndirectCall() const { return Type == PseudoProbeType::IndirectCall; }
    138   bool isDirectCall() const { return Type == PseudoProbeType::DirectCall; }
    139   bool isCall() const { return isIndirectCall() || isDirectCall(); }
    140 
    141   PseudoProbeInlineTree *getInlineTreeNode() const { return InlineTree; }
    142 
    143   // Get the inlined context by traversing current inline tree backwards,
    144   // each tree node has its InlineSite which is taken as the context.
    145   // \p ContextStack is populated in root to leaf order
    146   void getInlineContext(SmallVectorImpl<std::string> &ContextStack,
    147                         const GUIDProbeFunctionMap &GUID2FuncMAP,
    148                         bool ShowName) const;
    149   // Helper function to get the string from context stack
    150   std::string getInlineContextStr(const GUIDProbeFunctionMap &GUID2FuncMAP,
    151                                   bool ShowName) const;
    152   // Print pseudo probe while disassembling
    153   void print(raw_ostream &OS, const GUIDProbeFunctionMap &GUID2FuncMAP,
    154              bool ShowName);
    155 };
    156 
    157 /*
    158 Decode pseudo probe info from ELF section, used along with ELF reader
    159 Two sections are decoded here:
    160   1) \fn buildGUID2FunctionMap is responsible for .pseudo_probe_desc
    161   section which encodes all function descriptors.
    162   2) \fn buildAddress2ProbeMap is responsible for .pseudoprobe section
    163     which encodes an inline function forest and each tree includes its
    164     inlined function and all pseudo probes inside the function.
    165 see \file MCPseudoProbe.h for the details of the section encoding format.
    166 */
    167 class PseudoProbeDecoder {
    168   // GUID to PseudoProbeFuncDesc map.
    169   GUIDProbeFunctionMap GUID2FuncDescMap;
    170 
    171   // Address to probes map.
    172   AddressProbesMap Address2ProbesMap;
    173 
    174   // The dummy root of the inline trie, all the outlined function will directly
    175   // be the children of the dummy root, all the inlined function will be the
    176   // children of its inlineer. So the relation would be like:
    177   // DummyRoot --> OutlinedFunc --> InlinedFunc1 --> InlinedFunc2
    178   PseudoProbeInlineTree DummyInlineRoot;
    179 
    180   /// Points to the current location in the buffer.
    181   const uint8_t *Data = nullptr;
    182 
    183   /// Points to the end of the buffer.
    184   const uint8_t *End = nullptr;
    185 
    186   /// SectionName used for debug
    187   std::string SectionName;
    188 
    189   // Decoding helper function
    190   template <typename T> T readUnencodedNumber();
    191   template <typename T> T readUnsignedNumber();
    192   template <typename T> T readSignedNumber();
    193   StringRef readString(uint32_t Size);
    194 
    195 public:
    196   // Decode pseudo_probe_desc section to build GUID to PseudoProbeFuncDesc map.
    197   void buildGUID2FuncDescMap(const uint8_t *Start, std::size_t Size);
    198 
    199   // Decode pseudo_probe section to build address to probes map.
    200   void buildAddress2ProbeMap(const uint8_t *Start, std::size_t Size);
    201 
    202   // Print pseudo_probe_desc section info
    203   void printGUID2FuncDescMap(raw_ostream &OS);
    204 
    205   // Print pseudo_probe section info, used along with show-disassembly
    206   void printProbeForAddress(raw_ostream &OS, uint64_t Address);
    207 
    208   // Look up the probe of a call for the input address
    209   const PseudoProbe *getCallProbeForAddr(uint64_t Address) const;
    210 
    211   const PseudoProbeFuncDesc *getFuncDescForGUID(uint64_t GUID) const;
    212 
    213   // Helper function to populate one probe's inline stack into
    214   // \p InlineContextStack.
    215   // Current leaf location info will be added if IncludeLeaf is true
    216   // Example:
    217   //  Current probe(bar:3) inlined at foo:2 then inlined at main:1
    218   //  IncludeLeaf = true,  Output: [main:1, foo:2, bar:3]
    219   //  IncludeLeaf = false, Output: [main:1, foo:2]
    220   void
    221   getInlineContextForProbe(const PseudoProbe *Probe,
    222                            SmallVectorImpl<std::string> &InlineContextStack,
    223                            bool IncludeLeaf) const;
    224 
    225   const AddressProbesMap &getAddress2ProbesMap() const {
    226     return Address2ProbesMap;
    227   }
    228 
    229   const PseudoProbeFuncDesc *
    230   getInlinerDescForProbe(const PseudoProbe *Probe) const;
    231 };
    232 
    233 } // end namespace sampleprof
    234 } // end namespace llvm
    235 
    236 #endif
    237