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