MCPseudoProbe.h 15 KB

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