Skip to content

Commit 213eda1

Browse files
authored
[BOLT] Add CallSiteInfo entries in YAMLBAT (#76896)
Attach call counters to YAML profile, covering inter-function control flow. Depends on: #86218 Test Plan: Updated bolt/test/X86/bolt-address-translation-yaml.test
1 parent 4fc8df9 commit 213eda1

File tree

5 files changed

+125
-1
lines changed

5 files changed

+125
-1
lines changed

bolt/include/bolt/Profile/BoltAddressTranslation.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@ class BoltAddressTranslation {
118118
/// True if a given \p Address is a function with translation table entry.
119119
bool isBATFunction(uint64_t Address) const { return Maps.count(Address); }
120120

121+
/// Returns branch offsets grouped by containing basic block in a given
122+
/// function.
123+
std::unordered_map<uint32_t, std::vector<uint32_t>>
124+
getBFBranches(uint64_t FuncOutputAddress) const;
125+
121126
private:
122127
/// Helper to update \p Map by inserting one or more BAT entries reflecting
123128
/// \p BB for function located at \p FuncAddress. At least one entry will be

bolt/include/bolt/Profile/DataAggregator.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,9 @@ class DataAggregator : public DataReader {
467467
std::error_code writeBATYAML(BinaryContext &BC,
468468
StringRef OutputFilename) const;
469469

470+
/// Fixup profile collected on BOLTed binary, namely handle split functions.
471+
void fixupBATProfile(BinaryContext &BC);
472+
470473
/// Filter out binaries based on PID
471474
void filterBinaryMMapInfo();
472475

bolt/lib/Profile/BoltAddressTranslation.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,5 +577,25 @@ void BoltAddressTranslation::saveMetadata(BinaryContext &BC) {
577577
}
578578
}
579579

580+
std::unordered_map<uint32_t, std::vector<uint32_t>>
581+
BoltAddressTranslation::getBFBranches(uint64_t OutputAddress) const {
582+
std::unordered_map<uint32_t, std::vector<uint32_t>> Branches;
583+
auto FuncIt = Maps.find(OutputAddress);
584+
assert(FuncIt != Maps.end());
585+
std::vector<uint32_t> InputOffsets;
586+
for (const auto &KV : FuncIt->second)
587+
InputOffsets.emplace_back(KV.second);
588+
// Sort with LSB BRANCHENTRY bit.
589+
llvm::sort(InputOffsets);
590+
uint32_t BBOffset{0};
591+
for (uint32_t InOffset : InputOffsets) {
592+
if (InOffset & BRANCHENTRY)
593+
Branches[BBOffset].push_back(InOffset >> 1);
594+
else
595+
BBOffset = InOffset >> 1;
596+
}
597+
return Branches;
598+
}
599+
580600
} // namespace bolt
581601
} // namespace llvm

