[llvm] r359612 - [llvm-profdata] Add overlap command to compute similarity b/w two profile files

Rong Xu via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 30 14:19:12 PDT 2019


Author: xur
Date: Tue Apr 30 14:19:12 2019
New Revision: 359612

URL: http://llvm.org/viewvc/llvm-project?rev=359612&view=rev
Log:
[llvm-profdata] Add overlap command to compute similarity b/w two profile files

Add overlap functionality to llvm-profdata tool to compute the similarity
between two profile files.

Differential Revision: https://reviews.llvm.org/D60977

Added:
    llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_1.proftext
    llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_1_cs.proftext
    llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_1_vp.proftext
    llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_2.proftext
    llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_2_cs.proftext
    llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_2_vp.proftext
    llvm/trunk/test/tools/llvm-profdata/overlap.test
    llvm/trunk/test/tools/llvm-profdata/overlap_cs.test
    llvm/trunk/test/tools/llvm-profdata/overlap_vp.test
Modified:
    llvm/trunk/docs/CommandGuide/llvm-profdata.rst
    llvm/trunk/include/llvm/ProfileData/InstrProf.h
    llvm/trunk/include/llvm/ProfileData/InstrProfReader.h
    llvm/trunk/include/llvm/ProfileData/InstrProfWriter.h
    llvm/trunk/lib/ProfileData/InstrProf.cpp
    llvm/trunk/lib/ProfileData/InstrProfReader.cpp
    llvm/trunk/lib/ProfileData/InstrProfWriter.cpp
    llvm/trunk/tools/llvm-profdata/llvm-profdata.cpp

Modified: llvm/trunk/docs/CommandGuide/llvm-profdata.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/llvm-profdata.rst?rev=359612&r1=359611&r2=359612&view=diff
==============================================================================
--- llvm/trunk/docs/CommandGuide/llvm-profdata.rst (original)
+++ llvm/trunk/docs/CommandGuide/llvm-profdata.rst Tue Apr 30 14:19:12 2019
@@ -17,6 +17,7 @@ COMMANDS
 
 * :ref:`merge <profdata-merge>`
 * :ref:`show <profdata-show>`
+* :ref:`overlap <profdata-overlap>`
 
 .. program:: llvm-profdata merge
 
@@ -231,6 +232,72 @@ OPTIONS
  Only show context sensitive profile counts. The default is to filter all
  context sensitive profile counts.
 
+.. program:: llvm-profdata overlap
+
+.. _profdata-overlap:
+
+OVERLAP
+-------
+
+SYNOPSIS
+^^^^^^^^
+
+:program:`llvm-profdata overlap` [*options*] [*base profile file*] [*test profile file*]
+
+DESCRIPTION
+^^^^^^^^^^^
+
+:program:`llvm-profdata overlap` takes two profile data files and displays the
+*overlap* of counter distribution between the whole files and between any of the
+specified functions.
+
+In this command, *overlap* is defined as follows:
+Suppose *base profile file* has the following counts:
+{c1_1, c1_2, ..., c1_n, c1_u_1, c2_u_2, ..., c2_u_s},
+and *test profile file* has
+{c2_1, c2_2, ..., c2_n, c2_v_1, c2_v_2, ..., c2_v_t}.
+Here c{1|2}_i (i = 1 .. n) are matched counters and c1_u_i (i = 1 .. s) and
+c2_v_i (i = 1 .. v) are unmatched counters (or counters only existing in)
+*base profile file* and *test profile file*, respectively.
+Let sum_1 = c1_1 + c1_2 +  ... + c1_n +  c1_u_1 + c2_u_2 + ... + c2_u_s, and
+sum_2 = c2_1 + c2_2 + ... + c2_n + c2_v_1 + c2_v_2 + ... + c2_v_t.
+*overlap* = min(c1_1/sum_1, c2_1/sum_2) + min(c1_2/sum_1, c2_2/sum_2) + ...
+            min(c1_n/sum_1, c2_n/sum_2).
+
+The result overlap distribution is a percentage number, ranging from 0.0% to
+100.0%, where 0.0% means there is no overlap and 100.0% means a perfect
+overlap.
+
+Here is an example, if *base profile file* has counts of {400, 600}, and
+*test profile file* has matched counts of {60000, 40000}. The *overlap* is 80%.
+
+
+OPTIONS
+^^^^^^^
+
+.. option:: -function=string
+
+ Print details for a function if the function's name contains the given string.
+
+.. option:: -help
+
+ Print a summary of command line options.
+
+.. option:: -o=output or -o output
+
+ Specify the output file name.  If *output* is ``-`` or it isn't specified,
+ then the output is sent to standard output.
+
+.. option:: -value-cutoff=n
+
+ Show only those functions whose max count values are greater or equal to ``n``.
+ By default, the value-cutoff is set to max of unsigned long long.
+
+.. option:: -cs
+
+ Only show overlap for the context sensitive profile counts. The default is to show
+ non-context sensitive profile counts.
+
 EXIT STATUS
 -----------
 

