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