Skip to content

Commit 8f1d94a

Browse files
authored
[BOLT] Use continuous output addresses in delta encoding in BAT
Make output function addresses be delta-encoded wrt last offset in the previous function. This reduces the deltas in function start addresses. Test Plan: Reduces BAT section size to: - large binary: 12218860 bytes (0.32x original), - medium binary: 1606580 bytes (0.27x original), - small binary: 404 bytes (0.28x original), Reviewers: rafaelauler Reviewed By: rafaelauler Pull Request: llvm#76904
1 parent 8336515 commit 8f1d94a

File tree

3 files changed

+36
-27
lines changed

3 files changed

+36
-27
lines changed

bolt/docs/BAT.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,15 @@ Header:
6969

7070
The header is followed by Functions table with `NumFuncs` entries.
7171
Output binary addresses are delta encoded, meaning that only the difference with
72-
the previous output address is stored. Addresses implicitly start at zero.
72+
the last previous output address is stored. Addresses implicitly start at zero.
73+
Output addresses are continuous through function start addresses and function
74+
internal offsets, and between hot and cold fragments, to better spread deltas
75+
and save space.
76+
7377
Hot indices are delta encoded, implicitly starting at zero.
7478
| Entry | Encoding | Description |
7579
| ------ | ------| ----------- |
76-
| `Address` | Delta, ULEB128 | Function address in the output binary |
80+
| `Address` | Continuous, Delta, ULEB128 | Function address in the output binary |
7781
| `HotIndex` | Delta, ULEB128 | Cold functions only: index of corresponding hot function in hot functions table |
7882
| `NumEntries` | ULEB128 | Number of address translation entries for a function |
7983

@@ -82,10 +86,10 @@ function.
8286

8387
### Address translation table
8488
Delta encoding means that only the difference with the previous corresponding
85-
entry is encoded. Offsets implicitly start at zero.
89+
entry is encoded. Input offsets implicitly start at zero.
8690
| Entry | Encoding | Description |
8791
| ------ | ------| ----------- |
88-
| `OutputOffset` | Delta, ULEB128 | Function offset in output binary |
92+
| `OutputOffset` | Continuous, Delta, ULEB128 | Function offset in output binary |
8993
| `InputOffset` | Delta, SLEB128 | Function offset in input binary with `BRANCHENTRY` LSB bit |
9094

9195
`BRANCHENTRY` bit denotes whether a given offset pair is a control flow source

bolt/include/bolt/Profile/BoltAddressTranslation.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,14 @@ class BoltAddressTranslation {
121121

122122
/// Write the serialized address translation table for a function.
123123
template <bool Cold>
124-
void writeMaps(std::map<uint64_t, MapTy> &Maps, raw_ostream &OS);
124+
void writeMaps(std::map<uint64_t, MapTy> &Maps, uint64_t &PrevAddress,
125+
raw_ostream &OS);
125126

126127
/// Read the serialized address translation table for a function.
127128
/// Return a parse error if failed.
128129
template <bool Cold>
129-
void parseMaps(std::vector<uint64_t> &HotFuncs, DataExtractor &DE,
130-
uint64_t &Offset, Error &Err);
130+
void parseMaps(std::vector<uint64_t> &HotFuncs, uint64_t &PrevAddress,
131+
DataExtractor &DE, uint64_t &Offset, Error &Err);
131132

132133
std::map<uint64_t, MapTy> Maps;
133134

bolt/lib/Profile/BoltAddressTranslation.cpp

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,17 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) {
102102
}
103103
}
104104

105-
writeMaps</*Cold=*/false>(Maps, OS);
106-
writeMaps</*Cold=*/true>(Maps, OS);
105+
// Output addresses are delta-encoded
106+
uint64_t PrevAddress = 0;
107+
writeMaps</*Cold=*/false>(Maps, PrevAddress, OS);
108+
writeMaps</*Cold=*/true>(Maps, PrevAddress, OS);
107109

108110
outs() << "BOLT-INFO: Wrote " << Maps.size() << " BAT maps\n";
109111
}
110112

