Skip to content

Commit 121ed07

Browse files
authored
[MC][NFC] Count pseudo probes and function records
Pre-parse pseudo probes section counting the number of probes and function records. These numbers are used in follow-up diff to pre-allocate vectors for decoded probes and inline tree nodes. Additional benefit is avoiding error handling during parsing. This pre-parsing is fast: for a 404MiB .pseudo_probe section with 43373881 probes and 25228770 function records, it only takes 0.68±0.01s. The total time of buildAddress2ProbeMap is 21s. Reviewers: dcci, maksfb, rafaelauler, wlei-llvm, ayermolo Reviewed By: wlei-llvm Pull Request: #102774
1 parent e04d124 commit 121ed07

File tree

3 files changed

+113
-37
lines changed

3 files changed

+113
-37
lines changed

bolt/lib/Rewrite/PseudoProbeRewriter.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,6 @@ void PseudoProbeRewriter::parsePseudoProbe() {
143143
if (!ProbeDecoder.buildAddress2ProbeMap(
144144
reinterpret_cast<const uint8_t *>(Contents.data()), Contents.size(),
145145
GuidFilter, FuncStartAddrs)) {
146-
ProbeDecoder.getAddress2ProbesMap().clear();
147146
errs() << "BOLT-WARNING: fail in building Address2ProbeMap\n";
148147
return;
149148
}

llvm/include/llvm/MC/MCPseudoProbe.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,12 @@ class MCPseudoProbeDecoder {
370370
// Decode pseudo_probe_desc section to build GUID to PseudoProbeFuncDesc map.
371371
bool buildGUID2FuncDescMap(const uint8_t *Start, std::size_t Size);
372372

373+
// Decode pseudo_probe section to count the number of probes and inlined
374+
// function records for each function record.
375+
template <bool IsTopLevelFunc>
376+
bool countRecords(bool &Discard, uint32_t &ProbeCount, uint32_t &InlinedCount,
377+
const Uint64Set &GuidFilter);
378+
373379
// Decode pseudo_probe section to build address to probes map for specifed
374380
// functions only.
375381
bool buildAddress2ProbeMap(const uint8_t *Start, std::size_t Size,

llvm/lib/MC/MCPseudoProbe.cpp

Lines changed: 107 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "llvm/MC/MCObjectStreamer.h"
1919
#include "llvm/MC/MCSymbol.h"
2020
#include "llvm/Support/Endian.h"
21+
#include "llvm/Support/Error.h"
2122
#include "llvm/Support/LEB128.h"
2223
#include "llvm/Support/MD5.h"
2324
#include "llvm/Support/raw_ostream.h"
@@ -429,17 +430,11 @@ bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
429430
Index = Cur->getChildren().size();
430431
} else {
431432
// Read inline site for inlinees
432-
auto ErrorOrIndex = readUnsignedNumber<uint32_t>();
433-
if (!ErrorOrIndex)
434-
return false;
435-
Index = std::move(*ErrorOrIndex);
433+
Index = cantFail(errorOrToExpected(readUnsignedNumber<uint32_t>()));
436434
}
437435

438436
// Read guid
439-
auto ErrorOrCurGuid = readUnencodedNumber<uint64_t>();
440-
if (!ErrorOrCurGuid)
441-
return false;
442-
uint64_t Guid = std::move(*ErrorOrCurGuid);
437+
uint64_t Guid = cantFail(errorOrToExpected(readUnencodedNumber<uint64_t>()));
443438

444439
// Decide if top-level node should be disgarded.
445440
if (IsTopLevelFunc && !GuidFilter.empty() && !GuidFilter.count(Guid))
@@ -457,41 +452,27 @@ bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
457452
}
458453

459454
// 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);
455+
uint32_t NodeCount =
456+
cantFail(errorOrToExpected(readUnsignedNumber<uint32_t>()));
464457
// Read number of direct inlinees
465-
auto ErrorOrCurChildrenToProcess = readUnsignedNumber<uint32_t>();
466-
if (!ErrorOrCurChildrenToProcess)
467-
return false;
458+
uint32_t ChildrenToProcess =
459+
cantFail(errorOrToExpected(readUnsignedNumber<uint32_t>()));
468460
// Read all probes in this node
469461
for (std::size_t I = 0; I < NodeCount; I++) {
470462
// Read index
471-
auto ErrorOrIndex = readUnsignedNumber<uint32_t>();
472-
if (!ErrorOrIndex)
473-
return false;
474-
uint32_t Index = std::move(*ErrorOrIndex);
463+
uint32_t Index =
464+
cantFail(errorOrToExpected(readUnsignedNumber<uint32_t>()));
475465
// Read type | flag.
476-
auto ErrorOrValue = readUnencodedNumber<uint8_t>();
477-
if (!ErrorOrValue)
478-
return false;
479-
uint8_t Value = std::move(*ErrorOrValue);
466+
uint8_t Value = cantFail(errorOrToExpected(readUnencodedNumber<uint8_t>()));
480467
uint8_t Kind = Value & 0xf;
481468
uint8_t Attr = (Value & 0x70) >> 4;
482469
// Read address
483470
uint64_t Addr = 0;
484471
if (Value & 0x80) {
485-
auto ErrorOrOffset = readSignedNumber<int64_t>();
486-
if (!ErrorOrOffset)
487-
return false;
488-
int64_t Offset = std::move(*ErrorOrOffset);
472+
int64_t Offset = cantFail(errorOrToExpected(readSignedNumber<int64_t>()));
489473
Addr = LastAddr + Offset;
490474
} else {
491-
auto ErrorOrAddr = readUnencodedNumber<int64_t>();
492-
if (!ErrorOrAddr)
493-
return false;
494-
Addr = std::move(*ErrorOrAddr);
475+
Addr = cantFail(errorOrToExpected(readUnencodedNumber<int64_t>()));
495476
if (isSentinelProbe(Attr)) {
496477
// For sentinel probe, the addr field actually stores the GUID of the
497478
// split function. Convert it to the real address.
@@ -508,10 +489,8 @@ bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
508489

509490
uint32_t Discriminator = 0;
510491
if (hasDiscriminator(Attr)) {
511-
auto ErrorOrDiscriminator = readUnsignedNumber<uint32_t>();
512-
if (!ErrorOrDiscriminator)
513-
return false;
514-
Discriminator = std::move(*ErrorOrDiscriminator);
492+
Discriminator =
493+
cantFail(errorOrToExpected(readUnsignedNumber<uint32_t>()));
515494
}
516495

517496
if (Cur && !isSentinelProbe(Attr)) {
@@ -524,17 +503,109 @@ bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
524503
LastAddr = Addr;
525504
}
526505

527-
uint32_t ChildrenToProcess = std::move(*ErrorOrCurChildrenToProcess);
528506
for (uint32_t I = 0; I < ChildrenToProcess; I++) {
529507
buildAddress2ProbeMap(Cur, LastAddr, GuidFilter, FuncStartAddrs);
530508
}
509+
return true;
510+
}
511+
512+
template <bool IsTopLevelFunc>
513+
bool MCPseudoProbeDecoder::countRecords(bool &Discard, uint32_t &ProbeCount,
514+
uint32_t &InlinedCount,
515+
const Uint64Set &GuidFilter) {
516+
if (!IsTopLevelFunc)
517+
// Read inline site for inlinees
518+
if (!readUnsignedNumber<uint32_t>())
519+
return false;
520+
521+
// Read guid
522+
auto ErrorOrCurGuid = readUnencodedNumber<uint64_t>();
523+
if (!ErrorOrCurGuid)
524+
return false;
525+
uint64_t Guid = std::move(*ErrorOrCurGuid);
526+
527+
// Decide if top-level node should be disgarded.
528+
if (IsTopLevelFunc) {
529+
Discard = !GuidFilter.empty() && !GuidFilter.count(Guid);
530+
if (!Discard)
531+
// Allocate an entry for top-level function record.
532+
++InlinedCount;
533+
}
534+
535+
// Read number of probes in the current node.
536+
auto ErrorOrNodeCount = readUnsignedNumber<uint32_t>();
537+
if (!ErrorOrNodeCount)
538+
return false;
539+
uint32_t NodeCount = std::move(*ErrorOrNodeCount);
540+
uint32_t CurrentProbeCount = 0;
541+
542+
// Read number of direct inlinees
543+
auto ErrorOrCurChildrenToProcess = readUnsignedNumber<uint32_t>();
544+
if (!ErrorOrCurChildrenToProcess)
545+
return false;
546+
uint32_t ChildrenToProcess = std::move(*ErrorOrCurChildrenToProcess);
547+
548+
// Read all probes in this node
549+
for (std::size_t I = 0; I < NodeCount; I++) {
550+
// Read index
551+
if (!readUnsignedNumber<uint32_t>())
552+
return false;
553+
554+
// Read type | flag.
555+
auto ErrorOrValue = readUnencodedNumber<uint8_t>();
556+
if (!ErrorOrValue)
557+
return false;
558+
uint8_t Value = std::move(*ErrorOrValue);
559+
560+
uint8_t Attr = (Value & 0x70) >> 4;
561+
if (Value & 0x80) {
562+
// Offset
563+
if (!readSignedNumber<int64_t>())
564+
return false;
565+
} else {
566+
// Addr
567+
if (!readUnencodedNumber<int64_t>())
568+
return false;
569+
}
570+
571+
if (hasDiscriminator(Attr))
572+
// Discriminator
573+
if (!readUnsignedNumber<uint32_t>())
574+
return false;
575+
576+
if (!Discard && !isSentinelProbe(Attr))
577+
++CurrentProbeCount;
578+
}
531579

580+
if (!Discard) {
581+
ProbeCount += CurrentProbeCount;
582+
InlinedCount += ChildrenToProcess;
583+
}
584+
585+
for (uint32_t I = 0; I < ChildrenToProcess; I++)
586+
if (!countRecords<false>(Discard, ProbeCount, InlinedCount, GuidFilter))
587+
return false;
532588
return true;
533589
}
534590

535591
bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
536592
const uint8_t *Start, std::size_t Size, const Uint64Set &GuidFilter,
537593
const Uint64Map &FuncStartAddrs) {
594+
// For function records in the order of their appearance in the encoded data
595+
// (DFS), count the number of contained probes and inlined function records.
596+
uint32_t ProbeCount = 0;
597+
uint32_t InlinedCount = 0;
598+
uint32_t TopLevelFuncs = 0;
599+
Data = Start;
600+
End = Data + Size;
601+
bool Discard = false;
602+
while (Data < End) {
603+
if (!countRecords<true>(Discard, ProbeCount, InlinedCount, GuidFilter))
604+
return false;
605+
TopLevelFuncs += !Discard;
606+
}
607+
assert(Data == End && "Have unprocessed data in pseudo_probe section");
608+
538609
Data = Start;
539610
End = Data + Size;
540611
uint64_t LastAddr = 0;

0 commit comments

Comments
 (0)