@@ -122,15 +122,149 @@ void SampleProfileMatcher::findProfileAnchors(
122
122
}
123
123
}
124
124
125
+ MyersDiff::DiffResult
126
+ MyersDiff::shortestEdit (const std::vector<Anchor> &A,
127
+ const std::vector<Anchor> &B) const {
128
+ int32_t N = A.size (), M = B.size (), Max = N + M;
129
+ auto Index = [&](int32_t I) { return I + Max; };
130
+
131
+ DiffResult Diff;
132
+ if (Max == 0 )
133
+ return Diff;
134
+
135
+ // Backtrack the SES result.
136
+ auto Backtrack = [&](const std::vector<std::vector<int32_t >> &Trace,
137
+ const std::vector<Anchor> &A,
138
+ const std::vector<Anchor> &B) {
139
+ int32_t X = N, Y = M;
140
+ for (int32_t D = Trace.size () - 1 ; X > 0 || Y > 0 ; D--) {
141
+ const auto &P = Trace[D];
142
+ int32_t K = X - Y;
143
+ int32_t PrevK = K;
144
+ if (K == -D || (K != D && P[Index (K - 1 )] < P[Index (K + 1 )]))
145
+ PrevK = K + 1 ;
146
+ else
147
+ PrevK = K - 1 ;
148
+
149
+ int32_t PrevX = P[Index (PrevK)];
150
+ int32_t PrevY = PrevX - PrevK;
151
+ while (X > PrevX && Y > PrevY) {
152
+ X--;
153
+ Y--;
154
+ Diff.addEqualLocations (A[X].Loc , B[Y].Loc );
155
+ }
156
+
157
+ if (D == 0 )
158
+ break ;
159
+
160
+ if (Y == PrevY) {
161
+ X--;
162
+ Diff.addInsertion (A[X].Loc );
163
+ } else if (X == PrevX) {
164
+ Y--;
165
+ Diff.addDeletion (B[Y].Loc );
166
+ }
167
+ X = PrevX;
168
+ Y = PrevY;
169
+ }
170
+ };
171
+
172
+ // The greedy LCS/SES algorithm.
173
+ std::vector<int32_t > V (2 * Max + 1 , -1 );
174
+ V[Index (1 )] = 0 ;
175
+ std::vector<std::vector<int32_t >> Trace;
176
+ for (int32_t D = 0 ; D <= Max; D++) {
177
+ Trace.push_back (V);
178
+ for (int32_t K = -D; K <= D; K += 2 ) {
179
+ int32_t X = 0 , Y = 0 ;
180
+ if (K == -D || (K != D && V[Index (K - 1 )] < V[Index (K + 1 )]))
181
+ X = V[Index (K + 1 )];
182
+ else
183
+ X = V[Index (K - 1 )] + 1 ;
184
+ Y = X - K;
185
+ while (X < N && Y < M && A[X] == B[Y])
186
+ X++, Y++;
187
+
188
+ V[Index (K)] = X;
189
+
190
+ if (X >= N && Y >= M) {
191
+ // Length of an SES is D.
192
+ Backtrack (Trace, A, B);
193
+ return Diff;
194
+ }
195
+ }
196
+ }
197
+ // Length of an SES is greater than Max.
198
+ return Diff;
199
+ }
200
+
201
+ void SampleProfileMatcher::matchNonAnchorAndWriteResults (
202
+ const LocToLocMap &AnchorMatchings,
203
+ const std::map<LineLocation, StringRef> &IRAnchors,
204
+ LocToLocMap &IRToProfileLocationMap) {
205
+ auto InsertMatching = [&](const LineLocation &From, const LineLocation &To) {
206
+ // Skip the unchanged location mapping to save memory.
207
+ if (From != To)
208
+ IRToProfileLocationMap.insert ({From, To});
209
+ };
210
+
211
+ // Use function's beginning location as the initial anchor.
212
+ int32_t LocationDelta = 0 ;
213
+ SmallVector<LineLocation> LastMatchedNonAnchors;
214
+ for (const auto &IR : IRAnchors) {
215
+ const auto &Loc = IR.first ;
216
+ StringRef CalleeName = IR.second ;
217
+ bool IsMatchedAnchor = false ;
218
+
219
+ // Match the anchor location in lexical order.
220
+ auto R = AnchorMatchings.find (Loc);
221
+ if (R != AnchorMatchings.end ()) {
222
+ const auto &Candidate = R->second ;
223
+ InsertMatching (Loc, Candidate);
224
+ LLVM_DEBUG (dbgs () << " Callsite with callee:" << CalleeName
225
+ << " is matched from " << Loc << " to " << Candidate
226
+ << " \n " );
227
+ LocationDelta = Candidate.LineOffset - Loc.LineOffset ;
228
+
229
+ // Match backwards for non-anchor locations.
230
+ // The locations in LastMatchedNonAnchors have been matched forwards
231
+ // based on the previous anchor, spilt it evenly and overwrite the
232
+ // second half based on the current anchor.
233
+ for (size_t I = (LastMatchedNonAnchors.size () + 1 ) / 2 ;
234
+ I < LastMatchedNonAnchors.size (); I++) {
235
+ const auto &L = LastMatchedNonAnchors[I];
236
+ uint32_t CandidateLineOffset = L.LineOffset + LocationDelta;
237
+ LineLocation Candidate (CandidateLineOffset, L.Discriminator );
238
+ InsertMatching (L, Candidate);
239
+ LLVM_DEBUG (dbgs () << " Location is rematched backwards from " << L
240
+ << " to " << Candidate << " \n " );
241
+ }
242
+
243
+ IsMatchedAnchor = true ;
244
+ LastMatchedNonAnchors.clear ();
245
+ }
246
+
247
+ // Match forwards for non-anchor locations.
248
+ if (!IsMatchedAnchor) {
249
+ uint32_t CandidateLineOffset = Loc.LineOffset + LocationDelta;
250
+ LineLocation Candidate (CandidateLineOffset, Loc.Discriminator );
251
+ InsertMatching (Loc, Candidate);
252
+ LLVM_DEBUG (dbgs () << " Location is matched from " << Loc << " to "
253
+ << Candidate << " \n " );
254
+ LastMatchedNonAnchors.emplace_back (Loc);
255
+ }
256
+ }
257
+ }
258
+
125
259
// Call target name anchor based profile fuzzy matching.
126
260
// Input:
127
261
// For IR locations, the anchor is the callee name of direct callsite; For
128
262
// profile locations, it's the call target name for BodySamples or inlinee's
129
263
// profile name for CallsiteSamples.
130
264
// Matching heuristic:
131
- // First match all the anchors in lexical order , then split the non-anchor
132
- // locations between the two anchors evenly, first half are matched based on the
133
- // start anchor, second half are matched based on the end anchor.
265
+ // First match all the anchors using the diff algorithm , then split the
266
+ // non-anchor locations between the two anchors evenly, first half are matched
267
+ // based on the start anchor, second half are matched based on the end anchor.
134
268
// For example, given:
135
269
// IR locations: [1, 2(foo), 3, 5, 6(bar), 7]
136
270
// Profile locations: [1, 2, 3(foo), 4, 7, 8(bar), 9]
@@ -149,77 +283,40 @@ void SampleProfileMatcher::runStaleProfileMatching(
149
283
assert (IRToProfileLocationMap.empty () &&
150
284
" Run stale profile matching only once per function" );
151
285
152
- std::unordered_map<FunctionId, std::set<LineLocation>> CalleeToCallsitesMap ;
286
+ std::vector<Anchor> ProfileCallsiteAnchors ;
153
287
for (const auto &I : ProfileAnchors) {
154
288
const auto &Loc = I.first ;
155
289
const auto &Callees = I.second ;
156
290
// Filter out possible indirect calls, use direct callee name as anchor.
157
291
if (Callees.size () == 1 ) {
158
- FunctionId CalleeName = *Callees.begin ();
159
- const auto &Candidates = CalleeToCallsitesMap.try_emplace (
160
- CalleeName, std::set<LineLocation>());
161
- Candidates.first ->second .insert (Loc);
292
+ auto CalleeName = *Callees.begin ();
293
+ ProfileCallsiteAnchors.emplace_back (Loc, CalleeName);
294
+ } else if (Callees.size () > 1 ) {
295
+ ProfileCallsiteAnchors.emplace_back (Loc,
296
+ FunctionId (UnknownIndirectCallee));
162
297
}
163
298
}
164
299
165
- auto InsertMatching = [&](const LineLocation &From, const LineLocation &To) {
166
- // Skip the unchanged location mapping to save memory.
167
- if (From != To)
168
- IRToProfileLocationMap.insert ({From, To});
169
- };
170
-
171
- // Use function's beginning location as the initial anchor.
172
- int32_t LocationDelta = 0 ;
173
- SmallVector<LineLocation> LastMatchedNonAnchors;
300
+ std::vector<Anchor> IRCallsiteAnchors;
301
+ for (const auto &I : IRAnchors) {
302
+ const auto &Loc = I.first ;
303
+ const auto &CalleeName = I.second ;
304
+ if (CalleeName.empty ())
305
+ continue ;
306
+ IRCallsiteAnchors.emplace_back (Loc, FunctionId (CalleeName));
307
+ }
174
308
175
- for (const auto &IR : IRAnchors) {
176
- const auto &Loc = IR.first ;
177
- auto CalleeName = IR.second ;
178
- bool IsMatchedAnchor = false ;
179
- // Match the anchor location in lexical order.
180
- if (!CalleeName.empty ()) {
181
- auto CandidateAnchors =
182
- CalleeToCallsitesMap.find (getRepInFormat (CalleeName));
183
- if (CandidateAnchors != CalleeToCallsitesMap.end () &&
184
- !CandidateAnchors->second .empty ()) {
185
- auto CI = CandidateAnchors->second .begin ();
186
- const auto Candidate = *CI;
187
- CandidateAnchors->second .erase (CI);
188
- InsertMatching (Loc, Candidate);
189
- LLVM_DEBUG (dbgs () << " Callsite with callee:" << CalleeName
190
- << " is matched from " << Loc << " to " << Candidate
191
- << " \n " );
192
- LocationDelta = Candidate.LineOffset - Loc.LineOffset ;
193
-
194
- // Match backwards for non-anchor locations.
195
- // The locations in LastMatchedNonAnchors have been matched forwards
196
- // based on the previous anchor, spilt it evenly and overwrite the
197
- // second half based on the current anchor.
198
- for (size_t I = (LastMatchedNonAnchors.size () + 1 ) / 2 ;
199
- I < LastMatchedNonAnchors.size (); I++) {
200
- const auto &L = LastMatchedNonAnchors[I];
201
- uint32_t CandidateLineOffset = L.LineOffset + LocationDelta;
202
- LineLocation Candidate (CandidateLineOffset, L.Discriminator );
203
- InsertMatching (L, Candidate);
204
- LLVM_DEBUG (dbgs () << " Location is rematched backwards from " << L
205
- << " to " << Candidate << " \n " );
206
- }
309
+ if (IRCallsiteAnchors.empty () || ProfileCallsiteAnchors.empty ())
310
+ return ;
207
311
208
- IsMatchedAnchor = true ;
209
- LastMatchedNonAnchors.clear ();
210
- }
211
- }
312
+ // Use the diff algorithm to find the SES, the resulting equal locations from
313
+ // IR to Profile are used as anchor to match other locations. Note that here
314
+ // use IR anchor as base(A) to align with the order of IRToProfileLocationMap.
315
+ MyersDiff Diff;
316
+ auto DiffRes = Diff.shortestEdit (IRCallsiteAnchors, ProfileCallsiteAnchors);
212
317
213
- // Match forwards for non-anchor locations.
214
- if (!IsMatchedAnchor) {
215
- uint32_t CandidateLineOffset = Loc.LineOffset + LocationDelta;
216
- LineLocation Candidate (CandidateLineOffset, Loc.Discriminator );
217
- InsertMatching (Loc, Candidate);
218
- LLVM_DEBUG (dbgs () << " Location is matched from " << Loc << " to "
219
- << Candidate << " \n " );
220
- LastMatchedNonAnchors.emplace_back (Loc);
221
- }
222
- }
318
+ matchNonAnchorAndWriteResults (DiffRes.EqualLocations , IRAnchors,
319
+ IRToProfileLocationMap);
223
320
}
224
321
225
322
void SampleProfileMatcher::runOnFunction (Function &F) {
0 commit comments