Modified: llvm/trunk/include/llvm/ProfileData/InstrProf.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/InstrProf.h?rev=359612&r1=359611&r2=359612&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ProfileData/InstrProf.h (original)
+++ llvm/trunk/include/llvm/ProfileData/InstrProf.h Tue Apr 30 14:19:12 2019
@@ -590,6 +590,70 @@ StringRef InstrProfSymtab::getOrigFuncNa
   return PGOName.drop_front(S + 1);
 }
 
+// To store the sums of profile count values, or the percentage of
+// the sums of the total count values.
+struct CountSumOrPercent {
+  uint64_t NumEntries;
+  double CountSum;
+  double ValueCounts[IPVK_Last - IPVK_First + 1];
+  CountSumOrPercent() : NumEntries(0), CountSum(0.0f), ValueCounts() {}
+  void reset() {
+    NumEntries = 0;
+    CountSum = 0.0f;
+    for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++)
+      ValueCounts[I] = 0.0f;
+  }
+};
+
+// Function level or program level overlap information.
+struct OverlapStats {
+  enum OverlapStatsLevel { ProgramLevel, FunctionLevel };
+  // Sum of the total count values for the base profile.
+  CountSumOrPercent Base;
+  // Sum of the total count values for the test profile.
+  CountSumOrPercent Test;
+  // Overlap lap score. Should be in range of [0.0f to 1.0f].
+  CountSumOrPercent Overlap;
+  CountSumOrPercent Mismatch;
+  CountSumOrPercent Unique;
+  OverlapStatsLevel Level;
+  const std::string *BaseFilename;
+  const std::string *TestFilename;
+  StringRef FuncName;
+  uint64_t FuncHash;
+  bool Valid;
+
+  OverlapStats(OverlapStatsLevel L = ProgramLevel)
+      : Level(L), BaseFilename(nullptr), TestFilename(nullptr), FuncHash(0),
+        Valid(false) {}
+
+  void dump(raw_fd_ostream &OS) const;
+
+  void setFuncInfo(StringRef Name, uint64_t Hash) {
+    FuncName = Name;
+    FuncHash = Hash;
+  }
+
+  Error accumuateCounts(const std::string &BaseFilename,
+                        const std::string &TestFilename, bool IsCS);
+  void addOneMismatch(const CountSumOrPercent &MismatchFunc);
+  void addOneUnique(const CountSumOrPercent &UniqueFunc);
+
+  static inline double score(uint64_t Val1, uint64_t Val2, double Sum1,
+                             double Sum2) {
+    if (Sum1 < 1.0f || Sum2 < 1.0f)
+      return 0.0f;
+    return std::min(Val1 / Sum1, Val2 / Sum2);
+  }
+};
+
+// This is used to filter the functions whose overlap information
+// to be output.
+struct OverlapFuncFilters {
+  uint64_t ValueCutoff;
+  const std::string NameFilter;
+};
+
 struct InstrProfValueSiteRecord {
   /// Value profiling data pairs at a given value site.
   std::list<InstrProfValueData> ValueData;
@@ -615,6 +679,10 @@ struct InstrProfValueSiteRecord {
              function_ref<void(instrprof_error)> Warn);
   /// Scale up value profile data counts.
   void scale(uint64_t Weight, function_ref<void(instrprof_error)> Warn);
+
+  /// Compute the overlap b/w this record and Input record.
+  void overlap(InstrProfValueSiteRecord &Input, uint32_t ValueKind,
+               OverlapStats &Overlap, OverlapStats &FuncLevelOverlap);
 };
 
 /// Profiling information for a single function.
