diff --git a/llvm/include/llvm/Analysis/ProfileSummaryInfo.h b/llvm/include/llvm/Analysis/ProfileSummaryInfo.h --- a/llvm/include/llvm/Analysis/ProfileSummaryInfo.h +++ b/llvm/include/llvm/Analysis/ProfileSummaryInfo.h @@ -72,13 +72,6 @@ Summary->getKind() == ProfileSummary::PSK_Sample; } - /// Returns true if module \c M has partial-profile sample profile. - bool hasPartialSampleProfile() { - return hasProfileSummary() && - Summary->getKind() == ProfileSummary::PSK_Sample && - Summary->isPartialProfile(); - } - /// Returns true if module \c M has instrumentation profile. bool hasInstrumentationProfile() { return hasProfileSummary() && @@ -106,6 +99,8 @@ Optional getProfileCount(const CallBase &CallInst, BlockFrequencyInfo *BFI, bool AllowSynthetic = false); + /// Returns true if module \c M has partial-profile sample profile. + bool hasPartialSampleProfile(); /// Returns true if the working set size of the code is considered huge. bool hasHugeWorkingSetSize(); /// Returns true if the working set size of the code is considered large. @@ -118,6 +113,8 @@ bool isFunctionEntryCold(const Function *F); /// Returns true if \p F contains only cold code. bool isFunctionColdInCallGraph(const Function *F, BlockFrequencyInfo &BFI); + /// Returns true if the hotness of \p F is unknown. + bool isFunctionHotnessUnknown(const Function &F); /// Returns true if \p F contains hot code with regard to a given hot /// percentile cutoff value. bool isFunctionHotInCallGraphNthPercentile(int PercentileCutoff, diff --git a/llvm/lib/Analysis/ProfileSummaryInfo.cpp b/llvm/lib/Analysis/ProfileSummaryInfo.cpp --- a/llvm/lib/Analysis/ProfileSummaryInfo.cpp +++ b/llvm/lib/Analysis/ProfileSummaryInfo.cpp @@ -66,6 +66,10 @@ cl::desc("A fixed cold count that overrides the count derived from" " profile-summary-cutoff-cold")); +static cl::opt PartialProfile( + "partial-profile", cl::Hidden, cl::init(false), + cl::desc("Specify the current profile is used as a partial profile.")); + // Find the summary entry for a desired percentile of counts. static const ProfileSummaryEntry &getEntryForPercentile(SummaryEntryVector &DS, uint64_t Percentile) { @@ -192,6 +196,11 @@ return true; } +bool ProfileSummaryInfo::isFunctionHotnessUnknown(const Function &F) { + assert(hasPartialSampleProfile() && "Expect partial sample profile"); + return !F.getEntryCount().hasValue(); +} + template bool ProfileSummaryInfo::isFunctionHotOrColdInCallGraphNthPercentile( int PercentileCutoff, const Function *F, BlockFrequencyInfo &BFI) { @@ -399,6 +408,12 @@ return hasSampleProfile() && CB.getCaller()->hasProfileData(); } +bool ProfileSummaryInfo::hasPartialSampleProfile() { + return hasProfileSummary() && + Summary->getKind() == ProfileSummary::PSK_Sample && + (PartialProfile || Summary->isPartialProfile()); +} + INITIALIZE_PASS(ProfileSummaryInfoWrapperPass, "profile-summary-info", "Profile summary info", false, true) diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp --- a/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -177,6 +177,17 @@ "profile-guided-section-prefix", cl::Hidden, cl::init(true), cl::ZeroOrMore, cl::desc("Use profile info to add section prefix for hot/cold functions")); +static cl::opt ProfileUnknownInSpecialSection( + "profile-unknown-in-special-section", cl::Hidden, cl::init(false), + cl::ZeroOrMore, + cl::desc("In profiling mode like sampleFDO, if a function doesn't have " + "profile, we cannot tell the function is cold for sure because " + "it may be a function newly added without ever being sampled. " + "With the flag enabled, compiler can put such profile unknown " + "functions into a special section, so runtime system can choose " + "to handle it in a different way than .text section, to save " + "RAM for example. ")); + static cl::opt FreqRatioToSkipMerge( "cgp-freq-ratio-to-skip-merge", cl::Hidden, cl::init(2), cl::desc("Skip merging empty blocks if (frequency of empty block) / " @@ -452,6 +463,9 @@ F.setSectionPrefix(".hot"); else if (PSI->isFunctionColdInCallGraph(&F, *BFI)) F.setSectionPrefix(".unlikely"); + else if (ProfileUnknownInSpecialSection && PSI->hasPartialSampleProfile() && + PSI->isFunctionHotnessUnknown(F)) + F.setSectionPrefix(".unknown"); } /// This optimization identifies DIV instructions that can be diff --git a/llvm/test/Transforms/SampleProfile/section-accurate-samplepgo.ll b/llvm/test/Transforms/SampleProfile/section-accurate-samplepgo.ll --- a/llvm/test/Transforms/SampleProfile/section-accurate-samplepgo.ll +++ b/llvm/test/Transforms/SampleProfile/section-accurate-samplepgo.ll @@ -1,5 +1,6 @@ ; REQUIRES: x86-registered-target ; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.prof -codegenprepare -S | FileCheck %s +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.prof -codegenprepare -profile-unknown-in-special-section -partial-profile -S | FileCheck %s --check-prefix UNKNOWN ; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.prof -codegenprepare -profile-sample-accurate -S | FileCheck %s --check-prefix ACCURATE target triple = "x86_64-pc-linux-gnu" @@ -11,7 +12,8 @@ declare void @hot_func() ; CHECK-NOT: foo_not_in_profile{{.*}}!section_prefix -; CHECK: foo_not_in_profile{{.*}}!prof ![[UNKNOWN_ID:[0-9]+]] +; CHECK: foo_not_in_profile{{.*}}!prof ![[NOPROFILE_ID:[0-9]+]] +; UNKNOWN: foo_not_in_profile{{.*}}!prof ![[NOPROFILE_ID:[0-9]+]] !section_prefix ![[UNKNOWN_ID:[0-9]+]] ; ACCURATE: foo_not_in_profile{{.*}}!prof ![[ZERO_ID:[0-9]+]] !section_prefix ![[COLD_ID:[0-9]+]] ; The function not appearing in profile is cold when -profile-sample-accurate ; is on. @@ -31,9 +33,11 @@ attributes #0 = { "profile-sample-accurate" } -; CHECK: ![[UNKNOWN_ID]] = !{!"function_entry_count", i64 -1} +; CHECK: ![[NOPROFILE_ID]] = !{!"function_entry_count", i64 -1} ; CHECK: ![[ZERO_ID]] = !{!"function_entry_count", i64 0} ; CHECK: ![[COLD_ID]] = !{!"function_section_prefix", !".unlikely"} +; UNKNOWN: ![[NOPROFILE_ID]] = !{!"function_entry_count", i64 -1} +; UNKNOWN: ![[UNKNOWN_ID]] = !{!"function_section_prefix", !".unknown"} ; ACCURATE: ![[ZERO_ID]] = !{!"function_entry_count", i64 0} ; ACCURATE: ![[COLD_ID]] = !{!"function_section_prefix", !".unlikely"} !llvm.module.flags = !{!1}