MCPseudoProbe.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- MCPseudoProbe.h - Pseudo probe encoding support ---------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // This file contains the declaration of the MCPseudoProbe to support the pseudo
  15. // probe encoding for AutoFDO. Pseudo probes together with their inline context
  16. // are encoded in a DFS recursive way in the .pseudoprobe sections. For each
  17. // .pseudoprobe section, the encoded binary data consist of a single or mutiple
  18. // function records each for one outlined function. A function record has the
  19. // following format :
  20. //
  21. // FUNCTION BODY (one for each outlined function present in the text section)
  22. // GUID (uint64)
  23. // GUID of the function
  24. // NPROBES (ULEB128)
  25. // Number of probes originating from this function.
  26. // NUM_INLINED_FUNCTIONS (ULEB128)
  27. // Number of callees inlined into this function, aka number of
  28. // first-level inlinees
  29. // PROBE RECORDS
  30. // A list of NPROBES entries. Each entry contains:
  31. // INDEX (ULEB128)
  32. // TYPE (uint4)
  33. // 0 - block probe, 1 - indirect call, 2 - direct call
  34. // ATTRIBUTE (uint3)
  35. // 1 - reserved
  36. // ADDRESS_TYPE (uint1)
  37. // 0 - code address, 1 - address delta
  38. // CODE_ADDRESS (uint64 or ULEB128)
  39. // code address or address delta, depending on ADDRESS_TYPE
  40. // INLINED FUNCTION RECORDS
  41. // A list of NUM_INLINED_FUNCTIONS entries describing each of the inlined
  42. // callees. Each record contains:
  43. // INLINE SITE
  44. // ID of the callsite probe (ULEB128)
  45. // FUNCTION BODY
  46. // A FUNCTION BODY entry describing the inlined function.
  47. //===----------------------------------------------------------------------===//
  48. #ifndef LLVM_MC_MCPSEUDOPROBE_H
  49. #define LLVM_MC_MCPSEUDOPROBE_H
  50. #include "llvm/ADT/SmallVector.h"
  51. #include "llvm/ADT/StringRef.h"
  52. #include "llvm/IR/PseudoProbe.h"
  53. #include "llvm/Support/ErrorOr.h"
  54. #include <list>
  55. #include <map>
  56. #include <memory>
  57. #include <string>
  58. #include <tuple>
  59. #include <type_traits>
  60. #include <unordered_map>
  61. #include <vector>
  62. namespace llvm {
  63. class MCSection;
  64. class MCSymbol;
  65. class MCObjectStreamer;
  66. class raw_ostream;
  67. enum class MCPseudoProbeFlag {
  68. // If set, indicates that the probe is encoded as an address delta
  69. // instead of a real code address.
  70. AddressDelta = 0x1,
  71. };
  72. // Function descriptor decoded from .pseudo_probe_desc section
  73. struct MCPseudoProbeFuncDesc {
  74. uint64_t FuncGUID = 0;
  75. uint64_t FuncHash = 0;
  76. std::string FuncName;
  77. MCPseudoProbeFuncDesc(uint64_t GUID, uint64_t Hash, StringRef Name)
  78. : FuncGUID(GUID), FuncHash(Hash), FuncName(Name){};
  79. void print(raw_ostream &OS);
  80. };
  81. class MCPseudoProbe;
  82. class MCDecodedPseudoProbe;
  83. // An inline frame has the form <Guid, ProbeID>
  84. using InlineSite = std::tuple<uint64_t, uint32_t>;
  85. using MCPseudoProbeInlineStack = SmallVector<InlineSite, 8>;
  86. // GUID to PseudoProbeFuncDesc map
  87. using GUIDProbeFunctionMap =
  88. std::unordered_map<uint64_t, MCPseudoProbeFuncDesc>;
  89. // Address to pseudo probes map.
  90. using AddressProbesMap =
  91. std::unordered_map<uint64_t, std::list<MCDecodedPseudoProbe>>;
  92. class MCPseudoProbeInlineTree;
  93. class MCDecodedPseudoProbeInlineTree;
  94. class MCPseudoProbeBase {
  95. protected:
  96. uint64_t Guid;
  97. uint64_t Index;
  98. uint8_t Attributes;
  99. uint8_t Type;
  100. // The value should be equal to PseudoProbeReservedId::Last + 1 which is
  101. // defined in SampleProfileProbe.h. The header file is not included here to
  102. // reduce the dependency from MC to IPO.
  103. const static uint32_t PseudoProbeFirstId = 1;
  104. public:
  105. MCPseudoProbeBase(uint64_t G, uint64_t I, uint64_t At, uint8_t T)
  106. : Guid(G), Index(I), Attributes(At), Type(T) {}
  107. bool isEntry() const { return Index == PseudoProbeFirstId; }
  108. uint64_t getGuid() const { return Guid; }
  109. uint64_t getIndex() const { return Index; }
  110. uint8_t getAttributes() const { return Attributes; }
  111. uint8_t getType() const { return Type; }
  112. bool isBlock() const {
  113. return Type == static_cast<uint8_t>(PseudoProbeType::Block);
  114. }
  115. bool isIndirectCall() const {
  116. return Type == static_cast<uint8_t>(PseudoProbeType::IndirectCall);
  117. }
  118. bool isDirectCall() const {
  119. return Type == static_cast<uint8_t>(PseudoProbeType::DirectCall);
  120. }
  121. bool isCall() const { return isIndirectCall() || isDirectCall(); }
  122. void setAttributes(uint8_t Attr) { Attributes = Attr; }
  123. };
  124. /// Instances of this class represent a pseudo probe instance for a pseudo probe
  125. /// table entry, which is created during a machine instruction is assembled and
  126. /// uses an address from a temporary label created at the current address in the
  127. /// current section.
  128. class MCPseudoProbe : public MCPseudoProbeBase {
  129. MCSymbol *Label;
  130. public:
  131. MCPseudoProbe(MCSymbol *Label, uint64_t Guid, uint64_t Index, uint64_t Type,
  132. uint64_t Attributes)
  133. : MCPseudoProbeBase(Guid, Index, Attributes, Type), Label(Label) {
  134. assert(Type <= 0xFF && "Probe type too big to encode, exceeding 2^8");
  135. assert(Attributes <= 0xFF &&
  136. "Probe attributes too big to encode, exceeding 2^16");
  137. }
  138. MCSymbol *getLabel() const { return Label; }
  139. void emit(MCObjectStreamer *MCOS, const MCPseudoProbe *LastProbe) const;
  140. };
  141. // Represents a callsite with caller function name and probe id
  142. using MCPseduoProbeFrameLocation = std::pair<StringRef, uint32_t>;
  143. class MCDecodedPseudoProbe : public MCPseudoProbeBase {
  144. uint64_t Address;
  145. MCDecodedPseudoProbeInlineTree *InlineTree;
  146. public:
  147. MCDecodedPseudoProbe(uint64_t Ad, uint64_t G, uint32_t I, PseudoProbeType K,
  148. uint8_t At, MCDecodedPseudoProbeInlineTree *Tree)
  149. : MCPseudoProbeBase(G, I, At, static_cast<uint8_t>(K)), Address(Ad),
  150. InlineTree(Tree){};
  151. uint64_t getAddress() const { return Address; }
  152. void setAddress(uint64_t Addr) { Address = Addr; }
  153. MCDecodedPseudoProbeInlineTree *getInlineTreeNode() const {
  154. return InlineTree;
  155. }
  156. // Get the inlined context by traversing current inline tree backwards,
  157. // each tree node has its InlineSite which is taken as the context.
  158. // \p ContextStack is populated in root to leaf order
  159. void
  160. getInlineContext(SmallVectorImpl<MCPseduoProbeFrameLocation> &ContextStack,
  161. const GUIDProbeFunctionMap &GUID2FuncMAP) const;
  162. // Helper function to get the string from context stack
  163. std::string
  164. getInlineContextStr(const GUIDProbeFunctionMap &GUID2FuncMAP) const;
  165. // Print pseudo probe while disassembling
  166. void print(raw_ostream &OS, const GUIDProbeFunctionMap &GUID2FuncMAP,
  167. bool ShowName) const;
  168. };
  169. template <typename ProbeType, typename DerivedProbeInlineTreeType>
  170. class MCPseudoProbeInlineTreeBase {
  171. struct InlineSiteHash {
  172. uint64_t operator()(const InlineSite &Site) const {
  173. return std::get<0>(Site) ^ std::get<1>(Site);
  174. }
  175. };
  176. protected:
  177. // Track children (e.g. inlinees) of current context
  178. using InlinedProbeTreeMap = std::unordered_map<
  179. InlineSite, std::unique_ptr<DerivedProbeInlineTreeType>, InlineSiteHash>;
  180. InlinedProbeTreeMap Children;
  181. // Set of probes that come with the function.
  182. std::vector<ProbeType> Probes;
  183. MCPseudoProbeInlineTreeBase() {
  184. static_assert(std::is_base_of<MCPseudoProbeInlineTreeBase,
  185. DerivedProbeInlineTreeType>::value,
  186. "DerivedProbeInlineTreeType must be subclass of "
  187. "MCPseudoProbeInlineTreeBase");
  188. }
  189. public:
  190. uint64_t Guid = 0;
  191. // Root node has a GUID 0.
  192. bool isRoot() const { return Guid == 0; }
  193. InlinedProbeTreeMap &getChildren() { return Children; }
  194. const InlinedProbeTreeMap &getChildren() const { return Children; }
  195. std::vector<ProbeType> &getProbes() { return Probes; }
  196. void addProbes(ProbeType Probe) { Probes.push_back(Probe); }
  197. // Caller node of the inline site
  198. MCPseudoProbeInlineTreeBase<ProbeType, DerivedProbeInlineTreeType> *Parent;
  199. DerivedProbeInlineTreeType *getOrAddNode(const InlineSite &Site) {
  200. auto Ret = Children.emplace(
  201. Site, std::make_unique<DerivedProbeInlineTreeType>(Site));
  202. Ret.first->second->Parent = this;
  203. return Ret.first->second.get();
  204. };
  205. };
  206. // A Tri-tree based data structure to group probes by inline stack.
  207. // A tree is allocated for a standalone .text section. A fake
  208. // instance is created as the root of a tree.
  209. // A real instance of this class is created for each function, either a
  210. // not inlined function that has code in .text section or an inlined function.
  211. class MCPseudoProbeInlineTree
  212. : public MCPseudoProbeInlineTreeBase<MCPseudoProbe,
  213. MCPseudoProbeInlineTree> {
  214. public:
  215. MCPseudoProbeInlineTree() = default;
  216. MCPseudoProbeInlineTree(uint64_t Guid) { this->Guid = Guid; }
  217. MCPseudoProbeInlineTree(const InlineSite &Site) {
  218. this->Guid = std::get<0>(Site);
  219. }
  220. // MCPseudoProbeInlineTree method based on Inlinees
  221. void addPseudoProbe(const MCPseudoProbe &Probe,
  222. const MCPseudoProbeInlineStack &InlineStack);
  223. void emit(MCObjectStreamer *MCOS, const MCPseudoProbe *&LastProbe);
  224. };
  225. // inline tree node for the decoded pseudo probe
  226. class MCDecodedPseudoProbeInlineTree
  227. : public MCPseudoProbeInlineTreeBase<MCDecodedPseudoProbe *,
  228. MCDecodedPseudoProbeInlineTree> {
  229. public:
  230. InlineSite ISite;
  231. // Used for decoding
  232. uint32_t ChildrenToProcess = 0;
  233. MCDecodedPseudoProbeInlineTree() = default;
  234. MCDecodedPseudoProbeInlineTree(const InlineSite &Site) : ISite(Site){};
  235. // Return false if it's a dummy inline site
  236. bool hasInlineSite() const { return std::get<0>(ISite) != 0; }
  237. };
  238. /// Instances of this class represent the pseudo probes inserted into a compile
  239. /// unit.
  240. class MCPseudoProbeSection {
  241. public:
  242. void addPseudoProbe(MCSection *Sec, const MCPseudoProbe &Probe,
  243. const MCPseudoProbeInlineStack &InlineStack) {
  244. MCProbeDivisions[Sec].addPseudoProbe(Probe, InlineStack);
  245. }
  246. // TODO: Sort by getOrdinal to ensure a determinstic section order
  247. using MCProbeDivisionMap = std::map<MCSection *, MCPseudoProbeInlineTree>;
  248. private:
  249. // A collection of MCPseudoProbe for each text section. The MCPseudoProbes
  250. // are grouped by GUID of the functions where they are from and will be
  251. // encoded by groups. In the comdat scenario where a text section really only
  252. // contains the code of a function solely, the probes associated with a comdat
  253. // function are still grouped by GUIDs due to inlining that can bring probes
  254. // from different functions into one function.
  255. MCProbeDivisionMap MCProbeDivisions;
  256. public:
  257. const MCProbeDivisionMap &getMCProbes() const { return MCProbeDivisions; }
  258. bool empty() const { return MCProbeDivisions.empty(); }
  259. void emit(MCObjectStreamer *MCOS);
  260. };
  261. class MCPseudoProbeTable {
  262. // A collection of MCPseudoProbe in the current module grouped by text
  263. // sections. MCPseudoProbes will be encoded into a corresponding
  264. // .pseudoprobe section. With functions emitted as separate comdats,
  265. // a text section really only contains the code of a function solely, and the
  266. // probes associated with the text section will be emitted into a standalone
  267. // .pseudoprobe section that shares the same comdat group with the function.
  268. MCPseudoProbeSection MCProbeSections;
  269. public:
  270. static void emit(MCObjectStreamer *MCOS);
  271. MCPseudoProbeSection &getProbeSections() { return MCProbeSections; }
  272. #ifndef NDEBUG
  273. static int DdgPrintIndent;
  274. #endif
  275. };
  276. class MCPseudoProbeDecoder {
  277. // GUID to PseudoProbeFuncDesc map.
  278. GUIDProbeFunctionMap GUID2FuncDescMap;
  279. // Address to probes map.
  280. AddressProbesMap Address2ProbesMap;
  281. // The dummy root of the inline trie, all the outlined function will directly
  282. // be the children of the dummy root, all the inlined function will be the
  283. // children of its inlineer. So the relation would be like:
  284. // DummyRoot --> OutlinedFunc --> InlinedFunc1 --> InlinedFunc2
  285. MCDecodedPseudoProbeInlineTree DummyInlineRoot;
  286. /// Points to the current location in the buffer.
  287. const uint8_t *Data = nullptr;
  288. /// Points to the end of the buffer.
  289. const uint8_t *End = nullptr;
  290. // Decoding helper function
  291. template <typename T> ErrorOr<T> readUnencodedNumber();
  292. template <typename T> ErrorOr<T> readUnsignedNumber();
  293. template <typename T> ErrorOr<T> readSignedNumber();
  294. ErrorOr<StringRef> readString(uint32_t Size);
  295. public:
  296. // Decode pseudo_probe_desc section to build GUID to PseudoProbeFuncDesc map.
  297. bool buildGUID2FuncDescMap(const uint8_t *Start, std::size_t Size);
  298. // Decode pseudo_probe section to build address to probes map.
  299. bool buildAddress2ProbeMap(const uint8_t *Start, std::size_t Size);
  300. // Print pseudo_probe_desc section info
  301. void printGUID2FuncDescMap(raw_ostream &OS);
  302. // Print pseudo_probe section info, used along with show-disassembly
  303. void printProbeForAddress(raw_ostream &OS, uint64_t Address);
  304. // do printProbeForAddress for all addresses
  305. void printProbesForAllAddresses(raw_ostream &OS);
  306. // Look up the probe of a call for the input address
  307. const MCDecodedPseudoProbe *getCallProbeForAddr(uint64_t Address) const;
  308. const MCPseudoProbeFuncDesc *getFuncDescForGUID(uint64_t GUID) const;
  309. // Helper function to populate one probe's inline stack into
  310. // \p InlineContextStack.
  311. // Current leaf location info will be added if IncludeLeaf is true
  312. // Example:
  313. // Current probe(bar:3) inlined at foo:2 then inlined at main:1
  314. // IncludeLeaf = true, Output: [main:1, foo:2, bar:3]
  315. // IncludeLeaf = false, Output: [main:1, foo:2]
  316. void getInlineContextForProbe(
  317. const MCDecodedPseudoProbe *Probe,
  318. SmallVectorImpl<MCPseduoProbeFrameLocation> &InlineContextStack,
  319. bool IncludeLeaf) const;
  320. const AddressProbesMap &getAddress2ProbesMap() const {
  321. return Address2ProbesMap;
  322. }
  323. AddressProbesMap &getAddress2ProbesMap() { return Address2ProbesMap; }
  324. const GUIDProbeFunctionMap &getGUID2FuncDescMap() const {
  325. return GUID2FuncDescMap;
  326. }
  327. const MCPseudoProbeFuncDesc *
  328. getInlinerDescForProbe(const MCDecodedPseudoProbe *Probe) const;
  329. const MCDecodedPseudoProbeInlineTree &getDummyInlineRoot() const {
  330. return DummyInlineRoot;
  331. }
  332. };
  333. } // end namespace llvm
  334. #endif // LLVM_MC_MCPSEUDOPROBE_H
  335. #ifdef __GNUC__
  336. #pragma GCC diagnostic pop
  337. #endif