Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1256ef2

Browse files
author
spupyrev
committed
[BOLT] Fine-tuning hash computation for stale matching
Fine-tuning hash computation for stale matching: - introducing a new "loose" basic block hash that allows to match many more blocks than before; - tweaking params of the inference algorithm that find (slightly) better solutions; - added more meaningful tests for stale matching. Tested the changes on several open-source benchmarks (clang, rocksdb, chrome) and one prod workload using different compiler modes (LTO/PGO etc). There is always an improvement in the quality of inferred profiles. (The current implementation is still not optimal but the diff is a step forward; I am open to further suggestions) Reviewed By: Amir Differential Revision: https://reviews.llvm.org/D156278
1 parent c81ab62 commit 1256ef2

5 files changed

Lines changed: 167 additions & 110 deletions

File tree

bolt/include/bolt/Core/HashUtilities.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
namespace llvm {
2121
namespace bolt {
2222

23-
uint16_t hash_64_to_16(const uint64_t Hash);
24-
2523
std::string hashInteger(uint64_t Value);
2624

2725
std::string hashSymbol(BinaryContext &BC, const MCSymbol &Symbol);
@@ -35,6 +33,8 @@ using OperandHashFuncTy = function_ref<typename std::string(const MCOperand &)>;
3533
std::string hashBlock(BinaryContext &BC, const BinaryBasicBlock &BB,
3634
OperandHashFuncTy OperandHashFunc);
3735

36+
std::string hashBlockLoose(BinaryContext &BC, const BinaryBasicBlock &BB);
37+
3838
} // namespace bolt
3939
} // namespace llvm
4040

bolt/lib/Core/HashUtilities.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,5 +130,42 @@ std::string hashBlock(BinaryContext &BC, const BinaryBasicBlock &BB,
130130
return HashString;
131131
}
132132

133+
/// A "loose" hash of a basic block to use with the stale profile matching. The
134+
/// computed value will be the same for blocks with minor changes (such as
135+
/// reordering of instructions or using different operands) but may result in
136+
/// collisions that need to be resolved by a stronger hashing.
137+
std::string hashBlockLoose(BinaryContext &BC, const BinaryBasicBlock &BB) {
138+
// The hash is computed by creating a string of all lexicographically ordered
139+
// instruction opcodes, which is then hashed with std::hash.
140+
std::set<std::string> Opcodes;
141+
for (const MCInst &Inst : BB) {
142+
if (BC.MIB->isPseudo(Inst))
143+
continue;
144+
145+
// Ignore unconditional jumps, as they can be added / removed as a result
146+
// of basic block reordering.
147+
if (BC.MIB->isUnconditionalBranch(Inst))
148+
continue;
149+
150+
// Do not distinguish different types of conditional jumps.
151+
if (BC.MIB->isConditionalBranch(Inst)) {
152+
Opcodes.insert("JMP");
153+
continue;
154+
}
155+
156+
std::string Mnemonic = BC.InstPrinter->getMnemonic(&Inst).first;
157+
Mnemonic.erase(
158+
std::remove_if(Mnemonic.begin(), Mnemonic.end(),
159+
[](unsigned char ch) { return std::isspace(ch); }),
160+
Mnemonic.end());
161+
Opcodes.insert(Mnemonic);
162+
}
163+
164+
std::string HashString;
165+
for (const std::string &Opcode : Opcodes)
166+
HashString.append(Opcode);
167+
return HashString;
168+
}
169+
133170
} // namespace bolt
134171
} // namespace llvm

bolt/lib/Profile/StaleProfileMatching.cpp

