21
21
using namespace llvm ;
22
22
using namespace lld ::macho;
23
23
24
+ using UtilityNodes = SmallVector<BPFunctionNode::UtilityNodeT>;
25
+
24
26
// / Symbols can be appended with "(.__uniq.xxxx)?.llvm.yyyy" where "xxxx" and
25
27
// / "yyyy" are numbers that could change between builds. We need to use the root
26
28
// / symbol name before this suffix so these symbols can be matched with profiles
@@ -60,12 +62,15 @@ getRelocHash(const Reloc &reloc,
60
62
return getRelocHash (kind, sectionIdx.value_or (0 ), 0 , reloc.addend );
61
63
}
62
64
63
- static void constructNodesForCompression (
64
- const SmallVector<const InputSection *> §ions,
65
+ // / Given \p sectionIdxs, a list of section indexes, return a list of utility
66
+ // / nodes for each section index. If \p duplicateSectionIdx is provided,
67
+ // / populate it with nearly identical sections. Increment \p maxUN to be the
68
+ // / largest utility node we have used so far.
69
+ static SmallVector<std::pair<unsigned , UtilityNodes>> getUnsForCompression (
70
+ ArrayRef<const InputSection *> sections,
65
71
const DenseMap<const InputSection *, uint64_t > §ionToIdx,
66
- const SmallVector<unsigned > §ionIdxs,
67
- std::vector<BPFunctionNode> &nodes,
68
- DenseMap<unsigned , SmallVector<unsigned >> &duplicateSectionIdxs,
72
+ ArrayRef<unsigned > sectionIdxs,
73
+ DenseMap<unsigned , SmallVector<unsigned >> *duplicateSectionIdxs,
69
74
BPFunctionNode::UtilityNodeT &maxUN) {
70
75
TimeTraceScope timeScope (" Build nodes for compression" );
71
76
@@ -103,49 +108,52 @@ static void constructNodesForCompression(
103
108
for (auto hash : hashes)
104
109
++hashFrequency[hash];
105
110
106
- // Merge section that are nearly identical
107
- SmallVector<std::pair<unsigned , SmallVector<uint64_t >>> newSectionHashes;
108
- DenseMap<uint64_t , unsigned > wholeHashToSectionIdx;
109
- for (auto &[sectionIdx, hashes] : sectionHashes) {
110
- uint64_t wholeHash = 0 ;
111
- for (auto hash : hashes)
112
- if (hashFrequency[hash] > 5 )
113
- wholeHash ^= hash;
114
- auto [it, wasInserted] =
115
- wholeHashToSectionIdx.insert (std::make_pair (wholeHash, sectionIdx));
116
- if (wasInserted) {
117
- newSectionHashes.emplace_back (sectionIdx, hashes);
118
- } else {
119
- duplicateSectionIdxs[it->getSecond ()].push_back (sectionIdx);
111
+ if (duplicateSectionIdxs) {
112
+ // Merge section that are nearly identical
113
+ SmallVector<std::pair<unsigned , SmallVector<uint64_t >>> newSectionHashes;
114
+ DenseMap<uint64_t , unsigned > wholeHashToSectionIdx;
115
+ for (auto &[sectionIdx, hashes] : sectionHashes) {
116
+ uint64_t wholeHash = 0 ;
117
+ for (auto hash : hashes)
118
+ if (hashFrequency[hash] > 5 )
119
+ wholeHash ^= hash;
120
+ auto [it, wasInserted] =
121
+ wholeHashToSectionIdx.insert (std::make_pair (wholeHash, sectionIdx));
122
+ if (wasInserted) {
123
+ newSectionHashes.emplace_back (sectionIdx, hashes);
124
+ } else {
125
+ (*duplicateSectionIdxs)[it->getSecond ()].push_back (sectionIdx);
126
+ }
120
127
}
121
- }
122
- sectionHashes = newSectionHashes;
128
+ sectionHashes = newSectionHashes;
123
129
124
- // Recompute hash frequencies
125
- hashFrequency.clear ();
126
- for (auto &[sectionIdx, hashes] : sectionHashes)
127
- for (auto hash : hashes)
128
- ++hashFrequency[hash];
130
+ // Recompute hash frequencies
131
+ hashFrequency.clear ();
132
+ for (auto &[sectionIdx, hashes] : sectionHashes)
133
+ for (auto hash : hashes)
134
+ ++hashFrequency[hash];
135
+ }
129
136
130
137
// Filter rare and common hashes and assign each a unique utility node that
131
138
// doesn't conflict with the trace utility nodes
132
139
DenseMap<uint64_t , BPFunctionNode::UtilityNodeT> hashToUN;
133
140
for (auto &[hash, frequency] : hashFrequency) {
134
- if (frequency <= 1 || frequency * 2 > wholeHashToSectionIdx .size ())
141
+ if (frequency <= 1 || frequency * 2 > sectionHashes .size ())
135
142
continue ;
136
143
hashToUN[hash] = ++maxUN;
137
144
}
138
145
139
- std::vector<BPFunctionNode::UtilityNodeT> uns ;
146
+ SmallVector< std::pair< unsigned , UtilityNodes>> sectionUns ;
140
147
for (auto &[sectionIdx, hashes] : sectionHashes) {
148
+ UtilityNodes uns;
141
149
for (auto &hash : hashes) {
142
150
auto it = hashToUN.find (hash);
143
151
if (it != hashToUN.end ())
144
152
uns.push_back (it->second );
145
153
}
146
- nodes.emplace_back (sectionIdx, uns);
147
- uns.clear ();
154
+ sectionUns.emplace_back (sectionIdx, uns);
148
155
}
156
+ return sectionUns;
149
157
}
150
158
151
159
DenseMap<const InputSection *, size_t > lld::macho::runBalancedPartitioning (
@@ -185,10 +193,10 @@ DenseMap<const InputSection *, size_t> lld::macho::runBalancedPartitioning(
185
193
sectionIdxs.end ());
186
194
}
187
195
188
- std::vector<BPFunctionNode> nodesForStartup;
189
196
BPFunctionNode::UtilityNodeT maxUN = 0 ;
190
- DenseMap<unsigned , SmallVector<BPFunctionNode::UtilityNodeT>>
191
- startupSectionIdxUNs;
197
+ DenseMap<unsigned , UtilityNodes> startupSectionIdxUNs;
198
+ // Used to define the initial order for startup functions.
199
+ DenseMap<unsigned , size_t > sectionIdxToTimestamp;
192
200
std::unique_ptr<InstrProfReader> reader;
193
201
if (!profilePath.empty ()) {
194
202
auto fs = vfs::getRealFileSystem ();
@@ -202,8 +210,6 @@ DenseMap<const InputSection *, size_t> lld::macho::runBalancedPartitioning(
202
210
}
203
211
auto &traces = reader->getTemporalProfTraces ();
204
212
205
- // Used to define the initial order for startup functions.
206
- DenseMap<unsigned , size_t > sectionIdxToTimestamp;
207
213
DenseMap<unsigned , BPFunctionNode::UtilityNodeT> sectionIdxToFirstUN;
208
214
for (size_t traceIdx = 0 ; traceIdx < traces.size (); traceIdx++) {
209
215
uint64_t currentSize = 0 , cutoffSize = 1 ;
@@ -245,15 +251,6 @@ DenseMap<const InputSection *, size_t> lld::macho::runBalancedPartitioning(
245
251
++maxUN;
246
252
sectionIdxToFirstUN.clear ();
247
253
}
248
-
249
- // These uns should already be sorted without duplicates.
250
- for (auto &[sectionIdx, uns] : startupSectionIdxUNs)
251
- nodesForStartup.emplace_back (sectionIdx, uns);
252
-
253
- llvm::sort (nodesForStartup, [§ionIdxToTimestamp](auto &L, auto &R) {
254
- return std::make_pair (sectionIdxToTimestamp[L.Id ], L.Id ) <
255
- std::make_pair (sectionIdxToTimestamp[R.Id ], R.Id );
256
- });
257
254
}
258
255
259
256
SmallVector<unsigned > sectionIdxsForFunctionCompression,
@@ -271,21 +268,32 @@ DenseMap<const InputSection *, size_t> lld::macho::runBalancedPartitioning(
271
268
}
272
269
}
273
270
274
- std::vector<BPFunctionNode> nodesForFunctionCompression,
275
- nodesForDataCompression;
276
271
// Map a section index (to be ordered for compression) to a list of duplicate
277
272
// section indices (not ordered for compression).
278
- DenseMap<unsigned , SmallVector<unsigned >> duplicateFunctionSectionIdxs,
279
- duplicateDataSectionIdxs;
280
- constructNodesForCompression (
273
+ DenseMap<unsigned , SmallVector<unsigned >> duplicateSectionIdxs;
274
+ auto unsForFunctionCompression = getUnsForCompression (
281
275
sections, sectionToIdx, sectionIdxsForFunctionCompression,
282
- nodesForFunctionCompression, duplicateFunctionSectionIdxs , maxUN);
283
- constructNodesForCompression (
276
+ &duplicateSectionIdxs , maxUN);
277
+ auto unsForDataCompression = getUnsForCompression (
284
278
sections, sectionToIdx, sectionIdxsForDataCompression,
285
- nodesForDataCompression, duplicateDataSectionIdxs , maxUN);
279
+ &duplicateSectionIdxs , maxUN);
286
280
287
- // Sort nodes by their Id (which is the section index) because the input
288
- // linker order tends to be not bad
281
+ std::vector<BPFunctionNode> nodesForStartup, nodesForFunctionCompression,
282
+ nodesForDataCompression;
283
+ for (auto &[sectionIdx, uns] : startupSectionIdxUNs)
284
+ nodesForStartup.emplace_back (sectionIdx, uns);
285
+ for (auto &[sectionIdx, uns] : unsForFunctionCompression)
286
+ nodesForFunctionCompression.emplace_back (sectionIdx, uns);
287
+ for (auto &[sectionIdx, uns] : unsForDataCompression)
288
+ nodesForDataCompression.emplace_back (sectionIdx, uns);
289
+
290
+ // Use the first timestamp to define the initial order for startup nodes.
291
+ llvm::sort (nodesForStartup, [§ionIdxToTimestamp](auto &L, auto &R) {
292
+ return std::make_pair (sectionIdxToTimestamp[L.Id ], L.Id ) <
293
+ std::make_pair (sectionIdxToTimestamp[R.Id ], R.Id );
294
+ });
295
+ // Sort compression nodes by their Id (which is the section index) because the
296
+ // input linker order tends to be not bad.
289
297
llvm::sort (nodesForFunctionCompression,
290
298
[](auto &L, auto &R) { return L.Id < R.Id ; });
291
299
llvm::sort (nodesForDataCompression,
@@ -318,8 +326,8 @@ DenseMap<const InputSection *, size_t> lld::macho::runBalancedPartitioning(
318
326
if (orderedSections.insert (isec))
319
327
++numCodeCompressionSections;
320
328
321
- auto It = duplicateFunctionSectionIdxs .find (node.Id );
322
- if (It == duplicateFunctionSectionIdxs .end ())
329
+ auto It = duplicateSectionIdxs .find (node.Id );
330
+ if (It == duplicateSectionIdxs .end ())
323
331
continue ;
324
332
for (auto dupSecIdx : It->getSecond ()) {
325
333
const auto *dupIsec = sections[dupSecIdx];
@@ -332,8 +340,8 @@ DenseMap<const InputSection *, size_t> lld::macho::runBalancedPartitioning(
332
340
const auto *isec = sections[node.Id ];
333
341
if (orderedSections.insert (isec))
334
342
++numDataCompressionSections;
335
- auto It = duplicateDataSectionIdxs .find (node.Id );
336
- if (It == duplicateDataSectionIdxs .end ())
343
+ auto It = duplicateSectionIdxs .find (node.Id );
344
+ if (It == duplicateSectionIdxs .end ())
337
345
continue ;
338
346
for (auto dupSecIdx : It->getSecond ()) {
339
347
const auto *dupIsec = sections[dupSecIdx];
0 commit comments