LLVM 23.0.0git
SampleProfileMatcher.cpp
Go to the documentation of this file.
1//===- SampleProfileMatcher.cpp - Sampling-based Stale Profile Matcher ----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the SampleProfileMatcher used for stale
10// profile matching.
11//
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/Statistic.h"
18#include "llvm/IR/MDBuilder.h"
21
22using namespace llvm;
23using namespace sampleprof;
24
25#define DEBUG_TYPE "sample-profile-matcher"
26
27STATISTIC(NumDirectProfileMatch,
28 "Number of functions matched by demangled basename");
29
30namespace llvm {
31
33 "func-profile-similarity-threshold", cl::Hidden, cl::init(80),
34 cl::desc("Consider a profile matches a function if the similarity of their "
35 "callee sequences is above the specified percentile."));
36
38 "min-func-count-for-cg-matching", cl::Hidden, cl::init(5),
39 cl::desc("The minimum number of basic blocks required for a function to "
40 "run stale profile call graph matching."));
41
43 "min-call-count-for-cg-matching", cl::Hidden, cl::init(3),
44 cl::desc("The minimum number of call anchors required for a function to "
45 "run stale profile call graph matching."));
46
48 "load-func-profile-for-cg-matching", cl::Hidden, cl::init(true),
50 "Load top-level profiles that the sample reader initially skipped for "
51 "the call-graph matching (only meaningful for extended binary "
52 "format)"));
53
58
60 "salvage-unused-profile-max-functions", cl::Hidden, cl::init(UINT_MAX),
61 cl::desc("The maximum number of functions in a module, above which salvage "
62 "unused profile will be skipped."));
63
65 "salvage-stale-profile-max-callsites", cl::Hidden, cl::init(UINT_MAX),
66 cl::desc("The maximum number of callsites in a function, above which stale "
67 "profile matching will be skipped."));
68
69} // end namespace llvm
70
71void SampleProfileMatcher::findIRAnchors(const Function &F,
72 AnchorMap &IRAnchors) const {
73 // For inlined code, recover the original callsite and callee by finding the
74 // top-level inline frame. e.g. For frame stack "main:1 @ foo:2 @ bar:3", the
75 // top-level frame is "main:1", the callsite is "1" and the callee is "foo".
76 auto FindTopLevelInlinedCallsite = [](const DILocation *DIL) {
77 assert((DIL && DIL->getInlinedAt()) && "No inlined callsite");
78 const DILocation *PrevDIL = nullptr;
79 do {
80 PrevDIL = DIL;
81 DIL = DIL->getInlinedAt();
82 } while (DIL->getInlinedAt());
83
84 LineLocation Callsite = FunctionSamples::getCallSiteIdentifier(
86 StringRef CalleeName = PrevDIL->getSubprogramLinkageName();
87 return std::make_pair(Callsite, FunctionId(CalleeName));
88 };
89
90 auto GetCanonicalCalleeName = [](const CallBase *CB) {
91 StringRef CalleeName = UnknownIndirectCallee;
92 if (Function *Callee = CB->getCalledFunction())
93 CalleeName = FunctionSamples::getCanonicalFnName(Callee->getName());
94 return CalleeName;
95 };
96
97 // Extract profile matching anchors in the IR.
98 for (auto &BB : F) {
99 for (auto &I : BB) {
100 DILocation *DIL = I.getDebugLoc();
101 if (!DIL)
102 continue;
103
105 if (auto Probe = extractProbe(I)) {
106 // Flatten inlined IR for the matching.
107 if (DIL->getInlinedAt()) {
108 IRAnchors.emplace(FindTopLevelInlinedCallsite(DIL));
109 } else {
110 // Use empty StringRef for basic block probe.
111 StringRef CalleeName;
112 if (const auto *CB = dyn_cast<CallBase>(&I)) {
113 // Skip the probe inst whose callee name is "llvm.pseudoprobe".
114 if (!isa<IntrinsicInst>(&I))
115 CalleeName = GetCanonicalCalleeName(CB);
116 }
117 LineLocation Loc = LineLocation(Probe->Id, 0);
118 IRAnchors.emplace(Loc, FunctionId(CalleeName));
119 }
120 }
121 } else {
122 // TODO: For line-number based profile(AutoFDO), currently only support
123 // find callsite anchors. In future, we need to parse all the non-call
124 // instructions to extract the line locations for profile matching.
126 continue;
127
128 if (DIL->getInlinedAt()) {
129 IRAnchors.emplace(FindTopLevelInlinedCallsite(DIL));
130 } else {
131 LineLocation Callsite = FunctionSamples::getCallSiteIdentifier(
133 StringRef CalleeName = GetCanonicalCalleeName(dyn_cast<CallBase>(&I));
134 IRAnchors.emplace(Callsite, FunctionId(CalleeName));
135 }
136 }
137 }
138 }
139}
140
141void SampleProfileMatcher::findProfileAnchors(const FunctionSamples &FS,
142 AnchorMap &ProfileAnchors) const {
143 auto isInvalidLineOffset = [](uint32_t LineOffset) {
144 return LineOffset & 0x8000;
145 };
146
147 auto InsertAnchor = [](const LineLocation &Loc, const FunctionId &CalleeName,
148 AnchorMap &ProfileAnchors) {
149 auto Ret = ProfileAnchors.try_emplace(Loc, CalleeName);
150 if (!Ret.second) {
151 // For multiple callees, which indicates it's an indirect call, we use a
152 // dummy name(UnknownIndirectCallee) as the indrect callee name.
153 Ret.first->second = FunctionId(UnknownIndirectCallee);
154 }
155 };
156
157 for (const auto &I : FS.getBodySamples()) {
158 const LineLocation &Loc = I.first;
159 if (isInvalidLineOffset(Loc.LineOffset))
160 continue;
161 for (const auto &C : I.second.getCallTargets())
162 InsertAnchor(Loc, C.first, ProfileAnchors);
163 }
164
165 for (const auto &I : FS.getCallsiteSamples()) {
166 const LineLocation &Loc = I.first;
167 if (isInvalidLineOffset(Loc.LineOffset))
168 continue;
169 for (const auto &C : I.second)
170 InsertAnchor(Loc, C.first, ProfileAnchors);
171 }
172}
173
174bool SampleProfileMatcher::functionHasProfile(const FunctionId &IRFuncName,
175 Function *&FuncWithoutProfile) {
176 FuncWithoutProfile = nullptr;
177 auto R = FunctionsWithoutProfile.find(IRFuncName);
178 if (R != FunctionsWithoutProfile.end())
179 FuncWithoutProfile = R->second;
180 return !FuncWithoutProfile;
181}
182
183bool SampleProfileMatcher::isProfileUnused(const FunctionId &ProfileFuncName) {
184 // In post-link, the profiled function may have been optimized away from the
185 // module. Check if the function name exists in the pseudo_probe descriptors.
186 return (SymbolMap->find(ProfileFuncName) == SymbolMap->end()) &&
189 !ProfileFuncName.isStringRef() ||
190 (ProbeManager->getDesc(ProfileFuncName.stringRef()) == nullptr));
191}
192
193bool SampleProfileMatcher::functionMatchesProfile(
194 const FunctionId &IRFuncName, const FunctionId &ProfileFuncName,
195 bool FindMatchedProfileOnly) {
196 if (IRFuncName == ProfileFuncName)
197 return true;
199 return false;
200
201 // If IR function doesn't have profile and the profile is unused, try
202 // matching them.
203 Function *IRFunc = nullptr;
204 if (functionHasProfile(IRFuncName, IRFunc) ||
205 !isProfileUnused(ProfileFuncName))
206 return false;
207
208 assert(FunctionId(IRFunc->getName()) != ProfileFuncName &&
209 "IR function should be different from profile function to match");
210 return functionMatchesProfile(*IRFunc, ProfileFuncName,
211 FindMatchedProfileOnly);
212}
213
215SampleProfileMatcher::longestCommonSequence(const AnchorList &AnchorList1,
216 const AnchorList &AnchorList2,
217 bool MatchUnusedFunction) {
218 LocToLocMap MatchedAnchors;
220 AnchorList1, AnchorList2,
221 [&](const FunctionId &A, const FunctionId &B) {
222 return functionMatchesProfile(
223 A, B,
224 !MatchUnusedFunction // Find matched function only
225 );
226 },
227 [&](LineLocation A, LineLocation B) {
228 MatchedAnchors.try_emplace(A, B);
229 });
230 return MatchedAnchors;
231}
232
233void SampleProfileMatcher::matchNonCallsiteLocs(
234 const LocToLocMap &MatchedAnchors, const AnchorMap &IRAnchors,
235 LocToLocMap &IRToProfileLocationMap) {
236 auto UpdateMatching = [&](const LineLocation &From, const LineLocation &To) {
237 // Skip the unchanged location mapping to save memory.
238 if (From != To)
239 IRToProfileLocationMap.insert_or_assign(From, To);
240 else
241 IRToProfileLocationMap.erase(From);
242 };
243
244 // Use function's beginning location as the initial anchor.
245 int32_t LocationDelta = 0;
246 SmallVector<LineLocation> LastMatchedNonAnchors;
247 for (const auto &IR : IRAnchors) {
248 const auto &Loc = IR.first;
249 bool IsMatchedAnchor = false;
250 // Match the anchor location in lexical order.
251 auto R = MatchedAnchors.find(Loc);
252 if (R != MatchedAnchors.end()) {
253 const auto &Candidate = R->second;
254 UpdateMatching(Loc, Candidate);
255 LLVM_DEBUG(dbgs() << "Callsite with callee:" << IR.second.stringRef()
256 << " is matched from " << Loc << " to " << Candidate
257 << "\n");
258 LocationDelta = Candidate.LineOffset - Loc.LineOffset;
259
260 // Match backwards for non-anchor locations.
261 // The locations in LastMatchedNonAnchors have been matched forwards
262 // based on the previous anchor, split it evenly and overwrite the
263 // second half based on the current anchor.
264 for (size_t I = (LastMatchedNonAnchors.size() + 1) / 2;
265 I < LastMatchedNonAnchors.size(); I++) {
266 const auto &L = LastMatchedNonAnchors[I];
267 uint32_t CandidateLineOffset = L.LineOffset + LocationDelta;
268 LineLocation Candidate(CandidateLineOffset, L.Discriminator);
269 UpdateMatching(L, Candidate);
270 LLVM_DEBUG(dbgs() << "Location is rematched backwards from " << L
271 << " to " << Candidate << "\n");
272 }
273
274 IsMatchedAnchor = true;
275 LastMatchedNonAnchors.clear();
276 }
277
278 // Match forwards for non-anchor locations.
279 if (!IsMatchedAnchor) {
280 uint32_t CandidateLineOffset = Loc.LineOffset + LocationDelta;
281 LineLocation Candidate(CandidateLineOffset, Loc.Discriminator);
282 UpdateMatching(Loc, Candidate);
283 LLVM_DEBUG(dbgs() << "Location is matched from " << Loc << " to "
284 << Candidate << "\n");
285 LastMatchedNonAnchors.emplace_back(Loc);
286 }
287 }
288}
289
290// Filter the non-call locations from IRAnchors and ProfileAnchors and write
291// them into a list for random access later.
292void SampleProfileMatcher::getFilteredAnchorList(
293 const AnchorMap &IRAnchors, const AnchorMap &ProfileAnchors,
294 AnchorList &FilteredIRAnchorsList, AnchorList &FilteredProfileAnchorList) {
295 for (const auto &I : IRAnchors) {
296 if (I.second.stringRef().empty())
297 continue;
298 FilteredIRAnchorsList.emplace_back(I);
299 }
300
301 for (const auto &I : ProfileAnchors)
302 FilteredProfileAnchorList.emplace_back(I);
303}
304
305// Call target name anchor based profile fuzzy matching.
306// Input:
307// For IR locations, the anchor is the callee name of direct callsite; For
308// profile locations, it's the call target name for BodySamples or inlinee's
309// profile name for CallsiteSamples.
310// Matching heuristic:
311// First match all the anchors using the diff algorithm, then split the
312// non-anchor locations between the two anchors evenly, first half are matched
313// based on the start anchor, second half are matched based on the end anchor.
314// For example, given:
315// IR locations: [1, 2(foo), 3, 5, 6(bar), 7]
316// Profile locations: [1, 2, 3(foo), 4, 7, 8(bar), 9]
317// The matching gives:
318// [1, 2(foo), 3, 5, 6(bar), 7]
319// | | | | | |
320// [1, 2, 3(foo), 4, 7, 8(bar), 9]
321// The output mapping: [2->3, 3->4, 5->7, 6->8, 7->9].
322void SampleProfileMatcher::runStaleProfileMatching(
323 const Function &F, const AnchorMap &IRAnchors,
324 const AnchorMap &ProfileAnchors, LocToLocMap &IRToProfileLocationMap,
325 bool RunCFGMatching, bool RunCGMatching) {
326 if (!RunCFGMatching && !RunCGMatching)
327 return;
328 LLVM_DEBUG(dbgs() << "Run stale profile matching for " << F.getName()
329 << "\n");
330 assert(IRToProfileLocationMap.empty() &&
331 "Run stale profile matching only once per function");
332
333 AnchorList FilteredProfileAnchorList;
334 AnchorList FilteredIRAnchorsList;
335 getFilteredAnchorList(IRAnchors, ProfileAnchors, FilteredIRAnchorsList,
336 FilteredProfileAnchorList);
337
338 if (FilteredIRAnchorsList.empty() || FilteredProfileAnchorList.empty())
339 return;
340
341 if (FilteredIRAnchorsList.size() > SalvageStaleProfileMaxCallsites ||
342 FilteredProfileAnchorList.size() > SalvageStaleProfileMaxCallsites) {
343 LLVM_DEBUG(dbgs() << "Skip stale profile matching for " << F.getName()
344 << " because the number of callsites in the IR is "
345 << FilteredIRAnchorsList.size()
346 << " and in the profile is "
347 << FilteredProfileAnchorList.size() << "\n");
348 return;
349 }
350
351 // Match the callsite anchors by finding the longest common subsequence
352 // between IR and profile.
353 // Define a match between two anchors as follows:
354 // 1) The function names of anchors are the same.
355 // 2) The similarity between the anchor functions is above a threshold if
356 // RunCGMatching is set.
357 // For 2), we only consider the anchor functions from IR and profile don't
358 // appear on either side to reduce the matching scope. Note that we need to
359 // use IR anchor as base(A side) to align with the order of
360 // IRToProfileLocationMap.
361 LocToLocMap MatchedAnchors =
362 longestCommonSequence(FilteredIRAnchorsList, FilteredProfileAnchorList,
363 RunCGMatching /* Match unused functions */);
364
365 // CFG level matching:
366 // Apply the callsite matchings to infer matching for the basic
367 // block(non-callsite) locations and write the result to
368 // IRToProfileLocationMap.
369 if (RunCFGMatching)
370 matchNonCallsiteLocs(MatchedAnchors, IRAnchors, IRToProfileLocationMap);
371}
372
373void SampleProfileMatcher::runOnFunction(Function &F) {
374 // We need to use flattened function samples for matching.
375 // Unlike IR, which includes all callsites from the source code, the callsites
376 // in profile only show up when they are hit by samples, i,e. the profile
377 // callsites in one context may differ from those in another context. To get
378 // the maximum number of callsites, we merge the function profiles from all
379 // contexts, aka, the flattened profile to find profile anchors.
380 const auto *FSForMatching = getFlattenedSamplesFor(F);
381 if (SalvageUnusedProfile && !FSForMatching) {
382 // Apply the matching in place to find the new function's matched profile.
383 auto R = FuncToProfileNameMap.find(&F);
384 if (R != FuncToProfileNameMap.end()) {
385 FSForMatching = getFlattenedSamplesFor(R->second);
386 // Fallback for profiles loaded by functionMatchesProfileHelper but not
387 // yet in FlattenedProfiles. This should be rare now that
388 // functionMatchesProfileHelper flattens after loading.
389 if (!FSForMatching && LoadFuncProfileforCGMatching)
390 FSForMatching = Reader.getSamplesFor(R->second.stringRef());
391 }
392 }
393 if (!FSForMatching)
394 return;
395
396 // Anchors for IR. It's a map from IR location to callee name, callee name is
397 // empty for non-call instruction and use a dummy name(UnknownIndirectCallee)
398 // for unknown indrect callee name.
399 AnchorMap IRAnchors;
400 findIRAnchors(F, IRAnchors);
401 // Anchors for profile. It's a map from callsite location to a set of callee
402 // name.
403 AnchorMap ProfileAnchors;
404 findProfileAnchors(*FSForMatching, ProfileAnchors);
405
406 // Compute the callsite match states for profile staleness report.
408 recordCallsiteMatchStates(F, IRAnchors, ProfileAnchors, nullptr);
409
411 return;
412 // For probe-based profiles, run matching only when profile checksum is
413 // mismatched.
414 bool ChecksumMismatch = FunctionSamples::ProfileIsProbeBased &&
415 !ProbeManager->profileIsValid(F, *FSForMatching);
416 bool RunCFGMatching =
417 !FunctionSamples::ProfileIsProbeBased || ChecksumMismatch;
418 bool RunCGMatching = SalvageUnusedProfile;
419 // For imported functions, the checksum metadata(pseudo_probe_desc) are
420 // dropped, so we leverage function attribute(profile-checksum-mismatch) to
421 // transfer the info: add the attribute during pre-link phase and check it
422 // during post-link phase(see "profileIsValid").
423 if (ChecksumMismatch && LTOPhase == ThinOrFullLTOPhase::ThinLTOPreLink)
424 F.addFnAttr("profile-checksum-mismatch");
425
426 // The matching result will be saved to IRToProfileLocationMap, create a
427 // new map for each function.
428 auto &IRToProfileLocationMap = getIRToProfileLocationMap(*FSForMatching);
429 runStaleProfileMatching(F, IRAnchors, ProfileAnchors, IRToProfileLocationMap,
430 RunCFGMatching, RunCGMatching);
431 // Find and update callsite match states after matching.
432 if (RunCFGMatching && (ReportProfileStaleness || PersistProfileStaleness))
433 recordCallsiteMatchStates(F, IRAnchors, ProfileAnchors,
434 &IRToProfileLocationMap);
435}
436
437void SampleProfileMatcher::recordCallsiteMatchStates(
438 const Function &F, const AnchorMap &IRAnchors,
439 const AnchorMap &ProfileAnchors,
440 const LocToLocMap *IRToProfileLocationMap) {
441 bool IsPostMatch = IRToProfileLocationMap != nullptr;
442 auto &CallsiteMatchStates =
443 FuncCallsiteMatchStates[FunctionSamples::getCanonicalFnName(F.getName())];
444
445 auto MapIRLocToProfileLoc = [&](const LineLocation &IRLoc) {
446 // IRToProfileLocationMap is null in pre-match phrase.
447 if (!IRToProfileLocationMap)
448 return IRLoc;
449 const auto &ProfileLoc = IRToProfileLocationMap->find(IRLoc);
450 if (ProfileLoc != IRToProfileLocationMap->end())
451 return ProfileLoc->second;
452 else
453 return IRLoc;
454 };
455
456 for (const auto &I : IRAnchors) {
457 // After fuzzy profile matching, use the matching result to remap the
458 // current IR callsite.
459 const auto &ProfileLoc = MapIRLocToProfileLoc(I.first);
460 const auto &IRCalleeId = I.second;
461 const auto &It = ProfileAnchors.find(ProfileLoc);
462 if (It == ProfileAnchors.end())
463 continue;
464 const auto &ProfCalleeId = It->second;
465 if (IRCalleeId == ProfCalleeId) {
466 auto It = CallsiteMatchStates.find(ProfileLoc);
467 if (It == CallsiteMatchStates.end())
468 CallsiteMatchStates.try_emplace(ProfileLoc, MatchState::InitialMatch);
469 else if (IsPostMatch) {
470 if (It->second == MatchState::InitialMatch)
471 It->second = MatchState::UnchangedMatch;
472 else if (It->second == MatchState::InitialMismatch)
473 It->second = MatchState::RecoveredMismatch;
474 }
475 }
476 }
477
478 // Check if there are any callsites in the profile that does not match to any
479 // IR callsites.
480 for (const auto &I : ProfileAnchors) {
481 const auto &Loc = I.first;
482 assert(!I.second.stringRef().empty() && "Callees should not be empty");
483 auto It = CallsiteMatchStates.find(Loc);
484 if (It == CallsiteMatchStates.end())
485 CallsiteMatchStates.try_emplace(Loc, MatchState::InitialMismatch);
486 else if (IsPostMatch) {
487 // Update the state if it's not matched(UnchangedMatch or
488 // RecoveredMismatch).
489 if (It->second == MatchState::InitialMismatch)
490 It->second = MatchState::UnchangedMismatch;
491 else if (It->second == MatchState::InitialMatch)
492 It->second = MatchState::RemovedMatch;
493 }
494 }
495}
496
497void SampleProfileMatcher::countMismatchedFuncSamples(const FunctionSamples &FS,
498 bool IsTopLevel) {
499 const auto *FuncDesc = ProbeManager->getDesc(FS.getGUID());
500 // Skip the function that is external or renamed.
501 if (!FuncDesc)
502 return;
503
504 if (ProbeManager->profileIsHashMismatched(*FuncDesc, FS)) {
505 if (IsTopLevel)
506 NumStaleProfileFunc++;
507 // Given currently all probe ids are after block probe ids, once the
508 // checksum is mismatched, it's likely all the callites are mismatched and
509 // dropped. We conservatively count all the samples as mismatched and stop
510 // counting the inlinees' profiles.
511 MismatchedFunctionSamples += FS.getTotalSamples();
512 return;
513 }
514
515 // Even the current-level function checksum is matched, it's possible that the
516 // nested inlinees' checksums are mismatched that affect the inlinee's sample
517 // loading, we need to go deeper to check the inlinees' function samples.
518 // Similarly, count all the samples as mismatched if the inlinee's checksum is
519 // mismatched using this recursive function.
520 for (const auto &I : FS.getCallsiteSamples())
521 for (const auto &CS : I.second)
522 countMismatchedFuncSamples(CS.second, false);
523}
524
525void SampleProfileMatcher::countMismatchedCallsiteSamples(
526 const FunctionSamples &FS) {
527 auto It = FuncCallsiteMatchStates.find(FS.getFuncName());
528 // Skip it if no mismatched callsite or this is an external function.
529 if (It == FuncCallsiteMatchStates.end() || It->second.empty())
530 return;
531 const auto &CallsiteMatchStates = It->second;
532
533 auto findMatchState = [&](const LineLocation &Loc) {
534 auto It = CallsiteMatchStates.find(Loc);
535 if (It == CallsiteMatchStates.end())
536 return MatchState::Unknown;
537 return It->second;
538 };
539
540 auto AttributeMismatchedSamples = [&](const enum MatchState &State,
541 uint64_t Samples) {
542 if (isMismatchState(State))
543 MismatchedCallsiteSamples += Samples;
544 else if (State == MatchState::RecoveredMismatch)
545 RecoveredCallsiteSamples += Samples;
546 };
547
548 // The non-inlined callsites are saved in the body samples of function
549 // profile, go through it to count the non-inlined callsite samples.
550 for (const auto &I : FS.getBodySamples())
551 AttributeMismatchedSamples(findMatchState(I.first), I.second.getSamples());
552
553 // Count the inlined callsite samples.
554 for (const auto &I : FS.getCallsiteSamples()) {
555 auto State = findMatchState(I.first);
556 uint64_t CallsiteSamples = 0;
557 for (const auto &CS : I.second)
558 CallsiteSamples += CS.second.getTotalSamples();
559 AttributeMismatchedSamples(State, CallsiteSamples);
560
561 if (isMismatchState(State))
562 continue;
563
564 // When the current level of inlined call site matches the profiled call
565 // site, we need to go deeper along the inline tree to count mismatches from
566 // lower level inlinees.
567 for (const auto &CS : I.second)
568 countMismatchedCallsiteSamples(CS.second);
569 }
570}
571
572void SampleProfileMatcher::countMismatchCallsites(const FunctionSamples &FS) {
573 auto It = FuncCallsiteMatchStates.find(FS.getFuncName());
574 // Skip it if no mismatched callsite or this is an external function.
575 if (It == FuncCallsiteMatchStates.end() || It->second.empty())
576 return;
577 const auto &MatchStates = It->second;
578 [[maybe_unused]] bool OnInitialState =
579 isInitialState(MatchStates.begin()->second);
580 for (const auto &I : MatchStates) {
581 TotalProfiledCallsites++;
582 assert(
583 (OnInitialState ? isInitialState(I.second) : isFinalState(I.second)) &&
584 "Profile matching state is inconsistent");
585
586 if (isMismatchState(I.second))
587 NumMismatchedCallsites++;
588 else if (I.second == MatchState::RecoveredMismatch)
589 NumRecoveredCallsites++;
590 }
591}
592
593void SampleProfileMatcher::countCallGraphRecoveredSamples(
594 const FunctionSamples &FS,
595 DenseSet<FunctionId> &CallGraphRecoveredProfiles) {
596 if (CallGraphRecoveredProfiles.count(FS.getFunction())) {
597 NumCallGraphRecoveredFuncSamples += FS.getTotalSamples();
598 return;
599 }
600
601 for (const auto &CM : FS.getCallsiteSamples()) {
602 for (const auto &CS : CM.second) {
603 countCallGraphRecoveredSamples(CS.second, CallGraphRecoveredProfiles);
604 }
605 }
606}
607
608void SampleProfileMatcher::computeAndReportProfileStaleness() {
610 return;
611
612 DenseSet<FunctionId> CallGraphRecoveredProfiles;
614 for (const auto &I : FuncToProfileNameMap) {
615 CallGraphRecoveredProfiles.insert(I.second);
616 if (GlobalValue::isAvailableExternallyLinkage(I.first->getLinkage()))
617 continue;
618 NumCallGraphRecoveredProfiledFunc++;
619 }
620 }
621
622 // Count profile mismatches for profile staleness report.
623 for (const auto &F : M) {
625 continue;
626 // As the stats will be merged by linker, skip reporting the metrics for
627 // imported functions to avoid repeated counting.
629 continue;
630 const auto *FS = Reader.getSamplesFor(F);
631 if (!FS)
632 continue;
633 TotalProfiledFunc++;
634 TotalFunctionSamples += FS->getTotalSamples();
635
636 if (SalvageUnusedProfile && !CallGraphRecoveredProfiles.empty())
637 countCallGraphRecoveredSamples(*FS, CallGraphRecoveredProfiles);
638
639 // Checksum mismatch is only used in pseudo-probe mode.
641 countMismatchedFuncSamples(*FS, true);
642
643 // Count mismatches and samples for calliste.
644 countMismatchCallsites(*FS);
645 countMismatchedCallsiteSamples(*FS);
646 }
647
650 errs() << "(" << NumStaleProfileFunc << "/" << TotalProfiledFunc
651 << ") of functions' profile are invalid and ("
652 << MismatchedFunctionSamples << "/" << TotalFunctionSamples
653 << ") of samples are discarded due to function hash mismatch.\n";
654 }
656 errs() << "(" << NumCallGraphRecoveredProfiledFunc << "/"
657 << TotalProfiledFunc << ") of functions' profile are matched and ("
658 << NumCallGraphRecoveredFuncSamples << "/" << TotalFunctionSamples
659 << ") of samples are reused by call graph matching.\n";
660 }
661
662 errs() << "(" << (NumMismatchedCallsites + NumRecoveredCallsites) << "/"
663 << TotalProfiledCallsites
664 << ") of callsites' profile are invalid and ("
665 << (MismatchedCallsiteSamples + RecoveredCallsiteSamples) << "/"
666 << TotalFunctionSamples
667 << ") of samples are discarded due to callsite location mismatch.\n";
668 errs() << "(" << NumRecoveredCallsites << "/"
669 << (NumRecoveredCallsites + NumMismatchedCallsites)
670 << ") of callsites and (" << RecoveredCallsiteSamples << "/"
671 << (RecoveredCallsiteSamples + MismatchedCallsiteSamples)
672 << ") of samples are recovered by stale profile matching.\n";
673 }
674
676 LLVMContext &Ctx = M.getContext();
677 MDBuilder MDB(Ctx);
678
681 ProfStatsVec.emplace_back("NumStaleProfileFunc", NumStaleProfileFunc);
682 ProfStatsVec.emplace_back("TotalProfiledFunc", TotalProfiledFunc);
683 ProfStatsVec.emplace_back("MismatchedFunctionSamples",
684 MismatchedFunctionSamples);
685 ProfStatsVec.emplace_back("TotalFunctionSamples", TotalFunctionSamples);
686 }
687
689 ProfStatsVec.emplace_back("NumCallGraphRecoveredProfiledFunc",
690 NumCallGraphRecoveredProfiledFunc);
691 ProfStatsVec.emplace_back("NumCallGraphRecoveredFuncSamples",
692 NumCallGraphRecoveredFuncSamples);
693 }
694
695 ProfStatsVec.emplace_back("NumMismatchedCallsites", NumMismatchedCallsites);
696 ProfStatsVec.emplace_back("NumRecoveredCallsites", NumRecoveredCallsites);
697 ProfStatsVec.emplace_back("TotalProfiledCallsites", TotalProfiledCallsites);
698 ProfStatsVec.emplace_back("MismatchedCallsiteSamples",
699 MismatchedCallsiteSamples);
700 ProfStatsVec.emplace_back("RecoveredCallsiteSamples",
701 RecoveredCallsiteSamples);
702
703 auto *MD = MDB.createLLVMStats(ProfStatsVec);
704 auto *NMD = M.getOrInsertNamedMetadata("llvm.stats");
705 NMD->addOperand(MD);
706 }
707}
708
709void SampleProfileMatcher::findFunctionsWithoutProfile() {
710 // TODO: Support MD5 profile.
712 return;
713 StringSet<> NamesInProfile;
714 for (FunctionId Name : Reader.getNameTable())
715 NamesInProfile.insert(Name.stringRef());
716
717 for (auto &F : M) {
718 // Skip declarations, as even if the function can be matched, we have
719 // nothing to do with it.
720 if (F.isDeclaration())
721 continue;
722
723 StringRef CanonFName = FunctionSamples::getCanonicalFnName(F.getName());
724 const auto *FS = getFlattenedSamplesFor(F);
725 if (FS)
726 continue;
727
728 // For extended binary, functions fully inlined may not be loaded in the
729 // top-level profile, so check the NameTable which has the all symbol names
730 // in profile.
731 if (NamesInProfile.count(CanonFName))
732 continue;
733
734 // For extended binary, non-profiled function symbols are in the profile
735 // symbol list table.
736 if (PSL && PSL->contains(CanonFName))
737 continue;
738
739 LLVM_DEBUG(dbgs() << "Function " << CanonFName
740 << " is not in profile or profile symbol list.\n");
741 FunctionsWithoutProfile[FunctionId(CanonFName)] = &F;
742 }
743}
744
745// Demangle \p FName and return the base function name (stripping namespaces,
746// templates, and parameter types). Returns an empty string on failure.
747static std::string getDemangledBaseName(ItaniumPartialDemangler &Demangler,
748 StringRef FName) {
749 auto FunctionName = FName.str();
750 if (Demangler.partialDemangle(FunctionName.c_str()))
751 return std::string();
752 size_t BaseNameSize = 0;
753 // The demangler API follows the __cxa_demangle one, and thus needs a
754 // pointer that originates from malloc (or nullptr) and the caller is
755 // responsible for free()-ing the buffer.
756 char *BaseNamePtr = Demangler.getFunctionBaseName(nullptr, &BaseNameSize);
757 std::string Result = (BaseNamePtr && BaseNameSize)
758 ? std::string(BaseNamePtr, BaseNameSize)
759 : std::string();
760 free(BaseNamePtr);
761 // Trim trailing whitespace/null — getFunctionBaseName may include trailing
762 // characters in the reported size.
763 while (!Result.empty() && (Result.back() == ' ' || Result.back() == '\0'))
764 Result.pop_back();
765 return Result;
766}
767
768void SampleProfileMatcher::matchFunctionsWithoutProfileByBasename() {
769 if (FunctionsWithoutProfile.empty() || !LoadFuncProfileforCGMatching)
770 return;
771 auto NameTable = Reader.getNameTable();
772 if (NameTable.empty())
773 return;
774
775 ItaniumPartialDemangler Demangler;
776
777 // Build a map from demangled basename to orphan function. Only keep
778 // basenames that map to exactly one orphan — ambiguous basenames like
779 // "get" or "operator()" would produce false positives.
780 StringMap<Function *> OrphansByBaseName;
781 StringSet<> AmbiguousBaseNames;
782 for (auto &[FuncId, Func] : FunctionsWithoutProfile) {
783 std::string BaseName = getDemangledBaseName(Demangler, Func->getName());
784 if (BaseName.empty() || AmbiguousBaseNames.count(BaseName))
785 continue;
786 auto [It, Inserted] = OrphansByBaseName.try_emplace(BaseName, Func);
787 if (!Inserted) {
788 // More than one orphan shares this basename — mark ambiguous.
789 OrphansByBaseName.erase(It);
790 AmbiguousBaseNames.insert(BaseName);
791 }
792 }
793 if (OrphansByBaseName.empty())
794 return;
795
796 // Scan the profile NameTable for candidates whose demangled basename matches
797 // a unique orphan. Use a map to track exactly one candidate per basename.
798 StringMap<FunctionId> CandidateByBaseName;
799 for (FunctionId ProfileFuncId : NameTable) {
800 StringRef ProfName = ProfileFuncId.stringRef();
801 if (ProfName.empty())
802 continue;
803
804 std::string ProfBaseName = getDemangledBaseName(Demangler, ProfName);
805 if (ProfBaseName.empty())
806 continue;
807
808 if (OrphansByBaseName.count(ProfBaseName)) {
809 if (AmbiguousBaseNames.count(ProfBaseName))
810 continue;
811
812 auto [It, Inserted] =
813 CandidateByBaseName.try_emplace(ProfBaseName, ProfileFuncId);
814 if (!Inserted) {
815 // More than one profile entry shares this basename — mark ambiguous.
816 CandidateByBaseName.erase(It);
817 AmbiguousBaseNames.insert(ProfBaseName);
818 }
819 }
820 }
821
822 if (CandidateByBaseName.empty())
823 return;
824
825 // Load candidate profiles on demand, match, and flatten.
826 DenseSet<StringRef> ToLoad;
827 for (auto &[BaseName, ProfId] : CandidateByBaseName)
828 ToLoad.insert(ProfId.stringRef());
829 Reader.read(ToLoad);
830
831 unsigned MatchCount = 0;
832 SampleProfileMap NewlyLoadedProfiles;
833 for (auto &[BaseName, ProfId] : CandidateByBaseName) {
834 if (!isProfileUnused(ProfId))
835 continue;
836 Function *OrphanFunc = OrphansByBaseName.lookup(BaseName);
837 if (!OrphanFunc)
838 continue;
839
840 FuncToProfileNameMap[OrphanFunc] = ProfId;
841 if (const auto *FS = Reader.getSamplesFor(ProfId.stringRef()))
842 NewlyLoadedProfiles.create(FS->getFunction()).merge(*FS);
843 MatchCount++;
844 LLVM_DEBUG(dbgs() << "Direct basename match: " << OrphanFunc->getName()
845 << " (IR) -> " << ProfId << " (Profile)"
846 << " [basename: " << BaseName << "]\n");
847 }
848
849 // Flatten newly loaded profiles so inlined callees are available for
850 // subsequent LCS-based CG matching.
851 if (!NewlyLoadedProfiles.empty())
852 ProfileConverter::flattenProfile(NewlyLoadedProfiles, FlattenedProfiles,
854
855 NumDirectProfileMatch += MatchCount;
856 LLVM_DEBUG(dbgs() << "Direct basename matching found " << MatchCount
857 << " matches\n");
858}
859
860bool SampleProfileMatcher::functionMatchesProfileHelper(
861 const Function &IRFunc, const FunctionId &ProfFunc) {
862 // The value is in the range [0, 1]. The bigger the value is, the more similar
863 // two sequences are.
864 float Similarity = 0.0;
865
866 // Match the functions if they have the same base name(after demangling) and
867 // skip the similarity check.
868 ItaniumPartialDemangler Demangler;
869 auto IRBaseName = getDemangledBaseName(Demangler, IRFunc.getName());
870 auto ProfBaseName = getDemangledBaseName(Demangler, ProfFunc.stringRef());
871 if (!IRBaseName.empty() && IRBaseName == ProfBaseName) {
872 LLVM_DEBUG(dbgs() << "The functions " << IRFunc.getName() << "(IR) and "
873 << ProfFunc << "(Profile) share the same base name: "
874 << IRBaseName << ".\n");
875 return true;
876 }
877
878 const auto *FSForMatching = getFlattenedSamplesFor(ProfFunc);
879 // With extbinary profile format, initial profile loading only reads profile
880 // based on current function names in the module.
881 // However, if a function is renamed, sample loader skips to load its original
882 // profile(which has a different name), we will miss this case. To address
883 // this, we load the top-level profile candidate explicitly for the matching.
884 if (!FSForMatching && LoadFuncProfileforCGMatching) {
885 DenseSet<StringRef> TopLevelFunc({ProfFunc.stringRef()});
886 if (std::error_code EC = Reader.read(TopLevelFunc))
887 return false;
888 FSForMatching = Reader.getSamplesFor(ProfFunc.stringRef());
889 // Flatten the newly loaded profile so its inlined callees get their own
890 // entries in FlattenedProfiles, making them discoverable by subsequent
891 // CG matching steps.
892 if (FSForMatching) {
893 SampleProfileMap TempProfiles;
894 TempProfiles.create(FSForMatching->getFunction()).merge(*FSForMatching);
895 ProfileConverter::flattenProfile(TempProfiles, FlattenedProfiles,
897 FSForMatching = getFlattenedSamplesFor(ProfFunc);
898 }
899 LLVM_DEBUG({
900 if (FSForMatching)
901 dbgs() << "Read top-level function " << ProfFunc
902 << " for call-graph matching\n";
903 });
904 }
905 if (!FSForMatching)
906 return false;
907 // The check for similarity or checksum may not be reliable if the function is
908 // tiny, we use the number of basic block as a proxy for the function
909 // complexity and skip the matching if it's too small.
910 if (IRFunc.size() < MinFuncCountForCGMatching ||
911 FSForMatching->getBodySamples().size() < MinFuncCountForCGMatching)
912 return false;
913
914 // For probe-based function, we first trust the checksum info. If the checksum
915 // doesn't match, we continue checking for similarity.
917 const auto *FuncDesc = ProbeManager->getDesc(IRFunc);
918 if (FuncDesc &&
919 !ProbeManager->profileIsHashMismatched(*FuncDesc, *FSForMatching)) {
920 LLVM_DEBUG(dbgs() << "The checksums for " << IRFunc.getName()
921 << "(IR) and " << ProfFunc << "(Profile) match.\n");
922
923 return true;
924 }
925 }
926
927 AnchorMap IRAnchors;
928 findIRAnchors(IRFunc, IRAnchors);
929 AnchorMap ProfileAnchors;
930 findProfileAnchors(*FSForMatching, ProfileAnchors);
931
932 AnchorList FilteredIRAnchorsList;
933 AnchorList FilteredProfileAnchorList;
934 getFilteredAnchorList(IRAnchors, ProfileAnchors, FilteredIRAnchorsList,
935 FilteredProfileAnchorList);
936
937 // Similarly skip the matching if the num of anchors is not enough.
938 if (FilteredIRAnchorsList.size() < MinCallCountForCGMatching ||
939 FilteredProfileAnchorList.size() < MinCallCountForCGMatching)
940 return false;
941
942 // Use the diff algorithm to find the LCS between IR and profile.
943
944 // Don't recursively match the callee function to avoid infinite matching,
945 // callee functions will be handled later since it's processed in top-down
946 // order .
947 LocToLocMap MatchedAnchors =
948 longestCommonSequence(FilteredIRAnchorsList, FilteredProfileAnchorList,
949 false /* Match unused functions */);
950
951 Similarity = static_cast<float>(MatchedAnchors.size()) /
952 FilteredProfileAnchorList.size();
953
954 LLVM_DEBUG(dbgs() << "The similarity between " << IRFunc.getName()
955 << "(IR) and " << ProfFunc << "(profile) is "
956 << format("%.2f", Similarity) << "\n");
957 assert((Similarity >= 0 && Similarity <= 1.0) &&
958 "Similarity value should be in [0, 1]");
959 return Similarity * 100 > FuncProfileSimilarityThreshold;
960}
961
962// If FindMatchedProfileOnly is set to true, only use the processed function
963// results. This is used for skipping the repeated recursive matching.
964bool SampleProfileMatcher::functionMatchesProfile(Function &IRFunc,
965 const FunctionId &ProfFunc,
966 bool FindMatchedProfileOnly) {
967 auto R = FuncProfileMatchCache.find({&IRFunc, ProfFunc});
968 if (R != FuncProfileMatchCache.end())
969 return R->second;
970
971 if (FindMatchedProfileOnly)
972 return false;
973
974 bool Matched = functionMatchesProfileHelper(IRFunc, ProfFunc);
975 FuncProfileMatchCache[{&IRFunc, ProfFunc}] = Matched;
976 if (Matched) {
977 FuncToProfileNameMap[&IRFunc] = ProfFunc;
978 LLVM_DEBUG(dbgs() << "Function:" << IRFunc.getName()
979 << " matches profile:" << ProfFunc << "\n");
980 }
981
982 return Matched;
983}
984
985void SampleProfileMatcher::UpdateWithSalvagedProfiles() {
986 DenseSet<StringRef> ProfileSalvagedFuncs;
987 // Update FuncNameToProfNameMap and SymbolMap.
988 for (auto &I : FuncToProfileNameMap) {
989 assert(I.first && "New function is null");
990 FunctionId FuncName(I.first->getName());
991 ProfileSalvagedFuncs.insert(I.second.stringRef());
992 FuncNameToProfNameMap->emplace(FuncName, I.second);
993
994 // We need to remove the old entry to avoid duplicating the function
995 // processing.
996 SymbolMap->erase(FuncName);
997 [[maybe_unused]] auto Ret = SymbolMap->emplace(I.second, I.first);
998 LLVM_DEBUG({
999 if (!Ret.second)
1000 dbgs() << "Profile Function " << I.second
1001 << " has already been matched to another IR function.\n";
1002 });
1003 }
1004
1005 // With extbinary profile format, initial profile loading only reads profile
1006 // based on current function names in the module, so we need to load top-level
1007 // profiles for functions with different profile name explicitly after
1008 // function-profile name map is established with stale profile matching.
1009 Reader.read(ProfileSalvagedFuncs);
1010 Reader.setFuncNameToProfNameMap(*FuncNameToProfNameMap);
1011}
1012
1014 ProfileConverter::flattenProfile(Reader.getProfiles(), FlattenedProfiles,
1016 // Disable SalvageUnusedProfile if the module has an extremely large number of
1017 // functions to limit compile time.
1020
1022 findFunctionsWithoutProfile();
1023 matchFunctionsWithoutProfileByBasename();
1024 }
1025
1026 // Process the matching in top-down order so that the caller matching result
1027 // can be used to the callee matching.
1028 std::vector<Function *> TopDownFunctionList;
1029 TopDownFunctionList.reserve(M.size());
1030 buildTopDownFuncOrder(CG, TopDownFunctionList);
1031 for (auto *F : TopDownFunctionList) {
1033 continue;
1034 runOnFunction(*F);
1035 }
1036
1038 UpdateWithSalvagedProfiles();
1039
1041 distributeIRToProfileLocationMap();
1042
1043 computeAndReportProfileStaleness();
1044}
1045
1046void SampleProfileMatcher::distributeIRToProfileLocationMap(
1047 FunctionSamples &FS) {
1048 const auto ProfileMappings = FuncMappings.find(FS.getFuncName());
1049 if (ProfileMappings != FuncMappings.end()) {
1050 FS.setIRToProfileLocationMap(&(ProfileMappings->second));
1051 }
1052
1053 for (auto &Callees :
1054 const_cast<CallsiteSampleMap &>(FS.getCallsiteSamples())) {
1055 for (auto &FS : Callees.second) {
1056 distributeIRToProfileLocationMap(FS.second);
1057 }
1058 }
1059}
1060
1061// Use a central place to distribute the matching results. Outlined and inlined
1062// profile with the function name will be set to the same pointer.
1063void SampleProfileMatcher::distributeIRToProfileLocationMap() {
1064 for (auto &I : Reader.getProfiles()) {
1065 distributeIRToProfileLocationMap(I.second);
1066 }
1067}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
itanium_demangle::ManglingParser< DefaultAllocator > Demangler
Legalize the Machine IR a function s Machine IR
Definition Legalizer.cpp:81
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
static std::string getDemangledBaseName(ItaniumPartialDemangler &Demangler, StringRef FName)
This file provides the interface for SampleProfileMatcher.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
#define LLVM_DEBUG(...)
Definition Debug.h:119
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:225
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:301
bool erase(const KeyT &Val)
Definition DenseMap.h:379
unsigned size() const
Definition DenseMap.h:174
bool empty() const
Definition DenseMap.h:173
iterator end()
Definition DenseMap.h:143
std::pair< iterator, bool > insert_or_assign(const KeyT &Key, V &&Val)
Definition DenseMap.h:344
Implements a dense probed hash-table based set.
Definition DenseSet.h:289
size_t size() const
Definition Function.h:858
static bool isAvailableExternallyLinkage(LinkageTypes Linkage)
reference emplace_back(ArgTypes &&... Args)
bool empty() const
Definition StringMap.h:102
size_type count(StringRef Key) const
count - Return 1 if the element is in the map, 0 otherwise.
Definition StringMap.h:274
ValueTy lookup(StringRef Key) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
Definition StringMap.h:249
void erase(iterator I)
Definition StringMap.h:417
std::pair< iterator, bool > try_emplace(StringRef Key, ArgsTy &&...Args)
Emplace a new element for the specified key into the map if the key isn't already in the map.
Definition StringMap.h:369
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::string str() const
Get the contents as an std::string.
Definition StringRef.h:222
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
std::pair< typename Base::iterator, bool > insert(StringRef key)
Definition StringSet.h:39
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:319
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:212
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
Definition DenseSet.h:190
This class represents a function that is read from a sample profile.
Definition FunctionId.h:36
StringRef stringRef() const
Convert to StringRef.
Definition FunctionId.h:108
bool isStringRef() const
Check if this object represents a StringRef, or a hash code.
Definition FunctionId.h:132
Representation of the samples collected for a function.
Definition SampleProf.h:792
static LLVM_ABI bool ProfileIsCS
static LLVM_ABI bool ProfileIsProbeBased
static StringRef getCanonicalFnName(const Function &F)
Return the canonical name for a function, taking into account suffix elision policy attributes.
static LLVM_ABI bool ProfileIsFS
If this profile uses flow sensitive discriminators.
sampleprof_error merge(const FunctionSamples &Other, uint64_t Weight=1)
Merge the samples in Other into this one.
static LLVM_ABI LineLocation getCallSiteIdentifier(const DILocation *DIL, bool ProfileIsFS=false)
Returns a unique call site identifier for a given debug location of a call instruction.
static LLVM_ABI bool UseMD5
Whether the profile uses MD5 to represent string.
static void flattenProfile(SampleProfileMap &ProfileMap, bool ProfileIsCS=false)
mapped_type & create(const SampleContext &Ctx)
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
initializer< Ty > init(const Ty &Val)
NodeAddr< FuncNode * > Func
Definition RDFGraph.h:393
std::map< LineLocation, FunctionSamplesMap > CallsiteSampleMap
Definition SampleProf.h:783
DenseMap< LineLocation, LineLocation > LocToLocMap
Definition SampleProf.h:785
This is an optimization pass for GlobalISel generic memory operations.
cl::opt< bool > ReportProfileStaleness("report-profile-staleness", cl::Hidden, cl::init(false), cl::desc("Compute and report stale profile statistical metrics."))
cl::opt< bool > PersistProfileStaleness("persist-profile-staleness", cl::Hidden, cl::init(false), cl::desc("Compute stale profile statistical metrics and write it into the " "native object file(.llvm_stats section)."))
std::map< LineLocation, FunctionId > AnchorMap
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
static cl::opt< bool > LoadFuncProfileforCGMatching("load-func-profile-for-cg-matching", cl::Hidden, cl::init(true), cl::desc("Load top-level profiles that the sample reader initially skipped for " "the call-graph matching (only meaningful for extended binary " "format)"))
static cl::opt< unsigned > SalvageUnusedProfileMaxFunctions("salvage-unused-profile-max-functions", cl::Hidden, cl::init(UINT_MAX), cl::desc("The maximum number of functions in a module, above which salvage " "unused profile will be skipped."))
static void buildTopDownFuncOrder(LazyCallGraph &CG, std::vector< Function * > &FunctionOrderList)
@ ThinLTOPreLink
ThinLTO prelink (summary) phase.
Definition Pass.h:81
static cl::opt< unsigned > MinCallCountForCGMatching("min-call-count-for-cg-matching", cl::Hidden, cl::init(3), cl::desc("The minimum number of call anchors required for a function to " "run stale profile call graph matching."))
LLVM_ABI std::optional< PseudoProbe > extractProbe(const Instruction &Inst)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
static cl::opt< unsigned > MinFuncCountForCGMatching("min-func-count-for-cg-matching", cl::Hidden, cl::init(5), cl::desc("The minimum number of basic blocks required for a function to " "run stale profile call graph matching."))
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition Format.h:129
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
cl::opt< bool > SalvageStaleProfile("salvage-stale-profile", cl::Hidden, cl::init(false), cl::desc("Salvage stale profile by fuzzy matching and use the remapped " "location for sample profile query."))
void longestCommonSequence(AnchorList AnchorList1, AnchorList AnchorList2, llvm::function_ref< bool(const Function &, const Function &)> FunctionMatchesProfile, llvm::function_ref< void(Loc, Loc)> InsertMatching)
std::vector< std::pair< LineLocation, FunctionId > > AnchorList
static bool skipProfileForFunction(const Function &F)
cl::opt< bool > SalvageUnusedProfile("salvage-unused-profile", cl::Hidden, cl::init(false), cl::desc("Salvage unused profile by matching with new " "functions on call graph."))
static cl::opt< unsigned > SalvageStaleProfileMaxCallsites("salvage-stale-profile-max-callsites", cl::Hidden, cl::init(UINT_MAX), cl::desc("The maximum number of callsites in a function, above which stale " "profile matching will be skipped."))
static cl::opt< unsigned > FuncProfileSimilarityThreshold("func-profile-similarity-threshold", cl::Hidden, cl::init(80), cl::desc("Consider a profile matches a function if the similarity of their " "callee sequences is above the specified percentile."))
"Partial" demangler.
Definition Demangle.h:85