Lines changed: 51 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -73,64 +73,39 @@ cl::opt<bool> StaleMatchingJoinIslands(
7373

7474
cl::opt<unsigned> StaleMatchingCostBlockInc(
7575
"stale-matching-cost-block-inc",
76-
cl::desc("The cost of increasing a block's count by one."), cl::init(110),
76+
cl::desc("The cost of increasing a block count by one."), cl::init(150),
7777
cl::ReallyHidden, cl::cat(BoltOptCategory));
7878

7979
cl::opt<unsigned> StaleMatchingCostBlockDec(
8080
"stale-matching-cost-block-dec",
81-
cl::desc("The cost of decreasing a block's count by one."), cl::init(100),
81+
cl::desc("The cost of decreasing a block count by one."), cl::init(150),
8282
cl::ReallyHidden, cl::cat(BoltOptCategory));
8383

84-
cl::opt<unsigned> StaleMatchingCostBlockEntryInc(
85-
"stale-matching-cost-block-entry-inc",
86-
cl::desc("The cost of increasing the entry block's count by one."),
87-
cl::init(110), cl::ReallyHidden, cl::cat(BoltOptCategory));
88-
89-
cl::opt<unsigned> StaleMatchingCostBlockEntryDec(
90-
"stale-matching-cost-block-entry-dec",
91-
cl::desc("The cost of decreasing the entry block's count by one."),
92-
cl::init(100), cl::ReallyHidden, cl::cat(BoltOptCategory));
93-
94-
cl::opt<unsigned> StaleMatchingCostBlockZeroInc(
95-
"stale-matching-cost-block-zero-inc",
96-
cl::desc("The cost of increasing a count of zero-weight block by one."),
97-
cl::init(10), cl::Hidden, cl::cat(BoltOptCategory));
98-
99-
cl::opt<unsigned> StaleMatchingCostBlockUnknownInc(
100-
"stale-matching-cost-block-unknown-inc",
101-
cl::desc("The cost of increasing an unknown block's count by one."),
102-
cl::init(10), cl::ReallyHidden, cl::cat(BoltOptCategory));
103-
10484
cl::opt<unsigned> StaleMatchingCostJumpInc(
10585
"stale-matching-cost-jump-inc",
106-
cl::desc("The cost of increasing a jump's count by one."), cl::init(100),
86+
cl::desc("The cost of increasing a jump count by one."), cl::init(150),
10787
cl::ReallyHidden, cl::cat(BoltOptCategory));
10888

109-
cl::opt<unsigned> StaleMatchingCostJumpFTInc(
110-
"stale-matching-cost-jump-ft-inc",
111-
cl::desc("The cost of increasing a fall-through jump's count by one."),
112-
cl::init(100), cl::ReallyHidden, cl::cat(BoltOptCategory));
113-
11489
cl::opt<unsigned> StaleMatchingCostJumpDec(
11590
"stale-matching-cost-jump-dec",
116-
cl::desc("The cost of decreasing a jump's count by one."), cl::init(110),
91+
cl::desc("The cost of decreasing a jump count by one."), cl::init(150),
11792
cl::ReallyHidden, cl::cat(BoltOptCategory));
11893

119-
cl::opt<unsigned> StaleMatchingCostJumpFTDec(
120-
"stale-matching-cost-jump-ft-dec",
121-
cl::desc("The cost of decreasing a fall-through jump's count by one."),
122-
cl::init(110), cl::ReallyHidden, cl::cat(BoltOptCategory));
94+
cl::opt<unsigned> StaleMatchingCostBlockUnknownInc(
95+
"stale-matching-cost-block-unknown-inc",
96+
cl::desc("The cost of increasing an unknown block count by one."),
97+
cl::init(1), cl::ReallyHidden, cl::cat(BoltOptCategory));
12398

12499
cl::opt<unsigned> StaleMatchingCostJumpUnknownInc(
125100
"stale-matching-cost-jump-unknown-inc",
126-
cl::desc("The cost of increasing an unknown jump's count by one."),
127-
cl::init(50), cl::ReallyHidden, cl::cat(BoltOptCategory));
101+
cl::desc("The cost of increasing an unknown jump count by one."),
102+
cl::init(140), cl::ReallyHidden, cl::cat(BoltOptCategory));
128103

129104
cl::opt<unsigned> StaleMatchingCostJumpUnknownFTInc(
130105
"stale-matching-cost-jump-unknown-ft-inc",
131106
cl::desc(
132-
"The cost of increasing an unknown fall-through jump's count by one."),
133-
cl::init(5), cl::ReallyHidden, cl::cat(BoltOptCategory));
107+
"The cost of increasing an unknown fall-through jump count by one."),
108+
cl::init(3), cl::ReallyHidden, cl::cat(BoltOptCategory));
134109

135110
} // namespace opts
136111