@@ -703,6 +771,18 @@ struct InstrProfRecord {
   /// Clear value data entries
   void clearValueData() { ValueData = nullptr; }
 
+  /// Compute the sums of all counts and store in Sum.
+  void accumuateCounts(CountSumOrPercent &Sum) const;
+
+  /// Compute the overlap b/w this IntrprofRecord and Other.
+  void overlap(InstrProfRecord &Other, OverlapStats &Overlap,
+               OverlapStats &FuncLevelOverlap, uint64_t ValueCutoff);
+
+  /// Compute the overlap of value profile counts.
+  void overlapValueProfData(uint32_t ValueKind, InstrProfRecord &Src,
+                            OverlapStats &Overlap,
+                            OverlapStats &FuncLevelOverlap);
+
 private:
   struct ValueProfData {
     std::vector<InstrProfValueSiteRecord> IndirectCallSites;
@@ -1060,5 +1140,4 @@ void createIRLevelProfileFlagVar(Module
 void createProfileFileNameVar(Module &M, StringRef InstrProfileOutput);
 
 } // end namespace llvm
-
 #endif // LLVM_PROFILEDATA_INSTRPROF_H

Modified: llvm/trunk/include/llvm/ProfileData/InstrProfReader.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/InstrProfReader.h?rev=359612&r1=359611&r2=359612&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ProfileData/InstrProfReader.h (original)
+++ llvm/trunk/include/llvm/ProfileData/InstrProfReader.h Tue Apr 30 14:19:12 2019
@@ -91,6 +91,9 @@ public:
   /// compiler.
   virtual InstrProfSymtab &getSymtab() = 0;
 
+  /// Compute the sum of counts and return in Sum.
+  void accumuateCounts(CountSumOrPercent &Sum, bool IsCS);
+
 protected:
   std::unique_ptr<InstrProfSymtab> Symtab;
 

Modified: llvm/trunk/include/llvm/ProfileData/InstrProfWriter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/InstrProfWriter.h?rev=359612&r1=359611&r2=359612&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ProfileData/InstrProfWriter.h (original)
+++ llvm/trunk/include/llvm/ProfileData/InstrProfWriter.h Tue Apr 30 14:19:12 2019
@@ -100,6 +100,11 @@ public:
   // Internal interface for testing purpose only.
   void setValueProfDataEndianness(support::endianness Endianness);
   void setOutputSparse(bool Sparse);
+  // Compute the overlap b/w this object and Other. Program level result is
+  // stored in Overlap and function level result is stored in FuncLevelOverlap.
+  void overlapRecord(NamedInstrProfRecord &&Other, OverlapStats &Overlap,
+                     OverlapStats &FuncLevelOverlap,
+                     const OverlapFuncFilters &FuncFilter);
 
 private:
   void addRecord(StringRef Name, uint64_t Hash, InstrProfRecord &&I,

Modified: llvm/trunk/lib/ProfileData/InstrProf.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/InstrProf.cpp?rev=359612&r1=359611&r2=359612&view=diff
==============================================================================
--- llvm/trunk/lib/ProfileData/InstrProf.cpp (original)
+++ llvm/trunk/lib/ProfileData/InstrProf.cpp Tue Apr 30 14:19:12 2019
@@ -29,6 +29,7 @@
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/Type.h"
+#include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compiler.h"
@@ -478,6 +479,127 @@ Error readPGOFuncNameStrings(StringRef N
   return Error::success();
 }
 
+void InstrProfRecord::accumuateCounts(CountSumOrPercent &Sum) const {
+  uint64_t FuncSum = 0;
+  Sum.NumEntries += Counts.size();
+  for (size_t F = 0, E = Counts.size(); F < E; ++F)
+    FuncSum += Counts[F];
+  Sum.CountSum += FuncSum;
+
+  for (uint32_t VK = IPVK_First; VK <= IPVK_Last; ++VK) {
+    uint64_t KindSum = 0;
+    uint32_t NumValueSites = getNumValueSites(VK);
+    for (size_t I = 0; I < NumValueSites; ++I) {
+      uint32_t NV = getNumValueDataForSite(VK, I);
+      std::unique_ptr<InstrProfValueData[]> VD = getValueForSite(VK, I);
+      for (uint32_t V = 0; V < NV; V++)
+        KindSum += VD[V].Count;
+    }
+    Sum.ValueCounts[VK] += KindSum;
+  }
+}
+
+void InstrProfValueSiteRecord::overlap(InstrProfValueSiteRecord &Input,
+                                       uint32_t ValueKind,
+                                       OverlapStats &Overlap,
+                                       OverlapStats &FuncLevelOverlap) {
+  this->sortByTargetValues();
+  Input.sortByTargetValues();
+  double Score = 0.0f, FuncLevelScore = 0.0f;
+  auto I = ValueData.begin();
+  auto IE = ValueData.end();
+  auto J = Input.ValueData.begin();
+  auto JE = Input.ValueData.end();
+  while (I != IE && J != JE) {
+    if (I->Value == J->Value) {
+      Score += OverlapStats::score(I->Count, J->Count,
+                                   Overlap.Base.ValueCounts[ValueKind],
+                                   Overlap.Test.ValueCounts[ValueKind]);
+      FuncLevelScore += OverlapStats::score(
+          I->Count, J->Count, FuncLevelOverlap.Base.ValueCounts[ValueKind],
+          FuncLevelOverlap.Test.ValueCounts[ValueKind]);
+      ++I;
+    } else if (I->Value < J->Value) {
+      ++I;
+      continue;
+    }
+    ++J;
+  }
+  Overlap.Overlap.ValueCounts[ValueKind] += Score;
+  FuncLevelOverlap.Overlap.ValueCounts[ValueKind] += FuncLevelScore;
+}
+
+// Return false on mismatch.
+void InstrProfRecord::overlapValueProfData(uint32_t ValueKind,
+                                           InstrProfRecord &Other,
+                                           OverlapStats &Overlap,
+                                           OverlapStats &FuncLevelOverlap) {
+  uint32_t ThisNumValueSites = getNumValueSites(ValueKind);
+  uint32_t OtherNumValueSites = Other.getNumValueSites(ValueKind);
+  assert(ThisNumValueSites == OtherNumValueSites);
+  if (!ThisNumValueSites)
+    return;
+
+  std::vector<InstrProfValueSiteRecord> &ThisSiteRecords =
+      getOrCreateValueSitesForKind(ValueKind);
+  MutableArrayRef<InstrProfValueSiteRecord> OtherSiteRecords =
+      Other.getValueSitesForKind(ValueKind);
+  for (uint32_t I = 0; I < ThisNumValueSites; I++)
+    ThisSiteRecords[I].overlap(OtherSiteRecords[I], ValueKind, Overlap,
+                               FuncLevelOverlap);
+}
+
+void InstrProfRecord::overlap(InstrProfRecord &Other, OverlapStats &Overlap,
+                              OverlapStats &FuncLevelOverlap,
+                              uint64_t ValueCutoff) {
+  // FuncLevel CountSum for other should already computed and nonzero.
+  assert(FuncLevelOverlap.Test.CountSum >= 1.0f);
+  accumuateCounts(FuncLevelOverlap.Base);
+  bool Mismatch = (Counts.size() != Other.Counts.size());
+
+  // Check if the value profiles mismatch.
+  if (!Mismatch) {
+    for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
+      uint32_t ThisNumValueSites = getNumValueSites(Kind);
+      uint32_t OtherNumValueSites = Other.getNumValueSites(Kind);
+      if (ThisNumValueSites != OtherNumValueSites) {
+        Mismatch = true;
+        break;
+      }
+    }
+  }
+  if (Mismatch) {
+    Overlap.addOneMismatch(FuncLevelOverlap.Test);
+    return;
+  }
+
+  // Compute overlap for value counts.
+  for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
+    overlapValueProfData(Kind, Other, Overlap, FuncLevelOverlap);
+
+  double Score = 0.0;
+  uint64_t MaxCount = 0;
+  // Compute overlap for edge counts.
+  for (size_t I = 0, E = Other.Counts.size(); I < E; ++I) {
+    Score += OverlapStats::score(Counts[I], Other.Counts[I],
+                                 Overlap.Base.CountSum, Overlap.Test.CountSum);
+    MaxCount = std::max(Other.Counts[I], MaxCount);
+  }
+  Overlap.Overlap.CountSum += Score;
+  Overlap.Overlap.NumEntries += 1;
+
+  if (MaxCount >= ValueCutoff) {
+    double FuncScore = 0.0;
+    for (size_t I = 0, E = Other.Counts.size(); I < E; ++I)
+      FuncScore += OverlapStats::score(Counts[I], Other.Counts[I],
+                                       FuncLevelOverlap.Base.CountSum,
+                                       FuncLevelOverlap.Test.CountSum);
+    FuncLevelOverlap.Overlap.CountSum = FuncScore;
+    FuncLevelOverlap.Overlap.NumEntries = Other.Counts.size();
+    FuncLevelOverlap.Valid = true;
+  }
+}
+
 void InstrProfValueSiteRecord::merge(InstrProfValueSiteRecord &Input,
                                      uint64_t Weight,
                                      function_ref<void(instrprof_error)> Warn) {
@@ -1046,4 +1168,117 @@ void createProfileFileNameVar(Module &M,
   }
 }
 
+Error OverlapStats::accumuateCounts(const std::string &BaseFilename,
+                                    const std::string &TestFilename,
+                                    bool IsCS) {
+  auto getProfileSum = [IsCS](const std::string &Filename,
+                              CountSumOrPercent &Sum) -> Error {
+    auto ReaderOrErr = InstrProfReader::create(Filename);
+    if (Error E = ReaderOrErr.takeError()) {
+      return E;
+    }
+    auto Reader = std::move(ReaderOrErr.get());
+    Reader->accumuateCounts(Sum, IsCS);
+    return Error::success();
+  };
+  auto Ret = getProfileSum(BaseFilename, Base);
+  if (Ret)
+    return std::move(Ret);
+  Ret = getProfileSum(TestFilename, Test);
+  if (Ret)
+    return std::move(Ret);
+  this->BaseFilename = &BaseFilename;
+  this->TestFilename = &TestFilename;
+  Valid = true;
+  return Error::success();
+}
+
+void OverlapStats::addOneMismatch(const CountSumOrPercent &MismatchFunc) {
+  Mismatch.NumEntries += 1;
+  Mismatch.CountSum += MismatchFunc.CountSum / Test.CountSum;
+  for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) {
+    if (Test.ValueCounts[I] >= 1.0f)
+      Mismatch.ValueCounts[I] +=
+          MismatchFunc.ValueCounts[I] / Test.ValueCounts[I];
+  }
+}
+
+void OverlapStats::addOneUnique(const CountSumOrPercent &UniqueFunc) {
+  Unique.NumEntries += 1;
+  Unique.CountSum += UniqueFunc.CountSum / Test.CountSum;
+  for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) {
+    if (Test.ValueCounts[I] >= 1.0f)
+      Unique.ValueCounts[I] += UniqueFunc.ValueCounts[I] / Test.ValueCounts[I];
+  }
+}
+
+void OverlapStats::dump(raw_fd_ostream &OS) const {
+  if (!Valid)
+    return;
+
+  const char *EntryName =
+      (Level == ProgramLevel ? "functions" : "edge counters");
+  if (Level == ProgramLevel) {
+    OS << "Profile overlap infomation for base_profile: " << *BaseFilename
+       << " and test_profile: " << *TestFilename << "\nProgram level:\n";
+  } else {
+    OS << "Function level:\n"
+       << "  Function: " << FuncName << " (Hash=" << FuncHash << ")\n";
+  }
+
+  OS << "  # of " << EntryName << " overlap: " << Overlap.NumEntries << "\n";
+  if (Mismatch.NumEntries)
+    OS << "  # of " << EntryName << " mismatch: " << Mismatch.NumEntries
+       << "\n";
+  if (Unique.NumEntries)
+    OS << "  # of " << EntryName
+       << " only in test_profile: " << Unique.NumEntries << "\n";
+
+  OS << "  Edge profile overlap: " << format("%.3f%%", Overlap.CountSum * 100)
+     << "\n";
+  if (Mismatch.NumEntries)
+    OS << "  Mismatched count percentage (Edge): "
+       << format("%.3f%%", Mismatch.CountSum * 100) << "\n";
+  if (Unique.NumEntries)
+    OS << "  Percentage of Edge profile only in test_profile: "
+       << format("%.3f%%", Unique.CountSum * 100) << "\n";
+  OS << "  Edge profile base count sum: " << format("%.0f", Base.CountSum)
+     << "\n"
+     << "  Edge profile test count sum: " << format("%.0f", Test.CountSum)
+     << "\n";
+
+  for (unsigned I = 0; I < IPVK_Last - IPVK_First + 1; I++) {
+    if (Base.ValueCounts[I] < 1.0f && Test.ValueCounts[I] < 1.0f)
+      continue;
+    char ProfileKindName[20];
+    switch (I) {
+    case IPVK_IndirectCallTarget:
+      strncpy(ProfileKindName, "IndirectCall", 19);
+      break;
+    case IPVK_MemOPSize:
+      strncpy(ProfileKindName, "MemOP", 19);
+      break;
+    default:
+      snprintf(ProfileKindName, 19, "VP[%d]", I);
+      break;
+    }
+    OS << "  " << ProfileKindName
+       << " profile overlap: " << format("%.3f%%", Overlap.ValueCounts[I] * 100)
+       << "\n";
+    if (Mismatch.NumEntries)
+      OS << "  Mismatched count percentage (" << ProfileKindName
+         << "): " << format("%.3f%%", Mismatch.ValueCounts[I] * 100) << "\n";
+    if (Unique.NumEntries)
+      OS << "  Percentage of " << ProfileKindName
+         << " profile only in test_profile: "
+         << format("%.3f%%", Unique.ValueCounts[I] * 100) << "\n";
+    OS << "  " << ProfileKindName
+       << " profile base count sum: " << format("%.0f", Base.ValueCounts[I])
+       << "\n"
+       << "  " << ProfileKindName
+       << " profile test count sum: " << format("%.0f", Test.ValueCounts[I])
+       << "\n";
+  }
+}
+
 } // end namespace llvm

