[llvm] r221032 - Add show and merge tools for sample PGO profiles.

Diego Novillo dnovillo at google.com
Fri Oct 31 17:56:55 PDT 2014


Author: dnovillo
Date: Fri Oct 31 19:56:55 2014
New Revision: 221032

URL: http://llvm.org/viewvc/llvm-project?rev=221032&view=rev
Log:
Add show and merge tools for sample PGO profiles.

Summary:
This patch extends the 'show' and 'merge' commands in llvm-profdata to handle
sample PGO formats. Using the 'merge' command it is now possible to convert
one sample PGO format to another.

The only format that is currently not working is 'gcc'. I still need to
implement support for it in lib/ProfileData.

The changes in the sample profile support classes are needed for the
merge operation.

Reviewers: bogner

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D6065

Added:
    llvm/trunk/test/tools/llvm-profdata/Inputs/sample-profile.proftext
    llvm/trunk/test/tools/llvm-profdata/sample-profile-basic.test
Modified:
    llvm/trunk/include/llvm/ProfileData/SampleProf.h
    llvm/trunk/include/llvm/ProfileData/SampleProfReader.h
    llvm/trunk/include/llvm/ProfileData/SampleProfWriter.h
    llvm/trunk/lib/ProfileData/SampleProf.cpp
    llvm/trunk/lib/ProfileData/SampleProfReader.cpp
    llvm/trunk/lib/ProfileData/SampleProfWriter.cpp
    llvm/trunk/tools/llvm-profdata/llvm-profdata.cpp

Modified: llvm/trunk/include/llvm/ProfileData/SampleProf.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/SampleProf.h?rev=221032&r1=221031&r2=221032&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ProfileData/SampleProf.h (original)
+++ llvm/trunk/include/llvm/ProfileData/SampleProf.h Fri Oct 31 19:56:55 2014
@@ -16,6 +16,8 @@
 
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
 
 #include <system_error>