@@ -145,7 +120,8 @@ struct BlendedBlockHash {
145120
using ValueOffset = Bitfield::Element<uint16_t, 0, 16>;
146121
using ValueOpcode = Bitfield::Element<uint16_t, 16, 16>;
147122
using ValueInstr = Bitfield::Element<uint16_t, 32, 16>;
148-
using ValueNeighbor = Bitfield::Element<uint16_t, 48, 16>;
123+
using ValuePred = Bitfield::Element<uint8_t, 48, 8>;
124+
using ValueSucc = Bitfield::Element<uint8_t, 56, 8>;
149125

150126
public:
151127
explicit BlendedBlockHash() {}
@@ -154,7 +130,8 @@ struct BlendedBlockHash {
154130
Offset = Bitfield::get<ValueOffset>(Hash);
155131
OpcodeHash = Bitfield::get<ValueOpcode>(Hash);
156132
InstrHash = Bitfield::get<ValueInstr>(Hash);
157-
NeighborHash = Bitfield::get<ValueNeighbor>(Hash);
133+
PredHash = Bitfield::get<ValuePred>(Hash);
134+
SuccHash = Bitfield::get<ValueSucc>(Hash);
158135
}
159136

160137
/// Combine the blended hash into uint64_t.
@@ -163,7 +140,8 @@ struct BlendedBlockHash {
163140
Bitfield::set<ValueOffset>(Hash, Offset);
164141
Bitfield::set<ValueOpcode>(Hash, OpcodeHash);
165142
Bitfield::set<ValueInstr>(Hash, InstrHash);
166-
Bitfield::set<ValueNeighbor>(Hash, NeighborHash);
143+
Bitfield::set<ValuePred>(Hash, PredHash);
144+
Bitfield::set<ValueSucc>(Hash, SuccHash);
167145
return Hash;
168146
}
169147

@@ -175,7 +153,8 @@ struct BlendedBlockHash {
175153
"incorrect blended hash distance computation");
176154
uint64_t Dist = 0;
177155
// Account for NeighborHash
178-
Dist += NeighborHash == BBH.NeighborHash ? 0 : 1;
156+
Dist += SuccHash == BBH.SuccHash ? 0 : 1;
157+
Dist += PredHash == BBH.PredHash ? 0 : 1;
179158
Dist <<= 16;
180159
// Account for InstrHash
181160
Dist += InstrHash == BBH.InstrHash ? 0 : 1;
@@ -192,9 +171,10 @@ struct BlendedBlockHash {
192171
/// (Strong) Hash of the basic block instructions, including opcodes and
193172
/// operands.
194173
uint16_t InstrHash{0};
195-
/// Hash of the (loose) basic block together with (loose) hashes of its
196-
/// successors and predecessors.
197-
uint16_t NeighborHash{0};
174+
/// (Loose) Hashes of the predecessors of the basic block.
175+
uint8_t PredHash{0};
176+
/// (Loose) Hashes of the successors of the basic block.
177+
uint8_t SuccHash{0};
198178
};
199179

200180
/// The object is used to identify and match basic blocks in a BinaryFunction
@@ -252,41 +232,43 @@ void BinaryFunction::computeBlockHashes() const {
252232

253233
std::vector<BlendedBlockHash> BlendedHashes(BasicBlocks.size());
254234
std::vector<uint64_t> OpcodeHashes(BasicBlocks.size());
255-
// Initialize hash components
235+
// Initialize hash components.
256236
for (size_t I = 0; I < BasicBlocks.size(); I++) {
257237
const BinaryBasicBlock *BB = BasicBlocks[I];
258238
assert(BB->getIndex() == I && "incorrect block index");
259239
BlendedHashes[I].Offset = BB->getOffset();
260-
// Hashing complete instructions
240+
// Hashing complete instructions.
261241
std::string InstrHashStr = hashBlock(
262242
BC, *BB, [&](const MCOperand &Op) { return hashInstOperand(BC, Op); });
263243
uint64_t InstrHash = std::hash<std::string>{}(InstrHashStr);
264-
BlendedHashes[I].InstrHash = hash_64_to_16(InstrHash);
265-
// Hashing opcodes
266-
std::string OpcodeHashStr =
267-
hashBlock(BC, *BB, [](const MCOperand &Op) { return std::string(); });
244+
BlendedHashes[I].InstrHash = (uint16_t)hash_value(InstrHash);
245+
// Hashing opcodes.
246+
std::string OpcodeHashStr = hashBlockLoose(BC, *BB);
268247
OpcodeHashes[I] = std::hash<std::string>{}(OpcodeHashStr);
269-
BlendedHashes[I].OpcodeHash = hash_64_to_16(OpcodeHashes[I]);
248+
BlendedHashes[I].OpcodeHash = (uint16_t)hash_value(OpcodeHashes[I]);
270249
}
271250

272-
// Initialize neighbor hash
251+
// Initialize neighbor hash.
273252
for (size_t I = 0; I < BasicBlocks.size(); I++) {
274253
const BinaryBasicBlock *BB = BasicBlocks[I];
275-
uint64_t Hash = OpcodeHashes[I];
276-
// Append hashes of successors
254+
// Append hashes of successors.
255+
uint64_t Hash = 0;
277256
for (BinaryBasicBlock *SuccBB : BB->successors()) {
278257
uint64_t SuccHash = OpcodeHashes[SuccBB->getIndex()];
279258
Hash = hashing::detail::hash_16_bytes(Hash, SuccHash);
280259
}
281-
// Append hashes of predecessors
260+
BlendedHashes[I].SuccHash = (uint8_t)hash_value(Hash);
261+
262+
// Append hashes of predecessors.
263+
Hash = 0;
282264
for (BinaryBasicBlock *PredBB : BB->predecessors()) {
283265
uint64_t PredHash = OpcodeHashes[PredBB->getIndex()];
284266
Hash = hashing::detail::hash_16_bytes(Hash, PredHash);
285267
}
286-
BlendedHashes[I].NeighborHash = hash_64_to_16(Hash);
268+
BlendedHashes[I].PredHash = (uint8_t)hash_value(Hash);
287269
}
288270

289-
// Assign hashes
271+
// Assign hashes.
290272
for (size_t I = 0; I < BasicBlocks.size(); I++) {
291273
const BinaryBasicBlock *BB = BasicBlocks[I];
292274
BB->setHash(BlendedHashes[I].combine());
@@ -409,20 +391,22 @@ void matchWeightsByHashes(BinaryContext &BC,
409391
const FlowBlock *MatchedBlock = Matcher.matchBlock(YamlHash);
410392
if (MatchedBlock != nullptr) {
411393
MatchedBlocks[YamlBB.Index] = MatchedBlock;
412-
LLVM_DEBUG(dbgs() << "Matched yaml block with bid = " << YamlBB.Index
413-
<< " and hash = " << Twine::utohexstr(YamlBB.Hash)
414-
<< " to BB with index = " << MatchedBlock->Index - 1
394+
BlendedBlockHash BinHash = BlendedHashes[MatchedBlock->Index - 1];
395+
LLVM_DEBUG(dbgs() << "Matched yaml block (bid = " << YamlBB.Index << ")"
396+
<< " with hash " << Twine::utohexstr(YamlBB.Hash)
397+
<< " to BB (index = " << MatchedBlock->Index - 1 << ")"
398+
<< " with hash " << Twine::utohexstr(BinHash.combine())
415399
<< "\n");
416400
// Update matching stats accounting for the matched block.
417-
BlendedBlockHash BinHash = BlendedHashes[MatchedBlock->Index - 1];
418401
if (Matcher.isHighConfidenceMatch(BinHash, YamlHash)) {
419402
++BC.Stats.NumMatchedBlocks;
420403
BC.Stats.MatchedSampleCount += YamlBB.ExecCount;
404+
LLVM_DEBUG(dbgs() << " exact match\n");
421405
}
422406
} else {
423407
LLVM_DEBUG(
424-
dbgs() << "Couldn't match yaml block with bid = " << YamlBB.Index
425-
<< " and hash = " << Twine::utohexstr(YamlBB.Hash) << "\n");
408+
dbgs() << "Couldn't match yaml block (bid = " << YamlBB.Index << ")"
409+
<< " with hash " << Twine::utohexstr(YamlBB.Hash) << "\n");
426410
}
427411

428412
// Update matching stats.
@@ -575,16 +559,15 @@ void applyInference(FlowFunction &Func) {
575559
Params.JoinIslands = opts::StaleMatchingJoinIslands;
576560

577561
Params.CostBlockInc = opts::StaleMatchingCostBlockInc;
562+
Params.CostBlockEntryInc = opts::StaleMatchingCostBlockInc;
578563
Params.CostBlockDec = opts::StaleMatchingCostBlockDec;
579-
Params.CostBlockEntryInc = opts::StaleMatchingCostBlockEntryInc;
580-
Params.CostBlockEntryDec = opts::StaleMatchingCostBlockEntryDec;
581-
Params.CostBlockZeroInc = opts::StaleMatchingCostBlockZeroInc;
564+
Params.CostBlockEntryDec = opts::StaleMatchingCostBlockDec;
582565
Params.CostBlockUnknownInc = opts::StaleMatchingCostBlockUnknownInc;
583566

584567
Params.CostJumpInc = opts::StaleMatchingCostJumpInc;
585-
Params.CostJumpFTInc = opts::StaleMatchingCostJumpFTInc;
568+
Params.CostJumpFTInc = opts::StaleMatchingCostJumpInc;
586569
Params.CostJumpDec = opts::StaleMatchingCostJumpDec;
587-
Params.CostJumpFTDec = opts::StaleMatchingCostJumpFTDec;
570+
Params.CostJumpFTDec = opts::StaleMatchingCostJumpDec;
588571
Params.CostJumpUnknownInc = opts::StaleMatchingCostJumpUnknownInc;
589572
Params.CostJumpUnknownFTInc = opts::StaleMatchingCostJumpUnknownFTInc;
590573

bolt/test/X86/Inputs/blarge_profile_stale.yaml

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ header:
66
profile-flags: [ lbr ]
77
profile-origin: branch profile reader
88
profile-events: ''
9+
dfs-order: false
910
functions:
1011
- name: SolveCubic
1112
fid: 6
@@ -15,20 +16,24 @@ functions:
1516
blocks:
1617
- bid: 0
1718
insns: 43
18-
hash: 0xD2411AC186118199
19+
hash: 0xed4db287e71c0000
1920
exec: 151
20-
succ: [ { bid: 1, cnt: 4, mis: 2 }, { bid: 11, cnt: 0 } ]
21+
succ: [ { bid: 1, cnt: 151, mis: 2 }, { bid: 7, cnt: 0 } ]
2122
- bid: 1
2223
insns: 7
23-
hash: 0xDF0C9CC1FEAA70C3
24-
succ: [ { bid: 10, cnt: 0 }, { bid: 2, cnt: 0 } ]
24+
hash: 0x39330000e4560088
25+
succ: [ { bid: 13, cnt: 151 }, { bid: 2, cnt: 0 } ]
2526
- bid: 13
2627
insns: 26
27-
hash: 0xF05DC5524E99E56F
28-
succ: [ { bid: 15, cnt: 89 }, { bid: 14, cnt: 0 } ]
29-
- bid: 15
28+
hash: 0xa9700000fe202a7
29+
succ: [ { bid: 3, cnt: 89 }, { bid: 2, cnt: 10 } ]
30+
- bid: 3
31+
insns: 9
32+
hash: 0x62391dad18a700a0
33+
succ: [ { bid: 5, cnt: 151 } ]
34+
- bid: 5
3035
insns: 9
31-
hash: 0xB2E8338276A9834E
36+
hash: 0x4d906d19ecec0111
3237
- name: usqrt
3338
fid: 7
3439
hash: 0x8B62B1F9AD81EA35
@@ -37,15 +42,15 @@ functions:
3742
blocks:
3843
- bid: 0
3944
insns: 4
40-
hash: 0xb1e5b76571270000
45+
hash: 0x1111111111111111
4146
exec: 20
4247
succ: [ { bid: 1, cnt: 0 } ]
4348
- bid: 1
4449
insns: 9
45-
hash: 0x587e93788b970010
50+
hash: 0x27e43a5e10cd0010
4651
succ: [ { bid: 3, cnt: 320, mis: 171 }, { bid: 2, cnt: 0 } ]
4752
- bid: 3
4853
insns: 2
49-
hash: 0x20e605d745e50039
54+
hash: 0x4db935b6471e0039
5055
succ: [ { bid: 1, cnt: 300, mis: 33 }, { bid: 4, cnt: 20 } ]
5156
...

0 commit comments

Comments
 (0)