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