@@ -30,7 +32,8 @@ enum class sampleprof_error {
   unsupported_version,
   too_large,
   truncated,
-  malformed
+  malformed,
+  unrecognized_format
 };
 
 inline std::error_code make_error_code(sampleprof_error E) {
@@ -110,27 +113,49 @@ namespace sampleprof {
 /// will be a list of one or more functions.
 class SampleRecord {
 public:
-  typedef SmallVector<std::pair<std::string, unsigned>, 8> CallTargetList;
+  typedef StringMap<unsigned> CallTargetMap;
 
   SampleRecord() : NumSamples(0), CallTargets() {}
 
   /// \brief Increment the number of samples for this record by \p S.
-  void addSamples(unsigned S) { NumSamples += S; }
+  ///
+  /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
+  /// around unsigned integers.
+  void addSamples(unsigned S) {
+    if (NumSamples <= std::numeric_limits<unsigned>::max() - S)
+      NumSamples += S;
+    else
+      NumSamples = std::numeric_limits<unsigned>::max();
+  }
 
   /// \brief Add called function \p F with samples \p S.
-  void addCalledTarget(std::string F, unsigned S) {
-    CallTargets.push_back(std::make_pair(F, S));
+  ///
+  /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
+  /// around unsigned integers.
+  void addCalledTarget(StringRef F, unsigned S) {
+    unsigned &TargetSamples = CallTargets[F];
+    if (TargetSamples <= std::numeric_limits<unsigned>::max() - S)
+      TargetSamples += S;
+    else
+      TargetSamples = std::numeric_limits<unsigned>::max();
   }
 
   /// \brief Return true if this sample record contains function calls.
   bool hasCalls() const { return CallTargets.size() > 0; }
 
   unsigned getSamples() const { return NumSamples; }
-  const CallTargetList &getCallTargets() const { return CallTargets; }
+  const CallTargetMap &getCallTargets() const { return CallTargets; }
+
+  /// \brief Merge the samples in \p Other into this record.
+  void merge(const SampleRecord &Other) {
+    addSamples(Other.getSamples());
+    for (const auto &I : Other.getCallTargets())
+      addCalledTarget(I.first(), I.second);
+  }
 
 private:
   unsigned NumSamples;
-  CallTargetList CallTargets;
+  CallTargetMap CallTargets;
 };
 
 typedef DenseMap<LineLocation, SampleRecord> BodySampleMap;
@@ -143,7 +168,7 @@ typedef DenseMap<LineLocation, SampleRec
 class FunctionSamples {
 public:
   FunctionSamples() : TotalSamples(0), TotalHeadSamples(0) {}
-  void print(raw_ostream &OS);
+  void print(raw_ostream &OS = dbgs());
   void addTotalSamples(unsigned Num) { TotalSamples += Num; }
   void addHeadSamples(unsigned Num) { TotalHeadSamples += Num; }
   void addBodySamples(int LineOffset, unsigned Discriminator, unsigned Num) {
@@ -163,10 +188,16 @@ public:
                                                                          Num);
   }
 
+  /// \brief Return the sample record at the given location.
+  /// Each location is specified by \p LineOffset and \p Discriminator.
+  SampleRecord &sampleRecordAt(const LineLocation &Loc) {
+    return BodySamples[Loc];
+  }
+
   /// \brief Return the number of samples collected at the given location.
   /// Each location is specified by \p LineOffset and \p Discriminator.
   unsigned samplesAt(int LineOffset, unsigned Discriminator) {
-    return BodySamples[LineLocation(LineOffset, Discriminator)].getSamples();
+    return sampleRecordAt(LineLocation(LineOffset, Discriminator)).getSamples();
   }
 
   bool empty() const { return BodySamples.empty(); }
@@ -181,6 +212,17 @@ public:
   /// \brief Return all the samples collected in the body of the function.
   const BodySampleMap &getBodySamples() const { return BodySamples; }
 
+  /// \brief Merge the samples in \p Other into this one.
+  void merge(const FunctionSamples &Other) {
+    addTotalSamples(Other.getTotalSamples());
+    addHeadSamples(Other.getHeadSamples());
+    for (const auto &I : Other.getBodySamples()) {
+      const LineLocation &Loc = I.first;
+      const SampleRecord &Rec = I.second;
+      sampleRecordAt(Loc).merge(Rec);
+    }
+  }
+
 private:
   /// \brief Total number of samples collected inside this function.
   ///

Modified: llvm/trunk/include/llvm/ProfileData/SampleProfReader.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/SampleProfReader.h?rev=221032&r1=221031&r2=221032&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ProfileData/SampleProfReader.h (original)
+++ llvm/trunk/include/llvm/ProfileData/SampleProfReader.h Fri Oct 31 19:56:55 2014
@@ -21,6 +21,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/ProfileData/SampleProf.h"
+#include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/ErrorOr.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -64,9 +65,6 @@ public:
 
   virtual ~SampleProfileReader() {}
 
-  /// \brief Print all the profiles to dbgs().
-  void dump();
-
   /// \brief Read and validate the file header.
   virtual std::error_code readHeader() = 0;
 
@@ -74,16 +72,19 @@ public:
   virtual std::error_code read() = 0;
 
   /// \brief Print the profile for \p FName on stream \p OS.
-  void printFunctionProfile(raw_ostream &OS, StringRef FName);
+  void dumpFunctionProfile(StringRef FName, raw_ostream &OS = dbgs());
 
-  /// \brief Print the profile for \p FName on dbgs().
-  void dumpFunctionProfile(StringRef FName);
+  /// \brief Print all the profiles on stream \p OS.
+  void dump(raw_ostream &OS = dbgs());
 
   /// \brief Return the samples collected for function \p F.
   FunctionSamples *getSamplesFor(const Function &F) {
     return &Profiles[F.getName()];
   }
 
+  /// \brief Return all the profiles.
+  StringMap<FunctionSamples> &getProfiles() { return Profiles; }
+
   /// \brief Report a parse error message.
   void reportParseError(int64_t LineNumber, Twine Msg) const {
     Ctx.diagnose(DiagnosticInfoSampleProfile(Buffer->getBufferIdentifier(),
@@ -91,7 +92,7 @@ public:
   }
 
   /// \brief Create a sample profile reader appropriate to the file format.
-  static std::error_code create(std::string Filename,
+  static std::error_code create(StringRef Filename,
                                 std::unique_ptr<SampleProfileReader> &Reader,
                                 LLVMContext &C);
 

Modified: llvm/trunk/include/llvm/ProfileData/SampleProfWriter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/SampleProfWriter.h?rev=221032&r1=221031&r2=221032&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ProfileData/SampleProfWriter.h (original)
+++ llvm/trunk/include/llvm/ProfileData/SampleProfWriter.h Fri Oct 31 19:56:55 2014
@@ -24,6 +24,8 @@ namespace llvm {
 
 namespace sampleprof {
 
+enum SampleProfileFormat { SPF_None = 0, SPF_Text, SPF_Binary, SPF_GCC };
+
 /// \brief Sample-based profile writer. Base class.
 class SampleProfileWriter {
 public:
@@ -32,21 +34,47 @@ public:
       : OS(Filename, EC, Flags) {}
   virtual ~SampleProfileWriter() {}
 
-  /// \brief Write sample profiles in \p S for function \p F.
+  /// \brief Write sample profiles in \p S for function \p FName.
   ///
   /// \returns true if the file was updated successfully. False, otherwise.
-  virtual bool write(const Function &F, const FunctionSamples &S) = 0;
+  virtual bool write(StringRef FName, const FunctionSamples &S) = 0;
+
+  /// \brief Write sample profiles in \p S for function \p F.
+  bool write(const Function &F, const FunctionSamples &S) {
+    return write(F.getName(), S);
+  }
 
   /// \brief Write all the sample profiles for all the functions in \p M.
   ///
   /// \returns true if the file was updated successfully. False, otherwise.
   bool write(const Module &M, StringMap<FunctionSamples> &P) {
-    for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I)
-      if (!write((*I), P[I->getName()]))
+    for (const auto &F : M) {
+      StringRef Name = F.getName();
+      if (!write(Name, P[Name]))
+        return false;
+    }
+    return true;
+  }
+
+  /// \brief Write all the sample profiles in the given map of samples.
+  ///
+  /// \returns true if the file was updated successfully. False, otherwise.
+  bool write(StringMap<FunctionSamples> &ProfileMap) {
+    for (auto &I : ProfileMap) {
+      StringRef FName = I.first();
+      FunctionSamples &Profile = I.second;
+      if (!write(FName, Profile))
         return false;
+    }
     return true;
   }
 
+  /// \brief Profile writer factory. Create a new writer based on the value of
+  /// \p Format.
+  static std::error_code create(StringRef Filename,
+                                std::unique_ptr<SampleProfileWriter> &Result,
+                                SampleProfileFormat Format);
+
 protected:
   /// \brief Output stream where to emit the profile to.
   raw_fd_ostream OS;
@@ -58,7 +86,7 @@ public:
   SampleProfileWriterText(StringRef F, std::error_code &EC)
       : SampleProfileWriter(F, EC, sys::fs::F_Text) {}
 
-  bool write(const Function &F, const FunctionSamples &S) override;
+  bool write(StringRef FName, const FunctionSamples &S) override;
   bool write(const Module &M, StringMap<FunctionSamples> &P) {
     return SampleProfileWriter::write(M, P);
   }
@@ -69,7 +97,7 @@ class SampleProfileWriterBinary : public
 public:
   SampleProfileWriterBinary(StringRef F, std::error_code &EC);
 
-  bool write(const Function &F, const FunctionSamples &S) override;
+  bool write(StringRef F, const FunctionSamples &S) override;
   bool write(const Module &M, StringMap<FunctionSamples> &P) {
     return SampleProfileWriter::write(M, P);
   }

Modified: llvm/trunk/lib/ProfileData/SampleProf.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/SampleProf.cpp?rev=221032&r1=221031&r2=221032&view=diff
==============================================================================
--- llvm/trunk/lib/ProfileData/SampleProf.cpp (original)
+++ llvm/trunk/lib/ProfileData/SampleProf.cpp Fri Oct 31 19:56:55 2014
@@ -36,6 +36,8 @@ class SampleProfErrorCategoryType : publ
       return "Truncated profile data";
     case sampleprof_error::malformed:
       return "Malformed profile data";
+    case sampleprof_error::unrecognized_format:
+      return "Unrecognized profile encoding format";
     }
     llvm_unreachable("A value of sampleprof_error has no message.");
   }

Modified: llvm/trunk/lib/ProfileData/SampleProfReader.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/SampleProfReader.cpp?rev=221032&r1=221031&r2=221032&view=diff
==============================================================================
--- llvm/trunk/lib/ProfileData/SampleProfReader.cpp (original)
+++ llvm/trunk/lib/ProfileData/SampleProfReader.cpp Fri Oct 31 19:56:55 2014
@@ -95,7 +95,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/ProfileData/SampleProfReader.h"
-#include "llvm/ProfileData/SampleProfWriter.h" // REMOVE
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorOr.h"
 #include "llvm/Support/LEB128.h"
@@ -112,50 +111,36 @@ using namespace llvm;
 void FunctionSamples::print(raw_ostream &OS) {
   OS << TotalSamples << ", " << TotalHeadSamples << ", " << BodySamples.size()
      << " sampled lines\n";
-  for (BodySampleMap::const_iterator SI = BodySamples.begin(),
-                                     SE = BodySamples.end();
-       SI != SE; ++SI) {
-    LineLocation Loc = SI->first;
-    SampleRecord Sample = SI->second;
+  for (const auto &SI : BodySamples) {
+    LineLocation Loc = SI.first;
+    const SampleRecord &Sample = SI.second;
     OS << "\tline offset: " << Loc.LineOffset
        << ", discriminator: " << Loc.Discriminator
        << ", number of samples: " << Sample.getSamples();
     if (Sample.hasCalls()) {
       OS << ", calls:";
-      for (SampleRecord::CallTargetList::const_iterator
-               I = Sample.getCallTargets().begin(),
-               E = Sample.getCallTargets().end();
-           I != E; ++I)
-        OS << " " << (*I).first << ":" << (*I).second;
+      for (const auto &I : Sample.getCallTargets())
+        OS << " " << I.first() << ":" << I.second;
     }
     OS << "\n";
   }
   OS << "\n";
 }
 
-/// \brief Print the function profile for \p FName on stream \p OS.
+/// \brief Dump the function profile for \p FName.
 ///
-/// \param OS Stream to emit the output to.
 /// \param FName Name of the function to print.
-void SampleProfileReader::printFunctionProfile(raw_ostream &OS,
-                                               StringRef FName) {
+/// \param OS Stream to emit the output to.
+void SampleProfileReader::dumpFunctionProfile(StringRef FName,
+                                              raw_ostream &OS) {
   OS << "Function: " << FName << ": ";
   Profiles[FName].print(OS);
 }
 
-/// \brief Dump the function profile for \p FName.
-///
-/// \param FName Name of the function to print.
-void SampleProfileReader::dumpFunctionProfile(StringRef FName) {
-  printFunctionProfile(dbgs(), FName);
-}
-
-/// \brief Dump all the function profiles found.
-void SampleProfileReader::dump() {
-  for (StringMap<FunctionSamples>::const_iterator I = Profiles.begin(),
-                                                  E = Profiles.end();
-       I != E; ++I)
-    dumpFunctionProfile(I->getKey());
+/// \brief Dump all the function profiles found on stream \p OS.
+void SampleProfileReader::dump(raw_ostream &OS) {
+  for (const auto &I : Profiles)
+    dumpFunctionProfile(I.getKey(), OS);
 }
 
 /// \brief Load samples from a text file.
@@ -245,8 +230,7 @@ std::error_code SampleProfileReaderText:
   return sampleprof_error::success;
 }
 
-template <typename T>
-ErrorOr<T> SampleProfileReaderBinary::readNumber() {
+template <typename T> ErrorOr<T> SampleProfileReaderBinary::readNumber() {
   unsigned NumBytesRead = 0;
   std::error_code EC;
   uint64_t Val = decodeULEB128(Data, &NumBytesRead);
@@ -396,7 +380,7 @@ setupMemoryBuffer(std::string Filename,
 ///
 /// \returns an error code indicating the status of the created reader.
 std::error_code
-SampleProfileReader::create(std::string Filename,
+SampleProfileReader::create(StringRef Filename,
                             std::unique_ptr<SampleProfileReader> &Reader,
                             LLVMContext &C) {
   std::unique_ptr<MemoryBuffer> Buffer;

Modified: llvm/trunk/lib/ProfileData/SampleProfWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/SampleProfWriter.cpp?rev=221032&r1=221031&r2=221032&view=diff
==============================================================================
--- llvm/trunk/lib/ProfileData/SampleProfWriter.cpp (original)
+++ llvm/trunk/lib/ProfileData/SampleProfWriter.cpp Fri Oct 31 19:56:55 2014
@@ -30,19 +30,16 @@ using namespace llvm::sampleprof;
 using namespace llvm;
 
 /// \brief Write samples to a text file.
-bool SampleProfileWriterText::write(const Function &F,
-                                    const FunctionSamples &S) {
+bool SampleProfileWriterText::write(StringRef FName, const FunctionSamples &S) {
   if (S.empty())
     return true;
 
-  OS << F.getName() << ":" << S.getTotalSamples() << ":" << S.getHeadSamples()
+  OS << FName << ":" << S.getTotalSamples() << ":" << S.getHeadSamples()
      << "\n";
 
-  for (BodySampleMap::const_iterator I = S.getBodySamples().begin(),
-                                     E = S.getBodySamples().end();
-       I != E; ++I) {
-    LineLocation Loc = I->first;
-    SampleRecord Sample = I->second;
+  for (const auto &I : S.getBodySamples()) {
+    LineLocation Loc = I.first;
+    const SampleRecord &Sample = I.second;
     if (Loc.Discriminator == 0)
       OS << Loc.LineOffset << ": ";
     else
@@ -50,11 +47,8 @@ bool SampleProfileWriterText::write(cons
 
     OS << Sample.getSamples();
 
-    for (SampleRecord::CallTargetList::const_iterator
-             I = Sample.getCallTargets().begin(),
-             E = Sample.getCallTargets().end();
-         I != E; ++I)
-      OS << " " << (*I).first << ":" << (*I).second;
+    for (const auto &J : Sample.getCallTargets())
+      OS << " " << J.first() << ":" << J.second;
     OS << "\n";
   }
 
@@ -75,31 +69,26 @@ SampleProfileWriterBinary::SampleProfile
 /// \brief Write samples to a binary file.
 ///
 /// \returns true if the samples were written successfully, false otherwise.
-bool SampleProfileWriterBinary::write(const Function &F,
+bool SampleProfileWriterBinary::write(StringRef FName,
                                       const FunctionSamples &S) {
   if (S.empty())
     return true;
 
-  OS << F.getName();
+  OS << FName;
   encodeULEB128(0, OS);
   encodeULEB128(S.getTotalSamples(), OS);
   encodeULEB128(S.getHeadSamples(), OS);
   encodeULEB128(S.getBodySamples().size(), OS);
-  for (BodySampleMap::const_iterator I = S.getBodySamples().begin(),
-                                     E = S.getBodySamples().end();
-       I != E; ++I) {
-    LineLocation Loc = I->first;
-    SampleRecord Sample = I->second;
+  for (const auto &I : S.getBodySamples()) {
+    LineLocation Loc = I.first;
+    const SampleRecord &Sample = I.second;
     encodeULEB128(Loc.LineOffset, OS);
     encodeULEB128(Loc.Discriminator, OS);
     encodeULEB128(Sample.getSamples(), OS);
     encodeULEB128(Sample.getCallTargets().size(), OS);
-    for (SampleRecord::CallTargetList::const_iterator
-             I = Sample.getCallTargets().begin(),
-             E = Sample.getCallTargets().end();
-         I != E; ++I) {
-      std::string Callee = (*I).first;
-      unsigned CalleeSamples = (*I).second;
+    for (const auto &J : Sample.getCallTargets()) {
+      std::string Callee = J.first();
+      unsigned CalleeSamples = J.second;
       OS << Callee;
       encodeULEB128(0, OS);
       encodeULEB128(CalleeSamples, OS);
@@ -108,3 +97,28 @@ bool SampleProfileWriterBinary::write(co
 
   return true;
 }
+
+/// \brief Create a sample profile writer based on the specified format.
+///
+/// \param Filename The file to create.
+///
+/// \param Writer The writer to instantiate according to the specified format.
+///
+/// \param Format Encoding format for the profile file.
+///
+/// \returns an error code indicating the status of the created writer.
+std::error_code
+SampleProfileWriter::create(StringRef Filename,
+                            std::unique_ptr<SampleProfileWriter> &Writer,
+                            SampleProfileFormat Format) {
+  std::error_code EC;
+
+  if (Format == SPF_Binary)
+    Writer.reset(new SampleProfileWriterBinary(Filename, EC));
+  else if (Format == SPF_Text)
+    Writer.reset(new SampleProfileWriterText(Filename, EC));
+  else
+    EC = sampleprof_error::unrecognized_format;
+
+  return EC;
+}

Added: llvm/trunk/test/tools/llvm-profdata/Inputs/sample-profile.proftext
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-profdata/Inputs/sample-profile.proftext?rev=221032&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-profdata/Inputs/sample-profile.proftext (added)
+++ llvm/trunk/test/tools/llvm-profdata/Inputs/sample-profile.proftext Fri Oct 31 19:56:55 2014
@@ -0,0 +1,12 @@
+_Z3bari:20301:1437
+1: 1437
+_Z3fooi:7711:610
+1: 610
+main:184019:0
+4: 534
+4.2: 534
+5: 1075
+5.1: 1075
+6: 2080
+7: 534
+9: 2064  _Z3bari:1471  _Z3fooi:631

Added: llvm/trunk/test/tools/llvm-profdata/sample-profile-basic.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-profdata/sample-profile-basic.test?rev=221032&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-profdata/sample-profile-basic.test (added)
+++ llvm/trunk/test/tools/llvm-profdata/sample-profile-basic.test Fri Oct 31 19:56:55 2014
@@ -0,0 +1,30 @@
+Basic tests for sample profiles.
+
+1- Show all functions
+RUN: llvm-profdata show --sample %p/Inputs/sample-profile.proftext | FileCheck %s --check-prefix=SHOW1
+SHOW1: Function: main: 184019, 0, 7 sampled lines
+SHOW1: line offset: 9, discriminator: 0, number of samples: 2064, calls: _Z3fooi:631 _Z3bari:1471
+SHOW1: Function: _Z3fooi: 7711, 610, 1 sampled lines
+SHOW1: Function: _Z3bari: 20301, 1437, 1 sampled lines
+SHOW1: line offset: 1, discriminator: 0, number of samples: 1437
+
+2- Show only bar
+RUN: llvm-profdata show --sample --function=_Z3bari %p/Inputs/sample-profile.proftext | FileCheck %s --check-prefix=SHOW2
+SHOW2: Function: _Z3bari: 20301, 1437, 1 sampled lines
+SHOW2: line offset: 1, discriminator: 0, number of samples: 1437
+SHOW2-NOT: Function: main: 184019, 0, 7 sampled lines
+SHOW2-NOT: Function: _Z3fooi: 7711, 610, 1 sampled lines
+
+3- Convert the profile to binary encoding and check that they are both
+   identical.
+RUN: llvm-profdata merge --sample %p/Inputs/sample-profile.proftext --binary -o - | llvm-profdata show --sample - -o %t-binary
+RUN: llvm-profdata show --sample %p/Inputs/sample-profile.proftext -o %t-text
+RUN: diff %t-binary %t-text
+
+4- Merge the binary and text encodings of the profile and check that the
+   counters have doubled.
+RUN: llvm-profdata merge --sample %p/Inputs/sample-profile.proftext -o %t-binprof
+RUN: llvm-profdata merge --sample --text %p/Inputs/sample-profile.proftext %t-binprof -o - | FileCheck %s --check-prefix=MERGE1
+MERGE1: main:368038:0
+MERGE1: 9: 4128 _Z3fooi:1262 _Z3bari:2942
+MERGE1: _Z3fooi:15422:1220

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=221032&r1=221031&r2=221032&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-profdata/llvm-profdata.cpp (original)
+++ llvm/trunk/tools/llvm-profdata/llvm-profdata.cpp Fri Oct 31 19:56:55 2014
@@ -14,6 +14,9 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/ProfileData/InstrProfWriter.h"
+#include "llvm/ProfileData/SampleProfReader.h"
+#include "llvm/ProfileData/SampleProfWriter.h"
+#include "llvm/IR/LLVMContext.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Format.h"
@@ -33,18 +36,9 @@ static void exitWithError(const Twine &M
   ::exit(1);
 }
 
-int merge_main(int argc, const char *argv[]) {
-  cl::list<std::string> Inputs(cl::Positional, cl::Required, cl::OneOrMore,
-                               cl::desc("<filenames...>"));
-
-  cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
-                                      cl::init("-"), cl::Required,
-                                      cl::desc("Output file"));
-  cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
-                            cl::aliasopt(OutputFilename));
-
-  cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
+enum ProfileKinds { instr, sample };
 
+void mergeInstrProfile(cl::list<std::string> Inputs, StringRef OutputFilename) {
   if (OutputFilename.compare("-") == 0)
     exitWithError("Cannot write indexed profdata format to stdout.");
 
@@ -67,50 +61,84 @@ int merge_main(int argc, const char *arg
       exitWithError(Reader->getError().message(), Filename);
   }
   Writer.write(Output);
-
-  return 0;
 }
 
-int show_main(int argc, const char *argv[]) {
-  cl::opt<std::string> Filename(cl::Positional, cl::Required,
-                                cl::desc("<profdata-file>"));
+void mergeSampleProfile(cl::list<std::string> Inputs, StringRef OutputFilename,
+                        sampleprof::SampleProfileFormat OutputFormat) {
+  using namespace sampleprof;
+  std::unique_ptr<SampleProfileWriter> Writer;
+  if (std::error_code EC = SampleProfileWriter::create(OutputFilename.data(),
+                                                       Writer, OutputFormat))
+    exitWithError(EC.message(), OutputFilename);
 
-  cl::opt<bool> ShowCounts("counts", cl::init(false),
-                           cl::desc("Show counter values for shown functions"));
-  cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false),
-                                 cl::desc("Details for every function"));
-  cl::opt<std::string> ShowFunction("function",
-                                    cl::desc("Details for matching functions"));
+  StringMap<FunctionSamples> ProfileMap;
+  for (const auto &Filename : Inputs) {
+    std::unique_ptr<SampleProfileReader> Reader;
+    if (std::error_code EC =
+            SampleProfileReader::create(Filename, Reader, getGlobalContext()))
+      exitWithError(EC.message(), Filename);
+
+    if (std::error_code EC = Reader->read())
+      exitWithError(EC.message(), Filename);
+
+    StringMap<FunctionSamples> &Profiles = Reader->getProfiles();
+    for (StringMap<FunctionSamples>::iterator I = Profiles.begin(),
+                                              E = Profiles.end();
+         I != E; ++I) {
+      StringRef FName = I->first();
+      FunctionSamples &Samples = I->second;
+      ProfileMap[FName].merge(Samples);
+    }
+  }
+  Writer->write(ProfileMap);
+}
+
+int merge_main(int argc, const char *argv[]) {
+  cl::list<std::string> Inputs(cl::Positional, cl::Required, cl::OneOrMore,
+                               cl::desc("<filenames...>"));
 
   cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
-                                      cl::init("-"),
+                                      cl::init("-"), cl::Required,
                                       cl::desc("Output file"));
   cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
                             cl::aliasopt(OutputFilename));
+  cl::opt<ProfileKinds> ProfileKind(
+      cl::desc("Profile kind:"), cl::init(instr),
+      cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
+                 clEnumVal(sample, "Sample profile"), clEnumValEnd));
+
+  cl::opt<sampleprof::SampleProfileFormat> OutputFormat(
+      cl::desc("Format of output profile (only meaningful with --sample)"),
+      cl::init(sampleprof::SPF_Binary),
+      cl::values(clEnumValN(sampleprof::SPF_Binary, "binary",
+                            "Binary encoding (default)"),
+                 clEnumValN(sampleprof::SPF_Text, "text", "Text encoding"),
+                 clEnumValN(sampleprof::SPF_GCC, "gcc", "GCC encoding"),
+                 clEnumValEnd));
 
-  cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
+  cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
+
+  if (ProfileKind == instr)
+    mergeInstrProfile(Inputs, OutputFilename);
+  else
+    mergeSampleProfile(Inputs, OutputFilename, OutputFormat);
+
+  return 0;
+}
 
+int showInstrProfile(std::string Filename, bool ShowCounts,
+                     bool ShowAllFunctions, std::string ShowFunction,
+                     raw_fd_ostream &OS) {
   std::unique_ptr<InstrProfReader> Reader;
   if (std::error_code EC = InstrProfReader::create(Filename, Reader))
     exitWithError(EC.message(), Filename);
 
-  if (OutputFilename.empty())
-    OutputFilename = "-";
-
-  std::error_code EC;
-  raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text);
-  if (EC)
-    exitWithError(EC.message(), OutputFilename);
-
-  if (ShowAllFunctions && !ShowFunction.empty())
-    errs() << "warning: -function argument ignored: showing all functions\n";
-
   uint64_t MaxFunctionCount = 0, MaxBlockCount = 0;
   size_t ShownFunctions = 0, TotalFunctions = 0;
   for (const auto &Func : *Reader) {
-    bool Show = ShowAllFunctions ||
-                (!ShowFunction.empty() &&
-                 Func.Name.find(ShowFunction) != Func.Name.npos);
+    bool Show =
+        ShowAllFunctions || (!ShowFunction.empty() &&
+                             Func.Name.find(ShowFunction) != Func.Name.npos);
 
     ++TotalFunctions;
     assert(Func.Counts.size() > 0 && "function missing entry counter");
@@ -150,6 +178,65 @@ int show_main(int argc, const char *argv
   return 0;
 }
 
+int showSampleProfile(std::string Filename, bool ShowCounts,
+                      bool ShowAllFunctions, std::string ShowFunction,
+                      raw_fd_ostream &OS) {
+  using namespace sampleprof;
+  std::unique_ptr<SampleProfileReader> Reader;
+  if (std::error_code EC =
+          SampleProfileReader::create(Filename, Reader, getGlobalContext()))
+    exitWithError(EC.message(), Filename);
+
+  Reader->read();
+  if (ShowAllFunctions || ShowFunction.empty())
+    Reader->dump(OS);
+  else
+    Reader->dumpFunctionProfile(ShowFunction, OS);
+
+  return 0;
+}
+
+int show_main(int argc, const char *argv[]) {
+  cl::opt<std::string> Filename(cl::Positional, cl::Required,
+                                cl::desc("<profdata-file>"));
+
+  cl::opt<bool> ShowCounts("counts", cl::init(false),
+                           cl::desc("Show counter values for shown functions"));
+  cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false),
+                                 cl::desc("Details for every function"));
+  cl::opt<std::string> ShowFunction("function",
+                                    cl::desc("Details for matching functions"));
+
+  cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
+                                      cl::init("-"), cl::desc("Output file"));
+  cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
+                            cl::aliasopt(OutputFilename));
+  cl::opt<ProfileKinds> ProfileKind(
+      cl::desc("Profile kind:"), cl::init(instr),
+      cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
+                 clEnumVal(sample, "Sample profile"), clEnumValEnd));
+
+  cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
+
+  if (OutputFilename.empty())
+    OutputFilename = "-";
+
+  std::error_code EC;
+  raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text);
+  if (EC)
+    exitWithError(EC.message(), OutputFilename);
+
+  if (ShowAllFunctions && !ShowFunction.empty())
+    errs() << "warning: -function argument ignored: showing all functions\n";
+
+  if (ProfileKind == instr)
+    return showInstrProfile(Filename, ShowCounts, ShowAllFunctions,
+                            ShowFunction, OS);
+  else
+    return showSampleProfile(Filename, ShowCounts, ShowAllFunctions,
+                             ShowFunction, OS);
+}
+
 int main(int argc, const char *argv[]) {
   // Print a stack trace if we signal out.
   sys::PrintStackTraceOnErrorSignal();





More information about the llvm-commits mailing list