PseudoProbe.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. //===--- PseudoProbe.cpp - Pseudo probe decoding utilities ------*- 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. #include "PseudoProbe.h"
  9. #include "ErrorHandling.h"
  10. #include "llvm/Support/Endian.h"
  11. #include "llvm/Support/LEB128.h"
  12. #include "llvm/Support/raw_ostream.h"
  13. #include <limits>
  14. #include <memory>
  15. using namespace llvm;
  16. using namespace sampleprof;
  17. using namespace support;
  18. namespace llvm {
  19. namespace sampleprof {
  20. static StringRef getProbeFNameForGUID(const GUIDProbeFunctionMap &GUID2FuncMAP,
  21. uint64_t GUID) {
  22. auto It = GUID2FuncMAP.find(GUID);
  23. assert(It != GUID2FuncMAP.end() &&
  24. "Probe function must exist for a valid GUID");
  25. return It->second.FuncName;
  26. }
  27. void PseudoProbeFuncDesc::print(raw_ostream &OS) {
  28. OS << "GUID: " << FuncGUID << " Name: " << FuncName << "\n";
  29. OS << "Hash: " << FuncHash << "\n";
  30. }
  31. void PseudoProbe::getInlineContext(SmallVectorImpl<std::string> &ContextStack,
  32. const GUIDProbeFunctionMap &GUID2FuncMAP,
  33. bool ShowName) const {
  34. uint32_t Begin = ContextStack.size();
  35. PseudoProbeInlineTree *Cur = InlineTree;
  36. // It will add the string of each node's inline site during iteration.
  37. // Note that it won't include the probe's belonging function(leaf location)
  38. while (Cur->hasInlineSite()) {
  39. std::string ContextStr;
  40. if (ShowName) {
  41. StringRef FuncName =
  42. getProbeFNameForGUID(GUID2FuncMAP, std::get<0>(Cur->ISite));
  43. ContextStr += FuncName.str();
  44. } else {
  45. ContextStr += Twine(std::get<0>(Cur->ISite)).str();
  46. }
  47. ContextStr += ":";
  48. ContextStr += Twine(std::get<1>(Cur->ISite)).str();
  49. ContextStack.emplace_back(ContextStr);
  50. Cur = Cur->Parent;
  51. }
  52. // Make the ContextStack in caller-callee order
  53. std::reverse(ContextStack.begin() + Begin, ContextStack.end());
  54. }
  55. std::string
  56. PseudoProbe::getInlineContextStr(const GUIDProbeFunctionMap &GUID2FuncMAP,
  57. bool ShowName) const {
  58. std::ostringstream OContextStr;
  59. SmallVector<std::string, 16> ContextStack;
  60. getInlineContext(ContextStack, GUID2FuncMAP, ShowName);
  61. for (auto &CxtStr : ContextStack) {
  62. if (OContextStr.str().size())
  63. OContextStr << " @ ";
  64. OContextStr << CxtStr;
  65. }
  66. return OContextStr.str();
  67. }
  68. static const char *PseudoProbeTypeStr[3] = {"Block", "IndirectCall",
  69. "DirectCall"};
  70. void PseudoProbe::print(raw_ostream &OS,
  71. const GUIDProbeFunctionMap &GUID2FuncMAP,
  72. bool ShowName) {
  73. OS << "FUNC: ";
  74. if (ShowName) {
  75. StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, GUID);
  76. OS << FuncName.str() << " ";
  77. } else {
  78. OS << GUID << " ";
  79. }
  80. OS << "Index: " << Index << " ";
  81. OS << "Type: " << PseudoProbeTypeStr[static_cast<uint8_t>(Type)] << " ";
  82. if (isDangling()) {
  83. OS << "Dangling ";
  84. }
  85. if (isTailCall()) {
  86. OS << "TailCall ";
  87. }
  88. std::string InlineContextStr = getInlineContextStr(GUID2FuncMAP, ShowName);
  89. if (InlineContextStr.size()) {
  90. OS << "Inlined: @ ";
  91. OS << InlineContextStr;
  92. }
  93. OS << "\n";
  94. }
  95. template <typename T> T PseudoProbeDecoder::readUnencodedNumber() {
  96. if (Data + sizeof(T) > End) {
  97. exitWithError("Decode unencoded number error in " + SectionName +
  98. " section");
  99. }
  100. T Val = endian::readNext<T, little, unaligned>(Data);
  101. return Val;
  102. }
  103. template <typename T> T PseudoProbeDecoder::readUnsignedNumber() {
  104. unsigned NumBytesRead = 0;
  105. uint64_t Val = decodeULEB128(Data, &NumBytesRead);
  106. if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) {
  107. exitWithError("Decode number error in " + SectionName + " section");
  108. }
  109. Data += NumBytesRead;
  110. return static_cast<T>(Val);
  111. }
  112. template <typename T> T PseudoProbeDecoder::readSignedNumber() {
  113. unsigned NumBytesRead = 0;
  114. int64_t Val = decodeSLEB128(Data, &NumBytesRead);
  115. if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) {
  116. exitWithError("Decode number error in " + SectionName + " section");
  117. }
  118. Data += NumBytesRead;
  119. return static_cast<T>(Val);
  120. }
  121. StringRef PseudoProbeDecoder::readString(uint32_t Size) {
  122. StringRef Str(reinterpret_cast<const char *>(Data), Size);
  123. if (Data + Size > End) {
  124. exitWithError("Decode string error in " + SectionName + " section");
  125. }
  126. Data += Size;
  127. return Str;
  128. }
  129. void PseudoProbeDecoder::buildGUID2FuncDescMap(const uint8_t *Start,
  130. std::size_t Size) {
  131. // The pseudo_probe_desc section has a format like:
  132. // .section .pseudo_probe_desc,"",@progbits
  133. // .quad -5182264717993193164 // GUID
  134. // .quad 4294967295 // Hash
  135. // .uleb 3 // Name size
  136. // .ascii "foo" // Name
  137. // .quad -2624081020897602054
  138. // .quad 174696971957
  139. // .uleb 34
  140. // .ascii "main"
  141. #ifndef NDEBUG
  142. SectionName = "pseudo_probe_desc";
  143. #endif
  144. Data = Start;
  145. End = Data + Size;
  146. while (Data < End) {
  147. uint64_t GUID = readUnencodedNumber<uint64_t>();
  148. uint64_t Hash = readUnencodedNumber<uint64_t>();
  149. uint32_t NameSize = readUnsignedNumber<uint32_t>();
  150. StringRef Name = readString(NameSize);
  151. // Initialize PseudoProbeFuncDesc and populate it into GUID2FuncDescMap
  152. GUID2FuncDescMap.emplace(GUID, PseudoProbeFuncDesc(GUID, Hash, Name));
  153. }
  154. assert(Data == End && "Have unprocessed data in pseudo_probe_desc section");
  155. }
  156. void PseudoProbeDecoder::buildAddress2ProbeMap(const uint8_t *Start,
  157. std::size_t Size) {
  158. // The pseudo_probe section encodes an inline forest and each tree has a
  159. // format like:
  160. // FUNCTION BODY (one for each uninlined function present in the text
  161. // section)
  162. // GUID (uint64)
  163. // GUID of the function
  164. // NPROBES (ULEB128)
  165. // Number of probes originating from this function.
  166. // NUM_INLINED_FUNCTIONS (ULEB128)
  167. // Number of callees inlined into this function, aka number of
  168. // first-level inlinees
  169. // PROBE RECORDS
  170. // A list of NPROBES entries. Each entry contains:
  171. // INDEX (ULEB128)
  172. // TYPE (uint4)
  173. // 0 - block probe, 1 - indirect call, 2 - direct call
  174. // ATTRIBUTE (uint3)
  175. // 1 - tail call, 2 - dangling
  176. // ADDRESS_TYPE (uint1)
  177. // 0 - code address, 1 - address delta
  178. // CODE_ADDRESS (uint64 or ULEB128)
  179. // code address or address delta, depending on Flag
  180. // INLINED FUNCTION RECORDS
  181. // A list of NUM_INLINED_FUNCTIONS entries describing each of the
  182. // inlined callees. Each record contains:
  183. // INLINE SITE
  184. // GUID of the inlinee (uint64)
  185. // Index of the callsite probe (ULEB128)
  186. // FUNCTION BODY
  187. // A FUNCTION BODY entry describing the inlined function.
  188. #ifndef NDEBUG
  189. SectionName = "pseudo_probe";
  190. #endif
  191. Data = Start;
  192. End = Data + Size;
  193. PseudoProbeInlineTree *Root = &DummyInlineRoot;
  194. PseudoProbeInlineTree *Cur = &DummyInlineRoot;
  195. uint64_t LastAddr = 0;
  196. uint32_t Index = 0;
  197. // A DFS-based decoding
  198. while (Data < End) {
  199. // Read inline site for inlinees
  200. if (Root != Cur) {
  201. Index = readUnsignedNumber<uint32_t>();
  202. }
  203. // Switch/add to a new tree node(inlinee)
  204. Cur = Cur->getOrAddNode(std::make_tuple(Cur->GUID, Index));
  205. // Read guid
  206. Cur->GUID = readUnencodedNumber<uint64_t>();
  207. // Read number of probes in the current node.
  208. uint32_t NodeCount = readUnsignedNumber<uint32_t>();
  209. // Read number of direct inlinees
  210. Cur->ChildrenToProcess = readUnsignedNumber<uint32_t>();
  211. // Read all probes in this node
  212. for (std::size_t I = 0; I < NodeCount; I++) {
  213. // Read index
  214. uint32_t Index = readUnsignedNumber<uint32_t>();
  215. // Read type | flag.
  216. uint8_t Value = readUnencodedNumber<uint8_t>();
  217. uint8_t Kind = Value & 0xf;
  218. uint8_t Attr = (Value & 0x70) >> 4;
  219. // Read address
  220. uint64_t Addr = 0;
  221. if (Value & 0x80) {
  222. int64_t Offset = readSignedNumber<int64_t>();
  223. Addr = LastAddr + Offset;
  224. } else {
  225. Addr = readUnencodedNumber<int64_t>();
  226. }
  227. // Populate Address2ProbesMap
  228. std::vector<PseudoProbe> &ProbeVec = Address2ProbesMap[Addr];
  229. ProbeVec.emplace_back(Addr, Cur->GUID, Index, PseudoProbeType(Kind), Attr,
  230. Cur);
  231. Cur->addProbes(&ProbeVec.back());
  232. LastAddr = Addr;
  233. }
  234. // Look for the parent for the next node by subtracting the current
  235. // node count from tree counts along the parent chain. The first node
  236. // in the chain that has a non-zero tree count is the target.
  237. while (Cur != Root) {
  238. if (Cur->ChildrenToProcess == 0) {
  239. Cur = Cur->Parent;
  240. if (Cur != Root) {
  241. assert(Cur->ChildrenToProcess > 0 &&
  242. "Should have some unprocessed nodes");
  243. Cur->ChildrenToProcess -= 1;
  244. }
  245. } else {
  246. break;
  247. }
  248. }
  249. }
  250. assert(Data == End && "Have unprocessed data in pseudo_probe section");
  251. assert(Cur == Root &&
  252. " Cur should point to root when the forest is fully built up");
  253. }
  254. void PseudoProbeDecoder::printGUID2FuncDescMap(raw_ostream &OS) {
  255. OS << "Pseudo Probe Desc:\n";
  256. // Make the output deterministic
  257. std::map<uint64_t, PseudoProbeFuncDesc> OrderedMap(GUID2FuncDescMap.begin(),
  258. GUID2FuncDescMap.end());
  259. for (auto &I : OrderedMap) {
  260. I.second.print(OS);
  261. }
  262. }
  263. void PseudoProbeDecoder::printProbeForAddress(raw_ostream &OS,
  264. uint64_t Address) {
  265. auto It = Address2ProbesMap.find(Address);
  266. if (It != Address2ProbesMap.end()) {
  267. for (auto &Probe : It->second) {
  268. OS << " [Probe]:\t";
  269. Probe.print(OS, GUID2FuncDescMap, true);
  270. }
  271. }
  272. }
  273. const PseudoProbe *
  274. PseudoProbeDecoder::getCallProbeForAddr(uint64_t Address) const {
  275. auto It = Address2ProbesMap.find(Address);
  276. if (It == Address2ProbesMap.end())
  277. return nullptr;
  278. const std::vector<PseudoProbe> &Probes = It->second;
  279. const PseudoProbe *CallProbe = nullptr;
  280. for (const auto &Probe : Probes) {
  281. if (Probe.isCall()) {
  282. assert(!CallProbe &&
  283. "There should be only one call probe corresponding to address "
  284. "which is a callsite.");
  285. CallProbe = &Probe;
  286. }
  287. }
  288. return CallProbe;
  289. }
  290. const PseudoProbeFuncDesc *
  291. PseudoProbeDecoder::getFuncDescForGUID(uint64_t GUID) const {
  292. auto It = GUID2FuncDescMap.find(GUID);
  293. assert(It != GUID2FuncDescMap.end() && "Function descriptor doesn't exist");
  294. return &It->second;
  295. }
  296. void PseudoProbeDecoder::getInlineContextForProbe(
  297. const PseudoProbe *Probe, SmallVectorImpl<std::string> &InlineContextStack,
  298. bool IncludeLeaf) const {
  299. Probe->getInlineContext(InlineContextStack, GUID2FuncDescMap, true);
  300. if (!IncludeLeaf)
  301. return;
  302. // Note that the context from probe doesn't include leaf frame,
  303. // hence we need to retrieve and prepend leaf if requested.
  304. const auto *FuncDesc = getFuncDescForGUID(Probe->GUID);
  305. InlineContextStack.emplace_back(FuncDesc->FuncName + ":" +
  306. Twine(Probe->Index).str());
  307. }
  308. const PseudoProbeFuncDesc *
  309. PseudoProbeDecoder::getInlinerDescForProbe(const PseudoProbe *Probe) const {
  310. PseudoProbeInlineTree *InlinerNode = Probe->InlineTree;
  311. if (!InlinerNode->hasInlineSite())
  312. return nullptr;
  313. return getFuncDescForGUID(std::get<0>(InlinerNode->ISite));
  314. }
  315. } // end namespace sampleprof
  316. } // end namespace llvm