111113
template <bool Cold>
112114
void BoltAddressTranslation::writeMaps(std::map<uint64_t, MapTy> &Maps,
113-
raw_ostream &OS) {
115+
uint64_t &PrevAddress, raw_ostream &OS) {
114116
const uint32_t NumFuncs =
115117
llvm::count_if(llvm::make_first_range(Maps), [&](const uint64_t Address) {
116118
return Cold == ColdPartSource.count(Address);
@@ -119,8 +121,6 @@ void BoltAddressTranslation::writeMaps(std::map<uint64_t, MapTy> &Maps,
119121
LLVM_DEBUG(dbgs() << "Writing " << NumFuncs << (Cold ? " cold" : "")
120122
<< " functions for BAT.\n");
121123
size_t PrevIndex = 0;
122-
// Output addresses are delta-encoded
123-
uint64_t PrevAddress = 0;
124124
for (auto &MapEntry : Maps) {
125125
const uint64_t Address = MapEntry.first;
126126
// Only process cold fragments in cold mode, and vice versa.
@@ -139,12 +139,14 @@ void BoltAddressTranslation::writeMaps(std::map<uint64_t, MapTy> &Maps,
139139
PrevIndex = HotIndex;
140140
}
141141
encodeULEB128(NumEntries, OS);
142-
uint64_t InOffset = 0, OutOffset = 0;
142+
uint64_t InOffset = 0;
143143
// Output and Input addresses and delta-encoded
144144
for (std::pair<const uint32_t, uint32_t> &KeyVal : Map) {
145-
encodeULEB128(KeyVal.first - OutOffset, OS);
145+
const uint64_t OutputAddress = KeyVal.first + Address;
146+
encodeULEB128(OutputAddress - PrevAddress, OS);
147+
PrevAddress = OutputAddress;
146148
encodeSLEB128(KeyVal.second - InOffset, OS);
147-
std::tie(OutOffset, InOffset) = KeyVal;
149+
InOffset = KeyVal.second;
148150
}
149151
}
150152
}
@@ -170,21 +172,21 @@ std::error_code BoltAddressTranslation::parse(StringRef Buf) {
170172

171173
Error Err(Error::success());
172174
std::vector<uint64_t> HotFuncs;
173-
parseMaps</*Cold=*/false>(HotFuncs, DE, Offset, Err);
174-
parseMaps</*Cold=*/true>(HotFuncs, DE, Offset, Err);
175+
uint64_t PrevAddress = 0;
176+
parseMaps</*Cold=*/false>(HotFuncs, PrevAddress, DE, Offset, Err);
177+
parseMaps</*Cold=*/true>(HotFuncs, PrevAddress, DE, Offset, Err);
175178
outs() << "BOLT-INFO: Parsed " << Maps.size() << " BAT entries\n";
176179
return errorToErrorCode(std::move(Err));
177180
}
178181

179182
template <bool Cold>
180183
void BoltAddressTranslation::parseMaps(std::vector<uint64_t> &HotFuncs,
181-
DataExtractor &DE, uint64_t &Offset,
182-
Error &Err) {
184+
uint64_t &PrevAddress, DataExtractor &DE,
185+
uint64_t &Offset, Error &Err) {
183186
const uint32_t NumFunctions = DE.getULEB128(&Offset, &Err);
184187
LLVM_DEBUG(dbgs() << "Parsing " << NumFunctions << (Cold ? " cold" : "")
185188
<< " functions\n");
186189
size_t HotIndex = 0;
187-
uint64_t PrevAddress = 0;
188190
for (uint32_t I = 0; I < NumFunctions; ++I) {
189191
const uint64_t Address = PrevAddress + DE.getULEB128(&Offset, &Err);
190192
PrevAddress = Address;
@@ -199,18 +201,20 @@ void BoltAddressTranslation::parseMaps(std::vector<uint64_t> &HotFuncs,
199201

200202
LLVM_DEBUG(dbgs() << "Parsing " << NumEntries << " entries for 0x"
201203
<< Twine::utohexstr(Address) << "\n");
202-
uint64_t InputOffset = 0, OutputOffset = 0;
204+
uint64_t InputOffset = 0;
203205
for (uint32_t J = 0; J < NumEntries; ++J) {
204206
const uint64_t OutputDelta = DE.getULEB128(&Offset, &Err);
207+
const uint64_t OutputAddress = PrevAddress + OutputDelta;
208+
const uint64_t OutputOffset = OutputAddress - Address;
209+
PrevAddress = OutputAddress;
205210
const int64_t InputDelta = DE.getSLEB128(&Offset, &Err);
206-
OutputOffset += OutputDelta;
207211
InputOffset += InputDelta;
208212
Map.insert(std::pair<uint32_t, uint32_t>(OutputOffset, InputOffset));
209-
LLVM_DEBUG(dbgs() << formatv("{0:x} -> {1:x} ({2}/{3}b -> {4}/{5}b)\n",
210-
OutputOffset, InputOffset, OutputDelta,
211-
encodeULEB128(OutputDelta, nulls()),
212-
InputDelta,
213-
encodeSLEB128(InputDelta, nulls())));
213+
LLVM_DEBUG(
214+
dbgs() << formatv("{0:x} -> {1:x} ({2}/{3}b -> {4}/{5}b), {6:x}\n",
215+
OutputOffset, InputOffset, OutputDelta,
216+
encodeULEB128(OutputDelta, nulls()), InputDelta,
217+
encodeSLEB128(InputDelta, nulls()), OutputAddress));
214218
}
215219
Maps.insert(std::pair<uint64_t, MapTy>(Address, Map));
216220
}

0 commit comments

Comments
 (0)