Skip to content

Commit a91cd53

Browse files
authored
[BOLT][NFC] Refactor BAT metadata data structures
Hide the implementations of `FuncHashes` and `BBHashMap` classes, getting rid of `at` accessors that could throw an exception. Test Plan: NFC Reviewers: ayermolo, maksfb, dcci, rafaelauler Reviewed By: rafaelauler Pull Request: #86353
1 parent e14c6fa commit a91cd53

File tree

2 files changed

+137
-65
lines changed

2 files changed

+137
-65
lines changed

bolt/include/bolt/Profile/BoltAddressTranslation.h

Lines changed: 101 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -115,17 +115,6 @@ class BoltAddressTranslation {
115115
/// Save function and basic block hashes used for metadata dump.
116116
void saveMetadata(BinaryContext &BC);
117117

118-
/// Returns BB hash by function output address (after BOLT) and basic block
119-
/// input offset.
120-
size_t getBBHash(uint64_t FuncOutputAddress, uint32_t BBInputOffset) const;
121-
122-
/// Returns BF hash by function output address (after BOLT).
123-
size_t getBFHash(uint64_t OutputAddress) const;
124-
125-
/// Returns BB index by function output address (after BOLT) and basic block
126-
/// input offset.
127-
unsigned getBBIndex(uint64_t FuncOutputAddress, uint32_t BBInputOffset) const;
128-
129118
/// True if a given \p Address is a function with translation table entry.
130119
bool isBATFunction(uint64_t Address) const { return Maps.count(Address); }
131120

@@ -135,7 +124,7 @@ class BoltAddressTranslation {
135124
/// emitted for the start of the BB. More entries may be emitted to cover
136125
/// the location of calls or any instruction that may change control flow.
137126
void writeEntriesForBB(MapTy &Map, const BinaryBasicBlock &BB,
138-
uint64_t FuncAddress);
127+
uint64_t FuncInputAddress, uint64_t FuncOutputAddress);
139128

140129
/// Write the serialized address translation table for a function.
141130
template <bool Cold>
@@ -158,10 +147,6 @@ class BoltAddressTranslation {
158147

159148
std::map<uint64_t, MapTy> Maps;
160149

161-
/// Map basic block input offset to a basic block index and hash pair.
162-
using BBHashMap = std::unordered_map<uint32_t, std::pair<unsigned, size_t>>;
163-
std::unordered_map<uint64_t, std::pair<size_t, BBHashMap>> FuncHashes;
164-
165150
/// Map a function to its basic blocks count
166151
std::unordered_map<uint64_t, size_t> NumBasicBlocksMap;
167152

@@ -174,6 +159,106 @@ class BoltAddressTranslation {
174159
/// Identifies the address of a control-flow changing instructions in a
175160
/// translation map entry
176161
const static uint32_t BRANCHENTRY = 0x1;
162+
163+
public:
164+
/// Map basic block input offset to a basic block index and hash pair.
165+
class BBHashMapTy {
166+
class EntryTy {
167+
unsigned Index;
168+
size_t Hash;
169+
170+
public:
171+
unsigned getBBIndex() const { return Index; }
172+
size_t getBBHash() const { return Hash; }
173+
EntryTy(unsigned Index, size_t Hash) : Index(Index), Hash(Hash) {}
174+
};
175+
176+
std::unordered_map<uint32_t, EntryTy> Map;
177+
const EntryTy &getEntry(uint32_t BBInputOffset) const {
178+
auto It = Map.find(BBInputOffset);
179+
assert(It != Map.end());
180+
return It->second;
181+
}
182+
183+
public:
184+
bool isInputBlock(uint32_t InputOffset) const {
185+
return Map.count(InputOffset);
186+
}
187+
188+
unsigned getBBIndex(uint32_t BBInputOffset) const {
189+
return getEntry(BBInputOffset).getBBIndex();
190+
}
191+
192+
size_t getBBHash(uint32_t BBInputOffset) const {
193+
return getEntry(BBInputOffset).getBBHash();
194+
}
195+
196+
void addEntry(uint32_t BBInputOffset, unsigned BBIndex, size_t BBHash) {
197+
Map.emplace(BBInputOffset, EntryTy(BBIndex, BBHash));
198+
}
199+
200+
size_t getNumBasicBlocks() const { return Map.size(); }
201+
};
202+
203+
/// Map function output address to its hash and basic blocks hash map.
204+
class FuncHashesTy {
205+
class EntryTy {
206+
size_t Hash;
207+
BBHashMapTy BBHashMap;
208+
209+
public:
210+
size_t getBFHash() const { return Hash; }
211+
const BBHashMapTy &getBBHashMap() const { return BBHashMap; }
212+
EntryTy(size_t Hash) : Hash(Hash) {}
213+
};
214+
215+
std::unordered_map<uint64_t, EntryTy> Map;
216+
const EntryTy &getEntry(uint64_t FuncOutputAddress) const {
217+
auto It = Map.find(FuncOutputAddress);
218+
assert(It != Map.end());
219+
return It->second;
220+
}
221+
222+
public:
223+
size_t getBFHash(uint64_t FuncOutputAddress) const {
224+
return getEntry(FuncOutputAddress).getBFHash();
225+
}
226+
227+
const BBHashMapTy &getBBHashMap(uint64_t FuncOutputAddress) const {
228+
return getEntry(FuncOutputAddress).getBBHashMap();
229+
}
230+
231+
void addEntry(uint64_t FuncOutputAddress, size_t BFHash) {
232+
Map.emplace(FuncOutputAddress, EntryTy(BFHash));
233+
}
234+
235+
size_t getNumFunctions() const { return Map.size(); };
236+
237+
size_t getNumBasicBlocks() const {
238+
size_t NumBasicBlocks{0};
239+
for (auto &I : Map)
240+
NumBasicBlocks += I.second.getBBHashMap().getNumBasicBlocks();
241+
return NumBasicBlocks;
242+
}
243+
};
244+
245+
/// Returns BF hash by function output address (after BOLT).
246+
size_t getBFHash(uint64_t FuncOutputAddress) const {
247+
return FuncHashes.getBFHash(FuncOutputAddress);
248+
}
249+
250+
/// Returns BBHashMap by function output address (after BOLT).
251+
const BBHashMapTy &getBBHashMap(uint64_t FuncOutputAddress) const {
252+
return FuncHashes.getBBHashMap(FuncOutputAddress);
253+
}
254+
255+
BBHashMapTy &getBBHashMap(uint64_t FuncOutputAddress) {
256+
return const_cast<BBHashMapTy &>(
257+
std::as_const(*this).getBBHashMap(FuncOutputAddress));
258+
}
259+
260+
private:
261+
FuncHashesTy FuncHashes;
177262
};
178263
} // namespace bolt
179264

bolt/lib/Profile/BoltAddressTranslation.cpp

Lines changed: 36 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,10 @@ const char *BoltAddressTranslation::SECTION_NAME = ".note.bolt_bat";
2222

2323
void BoltAddressTranslation::writeEntriesForBB(MapTy &Map,
2424
const BinaryBasicBlock &BB,
25-
uint64_t FuncAddress) {
26-
uint64_t HotFuncAddress = ColdPartSource.count(FuncAddress)
27-
? ColdPartSource[FuncAddress]
28-
: FuncAddress;
25+
uint64_t FuncInputAddress,
26+
uint64_t FuncOutputAddress) {
2927
const uint64_t BBOutputOffset =
30-
BB.getOutputAddressRange().first - FuncAddress;
28+
BB.getOutputAddressRange().first - FuncOutputAddress;
3129
const uint32_t BBInputOffset = BB.getInputOffset();
3230

3331
// Every output BB must track back to an input BB for profile collection
@@ -42,11 +40,14 @@ void BoltAddressTranslation::writeEntriesForBB(MapTy &Map,
4240
LLVM_DEBUG(dbgs() << "BB " << BB.getName() << "\n");
4341
LLVM_DEBUG(dbgs() << " Key: " << Twine::utohexstr(BBOutputOffset)
4442
<< " Val: " << Twine::utohexstr(BBInputOffset) << "\n");
45-
LLVM_DEBUG(dbgs() << formatv(" Hash: {0:x}\n",
46-
getBBHash(HotFuncAddress, BBInputOffset)));
47-
(void)HotFuncAddress;
48-
LLVM_DEBUG(dbgs() << formatv(" Index: {0}\n",
49-
getBBIndex(HotFuncAddress, BBInputOffset)));
43+
// NB: in `writeEntriesForBB` we use the input address because hashes are
44+
// saved early in `saveMetadata` before output addresses are assigned.
45+
const BBHashMapTy &BBHashMap = getBBHashMap(FuncInputAddress);
46+
(void)BBHashMap;
47+
LLVM_DEBUG(
48+
dbgs() << formatv(" Hash: {0:x}\n", BBHashMap.getBBHash(BBInputOffset)));
49+
LLVM_DEBUG(
50+
dbgs() << formatv(" Index: {0}\n", BBHashMap.getBBIndex(BBInputOffset)));
5051
// In case of conflicts (same Key mapping to different Vals), the last
5152
// update takes precedence. Of course it is not ideal to have conflicts and
5253
// those happen when we have an empty BB that either contained only
@@ -63,7 +64,7 @@ void BoltAddressTranslation::writeEntriesForBB(MapTy &Map,
6364
const auto InputAddress = BB.getFunction()->getAddress() + InputOffset;
6465
const auto OutputAddress = IOAddressMap.lookup(InputAddress);
6566
assert(OutputAddress && "Unknown instruction address");
66-
const auto OutputOffset = *OutputAddress - FuncAddress;
67+
const auto OutputOffset = *OutputAddress - FuncOutputAddress;
6768

6869
// Is this the first instruction in the BB? No need to duplicate the entry.
6970
if (OutputOffset == BBOutputOffset)
@@ -99,7 +100,7 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) {
99100
MapTy Map;
100101
for (const BinaryBasicBlock *const BB :
101102
Function.getLayout().getMainFragment())
102-
writeEntriesForBB(Map, *BB, Function.getOutputAddress());
103+
writeEntriesForBB(Map, *BB, InputAddress, OutputAddress);
103104
Maps.emplace(Function.getOutputAddress(), std::move(Map));
104105
ReverseMap.emplace(OutputAddress, InputAddress);
105106

@@ -113,7 +114,7 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) {
113114
ColdPartSource.emplace(FF.getAddress(), Function.getOutputAddress());
114115
Map.clear();
115116
for (const BinaryBasicBlock *const BB : FF)
116-
writeEntriesForBB(Map, *BB, FF.getAddress());
117+
writeEntriesForBB(Map, *BB, InputAddress, FF.getAddress());
117118

118119
Maps.emplace(FF.getAddress(), std::move(Map));
119120
}
@@ -125,11 +126,9 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) {
125126
writeMaps</*Cold=*/true>(Maps, PrevAddress, OS);
126127

127128
BC.outs() << "BOLT-INFO: Wrote " << Maps.size() << " BAT maps\n";
128-
const uint64_t NumBBHashes = std::accumulate(
129-
FuncHashes.begin(), FuncHashes.end(), 0ull,
130-
[](size_t Acc, const auto &B) { return Acc + B.second.second.size(); });
131-
BC.outs() << "BOLT-INFO: Wrote " << FuncHashes.size() << " function and "
132-
<< NumBBHashes << " basic block hashes\n";
129+
BC.outs() << "BOLT-INFO: Wrote " << FuncHashes.getNumFunctions()
130+
<< " function and " << FuncHashes.getNumBasicBlocks()
131+
<< " basic block hashes\n";
133132
}
134133

135134
APInt BoltAddressTranslation::calculateBranchEntriesBitMask(MapTy &Map,
@@ -176,11 +175,10 @@ void BoltAddressTranslation::writeMaps(std::map<uint64_t, MapTy> &Maps,
176175
// Only process cold fragments in cold mode, and vice versa.
177176
if (Cold != ColdPartSource.count(Address))
178177
continue;
179-
// NB: here we use the input address because hashes are saved early (in
180-
// `saveMetadata`) before output addresses are assigned.
178+
// NB: in `writeMaps` we use the input address because hashes are saved
179+
// early in `saveMetadata` before output addresses are assigned.
181180
const uint64_t HotInputAddress =
182181
ReverseMap[Cold ? ColdPartSource[Address] : Address];
183-
std::pair<size_t, BBHashMap> &FuncHashPair = FuncHashes[HotInputAddress];
184182
MapTy &Map = MapEntry.second;
185183
const uint32_t NumEntries = Map.size();
186184
LLVM_DEBUG(dbgs() << "Writing " << NumEntries << " entries for 0x"
@@ -194,10 +192,11 @@ void BoltAddressTranslation::writeMaps(std::map<uint64_t, MapTy> &Maps,
194192
PrevIndex = HotIndex;
195193
} else {
196194
// Function hash
197-
LLVM_DEBUG(dbgs() << "Hash: " << formatv("{0:x}\n", FuncHashPair.first));
198-
OS.write(reinterpret_cast<char *>(&FuncHashPair.first), 8);
195+
size_t BFHash = getBFHash(HotInputAddress);
196+
LLVM_DEBUG(dbgs() << "Hash: " << formatv("{0:x}\n", BFHash));
197+
OS.write(reinterpret_cast<char *>(&BFHash), 8);
199198
// Number of basic blocks
200-
size_t NumBasicBlocks = FuncHashPair.second.size();
199+
size_t NumBasicBlocks = getBBHashMap(HotInputAddress).getNumBasicBlocks();
201200
LLVM_DEBUG(dbgs() << "Basic blocks: " << NumBasicBlocks << '\n');
202201
encodeULEB128(NumBasicBlocks, OS);
203202
}
@@ -221,6 +220,7 @@ void BoltAddressTranslation::writeMaps(std::map<uint64_t, MapTy> &Maps,
221220
});
222221
}
223222
}
223+
const BBHashMapTy &BBHashMap = getBBHashMap(HotInputAddress);
224224
size_t Index = 0;
225225
uint64_t InOffset = 0;
226226
size_t PrevBBIndex = 0;
@@ -233,9 +233,9 @@ void BoltAddressTranslation::writeMaps(std::map<uint64_t, MapTy> &Maps,
233233
encodeSLEB128(KeyVal.second - InOffset, OS);
234234
InOffset = KeyVal.second; // Keeping InOffset as if BRANCHENTRY is encoded
235235
if ((InOffset & BRANCHENTRY) == 0) {
236-
unsigned BBIndex;
237-
size_t BBHash;
238-
std::tie(BBIndex, BBHash) = FuncHashPair.second[InOffset >> 1];
236+
const bool IsBlock = BBHashMap.isInputBlock(InOffset >> 1);
237+
unsigned BBIndex = IsBlock ? BBHashMap.getBBIndex(InOffset >> 1) : 0;
238+
size_t BBHash = IsBlock ? BBHashMap.getBBHash(InOffset >> 1) : 0;
239239
OS.write(reinterpret_cast<char *>(&BBHash), 8);
240240
// Basic block index in the input binary
241241
encodeULEB128(BBIndex - PrevBBIndex, OS);
@@ -295,7 +295,7 @@ void BoltAddressTranslation::parseMaps(std::vector<uint64_t> &HotFuncs,
295295
HotFuncs.push_back(Address);
296296
// Function hash
297297
const size_t FuncHash = DE.getU64(&Offset, &Err);
298-
FuncHashes[Address].first = FuncHash;
298+
FuncHashes.addEntry(Address, FuncHash);
299299
LLVM_DEBUG(dbgs() << formatv("{0:x}: hash {1:x}\n", Address, FuncHash));
300300
// Number of basic blocks
301301
const size_t NumBasicBlocks = DE.getULEB128(&Offset, &Err);
@@ -355,8 +355,7 @@ void BoltAddressTranslation::parseMaps(std::vector<uint64_t> &HotFuncs,
355355
BBIndexDelta = DE.getULEB128(&Offset, &Err);
356356
BBIndex += BBIndexDelta;
357357
// Map basic block hash to hot fragment by input offset
358-
FuncHashes[HotAddress].second.emplace(InputOffset >> 1,
359-
std::pair(BBIndex, BBHash));
358+
getBBHashMap(HotAddress).addEntry(InputOffset >> 1, BBIndex, BBHash);
360359
}
361360
LLVM_DEBUG({
362361
dbgs() << formatv(
@@ -385,6 +384,8 @@ void BoltAddressTranslation::dump(raw_ostream &OS) {
385384
OS << formatv(", hash: {0:x}", getBFHash(Address));
386385
OS << "\n";
387386
OS << "BB mappings:\n";
387+
const BBHashMapTy &BBHashMap =
388+
getBBHashMap(HotAddress ? HotAddress : Address);
388389
for (const auto &Entry : MapEntry.second) {
389390
const bool IsBranch = Entry.second & BRANCHENTRY;
390391
const uint32_t Val = Entry.second >> 1; // dropping BRANCHENTRY bit
@@ -393,8 +394,7 @@ void BoltAddressTranslation::dump(raw_ostream &OS) {
393394
if (IsBranch)
394395
OS << " (branch)";
395396
else
396-
OS << formatv(" hash: {0:x}",
397-
getBBHash(HotAddress ? HotAddress : Address, Val));
397+
OS << formatv(" hash: {0:x}", BBHashMap.getBBHash(Val));
398398
OS << "\n";
399399
}
400400
OS << "\n";
@@ -515,27 +515,14 @@ void BoltAddressTranslation::saveMetadata(BinaryContext &BC) {
515515
if (BF.isIgnored() || (!BC.HasRelocations && !BF.isSimple()))
516516
continue;
517517
// Prepare function and block hashes
518-
FuncHashes[BF.getAddress()].first = BF.computeHash();
518+
FuncHashes.addEntry(BF.getAddress(), BF.computeHash());
519519
BF.computeBlockHashes();
520+
BBHashMapTy &BBHashMap = getBBHashMap(BF.getAddress());
521+
// Set BF/BB metadata
520522
for (const BinaryBasicBlock &BB : BF)
521-
FuncHashes[BF.getAddress()].second.emplace(
522-
BB.getInputOffset(), std::pair(BB.getIndex(), BB.getHash()));
523+
BBHashMap.addEntry(BB.getInputOffset(), BB.getIndex(), BB.getHash());
523524
}
524525
}
525526

526-
unsigned BoltAddressTranslation::getBBIndex(uint64_t FuncOutputAddress,
527-
uint32_t BBInputOffset) const {
528-
return FuncHashes.at(FuncOutputAddress).second.at(BBInputOffset).first;
529-
}
530-
531-
size_t BoltAddressTranslation::getBBHash(uint64_t FuncOutputAddress,
532-
uint32_t BBInputOffset) const {
533-
return FuncHashes.at(FuncOutputAddress).second.at(BBInputOffset).second;
534-
}
535-
536-
size_t BoltAddressTranslation::getBFHash(uint64_t OutputAddress) const {
537-
return FuncHashes.at(OutputAddress).first;
538-
}
539-
540527
} // namespace bolt
541528
} // namespace llvm

0 commit comments

Comments
 (0)