xref: /freebsd/contrib/llvm-project/llvm/lib/MC/MCPseudoProbe.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/IR/PseudoProbe.h"
12 #include "llvm/MC/MCAsmInfo.h"
13 #include "llvm/MC/MCAssembler.h"
14 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCExpr.h"
16 #include "llvm/MC/MCObjectFileInfo.h"
17 #include "llvm/MC/MCObjectStreamer.h"
18 #include "llvm/MC/MCSymbol.h"
19 #include "llvm/Support/Endian.h"
20 #include "llvm/Support/Error.h"
21 #include "llvm/Support/LEB128.h"
22 #include "llvm/Support/MD5.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include <algorithm>
25 #include <cassert>
26 #include <limits>
27 #include <memory>
28 #include <sstream>
29 #include <vector>
30 
31 #define DEBUG_TYPE "mcpseudoprobe"
32 
33 using namespace llvm;
34 using namespace support;
35 
36 #ifndef NDEBUG
37 int MCPseudoProbeTable::DdgPrintIndent = 0;
38 #endif
39 
buildSymbolDiff(MCObjectStreamer * MCOS,const MCSymbol * A,const MCSymbol * B)40 static const MCExpr *buildSymbolDiff(MCObjectStreamer *MCOS, const MCSymbol *A,
41                                      const MCSymbol *B) {
42   MCContext &Context = MCOS->getContext();
43   const MCExpr *ARef = MCSymbolRefExpr::create(A, Context);
44   const MCExpr *BRef = MCSymbolRefExpr::create(B, Context);
45   const MCExpr *AddrDelta =
46       MCBinaryExpr::create(MCBinaryExpr::Sub, ARef, BRef, Context);
47   return AddrDelta;
48 }
49 
getGuid() const50 uint64_t MCDecodedPseudoProbe::getGuid() const { return InlineTree->Guid; }
51 
emit(MCObjectStreamer * MCOS,const MCPseudoProbe * LastProbe) const52 void MCPseudoProbe::emit(MCObjectStreamer *MCOS,
53                          const MCPseudoProbe *LastProbe) const {
54   bool IsSentinel = isSentinelProbe(getAttributes());
55   assert((LastProbe || IsSentinel) &&
56          "Last probe should not be null for non-sentinel probes");
57 
58   // Emit Index
59   MCOS->emitULEB128IntValue(Index);
60   // Emit Type and the flag:
61   // Type (bit 0 to 3), with bit 4 to 6 for attributes.
62   // Flag (bit 7, 0 - code address, 1 - address delta). This indicates whether
63   // the following field is a symbolic code address or an address delta.
64   // Emit FS discriminator
65   assert(Type <= 0xF && "Probe type too big to encode, exceeding 15");
66   auto NewAttributes = Attributes;
67   if (Discriminator)
68     NewAttributes |= (uint32_t)PseudoProbeAttributes::HasDiscriminator;
69   assert(NewAttributes <= 0x7 &&
70          "Probe attributes too big to encode, exceeding 7");
71   uint8_t PackedType = Type | (NewAttributes << 4);
72   uint8_t Flag =
73       !IsSentinel ? ((int8_t)MCPseudoProbeFlag::AddressDelta << 7) : 0;
74   MCOS->emitInt8(Flag | PackedType);
75 
76   if (!IsSentinel) {
77     // Emit the delta between the address label and LastProbe.
78     const MCExpr *AddrDelta =
79         buildSymbolDiff(MCOS, Label, LastProbe->getLabel());
80     int64_t Delta;
81     if (AddrDelta->evaluateAsAbsolute(Delta, MCOS->getAssemblerPtr())) {
82       MCOS->emitSLEB128IntValue(Delta);
83     } else {
84       MCOS->insert(MCOS->getContext().allocFragment<MCPseudoProbeAddrFragment>(
85           AddrDelta));
86     }
87   } else {
88     // Emit the GUID of the split function that the sentinel probe represents.
89     MCOS->emitInt64(Guid);
90   }
91 
92   if (Discriminator)
93     MCOS->emitULEB128IntValue(Discriminator);
94 
95   LLVM_DEBUG({
96     dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
97     dbgs() << "Probe: " << Index << "\n";
98   });
99 }
100 
addPseudoProbe(const MCPseudoProbe & Probe,const MCPseudoProbeInlineStack & InlineStack)101 void MCPseudoProbeInlineTree::addPseudoProbe(
102     const MCPseudoProbe &Probe, const MCPseudoProbeInlineStack &InlineStack) {
103   // The function should not be called on the root.
104   assert(isRoot() && "Should only be called on root");
105 
106   // When it comes here, the input look like:
107   //    Probe: GUID of C, ...
108   //    InlineStack: [88, A], [66, B]
109   // which means, Function A inlines function B at call site with a probe id of
110   // 88, and B inlines C at probe 66. The tri-tree expects a tree path like {[0,
111   // A], [88, B], [66, C]} to locate the tree node where the probe should be
112   // added. Note that the edge [0, A] means A is the top-level function we are
113   // emitting probes for.
114 
115   // Make a [0, A] edge.
116   // An empty inline stack means the function that the probe originates from
117   // is a top-level function.
118   InlineSite Top;
119   if (InlineStack.empty()) {
120     Top = InlineSite(Probe.getGuid(), 0);
121   } else {
122     Top = InlineSite(std::get<0>(InlineStack.front()), 0);
123   }
124 
125   auto *Cur = getOrAddNode(Top);
126 
127   // Make interior edges by walking the inline stack. Once it's done, Cur should
128   // point to the node that the probe originates from.
129   if (!InlineStack.empty()) {
130     auto Iter = InlineStack.begin();
131     auto Index = std::get<1>(*Iter);
132     Iter++;
133     for (; Iter != InlineStack.end(); Iter++) {
134       // Make an edge by using the previous probe id and current GUID.
135       Cur = Cur->getOrAddNode(InlineSite(std::get<0>(*Iter), Index));
136       Index = std::get<1>(*Iter);
137     }
138     Cur = Cur->getOrAddNode(InlineSite(Probe.getGuid(), Index));
139   }
140 
141   Cur->Probes.push_back(Probe);
142 }
143 
emit(MCObjectStreamer * MCOS,const MCPseudoProbe * & LastProbe)144 void MCPseudoProbeInlineTree::emit(MCObjectStreamer *MCOS,
145                                    const MCPseudoProbe *&LastProbe) {
146   LLVM_DEBUG({
147     dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
148     dbgs() << "Group [\n";
149     MCPseudoProbeTable::DdgPrintIndent += 2;
150   });
151   assert(!isRoot() && "Root should be handled separately");
152 
153   // Emit probes grouped by GUID.
154   LLVM_DEBUG({
155     dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
156     dbgs() << "GUID: " << Guid << "\n";
157   });
158   // Emit Guid
159   MCOS->emitInt64(Guid);
160   // Emit number of probes in this node, including a sentinel probe for
161   // top-level functions if needed.
162   bool NeedSentinel = false;
163   if (Parent->isRoot()) {
164     assert(isSentinelProbe(LastProbe->getAttributes()) &&
165            "Starting probe of a top-level function should be a sentinel probe");
166     // The main body of a split function doesn't need a sentinel probe.
167     if (LastProbe->getGuid() != Guid)
168       NeedSentinel = true;
169   }
170 
171   MCOS->emitULEB128IntValue(Probes.size() + NeedSentinel);
172   // Emit number of direct inlinees
173   MCOS->emitULEB128IntValue(Children.size());
174   // Emit sentinel probe for top-level functions
175   if (NeedSentinel)
176     LastProbe->emit(MCOS, nullptr);
177 
178   // Emit probes in this group
179   for (const auto &Probe : Probes) {
180     Probe.emit(MCOS, LastProbe);
181     LastProbe = &Probe;
182   }
183 
184   // Emit sorted descendant. InlineSite is unique for each pair, so there will
185   // be no ordering of Inlinee based on MCPseudoProbeInlineTree*
186   using InlineeType = std::pair<InlineSite, MCPseudoProbeInlineTree *>;
187   std::vector<InlineeType> Inlinees;
188   for (const auto &Child : Children)
189     Inlinees.emplace_back(Child.first, Child.second.get());
190   llvm::sort(Inlinees, llvm::less_first());
191 
192   for (const auto &Inlinee : Inlinees) {
193     // Emit probe index
194     MCOS->emitULEB128IntValue(std::get<1>(Inlinee.first));
195     LLVM_DEBUG({
196       dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
197       dbgs() << "InlineSite: " << std::get<1>(Inlinee.first) << "\n";
198     });
199     // Emit the group
200     Inlinee.second->emit(MCOS, LastProbe);
201   }
202 
203   LLVM_DEBUG({
204     MCPseudoProbeTable::DdgPrintIndent -= 2;
205     dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
206     dbgs() << "]\n";
207   });
208 }
209 
emit(MCObjectStreamer * MCOS)210 void MCPseudoProbeSections::emit(MCObjectStreamer *MCOS) {
211   MCContext &Ctx = MCOS->getContext();
212   SmallVector<std::pair<MCSymbol *, MCPseudoProbeInlineTree *>> Vec;
213   Vec.reserve(MCProbeDivisions.size());
214   for (auto &ProbeSec : MCProbeDivisions)
215     Vec.emplace_back(ProbeSec.first, &ProbeSec.second);
216   for (auto I : llvm::enumerate(MCOS->getAssembler()))
217     I.value().setOrdinal(I.index());
218   llvm::sort(Vec, [](auto A, auto B) {
219     return A.first->getSection().getOrdinal() <
220            B.first->getSection().getOrdinal();
221   });
222   for (auto [FuncSym, RootPtr] : Vec) {
223     const auto &Root = *RootPtr;
224     if (auto *S = Ctx.getObjectFileInfo()->getPseudoProbeSection(
225             FuncSym->getSection())) {
226       // Switch to the .pseudoprobe section or a comdat group.
227       MCOS->switchSection(S);
228       // Emit probes grouped by GUID.
229       // Emit sorted descendant. InlineSite is unique for each pair, so there
230       // will be no ordering of Inlinee based on MCPseudoProbeInlineTree*
231       using InlineeType = std::pair<InlineSite, MCPseudoProbeInlineTree *>;
232       std::vector<InlineeType> Inlinees;
233       for (const auto &Child : Root.getChildren())
234         Inlinees.emplace_back(Child.first, Child.second.get());
235       llvm::sort(Inlinees, llvm::less_first());
236 
237       for (const auto &Inlinee : Inlinees) {
238         // Emit the group guarded by a sentinel probe.
239         MCPseudoProbe SentinelProbe(
240             const_cast<MCSymbol *>(FuncSym), MD5Hash(FuncSym->getName()),
241             (uint32_t)PseudoProbeReservedId::Invalid,
242             (uint32_t)PseudoProbeType::Block,
243             (uint32_t)PseudoProbeAttributes::Sentinel, 0);
244         const MCPseudoProbe *Probe = &SentinelProbe;
245         Inlinee.second->emit(MCOS, Probe);
246       }
247     }
248   }
249 }
250 
251 //
252 // This emits the pseudo probe tables.
253 //
emit(MCObjectStreamer * MCOS)254 void MCPseudoProbeTable::emit(MCObjectStreamer *MCOS) {
255   MCContext &Ctx = MCOS->getContext();
256   auto &ProbeTable = Ctx.getMCPseudoProbeTable();
257 
258   // Bail out early so we don't switch to the pseudo_probe section needlessly
259   // and in doing so create an unnecessary (if empty) section.
260   auto &ProbeSections = ProbeTable.getProbeSections();
261   if (ProbeSections.empty())
262     return;
263 
264   LLVM_DEBUG(MCPseudoProbeTable::DdgPrintIndent = 0);
265 
266   // Put out the probe.
267   ProbeSections.emit(MCOS);
268 }
269 
getProbeFNameForGUID(const GUIDProbeFunctionMap & GUID2FuncMAP,uint64_t GUID)270 static StringRef getProbeFNameForGUID(const GUIDProbeFunctionMap &GUID2FuncMAP,
271                                       uint64_t GUID) {
272   auto It = GUID2FuncMAP.find(GUID);
273   assert(It != GUID2FuncMAP.end() &&
274          "Probe function must exist for a valid GUID");
275   return It->FuncName;
276 }
277 
print(raw_ostream & OS)278 void MCPseudoProbeFuncDesc::print(raw_ostream &OS) {
279   OS << "GUID: " << FuncGUID << " Name: " << FuncName << "\n";
280   OS << "Hash: " << FuncHash << "\n";
281 }
282 
getInlineContext(SmallVectorImpl<MCPseudoProbeFrameLocation> & ContextStack,const GUIDProbeFunctionMap & GUID2FuncMAP) const283 void MCDecodedPseudoProbe::getInlineContext(
284     SmallVectorImpl<MCPseudoProbeFrameLocation> &ContextStack,
285     const GUIDProbeFunctionMap &GUID2FuncMAP) const {
286   uint32_t Begin = ContextStack.size();
287   MCDecodedPseudoProbeInlineTree *Cur = InlineTree;
288   // It will add the string of each node's inline site during iteration.
289   // Note that it won't include the probe's belonging function(leaf location)
290   while (Cur->hasInlineSite()) {
291     StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, Cur->Parent->Guid);
292     ContextStack.emplace_back(MCPseudoProbeFrameLocation(
293         FuncName, std::get<1>(Cur->getInlineSite())));
294     Cur = static_cast<MCDecodedPseudoProbeInlineTree *>(Cur->Parent);
295   }
296   // Make the ContextStack in caller-callee order
297   std::reverse(ContextStack.begin() + Begin, ContextStack.end());
298 }
299 
getInlineContextStr(const GUIDProbeFunctionMap & GUID2FuncMAP) const300 std::string MCDecodedPseudoProbe::getInlineContextStr(
301     const GUIDProbeFunctionMap &GUID2FuncMAP) const {
302   std::ostringstream OContextStr;
303   SmallVector<MCPseudoProbeFrameLocation, 16> ContextStack;
304   getInlineContext(ContextStack, GUID2FuncMAP);
305   for (auto &Cxt : ContextStack) {
306     if (OContextStr.str().size())
307       OContextStr << " @ ";
308     OContextStr << Cxt.first.str() << ":" << Cxt.second;
309   }
310   return OContextStr.str();
311 }
312 
313 static const char *PseudoProbeTypeStr[3] = {"Block", "IndirectCall",
314                                             "DirectCall"};
315 
print(raw_ostream & OS,const GUIDProbeFunctionMap & GUID2FuncMAP,bool ShowName) const316 void MCDecodedPseudoProbe::print(raw_ostream &OS,
317                                  const GUIDProbeFunctionMap &GUID2FuncMAP,
318                                  bool ShowName) const {
319   OS << "FUNC: ";
320   if (ShowName) {
321     StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, getGuid());
322     OS << FuncName.str() << " ";
323   } else {
324     OS << getGuid() << " ";
325   }
326   OS << "Index: " << Index << "  ";
327   if (Discriminator)
328     OS << "Discriminator: " << Discriminator << "  ";
329   OS << "Type: " << PseudoProbeTypeStr[static_cast<uint8_t>(Type)] << "  ";
330   std::string InlineContextStr = getInlineContextStr(GUID2FuncMAP);
331   if (InlineContextStr.size()) {
332     OS << "Inlined: @ ";
333     OS << InlineContextStr;
334   }
335   OS << "\n";
336 }
337 
readUnencodedNumber()338 template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnencodedNumber() {
339   if (Data + sizeof(T) > End) {
340     return std::error_code();
341   }
342   T Val = endian::readNext<T, llvm::endianness::little>(Data);
343   return ErrorOr<T>(Val);
344 }
345 
readUnsignedNumber()346 template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnsignedNumber() {
347   unsigned NumBytesRead = 0;
348   uint64_t Val = decodeULEB128(Data, &NumBytesRead);
349   if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) {
350     return std::error_code();
351   }
352   Data += NumBytesRead;
353   return ErrorOr<T>(static_cast<T>(Val));
354 }
355 
readSignedNumber()356 template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readSignedNumber() {
357   unsigned NumBytesRead = 0;
358   int64_t Val = decodeSLEB128(Data, &NumBytesRead);
359   if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) {
360     return std::error_code();
361   }
362   Data += NumBytesRead;
363   return ErrorOr<T>(static_cast<T>(Val));
364 }
365 
readString(uint32_t Size)366 ErrorOr<StringRef> MCPseudoProbeDecoder::readString(uint32_t Size) {
367   StringRef Str(reinterpret_cast<const char *>(Data), Size);
368   if (Data + Size > End) {
369     return std::error_code();
370   }
371   Data += Size;
372   return ErrorOr<StringRef>(Str);
373 }
374 
buildGUID2FuncDescMap(const uint8_t * Start,std::size_t Size,bool IsMMapped)375 bool MCPseudoProbeDecoder::buildGUID2FuncDescMap(const uint8_t *Start,
376                                                  std::size_t Size,
377                                                  bool IsMMapped) {
378   // The pseudo_probe_desc section has a format like:
379   // .section .pseudo_probe_desc,"",@progbits
380   // .quad -5182264717993193164   // GUID
381   // .quad 4294967295             // Hash
382   // .uleb 3                      // Name size
383   // .ascii "foo"                 // Name
384   // .quad -2624081020897602054
385   // .quad 174696971957
386   // .uleb 34
387   // .ascii "main"
388 
389   Data = Start;
390   End = Data + Size;
391 
392   uint32_t FuncDescCount = 0;
393   while (Data < End) {
394     // GUID
395     if (!readUnencodedNumber<uint64_t>())
396       return false;
397     // Hash
398     if (!readUnencodedNumber<uint64_t>())
399       return false;
400 
401     auto ErrorOrNameSize = readUnsignedNumber<uint32_t>();
402     if (!ErrorOrNameSize)
403       return false;
404     // Function name
405     if (!readString(*ErrorOrNameSize))
406       return false;
407     ++FuncDescCount;
408   }
409   assert(Data == End && "Have unprocessed data in pseudo_probe_desc section");
410   GUID2FuncDescMap.reserve(FuncDescCount);
411 
412   Data = Start;
413   End = Data + Size;
414   while (Data < End) {
415     uint64_t GUID =
416         cantFail(errorOrToExpected(readUnencodedNumber<uint64_t>()));
417     uint64_t Hash =
418         cantFail(errorOrToExpected(readUnencodedNumber<uint64_t>()));
419     uint32_t NameSize =
420         cantFail(errorOrToExpected(readUnsignedNumber<uint32_t>()));
421     StringRef Name = cantFail(errorOrToExpected(readString(NameSize)));
422 
423     // Initialize PseudoProbeFuncDesc and populate it into GUID2FuncDescMap
424     GUID2FuncDescMap.emplace_back(
425         GUID, Hash, IsMMapped ? Name : Name.copy(FuncNameAllocator));
426   }
427   assert(Data == End && "Have unprocessed data in pseudo_probe_desc section");
428   assert(GUID2FuncDescMap.size() == FuncDescCount &&
429          "Mismatching function description count pre- and post-parsing");
430   llvm::sort(GUID2FuncDescMap, [](const auto &LHS, const auto &RHS) {
431     return LHS.FuncGUID < RHS.FuncGUID;
432   });
433   return true;
434 }
435 
436 template <bool IsTopLevelFunc>
buildAddress2ProbeMap(MCDecodedPseudoProbeInlineTree * Cur,uint64_t & LastAddr,const Uint64Set & GuidFilter,const Uint64Map & FuncStartAddrs,const uint32_t CurChildIndex)437 bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
438     MCDecodedPseudoProbeInlineTree *Cur, uint64_t &LastAddr,
439     const Uint64Set &GuidFilter, const Uint64Map &FuncStartAddrs,
440     const uint32_t CurChildIndex) {
441   // The pseudo_probe section encodes an inline forest and each tree has a
442   // format defined in MCPseudoProbe.h
443 
444   uint32_t Index = 0;
445   if (IsTopLevelFunc) {
446     // Use a sequential id for top level inliner.
447     Index = CurChildIndex;
448   } else {
449     // Read inline site for inlinees
450     Index = cantFail(errorOrToExpected(readUnsignedNumber<uint32_t>()));
451   }
452 
453   // Read guid
454   uint64_t Guid = cantFail(errorOrToExpected(readUnencodedNumber<uint64_t>()));
455 
456   // Decide if top-level node should be disgarded.
457   if (IsTopLevelFunc && !GuidFilter.empty() && !GuidFilter.count(Guid))
458     Cur = nullptr;
459 
460   // If the incoming node is null, all its children nodes should be disgarded.
461   if (Cur) {
462     // Switch/add to a new tree node(inlinee)
463     Cur->getChildren()[CurChildIndex] =
464         MCDecodedPseudoProbeInlineTree(InlineSite(Guid, Index), Cur);
465     Cur = &Cur->getChildren()[CurChildIndex];
466     if (IsTopLevelFunc && !EncodingIsAddrBased) {
467       if (auto V = FuncStartAddrs.lookup(Guid))
468         LastAddr = V;
469     }
470   }
471 
472   // Read number of probes in the current node.
473   uint32_t NodeCount =
474       cantFail(errorOrToExpected(readUnsignedNumber<uint32_t>()));
475   uint32_t CurrentProbeCount = 0;
476   // Read number of direct inlinees
477   uint32_t ChildrenToProcess =
478       cantFail(errorOrToExpected(readUnsignedNumber<uint32_t>()));
479   // Read all probes in this node
480   for (std::size_t I = 0; I < NodeCount; I++) {
481     // Read index
482     uint32_t Index =
483         cantFail(errorOrToExpected(readUnsignedNumber<uint32_t>()));
484     // Read type | flag.
485     uint8_t Value = cantFail(errorOrToExpected(readUnencodedNumber<uint8_t>()));
486     uint8_t Kind = Value & 0xf;
487     uint8_t Attr = (Value & 0x70) >> 4;
488     // Read address
489     uint64_t Addr = 0;
490     if (Value & 0x80) {
491       int64_t Offset = cantFail(errorOrToExpected(readSignedNumber<int64_t>()));
492       Addr = LastAddr + Offset;
493     } else {
494       Addr = cantFail(errorOrToExpected(readUnencodedNumber<int64_t>()));
495       if (isSentinelProbe(Attr)) {
496         // For sentinel probe, the addr field actually stores the GUID of the
497         // split function. Convert it to the real address.
498         if (auto V = FuncStartAddrs.lookup(Addr))
499           Addr = V;
500       } else {
501         // For now we assume all probe encoding should be either based on
502         // leading probe address or function start address.
503         // The scheme is for downwards compatibility.
504         // TODO: retire this scheme once compatibility is no longer an issue.
505         EncodingIsAddrBased = true;
506       }
507     }
508 
509     uint32_t Discriminator = 0;
510     if (hasDiscriminator(Attr)) {
511       Discriminator =
512           cantFail(errorOrToExpected(readUnsignedNumber<uint32_t>()));
513     }
514 
515     if (Cur && !isSentinelProbe(Attr)) {
516       PseudoProbeVec.emplace_back(Addr, Index, PseudoProbeType(Kind), Attr,
517                                   Discriminator, Cur);
518       ++CurrentProbeCount;
519     }
520     LastAddr = Addr;
521   }
522 
523   if (Cur) {
524     Cur->setProbes(
525         MutableArrayRef(PseudoProbeVec).take_back(CurrentProbeCount));
526     InlineTreeVec.resize(InlineTreeVec.size() + ChildrenToProcess);
527     Cur->getChildren() =
528         MutableArrayRef(InlineTreeVec).take_back(ChildrenToProcess);
529   }
530   for (uint32_t I = 0; I < ChildrenToProcess; I++) {
531     buildAddress2ProbeMap<false>(Cur, LastAddr, GuidFilter, FuncStartAddrs, I);
532   }
533   return Cur;
534 }
535 
536 template <bool IsTopLevelFunc>
countRecords(bool & Discard,uint32_t & ProbeCount,uint32_t & InlinedCount,const Uint64Set & GuidFilter)537 bool MCPseudoProbeDecoder::countRecords(bool &Discard, uint32_t &ProbeCount,
538                                         uint32_t &InlinedCount,
539                                         const Uint64Set &GuidFilter) {
540   if (!IsTopLevelFunc)
541     // Read inline site for inlinees
542     if (!readUnsignedNumber<uint32_t>())
543       return false;
544 
545   // Read guid
546   auto ErrorOrCurGuid = readUnencodedNumber<uint64_t>();
547   if (!ErrorOrCurGuid)
548     return false;
549   uint64_t Guid = std::move(*ErrorOrCurGuid);
550 
551   // Decide if top-level node should be disgarded.
552   if (IsTopLevelFunc) {
553     Discard = !GuidFilter.empty() && !GuidFilter.count(Guid);
554     if (!Discard)
555       // Allocate an entry for top-level function record.
556       ++InlinedCount;
557   }
558 
559   // Read number of probes in the current node.
560   auto ErrorOrNodeCount = readUnsignedNumber<uint32_t>();
561   if (!ErrorOrNodeCount)
562     return false;
563   uint32_t NodeCount = std::move(*ErrorOrNodeCount);
564   uint32_t CurrentProbeCount = 0;
565 
566   // Read number of direct inlinees
567   auto ErrorOrCurChildrenToProcess = readUnsignedNumber<uint32_t>();
568   if (!ErrorOrCurChildrenToProcess)
569     return false;
570   uint32_t ChildrenToProcess = std::move(*ErrorOrCurChildrenToProcess);
571 
572   // Read all probes in this node
573   for (std::size_t I = 0; I < NodeCount; I++) {
574     // Read index
575     if (!readUnsignedNumber<uint32_t>())
576       return false;
577 
578     // Read type | flag.
579     auto ErrorOrValue = readUnencodedNumber<uint8_t>();
580     if (!ErrorOrValue)
581       return false;
582     uint8_t Value = std::move(*ErrorOrValue);
583 
584     uint8_t Attr = (Value & 0x70) >> 4;
585     if (Value & 0x80) {
586       // Offset
587       if (!readSignedNumber<int64_t>())
588         return false;
589     } else {
590       // Addr
591       if (!readUnencodedNumber<int64_t>())
592         return false;
593     }
594 
595     if (hasDiscriminator(Attr))
596       // Discriminator
597       if (!readUnsignedNumber<uint32_t>())
598         return false;
599 
600     if (!Discard && !isSentinelProbe(Attr))
601       ++CurrentProbeCount;
602   }
603 
604   if (!Discard) {
605     ProbeCount += CurrentProbeCount;
606     InlinedCount += ChildrenToProcess;
607   }
608 
609   for (uint32_t I = 0; I < ChildrenToProcess; I++)
610     if (!countRecords<false>(Discard, ProbeCount, InlinedCount, GuidFilter))
611       return false;
612   return true;
613 }
614 
buildAddress2ProbeMap(const uint8_t * Start,std::size_t Size,const Uint64Set & GuidFilter,const Uint64Map & FuncStartAddrs)615 bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
616     const uint8_t *Start, std::size_t Size, const Uint64Set &GuidFilter,
617     const Uint64Map &FuncStartAddrs) {
618   // For function records in the order of their appearance in the encoded data
619   // (DFS), count the number of contained probes and inlined function records.
620   uint32_t ProbeCount = 0;
621   uint32_t InlinedCount = 0;
622   uint32_t TopLevelFuncs = 0;
623   Data = Start;
624   End = Data + Size;
625   bool Discard = false;
626   while (Data < End) {
627     if (!countRecords<true>(Discard, ProbeCount, InlinedCount, GuidFilter))
628       return false;
629     TopLevelFuncs += !Discard;
630   }
631   assert(Data == End && "Have unprocessed data in pseudo_probe section");
632   PseudoProbeVec.reserve(ProbeCount);
633   InlineTreeVec.reserve(InlinedCount);
634 
635   // Allocate top-level function records as children of DummyInlineRoot.
636   InlineTreeVec.resize(TopLevelFuncs);
637   DummyInlineRoot.getChildren() = MutableArrayRef(InlineTreeVec);
638 
639   Data = Start;
640   End = Data + Size;
641   uint64_t LastAddr = 0;
642   uint32_t CurChildIndex = 0;
643   while (Data < End)
644     CurChildIndex += buildAddress2ProbeMap<true>(
645         &DummyInlineRoot, LastAddr, GuidFilter, FuncStartAddrs, CurChildIndex);
646   assert(Data == End && "Have unprocessed data in pseudo_probe section");
647   assert(PseudoProbeVec.size() == ProbeCount &&
648          "Mismatching probe count pre- and post-parsing");
649   assert(InlineTreeVec.size() == InlinedCount &&
650          "Mismatching function records count pre- and post-parsing");
651 
652   std::vector<std::pair<uint64_t, uint32_t>> SortedA2P(ProbeCount);
653   for (const auto &[I, Probe] : llvm::enumerate(PseudoProbeVec))
654     SortedA2P[I] = {Probe.getAddress(), I};
655   llvm::sort(SortedA2P);
656   Address2ProbesMap.reserve(ProbeCount);
657   for (const uint32_t I : llvm::make_second_range(SortedA2P))
658     Address2ProbesMap.emplace_back(PseudoProbeVec[I]);
659   SortedA2P.clear();
660   return true;
661 }
662 
printGUID2FuncDescMap(raw_ostream & OS)663 void MCPseudoProbeDecoder::printGUID2FuncDescMap(raw_ostream &OS) {
664   OS << "Pseudo Probe Desc:\n";
665   for (auto &I : GUID2FuncDescMap)
666     I.print(OS);
667 }
668 
printProbeForAddress(raw_ostream & OS,uint64_t Address)669 void MCPseudoProbeDecoder::printProbeForAddress(raw_ostream &OS,
670                                                 uint64_t Address) {
671   for (const MCDecodedPseudoProbe &Probe : Address2ProbesMap.find(Address)) {
672     OS << " [Probe]:\t";
673     Probe.print(OS, GUID2FuncDescMap, true);
674   }
675 }
676 
printProbesForAllAddresses(raw_ostream & OS)677 void MCPseudoProbeDecoder::printProbesForAllAddresses(raw_ostream &OS) {
678   uint64_t PrevAddress = INT64_MAX;
679   for (MCDecodedPseudoProbe &Probe : Address2ProbesMap) {
680     uint64_t Address = Probe.getAddress();
681     if (Address != PrevAddress) {
682       PrevAddress = Address;
683       OS << "Address:\t" << Address << '\n';
684     }
685     OS << " [Probe]:\t";
686     Probe.print(OS, GUID2FuncDescMap, true);
687   }
688 }
689 
690 const MCDecodedPseudoProbe *
getCallProbeForAddr(uint64_t Address) const691 MCPseudoProbeDecoder::getCallProbeForAddr(uint64_t Address) const {
692   const MCDecodedPseudoProbe *CallProbe = nullptr;
693   for (const MCDecodedPseudoProbe &Probe : Address2ProbesMap.find(Address)) {
694     if (Probe.isCall()) {
695       // Disabling the assert and returning first call probe seen so far.
696       // Subsequent call probes, if any, are ignored. Due to the the way
697       // .pseudo_probe section is decoded, probes of the same-named independent
698       // static functions are merged thus multiple call probes may be seen for a
699       // callsite. This should only happen to compiler-generated statics, with
700       // -funique-internal-linkage-names where user statics get unique names.
701       //
702       // TODO: re-enable or narrow down the assert to static functions only.
703       //
704       // assert(!CallProbe &&
705       //        "There should be only one call probe corresponding to address "
706       //        "which is a callsite.");
707       CallProbe = &Probe;
708       break;
709     }
710   }
711   return CallProbe;
712 }
713 
714 const MCPseudoProbeFuncDesc *
getFuncDescForGUID(uint64_t GUID) const715 MCPseudoProbeDecoder::getFuncDescForGUID(uint64_t GUID) const {
716   auto It = GUID2FuncDescMap.find(GUID);
717   assert(It != GUID2FuncDescMap.end() && "Function descriptor doesn't exist");
718   return &*It;
719 }
720 
getInlineContextForProbe(const MCDecodedPseudoProbe * Probe,SmallVectorImpl<MCPseudoProbeFrameLocation> & InlineContextStack,bool IncludeLeaf) const721 void MCPseudoProbeDecoder::getInlineContextForProbe(
722     const MCDecodedPseudoProbe *Probe,
723     SmallVectorImpl<MCPseudoProbeFrameLocation> &InlineContextStack,
724     bool IncludeLeaf) const {
725   Probe->getInlineContext(InlineContextStack, GUID2FuncDescMap);
726   if (!IncludeLeaf)
727     return;
728   // Note that the context from probe doesn't include leaf frame,
729   // hence we need to retrieve and prepend leaf if requested.
730   const auto *FuncDesc = getFuncDescForGUID(Probe->getGuid());
731   InlineContextStack.emplace_back(
732       MCPseudoProbeFrameLocation(FuncDesc->FuncName, Probe->getIndex()));
733 }
734 
getInlinerDescForProbe(const MCDecodedPseudoProbe * Probe) const735 const MCPseudoProbeFuncDesc *MCPseudoProbeDecoder::getInlinerDescForProbe(
736     const MCDecodedPseudoProbe *Probe) const {
737   MCDecodedPseudoProbeInlineTree *InlinerNode = Probe->getInlineTreeNode();
738   if (!InlinerNode->hasInlineSite())
739     return nullptr;
740   return getFuncDescForGUID(InlinerNode->Parent->Guid);
741 }
742