xref: /openbsd/gnu/llvm/llvm/lib/MC/MCPseudoProbe.cpp (revision d415bd75)
1 //===- lib/MC/MCPseudoProbe.cpp - Pseudo probe encoding support ----------===//
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 #include "llvm/MC/MCPseudoProbe.h"
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/MC/MCAsmInfo.h"
12 #include "llvm/MC/MCContext.h"
13 #include "llvm/MC/MCExpr.h"
14 #include "llvm/MC/MCFragment.h"
15 #include "llvm/MC/MCObjectFileInfo.h"
16 #include "llvm/MC/MCObjectStreamer.h"
17 #include "llvm/MC/MCSymbol.h"
18 #include "llvm/Support/Endian.h"
19 #include "llvm/Support/LEB128.h"
20 #include "llvm/Support/MD5.h"
21 #include "llvm/Support/raw_ostream.h"
22 #include <algorithm>
23 #include <cassert>
24 #include <limits>
25 #include <memory>
26 #include <sstream>
27 #include <vector>
28 
29 #define DEBUG_TYPE "mcpseudoprobe"
30 
31 using namespace llvm;
32 using namespace support;
33 
34 #ifndef NDEBUG
35 int MCPseudoProbeTable::DdgPrintIndent = 0;
36 #endif
37 
buildSymbolDiff(MCObjectStreamer * MCOS,const MCSymbol * A,const MCSymbol * B)38 static const MCExpr *buildSymbolDiff(MCObjectStreamer *MCOS, const MCSymbol *A,
39                                      const MCSymbol *B) {
40   MCContext &Context = MCOS->getContext();
41   MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
42   const MCExpr *ARef = MCSymbolRefExpr::create(A, Variant, Context);
43   const MCExpr *BRef = MCSymbolRefExpr::create(B, Variant, Context);
44   const MCExpr *AddrDelta =
45       MCBinaryExpr::create(MCBinaryExpr::Sub, ARef, BRef, Context);
46   return AddrDelta;
47 }
48 
emit(MCObjectStreamer * MCOS,const MCPseudoProbe * LastProbe) const49 void MCPseudoProbe::emit(MCObjectStreamer *MCOS,
50                          const MCPseudoProbe *LastProbe) const {
51   bool IsSentinel = isSentinelProbe(getAttributes());
52   assert((LastProbe || IsSentinel) &&
53          "Last probe should not be null for non-sentinel probes");
54 
55   // Emit Index
56   MCOS->emitULEB128IntValue(Index);
57   // Emit Type and the flag:
58   // Type (bit 0 to 3), with bit 4 to 6 for attributes.
59   // Flag (bit 7, 0 - code address, 1 - address delta). This indicates whether
60   // the following field is a symbolic code address or an address delta.
61   assert(Type <= 0xF && "Probe type too big to encode, exceeding 15");
62   assert(Attributes <= 0x7 &&
63          "Probe attributes too big to encode, exceeding 7");
64   uint8_t PackedType = Type | (Attributes << 4);
65   uint8_t Flag =
66       !IsSentinel ? ((int8_t)MCPseudoProbeFlag::AddressDelta << 7) : 0;
67   MCOS->emitInt8(Flag | PackedType);
68 
69   if (!IsSentinel) {
70     // Emit the delta between the address label and LastProbe.
71     const MCExpr *AddrDelta =
72         buildSymbolDiff(MCOS, Label, LastProbe->getLabel());
73     int64_t Delta;
74     if (AddrDelta->evaluateAsAbsolute(Delta, MCOS->getAssemblerPtr())) {
75       MCOS->emitSLEB128IntValue(Delta);
76     } else {
77       MCOS->insert(new MCPseudoProbeAddrFragment(AddrDelta));
78     }
79   } else {
80     // Emit the GUID of the split function that the sentinel probe represents.
81     MCOS->emitInt64(Guid);
82   }
83 
84   LLVM_DEBUG({
85     dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
86     dbgs() << "Probe: " << Index << "\n";
87   });
88 }
89 
addPseudoProbe(const MCPseudoProbe & Probe,const MCPseudoProbeInlineStack & InlineStack)90 void MCPseudoProbeInlineTree::addPseudoProbe(
91     const MCPseudoProbe &Probe, const MCPseudoProbeInlineStack &InlineStack) {
92   // The function should not be called on the root.
93   assert(isRoot() && "Should only be called on root");
94 
95   // When it comes here, the input look like:
96   //    Probe: GUID of C, ...
97   //    InlineStack: [88, A], [66, B]
98   // which means, Function A inlines function B at call site with a probe id of
99   // 88, and B inlines C at probe 66. The tri-tree expects a tree path like {[0,
100   // A], [88, B], [66, C]} to locate the tree node where the probe should be
101   // added. Note that the edge [0, A] means A is the top-level function we are
102   // emitting probes for.
103 
104   // Make a [0, A] edge.
105   // An empty inline stack means the function that the probe originates from
106   // is a top-level function.
107   InlineSite Top;
108   if (InlineStack.empty()) {
109     Top = InlineSite(Probe.getGuid(), 0);
110   } else {
111     Top = InlineSite(std::get<0>(InlineStack.front()), 0);
112   }
113 
114   auto *Cur = getOrAddNode(Top);
115 
116   // Make interior edges by walking the inline stack. Once it's done, Cur should
117   // point to the node that the probe originates from.
118   if (!InlineStack.empty()) {
119     auto Iter = InlineStack.begin();
120     auto Index = std::get<1>(*Iter);
121     Iter++;
122     for (; Iter != InlineStack.end(); Iter++) {
123       // Make an edge by using the previous probe id and current GUID.
124       Cur = Cur->getOrAddNode(InlineSite(std::get<0>(*Iter), Index));
125       Index = std::get<1>(*Iter);
126     }
127     Cur = Cur->getOrAddNode(InlineSite(Probe.getGuid(), Index));
128   }
129 
130   Cur->Probes.push_back(Probe);
131 }
132 
emit(MCObjectStreamer * MCOS,const MCPseudoProbe * & LastProbe)133 void MCPseudoProbeInlineTree::emit(MCObjectStreamer *MCOS,
134                                    const MCPseudoProbe *&LastProbe) {
135   LLVM_DEBUG({
136     dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
137     dbgs() << "Group [\n";
138     MCPseudoProbeTable::DdgPrintIndent += 2;
139   });
140   assert(!isRoot() && "Root should be handled seperately");
141 
142   // Emit probes grouped by GUID.
143   LLVM_DEBUG({
144     dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
145     dbgs() << "GUID: " << Guid << "\n";
146   });
147   // Emit Guid
148   MCOS->emitInt64(Guid);
149   // Emit number of probes in this node, including a sentinel probe for
150   // top-level functions if needed.
151   bool NeedSentinel = false;
152   if (Parent->isRoot()) {
153     assert(isSentinelProbe(LastProbe->getAttributes()) &&
154            "Starting probe of a top-level function should be a sentinel probe");
155     // The main body of a split function doesn't need a sentinel probe.
156     if (LastProbe->getGuid() != Guid)
157       NeedSentinel = true;
158   }
159 
160   MCOS->emitULEB128IntValue(Probes.size() + NeedSentinel);
161   // Emit number of direct inlinees
162   MCOS->emitULEB128IntValue(Children.size());
163   // Emit sentinel probe for top-level functions
164   if (NeedSentinel)
165     LastProbe->emit(MCOS, nullptr);
166 
167   // Emit probes in this group
168   for (const auto &Probe : Probes) {
169     Probe.emit(MCOS, LastProbe);
170     LastProbe = &Probe;
171   }
172 
173   // Emit sorted descendant. InlineSite is unique for each pair, so there will
174   // be no ordering of Inlinee based on MCPseudoProbeInlineTree*
175   using InlineeType = std::pair<InlineSite, MCPseudoProbeInlineTree *>;
176   auto Comparer = [](const InlineeType &A, const InlineeType &B) {
177     return A.first < B.first;
178   };
179   std::vector<InlineeType> Inlinees;
180   for (const auto &Child : Children)
181     Inlinees.emplace_back(Child.first, Child.second.get());
182   std::sort(Inlinees.begin(), Inlinees.end(), Comparer);
183 
184   for (const auto &Inlinee : Inlinees) {
185     // Emit probe index
186     MCOS->emitULEB128IntValue(std::get<1>(Inlinee.first));
187     LLVM_DEBUG({
188       dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
189       dbgs() << "InlineSite: " << std::get<1>(Inlinee.first) << "\n";
190     });
191     // Emit the group
192     Inlinee.second->emit(MCOS, LastProbe);
193   }
194 
195   LLVM_DEBUG({
196     MCPseudoProbeTable::DdgPrintIndent -= 2;
197     dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
198     dbgs() << "]\n";
199   });
200 }
201 
emit(MCObjectStreamer * MCOS)202 void MCPseudoProbeSections::emit(MCObjectStreamer *MCOS) {
203   MCContext &Ctx = MCOS->getContext();
204   for (auto &ProbeSec : MCProbeDivisions) {
205     const auto *FuncSym = ProbeSec.first;
206     const auto &Root = ProbeSec.second;
207     if (auto *S = Ctx.getObjectFileInfo()->getPseudoProbeSection(
208             FuncSym->getSection())) {
209       // Switch to the .pseudoprobe section or a comdat group.
210       MCOS->switchSection(S);
211       // Emit probes grouped by GUID.
212       // Emit sorted descendant. InlineSite is unique for each pair, so there
213       // will be no ordering of Inlinee based on MCPseudoProbeInlineTree*
214       using InlineeType = std::pair<InlineSite, MCPseudoProbeInlineTree *>;
215       auto Comparer = [](const InlineeType &A, const InlineeType &B) {
216         return A.first < B.first;
217       };
218       std::vector<InlineeType> Inlinees;
219       for (const auto &Child : Root.getChildren())
220         Inlinees.emplace_back(Child.first, Child.second.get());
221       std::sort(Inlinees.begin(), Inlinees.end(), Comparer);
222 
223       for (const auto &Inlinee : Inlinees) {
224         // Emit the group guarded by a sentinel probe.
225         MCPseudoProbe SentinelProbe(const_cast<MCSymbol *>(FuncSym),
226                                     MD5Hash(FuncSym->getName()),
227                                     (uint32_t)PseudoProbeReservedId::Invalid,
228                                     (uint32_t)PseudoProbeType::Block,
229                                     (uint32_t)PseudoProbeAttributes::Sentinel);
230         const MCPseudoProbe *Probe = &SentinelProbe;
231         Inlinee.second->emit(MCOS, Probe);
232       }
233     }
234   }
235 }
236 
237 //
238 // This emits the pseudo probe tables.
239 //
emit(MCObjectStreamer * MCOS)240 void MCPseudoProbeTable::emit(MCObjectStreamer *MCOS) {
241   MCContext &Ctx = MCOS->getContext();
242   auto &ProbeTable = Ctx.getMCPseudoProbeTable();
243 
244   // Bail out early so we don't switch to the pseudo_probe section needlessly
245   // and in doing so create an unnecessary (if empty) section.
246   auto &ProbeSections = ProbeTable.getProbeSections();
247   if (ProbeSections.empty())
248     return;
249 
250   LLVM_DEBUG(MCPseudoProbeTable::DdgPrintIndent = 0);
251 
252   // Put out the probe.
253   ProbeSections.emit(MCOS);
254 }
255 
getProbeFNameForGUID(const GUIDProbeFunctionMap & GUID2FuncMAP,uint64_t GUID)256 static StringRef getProbeFNameForGUID(const GUIDProbeFunctionMap &GUID2FuncMAP,
257                                       uint64_t GUID) {
258   auto It = GUID2FuncMAP.find(GUID);
259   assert(It != GUID2FuncMAP.end() &&
260          "Probe function must exist for a valid GUID");
261   return It->second.FuncName;
262 }
263 
print(raw_ostream & OS)264 void MCPseudoProbeFuncDesc::print(raw_ostream &OS) {
265   OS << "GUID: " << FuncGUID << " Name: " << FuncName << "\n";
266   OS << "Hash: " << FuncHash << "\n";
267 }
268 
getInlineContext(SmallVectorImpl<MCPseduoProbeFrameLocation> & ContextStack,const GUIDProbeFunctionMap & GUID2FuncMAP) const269 void MCDecodedPseudoProbe::getInlineContext(
270     SmallVectorImpl<MCPseduoProbeFrameLocation> &ContextStack,
271     const GUIDProbeFunctionMap &GUID2FuncMAP) const {
272   uint32_t Begin = ContextStack.size();
273   MCDecodedPseudoProbeInlineTree *Cur = InlineTree;
274   // It will add the string of each node's inline site during iteration.
275   // Note that it won't include the probe's belonging function(leaf location)
276   while (Cur->hasInlineSite()) {
277     StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, Cur->Parent->Guid);
278     ContextStack.emplace_back(
279         MCPseduoProbeFrameLocation(FuncName, std::get<1>(Cur->ISite)));
280     Cur = static_cast<MCDecodedPseudoProbeInlineTree *>(Cur->Parent);
281   }
282   // Make the ContextStack in caller-callee order
283   std::reverse(ContextStack.begin() + Begin, ContextStack.end());
284 }
285 
getInlineContextStr(const GUIDProbeFunctionMap & GUID2FuncMAP) const286 std::string MCDecodedPseudoProbe::getInlineContextStr(
287     const GUIDProbeFunctionMap &GUID2FuncMAP) const {
288   std::ostringstream OContextStr;
289   SmallVector<MCPseduoProbeFrameLocation, 16> ContextStack;
290   getInlineContext(ContextStack, GUID2FuncMAP);
291   for (auto &Cxt : ContextStack) {
292     if (OContextStr.str().size())
293       OContextStr << " @ ";
294     OContextStr << Cxt.first.str() << ":" << Cxt.second;
295   }
296   return OContextStr.str();
297 }
298 
299 static const char *PseudoProbeTypeStr[3] = {"Block", "IndirectCall",
300                                             "DirectCall"};
301 
print(raw_ostream & OS,const GUIDProbeFunctionMap & GUID2FuncMAP,bool ShowName) const302 void MCDecodedPseudoProbe::print(raw_ostream &OS,
303                                  const GUIDProbeFunctionMap &GUID2FuncMAP,
304                                  bool ShowName) const {
305   OS << "FUNC: ";
306   if (ShowName) {
307     StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, Guid);
308     OS << FuncName.str() << " ";
309   } else {
310     OS << Guid << " ";
311   }
312   OS << "Index: " << Index << "  ";
313   OS << "Type: " << PseudoProbeTypeStr[static_cast<uint8_t>(Type)] << "  ";
314   std::string InlineContextStr = getInlineContextStr(GUID2FuncMAP);
315   if (InlineContextStr.size()) {
316     OS << "Inlined: @ ";
317     OS << InlineContextStr;
318   }
319   OS << "\n";
320 }
321 
readUnencodedNumber()322 template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnencodedNumber() {
323   if (Data + sizeof(T) > End) {
324     return std::error_code();
325   }
326   T Val = endian::readNext<T, little, unaligned>(Data);
327   return ErrorOr<T>(Val);
328 }
329 
readUnsignedNumber()330 template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnsignedNumber() {
331   unsigned NumBytesRead = 0;
332   uint64_t Val = decodeULEB128(Data, &NumBytesRead);
333   if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) {
334     return std::error_code();
335   }
336   Data += NumBytesRead;
337   return ErrorOr<T>(static_cast<T>(Val));
338 }
339 
readSignedNumber()340 template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readSignedNumber() {
341   unsigned NumBytesRead = 0;
342   int64_t Val = decodeSLEB128(Data, &NumBytesRead);
343   if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) {
344     return std::error_code();
345   }
346   Data += NumBytesRead;
347   return ErrorOr<T>(static_cast<T>(Val));
348 }
349 
readString(uint32_t Size)350 ErrorOr<StringRef> MCPseudoProbeDecoder::readString(uint32_t Size) {
351   StringRef Str(reinterpret_cast<const char *>(Data), Size);
352   if (Data + Size > End) {
353     return std::error_code();
354   }
355   Data += Size;
356   return ErrorOr<StringRef>(Str);
357 }
358 
buildGUID2FuncDescMap(const uint8_t * Start,std::size_t Size)359 bool MCPseudoProbeDecoder::buildGUID2FuncDescMap(const uint8_t *Start,
360                                                  std::size_t Size) {
361   // The pseudo_probe_desc section has a format like:
362   // .section .pseudo_probe_desc,"",@progbits
363   // .quad -5182264717993193164   // GUID
364   // .quad 4294967295             // Hash
365   // .uleb 3                      // Name size
366   // .ascii "foo"                 // Name
367   // .quad -2624081020897602054
368   // .quad 174696971957
369   // .uleb 34
370   // .ascii "main"
371 
372   Data = Start;
373   End = Data + Size;
374 
375   while (Data < End) {
376     auto ErrorOrGUID = readUnencodedNumber<uint64_t>();
377     if (!ErrorOrGUID)
378       return false;
379 
380     auto ErrorOrHash = readUnencodedNumber<uint64_t>();
381     if (!ErrorOrHash)
382       return false;
383 
384     auto ErrorOrNameSize = readUnsignedNumber<uint32_t>();
385     if (!ErrorOrNameSize)
386       return false;
387     uint32_t NameSize = std::move(*ErrorOrNameSize);
388 
389     auto ErrorOrName = readString(NameSize);
390     if (!ErrorOrName)
391       return false;
392 
393     uint64_t GUID = std::move(*ErrorOrGUID);
394     uint64_t Hash = std::move(*ErrorOrHash);
395     StringRef Name = std::move(*ErrorOrName);
396 
397     // Initialize PseudoProbeFuncDesc and populate it into GUID2FuncDescMap
398     GUID2FuncDescMap.emplace(GUID, MCPseudoProbeFuncDesc(GUID, Hash, Name));
399   }
400   assert(Data == End && "Have unprocessed data in pseudo_probe_desc section");
401   return true;
402 }
403 
buildAddress2ProbeMap(MCDecodedPseudoProbeInlineTree * Cur,uint64_t & LastAddr,const Uint64Set & GuidFilter,const Uint64Map & FuncStartAddrs)404 bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
405     MCDecodedPseudoProbeInlineTree *Cur, uint64_t &LastAddr,
406     const Uint64Set &GuidFilter, const Uint64Map &FuncStartAddrs) {
407   // The pseudo_probe section encodes an inline forest and each tree has a
408   // format defined in MCPseudoProbe.h
409 
410   uint32_t Index = 0;
411   bool IsTopLevelFunc = Cur == &DummyInlineRoot;
412   if (IsTopLevelFunc) {
413     // Use a sequential id for top level inliner.
414     Index = Cur->getChildren().size();
415   } else {
416     // Read inline site for inlinees
417     auto ErrorOrIndex = readUnsignedNumber<uint32_t>();
418     if (!ErrorOrIndex)
419       return false;
420     Index = std::move(*ErrorOrIndex);
421   }
422 
423   // Read guid
424   auto ErrorOrCurGuid = readUnencodedNumber<uint64_t>();
425   if (!ErrorOrCurGuid)
426     return false;
427   uint64_t Guid = std::move(*ErrorOrCurGuid);
428 
429   // Decide if top-level node should be disgarded.
430   if (IsTopLevelFunc && !GuidFilter.empty() && !GuidFilter.count(Guid))
431     Cur = nullptr;
432 
433   // If the incoming node is null, all its children nodes should be disgarded.
434   if (Cur) {
435     // Switch/add to a new tree node(inlinee)
436     Cur = Cur->getOrAddNode(std::make_tuple(Guid, Index));
437     Cur->Guid = Guid;
438     if (IsTopLevelFunc && !EncodingIsAddrBased) {
439       if (auto V = FuncStartAddrs.lookup(Guid))
440         LastAddr = V;
441     }
442   }
443 
444   // Read number of probes in the current node.
445   auto ErrorOrNodeCount = readUnsignedNumber<uint32_t>();
446   if (!ErrorOrNodeCount)
447     return false;
448   uint32_t NodeCount = std::move(*ErrorOrNodeCount);
449   // Read number of direct inlinees
450   auto ErrorOrCurChildrenToProcess = readUnsignedNumber<uint32_t>();
451   if (!ErrorOrCurChildrenToProcess)
452     return false;
453   // Read all probes in this node
454   for (std::size_t I = 0; I < NodeCount; I++) {
455     // Read index
456     auto ErrorOrIndex = readUnsignedNumber<uint32_t>();
457     if (!ErrorOrIndex)
458       return false;
459     uint32_t Index = std::move(*ErrorOrIndex);
460     // Read type | flag.
461     auto ErrorOrValue = readUnencodedNumber<uint8_t>();
462     if (!ErrorOrValue)
463       return false;
464     uint8_t Value = std::move(*ErrorOrValue);
465     uint8_t Kind = Value & 0xf;
466     uint8_t Attr = (Value & 0x70) >> 4;
467     // Read address
468     uint64_t Addr = 0;
469     if (Value & 0x80) {
470       auto ErrorOrOffset = readSignedNumber<int64_t>();
471       if (!ErrorOrOffset)
472         return false;
473       int64_t Offset = std::move(*ErrorOrOffset);
474       Addr = LastAddr + Offset;
475     } else {
476       auto ErrorOrAddr = readUnencodedNumber<int64_t>();
477       if (!ErrorOrAddr)
478         return false;
479       Addr = std::move(*ErrorOrAddr);
480       if (isSentinelProbe(Attr)) {
481         // For sentinel probe, the addr field actually stores the GUID of the
482         // split function. Convert it to the real address.
483         if (auto V = FuncStartAddrs.lookup(Addr))
484           Addr = V;
485       } else {
486         // For now we assume all probe encoding should be either based on
487         // leading probe address or function start address.
488         // The scheme is for downwards compatibility.
489         // TODO: retire this scheme once compatibility is no longer an issue.
490         EncodingIsAddrBased = true;
491       }
492     }
493 
494     if (Cur && !isSentinelProbe(Attr)) {
495       // Populate Address2ProbesMap
496       auto &Probes = Address2ProbesMap[Addr];
497       Probes.emplace_back(Addr, Cur->Guid, Index, PseudoProbeType(Kind), Attr,
498                           Cur);
499       Cur->addProbes(&Probes.back());
500     }
501     LastAddr = Addr;
502   }
503 
504   uint32_t ChildrenToProcess = std::move(*ErrorOrCurChildrenToProcess);
505   for (uint32_t I = 0; I < ChildrenToProcess; I++) {
506     buildAddress2ProbeMap(Cur, LastAddr, GuidFilter, FuncStartAddrs);
507   }
508 
509   return true;
510 }
511 
buildAddress2ProbeMap(const uint8_t * Start,std::size_t Size,const Uint64Set & GuidFilter,const Uint64Map & FuncStartAddrs)512 bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
513     const uint8_t *Start, std::size_t Size, const Uint64Set &GuidFilter,
514     const Uint64Map &FuncStartAddrs) {
515   Data = Start;
516   End = Data + Size;
517   uint64_t LastAddr = 0;
518   while (Data < End)
519     buildAddress2ProbeMap(&DummyInlineRoot, LastAddr, GuidFilter,
520                           FuncStartAddrs);
521   assert(Data == End && "Have unprocessed data in pseudo_probe section");
522   return true;
523 }
524 
printGUID2FuncDescMap(raw_ostream & OS)525 void MCPseudoProbeDecoder::printGUID2FuncDescMap(raw_ostream &OS) {
526   OS << "Pseudo Probe Desc:\n";
527   // Make the output deterministic
528   std::map<uint64_t, MCPseudoProbeFuncDesc> OrderedMap(GUID2FuncDescMap.begin(),
529                                                        GUID2FuncDescMap.end());
530   for (auto &I : OrderedMap) {
531     I.second.print(OS);
532   }
533 }
534 
printProbeForAddress(raw_ostream & OS,uint64_t Address)535 void MCPseudoProbeDecoder::printProbeForAddress(raw_ostream &OS,
536                                                 uint64_t Address) {
537   auto It = Address2ProbesMap.find(Address);
538   if (It != Address2ProbesMap.end()) {
539     for (auto &Probe : It->second) {
540       OS << " [Probe]:\t";
541       Probe.print(OS, GUID2FuncDescMap, true);
542     }
543   }
544 }
545 
printProbesForAllAddresses(raw_ostream & OS)546 void MCPseudoProbeDecoder::printProbesForAllAddresses(raw_ostream &OS) {
547   std::vector<uint64_t> Addresses;
548   for (auto Entry : Address2ProbesMap)
549     Addresses.push_back(Entry.first);
550   llvm::sort(Addresses);
551   for (auto K : Addresses) {
552     OS << "Address:\t";
553     OS << K;
554     OS << "\n";
555     printProbeForAddress(OS, K);
556   }
557 }
558 
559 const MCDecodedPseudoProbe *
getCallProbeForAddr(uint64_t Address) const560 MCPseudoProbeDecoder::getCallProbeForAddr(uint64_t Address) const {
561   auto It = Address2ProbesMap.find(Address);
562   if (It == Address2ProbesMap.end())
563     return nullptr;
564   const auto &Probes = It->second;
565 
566   const MCDecodedPseudoProbe *CallProbe = nullptr;
567   for (const auto &Probe : Probes) {
568     if (Probe.isCall()) {
569       assert(!CallProbe &&
570              "There should be only one call probe corresponding to address "
571              "which is a callsite.");
572       CallProbe = &Probe;
573     }
574   }
575   return CallProbe;
576 }
577 
578 const MCPseudoProbeFuncDesc *
getFuncDescForGUID(uint64_t GUID) const579 MCPseudoProbeDecoder::getFuncDescForGUID(uint64_t GUID) const {
580   auto It = GUID2FuncDescMap.find(GUID);
581   assert(It != GUID2FuncDescMap.end() && "Function descriptor doesn't exist");
582   return &It->second;
583 }
584 
getInlineContextForProbe(const MCDecodedPseudoProbe * Probe,SmallVectorImpl<MCPseduoProbeFrameLocation> & InlineContextStack,bool IncludeLeaf) const585 void MCPseudoProbeDecoder::getInlineContextForProbe(
586     const MCDecodedPseudoProbe *Probe,
587     SmallVectorImpl<MCPseduoProbeFrameLocation> &InlineContextStack,
588     bool IncludeLeaf) const {
589   Probe->getInlineContext(InlineContextStack, GUID2FuncDescMap);
590   if (!IncludeLeaf)
591     return;
592   // Note that the context from probe doesn't include leaf frame,
593   // hence we need to retrieve and prepend leaf if requested.
594   const auto *FuncDesc = getFuncDescForGUID(Probe->getGuid());
595   InlineContextStack.emplace_back(
596       MCPseduoProbeFrameLocation(FuncDesc->FuncName, Probe->getIndex()));
597 }
598 
getInlinerDescForProbe(const MCDecodedPseudoProbe * Probe) const599 const MCPseudoProbeFuncDesc *MCPseudoProbeDecoder::getInlinerDescForProbe(
600     const MCDecodedPseudoProbe *Probe) const {
601   MCDecodedPseudoProbeInlineTree *InlinerNode = Probe->getInlineTreeNode();
602   if (!InlinerNode->hasInlineSite())
603     return nullptr;
604   return getFuncDescForGUID(InlinerNode->Parent->Guid);
605 }
606