Modified: llvm/trunk/lib/ProfileData/InstrProfReader.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/InstrProfReader.cpp?rev=359612&r1=359611&r2=359612&view=diff
==============================================================================
--- llvm/trunk/lib/ProfileData/InstrProfReader.cpp (original)
+++ llvm/trunk/lib/ProfileData/InstrProfReader.cpp Tue Apr 30 14:19:12 2019
@@ -900,3 +900,17 @@ Error IndexedInstrProfReader::readNextRe
   }
   return success();
 }
+
+void InstrProfReader::accumuateCounts(CountSumOrPercent &Sum, bool IsCS) {
+  uint64_t NumFuncs = 0;
+  for (const auto &Func : *this) {
+    if (isIRLevelProfile()) {
+      bool FuncIsCS = NamedInstrProfRecord::hasCSFlagInHash(Func.Hash);
+      if (FuncIsCS != IsCS)
+        continue;
+    }
+    Func.accumuateCounts(Sum);
+    ++NumFuncs;
+  }
+  Sum.NumEntries = NumFuncs;
+}

Modified: llvm/trunk/lib/ProfileData/InstrProfWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/InstrProfWriter.cpp?rev=359612&r1=359611&r2=359612&view=diff
==============================================================================
--- llvm/trunk/lib/ProfileData/InstrProfWriter.cpp (original)
+++ llvm/trunk/lib/ProfileData/InstrProfWriter.cpp Tue Apr 30 14:19:12 2019
@@ -187,6 +187,40 @@ void InstrProfWriter::addRecord(NamedIns
   addRecord(Name, Hash, std::move(I), Weight, Warn);
 }
 
