1 //===- lib/MC/MCPseudoProbe.cpp - Pseudo probe encoding support ----------===//
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
7 //===----------------------------------------------------------------------===//
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/MCFragment.h"
17 #include "llvm/MC/MCObjectFileInfo.h"
18 #include "llvm/MC/MCObjectStreamer.h"
19 #include "llvm/MC/MCSymbol.h"
20 #include "llvm/Support/Endian.h"
21 #include "llvm/Support/Error.h"
22 #include "llvm/Support/LEB128.h"
23 #include "llvm/Support/MD5.h"
24 #include "llvm/Support/raw_ostream.h"
32 #define DEBUG_TYPE "mcpseudoprobe"
35 using namespace support
;
38 int MCPseudoProbeTable::DdgPrintIndent
= 0;
41 static const MCExpr
*buildSymbolDiff(MCObjectStreamer
*MCOS
, const MCSymbol
*A
,
43 MCContext
&Context
= MCOS
->getContext();
44 MCSymbolRefExpr::VariantKind Variant
= MCSymbolRefExpr::VK_None
;
45 const MCExpr
*ARef
= MCSymbolRefExpr::create(A
, Variant
, Context
);
46 const MCExpr
*BRef
= MCSymbolRefExpr::create(B
, Variant
, Context
);
47 const MCExpr
*AddrDelta
=
48 MCBinaryExpr::create(MCBinaryExpr::Sub
, ARef
, BRef
, Context
);
52 uint64_t MCDecodedPseudoProbe::getGuid() const { return InlineTree
->Guid
; }
54 void MCPseudoProbe::emit(MCObjectStreamer
*MCOS
,
55 const MCPseudoProbe
*LastProbe
) const {
56 bool IsSentinel
= isSentinelProbe(getAttributes());
57 assert((LastProbe
|| IsSentinel
) &&
58 "Last probe should not be null for non-sentinel probes");
61 MCOS
->emitULEB128IntValue(Index
);
62 // Emit Type and the flag:
63 // Type (bit 0 to 3), with bit 4 to 6 for attributes.
64 // Flag (bit 7, 0 - code address, 1 - address delta). This indicates whether
65 // the following field is a symbolic code address or an address delta.
66 // Emit FS discriminator
67 assert(Type
<= 0xF && "Probe type too big to encode, exceeding 15");
68 auto NewAttributes
= Attributes
;
70 NewAttributes
|= (uint32_t)PseudoProbeAttributes::HasDiscriminator
;
71 assert(NewAttributes
<= 0x7 &&
72 "Probe attributes too big to encode, exceeding 7");
73 uint8_t PackedType
= Type
| (NewAttributes
<< 4);
75 !IsSentinel
? ((int8_t)MCPseudoProbeFlag::AddressDelta
<< 7) : 0;
76 MCOS
->emitInt8(Flag
| PackedType
);
79 // Emit the delta between the address label and LastProbe.
80 const MCExpr
*AddrDelta
=
81 buildSymbolDiff(MCOS
, Label
, LastProbe
->getLabel());
83 if (AddrDelta
->evaluateAsAbsolute(Delta
, MCOS
->getAssemblerPtr())) {
84 MCOS
->emitSLEB128IntValue(Delta
);
86 MCOS
->insert(MCOS
->getContext().allocFragment
<MCPseudoProbeAddrFragment
>(
90 // Emit the GUID of the split function that the sentinel probe represents.
91 MCOS
->emitInt64(Guid
);
95 MCOS
->emitULEB128IntValue(Discriminator
);
98 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
);
99 dbgs() << "Probe: " << Index
<< "\n";
103 void MCPseudoProbeInlineTree::addPseudoProbe(
104 const MCPseudoProbe
&Probe
, const MCPseudoProbeInlineStack
&InlineStack
) {
105 // The function should not be called on the root.
106 assert(isRoot() && "Should only be called on root");
108 // When it comes here, the input look like:
109 // Probe: GUID of C, ...
110 // InlineStack: [88, A], [66, B]
111 // which means, Function A inlines function B at call site with a probe id of
112 // 88, and B inlines C at probe 66. The tri-tree expects a tree path like {[0,
113 // A], [88, B], [66, C]} to locate the tree node where the probe should be
114 // added. Note that the edge [0, A] means A is the top-level function we are
115 // emitting probes for.
117 // Make a [0, A] edge.
118 // An empty inline stack means the function that the probe originates from
119 // is a top-level function.
121 if (InlineStack
.empty()) {
122 Top
= InlineSite(Probe
.getGuid(), 0);
124 Top
= InlineSite(std::get
<0>(InlineStack
.front()), 0);
127 auto *Cur
= getOrAddNode(Top
);
129 // Make interior edges by walking the inline stack. Once it's done, Cur should
130 // point to the node that the probe originates from.
131 if (!InlineStack
.empty()) {
132 auto Iter
= InlineStack
.begin();
133 auto Index
= std::get
<1>(*Iter
);
135 for (; Iter
!= InlineStack
.end(); Iter
++) {
136 // Make an edge by using the previous probe id and current GUID.
137 Cur
= Cur
->getOrAddNode(InlineSite(std::get
<0>(*Iter
), Index
));
138 Index
= std::get
<1>(*Iter
);
140 Cur
= Cur
->getOrAddNode(InlineSite(Probe
.getGuid(), Index
));
143 Cur
->Probes
.push_back(Probe
);
146 void MCPseudoProbeInlineTree::emit(MCObjectStreamer
*MCOS
,
147 const MCPseudoProbe
*&LastProbe
) {
149 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
);
150 dbgs() << "Group [\n";
151 MCPseudoProbeTable::DdgPrintIndent
+= 2;
153 assert(!isRoot() && "Root should be handled separately");
155 // Emit probes grouped by GUID.
157 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
);
158 dbgs() << "GUID: " << Guid
<< "\n";
161 MCOS
->emitInt64(Guid
);
162 // Emit number of probes in this node, including a sentinel probe for
163 // top-level functions if needed.
164 bool NeedSentinel
= false;
165 if (Parent
->isRoot()) {
166 assert(isSentinelProbe(LastProbe
->getAttributes()) &&
167 "Starting probe of a top-level function should be a sentinel probe");
168 // The main body of a split function doesn't need a sentinel probe.
169 if (LastProbe
->getGuid() != Guid
)
173 MCOS
->emitULEB128IntValue(Probes
.size() + NeedSentinel
);
174 // Emit number of direct inlinees
175 MCOS
->emitULEB128IntValue(Children
.size());
176 // Emit sentinel probe for top-level functions
178 LastProbe
->emit(MCOS
, nullptr);
180 // Emit probes in this group
181 for (const auto &Probe
: Probes
) {
182 Probe
.emit(MCOS
, LastProbe
);
186 // Emit sorted descendant. InlineSite is unique for each pair, so there will
187 // be no ordering of Inlinee based on MCPseudoProbeInlineTree*
188 using InlineeType
= std::pair
<InlineSite
, MCPseudoProbeInlineTree
*>;
189 std::vector
<InlineeType
> Inlinees
;
190 for (const auto &Child
: Children
)
191 Inlinees
.emplace_back(Child
.first
, Child
.second
.get());
192 llvm::sort(Inlinees
, llvm::less_first());
194 for (const auto &Inlinee
: Inlinees
) {
196 MCOS
->emitULEB128IntValue(std::get
<1>(Inlinee
.first
));
198 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
);
199 dbgs() << "InlineSite: " << std::get
<1>(Inlinee
.first
) << "\n";
202 Inlinee
.second
->emit(MCOS
, LastProbe
);
206 MCPseudoProbeTable::DdgPrintIndent
-= 2;
207 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
);
212 void MCPseudoProbeSections::emit(MCObjectStreamer
*MCOS
) {
213 MCContext
&Ctx
= MCOS
->getContext();
214 SmallVector
<std::pair
<MCSymbol
*, MCPseudoProbeInlineTree
*>> Vec
;
215 Vec
.reserve(MCProbeDivisions
.size());
216 for (auto &ProbeSec
: MCProbeDivisions
)
217 Vec
.emplace_back(ProbeSec
.first
, &ProbeSec
.second
);
218 for (auto I
: llvm::enumerate(MCOS
->getAssembler()))
219 I
.value().setOrdinal(I
.index());
220 llvm::sort(Vec
, [](auto A
, auto B
) {
221 return A
.first
->getSection().getOrdinal() <
222 B
.first
->getSection().getOrdinal();
224 for (auto [FuncSym
, RootPtr
] : Vec
) {
225 const auto &Root
= *RootPtr
;
226 if (auto *S
= Ctx
.getObjectFileInfo()->getPseudoProbeSection(
227 FuncSym
->getSection())) {
228 // Switch to the .pseudoprobe section or a comdat group.
229 MCOS
->switchSection(S
);
230 // Emit probes grouped by GUID.
231 // Emit sorted descendant. InlineSite is unique for each pair, so there
232 // will be no ordering of Inlinee based on MCPseudoProbeInlineTree*
233 using InlineeType
= std::pair
<InlineSite
, MCPseudoProbeInlineTree
*>;
234 std::vector
<InlineeType
> Inlinees
;
235 for (const auto &Child
: Root
.getChildren())
236 Inlinees
.emplace_back(Child
.first
, Child
.second
.get());
237 llvm::sort(Inlinees
, llvm::less_first());
239 for (const auto &Inlinee
: Inlinees
) {
240 // Emit the group guarded by a sentinel probe.
241 MCPseudoProbe
SentinelProbe(
242 const_cast<MCSymbol
*>(FuncSym
), MD5Hash(FuncSym
->getName()),
243 (uint32_t)PseudoProbeReservedId::Invalid
,
244 (uint32_t)PseudoProbeType::Block
,
245 (uint32_t)PseudoProbeAttributes::Sentinel
, 0);
246 const MCPseudoProbe
*Probe
= &SentinelProbe
;
247 Inlinee
.second
->emit(MCOS
, Probe
);
254 // This emits the pseudo probe tables.
256 void MCPseudoProbeTable::emit(MCObjectStreamer
*MCOS
) {
257 MCContext
&Ctx
= MCOS
->getContext();
258 auto &ProbeTable
= Ctx
.getMCPseudoProbeTable();
260 // Bail out early so we don't switch to the pseudo_probe section needlessly
261 // and in doing so create an unnecessary (if empty) section.
262 auto &ProbeSections
= ProbeTable
.getProbeSections();
263 if (ProbeSections
.empty())
266 LLVM_DEBUG(MCPseudoProbeTable::DdgPrintIndent
= 0);
268 // Put out the probe.
269 ProbeSections
.emit(MCOS
);
272 static StringRef
getProbeFNameForGUID(const GUIDProbeFunctionMap
&GUID2FuncMAP
,
274 auto It
= GUID2FuncMAP
.find(GUID
);
275 assert(It
!= GUID2FuncMAP
.end() &&
276 "Probe function must exist for a valid GUID");
280 void MCPseudoProbeFuncDesc::print(raw_ostream
&OS
) {
281 OS
<< "GUID: " << FuncGUID
<< " Name: " << FuncName
<< "\n";
282 OS
<< "Hash: " << FuncHash
<< "\n";
285 void MCDecodedPseudoProbe::getInlineContext(
286 SmallVectorImpl
<MCPseudoProbeFrameLocation
> &ContextStack
,
287 const GUIDProbeFunctionMap
&GUID2FuncMAP
) const {
288 uint32_t Begin
= ContextStack
.size();
289 MCDecodedPseudoProbeInlineTree
*Cur
= InlineTree
;
290 // It will add the string of each node's inline site during iteration.
291 // Note that it won't include the probe's belonging function(leaf location)
292 while (Cur
->hasInlineSite()) {
293 StringRef FuncName
= getProbeFNameForGUID(GUID2FuncMAP
, Cur
->Parent
->Guid
);
294 ContextStack
.emplace_back(MCPseudoProbeFrameLocation(
295 FuncName
, std::get
<1>(Cur
->getInlineSite())));
296 Cur
= static_cast<MCDecodedPseudoProbeInlineTree
*>(Cur
->Parent
);
298 // Make the ContextStack in caller-callee order
299 std::reverse(ContextStack
.begin() + Begin
, ContextStack
.end());
302 std::string
MCDecodedPseudoProbe::getInlineContextStr(
303 const GUIDProbeFunctionMap
&GUID2FuncMAP
) const {
304 std::ostringstream OContextStr
;
305 SmallVector
<MCPseudoProbeFrameLocation
, 16> ContextStack
;
306 getInlineContext(ContextStack
, GUID2FuncMAP
);
307 for (auto &Cxt
: ContextStack
) {
308 if (OContextStr
.str().size())
309 OContextStr
<< " @ ";
310 OContextStr
<< Cxt
.first
.str() << ":" << Cxt
.second
;
312 return OContextStr
.str();
315 static const char *PseudoProbeTypeStr
[3] = {"Block", "IndirectCall",
318 void MCDecodedPseudoProbe::print(raw_ostream
&OS
,
319 const GUIDProbeFunctionMap
&GUID2FuncMAP
,
320 bool ShowName
) const {
323 StringRef FuncName
= getProbeFNameForGUID(GUID2FuncMAP
, getGuid());
324 OS
<< FuncName
.str() << " ";
326 OS
<< getGuid() << " ";
328 OS
<< "Index: " << Index
<< " ";
330 OS
<< "Discriminator: " << Discriminator
<< " ";
331 OS
<< "Type: " << PseudoProbeTypeStr
[static_cast<uint8_t>(Type
)] << " ";
332 std::string InlineContextStr
= getInlineContextStr(GUID2FuncMAP
);
333 if (InlineContextStr
.size()) {
335 OS
<< InlineContextStr
;
340 template <typename T
> ErrorOr
<T
> MCPseudoProbeDecoder::readUnencodedNumber() {
341 if (Data
+ sizeof(T
) > End
) {
342 return std::error_code();
344 T Val
= endian::readNext
<T
, llvm::endianness::little
>(Data
);
345 return ErrorOr
<T
>(Val
);
348 template <typename T
> ErrorOr
<T
> MCPseudoProbeDecoder::readUnsignedNumber() {
349 unsigned NumBytesRead
= 0;
350 uint64_t Val
= decodeULEB128(Data
, &NumBytesRead
);
351 if (Val
> std::numeric_limits
<T
>::max() || (Data
+ NumBytesRead
> End
)) {
352 return std::error_code();
354 Data
+= NumBytesRead
;
355 return ErrorOr
<T
>(static_cast<T
>(Val
));
358 template <typename T
> ErrorOr
<T
> MCPseudoProbeDecoder::readSignedNumber() {
359 unsigned NumBytesRead
= 0;
360 int64_t Val
= decodeSLEB128(Data
, &NumBytesRead
);
361 if (Val
> std::numeric_limits
<T
>::max() || (Data
+ NumBytesRead
> End
)) {
362 return std::error_code();
364 Data
+= NumBytesRead
;
365 return ErrorOr
<T
>(static_cast<T
>(Val
));
368 ErrorOr
<StringRef
> MCPseudoProbeDecoder::readString(uint32_t Size
) {
369 StringRef
Str(reinterpret_cast<const char *>(Data
), Size
);
370 if (Data
+ Size
> End
) {
371 return std::error_code();
374 return ErrorOr
<StringRef
>(Str
);
377 bool MCPseudoProbeDecoder::buildGUID2FuncDescMap(const uint8_t *Start
,
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
394 uint32_t FuncDescCount
= 0;
397 if (!readUnencodedNumber
<uint64_t>())
400 if (!readUnencodedNumber
<uint64_t>())
403 auto ErrorOrNameSize
= readUnsignedNumber
<uint32_t>();
404 if (!ErrorOrNameSize
)
407 if (!readString(*ErrorOrNameSize
))
411 assert(Data
== End
&& "Have unprocessed data in pseudo_probe_desc section");
412 GUID2FuncDescMap
.reserve(FuncDescCount
);
418 cantFail(errorOrToExpected(readUnencodedNumber
<uint64_t>()));
420 cantFail(errorOrToExpected(readUnencodedNumber
<uint64_t>()));
422 cantFail(errorOrToExpected(readUnsignedNumber
<uint32_t>()));
423 StringRef Name
= cantFail(errorOrToExpected(readString(NameSize
)));
425 // Initialize PseudoProbeFuncDesc and populate it into GUID2FuncDescMap
426 GUID2FuncDescMap
.emplace_back(
427 GUID
, Hash
, IsMMapped
? Name
: Name
.copy(FuncNameAllocator
));
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::sort(GUID2FuncDescMap
, [](const auto &LHS
, const auto &RHS
) {
433 return LHS
.FuncGUID
< RHS
.FuncGUID
;
438 template <bool IsTopLevelFunc
>
439 bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
440 MCDecodedPseudoProbeInlineTree
*Cur
, uint64_t &LastAddr
,
441 const Uint64Set
&GuidFilter
, const Uint64Map
&FuncStartAddrs
,
442 const uint32_t CurChildIndex
) {
443 // The pseudo_probe section encodes an inline forest and each tree has a
444 // format defined in MCPseudoProbe.h
447 if (IsTopLevelFunc
) {
448 // Use a sequential id for top level inliner.
449 Index
= CurChildIndex
;
451 // Read inline site for inlinees
452 Index
= cantFail(errorOrToExpected(readUnsignedNumber
<uint32_t>()));
456 uint64_t Guid
= cantFail(errorOrToExpected(readUnencodedNumber
<uint64_t>()));
458 // Decide if top-level node should be disgarded.
459 if (IsTopLevelFunc
&& !GuidFilter
.empty() && !GuidFilter
.count(Guid
))
462 // If the incoming node is null, all its children nodes should be disgarded.
464 // Switch/add to a new tree node(inlinee)
465 Cur
->getChildren()[CurChildIndex
] =
466 MCDecodedPseudoProbeInlineTree(InlineSite(Guid
, Index
), Cur
);
467 Cur
= &Cur
->getChildren()[CurChildIndex
];
468 if (IsTopLevelFunc
&& !EncodingIsAddrBased
) {
469 if (auto V
= FuncStartAddrs
.lookup(Guid
))
474 // Read number of probes in the current node.
476 cantFail(errorOrToExpected(readUnsignedNumber
<uint32_t>()));
477 uint32_t CurrentProbeCount
= 0;
478 // Read number of direct inlinees
479 uint32_t ChildrenToProcess
=
480 cantFail(errorOrToExpected(readUnsignedNumber
<uint32_t>()));
481 // Read all probes in this node
482 for (std::size_t I
= 0; I
< NodeCount
; I
++) {
485 cantFail(errorOrToExpected(readUnsignedNumber
<uint32_t>()));
487 uint8_t Value
= cantFail(errorOrToExpected(readUnencodedNumber
<uint8_t>()));
488 uint8_t Kind
= Value
& 0xf;
489 uint8_t Attr
= (Value
& 0x70) >> 4;
493 int64_t Offset
= cantFail(errorOrToExpected(readSignedNumber
<int64_t>()));
494 Addr
= LastAddr
+ Offset
;
496 Addr
= cantFail(errorOrToExpected(readUnencodedNumber
<int64_t>()));
497 if (isSentinelProbe(Attr
)) {
498 // For sentinel probe, the addr field actually stores the GUID of the
499 // split function. Convert it to the real address.
500 if (auto V
= FuncStartAddrs
.lookup(Addr
))
503 // For now we assume all probe encoding should be either based on
504 // leading probe address or function start address.
505 // The scheme is for downwards compatibility.
506 // TODO: retire this scheme once compatibility is no longer an issue.
507 EncodingIsAddrBased
= true;
511 uint32_t Discriminator
= 0;
512 if (hasDiscriminator(Attr
)) {
514 cantFail(errorOrToExpected(readUnsignedNumber
<uint32_t>()));
517 if (Cur
&& !isSentinelProbe(Attr
)) {
518 PseudoProbeVec
.emplace_back(Addr
, Index
, PseudoProbeType(Kind
), Attr
,
527 MutableArrayRef(PseudoProbeVec
).take_back(CurrentProbeCount
));
528 InlineTreeVec
.resize(InlineTreeVec
.size() + ChildrenToProcess
);
530 MutableArrayRef(InlineTreeVec
).take_back(ChildrenToProcess
);
532 for (uint32_t I
= 0; I
< ChildrenToProcess
; I
++) {
533 buildAddress2ProbeMap
<false>(Cur
, LastAddr
, GuidFilter
, FuncStartAddrs
, I
);
538 template <bool IsTopLevelFunc
>
539 bool MCPseudoProbeDecoder::countRecords(bool &Discard
, uint32_t &ProbeCount
,
540 uint32_t &InlinedCount
,
541 const Uint64Set
&GuidFilter
) {
543 // Read inline site for inlinees
544 if (!readUnsignedNumber
<uint32_t>())
548 auto ErrorOrCurGuid
= readUnencodedNumber
<uint64_t>();
551 uint64_t Guid
= std::move(*ErrorOrCurGuid
);
553 // Decide if top-level node should be disgarded.
554 if (IsTopLevelFunc
) {
555 Discard
= !GuidFilter
.empty() && !GuidFilter
.count(Guid
);
557 // Allocate an entry for top-level function record.
561 // Read number of probes in the current node.
562 auto ErrorOrNodeCount
= readUnsignedNumber
<uint32_t>();
563 if (!ErrorOrNodeCount
)
565 uint32_t NodeCount
= std::move(*ErrorOrNodeCount
);
566 uint32_t CurrentProbeCount
= 0;
568 // Read number of direct inlinees
569 auto ErrorOrCurChildrenToProcess
= readUnsignedNumber
<uint32_t>();
570 if (!ErrorOrCurChildrenToProcess
)
572 uint32_t ChildrenToProcess
= std::move(*ErrorOrCurChildrenToProcess
);
574 // Read all probes in this node
575 for (std::size_t I
= 0; I
< NodeCount
; I
++) {
577 if (!readUnsignedNumber
<uint32_t>())
581 auto ErrorOrValue
= readUnencodedNumber
<uint8_t>();
584 uint8_t Value
= std::move(*ErrorOrValue
);
586 uint8_t Attr
= (Value
& 0x70) >> 4;
589 if (!readSignedNumber
<int64_t>())
593 if (!readUnencodedNumber
<int64_t>())
597 if (hasDiscriminator(Attr
))
599 if (!readUnsignedNumber
<uint32_t>())
602 if (!Discard
&& !isSentinelProbe(Attr
))
607 ProbeCount
+= CurrentProbeCount
;
608 InlinedCount
+= ChildrenToProcess
;
611 for (uint32_t I
= 0; I
< ChildrenToProcess
; I
++)
612 if (!countRecords
<false>(Discard
, ProbeCount
, InlinedCount
, GuidFilter
))
617 bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
618 const uint8_t *Start
, std::size_t Size
, const Uint64Set
&GuidFilter
,
619 const Uint64Map
&FuncStartAddrs
) {
620 // For function records in the order of their appearance in the encoded data
621 // (DFS), count the number of contained probes and inlined function records.
622 uint32_t ProbeCount
= 0;
623 uint32_t InlinedCount
= 0;
624 uint32_t TopLevelFuncs
= 0;
627 bool Discard
= false;
629 if (!countRecords
<true>(Discard
, ProbeCount
, InlinedCount
, GuidFilter
))
631 TopLevelFuncs
+= !Discard
;
633 assert(Data
== End
&& "Have unprocessed data in pseudo_probe section");
634 PseudoProbeVec
.reserve(ProbeCount
);
635 InlineTreeVec
.reserve(InlinedCount
);
637 // Allocate top-level function records as children of DummyInlineRoot.
638 InlineTreeVec
.resize(TopLevelFuncs
);
639 DummyInlineRoot
.getChildren() = MutableArrayRef(InlineTreeVec
);
643 uint64_t LastAddr
= 0;
644 uint32_t CurChildIndex
= 0;
646 CurChildIndex
+= buildAddress2ProbeMap
<true>(
647 &DummyInlineRoot
, LastAddr
, GuidFilter
, FuncStartAddrs
, CurChildIndex
);
648 assert(Data
== End
&& "Have unprocessed data in pseudo_probe section");
649 assert(PseudoProbeVec
.size() == ProbeCount
&&
650 "Mismatching probe count pre- and post-parsing");
651 assert(InlineTreeVec
.size() == InlinedCount
&&
652 "Mismatching function records count pre- and post-parsing");
654 std::vector
<std::pair
<uint64_t, uint32_t>> SortedA2P(ProbeCount
);
655 for (const auto &[I
, Probe
] : llvm::enumerate(PseudoProbeVec
))
656 SortedA2P
[I
] = {Probe
.getAddress(), I
};
657 llvm::sort(SortedA2P
);
658 Address2ProbesMap
.reserve(ProbeCount
);
659 for (const uint32_t I
: llvm::make_second_range(SortedA2P
))
660 Address2ProbesMap
.emplace_back(PseudoProbeVec
[I
]);
665 void MCPseudoProbeDecoder::printGUID2FuncDescMap(raw_ostream
&OS
) {
666 OS
<< "Pseudo Probe Desc:\n";
667 for (auto &I
: GUID2FuncDescMap
)
671 void MCPseudoProbeDecoder::printProbeForAddress(raw_ostream
&OS
,
673 for (const MCDecodedPseudoProbe
&Probe
: Address2ProbesMap
.find(Address
)) {
675 Probe
.print(OS
, GUID2FuncDescMap
, true);
679 void MCPseudoProbeDecoder::printProbesForAllAddresses(raw_ostream
&OS
) {
680 uint64_t PrevAddress
= INT64_MAX
;
681 for (MCDecodedPseudoProbe
&Probe
: Address2ProbesMap
) {
682 uint64_t Address
= Probe
.getAddress();
683 if (Address
!= PrevAddress
) {
684 PrevAddress
= Address
;
685 OS
<< "Address:\t" << Address
<< '\n';
688 Probe
.print(OS
, GUID2FuncDescMap
, true);
692 const MCDecodedPseudoProbe
*
693 MCPseudoProbeDecoder::getCallProbeForAddr(uint64_t Address
) const {
694 const MCDecodedPseudoProbe
*CallProbe
= nullptr;
695 for (const MCDecodedPseudoProbe
&Probe
: Address2ProbesMap
.find(Address
)) {
696 if (Probe
.isCall()) {
697 // Disabling the assert and returning first call probe seen so far.
698 // Subsequent call probes, if any, are ignored. Due to the the way
699 // .pseudo_probe section is decoded, probes of the same-named independent
700 // static functions are merged thus multiple call probes may be seen for a
701 // callsite. This should only happen to compiler-generated statics, with
702 // -funique-internal-linkage-names where user statics get unique names.
704 // TODO: re-enable or narrow down the assert to static functions only.
706 // assert(!CallProbe &&
707 // "There should be only one call probe corresponding to address "
708 // "which is a callsite.");
716 const MCPseudoProbeFuncDesc
*
717 MCPseudoProbeDecoder::getFuncDescForGUID(uint64_t GUID
) const {
718 auto It
= GUID2FuncDescMap
.find(GUID
);
719 assert(It
!= GUID2FuncDescMap
.end() && "Function descriptor doesn't exist");
723 void MCPseudoProbeDecoder::getInlineContextForProbe(
724 const MCDecodedPseudoProbe
*Probe
,
725 SmallVectorImpl
<MCPseudoProbeFrameLocation
> &InlineContextStack
,
726 bool IncludeLeaf
) const {
727 Probe
->getInlineContext(InlineContextStack
, GUID2FuncDescMap
);
730 // Note that the context from probe doesn't include leaf frame,
731 // hence we need to retrieve and prepend leaf if requested.
732 const auto *FuncDesc
= getFuncDescForGUID(Probe
->getGuid());
733 InlineContextStack
.emplace_back(
734 MCPseudoProbeFrameLocation(FuncDesc
->FuncName
, Probe
->getIndex()));
737 const MCPseudoProbeFuncDesc
*MCPseudoProbeDecoder::getInlinerDescForProbe(
738 const MCDecodedPseudoProbe
*Probe
) const {
739 MCDecodedPseudoProbeInlineTree
*InlinerNode
= Probe
->getInlineTreeNode();
740 if (!InlinerNode
->hasInlineSite())
742 return getFuncDescForGUID(InlinerNode
->Parent
->Guid
);