[llvm] [SampleFDO] Improve stale profile matching by diff algorithm (PR #87375)

Lei Wang via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 25 18:22:34 PDT 2024


https://github.com/wlei-llvm updated https://github.com/llvm/llvm-project/pull/87375

>From 51c8adc59dda52f30430e7283fc29d24f01c02fd Mon Sep 17 00:00:00 2001
From: wlei <wlei at fb.com>
Date: Mon, 1 Apr 2024 10:04:47 -0700
Subject: [PATCH 1/2] [SampleFDO] Use Myers diff for stale profile matching

---
 .../Transforms/IPO/SampleProfileMatcher.h     |  55 ++++-
 .../Transforms/IPO/SampleProfileMatcher.cpp   | 223 +++++++++++++-----
 llvm/unittests/Transforms/IPO/CMakeLists.txt  |   2 +
 .../IPO/SampleProfileMatcherTests.cpp         | 134 +++++++++++
 4 files changed, 349 insertions(+), 65 deletions(-)
 create mode 100644 llvm/unittests/Transforms/IPO/SampleProfileMatcherTests.cpp

diff --git a/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h b/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
index 7ae6194da7c9cc..44335274239b6b 100644
--- a/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
+++ b/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
@@ -19,6 +19,53 @@
 
 namespace llvm {
 
+// Callsite location based matching anchor.
+struct Anchor {
+  LineLocation Loc;
+  FunctionId FuncId;
+
+  Anchor(const LineLocation &Loc, const FunctionId &FuncId)
+      : Loc(Loc), FuncId(FuncId) {}
+  bool operator==(const Anchor &Other) const {
+    return this->FuncId == Other.FuncId;
+  }
+};
+
+// This class implements the Myers diff algorithm used for stale profile
+// matching. The algorithm provides a simple and efficient way to find the
+// Longest Common Subsequence(LCS) or the Shortest Edit Script(SES) of two
+// sequences. For more details, refer to the paper 'An O(ND) Difference
+// Algorithm and Its Variations' by Eugene W. Myers.
+// In the scenario of profile fuzzy matching, the two sequences are the IR
+// callsite anchors and profile callsite anchors. The subsequence equivalent
+// parts from the resulting SES are used to remap the IR locations to the
+// profile locations.
+class MyersDiff {
+public:
+  struct DiffResult {
+    LocToLocMap EqualLocations;
+    // New IR locations that are inserted in the new version.
+    std::vector<LineLocation> Insertions;
+    // Old Profile locations that are deleted in the new version.
+    std::vector<LineLocation> Deletions;
+    void addEqualLocations(const LineLocation &IRLoc,
+                           const LineLocation &ProfLoc) {
+      EqualLocations.insert({IRLoc, ProfLoc});
+    }
+    void addInsertion(const LineLocation &IRLoc) {
+      Insertions.push_back(IRLoc);
+    }
+    void addDeletion(const LineLocation &ProfLoc) {
+      Deletions.push_back(ProfLoc);
+    }
+  };
+
+  // The basic greedy version of Myers's algorithm. Refer to page 6 of the
+  // original paper.
+  DiffResult shortestEdit(const std::vector<Anchor> &A,
+                          const std::vector<Anchor> &B) const;
+};
+
 // Sample profile matching - fuzzy match.
 class SampleProfileMatcher {
   Module &M;
@@ -27,8 +74,8 @@ class SampleProfileMatcher {
   const ThinOrFullLTOPhase LTOPhase;
   SampleProfileMap FlattenedProfiles;
   // For each function, the matcher generates a map, of which each entry is a
-  // mapping from the source location of current build to the source location in
-  // the profile.
+  // mapping from the source location of current build to the source location
+  // in the profile.
   StringMap<LocToLocMap> FuncMappings;
 
   // Match state for an anchor/callsite.
@@ -143,6 +190,10 @@ class SampleProfileMatcher {
   }
   void distributeIRToProfileLocationMap();
   void distributeIRToProfileLocationMap(FunctionSamples &FS);
+  void matchNonAnchorAndWriteResults(
+      const LocToLocMap &AnchorMatchings,
+      const std::map<LineLocation, StringRef> &IRAnchors,
+      LocToLocMap &IRToProfileLocationMap);
   void runStaleProfileMatching(
       const Function &F, const std::map<LineLocation, StringRef> &IRAnchors,
       const std::map<LineLocation, std::unordered_set<FunctionId>>
diff --git a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
index 1ca89e0091daff..139a1636a7cbd3 100644
--- a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
+++ b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
@@ -122,15 +122,149 @@ void SampleProfileMatcher::findProfileAnchors(
   }
 }
 
+MyersDiff::DiffResult
+MyersDiff::shortestEdit(const std::vector<Anchor> &A,
+                        const std::vector<Anchor> &B) const {
+  int32_t N = A.size(), M = B.size(), Max = N + M;
+  auto Index = [&](int32_t I) { return I + Max; };
+
+  DiffResult Diff;
+  if (Max == 0)
+    return Diff;
+
+  // Backtrack the SES result.
+  auto Backtrack = [&](const std::vector<std::vector<int32_t>> &Trace,
+                       const std::vector<Anchor> &A,
+                       const std::vector<Anchor> &B) {
+    int32_t X = N, Y = M;
+    for (int32_t D = Trace.size() - 1; X > 0 || Y > 0; D--) {
+      const auto &P = Trace[D];
+      int32_t K = X - Y;
+      int32_t PrevK = K;
+      if (K == -D || (K != D && P[Index(K - 1)] < P[Index(K + 1)]))
+        PrevK = K + 1;
+      else
+        PrevK = K - 1;
+
+      int32_t PrevX = P[Index(PrevK)];
+      int32_t PrevY = PrevX - PrevK;
+      while (X > PrevX && Y > PrevY) {
+        X--;
+        Y--;
+        Diff.addEqualLocations(A[X].Loc, B[Y].Loc);
+      }
+
+      if (D == 0)
+        break;
+
+      if (Y == PrevY) {
+        X--;
+        Diff.addInsertion(A[X].Loc);
+      } else if (X == PrevX) {
+        Y--;
+        Diff.addDeletion(B[Y].Loc);
+      }
+      X = PrevX;
+      Y = PrevY;
+    }
+  };
+
+  // The greedy LCS/SES algorithm.
+  std::vector<int32_t> V(2 * Max + 1, -1);
+  V[Index(1)] = 0;
+  std::vector<std::vector<int32_t>> Trace;
+  for (int32_t D = 0; D <= Max; D++) {
+    Trace.push_back(V);
+    for (int32_t K = -D; K <= D; K += 2) {
+      int32_t X = 0, Y = 0;
+      if (K == -D || (K != D && V[Index(K - 1)] < V[Index(K + 1)]))
+        X = V[Index(K + 1)];
+      else
+        X = V[Index(K - 1)] + 1;
+      Y = X - K;
+      while (X < N && Y < M && A[X] == B[Y])
+        X++, Y++;
+
+      V[Index(K)] = X;
+
+      if (X >= N && Y >= M) {
+        // Length of an SES is D.
+        Backtrack(Trace, A, B);
+        return Diff;
+      }
+    }
+  }
+  // Length of an SES is greater than Max.
+  return Diff;
+}
+
+void SampleProfileMatcher::matchNonAnchorAndWriteResults(
+    const LocToLocMap &AnchorMatchings,
+    const std::map<LineLocation, StringRef> &IRAnchors,
+    LocToLocMap &IRToProfileLocationMap) {
+  auto InsertMatching = [&](const LineLocation &From, const LineLocation &To) {
+    // Skip the unchanged location mapping to save memory.
+    if (From != To)
+      IRToProfileLocationMap.insert({From, To});
+  };
+
+  // Use function's beginning location as the initial anchor.
+  int32_t LocationDelta = 0;
+  SmallVector<LineLocation> LastMatchedNonAnchors;
+  for (const auto &IR : IRAnchors) {
+    const auto &Loc = IR.first;
+    StringRef CalleeName = IR.second;
+    bool IsMatchedAnchor = false;
+
+    // Match the anchor location in lexical order.
+    auto R = AnchorMatchings.find(Loc);
+    if (R != AnchorMatchings.end()) {
+      const auto &Candidate = R->second;
+      InsertMatching(Loc, Candidate);
+      LLVM_DEBUG(dbgs() << "Callsite with callee:" << CalleeName
+                        << " is matched from " << Loc << " to " << Candidate
+                        << "\n");
+      LocationDelta = Candidate.LineOffset - Loc.LineOffset;
+
+      // Match backwards for non-anchor locations.
+      // The locations in LastMatchedNonAnchors have been matched forwards
+      // based on the previous anchor, spilt it evenly and overwrite the
+      // second half based on the current anchor.
+      for (size_t I = (LastMatchedNonAnchors.size() + 1) / 2;
+           I < LastMatchedNonAnchors.size(); I++) {
+        const auto &L = LastMatchedNonAnchors[I];
+        uint32_t CandidateLineOffset = L.LineOffset + LocationDelta;
+        LineLocation Candidate(CandidateLineOffset, L.Discriminator);
+        InsertMatching(L, Candidate);
+        LLVM_DEBUG(dbgs() << "Location is rematched backwards from " << L
+                          << " to " << Candidate << "\n");
+      }
+
+      IsMatchedAnchor = true;
+      LastMatchedNonAnchors.clear();
+    }
+
+    // Match forwards for non-anchor locations.
+    if (!IsMatchedAnchor) {
+      uint32_t CandidateLineOffset = Loc.LineOffset + LocationDelta;
+      LineLocation Candidate(CandidateLineOffset, Loc.Discriminator);
+      InsertMatching(Loc, Candidate);
+      LLVM_DEBUG(dbgs() << "Location is matched from " << Loc << " to "
+                        << Candidate << "\n");
+      LastMatchedNonAnchors.emplace_back(Loc);
+    }
+  }
+}
+
 // Call target name anchor based profile fuzzy matching.
 // Input:
 // For IR locations, the anchor is the callee name of direct callsite; For
 // profile locations, it's the call target name for BodySamples or inlinee's
 // profile name for CallsiteSamples.
 // Matching heuristic:
-// First match all the anchors in lexical order, then split the non-anchor
-// locations between the two anchors evenly, first half are matched based on the
-// start anchor, second half are matched based on the end anchor.
+// First match all the anchors using the diff algorithm, then split the
+// non-anchor locations between the two anchors evenly, first half are matched
+// based on the start anchor, second half are matched based on the end anchor.
 // For example, given:
 // IR locations:      [1, 2(foo), 3, 5, 6(bar), 7]
 // Profile locations: [1, 2, 3(foo), 4, 7, 8(bar), 9]
@@ -149,77 +283,40 @@ void SampleProfileMatcher::runStaleProfileMatching(
   assert(IRToProfileLocationMap.empty() &&
          "Run stale profile matching only once per function");
 
-  std::unordered_map<FunctionId, std::set<LineLocation>> CalleeToCallsitesMap;
+  std::vector<Anchor> ProfileCallsiteAnchors;
   for (const auto &I : ProfileAnchors) {
     const auto &Loc = I.first;
     const auto &Callees = I.second;
     // Filter out possible indirect calls, use direct callee name as anchor.
     if (Callees.size() == 1) {
-      FunctionId CalleeName = *Callees.begin();
-      const auto &Candidates = CalleeToCallsitesMap.try_emplace(
-          CalleeName, std::set<LineLocation>());
-      Candidates.first->second.insert(Loc);
+      auto CalleeName = *Callees.begin();
+      ProfileCallsiteAnchors.emplace_back(Loc, CalleeName);
+    } else if (Callees.size() > 1) {
+      ProfileCallsiteAnchors.emplace_back(Loc,
+                                          FunctionId(UnknownIndirectCallee));
     }
   }
 
-  auto InsertMatching = [&](const LineLocation &From, const LineLocation &To) {
-    // Skip the unchanged location mapping to save memory.
-    if (From != To)
-      IRToProfileLocationMap.insert({From, To});
-  };
-
-  // Use function's beginning location as the initial anchor.
-  int32_t LocationDelta = 0;
-  SmallVector<LineLocation> LastMatchedNonAnchors;
+  std::vector<Anchor> IRCallsiteAnchors;
+  for (const auto &I : IRAnchors) {
+    const auto &Loc = I.first;
+    const auto &CalleeName = I.second;
+    if (CalleeName.empty())
+      continue;
+    IRCallsiteAnchors.emplace_back(Loc, FunctionId(CalleeName));
+  }
 
-  for (const auto &IR : IRAnchors) {
-    const auto &Loc = IR.first;
-    auto CalleeName = IR.second;
-    bool IsMatchedAnchor = false;
-    // Match the anchor location in lexical order.
-    if (!CalleeName.empty()) {
-      auto CandidateAnchors =
-          CalleeToCallsitesMap.find(getRepInFormat(CalleeName));
-      if (CandidateAnchors != CalleeToCallsitesMap.end() &&
-          !CandidateAnchors->second.empty()) {
-        auto CI = CandidateAnchors->second.begin();
-        const auto Candidate = *CI;
-        CandidateAnchors->second.erase(CI);
-        InsertMatching(Loc, Candidate);
-        LLVM_DEBUG(dbgs() << "Callsite with callee:" << CalleeName
-                          << " is matched from " << Loc << " to " << Candidate
-                          << "\n");
-        LocationDelta = Candidate.LineOffset - Loc.LineOffset;
-
-        // Match backwards for non-anchor locations.
-        // The locations in LastMatchedNonAnchors have been matched forwards
-        // based on the previous anchor, spilt it evenly and overwrite the
-        // second half based on the current anchor.
-        for (size_t I = (LastMatchedNonAnchors.size() + 1) / 2;
-             I < LastMatchedNonAnchors.size(); I++) {
-          const auto &L = LastMatchedNonAnchors[I];
-          uint32_t CandidateLineOffset = L.LineOffset + LocationDelta;
-          LineLocation Candidate(CandidateLineOffset, L.Discriminator);
-          InsertMatching(L, Candidate);
-          LLVM_DEBUG(dbgs() << "Location is rematched backwards from " << L
-                            << " to " << Candidate << "\n");
-        }
+  if (IRCallsiteAnchors.empty() || ProfileCallsiteAnchors.empty())
+    return;
 
-        IsMatchedAnchor = true;
-        LastMatchedNonAnchors.clear();
-      }
-    }
+  // Use the diff algorithm to find the SES, the resulting equal locations from
+  // IR to Profile are used as anchor to match other locations. Note that here
+  // use IR anchor as base(A) to align with the order of IRToProfileLocationMap.
+  MyersDiff Diff;
+  auto DiffRes = Diff.shortestEdit(IRCallsiteAnchors, ProfileCallsiteAnchors);
 
-    // Match forwards for non-anchor locations.
-    if (!IsMatchedAnchor) {
-      uint32_t CandidateLineOffset = Loc.LineOffset + LocationDelta;
-      LineLocation Candidate(CandidateLineOffset, Loc.Discriminator);
-      InsertMatching(Loc, Candidate);
-      LLVM_DEBUG(dbgs() << "Location is matched from " << Loc << " to "
-                        << Candidate << "\n");
-      LastMatchedNonAnchors.emplace_back(Loc);
-    }
-  }
+  matchNonAnchorAndWriteResults(DiffRes.EqualLocations, IRAnchors,
+                                IRToProfileLocationMap);
 }
 
 void SampleProfileMatcher::runOnFunction(Function &F) {
diff --git a/llvm/unittests/Transforms/IPO/CMakeLists.txt b/llvm/unittests/Transforms/IPO/CMakeLists.txt
index 4e4372179b46c7..80d0eadf0cce09 100644
--- a/llvm/unittests/Transforms/IPO/CMakeLists.txt
+++ b/llvm/unittests/Transforms/IPO/CMakeLists.txt
@@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS
   AsmParser
   Core
   IPO
+  ProfileData
   Support
   TargetParser
   TransformUtils
@@ -13,6 +14,7 @@ add_llvm_unittest(IPOTests
   WholeProgramDevirt.cpp
   AttributorTest.cpp
   FunctionSpecializationTest.cpp
+  SampleProfileMatcherTests.cpp
   )
 
 set_property(TARGET IPOTests PROPERTY FOLDER "Tests/UnitTests/TransformsTests")
diff --git a/llvm/unittests/Transforms/IPO/SampleProfileMatcherTests.cpp b/llvm/unittests/Transforms/IPO/SampleProfileMatcherTests.cpp
new file mode 100644
index 00000000000000..37b92c80068ddd
--- /dev/null
+++ b/llvm/unittests/Transforms/IPO/SampleProfileMatcherTests.cpp
@@ -0,0 +1,134 @@
+//===- SampleProfileMatcherTests.cpp - SampleProfileMatcher Unit Tests -----==//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/IPO/SampleProfileMatcher.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+MyersDiff Diff;
+
+std::vector<Anchor>
+createAnchorsFromStrings(const std::vector<std::string> &SV) {
+  std::vector<Anchor> Anchors;
+  for (uint64_t I = 0; I < SV.size(); I++) {
+    Anchors.push_back(Anchor(LineLocation(I, 0), FunctionId(SV[I])));
+  }
+  return Anchors;
+}
+
+LocToLocMap
+createEqualLocations(const std::vector<std::pair<uint32_t, uint32_t>> &V) {
+  LocToLocMap LocMap;
+  for (auto P : V) {
+    LocMap.emplace(LineLocation(P.first, 0), LineLocation(P.second, 0));
+  }
+  return LocMap;
+}
+
+std::vector<LineLocation> createLocations(const std::vector<uint32_t> &V) {
+  std::vector<LineLocation> Locations;
+  for (auto I : V) {
+    Locations.emplace_back(LineLocation(I, 0));
+  }
+  return Locations;
+}
+
+TEST(SampleProfileMatcherTests, MyersDiffTest1) {
+
+  std::vector<Anchor> AnchorsA;
+  std::vector<Anchor> AnchorsB;
+  auto R = Diff.shortestEdit(AnchorsA, AnchorsB);
+  EXPECT_TRUE(R.EqualLocations.empty());
+  EXPECT_TRUE(R.Deletions.empty());
+  EXPECT_TRUE(R.Insertions.empty());
+}
+
+TEST(SampleProfileMatcherTests, MyersDiffTest2) {
+  std::vector<std::string> A({"a", "b", "c"});
+  std::vector<Anchor> AnchorsA = createAnchorsFromStrings(A);
+  std::vector<Anchor> AnchorsB;
+  auto R = Diff.shortestEdit(AnchorsA, AnchorsB);
+  EXPECT_TRUE(R.EqualLocations.empty());
+  EXPECT_EQ(R.Insertions, createLocations(std::vector<uint32_t>({2, 1, 0})));
+  EXPECT_TRUE(R.Deletions.empty());
+}
+
+TEST(SampleProfileMatcherTests, MyersDiffTest3) {
+
+  std::vector<Anchor> AnchorsA;
+  std::vector<std::string> B({"a", "b", "c"});
+  std::vector<Anchor> AnchorsB = createAnchorsFromStrings(B);
+  auto R = Diff.shortestEdit(AnchorsA, AnchorsB);
+  EXPECT_TRUE(R.EqualLocations.empty());
+  EXPECT_TRUE(R.Insertions.empty());
+  EXPECT_EQ(R.Deletions, createLocations(std::vector<uint32_t>({2, 1, 0})));
+}
+
+TEST(SampleProfileMatcherTests, MyersDiffTest4) {
+  std::vector<std::string> A({"a", "b", "c"});
+  std::vector<std::string> B({"a", "b", "c"});
+  std::vector<Anchor> AnchorsA = createAnchorsFromStrings(A);
+  std::vector<Anchor> AnchorsB = createAnchorsFromStrings(B);
+  LocToLocMap ExpectEqualLocations =
+      createEqualLocations({{0, 0}, {1, 1}, {2, 2}});
+  auto R = Diff.shortestEdit(AnchorsA, AnchorsB);
+  EXPECT_EQ(R.EqualLocations, ExpectEqualLocations);
+  EXPECT_TRUE(R.Insertions.empty());
+  EXPECT_TRUE(R.Deletions.empty());
+}
+
+TEST(SampleProfileMatcherTests, MyersDiffTest5) {
+  std::vector<std::string> A({"a", "b", "c"});
+  std::vector<std::string> B({"b", "c", "d"});
+  std::vector<Anchor> AnchorsA = createAnchorsFromStrings(A);
+  std::vector<Anchor> AnchorsB = createAnchorsFromStrings(B);
+  LocToLocMap ExpectEqualLocations = createEqualLocations({{1, 0}, {2, 1}});
+  auto R = Diff.shortestEdit(AnchorsA, AnchorsB);
+  EXPECT_EQ(R.EqualLocations, ExpectEqualLocations);
+  EXPECT_EQ(R.Insertions, createLocations(std::vector<uint32_t>({0})));
+  EXPECT_EQ(R.Deletions, createLocations(std::vector<uint32_t>({2})));
+}
+
+TEST(SampleProfileMatcherTests, MyersDiffTest6) {
+  std::vector<std::string> A({"a", "b", "d"});
+  std::vector<std::string> B({"a", "c", "d"});
+  std::vector<Anchor> AnchorsA = createAnchorsFromStrings(A);
+  std::vector<Anchor> AnchorsB = createAnchorsFromStrings(B);
+  LocToLocMap ExpectEqualLocations = createEqualLocations({{0, 0}, {2, 2}});
+  auto R = Diff.shortestEdit(AnchorsA, AnchorsB);
+  EXPECT_EQ(R.EqualLocations, ExpectEqualLocations);
+  EXPECT_EQ(R.Insertions, createLocations(std::vector<uint32_t>({1})));
+  EXPECT_EQ(R.Deletions, createLocations(std::vector<uint32_t>({1})));
+}
+
+TEST(SampleProfileMatcherTests, MyersDiffTest7) {
+  std::vector<std::string> A({"a", "b", "c", "a", "b", "b", "a"});
+  std::vector<std::string> B({"c", "b", "a", "b", "a", "c"});
+  std::vector<Anchor> AnchorsA = createAnchorsFromStrings(A);
+  std::vector<Anchor> AnchorsB = createAnchorsFromStrings(B);
+  LocToLocMap ExpectEqualLocations =
+      createEqualLocations({{2, 0}, {3, 2}, {4, 3}, {6, 4}});
+  auto R = Diff.shortestEdit(AnchorsA, AnchorsB);
+  EXPECT_EQ(R.EqualLocations, ExpectEqualLocations);
+  EXPECT_EQ(R.Insertions, createLocations(std::vector<uint32_t>({5, 1, 0})));
+  EXPECT_EQ(R.Deletions, createLocations(std::vector<uint32_t>({5, 1})));
+}
+
+TEST(SampleProfileMatcherTests, MyersDiffTest8) {
+  std::vector<std::string> A({"a", "c", "b", "c", "b", "d", "e"});
+  std::vector<std::string> B({"a", "b", "c", "a", "a", "b", "c", "c", "d"});
+  std::vector<Anchor> AnchorsA = createAnchorsFromStrings(A);
+  std::vector<Anchor> AnchorsB = createAnchorsFromStrings(B);
+  LocToLocMap ExpectEqualLocations =
+      createEqualLocations({{0, 0}, {2, 1}, {3, 2}, {4, 5}, {5, 8}});
+  auto R = Diff.shortestEdit(AnchorsA, AnchorsB);
+  EXPECT_EQ(R.EqualLocations, ExpectEqualLocations);
+  EXPECT_EQ(R.Insertions, createLocations(std::vector<uint32_t>({6, 1})));
+  EXPECT_EQ(R.Deletions, createLocations(std::vector<uint32_t>({7, 6, 4, 3})));
+}

>From 858b04060a0e606439f49a9e0f95d2ebd50e12f6 Mon Sep 17 00:00:00 2001
From: wlei <wlei at fb.com>
Date: Thu, 25 Apr 2024 18:10:15 -0700
Subject: [PATCH 2/2] addressing comments

---
 .../Transforms/IPO/SampleProfileMatcher.h     |  8 +++--
 .../Transforms/IPO/SampleProfileMatcher.cpp   | 20 ++++++++----
 .../IPO/SampleProfileMatcherTests.cpp         | 32 ++++++++++++++-----
 3 files changed, 43 insertions(+), 17 deletions(-)

diff --git a/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h b/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
index 44335274239b6b..5b56638c13344b 100644
--- a/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
+++ b/llvm/include/llvm/Transforms/IPO/SampleProfileMatcher.h
@@ -44,26 +44,30 @@ class MyersDiff {
 public:
   struct DiffResult {
     LocToLocMap EqualLocations;
+#ifndef NDEBUG
     // New IR locations that are inserted in the new version.
     std::vector<LineLocation> Insertions;
     // Old Profile locations that are deleted in the new version.
     std::vector<LineLocation> Deletions;
+#endif
     void addEqualLocations(const LineLocation &IRLoc,
                            const LineLocation &ProfLoc) {
       EqualLocations.insert({IRLoc, ProfLoc});
     }
+#ifndef NDEBUG
     void addInsertion(const LineLocation &IRLoc) {
       Insertions.push_back(IRLoc);
     }
     void addDeletion(const LineLocation &ProfLoc) {
       Deletions.push_back(ProfLoc);
     }
+#endif
   };
 
   // The basic greedy version of Myers's algorithm. Refer to page 6 of the
   // original paper.
-  DiffResult shortestEdit(const std::vector<Anchor> &A,
-                          const std::vector<Anchor> &B) const;
+  DiffResult longestCommonSequence(const std::vector<Anchor> &A,
+                                   const std::vector<Anchor> &B) const;
 };
 
 // Sample profile matching - fuzzy match.
diff --git a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
index 139a1636a7cbd3..de81450f0da252 100644
--- a/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
+++ b/llvm/lib/Transforms/IPO/SampleProfileMatcher.cpp
@@ -123,8 +123,8 @@ void SampleProfileMatcher::findProfileAnchors(
 }
 
 MyersDiff::DiffResult
-MyersDiff::shortestEdit(const std::vector<Anchor> &A,
-                        const std::vector<Anchor> &B) const {
+MyersDiff::longestCommonSequence(const std::vector<Anchor> &A,
+                                 const std::vector<Anchor> &B) const {
   int32_t N = A.size(), M = B.size(), Max = N + M;
   auto Index = [&](int32_t I) { return I + Max; };
 
@@ -159,10 +159,14 @@ MyersDiff::shortestEdit(const std::vector<Anchor> &A,
 
       if (Y == PrevY) {
         X--;
+#ifndef NDEBUG
         Diff.addInsertion(A[X].Loc);
+#endif
       } else if (X == PrevX) {
         Y--;
+#ifndef NDEBUG
         Diff.addDeletion(B[Y].Loc);
+#endif
       }
       X = PrevX;
       Y = PrevY;
@@ -213,7 +217,7 @@ void SampleProfileMatcher::matchNonAnchorAndWriteResults(
   SmallVector<LineLocation> LastMatchedNonAnchors;
   for (const auto &IR : IRAnchors) {
     const auto &Loc = IR.first;
-    StringRef CalleeName = IR.second;
+    [[maybe_unused]] StringRef CalleeName = IR.second;
     bool IsMatchedAnchor = false;
 
     // Match the anchor location in lexical order.
@@ -309,11 +313,13 @@ void SampleProfileMatcher::runStaleProfileMatching(
   if (IRCallsiteAnchors.empty() || ProfileCallsiteAnchors.empty())
     return;
 
-  // Use the diff algorithm to find the SES, the resulting equal locations from
-  // IR to Profile are used as anchor to match other locations. Note that here
-  // use IR anchor as base(A) to align with the order of IRToProfileLocationMap.
+  // Use the diff algorithm to find the LCS/SES, the resulting equal locations
+  // from IR to Profile are used as anchor to match other locations. Note that
+  // here use IR anchor as base(A) to align with the order of
+  // IRToProfileLocationMap.
   MyersDiff Diff;
-  auto DiffRes = Diff.shortestEdit(IRCallsiteAnchors, ProfileCallsiteAnchors);
+  auto DiffRes =
+      Diff.longestCommonSequence(IRCallsiteAnchors, ProfileCallsiteAnchors);
 
   matchNonAnchorAndWriteResults(DiffRes.EqualLocations, IRAnchors,
                                 IRToProfileLocationMap);
diff --git a/llvm/unittests/Transforms/IPO/SampleProfileMatcherTests.cpp b/llvm/unittests/Transforms/IPO/SampleProfileMatcherTests.cpp
index 37b92c80068ddd..25d5c053d3ccbd 100644
--- a/llvm/unittests/Transforms/IPO/SampleProfileMatcherTests.cpp
+++ b/llvm/unittests/Transforms/IPO/SampleProfileMatcherTests.cpp
@@ -43,20 +43,24 @@ TEST(SampleProfileMatcherTests, MyersDiffTest1) {
 
   std::vector<Anchor> AnchorsA;
   std::vector<Anchor> AnchorsB;
-  auto R = Diff.shortestEdit(AnchorsA, AnchorsB);
+  auto R = Diff.longestCommonSequence(AnchorsA, AnchorsB);
   EXPECT_TRUE(R.EqualLocations.empty());
+#ifndef NDEBUG
   EXPECT_TRUE(R.Deletions.empty());
   EXPECT_TRUE(R.Insertions.empty());
+#endif
 }
 
 TEST(SampleProfileMatcherTests, MyersDiffTest2) {
   std::vector<std::string> A({"a", "b", "c"});
   std::vector<Anchor> AnchorsA = createAnchorsFromStrings(A);
   std::vector<Anchor> AnchorsB;
-  auto R = Diff.shortestEdit(AnchorsA, AnchorsB);
+  auto R = Diff.longestCommonSequence(AnchorsA, AnchorsB);
   EXPECT_TRUE(R.EqualLocations.empty());
+#ifndef NDEBUG
   EXPECT_EQ(R.Insertions, createLocations(std::vector<uint32_t>({2, 1, 0})));
   EXPECT_TRUE(R.Deletions.empty());
+#endif
 }
 
 TEST(SampleProfileMatcherTests, MyersDiffTest3) {
@@ -64,10 +68,12 @@ TEST(SampleProfileMatcherTests, MyersDiffTest3) {
   std::vector<Anchor> AnchorsA;
   std::vector<std::string> B({"a", "b", "c"});
   std::vector<Anchor> AnchorsB = createAnchorsFromStrings(B);
-  auto R = Diff.shortestEdit(AnchorsA, AnchorsB);
+  auto R = Diff.longestCommonSequence(AnchorsA, AnchorsB);
   EXPECT_TRUE(R.EqualLocations.empty());
+#ifndef NDEBUG
   EXPECT_TRUE(R.Insertions.empty());
   EXPECT_EQ(R.Deletions, createLocations(std::vector<uint32_t>({2, 1, 0})));
+#endif
 }
 
 TEST(SampleProfileMatcherTests, MyersDiffTest4) {
@@ -77,10 +83,12 @@ TEST(SampleProfileMatcherTests, MyersDiffTest4) {
   std::vector<Anchor> AnchorsB = createAnchorsFromStrings(B);
   LocToLocMap ExpectEqualLocations =
       createEqualLocations({{0, 0}, {1, 1}, {2, 2}});
-  auto R = Diff.shortestEdit(AnchorsA, AnchorsB);
+  auto R = Diff.longestCommonSequence(AnchorsA, AnchorsB);
   EXPECT_EQ(R.EqualLocations, ExpectEqualLocations);
+#ifndef NDEBUG
   EXPECT_TRUE(R.Insertions.empty());
   EXPECT_TRUE(R.Deletions.empty());
+#endif
 }
 
 TEST(SampleProfileMatcherTests, MyersDiffTest5) {
@@ -89,10 +97,12 @@ TEST(SampleProfileMatcherTests, MyersDiffTest5) {
   std::vector<Anchor> AnchorsA = createAnchorsFromStrings(A);
   std::vector<Anchor> AnchorsB = createAnchorsFromStrings(B);
   LocToLocMap ExpectEqualLocations = createEqualLocations({{1, 0}, {2, 1}});
-  auto R = Diff.shortestEdit(AnchorsA, AnchorsB);
+  auto R = Diff.longestCommonSequence(AnchorsA, AnchorsB);
   EXPECT_EQ(R.EqualLocations, ExpectEqualLocations);
+#ifndef NDEBUG
   EXPECT_EQ(R.Insertions, createLocations(std::vector<uint32_t>({0})));
   EXPECT_EQ(R.Deletions, createLocations(std::vector<uint32_t>({2})));
+#endif
 }
 
 TEST(SampleProfileMatcherTests, MyersDiffTest6) {
@@ -101,10 +111,12 @@ TEST(SampleProfileMatcherTests, MyersDiffTest6) {
   std::vector<Anchor> AnchorsA = createAnchorsFromStrings(A);
   std::vector<Anchor> AnchorsB = createAnchorsFromStrings(B);
   LocToLocMap ExpectEqualLocations = createEqualLocations({{0, 0}, {2, 2}});
-  auto R = Diff.shortestEdit(AnchorsA, AnchorsB);
+  auto R = Diff.longestCommonSequence(AnchorsA, AnchorsB);
   EXPECT_EQ(R.EqualLocations, ExpectEqualLocations);
+#ifndef NDEBUG
   EXPECT_EQ(R.Insertions, createLocations(std::vector<uint32_t>({1})));
   EXPECT_EQ(R.Deletions, createLocations(std::vector<uint32_t>({1})));
+#endif
 }
 
 TEST(SampleProfileMatcherTests, MyersDiffTest7) {
@@ -114,10 +126,12 @@ TEST(SampleProfileMatcherTests, MyersDiffTest7) {
   std::vector<Anchor> AnchorsB = createAnchorsFromStrings(B);
   LocToLocMap ExpectEqualLocations =
       createEqualLocations({{2, 0}, {3, 2}, {4, 3}, {6, 4}});
-  auto R = Diff.shortestEdit(AnchorsA, AnchorsB);
+  auto R = Diff.longestCommonSequence(AnchorsA, AnchorsB);
   EXPECT_EQ(R.EqualLocations, ExpectEqualLocations);
+#ifndef NDEBUG
   EXPECT_EQ(R.Insertions, createLocations(std::vector<uint32_t>({5, 1, 0})));
   EXPECT_EQ(R.Deletions, createLocations(std::vector<uint32_t>({5, 1})));
+#endif
 }
 
 TEST(SampleProfileMatcherTests, MyersDiffTest8) {
@@ -127,8 +141,10 @@ TEST(SampleProfileMatcherTests, MyersDiffTest8) {
   std::vector<Anchor> AnchorsB = createAnchorsFromStrings(B);
   LocToLocMap ExpectEqualLocations =
       createEqualLocations({{0, 0}, {2, 1}, {3, 2}, {4, 5}, {5, 8}});
-  auto R = Diff.shortestEdit(AnchorsA, AnchorsB);
+  auto R = Diff.longestCommonSequence(AnchorsA, AnchorsB);
   EXPECT_EQ(R.EqualLocations, ExpectEqualLocations);
+#ifndef NDEBUG
   EXPECT_EQ(R.Insertions, createLocations(std::vector<uint32_t>({6, 1})));
   EXPECT_EQ(R.Deletions, createLocations(std::vector<uint32_t>({7, 6, 4, 3})));
+#endif
 }



More information about the llvm-commits mailing list