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