Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BOLT] Extend profile stats pass #96969

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

ShatianWang
Copy link
Contributor

@ShatianWang ShatianWang commented Jun 27, 2024

The original profile stats pass in BOLT reports 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.

@llvmbot
Copy link
Collaborator

llvmbot commented Jun 27, 2024

@llvm/pr-subscribers-bolt

Author: ShatianWang (ShatianWang)

Changes

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 --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]

@ShatianWang ShatianWang marked this pull request as ready for review June 27, 2024 22:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants