Skip to content

Commit 5954b9d

Browse files
authored
[InstrProf] Adding utility weights to BalancedPartitioning (#72717)
Adding weights to utility nodes in BP so that we can give more importance to certain utilities. This is useful when we optimize several objectives jointly.
1 parent 9175dd9 commit 5954b9d

File tree

5 files changed

+146
-49
lines changed

5 files changed

+146
-49
lines changed

llvm/include/llvm/Support/BalancedPartitioning.h

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,27 @@ class BPFunctionNode {
5757
friend class BalancedPartitioning;
5858

5959
public:
60+
/// The type of ID
6061
using IDT = uint64_t;
61-
using UtilityNodeT = uint32_t;
62+
/// The type of UtilityNode
63+
struct UtilityNodeT {
64+
UtilityNodeT(uint32_t Id, uint32_t Weight = 1) : Id(Id), Weight(Weight) {}
65+
uint32_t Id;
66+
uint32_t Weight;
67+
68+
// Deduplicate utility nodes for a given function.
69+
// TODO: One may experiment with accumulating the weights of duplicates.
70+
static void sortAndDeduplicate(SmallVector<UtilityNodeT, 4> &UNs) {
71+
llvm::sort(UNs, [](const UtilityNodeT &L, const UtilityNodeT &R) {
72+
return L.Id < R.Id;
73+
});
74+
UNs.erase(std::unique(UNs.begin(), UNs.end(),
75+
[](const UtilityNodeT &L, const UtilityNodeT &R) {
76+
return L.Id == R.Id;
77+
}),
78+
UNs.end());
79+
}
80+
};
6281

6382
/// \param UtilityNodes the set of utility nodes (must be unique'd)
6483
BPFunctionNode(IDT Id, ArrayRef<UtilityNodeT> UtilityNodes)
@@ -78,8 +97,7 @@ class BPFunctionNode {
7897
uint64_t InputOrderIndex = 0;
7998

8099
friend class BPFunctionNodeTest_Basic_Test;
81-
friend class BalancedPartitioningTest_Basic_Test;
82-
friend class BalancedPartitioningTest_Large_Test;
100+
friend class BalancedPartitioningTest;
83101
};
84102

85103
/// Algorithm parameters; default values are tuned on real-world binaries
@@ -188,6 +206,8 @@ class BalancedPartitioning {
188206
float CachedGainRL;
189207
/// Whether \p CachedGainLR and \p CachedGainRL are valid
190208
bool CachedGainIsValid = false;
209+
/// The weight of this utility node
210+
uint32_t Weight = 1;
191211
};
192212

193213
protected:

llvm/lib/ProfileData/InstrProf.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -923,15 +923,15 @@ std::vector<BPFunctionNode> TemporalProfTraceTy::createBPFunctionNodes(
923923

924924
const int N = Log2_64(LargestTraceSize) + 1;
925925

926-
// TODO: We need to use the Trace.Weight field to give more weight to more
926+
// TODO: We may use the Trace.Weight field to give more weight to more
927927
// important utilities
928928
DenseMap<IDT, SmallVector<UtilityNodeT, 4>> FuncGroups;
929-
for (size_t TraceIdx = 0; TraceIdx < Traces.size(); TraceIdx++) {
929+
for (uint32_t TraceIdx = 0; TraceIdx < Traces.size(); TraceIdx++) {
930930
auto &Trace = Traces[TraceIdx].FunctionNameRefs;
931931
for (size_t Timestamp = 0; Timestamp < Trace.size(); Timestamp++) {
932932
for (int I = Log2_64(Timestamp + 1); I < N; I++) {
933933
auto FunctionId = Trace[Timestamp];
934-
UtilityNodeT GroupId = TraceIdx * N + I;
934+
UtilityNodeT GroupId(TraceIdx * N + I);
935935
FuncGroups[FunctionId].push_back(GroupId);
936936
}
937937
}
@@ -940,8 +940,7 @@ std::vector<BPFunctionNode> TemporalProfTraceTy::createBPFunctionNodes(
940940
std::vector<BPFunctionNode> Nodes;
941941
for (auto Id : FunctionIds) {
942942
auto &UNs = FuncGroups[Id];
943-
llvm::sort(UNs);
944-
UNs.erase(std::unique(UNs.begin(), UNs.end()), UNs.end());
943+
UtilityNodeT::sortAndDeduplicate(UNs);
945944
Nodes.emplace_back(Id, UNs);
946945
}
947946
return Nodes;

llvm/lib/Support/BalancedPartitioning.cpp

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,13 @@ using namespace llvm;
2121
#define DEBUG_TYPE "balanced-partitioning"
2222

2323
void BPFunctionNode::dump(raw_ostream &OS) const {
24-
OS << formatv("{{ID={0} Utilities={{{1:$[,]}} Bucket={2}}", Id,
25-
make_range(UtilityNodes.begin(), UtilityNodes.end()), Bucket);
24+
OS << "{ID=" << Id << " Utilities={";
25+
for (auto &N : UtilityNodes)
26+
OS << N.Id << " ,";
27+
OS << "}";
28+
if (Bucket.has_value())
29+
OS << " Bucket=" << Bucket.value();
30+
OS << "}";
2631
}
2732

2833
template <typename Func>
@@ -166,34 +171,40 @@ void BalancedPartitioning::runIterations(const FunctionNodeRange Nodes,
166171
unsigned RecDepth, unsigned LeftBucket,
167172
unsigned RightBucket,
168173
std::mt19937 &RNG) const {
169-
unsigned NumNodes = std::distance(Nodes.begin(), Nodes.end());
170-
DenseMap<BPFunctionNode::UtilityNodeT, unsigned> UtilityNodeIndex;
174+
// Count the degree of each utility node.
175+
DenseMap<uint32_t, unsigned> UtilityNodeIndex;
171176
for (auto &N : Nodes)
172177
for (auto &UN : N.UtilityNodes)
173-
++UtilityNodeIndex[UN];
178+
++UtilityNodeIndex[UN.Id];
174179
// Remove utility nodes if they have just one edge or are connected to all
175-
// functions
180+
// functions.
181+
unsigned NumNodes = std::distance(Nodes.begin(), Nodes.end());
176182
for (auto &N : Nodes)
177183
llvm::erase_if(N.UtilityNodes, [&](auto &UN) {
178-
return UtilityNodeIndex[UN] == 1 || UtilityNodeIndex[UN] == NumNodes;
184+
return UtilityNodeIndex[UN.Id] == 1 ||
185+
UtilityNodeIndex[UN.Id] == NumNodes;
179186
});
180187

181-
// Renumber utility nodes so they can be used to index into Signatures
188+
// Renumber utility nodes so they can be used to index into Signatures.
182189
UtilityNodeIndex.clear();
183190
for (auto &N : Nodes)
184191
for (auto &UN : N.UtilityNodes)
185-
UN = UtilityNodeIndex.insert({UN, UtilityNodeIndex.size()}).first->second;
192+
UN.Id = UtilityNodeIndex.insert({UN.Id, UtilityNodeIndex.size()})
193+
.first->second;
186194

187-
// Initialize signatures
195+
// Initialize signatures.
188196
SignaturesT Signatures(/*Size=*/UtilityNodeIndex.size());
189197
for (auto &N : Nodes) {
190198
for (auto &UN : N.UtilityNodes) {
191-
assert(UN < Signatures.size());
192-
if (N.Bucket == LeftBucket) {
193-
Signatures[UN].LeftCount++;
194-
} else {
195-
Signatures[UN].RightCount++;
196-
}
199+
assert(UN.Id < Signatures.size());
200+
if (N.Bucket == LeftBucket)
201+
Signatures[UN.Id].LeftCount++;
202+
else
203+
Signatures[UN.Id].RightCount++;
204+
// Identical utility nodes (having the same UN.Id) have the same weight
205+
// (unless there are hash collisions mapping utilities to the same Id);
206+
// thus, we get a new weight only when the signature is uninitialized.
207+
Signatures[UN.Id].Weight = UN.Weight;
197208
}
198209
}
199210

@@ -221,9 +232,11 @@ unsigned BalancedPartitioning::runIteration(const FunctionNodeRange Nodes,
221232
Signature.CachedGainLR = 0.f;
222233
Signature.CachedGainRL = 0.f;
223234
if (L > 0)
224-
Signature.CachedGainLR = Cost - logCost(L - 1, R + 1);
235+
Signature.CachedGainLR =
236+
(Cost - logCost(L - 1, R + 1)) * Signature.Weight;
225237
if (R > 0)
226-
Signature.CachedGainRL = Cost - logCost(L + 1, R - 1);
238+
Signature.CachedGainRL =
239+
(Cost - logCost(L + 1, R - 1)) * Signature.Weight;
227240
Signature.CachedGainIsValid = true;
228241
}
229242

@@ -282,14 +295,14 @@ bool BalancedPartitioning::moveFunctionNode(BPFunctionNode &N,
282295
// Update signatures and invalidate gain cache
283296
if (FromLeftToRight) {
284297
for (auto &UN : N.UtilityNodes) {
285-
auto &Signature = Signatures[UN];
298+
auto &Signature = Signatures[UN.Id];
286299
Signature.LeftCount--;
287300
Signature.RightCount++;
288301
Signature.CachedGainIsValid = false;
289302
}
290303
} else {
291304
for (auto &UN : N.UtilityNodes) {
292-
auto &Signature = Signatures[UN];
305+
auto &Signature = Signatures[UN.Id];
293306
Signature.LeftCount++;
294307
Signature.RightCount--;
295308
Signature.CachedGainIsValid = false;
@@ -318,8 +331,8 @@ float BalancedPartitioning::moveGain(const BPFunctionNode &N,
318331
const SignaturesT &Signatures) {
319332
float Gain = 0.f;
320333
for (auto &UN : N.UtilityNodes)
321-
Gain += (FromLeftToRight ? Signatures[UN].CachedGainLR
322-
: Signatures[UN].CachedGainRL);
334+
Gain += (FromLeftToRight ? Signatures[UN.Id].CachedGainLR
335+
: Signatures[UN.Id].CachedGainRL);
323336
return Gain;
324337
}
325338

llvm/unittests/ProfileData/BPFunctionNodeTest.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
#include "gtest/gtest.h"
1414

1515
using testing::Field;
16+
using testing::Matcher;
1617
using testing::UnorderedElementsAre;
17-
using testing::UnorderedElementsAreArray;
1818

1919
namespace llvm {
2020

@@ -24,29 +24,35 @@ void PrintTo(const BPFunctionNode &Node, std::ostream *OS) {
2424
}
2525

2626
TEST(BPFunctionNodeTest, Basic) {
27+
auto UNIdsAre = [](auto... Ids) {
28+
return UnorderedElementsAre(Field("Id", &BPFunctionNode::UtilityNodeT::Id,
29+
std::forward<uint32_t>(Ids))...);
30+
};
2731
auto NodeIs = [](BPFunctionNode::IDT Id,
28-
ArrayRef<BPFunctionNode::UtilityNodeT> UNs) {
29-
return AllOf(Field("Id", &BPFunctionNode::Id, Id),
30-
Field("UtilityNodes", &BPFunctionNode::UtilityNodes,
31-
UnorderedElementsAreArray(UNs)));
32+
Matcher<ArrayRef<BPFunctionNode::UtilityNodeT>> UNsMatcher) {
33+
return AllOf(
34+
Field("Id", &BPFunctionNode::Id, Id),
35+
Field("UtilityNodes", &BPFunctionNode::UtilityNodes, UNsMatcher));
3236
};
3337

3438
auto Nodes = TemporalProfTraceTy::createBPFunctionNodes({
3539
TemporalProfTraceTy({0, 1, 2, 3}),
3640
});
37-
EXPECT_THAT(Nodes,
38-
UnorderedElementsAre(NodeIs(0, {0, 1, 2}), NodeIs(1, {1, 2}),
39-
NodeIs(2, {1, 2}), NodeIs(3, {2})));
41+
EXPECT_THAT(Nodes, UnorderedElementsAre(NodeIs(0, UNIdsAre(0, 1, 2)),
42+
NodeIs(1, UNIdsAre(1, 2)),
43+
NodeIs(2, UNIdsAre(1, 2)),
44+
NodeIs(3, UNIdsAre(2))));
4045

4146
Nodes = TemporalProfTraceTy::createBPFunctionNodes({
4247
TemporalProfTraceTy({0, 1, 2, 3, 4}),
4348
TemporalProfTraceTy({4, 2}),
4449
});
4550

46-
EXPECT_THAT(Nodes,
47-
UnorderedElementsAre(NodeIs(0, {0, 1, 2}), NodeIs(1, {1, 2}),
48-
NodeIs(2, {1, 2, 4, 5}), NodeIs(3, {2}),
49-
NodeIs(4, {2, 3, 4, 5})));
51+
EXPECT_THAT(Nodes, UnorderedElementsAre(NodeIs(0, UNIdsAre(0, 1, 2)),
52+
NodeIs(1, UNIdsAre(1, 2)),
53+
NodeIs(2, UNIdsAre(1, 2, 4, 5)),
54+
NodeIs(3, UNIdsAre(2)),
55+
NodeIs(4, UNIdsAre(2, 3, 4, 5))));
5056
}
5157

5258
} // end namespace llvm

llvm/unittests/Support/BalancedPartitioningTest.cpp

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,20 @@ class BalancedPartitioningTest : public ::testing::Test {
3737
Ids.push_back(N.Id);
3838
return Ids;
3939
}
40+
41+
static testing::Matcher<BPFunctionNode> NodeIdIs(BPFunctionNode::IDT Id) {
42+
return Field("Id", &BPFunctionNode::Id, Id);
43+
};
44+
45+
static testing::Matcher<BPFunctionNode>
46+
NodeBucketIs(std::optional<uint32_t> Bucket) {
47+
return Field("Bucket", &BPFunctionNode::Bucket, Bucket);
48+
};
49+
50+
static testing::Matcher<BPFunctionNode>
51+
NodeIs(BPFunctionNode::IDT Id, std::optional<uint32_t> Bucket) {
52+
return AllOf(NodeIdIs(Id), NodeBucketIs(Bucket));
53+
};
4054
};
4155

4256
TEST_F(BalancedPartitioningTest, Basic) {
@@ -48,11 +62,6 @@ TEST_F(BalancedPartitioningTest, Basic) {
4862

4963
Bp.run(Nodes);
5064

51-
auto NodeIs = [](BPFunctionNode::IDT Id, std::optional<uint32_t> Bucket) {
52-
return AllOf(Field("Id", &BPFunctionNode::Id, Id),
53-
Field("Bucket", &BPFunctionNode::Bucket, Bucket));
54-
};
55-
5665
EXPECT_THAT(Nodes,
5766
UnorderedElementsAre(NodeIs(0, 0), NodeIs(1, 1), NodeIs(2, 2),
5867
NodeIs(3, 3), NodeIs(4, 4)));
@@ -79,8 +88,7 @@ TEST_F(BalancedPartitioningTest, Large) {
7988

8089
Bp.run(Nodes);
8190

82-
EXPECT_THAT(
83-
Nodes, Each(Not(Field("Bucket", &BPFunctionNode::Bucket, std::nullopt))));
91+
EXPECT_THAT(Nodes, Each(Not(NodeBucketIs(std::nullopt))));
8492
EXPECT_THAT(getIds(Nodes), UnorderedElementsAreArray(OrigIds));
8593
}
8694

@@ -97,4 +105,55 @@ TEST_F(BalancedPartitioningTest, MoveGain) {
97105
30.f);
98106
}
99107

108+
TEST_F(BalancedPartitioningTest, Weight1) {
109+
std::vector<BPFunctionNode::UtilityNodeT> UNs = {
110+
BPFunctionNode::UtilityNodeT(0, 100),
111+
BPFunctionNode::UtilityNodeT(1, 100),
112+
BPFunctionNode::UtilityNodeT(2, 100),
113+
BPFunctionNode::UtilityNodeT(3, 1),
114+
BPFunctionNode::UtilityNodeT(4, 1),
115+
};
116+
std::vector<BPFunctionNode> Nodes = {
117+
BPFunctionNode(0, {UNs[0], UNs[3]}), BPFunctionNode(1, {UNs[1], UNs[3]}),
118+
BPFunctionNode(2, {UNs[2], UNs[3]}), BPFunctionNode(3, {UNs[0], UNs[4]}),
119+
BPFunctionNode(4, {UNs[1], UNs[4]}), BPFunctionNode(5, {UNs[2], UNs[4]}),
120+
};
121+
122+
Bp.run(Nodes);
123+
124+
// Check that nodes that share important UNs are ordered together
125+
auto NodesRef = ArrayRef(Nodes);
126+
auto Groups = {NodesRef.slice(0, 2), NodesRef.slice(2, 2),
127+
NodesRef.slice(4, 2)};
128+
EXPECT_THAT(Groups, UnorderedElementsAre(
129+
UnorderedElementsAre(NodeIdIs(0), NodeIdIs(3)),
130+
UnorderedElementsAre(NodeIdIs(1), NodeIdIs(4)),
131+
UnorderedElementsAre(NodeIdIs(2), NodeIdIs(5))));
132+
}
133+
134+
TEST_F(BalancedPartitioningTest, Weight2) {
135+
std::vector<BPFunctionNode::UtilityNodeT> UNs = {
136+
BPFunctionNode::UtilityNodeT(0, 1),
137+
BPFunctionNode::UtilityNodeT(1, 1),
138+
BPFunctionNode::UtilityNodeT(2, 1),
139+
BPFunctionNode::UtilityNodeT(3, 100),
140+
BPFunctionNode::UtilityNodeT(4, 100),
141+
};
142+
std::vector<BPFunctionNode> Nodes = {
143+
BPFunctionNode(0, {UNs[0], UNs[3]}), BPFunctionNode(1, {UNs[1], UNs[4]}),
144+
BPFunctionNode(2, {UNs[2], UNs[3]}), BPFunctionNode(3, {UNs[0], UNs[4]}),
145+
BPFunctionNode(4, {UNs[1], UNs[3]}), BPFunctionNode(5, {UNs[2], UNs[4]}),
146+
};
147+
148+
Bp.run(Nodes);
149+
150+
// Check that nodes that share important UNs are ordered together
151+
auto NodesRef = ArrayRef(Nodes);
152+
auto Groups = {NodesRef.slice(0, 3), NodesRef.slice(3, 3)};
153+
EXPECT_THAT(Groups,
154+
UnorderedElementsAre(
155+
UnorderedElementsAre(NodeIdIs(0), NodeIdIs(2), NodeIdIs(4)),
156+
UnorderedElementsAre(NodeIdIs(1), NodeIdIs(3), NodeIdIs(5))));
157+
}
158+
100159
} // end namespace llvm

0 commit comments

Comments
 (0)