[llvm] [BOLT] Extend profile stats pass (PR #96969)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 27 14:42:38 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-bolt
Author: ShatianWang (ShatianWang)
<details>
<summary>Changes</summary>
The original profile stats pass in BOLT reports profile a bias score together with a standard deviation for the entire profile. We added a flag `print-bucketed-profile-stats` that when used together with the original flag `print-profile-stats` will print additional profile quality metrics evaluating the profile against three characteristics that a perfect profile would have.
---
Patch is 38.71 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/96969.diff
4 Files Affected:
- (added) bolt/include/bolt/Passes/ProfileStats.h (+33)
- (modified) bolt/lib/Passes/BinaryPasses.cpp (+2-90)
- (modified) bolt/lib/Passes/CMakeLists.txt (+1)
- (added) bolt/lib/Passes/ProfileStats.cpp (+817)
``````````diff
diff --git a/bolt/include/bolt/Passes/ProfileStats.h b/bolt/include/bolt/Passes/ProfileStats.h
new file mode 100644
index 0000000000000..1f22603141bcc
--- /dev/null
+++ b/bolt/include/bolt/Passes/ProfileStats.h
@@ -0,0 +1,33 @@
+//===- bolt/Passes/ProfileStats.h - profile quality metrics ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Functions to print profile stats to quantify profile quality.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BOLT_PASSES_PROFILESTATS_H
+#define BOLT_PASSES_PROFILESTATS_H
+
+#include <vector>
+
+namespace llvm {
+
+class raw_ostream;
+
+namespace bolt {
+class BinaryContext;
+namespace ProfileStats {
+
+/// Calculate and print various metrics related to profile quality
+void printAll(raw_ostream &OS, BinaryContext &BC);
+
+} // namespace ProfileStats
+} // namespace bolt
+} // namespace llvm
+
+#endif // BOLT_PASSES_PROFILESTATS_H
diff --git a/bolt/lib/Passes/BinaryPasses.cpp b/bolt/lib/Passes/BinaryPasses.cpp
index ecc2c08a30324..027e66b54f334 100644
--- a/bolt/lib/Passes/BinaryPasses.cpp
+++ b/bolt/lib/Passes/BinaryPasses.cpp
@@ -13,6 +13,7 @@
#include "bolt/Passes/BinaryPasses.h"
#include "bolt/Core/FunctionLayout.h"
#include "bolt/Core/ParallelUtilities.h"
+#include "bolt/Passes/ProfileStats.h"
#include "bolt/Passes/ReorderAlgorithm.h"
#include "bolt/Passes/ReorderFunctions.h"
#include "llvm/Support/CommandLine.h"
@@ -1280,96 +1281,7 @@ Error AssignSections::runOnFunctions(BinaryContext &BC) {
}
Error PrintProfileStats::runOnFunctions(BinaryContext &BC) {
- double FlowImbalanceMean = 0.0;
- size_t NumBlocksConsidered = 0;
- double WorstBias = 0.0;
- const BinaryFunction *WorstBiasFunc = nullptr;
-
- // For each function CFG, we fill an IncomingMap with the sum of the frequency
- // of incoming edges for each BB. Likewise for each OutgoingMap and the sum
- // of the frequency of outgoing edges.
- using FlowMapTy = std::unordered_map<const BinaryBasicBlock *, uint64_t>;
- std::unordered_map<const BinaryFunction *, FlowMapTy> TotalIncomingMaps;
- std::unordered_map<const BinaryFunction *, FlowMapTy> TotalOutgoingMaps;
-
- // Compute mean
- for (const auto &BFI : BC.getBinaryFunctions()) {
- const BinaryFunction &Function = BFI.second;
- if (Function.empty() || !Function.isSimple())
- continue;
- FlowMapTy &IncomingMap = TotalIncomingMaps[&Function];
- FlowMapTy &OutgoingMap = TotalOutgoingMaps[&Function];
- for (const BinaryBasicBlock &BB : Function) {
- uint64_t TotalOutgoing = 0ULL;
- auto SuccBIIter = BB.branch_info_begin();
- for (BinaryBasicBlock *Succ : BB.successors()) {
- uint64_t Count = SuccBIIter->Count;
- if (Count == BinaryBasicBlock::COUNT_NO_PROFILE || Count == 0) {
- ++SuccBIIter;
- continue;
- }
- TotalOutgoing += Count;
- IncomingMap[Succ] += Count;
- ++SuccBIIter;
- }
- OutgoingMap[&BB] = TotalOutgoing;
- }
-
- size_t NumBlocks = 0;
- double Mean = 0.0;
- for (const BinaryBasicBlock &BB : Function) {
- // Do not compute score for low frequency blocks, entry or exit blocks
- if (IncomingMap[&BB] < 100 || OutgoingMap[&BB] == 0 || BB.isEntryPoint())
- continue;
- ++NumBlocks;
- const double Difference = (double)OutgoingMap[&BB] - IncomingMap[&BB];
- Mean += fabs(Difference / IncomingMap[&BB]);
- }
-
- FlowImbalanceMean += Mean;
- NumBlocksConsidered += NumBlocks;
- if (!NumBlocks)
- continue;
- double FuncMean = Mean / NumBlocks;
- if (FuncMean > WorstBias) {
- WorstBias = FuncMean;
- WorstBiasFunc = &Function;
- }
- }
- if (NumBlocksConsidered > 0)
- FlowImbalanceMean /= NumBlocksConsidered;
-
- // Compute standard deviation
- NumBlocksConsidered = 0;
- double FlowImbalanceVar = 0.0;
- for (const auto &BFI : BC.getBinaryFunctions()) {
- const BinaryFunction &Function = BFI.second;
- if (Function.empty() || !Function.isSimple())
- continue;
- FlowMapTy &IncomingMap = TotalIncomingMaps[&Function];
- FlowMapTy &OutgoingMap = TotalOutgoingMaps[&Function];
- for (const BinaryBasicBlock &BB : Function) {
- if (IncomingMap[&BB] < 100 || OutgoingMap[&BB] == 0)
- continue;
- ++NumBlocksConsidered;
- const double Difference = (double)OutgoingMap[&BB] - IncomingMap[&BB];
- FlowImbalanceVar +=
- pow(fabs(Difference / IncomingMap[&BB]) - FlowImbalanceMean, 2);
- }
- }
- if (NumBlocksConsidered) {
- FlowImbalanceVar /= NumBlocksConsidered;
- FlowImbalanceVar = sqrt(FlowImbalanceVar);
- }
-
- // Report to user
- BC.outs() << format("BOLT-INFO: Profile bias score: %.4lf%% StDev: %.4lf%%\n",
- (100.0 * FlowImbalanceMean), (100.0 * FlowImbalanceVar));
- if (WorstBiasFunc && opts::Verbosity >= 1) {
- BC.outs() << "Worst average bias observed in "
- << WorstBiasFunc->getPrintName() << "\n";
- LLVM_DEBUG(WorstBiasFunc->dump());
- }
+ ProfileStats::printAll(BC.outs(), BC);
return Error::success();
}
diff --git a/bolt/lib/Passes/CMakeLists.txt b/bolt/lib/Passes/CMakeLists.txt
index 04057a895d666..87e3c5498f284 100644
--- a/bolt/lib/Passes/CMakeLists.txt
+++ b/bolt/lib/Passes/CMakeLists.txt
@@ -29,6 +29,7 @@ add_llvm_library(LLVMBOLTPasses
PatchEntries.cpp
PettisAndHansen.cpp
PLTCall.cpp
+ ProfileStats.cpp
RegAnalysis.cpp
RegReAssign.cpp
ReorderAlgorithm.cpp
diff --git a/bolt/lib/Passes/ProfileStats.cpp b/bolt/lib/Passes/ProfileStats.cpp
new file mode 100644
index 0000000000000..cab9215b9462b
--- /dev/null
+++ b/bolt/lib/Passes/ProfileStats.cpp
@@ -0,0 +1,817 @@
+//===- bolt/Passes/ProfileStats.cpp - profile quality metrics ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Functions to print profile stats to quantify profile quality.
+//
+//===----------------------------------------------------------------------===//
+
+#include "bolt/Passes/ProfileStats.h"
+#include "bolt/Core/BinaryBasicBlock.h"
+#include "bolt/Core/BinaryFunction.h"
+#include "bolt/Utils/CommandLineOpts.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/raw_ostream.h"
+#include <queue>
+#include <unordered_map>
+#include <unordered_set>
+
+#define DEBUG_TYPE "bolt-opts"
+
+using namespace llvm;
+using namespace bolt;
+
+namespace opts {
+extern cl::opt<unsigned> Verbosity;
+cl::opt<bool> PrintBucketedMetrics(
+ "print-bucketed-profile-stats",
+ cl::desc("print profile quality stats for buckets of functions created "
+ "based on their execution counts."),
+ cl::Hidden, cl::cat(BoltCategory));
+cl::opt<unsigned>
+ NumFunctionsPerBucket("num-functions-per-bucket",
+ cl::desc("Maximum number of functions per bucket."),
+ cl::init(500), cl::ZeroOrMore, cl::Hidden,
+ cl::cat(BoltOptCategory));
+cl::opt<unsigned> NumTopFunctions(
+ "num-top-functions",
+ cl::desc(
+ "Number of hottest functions to print aggregated profile stats of."),
+ cl::init(1000), cl::ZeroOrMore, cl::Hidden, cl::cat(BoltOptCategory));
+cl::opt<unsigned>
+ BBECThreshold("bbec-threshold",
+ cl::desc("Minimum execution count of a basic block for it to "
+ "be considered for profile stats computation."),
+ cl::init(100), cl::ZeroOrMore, cl::Hidden,
+ cl::cat(BoltOptCategory));
+} // namespace opts
+
+namespace {
+void printProfileBiasScore(raw_ostream &OS, BinaryContext &BC) {
+ double FlowImbalanceMean = 0.0;
+ size_t NumBlocksConsidered = 0;
+ double WorstBias = 0.0;
+ const BinaryFunction *WorstBiasFunc = nullptr;
+
+ // For each function CFG, we fill an IncomingMap with the sum of the frequency
+ // of incoming edges for each BB. Likewise for each OutgoingMap and the sum
+ // of the frequency of outgoing edges.
+ using FlowMapTy = std::unordered_map<const BinaryBasicBlock *, uint64_t>;
+ std::unordered_map<const BinaryFunction *, FlowMapTy> TotalIncomingMaps;
+ std::unordered_map<const BinaryFunction *, FlowMapTy> TotalOutgoingMaps;
+
+ // Compute mean
+ for (const auto &BFI : BC.getBinaryFunctions()) {
+ const BinaryFunction &Function = BFI.second;
+ if (Function.empty() || !Function.isSimple())
+ continue;
+ FlowMapTy &IncomingMap = TotalIncomingMaps[&Function];
+ FlowMapTy &OutgoingMap = TotalOutgoingMaps[&Function];
+ for (const BinaryBasicBlock &BB : Function) {
+ uint64_t TotalOutgoing = 0ULL;
+ auto SuccBIIter = BB.branch_info_begin();
+ for (BinaryBasicBlock *Succ : BB.successors()) {
+ uint64_t Count = SuccBIIter->Count;
+ if (Count == BinaryBasicBlock::COUNT_NO_PROFILE || Count == 0) {
+ ++SuccBIIter;
+ continue;
+ }
+ TotalOutgoing += Count;
+ IncomingMap[Succ] += Count;
+ ++SuccBIIter;
+ }
+ OutgoingMap[&BB] = TotalOutgoing;
+ }
+
+ size_t NumBlocks = 0;
+ double Mean = 0.0;
+ for (const BinaryBasicBlock &BB : Function) {
+ // Do not compute score for low frequency blocks, entry or exit blocks
+ if (IncomingMap[&BB] < 100 || OutgoingMap[&BB] == 0 || BB.isEntryPoint())
+ continue;
+ ++NumBlocks;
+ const double Difference = (double)OutgoingMap[&BB] - IncomingMap[&BB];
+ Mean += fabs(Difference / IncomingMap[&BB]);
+ }
+
+ FlowImbalanceMean += Mean;
+ NumBlocksConsidered += NumBlocks;
+ if (!NumBlocks)
+ continue;
+ double FuncMean = Mean / NumBlocks;
+ if (FuncMean > WorstBias) {
+ WorstBias = FuncMean;
+ WorstBiasFunc = &Function;
+ }
+ }
+ if (NumBlocksConsidered > 0)
+ FlowImbalanceMean /= NumBlocksConsidered;
+
+ // Compute standard deviation
+ NumBlocksConsidered = 0;
+ double FlowImbalanceVar = 0.0;
+ for (const auto &BFI : BC.getBinaryFunctions()) {
+ const BinaryFunction &Function = BFI.second;
+ if (Function.empty() || !Function.isSimple())
+ continue;
+ FlowMapTy &IncomingMap = TotalIncomingMaps[&Function];
+ FlowMapTy &OutgoingMap = TotalOutgoingMaps[&Function];
+ for (const BinaryBasicBlock &BB : Function) {
+ if (IncomingMap[&BB] < 100 || OutgoingMap[&BB] == 0)
+ continue;
+ ++NumBlocksConsidered;
+ const double Difference = (double)OutgoingMap[&BB] - IncomingMap[&BB];
+ FlowImbalanceVar +=
+ pow(fabs(Difference / IncomingMap[&BB]) - FlowImbalanceMean, 2);
+ }
+ }
+ if (NumBlocksConsidered) {
+ FlowImbalanceVar /= NumBlocksConsidered;
+ FlowImbalanceVar = sqrt(FlowImbalanceVar);
+ }
+
+ // Report to user
+ OS << format("BOLT-INFO: Profile bias score: %.4lf%% StDev: %.4lf%%\n",
+ (100.0 * FlowImbalanceMean), (100.0 * FlowImbalanceVar));
+ if (WorstBiasFunc && opts::Verbosity >= 1) {
+ OS << "Worst average bias observed in " << WorstBiasFunc->getPrintName()
+ << "\n";
+ LLVM_DEBUG(WorstBiasFunc->dump());
+ }
+}
+
+using FunctionListType = std::vector<const BinaryFunction *>;
+using function_iterator = FunctionListType::iterator;
+using FlowMapTy = std::unordered_map<const BinaryBasicBlock *, uint64_t>;
+using TotalFlowMapTy = std::unordered_map<const BinaryFunction *, FlowMapTy>;
+using FunctionFlowMapTy = std::unordered_map<const BinaryFunction *, uint64_t>;
+
+struct FlowInfo {
+ TotalFlowMapTy TotalIncomingMaps;
+ TotalFlowMapTy TotalOutgoingMaps;
+ TotalFlowMapTy TotalIECMaps;
+ TotalFlowMapTy TotalMaxCallMaps;
+ FunctionFlowMapTy CallGraphIncomingMap;
+};
+
+template <typename T>
+void printDistribution(raw_ostream &OS, std::vector<T> &values,
+ bool Fraction = false) {
+ if (values.empty())
+ return;
+ // Sort values from largest to smallest and print the MAX, TOP 1%, 5%, 10%,
+ // 20%, 50%, 80%, MIN. If Fraction is true, then values are printed as
+ // fractions instead of integers.
+ std::sort(values.begin(), values.end());
+
+ auto printLine = [&](std::string Text, double Percent) {
+ int Rank = int(values.size() * (1.0 - Percent / 100));
+ if (Percent == 0)
+ Rank = values.size() - 1;
+ if (Fraction)
+ OS << " " << Text << std::string(9 - Text.length(), ' ') << ": "
+ << format("%.2lf%%", values[Rank] * 100) << "\n";
+ else
+ OS << " " << Text << std::string(9 - Text.length(), ' ') << ": "
+ << values[Rank] << "\n";
+ };
+
+ printLine("MAX", 0);
+ int percentages[] = {1, 5, 10, 20, 50, 80};
+ for (size_t i = 0; i < sizeof(percentages) / sizeof(percentages[0]); ++i) {
+ printLine("TOP " + std::to_string(percentages[i]) + "%", percentages[i]);
+ }
+ printLine("MIN", 100);
+}
+
+void printKECMetrics(raw_ostream &OS,
+ iterator_range<function_iterator> &Functions,
+ size_t BBECThreshold, FlowInfo &TotalFlowMap) {
+ // Each BB's Inferred Execution Count (IEC) equals to the max of its
+ // inflow, outflow, and individual call counts (if any).
+ // For each BB, its KEC = BinaryBasicBlock::getKnownExecutionCount() should be
+ // equal to its IEC in a perfect profile.
+ TotalFlowMapTy &TotalIECMaps = TotalFlowMap.TotalIECMaps;
+ size_t NumConsideredBBs = 0;
+ std::vector<size_t> PosDiffs;
+ for (auto it = Functions.begin(); it != Functions.end(); ++it) {
+ const BinaryFunction *Function = *it;
+ if (Function->size() <= 1)
+ continue;
+ FlowMapTy &IECMap = TotalIECMaps[Function];
+ for (const BinaryBasicBlock &BB : *Function) {
+ size_t IEC = IECMap[&BB];
+ size_t KEC = BB.getKnownExecutionCount();
+ size_t BBEC = std::max(IEC, KEC);
+ // Do not consider low frequency blocks.
+ // A low frequency block is a block whose max(IEC, KEC) is below a given
+ // threshold.
+ if (BBEC < BBECThreshold)
+ continue;
+ NumConsideredBBs++;
+ if (IEC <= KEC)
+ continue;
+ PosDiffs.push_back(IEC - KEC);
+ }
+ }
+ OS << "-------------------------------------------------------\n"
+ << "Metric 1: KEC <> IEC\n"
+ << "-------------------------------------------------------\n";
+ if (NumConsideredBBs == 0) {
+ OS << " No BBs considered for this metric.\n";
+ } else {
+ OS << format("- %zu (%.2lf%%) of considered BBs have IEC > KEC\n",
+ PosDiffs.size(),
+ 100.0 * (double)PosDiffs.size() / NumConsideredBBs);
+
+ if (!PosDiffs.empty()) {
+ OS << "- Distribution of (IEC - KEC) among considered BBs with IEC > "
+ "KEC\n";
+ printDistribution(OS, PosDiffs);
+ }
+ }
+}
+
+void printFlowConservationMetrics(raw_ostream &OS,
+ iterator_range<function_iterator> &Functions,
+ size_t BBECThreshold,
+ FlowInfo &TotalFlowMap) {
+ // Each non-entry non-exit BB should have its inflow equal to its outflow in a
+ // perfect profile.
+ TotalFlowMapTy &TotalIncomingMaps = TotalFlowMap.TotalIncomingMaps;
+ TotalFlowMapTy &TotalOutgoingMaps = TotalFlowMap.TotalOutgoingMaps;
+ TotalFlowMapTy &TotalIECMaps = TotalFlowMap.TotalIECMaps;
+
+ size_t NumConsideredBBs = 0;
+ size_t NumFocalBBs = 0;
+ std::vector<double> MaxDiffFracs;
+ std::vector<size_t> MaxDiffs;
+ for (auto it = Functions.begin(); it != Functions.end(); ++it) {
+ const BinaryFunction *Function = *it;
+ if (Function->size() <= 1)
+ continue;
+ FlowMapTy &IncomingMap = TotalIncomingMaps[Function];
+ FlowMapTy &OutgoingMap = TotalOutgoingMaps[Function];
+ FlowMapTy &IECMap = TotalIECMaps[Function];
+
+ size_t MaxDifference = 0.0;
+ double MaxDiffFrac = 0.0;
+ for (const BinaryBasicBlock &BB : *Function) {
+ size_t BBEC = std::max(IECMap[&BB], BB.getKnownExecutionCount());
+ // Do not consider low frequency blocks.
+ if (BBEC < BBECThreshold)
+ continue;
+ NumConsideredBBs++;
+ // Do not consider entry or exit blocks.
+ if (BB.succ_size() == 0 || BB.isEntryPoint())
+ continue;
+ NumFocalBBs++;
+
+ size_t LHS = IncomingMap[&BB];
+ size_t RHS = OutgoingMap[&BB];
+
+ size_t MIN = std::min(LHS, RHS);
+ size_t MAX = std::max(LHS, RHS);
+ const size_t Difference = MAX - MIN;
+ double DiffFrac = 0.0;
+ if (MAX > 0)
+ DiffFrac = (double)Difference / MAX;
+ if (DiffFrac > MaxDiffFrac)
+ MaxDiffFrac = DiffFrac;
+ if (Difference > MaxDifference)
+ MaxDifference = Difference;
+ if (opts::Verbosity >= 2 && DiffFrac > 0.5 && Difference > 500) {
+ OS << "Big flow conservation violation observed in " << BB.getName()
+ << " in function " << Function->getPrintName() << "\n";
+ LLVM_DEBUG(Function->dump());
+ }
+ }
+ if (NumFocalBBs > 0) {
+ MaxDiffFracs.push_back(MaxDiffFrac);
+ MaxDiffs.push_back(MaxDifference);
+ }
+ }
+
+ OS << "-------------------------------------------------------\n"
+ << "Metric 2: BB inflow <> BB outflow\n"
+ << "-------------------------------------------------------\n";
+ if (NumFocalBBs == 0) {
+ OS << " No BBs considered for this metric.\n";
+ } else {
+ OS << format("Focus on %zu (%.2lf%%) of considered BBs that are neither "
+ "function entries nor exits\n",
+ NumFocalBBs, 100.0 * (double)NumFocalBBs / NumConsideredBBs)
+ << format("Focus on %zu (%.2lf%%) of considered functions that has at "
+ "least 1 focal BBs\n",
+ MaxDiffs.size(),
+ 100.0 * (double)MaxDiffs.size() /
+ (std::distance(Functions.begin(), Functions.end())))
+ << "LHS = BB SUM inflow; RHS = BB SUM outflow\n"
+ << "MAX = MAX(LHS, RHS); MIN = MIN(LHS, RHS)\n";
+
+ if (!MaxDiffFracs.empty()) {
+ OS << "- Distribution of Worst[(MAX - MIN) / MAX] among all considered "
+ "functions\n";
+ printDistribution(OS, MaxDiffFracs, /*Fraction*/ true);
+ }
+ if (!MaxDiffs.empty()) {
+ OS << "- Distribution of Worst[MAX - MIN] among all considered "
+ "functions\n";
+ printDistribution(OS, MaxDiffs);
+ }
+ }
+}
+
+void printFlowCallConservationMetrics(
+ raw_ostream &OS, iterator_range<function_iterator> &Functions,
+ size_t BBECThreshold, FlowInfo &TotalFlowMap) {
+ // Each non-entry non-exit BB that makes function call(s) should have its
+ // max(inflow, outflow) equal to its call count(s) in a perfect profile.
+ TotalFlowMapTy &TotalIncomingMaps = TotalFlowMap.TotalIncomingMaps;
+ TotalFlowMapTy &TotalOutgoingMaps = TotalFlowMap.TotalOutgoingMaps;
+ TotalFlowMapTy &TotalIECMaps = TotalFlowMap.TotalIECMaps;
+ TotalFlowMapTy &TotalMaxCallMaps = TotalFlowMap.TotalMaxCallMaps;
+
+ size_t NumConsideredBBs = 0;
+ size_t NumFocalBBs = 0;
+ std::vector<double> MaxDiffFracs;
+ std::vector<size_t> MaxDiffs;
+ for (auto it = Functions.begin(); it != Functions.end(); ++it) {
+ const BinaryFunction *Function = *it;
+ if (Function->size() <= 1)
+ continue;
+ FlowMapTy &IncomingMap = TotalIncomingMaps[Function];
+ FlowMapTy &OutgoingMap = TotalOutgoingMaps[Function];
+ FlowMapTy &IECMap = TotalIECMaps[Function];
+ FlowMapTy &MaxCallMap = TotalMaxCallMaps[Function];
+
+ size_t MaxDifference = 0.0;
+ double MaxDiffFrac = 0.0;
+ bool FunctionConsidered = false;
+ for (const BinaryBasicBlock &BB : *Function) {
+ size_t BBEC = std::max(IECMap[&BB], BB.getKnownExecutionCount());
+ // Do not consider low frequency blocks.
+ if (BBEC < BBECThreshold)
+ continue;
+ NumConsideredBBs++;
+ // Do not consider BBs that do not make function calls.
+ if (MaxCallMap.find(&BB) == MaxCallMap.end())
+ continue;
+ NumFocalBBs++;
+ FunctionConsidered = true;
+
+ size_t LHS = std::max(IncomingMap[&BB], OutgoingMap[&BB]);
+ size...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/96969
More information about the llvm-commits
mailing list