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