Skip to content

Commit a717a22

Browse files
committed
[𝘀𝗽𝗿] initial version
Created using spr 1.3.4
2 parents 6ffefbb + b6adebc commit a717a22

File tree

7 files changed

+300
-68
lines changed

7 files changed

+300
-68
lines changed

bolt/docs/BAT.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Functions table:
5454
| table |
5555
| |
5656
| Secondary entry |
57-
| points |
57+
| points and LPs |
5858
|------------------|
5959
6060
```
@@ -80,7 +80,7 @@ Hot indices are delta encoded, implicitly starting at zero.
8080
| `HotIndex` | Delta, ULEB128 | Index of corresponding hot function in hot functions table | Cold |
8181
| `FuncHash` | 8b | Function hash for input function | Hot |
8282
| `NumBlocks` | ULEB128 | Number of basic blocks in the original function | Hot |
83-
| `NumSecEntryPoints` | ULEB128 | Number of secondary entry points in the original function | Hot |
83+
| `NumSecEntryPoints` | ULEB128 | Number of secondary entry points and landing pads in the original function | Hot |
8484
| `ColdInputSkew` | ULEB128 | Skew to apply to all input offsets | Cold |
8585
| `NumEntries` | ULEB128 | Number of address translation entries for a function | Both |
8686
| `EqualElems` | ULEB128 | Number of equal offsets in the beginning of a function | Both |
@@ -116,7 +116,11 @@ input basic block mapping.
116116

117117
### Secondary Entry Points table
118118
The table is emitted for hot fragments only. It contains `NumSecEntryPoints`
119-
offsets denoting secondary entry points, delta encoded, implicitly starting at zero.
119+
offsets denoting secondary entry points and landing pads, delta encoded,
120+
implicitly starting at zero.
120121
| Entry | Encoding | Description |
121122
| ----- | -------- | ----------- |
122-
| `SecEntryPoint` | Delta, ULEB128 | Secondary entry point offset |
123+
| `SecEntryPoint` | Delta, ULEB128 | Secondary entry point offset with `LPENTRY` LSB bit |
124+
125+
`LPENTRY` bit denotes whether a given offset is a landing pad block. If not set,
126+
the offset is a secondary entry point.

bolt/include/bolt/Core/BinaryFunction.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,10 @@ class BinaryFunction {
908908
return BB && BB->getOffset() == Offset ? BB : nullptr;
909909
}
910910

911+
const BinaryBasicBlock *getBasicBlockAtOffset(uint64_t Offset) const {
912+
return const_cast<BinaryFunction *>(this)->getBasicBlockAtOffset(Offset);
913+
}
914+
911915
/// Retrieve the landing pad BB associated with invoke instruction \p Invoke
912916
/// that is in \p BB. Return nullptr if none exists
913917
BinaryBasicBlock *getLandingPadBBFor(const BinaryBasicBlock &BB,

bolt/include/bolt/Profile/BoltAddressTranslation.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,13 @@ class BoltAddressTranslation {
182182
/// translation map entry
183183
const static uint32_t BRANCHENTRY = 0x1;
184184

185+
/// Identifies a landing pad in secondary entry point map entry.
186+
const static uint32_t LPENTRY = 0x1;
187+
185188
public:
189+
/// Returns whether a given \p Offset is a secondary entry point or a landing pad in function with address \p Address.
190+
bool isSecondaryEntry(uint64_t Address, uint32_t Offset) const;
191+
186192
/// Map basic block input offset to a basic block index and hash pair.
187193
class BBHashMapTy {
188194
struct EntryTy {

bolt/include/bolt/Profile/DataAggregator.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,8 @@ class DataAggregator : public DataReader {
266266
uint64_t Mispreds);
267267

268268
/// Register a \p Branch.
269-
bool doBranch(uint64_t From, uint64_t To, uint64_t Count, uint64_t Mispreds);
269+
bool doBranch(uint64_t From, uint64_t To, uint64_t Count, uint64_t Mispreds,
270+
bool IsPreagg);
270271

271272
/// Register a trace between two LBR entries supplied in execution order.
272273
bool doTrace(const LBREntry &First, const LBREntry &Second,

bolt/lib/Profile/BoltAddressTranslation.cpp

Lines changed: 52 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -86,21 +86,16 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) {
8686
if (Function.isIgnored() || (!BC.HasRelocations && !Function.isSimple()))
8787
continue;
8888

89-
uint32_t NumSecondaryEntryPoints = 0;
90-
Function.forEachEntryPoint([&](uint64_t Offset, const MCSymbol *) {
91-
if (!Offset)
92-
return true;
93-
++NumSecondaryEntryPoints;
94-
SecondaryEntryPointsMap[OutputAddress].push_back(Offset);
95-
return true;
96-
});
97-
9889
LLVM_DEBUG(dbgs() << "Function name: " << Function.getPrintName() << "\n");
9990
LLVM_DEBUG(dbgs() << " Address reference: 0x"
10091
<< Twine::utohexstr(Function.getOutputAddress()) << "\n");
10192
LLVM_DEBUG(dbgs() << formatv(" Hash: {0:x}\n", getBFHash(InputAddress)));
102-
LLVM_DEBUG(dbgs() << " Secondary Entry Points: " << NumSecondaryEntryPoints
103-
<< '\n');
93+
LLVM_DEBUG({
94+
uint32_t NumSecondaryEntryPoints = 0;
95+
if (SecondaryEntryPointsMap.count(InputAddress))
96+
NumSecondaryEntryPoints = SecondaryEntryPointsMap[InputAddress].size();
97+
dbgs() << " Secondary Entry Points: " << NumSecondaryEntryPoints << '\n';
98+
});
10499

105100
MapTy Map;
106101
for (const BinaryBasicBlock *const BB :
@@ -206,10 +201,9 @@ void BoltAddressTranslation::writeMaps(uint64_t &PrevAddress, raw_ostream &OS) {
206201
<< Twine::utohexstr(Address) << ".\n");
207202
encodeULEB128(Address - PrevAddress, OS);
208203
PrevAddress = Address;
209-
const uint32_t NumSecondaryEntryPoints =
210-
SecondaryEntryPointsMap.count(Address)
211-
? SecondaryEntryPointsMap[Address].size()
212-
: 0;
204+
uint32_t NumSecondaryEntryPoints = 0;
205+
if (SecondaryEntryPointsMap.count(HotInputAddress))
206+
NumSecondaryEntryPoints = SecondaryEntryPointsMap[HotInputAddress].size();
213207
uint32_t Skew = 0;
214208
if (Cold) {
215209
auto HotEntryIt = llvm::lower_bound(HotFuncs, ColdPartSource[Address]);
@@ -281,7 +275,7 @@ void BoltAddressTranslation::writeMaps(uint64_t &PrevAddress, raw_ostream &OS) {
281275
if (!Cold && NumSecondaryEntryPoints) {
282276
LLVM_DEBUG(dbgs() << "Secondary entry points: ");
283277
// Secondary entry point offsets, delta-encoded
284-
for (uint32_t Offset : SecondaryEntryPointsMap[Address]) {
278+
for (uint32_t Offset : SecondaryEntryPointsMap[HotInputAddress]) {
285279
encodeULEB128(Offset - PrevOffset, OS);
286280
LLVM_DEBUG(dbgs() << formatv("{0:x} ", Offset));
287281
PrevOffset = Offset;
@@ -469,8 +463,12 @@ void BoltAddressTranslation::dump(raw_ostream &OS) const {
469463
const std::vector<uint32_t> &SecondaryEntryPoints =
470464
SecondaryEntryPointsIt->second;
471465
OS << SecondaryEntryPoints.size() << " secondary entry points:\n";
472-
for (uint32_t EntryPointOffset : SecondaryEntryPoints)
473-
OS << formatv("{0:x}\n", EntryPointOffset);
466+
for (uint32_t EntryPointOffset : SecondaryEntryPoints) {
467+
OS << formatv("{0:x}", EntryPointOffset >> 1);
468+
if (EntryPointOffset & LPENTRY)
469+
OS << " (lp)";
470+
OS << '\n';
471+
}
474472
}
475473
OS << "\n";
476474
}
@@ -582,14 +580,21 @@ void BoltAddressTranslation::saveMetadata(BinaryContext &BC) {
582580
// changed
583581
if (BF.isIgnored() || (!BC.HasRelocations && !BF.isSimple()))
584582
continue;
583+
const uint64_t FuncAddress = BF.getAddress();
585584
// Prepare function and block hashes
586-
FuncHashes.addEntry(BF.getAddress(), BF.computeHash());
585+
FuncHashes.addEntry(FuncAddress, BF.computeHash());
587586
BF.computeBlockHashes();
588-
BBHashMapTy &BBHashMap = getBBHashMap(BF.getAddress());
587+
BBHashMapTy &BBHashMap = getBBHashMap(FuncAddress);
588+
std::vector<uint32_t> SecondaryEntryPoints;
589589
// Set BF/BB metadata
590-
for (const BinaryBasicBlock &BB : BF)
590+
for (const BinaryBasicBlock &BB : BF) {
591591
BBHashMap.addEntry(BB.getInputOffset(), BB.getIndex(), BB.getHash());
592-
NumBasicBlocksMap.emplace(BF.getAddress(), BF.size());
592+
bool IsLandingPad = BB.isLandingPad();
593+
if (IsLandingPad || BF.getSecondaryEntryPointSymbol(BB))
594+
SecondaryEntryPoints.emplace_back(BB.getOffset() << 1 | IsLandingPad);
595+
}
596+
SecondaryEntryPointsMap.emplace(FuncAddress, SecondaryEntryPoints);
597+
NumBasicBlocksMap.emplace(FuncAddress, BF.size());
593598
}
594599
}
595600

@@ -599,13 +604,20 @@ BoltAddressTranslation::getSecondaryEntryPointId(uint64_t Address,
599604
auto FunctionIt = SecondaryEntryPointsMap.find(Address);
600605
if (FunctionIt == SecondaryEntryPointsMap.end())
601606
return 0;
602-
const std::vector<uint32_t> &Offsets = FunctionIt->second;
603-
auto OffsetIt = std::find(Offsets.begin(), Offsets.end(), Offset);
604-
if (OffsetIt == Offsets.end())
605-
return 0;
606-
// Adding one here because main entry point is not stored in BAT, and
607-
// enumeration for secondary entry points starts with 1.
608-
return OffsetIt - Offsets.begin() + 1;
607+
unsigned EntryPoints = 0;
608+
// Note we need to scan the vector to get the entry point id because it
609+
// contains both entry points and landing pads.
610+
for (uint32_t Off : FunctionIt->second) {
611+
// Skip landing pads.
612+
if (Off & LPENTRY)
613+
continue;
614+
// Adding one here because main entry point is not stored in BAT, and
615+
// enumeration for secondary entry points starts with 1.
616+
if (Off >> 1 == Offset)
617+
return EntryPoints + 1;
618+
++EntryPoints;
619+
}
620+
return 0;
609621
}
610622

611623
std::pair<const BinaryFunction *, unsigned>
@@ -637,5 +649,16 @@ BoltAddressTranslation::translateSymbol(const BinaryContext &BC,
637649
return std::pair(ParentBF, SecondaryEntryId);
638650
}
639651

652+
bool BoltAddressTranslation::isSecondaryEntry(uint64_t Address,
653+
uint32_t Offset) const {
654+
auto FunctionIt = SecondaryEntryPointsMap.find(Address);
655+
if (FunctionIt == SecondaryEntryPointsMap.end())
656+
return false;
657+
const std::vector<uint32_t> &Offsets = FunctionIt->second;
658+
uint64_t InputOffset = translate(Address, Offset, /*IsBranchSrc*/ false);
659+
auto OffsetIt = llvm::lower_bound(Offsets, InputOffset << 1);
660+
return OffsetIt != Offsets.end() && *OffsetIt >> 1 == InputOffset;
661+
}
662+
640663
} // namespace bolt
641664
} // namespace llvm

bolt/lib/Profile/DataAggregator.cpp

Lines changed: 75 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -778,42 +778,73 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc,
778778
}
779779

780780
bool DataAggregator::doBranch(uint64_t From, uint64_t To, uint64_t Count,
781-
uint64_t Mispreds) {
782-
bool IsReturn = false;
783-
auto handleAddress = [&](uint64_t &Addr, bool IsFrom) -> BinaryFunction * {
784-
if (BinaryFunction *Func = getBinaryFunctionContainingAddress(Addr)) {
785-
Addr -= Func->getAddress();
786-
if (IsFrom) {
787-
auto checkReturn = [&](auto MaybeInst) {
788-
IsReturn = MaybeInst && BC->MIB->isReturn(*MaybeInst);
789-
};
790-
if (Func->hasInstructions())
791-
checkReturn(Func->getInstructionAtOffset(Addr));
792-
else
793-
checkReturn(Func->disassembleInstructionAtOffset(Addr));
794-
}
781+
uint64_t Mispreds, bool IsPreagg) {
782+
// Returns whether \p Offset in \p Func contains a return instruction.
783+
auto checkReturn = [&](const BinaryFunction &Func, const uint64_t Offset) {
784+
auto isReturn = [&](auto MI) { return MI && BC->MIB->isReturn(*MI); };
785+
return Func.hasInstructions()
786+
? isReturn(Func.getInstructionAtOffset(Offset))
787+
: isReturn(Func.disassembleInstructionAtOffset(Offset));
788+
};
795789

796-
if (BAT)
797-
Addr = BAT->translate(Func->getAddress(), Addr, IsFrom);
790+
// Returns whether \p Offset in \p Func may be a call continuation excluding
791+
// entry points and landing pads.
792+
auto checkCallCont = [&](const BinaryFunction &Func, const uint64_t Offset) {
793+
// No call continuation at a function start.
794+
if (!Offset)
795+
return false;
798796

799-
if (BinaryFunction *ParentFunc = getBATParentFunction(*Func)) {
800-
Func = ParentFunc;
801-
if (IsFrom)
802-
NumColdSamples += Count;
803-
}
797+
if (!Func.hasCFG())
798+
return BAT && !BAT->isSecondaryEntry(Func.getAddress(), Offset);
804799

805-
return Func;
806-
}
807-
return nullptr;
800+
// The offset should not be an entry point or a landing pad.
801+
const BinaryBasicBlock *ContBB = Func.getBasicBlockAtOffset(Offset);
802+
return ContBB && !ContBB->isEntryPoint() && !ContBB->isLandingPad();
808803
};
809804

810-
BinaryFunction *FromFunc = handleAddress(From, /*IsFrom=*/true);
805+
// Mutates \p Addr to an offset into the containing function, performing BAT
806+
// offset translation and parent lookup.
807+
//
808+
// Returns the containing function (or BAT parent) and whether the address
809+
// corresponds to a return (if \p IsFrom) or a call continuation (otherwise).
810+
auto handleAddress = [&](uint64_t &Addr, bool IsFrom) {
811+
BinaryFunction *Func = getBinaryFunctionContainingAddress(Addr);
812+
if (!Func)
813+
return std::pair{Func, false};
814+
815+
Addr -= Func->getAddress();
816+
817+
bool IsRetOrCallCont =
818+
IsFrom ? checkReturn(*Func, Addr) : checkCallCont(*Func, Addr);
819+
820+
if (BAT)
821+
Addr = BAT->translate(Func->getAddress(), Addr, IsFrom);
822+
823+
BinaryFunction *ParentFunc = getBATParentFunction(*Func);
824+
if (!ParentFunc)
825+
return std::pair{Func, IsRetOrCallCont};
826+
827+
if (IsFrom)
828+
NumColdSamples += Count;
829+
830+
return std::pair{ParentFunc, IsRetOrCallCont};
831+
};
832+
833+
uint64_t ToOrig = To;
834+
auto [FromFunc, IsReturn] = handleAddress(From, /*IsFrom=*/true);
835+
auto [ToFunc, IsCallCont] = handleAddress(To, /*IsFrom=*/false);
836+
if (!FromFunc && !ToFunc)
837+
return false;
838+
839+
// Record call to continuation trace.
840+
if (IsPreagg && FromFunc != ToFunc && (IsReturn || IsCallCont)) {
841+
LBREntry First{ToOrig - 1, ToOrig - 1, false};
842+
LBREntry Second{ToOrig, ToOrig, false};
843+
return doTrace(First, Second, Count);
844+
}
811845
// Ignore returns.
812846
if (IsReturn)
813847
return true;
814-
BinaryFunction *ToFunc = handleAddress(To, /*IsFrom=*/false);
815-
if (!FromFunc && !ToFunc)
816-
return false;
817848

818849
// Treat recursive control transfers as inter-branches.
819850
if (FromFunc == ToFunc && To != 0) {
@@ -830,10 +861,19 @@ bool DataAggregator::doTrace(const LBREntry &First, const LBREntry &Second,
830861
BinaryFunction *ToFunc = getBinaryFunctionContainingAddress(Second.From);
831862
if (!FromFunc || !ToFunc) {
832863
LLVM_DEBUG({
833-
dbgs() << "Out of range trace starting in " << FromFunc->getPrintName()
834-
<< formatv(" @ {0:x}", First.To - FromFunc->getAddress())
835-
<< " and ending in " << ToFunc->getPrintName()
836-
<< formatv(" @ {0:x}\n", Second.From - ToFunc->getAddress());
864+
dbgs() << "Out of range trace starting in ";
865+
if (FromFunc)
866+
dbgs() << formatv("{0} @ {1:x}", *FromFunc,
867+
First.To - FromFunc->getAddress());
868+
else
869+
dbgs() << Twine::utohexstr(First.To);
870+
dbgs() << " and ending in ";
871+
if (ToFunc)
872+
dbgs() << formatv("{0} @ {1:x}", *ToFunc,
873+
Second.From - ToFunc->getAddress());
874+
else
875+
dbgs() << Twine::utohexstr(Second.From);
876+
dbgs() << '\n';
837877
});
838878
NumLongRangeTraces += Count;
839879
return false;
@@ -1620,7 +1660,8 @@ void DataAggregator::processBranchEvents() {
16201660
for (const auto &AggrLBR : BranchLBRs) {
16211661
const Trace &Loc = AggrLBR.first;
16221662
const TakenBranchInfo &Info = AggrLBR.second;
1623-
doBranch(Loc.From, Loc.To, Info.TakenCount, Info.MispredCount);
1663+
doBranch(Loc.From, Loc.To, Info.TakenCount, Info.MispredCount,
1664+
/*IsPreagg*/ false);
16241665
}
16251666
}
16261667

@@ -1781,7 +1822,7 @@ void DataAggregator::processPreAggregated() {
17811822
switch (AggrEntry.EntryType) {
17821823
case AggregatedLBREntry::BRANCH:
17831824
doBranch(AggrEntry.From.Offset, AggrEntry.To.Offset, AggrEntry.Count,
1784-
AggrEntry.Mispreds);
1825+
AggrEntry.Mispreds, /*IsPreagg=*/true);
17851826
break;
17861827
case AggregatedLBREntry::FT:
17871828
case AggregatedLBREntry::FT_EXTERNAL_ORIGIN: {

0 commit comments

Comments
 (0)