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