return true;
}
-// Like isFunctionHotInCallGraph but for a given cutoff.
-bool ProfileSummaryInfo::isFunctionHotInCallGraphNthPercentile(
+template<bool isHot>
+bool ProfileSummaryInfo::isFunctionHotOrColdInCallGraphNthPercentile(
int PercentileCutoff, const Function *F, BlockFrequencyInfo &BFI) {
if (!F || !computeSummary())
return false;
- if (auto FunctionCount = F->getEntryCount())
- if (isHotCountNthPercentile(PercentileCutoff, FunctionCount.getCount()))
+ if (auto FunctionCount = F->getEntryCount()) {
+ if (isHot &&
+ isHotCountNthPercentile(PercentileCutoff, FunctionCount.getCount()))
return true;
-
+ if (!isHot &&
+ !isColdCountNthPercentile(PercentileCutoff, FunctionCount.getCount()))
+ return false;
+ }
if (hasSampleProfile()) {
uint64_t TotalCallCount = 0;
for (const auto &BB : *F)
if (isa<CallInst>(I) || isa<InvokeInst>(I))
if (auto CallCount = getProfileCount(&I, nullptr))
TotalCallCount += CallCount.getValue();
- if (isHotCountNthPercentile(PercentileCutoff, TotalCallCount))
+ if (isHot && isHotCountNthPercentile(PercentileCutoff, TotalCallCount))
return true;
+ if (!isHot && !isColdCountNthPercentile(PercentileCutoff, TotalCallCount))
+ return false;
}
- for (const auto &BB : *F)
- if (isHotBlockNthPercentile(PercentileCutoff, &BB, &BFI))
+ for (const auto &BB : *F) {
+ if (isHot && isHotBlockNthPercentile(PercentileCutoff, &BB, &BFI))
return true;
- return false;
+ if (!isHot && !isColdBlockNthPercentile(PercentileCutoff, &BB, &BFI))
+ return false;
+ }
+ return !isHot;
+}
+
+// Like isFunctionHotInCallGraph but for a given cutoff.
+bool ProfileSummaryInfo::isFunctionHotInCallGraphNthPercentile(
+ int PercentileCutoff, const Function *F, BlockFrequencyInfo &BFI) {
+ return isFunctionHotOrColdInCallGraphNthPercentile<true>(
+ PercentileCutoff, F, BFI);
+}
+
+bool ProfileSummaryInfo::isFunctionColdInCallGraphNthPercentile(
+ int PercentileCutoff, const Function *F, BlockFrequencyInfo &BFI) {
+ return isFunctionHotOrColdInCallGraphNthPercentile<false>(
+ PercentileCutoff, F, BFI);
}
/// Returns true if the function's entry is a cold. If it returns false, it
return ColdCountThreshold && C <= ColdCountThreshold.getValue();
}
-bool ProfileSummaryInfo::isHotCountNthPercentile(int PercentileCutoff, uint64_t C) {
+template<bool isHot>
+bool ProfileSummaryInfo::isHotOrColdCountNthPercentile(int PercentileCutoff,
+ uint64_t C) {
auto CountThreshold = computeThreshold(PercentileCutoff);
- return CountThreshold && C >= CountThreshold.getValue();
+ if (isHot)
+ return CountThreshold && C >= CountThreshold.getValue();
+ else
+ return CountThreshold && C <= CountThreshold.getValue();
+}
+
+bool ProfileSummaryInfo::isHotCountNthPercentile(int PercentileCutoff, uint64_t C) {
+ return isHotOrColdCountNthPercentile<true>(PercentileCutoff, C);
+}
+
+bool ProfileSummaryInfo::isColdCountNthPercentile(int PercentileCutoff, uint64_t C) {
+ return isHotOrColdCountNthPercentile<false>(PercentileCutoff, C);
}
uint64_t ProfileSummaryInfo::getOrCompHotCountThreshold() {
return Count && isColdCount(*Count);
}
+template<bool isHot>
+bool ProfileSummaryInfo::isHotOrColdBlockNthPercentile(int PercentileCutoff,
+ const BasicBlock *BB,
+ BlockFrequencyInfo *BFI) {
+ auto Count = BFI->getBlockProfileCount(BB);
+ if (isHot)
+ return Count && isHotCountNthPercentile(PercentileCutoff, *Count);
+ else
+ return Count && isColdCountNthPercentile(PercentileCutoff, *Count);
+}
+
bool ProfileSummaryInfo::isHotBlockNthPercentile(int PercentileCutoff,
const BasicBlock *BB,
BlockFrequencyInfo *BFI) {
- auto Count = BFI->getBlockProfileCount(BB);
- return Count && isHotCountNthPercentile(PercentileCutoff, *Count);
+ return isHotOrColdBlockNthPercentile<true>(PercentileCutoff, BB, BFI);
+}
+
+bool ProfileSummaryInfo::isColdBlockNthPercentile(int PercentileCutoff,
+ const BasicBlock *BB,
+ BlockFrequencyInfo *BFI) {
+ return isHotOrColdBlockNthPercentile<false>(PercentileCutoff, BB, BFI);
}
bool ProfileSummaryInfo::isHotCallSite(const CallSite &CS,
" %y2 = phi i32 [0, %bb1], [1, %bb2] \n"
" ret i32 %y2\n"
"}\n"
+ "define i32 @l(i32 %x) {{\n"
+ "bb0:\n"
+ " %y1 = icmp eq i32 %x, 0 \n"
+ " br i1 %y1, label %bb1, label %bb2, !prof !23 \n"
+ "bb1:\n"
+ " %z1 = call i32 @g(i32 %x)\n"
+ " br label %bb3\n"
+ "bb2:\n"
+ " %z2 = call i32 @h(i32 %x)\n"
+ " br label %bb3\n"
+ "bb3:\n"
+ " %y2 = phi i32 [0, %bb1], [1, %bb2] \n"
+ " ret i32 %y2\n"
+ "}\n"
"!20 = !{{!\"function_entry_count\", i64 400}\n"
"!21 = !{{!\"function_entry_count\", i64 1}\n"
"!22 = !{{!\"function_entry_count\", i64 100}\n"
EXPECT_FALSE(PSI.isHotCountNthPercentile(990000, 100));
EXPECT_FALSE(PSI.isHotCountNthPercentile(990000, 2));
+ EXPECT_FALSE(PSI.isColdCountNthPercentile(990000, 400));
+ EXPECT_TRUE(PSI.isColdCountNthPercentile(990000, 100));
+ EXPECT_TRUE(PSI.isColdCountNthPercentile(990000, 2));
+
EXPECT_TRUE(PSI.isHotCountNthPercentile(999999, 400));
EXPECT_TRUE(PSI.isHotCountNthPercentile(999999, 100));
EXPECT_FALSE(PSI.isHotCountNthPercentile(999999, 2));
+ EXPECT_FALSE(PSI.isColdCountNthPercentile(999999, 400));
+ EXPECT_FALSE(PSI.isColdCountNthPercentile(999999, 100));
+ EXPECT_TRUE(PSI.isColdCountNthPercentile(999999, 2));
+
EXPECT_FALSE(PSI.isHotCountNthPercentile(10000, 400));
EXPECT_FALSE(PSI.isHotCountNthPercentile(10000, 100));
EXPECT_FALSE(PSI.isHotCountNthPercentile(10000, 2));
+ EXPECT_TRUE(PSI.isColdCountNthPercentile(10000, 400));
+ EXPECT_TRUE(PSI.isColdCountNthPercentile(10000, 100));
+ EXPECT_TRUE(PSI.isColdCountNthPercentile(10000, 2));
+
EXPECT_TRUE(PSI.isFunctionEntryHot(F));
EXPECT_FALSE(PSI.isFunctionEntryHot(G));
EXPECT_FALSE(PSI.isFunctionEntryHot(H));
EXPECT_FALSE(PSI.isHotBlockNthPercentile(990000, BB2, &BFI));
EXPECT_TRUE(PSI.isHotBlockNthPercentile(990000, BB3, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, &BB0, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, BB1, &BFI));
+ EXPECT_TRUE(PSI.isColdBlockNthPercentile(990000, BB2, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, BB3, &BFI));
+
EXPECT_TRUE(PSI.isHotBlockNthPercentile(999900, &BB0, &BFI));
EXPECT_TRUE(PSI.isHotBlockNthPercentile(999900, BB1, &BFI));
EXPECT_TRUE(PSI.isHotBlockNthPercentile(999900, BB2, &BFI));
EXPECT_TRUE(PSI.isHotBlockNthPercentile(999900, BB3, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(999900, &BB0, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(999900, BB1, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(999900, BB2, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(999900, BB3, &BFI));
+
EXPECT_FALSE(PSI.isHotBlockNthPercentile(10000, &BB0, &BFI));
EXPECT_FALSE(PSI.isHotBlockNthPercentile(10000, BB1, &BFI));
EXPECT_FALSE(PSI.isHotBlockNthPercentile(10000, BB2, &BFI));
EXPECT_FALSE(PSI.isHotBlockNthPercentile(10000, BB3, &BFI));
+ EXPECT_TRUE(PSI.isColdBlockNthPercentile(10000, &BB0, &BFI));
+ EXPECT_TRUE(PSI.isColdBlockNthPercentile(10000, BB1, &BFI));
+ EXPECT_TRUE(PSI.isColdBlockNthPercentile(10000, BB2, &BFI));
+ EXPECT_TRUE(PSI.isColdBlockNthPercentile(10000, BB3, &BFI));
+
CallSite CS1(BB1->getFirstNonPHI());
auto *CI2 = BB2->getFirstNonPHI();
CallSite CS2(CI2);
EXPECT_FALSE(PSI.isHotCallSite(CS2, &BFI));
}
+TEST_F(ProfileSummaryInfoTest, InstrProfNoFuncEntryCount) {
+ auto M = makeLLVMModule("InstrProf");
+ Function *F = M->getFunction("l");
+ ProfileSummaryInfo PSI = buildPSI(M.get());
+ EXPECT_TRUE(PSI.hasProfileSummary());
+ EXPECT_TRUE(PSI.hasInstrumentationProfile());
+
+ BasicBlock &BB0 = F->getEntryBlock();
+ BasicBlock *BB1 = BB0.getTerminator()->getSuccessor(0);
+ BasicBlock *BB2 = BB0.getTerminator()->getSuccessor(1);
+ BasicBlock *BB3 = BB1->getSingleSuccessor();
+
+ BlockFrequencyInfo BFI = buildBFI(*F);
+
+ // Without the entry count, all should return false.
+ EXPECT_FALSE(PSI.isHotBlockNthPercentile(990000, &BB0, &BFI));
+ EXPECT_FALSE(PSI.isHotBlockNthPercentile(990000, BB1, &BFI));
+ EXPECT_FALSE(PSI.isHotBlockNthPercentile(990000, BB2, &BFI));
+ EXPECT_FALSE(PSI.isHotBlockNthPercentile(990000, BB3, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, &BB0, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, BB1, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, BB2, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, BB3, &BFI));
+}
+
TEST_F(ProfileSummaryInfoTest, SampleProf) {
auto M = makeLLVMModule("SampleProfile");
Function *F = M->getFunction("f");
EXPECT_FALSE(PSI.isHotBlockNthPercentile(990000, BB2, &BFI));
EXPECT_TRUE(PSI.isHotBlockNthPercentile(990000, BB3, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, &BB0, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, BB1, &BFI));
+ EXPECT_TRUE(PSI.isColdBlockNthPercentile(990000, BB2, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, BB3, &BFI));
+
EXPECT_TRUE(PSI.isHotBlockNthPercentile(999900, &BB0, &BFI));
EXPECT_TRUE(PSI.isHotBlockNthPercentile(999900, BB1, &BFI));
EXPECT_TRUE(PSI.isHotBlockNthPercentile(999900, BB2, &BFI));
EXPECT_TRUE(PSI.isHotBlockNthPercentile(999900, BB3, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(999900, &BB0, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(999900, BB1, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(999900, BB2, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(999900, BB3, &BFI));
+
EXPECT_FALSE(PSI.isHotBlockNthPercentile(10000, &BB0, &BFI));
EXPECT_FALSE(PSI.isHotBlockNthPercentile(10000, BB1, &BFI));
EXPECT_FALSE(PSI.isHotBlockNthPercentile(10000, BB2, &BFI));
EXPECT_FALSE(PSI.isHotBlockNthPercentile(10000, BB3, &BFI));
+ EXPECT_TRUE(PSI.isColdBlockNthPercentile(10000, &BB0, &BFI));
+ EXPECT_TRUE(PSI.isColdBlockNthPercentile(10000, BB1, &BFI));
+ EXPECT_TRUE(PSI.isColdBlockNthPercentile(10000, BB2, &BFI));
+ EXPECT_TRUE(PSI.isColdBlockNthPercentile(10000, BB3, &BFI));
+
CallSite CS1(BB1->getFirstNonPHI());
auto *CI2 = BB2->getFirstNonPHI();
// Manually attach branch weights metadata to the call instruction.
// weights that exceed the hot count threshold.
CI2->setMetadata(llvm::LLVMContext::MD_prof, MDB.createBranchWeights({400}));
EXPECT_TRUE(PSI.isHotCallSite(CS2, &BFI));
+
+ {
+ Function *F = M->getFunction("l");
+ BlockFrequencyInfo BFI = buildBFI(*F);
+ BasicBlock &BB0 = F->getEntryBlock();
+ BasicBlock *BB1 = BB0.getTerminator()->getSuccessor(0);
+ BasicBlock *BB2 = BB0.getTerminator()->getSuccessor(1);
+ BasicBlock *BB3 = BB1->getSingleSuccessor();
+
+ // Without the entry count, all should return false.
+ EXPECT_FALSE(PSI.isHotBlockNthPercentile(990000, &BB0, &BFI));
+ EXPECT_FALSE(PSI.isHotBlockNthPercentile(990000, BB1, &BFI));
+ EXPECT_FALSE(PSI.isHotBlockNthPercentile(990000, BB2, &BFI));
+ EXPECT_FALSE(PSI.isHotBlockNthPercentile(990000, BB3, &BFI));
+
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, &BB0, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, BB1, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, BB2, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, BB3, &BFI));
+ }
+}
+
+TEST_F(ProfileSummaryInfoTest, SampleProfNoFuncEntryCount) {
+ auto M = makeLLVMModule("SampleProfile");
+ Function *F = M->getFunction("l");
+ ProfileSummaryInfo PSI = buildPSI(M.get());
+ EXPECT_TRUE(PSI.hasProfileSummary());
+ EXPECT_TRUE(PSI.hasSampleProfile());
+
+ BasicBlock &BB0 = F->getEntryBlock();
+ BasicBlock *BB1 = BB0.getTerminator()->getSuccessor(0);
+ BasicBlock *BB2 = BB0.getTerminator()->getSuccessor(1);
+ BasicBlock *BB3 = BB1->getSingleSuccessor();
+
+ BlockFrequencyInfo BFI = buildBFI(*F);
+
+ // Without the entry count, all should return false.
+ EXPECT_FALSE(PSI.isHotBlockNthPercentile(990000, &BB0, &BFI));
+ EXPECT_FALSE(PSI.isHotBlockNthPercentile(990000, BB1, &BFI));
+ EXPECT_FALSE(PSI.isHotBlockNthPercentile(990000, BB2, &BFI));
+ EXPECT_FALSE(PSI.isHotBlockNthPercentile(990000, BB3, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, &BB0, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, BB1, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, BB2, &BFI));
+ EXPECT_FALSE(PSI.isColdBlockNthPercentile(990000, BB3, &BFI));
}
} // end anonymous namespace