bolt/lib/Profile/DataAggregator.cpp

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,8 @@ Error DataAggregator::readProfile(BinaryContext &BC) {
604604
// BAT YAML is handled by DataAggregator since normal YAML output requires
605605
// CFG which is not available in BAT mode.
606606
if (usesBAT()) {
607+
// Postprocess split function profile for BAT
608+
fixupBATProfile(BC);
607609
if (opts::ProfileFormat == opts::ProfileFormatKind::PF_YAML)
608610
if (std::error_code EC = writeBATYAML(BC, opts::OutputFilename))
609611
report_error("cannot create output data file", EC);
@@ -2271,6 +2273,29 @@ DataAggregator::writeAggregatedFile(StringRef OutputFilename) const {
22712273
return std::error_code();
22722274
}
22732275

2276+
void DataAggregator::fixupBATProfile(BinaryContext &BC) {
2277+
for (auto &[FuncName, Branches] : NamesToBranches) {
2278+
BinaryData *BD = BC.getBinaryDataByName(FuncName);
2279+
assert(BD);
2280+
uint64_t FuncAddress = BD->getAddress();
2281+
if (!BAT->isBATFunction(FuncAddress))
2282+
continue;
2283+
// Filter out cold fragments
2284+
if (!BD->getSectionName().equals(BC.getMainCodeSectionName()))
2285+
continue;
2286+
// Convert inter-branches between hot and cold fragments into
2287+
// intra-branches.
2288+
for (auto &[OffsetFrom, CallToMap] : Branches.InterIndex) {
2289+
for (auto &[CallToLoc, CallToIdx] : CallToMap) {
2290+
if (CallToLoc.Name != FuncName)
2291+
continue;
2292+
Branches.IntraIndex[OffsetFrom][CallToLoc.Offset] = CallToIdx;
2293+
Branches.InterIndex[OffsetFrom].erase(CallToLoc);
2294+
}
2295+
}
2296+
}
2297+
}
2298+
22742299
std::error_code DataAggregator::writeBATYAML(BinaryContext &BC,
22752300
StringRef OutputFilename) const {
22762301
std::error_code EC;
@@ -2343,6 +2368,63 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC,
23432368
YamlBB.Successors.emplace_back(SI);
23442369
};
23452370

2371+
std::unordered_map<uint32_t, std::vector<uint32_t>> BFBranches =
2372+
BAT->getBFBranches(FuncAddress);
2373+
2374+
auto addCallsProfile = [&](yaml::bolt::BinaryBasicBlockProfile &YamlBB,
2375+
uint64_t Offset) {
2376+
// Iterate over BRANCHENTRY records in the current block
2377+
for (uint32_t BranchOffset : BFBranches[Offset]) {
2378+
if (!Branches.InterIndex.contains(BranchOffset))
2379+
continue;
2380+
for (const auto &[CallToLoc, CallToIdx] :
2381+
Branches.InterIndex.at(BranchOffset)) {
2382+
const llvm::bolt::BranchInfo &BI = Branches.Data.at(CallToIdx);
2383+
yaml::bolt::CallSiteInfo YamlCSI;
2384+
YamlCSI.DestId = 0; // designated for unknown functions
2385+
YamlCSI.EntryDiscriminator = 0;
2386+
YamlCSI.Count = BI.Branches;
2387+
YamlCSI.Mispreds = BI.Mispreds;
2388+
YamlCSI.Offset = BranchOffset - Offset;
2389+
BinaryData *CallTargetBD = BC.getBinaryDataByName(CallToLoc.Name);
2390+
if (!CallTargetBD) {
2391+
YamlBB.CallSites.emplace_back(YamlCSI);
2392+
continue;
2393+
}
2394+
uint64_t CallTargetAddress = CallTargetBD->getAddress();
2395+
BinaryFunction *CallTargetBF =
2396+
BC.getBinaryFunctionAtAddress(CallTargetAddress);
2397+
if (!CallTargetBF) {
2398+
YamlBB.CallSites.emplace_back(YamlCSI);
2399+
continue;
2400+
}
2401+
// Calls between hot and cold fragments must be handled in
2402+
// fixupBATProfile.
2403+
assert(CallTargetBF != BF && "invalid CallTargetBF");
2404+
YamlCSI.DestId = CallTargetBF->getFunctionNumber();
2405+
if (CallToLoc.Offset) {
2406+
if (BAT->isBATFunction(CallTargetAddress)) {
2407+
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Unsupported secondary "
2408+
"entry point in BAT function "
2409+
<< CallToLoc.Name << '\n');
2410+
} else if (const BinaryBasicBlock *CallTargetBB =
2411+
CallTargetBF->getBasicBlockAtOffset(
2412+
CallToLoc.Offset)) {
2413+
// Only record true call information, ignoring returns (normally
2414+
// won't have a target basic block) and jumps to the landing
2415+
// pads (not an entry point).
2416+
if (CallTargetBB->isEntryPoint()) {
2417+
YamlCSI.EntryDiscriminator =
2418+
CallTargetBF->getEntryIDForSymbol(
2419+
CallTargetBB->getLabel());
2420+
}
2421+
}
2422+
}
2423+
YamlBB.CallSites.emplace_back(YamlCSI);
2424+
}
2425+
}
2426+
};
2427+
23462428
for (const auto &[FromOffset, SuccKV] : Branches.IntraIndex) {
23472429
yaml::bolt::BinaryBasicBlockProfile YamlBB;
23482430
if (!BlockMap.isInputBlock(FromOffset))
@@ -2351,7 +2433,9 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC,
23512433
YamlBB.Hash = BlockMap.getBBHash(FromOffset);
23522434
for (const auto &[SuccOffset, SuccDataIdx] : SuccKV)
23532435
addSuccProfile(YamlBB, SuccOffset, SuccDataIdx);
2354-
if (YamlBB.ExecCount || !YamlBB.Successors.empty())
2436+
addCallsProfile(YamlBB, FromOffset);
2437+
if (YamlBB.ExecCount || !YamlBB.Successors.empty() ||
2438+
!YamlBB.CallSites.empty())
23552439
YamlBF.Blocks.emplace_back(YamlBB);
23562440
}
23572441
BP.Functions.emplace_back(YamlBF);

bolt/test/X86/bolt-address-translation-yaml.test

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,18 @@ YAML-BAT-CHECK-NEXT: - bid: 0
3636
YAML-BAT-CHECK-NEXT: insns: 26
3737
YAML-BAT-CHECK-NEXT: hash: 0xA900AE79CFD40000
3838
YAML-BAT-CHECK-NEXT: succ: [ { bid: 3, cnt: 0 }, { bid: 1, cnt: 0 } ]
39+
# Function covered by BAT with calls
40+
YAML-BAT-CHECK: - name: SolveCubic
41+
YAML-BAT-CHECK-NEXT: fid: [[#]]
42+
YAML-BAT-CHECK-NEXT: hash: 0x6AF7E61EA3966722
43+
YAML-BAT-CHECK-NEXT: exec: 25
44+
YAML-BAT-CHECK-NEXT: nblocks: 15
45+
YAML-BAT-CHECK-NEXT: blocks:
46+
YAML-BAT-CHECK: - bid: 3
47+
YAML-BAT-CHECK-NEXT: insns: [[#]]
48+
YAML-BAT-CHECK-NEXT: hash: 0xDDA1DC5F69F900AC
49+
YAML-BAT-CHECK-NEXT: calls: [ { off: 0x26, fid: [[#]], cnt: [[#]] } ]
50+
YAML-BAT-CHECK-NEXT: succ: [ { bid: 5, cnt: [[#]] }
3951
# Function covered by BAT - doesn't have insns in basic block
4052
YAML-BAT-CHECK: - name: usqrt
4153
YAML-BAT-CHECK-NEXT: fid: [[#]]

0 commit comments

Comments
 (0)