+void InstrProfWriter::overlapRecord(NamedInstrProfRecord &&Other,
+                                    OverlapStats &Overlap,
+                                    OverlapStats &FuncLevelOverlap,
+                                    const OverlapFuncFilters &FuncFilter) {
+  auto Name = Other.Name;
+  auto Hash = Other.Hash;
+  Other.accumuateCounts(FuncLevelOverlap.Test);
+  if (FunctionData.find(Name) == FunctionData.end()) {
+    Overlap.addOneUnique(FuncLevelOverlap.Test);
+    return;
+  }
+  if (FuncLevelOverlap.Test.CountSum < 1.0f) {
+    Overlap.Overlap.NumEntries += 1;
+    return;
+  }
+  auto &ProfileDataMap = FunctionData[Name];
+  bool NewFunc;
+  ProfilingData::iterator Where;
+  std::tie(Where, NewFunc) =
+      ProfileDataMap.insert(std::make_pair(Hash, InstrProfRecord()));
+  if (NewFunc) {
+    Overlap.addOneMismatch(FuncLevelOverlap.Test);
+    return;
+  }
+  InstrProfRecord &Dest = Where->second;
+
+  uint64_t ValueCutoff = FuncFilter.ValueCutoff;
+  if (!FuncFilter.NameFilter.empty() &&
+      Name.find(FuncFilter.NameFilter) != Name.npos)
+    ValueCutoff = 0;
+
+  Dest.overlap(Other, Overlap, FuncLevelOverlap, ValueCutoff);
+}
+
 void InstrProfWriter::addRecord(StringRef Name, uint64_t Hash,
                                 InstrProfRecord &&I, uint64_t Weight,
                                 function_ref<void(Error)> Warn) {

Added: llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_1.proftext
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_1.proftext?rev=359612&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_1.proftext (added)
+++ llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_1.proftext Tue Apr 30 14:19:12 2019
@@ -0,0 +1,36 @@
+# IR level Instrumentation Flag
+:ir
+bar
+# Func Hash:
+12884901887
+# Num Counters:
+1
+# Counter Values:
+100000
+
+bar1
+# Func Hash:
+12884901887
+# Num Counters:
+1
+# Counter Values:
+100000
+
+foo
+# Func Hash:
+25571299074
+# Num Counters:
+2
+# Counter Values:
+40000
+60000
+
+main
+# Func Hash:
+29212902728
+# Num Counters:
+2
+# Counter Values:
+200000
+0
+

Added: llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_1_cs.proftext
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_1_cs.proftext?rev=359612&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_1_cs.proftext (added)
+++ llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_1_cs.proftext Tue Apr 30 14:19:12 2019
@@ -0,0 +1,11 @@
+# CSIR level Instrumentation Flag
+:csir
+bar
+# Func Hash:
+1152921534274394772
+# Num Counters:
+2
+# Counter Values:
+6000
+4000
+

Added: llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_1_vp.proftext
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_1_vp.proftext?rev=359612&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_1_vp.proftext (added)
+++ llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_1_vp.proftext Tue Apr 30 14:19:12 2019
@@ -0,0 +1,25 @@
+:IR
+foo
+# Func Hash:
+72057649435042473
+# Num Counters:
+2
+# Counter Values:
+40000
+60000
+# Num Value Kinds:
+2
+# ValueKind = IPVK_IndirectCallTarget:
+0
+# NumValueSites:
+1
+2
+bar1:40000
+bar2:60000
+# ValueKind = IPVK_MemOPSize:
+1
+# NumValueSites:
+1
+2
+1:40000
+4:60000

Added: llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_2.proftext
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_2.proftext?rev=359612&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_2.proftext (added)
+++ llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_2.proftext Tue Apr 30 14:19:12 2019
@@ -0,0 +1,36 @@
+# IR level Instrumentation Flag
+:ir
+bar
+# Func Hash:
+12884901887
+# Num Counters:
+1
+# Counter Values:
+10000
+
+bar2
+# Func Hash:
+12884901887
+# Num Counters:
+1
+# Counter Values:
+10000
+
+foo
+# Func Hash:
+25571299075
+# Num Counters:
+2
+# Counter Values:
+4000
+6000
+
+main
+# Func Hash:
+29212902728
+# Num Counters:
+2
+# Counter Values:
+20000
+0
+

Added: llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_2_cs.proftext
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_2_cs.proftext?rev=359612&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_2_cs.proftext (added)
+++ llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_2_cs.proftext Tue Apr 30 14:19:12 2019
@@ -0,0 +1,11 @@
+# CSIR level Instrumentation Flag
+:csir
+bar
+# Func Hash:
+1152921534274394772
+# Num Counters:
+2
+# Counter Values:
+4000
+6000
+

Added: llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_2_vp.proftext
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_2_vp.proftext?rev=359612&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_2_vp.proftext (added)
+++ llvm/trunk/test/tools/llvm-profdata/Inputs/overlap_2_vp.proftext Tue Apr 30 14:19:12 2019
@@ -0,0 +1,25 @@
+:IR
+foo
+# Func Hash:
+72057649435042473
+# Num Counters:
+2
+# Counter Values:
+30000
+20000
+# Num Value Kinds:
+2
+# ValueKind = IPVK_IndirectCallTarget:
+0
+# NumValueSites:
+1
+2
+bar1:30000
+bar2:20000
+# ValueKind = IPVK_MemOPSize:
+1
+# NumValueSites:
+1
+2
+1:3000
+4:2000

Added: llvm/trunk/test/tools/llvm-profdata/overlap.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-profdata/overlap.test?rev=359612&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-profdata/overlap.test (added)
+++ llvm/trunk/test/tools/llvm-profdata/overlap.test Tue Apr 30 14:19:12 2019
@@ -0,0 +1,21 @@
+RUN: llvm-profdata overlap %p/Inputs/overlap_1.proftext %p/Inputs/overlap_2.proftext | FileCheck %s -check-prefix=OVERLAP
+RUN: llvm-profdata overlap -function=main %p/Inputs/overlap_1.proftext %p/Inputs/overlap_2.proftext | FileCheck %s -check-prefix=MAINFUNC -check-prefix=OVERLAP
+RUN: llvm-profdata overlap -value-cutoff=15000 %p/Inputs/overlap_1.proftext %p/Inputs/overlap_2.proftext | FileCheck %s -check-prefix=MAINFUNC -check-prefix=OVERLAP
+RUN: llvm-profdata merge %p/Inputs/overlap_1.proftext -o %t_1.profdata
+RUN: llvm-profdata merge %p/Inputs/overlap_2.proftext -o %t_2.profdata
+RUN: llvm-profdata overlap %t_1.profdata %t_2.profdata | FileCheck %s -check-prefix=OVERLAP
+MAINFUNC: Function: main (Hash=29212902728)
+MAINFUNC:   # of edge counters overlap: 2
+MAINFUNC:   Edge profile overlap: 100.000%
+MAINFUNC:   Edge profile base count sum: 200000
+MAINFUNC:   Edge profile test count sum: 20000
+OVERLAP: Profile overlap infomation for base_profile: {{.*}} and test_profile:
+OVERLAP: Program level:
+OVERLAP:   # of functions overlap: 2
+OVERLAP:   # of functions mismatch: 1
+OVERLAP:   # of functions only in test_profile: 1
+OVERLAP:   Edge profile overlap: 60.000%
+OVERLAP:   Mismatched count percentage (Edge): 20.000%
+OVERLAP:   Percentage of Edge profile only in test_profile: 20.000%
+OVERLAP:   Edge profile base count sum: 500000
+OVERLAP:   Edge profile test count sum: 50000

Added: llvm/trunk/test/tools/llvm-profdata/overlap_cs.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-profdata/overlap_cs.test?rev=359612&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-profdata/overlap_cs.test (added)
+++ llvm/trunk/test/tools/llvm-profdata/overlap_cs.test Tue Apr 30 14:19:12 2019
@@ -0,0 +1,10 @@
+RUN: llvm-profdata overlap -cs %p/Inputs/overlap_1_cs.proftext %p/Inputs/overlap_2_cs.proftext | FileCheck %s -check-prefix=OVERLAP
+RUN: llvm-profdata merge %p/Inputs/overlap_1_cs.proftext -o %t_1_cs.profdata
+RUN: llvm-profdata merge %p/Inputs/overlap_2_cs.proftext -o %t_2_cs.profdata
+RUN: llvm-profdata overlap -cs %t_1_cs.profdata %t_2_cs.profdata | FileCheck %s -check-prefix=OVERLAP
+OVERLAP: Profile overlap infomation for base_profile: {{.*}} and test_profile:
+OVERLAP: Program level:
+OVERLAP:  # of functions overlap: 1
+OVERLAP:  Edge profile overlap: 80.000%
+OVERLAP:  Edge profile base count sum: 10000
+OVERLAP:  Edge profile test count sum: 10000

Added: llvm/trunk/test/tools/llvm-profdata/overlap_vp.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-profdata/overlap_vp.test?rev=359612&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-profdata/overlap_vp.test (added)
+++ llvm/trunk/test/tools/llvm-profdata/overlap_vp.test Tue Apr 30 14:19:12 2019
@@ -0,0 +1,16 @@
+RUN: llvm-profdata overlap %p/Inputs/overlap_1_vp.proftext %p/Inputs/overlap_2_vp.proftext | FileCheck %s -check-prefix=OVERLAP
+RUN: llvm-profdata merge %p/Inputs/overlap_1_vp.proftext -o %t_1_vp.profdata
+RUN: llvm-profdata merge %p/Inputs/overlap_2_vp.proftext -o %t_2_vp.profdata
+RUN: llvm-profdata overlap %t_1_vp.profdata %t_2_vp.profdata | FileCheck %s -check-prefix=OVERLAP
+OVERLAP: Profile overlap infomation for base_profile: {{.*}} and test_profile:
+OVERLAP: Program level:
+OVERLAP:   # of functions overlap: 1
+OVERLAP:   Edge profile overlap: 80.000%
+OVERLAP:   Edge profile base count sum: 100000
+OVERLAP:   Edge profile test count sum: 50000
+OVERLAP:   IndirectCall profile overlap: 80.000%
+OVERLAP:   IndirectCall profile base count sum: 100000
+OVERLAP:   IndirectCall profile test count sum: 50000
+OVERLAP:   MemOP profile overlap: 80.000%
+OVERLAP:   MemOP profile base count sum: 100000
+OVERLAP:   MemOP profile test count sum: 5000

Modified: llvm/trunk/tools/llvm-profdata/llvm-profdata.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-profdata/llvm-profdata.cpp?rev=359612&r1=359611&r2=359612&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-profdata/llvm-profdata.cpp (original)
+++ llvm/trunk/tools/llvm-profdata/llvm-profdata.cpp Tue Apr 30 14:19:12 2019
@@ -200,6 +200,32 @@ static bool isFatalError(instrprof_error
   }
 }
 
