[llvm] [llvm-profgen] Add pgo accuracy metrics (PR #93975)

via llvm-commits llvm-commits at lists.llvm.org
Fri May 31 08:34:18 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-pgo

Author: None (lifengxiang1025)

<details>
<summary>Changes</summary>

Emit pgo accuracy metrics by comparing branch probability in bbaddrmap section and branch probability calculated by perf sampling.

---
Full diff: https://github.com/llvm/llvm-project/pull/93975.diff


9 Files Affected:

- (added) llvm/test/tools/llvm-profgen/Inputs/pgo-accuracy-metrics.perfbin () 
- (added) llvm/test/tools/llvm-profgen/Inputs/pgo-accuracy-metrics.perfscrpit (+2) 
- (added) llvm/test/tools/llvm-profgen/pgo-accuracy-metrics.test (+24) 
- (modified) llvm/tools/llvm-profgen/CMakeLists.txt (+1) 
- (added) llvm/tools/llvm-profgen/PGOAccuracyMetrics.cpp (+106) 
- (added) llvm/tools/llvm-profgen/PGOAccuracyMetrics.h (+45) 
- (modified) llvm/tools/llvm-profgen/ProfiledBinary.cpp (+8) 
- (modified) llvm/tools/llvm-profgen/ProfiledBinary.h (+10) 
- (modified) llvm/tools/llvm-profgen/llvm-profgen.cpp (+13) 


``````````diff
diff --git a/llvm/test/tools/llvm-profgen/Inputs/pgo-accuracy-metrics.perfbin b/llvm/test/tools/llvm-profgen/Inputs/pgo-accuracy-metrics.perfbin
new file mode 100755
index 0000000000000..7ae145c299adb
Binary files /dev/null and b/llvm/test/tools/llvm-profgen/Inputs/pgo-accuracy-metrics.perfbin differ
diff --git a/llvm/test/tools/llvm-profgen/Inputs/pgo-accuracy-metrics.perfscrpit b/llvm/test/tools/llvm-profgen/Inputs/pgo-accuracy-metrics.perfscrpit
new file mode 100644
index 0000000000000..7152093802751
--- /dev/null
+++ b/llvm/test/tools/llvm-profgen/Inputs/pgo-accuracy-metrics.perfscrpit
@@ -0,0 +1,2 @@
+PERF_RECORD_MMAP2 36922/36922: [0x5592aaa7f000(0x1000) @ 0x1000 08:10 26214013168 3588669473]: r-xp /pgo-accuracy-metrics.perfbin
+     5592aaa7f1fa 0x7f2ed752662d/0x7f2ed7526850/P/-/-/3  0x7f2ed7526602/0x7f2ed7526614/P/-/-/1  0x7f2ed7526b34/0x7f2ed75265f0/P/-/-/1  0x5592aaa7f080/0x7f2ed7526b30/P/-/-/1  0x5592aaa7f1ed/0x5592aaa7f080/P/-/-/1  0x5592aaa7f21e/0x5592aaa7f1e4/P/-/-/1  0x5592aaa7f213/0x5592aaa7f215/P/-/-/1  0x5592aaa7f1fd/0x5592aaa7f20a/P/-/-/15  0x7f2ed7526b3d/0x5592aaa7f1f2/P/-/-/1  0x7f2ed752665f/0x7f2ed7526b39/P/-/-/1  0x7f2ed7526639/0x7f2ed752664a/P/-/-/1  0x7f2ed752689d/0x7f2ed7526632/P/-/-/6  0x7f2ed752662d/0x7f2ed7526850/P/-/-/3  0x7f2ed7526602/0x7f2ed7526614/P/-/-/1  0x7f2ed7526b34/0x7f2ed75265f0/P/-/-/1  0x5592aaa7f080/0x7f2ed7526b30/P/-/-/1  0x5592aaa7f1ed/0x5592aaa7f080/P/-/-/1  0x5592aaa7f21e/0x5592aaa7f1e4/P/-/-/1  0x5592aaa7f213/0x5592aaa7f215/P/-/-/1  0x5592aaa7f1fd/0x5592aaa7f20a/P/-/-/15  0x7f2ed7526b3d/0x5592aaa7f1f2/P/-/-/1  0x7f2ed752665f/0x7f2ed7526b39/P/-/-/1  0x7f2ed7526639/0x7f2ed752664a/P/-/-/1  0x7f2ed752689d/0x7f2ed7526632/P/-/-/6  0x7f2ed752662d/0x7f2ed7526850/P/-/-/3  0x7f2ed7526602/0x7f2ed7526614/P/-/-/1  0x7f2ed7526b34/0x7f2ed75265f0/P/-/-/1  0x5592aaa7f080/0x7f2ed7526b30/P/-/-/1  0x5592aaa7f1ed/0x5592aaa7f080/P/-/-/1  0x5592aaa7f21e/0x5592aaa7f1e4/P/-/-/1  0x5592aaa7f213/0x5592aaa7f215/P/-/-/1  0x5592aaa7f1fd/0x5592aaa7f20a/P/-/-/14 
diff --git a/llvm/test/tools/llvm-profgen/pgo-accuracy-metrics.test b/llvm/test/tools/llvm-profgen/pgo-accuracy-metrics.test
new file mode 100644
index 0000000000000..b4fd875bd704e
--- /dev/null
+++ b/llvm/test/tools/llvm-profgen/pgo-accuracy-metrics.test
@@ -0,0 +1,24 @@
+; Test pgo accuracy metrics
+; RUN: llvm-profgen --perfscript=%S/Inputs/pgo-accuracy-metrics.perfscript --binary=%S/Inputs/pgo-accuracy-metrics.perfbin --output=%t --pgo-accuracy-metrics 2>&1 | FileCheck %s --check-prefix=CHECK-STATS
+
+; CHECK-STATS: UnknownBranches: 0
+; CHECK-STATS: MatchedBranches: 5
+; CHECK-STATS: DismatchedBranches: 4
+
+; Original code:
+; clang++ test.cpp  -g -fbasic-block-sections=labels -mllvm -pgo-analysis-map=br-prob
+
+#include <iostream>
+#include <random>
+int main() {
+    int a = 0;
+    int b = 0;
+    for (int i = 0; i < 100000000; ++i) {
+        if (rand() % 1) {
+            ++a;
+        } else {
+            ++b;
+        }
+    }
+    return 0;
+}
diff --git a/llvm/tools/llvm-profgen/CMakeLists.txt b/llvm/tools/llvm-profgen/CMakeLists.txt
index 354c63f409ffe..af8ea240f8a54 100644
--- a/llvm/tools/llvm-profgen/CMakeLists.txt
+++ b/llvm/tools/llvm-profgen/CMakeLists.txt
@@ -22,4 +22,5 @@ add_llvm_tool(llvm-profgen
   ProfiledBinary.cpp
   ProfileGenerator.cpp
   MissingFrameInferrer.cpp
+  PGOAccuracyMetrics.cpp
   )
diff --git a/llvm/tools/llvm-profgen/PGOAccuracyMetrics.cpp b/llvm/tools/llvm-profgen/PGOAccuracyMetrics.cpp
new file mode 100644
index 0000000000000..2c9394805e072
--- /dev/null
+++ b/llvm/tools/llvm-profgen/PGOAccuracyMetrics.cpp
@@ -0,0 +1,106 @@
+#include "PGOAccuracyMetrics.h"
+static cl::opt<double> BranchProbabilityThreshold(
+    "pgo-accuracy-metrics-branch-probability-threshold",
+    cl::desc("PGO accuracy metrics branch probability threshold"),
+    cl::init(20.0));
+
+namespace llvm {
+namespace sampleprof {
+
+void PGOAccuracyMetrics::init() {
+  for (auto &Function : BBAddrMaps) {
+    for (auto &Range : Function.getBBRanges()) {
+      uint64_t BaseAddress = Range.BaseAddress;
+      for (auto &BB : Range.BBEntries) {
+        uint64_t Address = BaseAddress + BB.Offset;
+        BBAddrToID[Address] =
+            std::make_pair(Function.getFunctionAddress(), BB.ID);
+      }
+    }
+  }
+
+  for (auto It : SampleCounters) {
+    const RangeSample &RangeCounter = It.second.RangeCounter;
+    const BranchSample &BranchCounter = It.second.BranchCounter;
+
+    for (auto Item : RangeCounter) {
+      auto From = BBAddrToID.lower_bound(Item.first.first);
+      auto End = BBAddrToID.upper_bound(Item.first.second);
+      if (From == End)
+        continue;
+      for (auto To = std::next(From); To != End; ++To) {
+        assert(From->second.first == To->second.first);
+        EdgeCounter[From->second.first]
+                   [std::make_pair(From->second.second, To->second.second)] +=
+            Item.second;
+        From = To;
+      }
+    }
+
+    for (auto Item : BranchCounter) {
+      auto Ptr = BBAddrToID.upper_bound(Item.first.first);
+      if (Ptr == BBAddrToID.begin())
+        continue;
+      auto From = std::prev(Ptr)->second;
+      auto To = BBAddrToID[Item.first.second];
+      assert(From.first == To.first);
+      EdgeCounter[From.first][{From.second, To.second}] += Item.second;
+    }
+  }
+}
+
+void PGOAccuracyMetrics::emitPGOAccuracyMetrics() {
+  assert(BBAddrMaps.size() == PGOAnalysisMaps.size());
+
+  for (uint64_t I = 0; I < BBAddrMaps.size(); ++I) {
+    auto &BBAddrMap = BBAddrMaps[I];
+    auto &PGOAnalysisMap = PGOAnalysisMaps[I];
+    assert(BBAddrMap.getNumBBEntries() == PGOAnalysisMap.BBEntries.size());
+    size_t Pos = 0;
+    for (auto &Range : BBAddrMap.getBBRanges()) {
+      for (auto &BB : Range.BBEntries) {
+        uint64_t Sum = 0;
+        for (auto Successor : PGOAnalysisMap.BBEntries[Pos].Successors) {
+          Sum += EdgeCounter[BBAddrMap.getFunctionAddress()]
+                            [std::make_pair(BB.ID, Successor.ID)];
+        }
+
+        for (auto Successor : PGOAnalysisMap.BBEntries[Pos].Successors) {
+          if (Successor.Prob.isUnknown()) {
+            ++UnknownBranches;
+            continue;
+          }
+          double SampleBranchProb =
+              rint((Sum == 0
+                        ? (double)1 /
+                              PGOAnalysisMap.BBEntries[Pos].Successors.size()
+                        : (double)EdgeCounter[BBAddrMap.getFunctionAddress()]
+                                             [std::make_pair(BB.ID,
+                                                             Successor.ID)] /
+                              Sum) *
+                   100.0 * 100.0) /
+              100.0;
+          double RecordBranchProb =
+              rint(((double)Successor.Prob.getNumerator() /
+                    Successor.Prob.getDenominator()) *
+                   100.0 * 100.0) /
+              100.0;
+          if (abs(SampleBranchProb - RecordBranchProb) <
+              BranchProbabilityThreshold) {
+            ++MatchedBranches;
+          } else {
+            ++DismatchedBranches;
+          }
+        }
+        ++Pos;
+      }
+    }
+  }
+
+  llvm::outs() << "UnknownBranches: " << UnknownBranches << "\n";
+  llvm::outs() << "MatchedBranches: " << MatchedBranches << "\n";
+  llvm::outs() << "DismatchedBranches: " << DismatchedBranches << "\n";
+}
+
+} // namespace sampleprof
+} // namespace llvm
diff --git a/llvm/tools/llvm-profgen/PGOAccuracyMetrics.h b/llvm/tools/llvm-profgen/PGOAccuracyMetrics.h
new file mode 100644
index 0000000000000..5363713abbff8
--- /dev/null
+++ b/llvm/tools/llvm-profgen/PGOAccuracyMetrics.h
@@ -0,0 +1,45 @@
+//===-- PGOAccuracyMetrics.h ------------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TOOLS_LLVM_PROFGEN_PGOACCURACYMETRICS_H
+#define LLVM_TOOLS_LLVM_PROFGEN_PGOACCURACYMETRICS_H
+
+#include "PerfReader.h"
+#include "llvm/Object/ELFTypes.h"
+
+namespace llvm {
+namespace sampleprof {
+class PGOAccuracyMetrics {
+public:
+  PGOAccuracyMetrics(const ContextSampleCounterMap &CSCM,
+                     const std::vector<BBAddrMap> &BBAM,
+                     const std::vector<PGOAnalysisMap> &PGOAM)
+      : SampleCounters(CSCM), BBAddrMaps(BBAM), PGOAnalysisMaps(PGOAM) {
+    init();
+  }
+  void init();
+  void emitPGOAccuracyMetrics();
+
+private:
+  const ContextSampleCounterMap &SampleCounters;
+  const std::vector<BBAddrMap> &BBAddrMaps;
+  const std::vector<PGOAnalysisMap> &PGOAnalysisMaps;
+
+  // key is bb's address, value is function's address and bb's unique id;
+  std::map<uint64_t, std::pair<uint64_t, uint32_t>> BBAddrToID;
+  std::unordered_map<uint64_t,
+                     std::map<std::pair<uint32_t, uint32_t>, uint64_t>>
+      EdgeCounter;
+
+  uint64_t UnknownBranches = 0;
+  uint64_t MatchedBranches = 0;
+  uint64_t DismatchedBranches = 0;
+};
+} // namespace sampleprof
+} // namespace llvm
+
+#endif
\ No newline at end of file
diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.cpp b/llvm/tools/llvm-profgen/ProfiledBinary.cpp
index 1baf35820f97f..d0695deae86e5 100644
--- a/llvm/tools/llvm-profgen/ProfiledBinary.cpp
+++ b/llvm/tools/llvm-profgen/ProfiledBinary.cpp
@@ -256,6 +256,14 @@ void ProfiledBinary::load() {
 
   warnNoFuncEntry();
 
+  if (auto *ELFObj = dyn_cast<ELFObjectFileBase>(Obj)) {
+    auto BBAddrMapsOrErr =
+        ELFObj->readBBAddrMap(std::nullopt, &PGOAnalysisMaps);
+    if (!BBAddrMapsOrErr.takeError()) {
+      BBAddrMaps = *BBAddrMapsOrErr;
+    }
+  }
+
   // TODO: decode other sections.
 }
 
diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.h b/llvm/tools/llvm-profgen/ProfiledBinary.h
index 5d2088ad7691c..08c6d065ebca4 100644
--- a/llvm/tools/llvm-profgen/ProfiledBinary.h
+++ b/llvm/tools/llvm-profgen/ProfiledBinary.h
@@ -299,6 +299,10 @@ class ProfiledBinary {
 
   bool IsCOFF = false;
 
+  std::vector<PGOAnalysisMap> PGOAnalysisMaps;
+
+  std::vector<BBAddrMap> BBAddrMaps;
+
   void setPreferredTextSegmentAddresses(const ObjectFile *O);
 
   template <class ELFT>
@@ -600,6 +604,12 @@ class ProfiledBinary {
   bool getMissingMMapWarned() { return MissingMMapWarned; }
 
   void setMissingMMapWarned(bool Value) { MissingMMapWarned = Value; }
+
+  const std::vector<BBAddrMap> &getBBAddrMaps() const { return BBAddrMaps; }
+
+  const std::vector<PGOAnalysisMap> &getPGOAnalysisMaps() const {
+    return PGOAnalysisMaps;
+  }
 };
 
 } // end namespace sampleprof
diff --git a/llvm/tools/llvm-profgen/llvm-profgen.cpp b/llvm/tools/llvm-profgen/llvm-profgen.cpp
index 3b974e25103ad..6a904d8acbe83 100644
--- a/llvm/tools/llvm-profgen/llvm-profgen.cpp
+++ b/llvm/tools/llvm-profgen/llvm-profgen.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "ErrorHandling.h"
+#include "PGOAccuracyMetrics.h"
 #include "PerfReader.h"
 #include "ProfileGenerator.h"
 #include "ProfiledBinary.h"
@@ -67,6 +68,11 @@ static cl::opt<std::string> DebugBinPath(
              "from it instead of the executable binary."),
     cl::cat(ProfGenCategory));
 
+static cl::opt<bool>
+    EmitPGOAccuracyMetrics("pgo-accuracy-metrics", cl::init(false),
+                           cl::desc("Print PGO accuracy metrics"),
+                           cl::cat(ProfGenCategory));
+
 extern cl::opt<bool> ShowDisassemblyOnly;
 extern cl::opt<bool> ShowSourceLocations;
 extern cl::opt<bool> SkipSymbolization;
@@ -179,6 +185,13 @@ int main(int argc, const char *argv[]) {
     // Parse perf events and samples
     Reader->parsePerfTraces();
 
+    if (EmitPGOAccuracyMetrics) {
+      PGOAccuracyMetrics PGOAM(Reader->getSampleCounters(),
+                               Binary->getBBAddrMaps(),
+                               Binary->getPGOAnalysisMaps());
+      PGOAM.emitPGOAccuracyMetrics();
+    }
+
     if (SkipSymbolization)
       return EXIT_SUCCESS;
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/93975


More information about the llvm-commits mailing list