1 //===- ProfileSummaryInfo.cpp - Global profile summary information --------===//
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 contains a pass that provides access to the global profile summary
10 // information.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/Analysis/ProfileSummaryInfo.h"
15 #include "llvm/Analysis/BlockFrequencyInfo.h"
16 #include "llvm/IR/BasicBlock.h"
17 #include "llvm/IR/Instructions.h"
18 #include "llvm/IR/Metadata.h"
19 #include "llvm/IR/Module.h"
20 #include "llvm/IR/ProfileSummary.h"
21 #include "llvm/InitializePasses.h"
22 #include "llvm/Support/CommandLine.h"
23 using namespace llvm;
24 
25 // The following two parameters determine the threshold for a count to be
26 // considered hot/cold. These two parameters are percentile values (multiplied
27 // by 10000). If the counts are sorted in descending order, the minimum count to
28 // reach ProfileSummaryCutoffHot gives the threshold to determine a hot count.
29 // Similarly, the minimum count to reach ProfileSummaryCutoffCold gives the
30 // threshold for determining cold count (everything <= this threshold is
31 // considered cold).
32 
33 static cl::opt<int> ProfileSummaryCutoffHot(
34     "profile-summary-cutoff-hot", cl::Hidden, cl::init(990000), cl::ZeroOrMore,
35     cl::desc("A count is hot if it exceeds the minimum count to"
36              " reach this percentile of total counts."));
37 
38 static cl::opt<int> ProfileSummaryCutoffCold(
39     "profile-summary-cutoff-cold", cl::Hidden, cl::init(999999), cl::ZeroOrMore,
40     cl::desc("A count is cold if it is below the minimum count"
41              " to reach this percentile of total counts."));
42 
43 static cl::opt<unsigned> ProfileSummaryHugeWorkingSetSizeThreshold(
44     "profile-summary-huge-working-set-size-threshold", cl::Hidden,
45     cl::init(15000), cl::ZeroOrMore,
46     cl::desc("The code working set size is considered huge if the number of"
47              " blocks required to reach the -profile-summary-cutoff-hot"
48              " percentile exceeds this count."));
49 
50 static cl::opt<unsigned> ProfileSummaryLargeWorkingSetSizeThreshold(
51     "profile-summary-large-working-set-size-threshold", cl::Hidden,
52     cl::init(12500), cl::ZeroOrMore,
53     cl::desc("The code working set size is considered large if the number of"
54              " blocks required to reach the -profile-summary-cutoff-hot"
55              " percentile exceeds this count."));
56 
57 // The next two options override the counts derived from summary computation and
58 // are useful for debugging purposes.
59 static cl::opt<int> ProfileSummaryHotCount(
60     "profile-summary-hot-count", cl::ReallyHidden, cl::ZeroOrMore,
61     cl::desc("A fixed hot count that overrides the count derived from"
62              " profile-summary-cutoff-hot"));
63 
64 static cl::opt<int> ProfileSummaryColdCount(
65     "profile-summary-cold-count", cl::ReallyHidden, cl::ZeroOrMore,
66     cl::desc("A fixed cold count that overrides the count derived from"
67              " profile-summary-cutoff-cold"));
68 
69 // Find the summary entry for a desired percentile of counts.
70 static const ProfileSummaryEntry &getEntryForPercentile(SummaryEntryVector &DS,
71                                                         uint64_t Percentile) {
72   auto It = partition_point(DS, [=](const ProfileSummaryEntry &Entry) {
73     return Entry.Cutoff < Percentile;
74   });
75   // The required percentile has to be <= one of the percentiles in the
76   // detailed summary.
77   if (It == DS.end())
78     report_fatal_error("Desired percentile exceeds the maximum cutoff");
79   return *It;
80 }
81 
82 // The profile summary metadata may be attached either by the frontend or by
83 // any backend passes (IR level instrumentation, for example). This method
84 // checks if the Summary is null and if so checks if the summary metadata is now
85 // available in the module and parses it to get the Summary object. Returns true
86 // if a valid Summary is available.
87 bool ProfileSummaryInfo::computeSummary() {
88   if (Summary)
89     return true;
90   // First try to get context sensitive ProfileSummary.
91   auto *SummaryMD = M.getProfileSummary(/* IsCS */ true);
92   if (SummaryMD) {
93     Summary.reset(ProfileSummary::getFromMD(SummaryMD));
94     return true;
95   }
96   // This will actually return PSK_Instr or PSK_Sample summary.
97   SummaryMD = M.getProfileSummary(/* IsCS */ false);
98   if (!SummaryMD)
99     return false;
100   Summary.reset(ProfileSummary::getFromMD(SummaryMD));
101   return true;
102 }
103 
104 // FIXME(CallSite): the parameter should be a CallBase.
105 Optional<uint64_t>
106 ProfileSummaryInfo::getProfileCount(const Instruction *Inst,
107                                     BlockFrequencyInfo *BFI,
108                                     bool AllowSynthetic) {
109   if (!Inst)
110     return None;
111   assert((isa<CallInst>(Inst) || isa<InvokeInst>(Inst)) &&
112          "We can only get profile count for call/invoke instruction.");
113   if (hasSampleProfile()) {
114     // In sample PGO mode, check if there is a profile metadata on the
115     // instruction. If it is present, determine hotness solely based on that,
116     // since the sampled entry count may not be accurate. If there is no
117     // annotated on the instruction, return None.
118     uint64_t TotalCount;
119     if (Inst->extractProfTotalWeight(TotalCount))
120       return TotalCount;
121     return None;
122   }
123   if (BFI)
124     return BFI->getBlockProfileCount(Inst->getParent(), AllowSynthetic);
125   return None;
126 }
127 
128 /// Returns true if the function's entry is hot. If it returns false, it
129 /// either means it is not hot or it is unknown whether it is hot or not (for
130 /// example, no profile data is available).
131 bool ProfileSummaryInfo::isFunctionEntryHot(const Function *F) {
132   if (!F || !computeSummary())
133     return false;
134   auto FunctionCount = F->getEntryCount();
135   // FIXME: The heuristic used below for determining hotness is based on
136   // preliminary SPEC tuning for inliner. This will eventually be a
137   // convenience method that calls isHotCount.
138   return FunctionCount && isHotCount(FunctionCount.getCount());
139 }
140 
141 /// Returns true if the function contains hot code. This can include a hot
142 /// function entry count, hot basic block, or (in the case of Sample PGO)
143 /// hot total call edge count.
144 /// If it returns false, it either means it is not hot or it is unknown
145 /// (for example, no profile data is available).
146 bool ProfileSummaryInfo::isFunctionHotInCallGraph(const Function *F,
147                                                   BlockFrequencyInfo &BFI) {
148   if (!F || !computeSummary())
149     return false;
150   if (auto FunctionCount = F->getEntryCount())
151     if (isHotCount(FunctionCount.getCount()))
152       return true;
153 
154   if (hasSampleProfile()) {
155     uint64_t TotalCallCount = 0;
156     for (const auto &BB : *F)
157       for (const auto &I : BB)
158         if (isa<CallInst>(I) || isa<InvokeInst>(I))
159           if (auto CallCount = getProfileCount(&I, nullptr))
160             TotalCallCount += CallCount.getValue();
161     if (isHotCount(TotalCallCount))
162       return true;
163   }
164   for (const auto &BB : *F)
165     if (isHotBlock(&BB, &BFI))
166       return true;
167   return false;
168 }
169 
170 /// Returns true if the function only contains cold code. This means that
171 /// the function entry and blocks are all cold, and (in the case of Sample PGO)
172 /// the total call edge count is cold.
173 /// If it returns false, it either means it is not cold or it is unknown
174 /// (for example, no profile data is available).
175 bool ProfileSummaryInfo::isFunctionColdInCallGraph(const Function *F,
176                                                    BlockFrequencyInfo &BFI) {
177   if (!F || !computeSummary())
178     return false;
179   if (auto FunctionCount = F->getEntryCount())
180     if (!isColdCount(FunctionCount.getCount()))
181       return false;
182 
183   if (hasSampleProfile()) {
184     uint64_t TotalCallCount = 0;
185     for (const auto &BB : *F)
186       for (const auto &I : BB)
187         if (isa<CallInst>(I) || isa<InvokeInst>(I))
188           if (auto CallCount = getProfileCount(&I, nullptr))
189             TotalCallCount += CallCount.getValue();
190     if (!isColdCount(TotalCallCount))
191       return false;
192   }
193   for (const auto &BB : *F)
194     if (!isColdBlock(&BB, &BFI))
195       return false;
196   return true;
197 }
198 
199 template<bool isHot>
200 bool ProfileSummaryInfo::isFunctionHotOrColdInCallGraphNthPercentile(
201     int PercentileCutoff, const Function *F, BlockFrequencyInfo &BFI) {
202   if (!F || !computeSummary())
203     return false;
204   if (auto FunctionCount = F->getEntryCount()) {
205     if (isHot &&
206         isHotCountNthPercentile(PercentileCutoff, FunctionCount.getCount()))
207       return true;
208     if (!isHot &&
209         !isColdCountNthPercentile(PercentileCutoff, FunctionCount.getCount()))
210       return false;
211   }
212   if (hasSampleProfile()) {
213     uint64_t TotalCallCount = 0;
214     for (const auto &BB : *F)
215       for (const auto &I : BB)
216         if (isa<CallInst>(I) || isa<InvokeInst>(I))
217           if (auto CallCount = getProfileCount(&I, nullptr))
218             TotalCallCount += CallCount.getValue();
219     if (isHot && isHotCountNthPercentile(PercentileCutoff, TotalCallCount))
220       return true;
221     if (!isHot && !isColdCountNthPercentile(PercentileCutoff, TotalCallCount))
222       return false;
223   }
224   for (const auto &BB : *F) {
225     if (isHot && isHotBlockNthPercentile(PercentileCutoff, &BB, &BFI))
226       return true;
227     if (!isHot && !isColdBlockNthPercentile(PercentileCutoff, &BB, &BFI))
228       return false;
229   }
230   return !isHot;
231 }
232 
233 // Like isFunctionHotInCallGraph but for a given cutoff.
234 bool ProfileSummaryInfo::isFunctionHotInCallGraphNthPercentile(
235     int PercentileCutoff, const Function *F, BlockFrequencyInfo &BFI) {
236   return isFunctionHotOrColdInCallGraphNthPercentile<true>(
237       PercentileCutoff, F, BFI);
238 }
239 
240 bool ProfileSummaryInfo::isFunctionColdInCallGraphNthPercentile(
241     int PercentileCutoff, const Function *F, BlockFrequencyInfo &BFI) {
242   return isFunctionHotOrColdInCallGraphNthPercentile<false>(
243       PercentileCutoff, F, BFI);
244 }
245 
246 /// Returns true if the function's entry is a cold. If it returns false, it
247 /// either means it is not cold or it is unknown whether it is cold or not (for
248 /// example, no profile data is available).
249 bool ProfileSummaryInfo::isFunctionEntryCold(const Function *F) {
250   if (!F)
251     return false;
252   if (F->hasFnAttribute(Attribute::Cold))
253     return true;
254   if (!computeSummary())
255     return false;
256   auto FunctionCount = F->getEntryCount();
257   // FIXME: The heuristic used below for determining coldness is based on
258   // preliminary SPEC tuning for inliner. This will eventually be a
259   // convenience method that calls isHotCount.
260   return FunctionCount && isColdCount(FunctionCount.getCount());
261 }
262 
263 /// Compute the hot and cold thresholds.
264 void ProfileSummaryInfo::computeThresholds() {
265   if (!computeSummary())
266     return;
267   auto &DetailedSummary = Summary->getDetailedSummary();
268   auto &HotEntry =
269       getEntryForPercentile(DetailedSummary, ProfileSummaryCutoffHot);
270   HotCountThreshold = HotEntry.MinCount;
271   if (ProfileSummaryHotCount.getNumOccurrences() > 0)
272     HotCountThreshold = ProfileSummaryHotCount;
273   auto &ColdEntry =
274       getEntryForPercentile(DetailedSummary, ProfileSummaryCutoffCold);
275   ColdCountThreshold = ColdEntry.MinCount;
276   if (ProfileSummaryColdCount.getNumOccurrences() > 0)
277     ColdCountThreshold = ProfileSummaryColdCount;
278   assert(ColdCountThreshold <= HotCountThreshold &&
279          "Cold count threshold cannot exceed hot count threshold!");
280   HasHugeWorkingSetSize =
281       HotEntry.NumCounts > ProfileSummaryHugeWorkingSetSizeThreshold;
282   HasLargeWorkingSetSize =
283       HotEntry.NumCounts > ProfileSummaryLargeWorkingSetSizeThreshold;
284 }
285 
286 Optional<uint64_t> ProfileSummaryInfo::computeThreshold(int PercentileCutoff) {
287   if (!computeSummary())
288     return None;
289   auto iter = ThresholdCache.find(PercentileCutoff);
290   if (iter != ThresholdCache.end()) {
291     return iter->second;
292   }
293   auto &DetailedSummary = Summary->getDetailedSummary();
294   auto &Entry =
295       getEntryForPercentile(DetailedSummary, PercentileCutoff);
296   uint64_t CountThreshold = Entry.MinCount;
297   ThresholdCache[PercentileCutoff] = CountThreshold;
298   return CountThreshold;
299 }
300 
301 bool ProfileSummaryInfo::hasHugeWorkingSetSize() {
302   if (!HasHugeWorkingSetSize)
303     computeThresholds();
304   return HasHugeWorkingSetSize && HasHugeWorkingSetSize.getValue();
305 }
306 
307 bool ProfileSummaryInfo::hasLargeWorkingSetSize() {
308   if (!HasLargeWorkingSetSize)
309     computeThresholds();
310   return HasLargeWorkingSetSize && HasLargeWorkingSetSize.getValue();
311 }
312 
313 bool ProfileSummaryInfo::isHotCount(uint64_t C) {
314   if (!HotCountThreshold)
315     computeThresholds();
316   return HotCountThreshold && C >= HotCountThreshold.getValue();
317 }
318 
319 bool ProfileSummaryInfo::isColdCount(uint64_t C) {
320   if (!ColdCountThreshold)
321     computeThresholds();
322   return ColdCountThreshold && C <= ColdCountThreshold.getValue();
323 }
324 
325 template<bool isHot>
326 bool ProfileSummaryInfo::isHotOrColdCountNthPercentile(int PercentileCutoff,
327                                                        uint64_t C) {
328   auto CountThreshold = computeThreshold(PercentileCutoff);
329   if (isHot)
330     return CountThreshold && C >= CountThreshold.getValue();
331   else
332     return CountThreshold && C <= CountThreshold.getValue();
333 }
334 
335 bool ProfileSummaryInfo::isHotCountNthPercentile(int PercentileCutoff, uint64_t C) {
336   return isHotOrColdCountNthPercentile<true>(PercentileCutoff, C);
337 }
338 
339 bool ProfileSummaryInfo::isColdCountNthPercentile(int PercentileCutoff, uint64_t C) {
340   return isHotOrColdCountNthPercentile<false>(PercentileCutoff, C);
341 }
342 
343 uint64_t ProfileSummaryInfo::getOrCompHotCountThreshold() {
344   if (!HotCountThreshold)
345     computeThresholds();
346   return HotCountThreshold ? HotCountThreshold.getValue() : UINT64_MAX;
347 }
348 
349 uint64_t ProfileSummaryInfo::getOrCompColdCountThreshold() {
350   if (!ColdCountThreshold)
351     computeThresholds();
352   return ColdCountThreshold ? ColdCountThreshold.getValue() : 0;
353 }
354 
355 bool ProfileSummaryInfo::isHotBlock(const BasicBlock *BB, BlockFrequencyInfo *BFI) {
356   auto Count = BFI->getBlockProfileCount(BB);
357   return Count && isHotCount(*Count);
358 }
359 
360 bool ProfileSummaryInfo::isColdBlock(const BasicBlock *BB,
361                                   BlockFrequencyInfo *BFI) {
362   auto Count = BFI->getBlockProfileCount(BB);
363   return Count && isColdCount(*Count);
364 }
365 
366 template<bool isHot>
367 bool ProfileSummaryInfo::isHotOrColdBlockNthPercentile(int PercentileCutoff,
368                                                        const BasicBlock *BB,
369                                                        BlockFrequencyInfo *BFI) {
370   auto Count = BFI->getBlockProfileCount(BB);
371   if (isHot)
372     return Count && isHotCountNthPercentile(PercentileCutoff, *Count);
373   else
374     return Count && isColdCountNthPercentile(PercentileCutoff, *Count);
375 }
376 
377 bool ProfileSummaryInfo::isHotBlockNthPercentile(int PercentileCutoff,
378                                                  const BasicBlock *BB,
379                                                  BlockFrequencyInfo *BFI) {
380   return isHotOrColdBlockNthPercentile<true>(PercentileCutoff, BB, BFI);
381 }
382 
383 bool ProfileSummaryInfo::isColdBlockNthPercentile(int PercentileCutoff,
384                                                   const BasicBlock *BB,
385                                                   BlockFrequencyInfo *BFI) {
386   return isHotOrColdBlockNthPercentile<false>(PercentileCutoff, BB, BFI);
387 }
388 
389 bool ProfileSummaryInfo::isHotCallSite(const CallBase &CB,
390                                        BlockFrequencyInfo *BFI) {
391   auto C = getProfileCount(&CB, BFI);
392   return C && isHotCount(*C);
393 }
394 
395 bool ProfileSummaryInfo::isColdCallSite(const CallBase &CB,
396                                         BlockFrequencyInfo *BFI) {
397   auto C = getProfileCount(&CB, BFI);
398   if (C)
399     return isColdCount(*C);
400 
401   // In SamplePGO, if the caller has been sampled, and there is no profile
402   // annotated on the callsite, we consider the callsite as cold.
403   return hasSampleProfile() && CB.getCaller()->hasProfileData();
404 }
405 
406 INITIALIZE_PASS(ProfileSummaryInfoWrapperPass, "profile-summary-info",
407                 "Profile summary info", false, true)
408 
409 ProfileSummaryInfoWrapperPass::ProfileSummaryInfoWrapperPass()
410     : ImmutablePass(ID) {
411   initializeProfileSummaryInfoWrapperPassPass(*PassRegistry::getPassRegistry());
412 }
413 
414 bool ProfileSummaryInfoWrapperPass::doInitialization(Module &M) {
415   PSI.reset(new ProfileSummaryInfo(M));
416   return false;
417 }
418 
419 bool ProfileSummaryInfoWrapperPass::doFinalization(Module &M) {
420   PSI.reset();
421   return false;
422 }
423 
424 AnalysisKey ProfileSummaryAnalysis::Key;
425 ProfileSummaryInfo ProfileSummaryAnalysis::run(Module &M,
426                                                ModuleAnalysisManager &) {
427   return ProfileSummaryInfo(M);
428 }
429 
430 PreservedAnalyses ProfileSummaryPrinterPass::run(Module &M,
431                                                  ModuleAnalysisManager &AM) {
432   ProfileSummaryInfo &PSI = AM.getResult<ProfileSummaryAnalysis>(M);
433 
434   OS << "Functions in " << M.getName() << " with hot/cold annotations: \n";
435   for (auto &F : M) {
436     OS << F.getName();
437     if (PSI.isFunctionEntryHot(&F))
438       OS << " :hot entry ";
439     else if (PSI.isFunctionEntryCold(&F))
440       OS << " :cold entry ";
441     OS << "\n";
442   }
443   return PreservedAnalyses::all();
444 }
445 
446 char ProfileSummaryInfoWrapperPass::ID = 0;
447