+/// Computer the overlap b/w profile BaseFilename and TestFileName,
+/// and store the program level result to Overlap.
+static void overlapInput(const std::string &BaseFilename,
+                         const std::string &TestFilename, WriterContext *WC,
+                         OverlapStats &Overlap,
+                         const OverlapFuncFilters &FuncFilter,
+                         raw_fd_ostream &OS, bool IsCS) {
+  auto ReaderOrErr = InstrProfReader::create(TestFilename);
+  if (Error E = ReaderOrErr.takeError()) {
+    // Skip the empty profiles by returning sliently.
+    instrprof_error IPE = InstrProfError::take(std::move(E));
+    if (IPE != instrprof_error::empty_raw_profile)
+      WC->Err = make_error<InstrProfError>(IPE);
+    return;
+  }
+
+  auto Reader = std::move(ReaderOrErr.get());
+  for (auto &I : *Reader) {
+    OverlapStats FuncOverlap(OverlapStats::FunctionLevel);
+    FuncOverlap.setFuncInfo(I.Name, I.Hash);
+
+    WC->Writer.overlapRecord(std::move(I), Overlap, FuncOverlap, FuncFilter);
+    FuncOverlap.dump(OS);
+  }
+}
+
 /// Load an input into a writer context.
 static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
                       WriterContext *WC) {
@@ -608,6 +634,65 @@ static int merge_main(int argc, const ch
   return 0;
 }
 
+/// Computer the overlap b/w profile BaseFilename and profile TestFilename.
+static void overlapInstrProfile(const std::string &BaseFilename,
+                                const std::string &TestFilename,
+                                const OverlapFuncFilters &FuncFilter,
+                                raw_fd_ostream &OS, bool IsCS) {
+  std::mutex ErrorLock;
+  SmallSet<instrprof_error, 4> WriterErrorCodes;
+  WriterContext Context(false, ErrorLock, WriterErrorCodes);
+  WeightedFile WeightedInput{BaseFilename, 1};
+  OverlapStats Overlap;
+  Error E = Overlap.accumuateCounts(BaseFilename, TestFilename, IsCS);
+  if (E)
+    exitWithError(std::move(E), "Error in getting profile count sums");
+  if (Overlap.Base.CountSum < 1.0f) {
+    OS << "Sum of edge counts for profile " << BaseFilename << " is 0.\n";
+    exit(0);
+  }
+  if (Overlap.Test.CountSum < 1.0f) {
+    OS << "Sum of edge counts for profile " << TestFilename << " is 0.\n";
+    exit(0);
+  }
+  loadInput(WeightedInput, nullptr, &Context);
+  overlapInput(BaseFilename, TestFilename, &Context, Overlap, FuncFilter, OS,
+               IsCS);
+  Overlap.dump(OS);
+}
+
+static int overlap_main(int argc, const char *argv[]) {
+  cl::opt<std::string> BaseFilename(cl::Positional, cl::Required,
+                                    cl::desc("<base profile file>"));
+  cl::opt<std::string> TestFilename(cl::Positional, cl::Required,
+                                    cl::desc("<test profile file>"));
+  cl::opt<std::string> Output("output", cl::value_desc("output"), cl::init("-"),
+                              cl::desc("Output file"));
+  cl::alias OutputA("o", cl::desc("Alias for --output"), cl::aliasopt(Output));
+  cl::opt<bool> IsCS("cs", cl::init(false),
+                     cl::desc("For context sensitive counts"));
+  cl::opt<unsigned long long> ValueCutoff(
+      "value-cutoff", cl::init(-1),
+      cl::desc(
+          "Function level overlap information for every function in test "
+          "profile with max count value greater then the parameter value"));
+  cl::opt<std::string> FuncNameFilter(
+      "function",
+      cl::desc("Function level overlap information for matching functions"));
+  cl::ParseCommandLineOptions(argc, argv, "LLVM profile data overlap tool\n");
+
+  std::error_code EC;
+  raw_fd_ostream OS(Output.data(), EC, sys::fs::F_Text);
+  if (EC)
+    exitWithErrorCode(EC, Output);
+
+  overlapInstrProfile(BaseFilename, TestFilename,
+                      OverlapFuncFilters{ValueCutoff, FuncNameFilter}, OS,
+                      IsCS);
+
+  return 0;
+}
+
 typedef struct ValueSitesStats {
   ValueSitesStats()
       : TotalNumValueSites(0), TotalNumValueSitesWithValueProfile(0),
@@ -965,6 +1050,8 @@ int main(int argc, const char *argv[]) {
       func = merge_main;
     else if (strcmp(argv[1], "show") == 0)
       func = show_main;
+    else if (strcmp(argv[1], "overlap") == 0)
+      func = overlap_main;
 
     if (func) {
       std::string Invocation(ProgName.str() + " " + argv[1]);
@@ -979,7 +1066,7 @@ int main(int argc, const char *argv[]) {
              << "USAGE: " << ProgName << " <command> [args...]\n"
              << "USAGE: " << ProgName << " <command> -help\n\n"
              << "See each individual command --help for more details.\n"
-             << "Available commands: merge, show\n";
+             << "Available commands: merge, show, overlap\n";
       return 0;
     }
   }
@@ -989,6 +1076,6 @@ int main(int argc, const char *argv[]) {
   else
     errs() << ProgName << ": Unknown command!\n";
 
-  errs() << "USAGE: " << ProgName << " <merge|show> [args...]\n";
+  errs() << "USAGE: " << ProgName << " <merge|show|overlap> [args...]\n";
   return 1;
 }




More information about the llvm-commits mailing list