MemoryProfileInfo.h 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- llvm/Analysis/MemoryProfileInfo.h - memory profile info ---*- 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 utilities to analyze memory profile information.
  15. //
  16. //===----------------------------------------------------------------------===//
  17. #ifndef LLVM_ANALYSIS_MEMORYPROFILEINFO_H
  18. #define LLVM_ANALYSIS_MEMORYPROFILEINFO_H
  19. #include "llvm/IR/Constants.h"
  20. #include "llvm/IR/InstrTypes.h"
  21. #include "llvm/IR/Metadata.h"
  22. #include "llvm/IR/Module.h"
  23. #include "llvm/IR/ModuleSummaryIndex.h"
  24. #include <map>
  25. namespace llvm {
  26. namespace memprof {
  27. /// Return the allocation type for a given set of memory profile values.
  28. AllocationType getAllocType(uint64_t MaxAccessCount, uint64_t MinSize,
  29. uint64_t MinLifetime);
  30. /// Build callstack metadata from the provided list of call stack ids. Returns
  31. /// the resulting metadata node.
  32. MDNode *buildCallstackMetadata(ArrayRef<uint64_t> CallStack, LLVMContext &Ctx);
  33. /// Returns the stack node from an MIB metadata node.
  34. MDNode *getMIBStackNode(const MDNode *MIB);
  35. /// Returns the allocation type from an MIB metadata node.
  36. AllocationType getMIBAllocType(const MDNode *MIB);
  37. /// Class to build a trie of call stack contexts for a particular profiled
  38. /// allocation call, along with their associated allocation types.
  39. /// The allocation will be at the root of the trie, which is then used to
  40. /// compute the minimum lists of context ids needed to associate a call context
  41. /// with a single allocation type.
  42. class CallStackTrie {
  43. private:
  44. struct CallStackTrieNode {
  45. // Allocation types for call context sharing the context prefix at this
  46. // node.
  47. uint8_t AllocTypes;
  48. // Map of caller stack id to the corresponding child Trie node.
  49. std::map<uint64_t, CallStackTrieNode *> Callers;
  50. CallStackTrieNode(AllocationType Type)
  51. : AllocTypes(static_cast<uint8_t>(Type)) {}
  52. };
  53. // The node for the allocation at the root.
  54. CallStackTrieNode *Alloc;
  55. // The allocation's leaf stack id.
  56. uint64_t AllocStackId;
  57. void deleteTrieNode(CallStackTrieNode *Node) {
  58. if (!Node)
  59. return;
  60. for (auto C : Node->Callers)
  61. deleteTrieNode(C.second);
  62. delete Node;
  63. }
  64. // Recursive helper to trim contexts and create metadata nodes.
  65. bool buildMIBNodes(CallStackTrieNode *Node, LLVMContext &Ctx,
  66. std::vector<uint64_t> &MIBCallStack,
  67. std::vector<Metadata *> &MIBNodes,
  68. bool CalleeHasAmbiguousCallerContext);
  69. public:
  70. CallStackTrie() : Alloc(nullptr), AllocStackId(0) {}
  71. ~CallStackTrie() { deleteTrieNode(Alloc); }
  72. bool empty() const { return Alloc == nullptr; }
  73. /// Add a call stack context with the given allocation type to the Trie.
  74. /// The context is represented by the list of stack ids (computed during
  75. /// matching via a debug location hash), expected to be in order from the
  76. /// allocation call down to the bottom of the call stack (i.e. callee to
  77. /// caller order).
  78. void addCallStack(AllocationType AllocType, ArrayRef<uint64_t> StackIds);
  79. /// Add the call stack context along with its allocation type from the MIB
  80. /// metadata to the Trie.
  81. void addCallStack(MDNode *MIB);
  82. /// Build and attach the minimal necessary MIB metadata. If the alloc has a
  83. /// single allocation type, add a function attribute instead. The reason for
  84. /// adding an attribute in this case is that it matches how the behavior for
  85. /// allocation calls will be communicated to lib call simplification after
  86. /// cloning or another optimization to distinguish the allocation types,
  87. /// which is lower overhead and more direct than maintaining this metadata.
  88. /// Returns true if memprof metadata attached, false if not (attribute added).
  89. bool buildAndAttachMIBMetadata(CallBase *CI);
  90. };
  91. /// Helper class to iterate through stack ids in both metadata (memprof MIB and
  92. /// callsite) and the corresponding ThinLTO summary data structures
  93. /// (CallsiteInfo and MIBInfo). This simplifies implementation of client code
  94. /// which doesn't need to worry about whether we are operating with IR (Regular
  95. /// LTO), or summary (ThinLTO).
  96. template <class NodeT, class IteratorT> class CallStack {
  97. public:
  98. CallStack(const NodeT *N = nullptr) : N(N) {}
  99. // Implement minimum required methods for range-based for loop.
  100. // The default implementation assumes we are operating on ThinLTO data
  101. // structures, which have a vector of StackIdIndices. There are specialized
  102. // versions provided to iterate through metadata.
  103. struct CallStackIterator {
  104. const NodeT *N = nullptr;
  105. IteratorT Iter;
  106. CallStackIterator(const NodeT *N, bool End);
  107. uint64_t operator*();
  108. bool operator==(const CallStackIterator &rhs) { return Iter == rhs.Iter; }
  109. bool operator!=(const CallStackIterator &rhs) { return !(*this == rhs); }
  110. void operator++() { ++Iter; }
  111. };
  112. bool empty() const { return N == nullptr; }
  113. CallStackIterator begin() const;
  114. CallStackIterator end() const { return CallStackIterator(N, /*End*/ true); }
  115. CallStackIterator beginAfterSharedPrefix(CallStack &Other);
  116. private:
  117. const NodeT *N = nullptr;
  118. };
  119. template <class NodeT, class IteratorT>
  120. CallStack<NodeT, IteratorT>::CallStackIterator::CallStackIterator(
  121. const NodeT *N, bool End)
  122. : N(N) {
  123. if (!N)
  124. return;
  125. Iter = End ? N->StackIdIndices.end() : N->StackIdIndices.begin();
  126. }
  127. template <class NodeT, class IteratorT>
  128. uint64_t CallStack<NodeT, IteratorT>::CallStackIterator::operator*() {
  129. assert(Iter != N->StackIdIndices.end());
  130. return *Iter;
  131. }
  132. template <class NodeT, class IteratorT>
  133. typename CallStack<NodeT, IteratorT>::CallStackIterator
  134. CallStack<NodeT, IteratorT>::begin() const {
  135. return CallStackIterator(N, /*End*/ false);
  136. }
  137. template <class NodeT, class IteratorT>
  138. typename CallStack<NodeT, IteratorT>::CallStackIterator
  139. CallStack<NodeT, IteratorT>::beginAfterSharedPrefix(CallStack &Other) {
  140. CallStackIterator Cur = begin();
  141. for (CallStackIterator OtherCur = Other.begin();
  142. Cur != end() && OtherCur != Other.end(); ++Cur, ++OtherCur)
  143. assert(*Cur == *OtherCur);
  144. return Cur;
  145. }
  146. /// Specializations for iterating through IR metadata stack contexts.
  147. template <>
  148. CallStack<MDNode, MDNode::op_iterator>::CallStackIterator::CallStackIterator(
  149. const MDNode *N, bool End);
  150. template <>
  151. uint64_t CallStack<MDNode, MDNode::op_iterator>::CallStackIterator::operator*();
  152. } // end namespace memprof
  153. } // end namespace llvm
  154. #endif
  155. #ifdef __GNUC__
  156. #pragma GCC diagnostic pop
  157. #endif