[llvm] r369798 - [SampleFDO] Add ExtBinary format to support extension of binary profile.

Wei Mi via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 23 12:05:31 PDT 2019


Author: wmi
Date: Fri Aug 23 12:05:30 2019
New Revision: 369798

URL: http://llvm.org/viewvc/llvm-project?rev=369798&view=rev
Log:
[SampleFDO] Add ExtBinary format to support extension of binary profile.

This is a patch split from https://reviews.llvm.org/D66374. It tries to add
a new format of profile called ExtBinary. The format adds a section header
table to the profile and organize the profile in sections, so the future
extension like adding a new section or extending an existing section will be
easier while keeping backward compatiblity feasible.

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


Added:
    llvm/trunk/test/Transforms/SampleProfile/Inputs/inline.extbinary.afdo   (with props)
    llvm/trunk/test/Transforms/SampleProfile/profile-format.ll
Removed:
    llvm/trunk/test/Transforms/SampleProfile/compact-binary-profile.ll
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/SampleProfReader.cpp
    llvm/trunk/lib/ProfileData/SampleProfWriter.cpp
    llvm/trunk/test/tools/llvm-profdata/roundtrip.test
    llvm/trunk/tools/llvm-profdata/llvm-profdata.cpp
    llvm/trunk/unittests/ProfileData/SampleProfTest.cpp

Modified: llvm/trunk/include/llvm/ProfileData/SampleProf.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/SampleProf.h?rev=369798&r1=369797&r2=369798&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ProfileData/SampleProf.h (original)
+++ llvm/trunk/include/llvm/ProfileData/SampleProf.h Fri Aug 23 12:05:30 2019
@@ -84,6 +84,7 @@ enum SampleProfileFormat {
   SPF_Text = 0x1,
   SPF_Compact_Binary = 0x2,
   SPF_GCC = 0x3,
+  SPF_Ext_Binary = 0x4,
   SPF_Binary = 0xff
 };
 
@@ -106,6 +107,27 @@ static inline StringRef getRepInFormat(S
 
 static inline uint64_t SPVersion() { return 103; }
 
+// Section Type used by SampleProfileExtBinaryBaseReader and
+// SampleProfileExtBinaryBaseWriter. Never change the existing
+// value of enum. Only append new ones.
+enum SecType {
+  SecInValid = 0,
+  SecProfSummary = 1,
+  SecNameTable = 2,
+  // marker for the first type of profile.
+  SecFuncProfileFirst = 32,
+  SecLBRProfile = SecFuncProfileFirst
+};
+
+// Entry type of section header table used by SampleProfileExtBinaryBaseReader
+// and SampleProfileExtBinaryBaseWriter.
+struct SecHdrTableEntry {
+  SecType Type;
+  uint64_t Flag;
+  uint64_t Offset;
+  uint64_t Size;
+};
+
 /// Represents the relative location of an instruction.
 ///
 /// Instruction locations are specified by the line offset from the

Modified: llvm/trunk/include/llvm/ProfileData/SampleProfReader.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/SampleProfReader.h?rev=369798&r1=369797&r2=369798&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ProfileData/SampleProfReader.h (original)
+++ llvm/trunk/include/llvm/ProfileData/SampleProfReader.h Fri Aug 23 12:05:30 2019
@@ -416,38 +416,89 @@ protected:
   /// Read the contents of the given profile instance.
   std::error_code readProfile(FunctionSamples &FProfile);
 
+  /// Read the contents of Magic number and Version number.
+  std::error_code readMagicIdent();
+
+  /// Read profile summary.
+  std::error_code readSummary();
+
+  /// Read the whole name table.
+  virtual std::error_code readNameTable();
+
   /// Points to the current location in the buffer.
   const uint8_t *Data = nullptr;
 
   /// Points to the end of the buffer.
   const uint8_t *End = nullptr;
 
+  /// Function name table.
+  std::vector<StringRef> NameTable;
+
+  /// Read a string indirectly via the name table.
+  virtual ErrorOr<StringRef> readStringFromTable();
+
 private:
   std::error_code readSummaryEntry(std::vector<ProfileSummaryEntry> &Entries);
   virtual std::error_code verifySPMagic(uint64_t Magic) = 0;
+};
 
-  /// Read profile summary.
-  std::error_code readSummary();
+class SampleProfileReaderRawBinary : public SampleProfileReaderBinary {
+private:
+  virtual std::error_code verifySPMagic(uint64_t Magic) override;
 
-  /// Read the whole name table.
-  virtual std::error_code readNameTable() = 0;
+public:
+  SampleProfileReaderRawBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C,
+                               SampleProfileFormat Format = SPF_Binary)
+      : SampleProfileReaderBinary(std::move(B), C, Format) {}
 
-  /// Read a string indirectly via the name table.
-  virtual ErrorOr<StringRef> readStringFromTable() = 0;
+  /// \brief Return true if \p Buffer is in the format supported by this class.
+  static bool hasFormat(const MemoryBuffer &Buffer);
 };
 
-class SampleProfileReaderRawBinary : public SampleProfileReaderBinary {
+/// SampleProfileReaderExtBinaryBase/SampleProfileWriterExtBinaryBase defines
+/// the basic structure of the extensible binary format.
+/// The format is organized in sections except the magic and version number
+/// at the beginning. There is a section table before all the sections, and
+/// each entry in the table describes the entry type, start, size and
+/// attributes. The format in each section is defined by the section itself.
+///
+/// It is easy to add a new section while maintaining the backward
+/// compatibility of the profile. Nothing extra needs to be done. If we want
+/// to extend an existing section, like add cache misses information in
+/// addition to the sample count in the profile body, we can add a new section
+/// with the extension and retire the existing section, and we could choose
+/// to keep the parser of the old section if we want the reader to be able
+/// to read both new and old format profile.
+///
+/// SampleProfileReaderExtBinary/SampleProfileWriterExtBinary define the
+/// commonly used sections of a profile in extensible binary format. It is
+/// possible to define other types of profile inherited from
+/// SampleProfileReaderExtBinaryBase/SampleProfileWriterExtBinaryBase.
+class SampleProfileReaderExtBinaryBase : public SampleProfileReaderBinary {
+protected:
+  std::vector<SecHdrTableEntry> SecHdrTable;
+  std::error_code readSecHdrTableEntry();
+  std::error_code readSecHdrTable();
+  virtual std::error_code readHeader() override;
+  virtual std::error_code verifySPMagic(uint64_t Magic) = 0;
+
+public:
+  SampleProfileReaderExtBinaryBase(std::unique_ptr<MemoryBuffer> B,
+                                   LLVMContext &C, SampleProfileFormat Format)
+      : SampleProfileReaderBinary(std::move(B), C, Format) {}
+
+  /// Read sample profiles in extensible format from the associated file.
+  std::error_code read() override;
+};
+
+class SampleProfileReaderExtBinary : public SampleProfileReaderExtBinaryBase {
 private:
-  /// Function name table.
-  std::vector<StringRef> NameTable;
   virtual std::error_code verifySPMagic(uint64_t Magic) override;
-  virtual std::error_code readNameTable() override;
-  /// Read a string indirectly via the name table.
-  virtual ErrorOr<StringRef> readStringFromTable() override;
 
 public:
-  SampleProfileReaderRawBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
-      : SampleProfileReaderBinary(std::move(B), C, SPF_Binary) {}
+  SampleProfileReaderExtBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C,
+                               SampleProfileFormat Format = SPF_Ext_Binary)
+      : SampleProfileReaderExtBinaryBase(std::move(B), C, Format) {}
 
   /// \brief Return true if \p Buffer is in the format supported by this class.
   static bool hasFormat(const MemoryBuffer &Buffer);

Modified: llvm/trunk/include/llvm/ProfileData/SampleProfWriter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/SampleProfWriter.h?rev=369798&r1=369797&r2=369798&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ProfileData/SampleProfWriter.h (original)
+++ llvm/trunk/include/llvm/ProfileData/SampleProfWriter.h Fri Aug 23 12:05:30 2019
@@ -36,7 +36,7 @@ public:
   /// Write sample profiles in \p S.
   ///
   /// \returns status code of the file update operation.
-  virtual std::error_code write(const FunctionSamples &S) = 0;
+  virtual std::error_code writeSample(const FunctionSamples &S) = 0;
 
   /// Write all the sample profiles in the given map of samples.
   ///
@@ -64,6 +64,10 @@ protected:
   virtual std::error_code
   writeHeader(const StringMap<FunctionSamples> &ProfileMap) = 0;
 
+  // Write function profiles to the profile file.
+  virtual std::error_code
+  writeFuncProfiles(const StringMap<FunctionSamples> &ProfileMap);
+
   /// Output stream where to emit the profile to.
   std::unique_ptr<raw_ostream> OutputStream;
 
@@ -72,12 +76,15 @@ protected:
 
   /// Compute summary for this profile.
   void computeSummary(const StringMap<FunctionSamples> &ProfileMap);
+
+  /// Profile format.
+  SampleProfileFormat Format;
 };
 
 /// Sample-based profile writer (text format).
 class SampleProfileWriterText : public SampleProfileWriter {
 public:
-  std::error_code write(const FunctionSamples &S) override;
+  std::error_code writeSample(const FunctionSamples &S) override;
 
 protected:
   SampleProfileWriterText(std::unique_ptr<raw_ostream> &OS)
@@ -102,13 +109,14 @@ private:
 /// Sample-based profile writer (binary format).
 class SampleProfileWriterBinary : public SampleProfileWriter {
 public:
-  virtual std::error_code write(const FunctionSamples &S) override;
+  virtual std::error_code writeSample(const FunctionSamples &S) override;
+
+protected:
   SampleProfileWriterBinary(std::unique_ptr<raw_ostream> &OS)
       : SampleProfileWriter(OS) {}
 
-protected:
-  virtual std::error_code writeNameTable() = 0;
-  virtual std::error_code writeMagicIdent() = 0;
+  virtual std::error_code writeMagicIdent(SampleProfileFormat Format);
+  virtual std::error_code writeNameTable();
   virtual std::error_code
   writeHeader(const StringMap<FunctionSamples> &ProfileMap) override;
   std::error_code writeSummary();
@@ -118,10 +126,10 @@ protected:
 
   MapVector<StringRef, uint32_t> NameTable;
 
-private:
   void addName(StringRef FName);
   void addNames(const FunctionSamples &S);
 
+private:
   friend ErrorOr<std::unique_ptr<SampleProfileWriter>>
   SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS,
                               SampleProfileFormat Format);
@@ -129,10 +137,50 @@ private:
 
 class SampleProfileWriterRawBinary : public SampleProfileWriterBinary {
   using SampleProfileWriterBinary::SampleProfileWriterBinary;
+};
+
+class SampleProfileWriterExtBinaryBase : public SampleProfileWriterBinary {
+  using SampleProfileWriterBinary::SampleProfileWriterBinary;
+
+public:
+  virtual std::error_code
+  write(const StringMap<FunctionSamples> &ProfileMap) override;
 
 protected:
-  virtual std::error_code writeNameTable() override;
-  virtual std::error_code writeMagicIdent() override;
+  uint64_t markSectionStart();
+  uint64_t addNewSection(SecType Sec, uint64_t SectionStart);
+  virtual void initSectionLayout() = 0;
+  virtual std::error_code
+  writeSections(const StringMap<FunctionSamples> &ProfileMap) = 0;
+
+  // Specifiy the section layout in the profile. Note that the order in
+  // SecHdrTable (order to collect sections) may be different from the
+  // order in SectionLayout (order to write out sections into profile).
+  SmallVector<SecType, 8> SectionLayout;
+
+private:
+  void allocSecHdrTable();
+  std::error_code writeSecHdrTable();
+  virtual std::error_code
+  writeHeader(const StringMap<FunctionSamples> &ProfileMap) override;
+
+  // The location where the output stream starts.
+  uint64_t FileStart;
+  // The location in the output stream where the SecHdrTable should be
+  // written to.
+  uint64_t SecHdrTableOffset;
+  std::vector<SecHdrTableEntry> SecHdrTable;
+};
+
+class SampleProfileWriterExtBinary : public SampleProfileWriterExtBinaryBase {
+  using SampleProfileWriterExtBinaryBase::SampleProfileWriterExtBinaryBase;
+
+private:
+  virtual void initSectionLayout() {
+    SectionLayout = {SecProfSummary, SecNameTable, SecLBRProfile};
+  };
+  virtual std::error_code
+  writeSections(const StringMap<FunctionSamples> &ProfileMap) override;
 };
 
 // CompactBinary is a compact format of binary profile which both reduces
@@ -169,7 +217,7 @@ class SampleProfileWriterCompactBinary :
   using SampleProfileWriterBinary::SampleProfileWriterBinary;
 
 public:
-  virtual std::error_code write(const FunctionSamples &S) override;
+  virtual std::error_code writeSample(const FunctionSamples &S) override;
   virtual std::error_code
   write(const StringMap<FunctionSamples> &ProfileMap) override;
 
@@ -181,7 +229,6 @@ protected:
   /// towards profile start.
   uint64_t TableOffset;
   virtual std::error_code writeNameTable() override;
-  virtual std::error_code writeMagicIdent() override;
   virtual std::error_code
   writeHeader(const StringMap<FunctionSamples> &ProfileMap) override;
   std::error_code writeFuncOffsetTable();

Modified: llvm/trunk/lib/ProfileData/SampleProfReader.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/SampleProfReader.cpp?rev=369798&r1=369797&r2=369798&view=diff
==============================================================================
--- llvm/trunk/lib/ProfileData/SampleProfReader.cpp (original)
+++ llvm/trunk/lib/ProfileData/SampleProfReader.cpp Fri Aug 23 12:05:30 2019
@@ -345,7 +345,7 @@ inline ErrorOr<uint32_t> SampleProfileRe
   return *Idx;
 }
 
-ErrorOr<StringRef> SampleProfileReaderRawBinary::readStringFromTable() {
+ErrorOr<StringRef> SampleProfileReaderBinary::readStringFromTable() {
   auto Idx = readStringIndex(NameTable);
   if (std::error_code EC = Idx.getError())
     return EC;
@@ -467,6 +467,40 @@ std::error_code SampleProfileReaderBinar
   return sampleprof_error::success;
 }
 
+std::error_code SampleProfileReaderExtBinaryBase::read() {
+  const uint8_t *BufStart =
+      reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
+
+  for (auto &Entry : SecHdrTable) {
+    // Skip empty section.
+    if (!Entry.Size)
+      continue;
+    Data = BufStart + Entry.Offset;
+    switch (Entry.Type) {
+    case SecProfSummary:
+      if (std::error_code EC = readSummary())
+        return EC;
+      break;
+    case SecNameTable:
+      if (std::error_code EC = readNameTable())
+        return EC;
+      break;
+    case SecLBRProfile:
+      while (Data < BufStart + Entry.Offset + Entry.Size) {
+        if (std::error_code EC = readFuncProfile())
+          return EC;
+      }
+      break;
+    default:
+      continue;
+    }
+    if (Data != BufStart + Entry.Offset + Entry.Size)
+      return sampleprof_error::malformed;
+  }
+
+  return sampleprof_error::success;
+}
+
 std::error_code SampleProfileReaderCompactBinary::read() {
   std::vector<uint64_t> OffsetsToUse;
   if (UseAllFuncs) {
@@ -501,6 +535,12 @@ std::error_code SampleProfileReaderRawBi
   return sampleprof_error::bad_magic;
 }
 
+std::error_code SampleProfileReaderExtBinary::verifySPMagic(uint64_t Magic) {
+  if (Magic == SPMagic(SPF_Ext_Binary))
+    return sampleprof_error::success;
+  return sampleprof_error::bad_magic;
+}
+
 std::error_code
 SampleProfileReaderCompactBinary::verifySPMagic(uint64_t Magic) {
   if (Magic == SPMagic(SPF_Compact_Binary))
@@ -508,7 +548,7 @@ SampleProfileReaderCompactBinary::verify
   return sampleprof_error::bad_magic;
 }
 
-std::error_code SampleProfileReaderRawBinary::readNameTable() {
+std::error_code SampleProfileReaderBinary::readNameTable() {
   auto Size = readNumber<uint32_t>();
   if (std::error_code EC = Size.getError())
     return EC;
@@ -537,10 +577,60 @@ std::error_code SampleProfileReaderCompa
   return sampleprof_error::success;
 }
 
-std::error_code SampleProfileReaderBinary::readHeader() {
-  Data = reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
-  End = Data + Buffer->getBufferSize();
+std::error_code SampleProfileReaderExtBinaryBase::readSecHdrTableEntry() {
+  SecHdrTableEntry Entry;
+  auto Type = readUnencodedNumber<uint64_t>();
+  if (std::error_code EC = Type.getError())
+    return EC;
+  Entry.Type = static_cast<SecType>(*Type);
+
+  auto Flag = readUnencodedNumber<uint64_t>();
+  if (std::error_code EC = Flag.getError())
+    return EC;
+  Entry.Flag = *Flag;
+
+  auto Offset = readUnencodedNumber<uint64_t>();
+  if (std::error_code EC = Offset.getError())
+    return EC;
+  Entry.Offset = *Offset;
+
+  auto Size = readUnencodedNumber<uint64_t>();
+  if (std::error_code EC = Size.getError())
+    return EC;
+  Entry.Size = *Size;
+
+  SecHdrTable.push_back(std::move(Entry));
+  return sampleprof_error::success;
+}
+
+std::error_code SampleProfileReaderExtBinaryBase::readSecHdrTable() {
+  auto EntryNum = readUnencodedNumber<uint64_t>();
+  if (std::error_code EC = EntryNum.getError())
+    return EC;
 
+  for (uint32_t i = 0; i < (*EntryNum); i++)
+    if (std::error_code EC = readSecHdrTableEntry())
+      return EC;
+
+  return sampleprof_error::success;
+}
+
+std::error_code SampleProfileReaderExtBinaryBase::readHeader() {
+  const uint8_t *BufStart =
+      reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
+  Data = BufStart;
+  End = BufStart + Buffer->getBufferSize();
+
+  if (std::error_code EC = readMagicIdent())
+    return EC;
+
+  if (std::error_code EC = readSecHdrTable())
+    return EC;
+
+  return sampleprof_error::success;
+}
+
+std::error_code SampleProfileReaderBinary::readMagicIdent() {
   // Read and check the magic identifier.
   auto Magic = readNumber<uint64_t>();
   if (std::error_code EC = Magic.getError())
@@ -555,6 +645,16 @@ std::error_code SampleProfileReaderBinar
   else if (*Version != SPVersion())
     return sampleprof_error::unsupported_version;
 
+  return sampleprof_error::success;
+}
+
+std::error_code SampleProfileReaderBinary::readHeader() {
+  Data = reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
+  End = Data + Buffer->getBufferSize();
+
+  if (std::error_code EC = readMagicIdent())
+    return EC;
+
   if (std::error_code EC = readSummary())
     return EC;
 
@@ -674,6 +774,13 @@ bool SampleProfileReaderRawBinary::hasFo
   return Magic == SPMagic();
 }
 
+bool SampleProfileReaderExtBinary::hasFormat(const MemoryBuffer &Buffer) {
+  const uint8_t *Data =
+      reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
+  uint64_t Magic = decodeULEB128(Data);
+  return Magic == SPMagic(SPF_Ext_Binary);
+}
+
 bool SampleProfileReaderCompactBinary::hasFormat(const MemoryBuffer &Buffer) {
   const uint8_t *Data =
       reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
@@ -1023,6 +1130,8 @@ SampleProfileReader::create(std::unique_
   std::unique_ptr<SampleProfileReader> Reader;
   if (SampleProfileReaderRawBinary::hasFormat(*B))
     Reader.reset(new SampleProfileReaderRawBinary(std::move(B), C));
+  else if (SampleProfileReaderExtBinary::hasFormat(*B))
+    Reader.reset(new SampleProfileReaderExtBinary(std::move(B), C));
   else if (SampleProfileReaderCompactBinary::hasFormat(*B))
     Reader.reset(new SampleProfileReaderCompactBinary(std::move(B), C));
   else if (SampleProfileReaderGCC::hasFormat(*B))
@@ -1033,8 +1142,9 @@ SampleProfileReader::create(std::unique_
     return sampleprof_error::unrecognized_format;
 
   FunctionSamples::Format = Reader->getFormat();
-  if (std::error_code EC = Reader->readHeader())
+  if (std::error_code EC = Reader->readHeader()) {
     return EC;
+  }
 
   return std::move(Reader);
 }

Modified: llvm/trunk/lib/ProfileData/SampleProfWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/SampleProfWriter.cpp?rev=369798&r1=369797&r2=369798&view=diff
==============================================================================
--- llvm/trunk/lib/ProfileData/SampleProfWriter.cpp (original)
+++ llvm/trunk/lib/ProfileData/SampleProfWriter.cpp Fri Aug 23 12:05:30 2019
@@ -39,11 +39,8 @@
 using namespace llvm;
 using namespace sampleprof;
 
-std::error_code
-SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) {
-  if (std::error_code EC = writeHeader(ProfileMap))
-    return EC;
-
+std::error_code SampleProfileWriter::writeFuncProfiles(
+    const StringMap<FunctionSamples> &ProfileMap) {
   // Sort the ProfileMap by total samples.
   typedef std::pair<StringRef, const FunctionSamples *> NameFunctionSamples;
   std::vector<NameFunctionSamples> V;
@@ -58,12 +55,77 @@ SampleProfileWriter::write(const StringM
       });
 
   for (const auto &I : V) {
-    if (std::error_code EC = write(*I.second))
+    if (std::error_code EC = writeSample(*I.second))
       return EC;
   }
   return sampleprof_error::success;
 }
 
+std::error_code
+SampleProfileWriter::write(const StringMap<FunctionSamples> &ProfileMap) {
+  if (std::error_code EC = writeHeader(ProfileMap))
+    return EC;
+
+  if (std::error_code EC = writeFuncProfiles(ProfileMap))
+    return EC;
+
+  return sampleprof_error::success;
+}
+
+/// Return the current position and prepare to use it as the start
+/// position of a section.
+uint64_t SampleProfileWriterExtBinaryBase::markSectionStart() {
+  return OutputStream->tell();
+}
+
+/// Add a new section into section header table. Return the position
+/// of SectionEnd.
+uint64_t
+SampleProfileWriterExtBinaryBase::addNewSection(SecType Sec,
+                                                uint64_t SectionStart) {
+  uint64_t SectionEnd = OutputStream->tell();
+  SecHdrTable.push_back(
+      {Sec, 0, SectionStart - FileStart, SectionEnd - SectionStart});
+  return SectionEnd;
+}
+
+std::error_code SampleProfileWriterExtBinaryBase::write(
+    const StringMap<FunctionSamples> &ProfileMap) {
+  if (std::error_code EC = writeHeader(ProfileMap))
+    return EC;
+
+  if (std::error_code EC = writeSections(ProfileMap))
+    return EC;
+
+  if (std::error_code EC = writeSecHdrTable())
+    return EC;
+
+  return sampleprof_error::success;
+}
+
+std::error_code SampleProfileWriterExtBinary::writeSections(
+    const StringMap<FunctionSamples> &ProfileMap) {
+  uint64_t SectionStart = markSectionStart();
+  computeSummary(ProfileMap);
+  if (auto EC = writeSummary())
+    return EC;
+  SectionStart = addNewSection(SecProfSummary, SectionStart);
+
+  // Generate the name table for all the functions referenced in the profile.
+  for (const auto &I : ProfileMap) {
+    addName(I.first());
+    addNames(I.second);
+  }
+  writeNameTable();
+  SectionStart = addNewSection(SecNameTable, SectionStart);
+
+  if (std::error_code EC = writeFuncProfiles(ProfileMap))
+    return EC;
+  addNewSection(SecLBRProfile, SectionStart);
+
+  return sampleprof_error::success;
+}
+
 std::error_code SampleProfileWriterCompactBinary::write(
     const StringMap<FunctionSamples> &ProfileMap) {
   if (std::error_code EC = SampleProfileWriter::write(ProfileMap))
@@ -81,7 +143,7 @@ std::error_code SampleProfileWriterCompa
 ///
 /// The format used here is more structured and deliberate because
 /// it needs to be parsed by the SampleProfileReaderText class.
-std::error_code SampleProfileWriterText::write(const FunctionSamples &S) {
+std::error_code SampleProfileWriterText::writeSample(const FunctionSamples &S) {
   auto &OS = *OutputStream;
   OS << S.getName() << ":" << S.getTotalSamples();
   if (Indent == 0)
@@ -117,7 +179,7 @@ std::error_code SampleProfileWriterText:
         OS << Loc.LineOffset << ": ";
       else
         OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
-      if (std::error_code EC = write(CalleeSamples))
+      if (std::error_code EC = writeSample(CalleeSamples))
         return EC;
     }
   Indent -= 1;
@@ -163,7 +225,7 @@ void SampleProfileWriterBinary::stablize
     NameTable[N] = i++;
 }
 
-std::error_code SampleProfileWriterRawBinary::writeNameTable() {
+std::error_code SampleProfileWriterBinary::writeNameTable() {
   auto &OS = *OutputStream;
   std::set<StringRef> V;
   stablizeNameTable(V);
@@ -214,25 +276,18 @@ std::error_code SampleProfileWriterCompa
   return sampleprof_error::success;
 }
 
-std::error_code SampleProfileWriterRawBinary::writeMagicIdent() {
-  auto &OS = *OutputStream;
-  // Write file magic identifier.
-  encodeULEB128(SPMagic(), OS);
-  encodeULEB128(SPVersion(), OS);
-  return sampleprof_error::success;
-}
-
-std::error_code SampleProfileWriterCompactBinary::writeMagicIdent() {
+std::error_code
+SampleProfileWriterBinary::writeMagicIdent(SampleProfileFormat Format) {
   auto &OS = *OutputStream;
   // Write file magic identifier.
-  encodeULEB128(SPMagic(SPF_Compact_Binary), OS);
+  encodeULEB128(SPMagic(Format), OS);
   encodeULEB128(SPVersion(), OS);
   return sampleprof_error::success;
 }
 
 std::error_code SampleProfileWriterBinary::writeHeader(
     const StringMap<FunctionSamples> &ProfileMap) {
-  writeMagicIdent();
+  writeMagicIdent(Format);
 
   computeSummary(ProfileMap);
   if (auto EC = writeSummary())
@@ -248,6 +303,65 @@ std::error_code SampleProfileWriterBinar
   return sampleprof_error::success;
 }
 
+void SampleProfileWriterExtBinaryBase::allocSecHdrTable() {
+  support::endian::Writer Writer(*OutputStream, support::little);
+
+  Writer.write(static_cast<uint64_t>(SectionLayout.size()));
+  SecHdrTableOffset = OutputStream->tell();
+  for (uint32_t i = 0; i < SectionLayout.size(); i++) {
+    Writer.write(static_cast<uint64_t>(-1));
+    Writer.write(static_cast<uint64_t>(-1));
+    Writer.write(static_cast<uint64_t>(-1));
+    Writer.write(static_cast<uint64_t>(-1));
+  }
+}
+
+std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() {
+  auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream);
+  uint64_t Saved = OutputStream->tell();
+
+  // Set OutputStream to the location saved in SecHdrTableOffset.
+  if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1)
+    return sampleprof_error::ostream_seek_unsupported;
+  support::endian::Writer Writer(*OutputStream, support::little);
+
+  DenseMap<uint32_t, uint32_t> IndexMap;
+  for (uint32_t i = 0; i < SecHdrTable.size(); i++) {
+    IndexMap.insert({static_cast<uint32_t>(SecHdrTable[i].Type), i});
+  }
+
+  // Write the sections in the order specified in SectionLayout.
+  // That is the sections order Reader will see. Note that the
+  // sections order in which Reader expects to read may be different
+  // from the order in which Writer is able to write, so we need
+  // to adjust the order in SecHdrTable to be consistent with
+  // SectionLayout when we write SecHdrTable to the memory.
+  for (uint32_t i = 0; i < SectionLayout.size(); i++) {
+    uint32_t idx = IndexMap[static_cast<uint32_t>(SectionLayout[i])];
+    Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Type));
+    Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Flag));
+    Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Offset));
+    Writer.write(static_cast<uint64_t>(SecHdrTable[idx].Size));
+  }
+
+  // Reset OutputStream.
+  if (OFS.seek(Saved) == (uint64_t)-1)
+    return sampleprof_error::ostream_seek_unsupported;
+
+  return sampleprof_error::success;
+}
+
+std::error_code SampleProfileWriterExtBinaryBase::writeHeader(
+    const StringMap<FunctionSamples> &ProfileMap) {
+  auto &OS = *OutputStream;
+  FileStart = OS.tell();
+  writeMagicIdent(Format);
+
+  initSectionLayout();
+  allocSecHdrTable();
+  return sampleprof_error::success;
+}
+
 std::error_code SampleProfileWriterCompactBinary::writeHeader(
     const StringMap<FunctionSamples> &ProfileMap) {
   support::endian::Writer Writer(*OutputStream, support::little);
@@ -324,13 +438,14 @@ std::error_code SampleProfileWriterBinar
 /// Write samples of a top-level function to a binary file.
 ///
 /// \returns true if the samples were written successfully, false otherwise.
-std::error_code SampleProfileWriterBinary::write(const FunctionSamples &S) {
+std::error_code
+SampleProfileWriterBinary::writeSample(const FunctionSamples &S) {
   encodeULEB128(S.getHeadSamples(), *OutputStream);
   return writeBody(S);
 }
 
 std::error_code
-SampleProfileWriterCompactBinary::write(const FunctionSamples &S) {
+SampleProfileWriterCompactBinary::writeSample(const FunctionSamples &S) {
   uint64_t Offset = OutputStream->tell();
   StringRef Name = S.getName();
   FuncOffsetTable[Name] = Offset;
@@ -349,7 +464,8 @@ ErrorOr<std::unique_ptr<SampleProfileWri
 SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
   std::error_code EC;
   std::unique_ptr<raw_ostream> OS;
-  if (Format == SPF_Binary || Format == SPF_Compact_Binary)
+  if (Format == SPF_Binary || Format == SPF_Ext_Binary ||
+      Format == SPF_Compact_Binary)
     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_None));
   else
     OS.reset(new raw_fd_ostream(Filename, EC, sys::fs::OF_Text));
@@ -374,6 +490,8 @@ SampleProfileWriter::create(std::unique_
 
   if (Format == SPF_Binary)
     Writer.reset(new SampleProfileWriterRawBinary(OS));
+  else if (Format == SPF_Ext_Binary)
+    Writer.reset(new SampleProfileWriterExtBinary(OS));
   else if (Format == SPF_Compact_Binary)
     Writer.reset(new SampleProfileWriterCompactBinary(OS));
   else if (Format == SPF_Text)
@@ -386,6 +504,7 @@ SampleProfileWriter::create(std::unique_
   if (EC)
     return EC;
 
+  Writer->Format = Format;
   return std::move(Writer);
 }
 

Added: llvm/trunk/test/Transforms/SampleProfile/Inputs/inline.extbinary.afdo
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SampleProfile/Inputs/inline.extbinary.afdo?rev=369798&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/Transforms/SampleProfile/Inputs/inline.extbinary.afdo
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Removed: llvm/trunk/test/Transforms/SampleProfile/compact-binary-profile.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SampleProfile/compact-binary-profile.ll?rev=369797&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/SampleProfile/compact-binary-profile.ll (original)
+++ llvm/trunk/test/Transforms/SampleProfile/compact-binary-profile.ll (removed)
@@ -1,121 +0,0 @@
-; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.prof -S | FileCheck %s
-; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/inline.prof -S | FileCheck %s
-; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.compactbinary.afdo -S | FileCheck %s
-; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/inline.compactbinary.afdo -S | FileCheck %s
-
-; Original C++ test case
-;
-; #include <stdio.h>
-;
-; int sum(int x, int y) {
-;   return x + y;
-; }
-;
-; int main() {
-;   int s, i = 0;
-;   while (i++ < 20000 * 20000)
-;     if (i != 100) s = sum(i, s); else s = 30;
-;   printf("sum is %d\n", s);
-;   return 0;
-; }
-;
- at .str = private unnamed_addr constant [11 x i8] c"sum is %d\0A\00", align 1
-
-; Check sample-profile phase using compactbinary format profile will annotate
-; the IR with exactly the same result as using text format.
-; CHECK: br i1 %cmp, label %while.body, label %while.end{{.*}} !prof ![[IDX1:[0-9]*]]
-; CHECK: br i1 %cmp1, label %if.then, label %if.else{{.*}} !prof ![[IDX2:[0-9]*]]
-; CHECK: call i32 (i8*, ...) @printf{{.*}} !prof ![[IDX3:[0-9]*]]
-; CHECK: = !{!"TotalCount", i64 26781}
-; CHECK: = !{!"MaxCount", i64 5553}
-; CHECK: ![[IDX1]] = !{!"branch_weights", i32 5392, i32 163}
-; CHECK: ![[IDX2]] = !{!"branch_weights", i32 5280, i32 113}
-; CHECK: ![[IDX3]] = !{!"branch_weights", i32 1}
-
-; Function Attrs: nounwind uwtable
-define i32 @_Z3sumii(i32 %x, i32 %y) !dbg !4 {
-entry:
-  %x.addr = alloca i32, align 4
-  %y.addr = alloca i32, align 4
-  store i32 %x, i32* %x.addr, align 4
-  store i32 %y, i32* %y.addr, align 4
-  %0 = load i32, i32* %x.addr, align 4, !dbg !11
-  %1 = load i32, i32* %y.addr, align 4, !dbg !11
-  %add = add nsw i32 %0, %1, !dbg !11
-  ret i32 %add, !dbg !11
-}
-
-; Function Attrs: uwtable
-define i32 @main() !dbg !7 {
-entry:
-  %retval = alloca i32, align 4
-  %s = alloca i32, align 4
-  %i = alloca i32, align 4
-  store i32 0, i32* %retval
-  store i32 0, i32* %i, align 4, !dbg !12
-  br label %while.cond, !dbg !13
-
-while.cond:                                       ; preds = %if.end, %entry
-  %0 = load i32, i32* %i, align 4, !dbg !14
-  %inc = add nsw i32 %0, 1, !dbg !14
-  store i32 %inc, i32* %i, align 4, !dbg !14
-  %cmp = icmp slt i32 %0, 400000000, !dbg !14
-  br i1 %cmp, label %while.body, label %while.end, !dbg !14
-
-while.body:                                       ; preds = %while.cond
-  %1 = load i32, i32* %i, align 4, !dbg !16
-  %cmp1 = icmp ne i32 %1, 100, !dbg !16
-  br i1 %cmp1, label %if.then, label %if.else, !dbg !16
-
-
-if.then:                                          ; preds = %while.body
-  %2 = load i32, i32* %i, align 4, !dbg !18
-  %3 = load i32, i32* %s, align 4, !dbg !18
-  %call = call i32 @_Z3sumii(i32 %2, i32 %3), !dbg !18
-  store i32 %call, i32* %s, align 4, !dbg !18
-  br label %if.end, !dbg !18
-
-if.else:                                          ; preds = %while.body
-  store i32 30, i32* %s, align 4, !dbg !20
-  br label %if.end
-
-if.end:                                           ; preds = %if.else, %if.then
-  br label %while.cond, !dbg !22
-
-while.end:                                        ; preds = %while.cond
-  %4 = load i32, i32* %s, align 4, !dbg !24
-  %call2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0), i32 %4), !dbg !24
-  ret i32 0, !dbg !25
-}
-
-declare i32 @printf(i8*, ...) #2
-
-!llvm.dbg.cu = !{!0}
-!llvm.module.flags = !{!8, !9}
-!llvm.ident = !{!10}
-
-!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.5 ", isOptimized: false, emissionKind: NoDebug, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
-!1 = !DIFile(filename: "calls.cc", directory: ".")
-!2 = !{}
-!4 = distinct !DISubprogram(name: "sum", line: 3, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 3, file: !1, scope: !5, type: !6, retainedNodes: !2)
-!5 = !DIFile(filename: "calls.cc", directory: ".")
-!6 = !DISubroutineType(types: !2)
-!7 = distinct !DISubprogram(name: "main", line: 7, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 7, file: !1, scope: !5, type: !6, retainedNodes: !2)
-!8 = !{i32 2, !"Dwarf Version", i32 4}
-!9 = !{i32 1, !"Debug Info Version", i32 3}
-!10 = !{!"clang version 3.5 "}
-!11 = !DILocation(line: 4, scope: !4)
-!12 = !DILocation(line: 8, scope: !7)
-!13 = !DILocation(line: 9, scope: !7)
-!14 = !DILocation(line: 9, scope: !15)
-!15 = !DILexicalBlockFile(discriminator: 2, file: !1, scope: !7)
-!16 = !DILocation(line: 10, scope: !17)
-!17 = distinct !DILexicalBlock(line: 10, column: 0, file: !1, scope: !7)
-!18 = !DILocation(line: 10, scope: !19)
-!19 = !DILexicalBlockFile(discriminator: 2, file: !1, scope: !17)
-!20 = !DILocation(line: 10, scope: !21)
-!21 = !DILexicalBlockFile(discriminator: 4, file: !1, scope: !17)
-!22 = !DILocation(line: 10, scope: !23)
-!23 = !DILexicalBlockFile(discriminator: 6, file: !1, scope: !17)
-!24 = !DILocation(line: 11, scope: !7)
-!25 = !DILocation(line: 12, scope: !7)

Added: llvm/trunk/test/Transforms/SampleProfile/profile-format.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SampleProfile/profile-format.ll?rev=369798&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/SampleProfile/profile-format.ll (added)
+++ llvm/trunk/test/Transforms/SampleProfile/profile-format.ll Fri Aug 23 12:05:30 2019
@@ -0,0 +1,123 @@
+; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.prof -S | FileCheck %s
+; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/inline.prof -S | FileCheck %s
+; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.compactbinary.afdo -S | FileCheck %s
+; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/inline.compactbinary.afdo -S | FileCheck %s
+; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.extbinary.afdo -S | FileCheck %s
+; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/inline.extbinary.afdo -S | FileCheck %s
+
+; Original C++ test case
+;
+; #include <stdio.h>
+;
+; int sum(int x, int y) {
+;   return x + y;
+; }
+;
+; int main() {
+;   int s, i = 0;
+;   while (i++ < 20000 * 20000)
+;     if (i != 100) s = sum(i, s); else s = 30;
+;   printf("sum is %d\n", s);
+;   return 0;
+; }
+;
+ at .str = private unnamed_addr constant [11 x i8] c"sum is %d\0A\00", align 1
+
+; Check sample-profile phase using compactbinary or extbinary format profile
+; will annotate the IR with exactly the same result as using text format.
+; CHECK: br i1 %cmp, label %while.body, label %while.end{{.*}} !prof ![[IDX1:[0-9]*]]
+; CHECK: br i1 %cmp1, label %if.then, label %if.else{{.*}} !prof ![[IDX2:[0-9]*]]
+; CHECK: call i32 (i8*, ...) @printf{{.*}} !prof ![[IDX3:[0-9]*]]
+; CHECK: = !{!"TotalCount", i64 26781}
+; CHECK: = !{!"MaxCount", i64 5553}
+; CHECK: ![[IDX1]] = !{!"branch_weights", i32 5392, i32 163}
+; CHECK: ![[IDX2]] = !{!"branch_weights", i32 5280, i32 113}
+; CHECK: ![[IDX3]] = !{!"branch_weights", i32 1}
+
+; Function Attrs: nounwind uwtable
+define i32 @_Z3sumii(i32 %x, i32 %y) !dbg !4 {
+entry:
+  %x.addr = alloca i32, align 4
+  %y.addr = alloca i32, align 4
+  store i32 %x, i32* %x.addr, align 4
+  store i32 %y, i32* %y.addr, align 4
+  %0 = load i32, i32* %x.addr, align 4, !dbg !11
+  %1 = load i32, i32* %y.addr, align 4, !dbg !11
+  %add = add nsw i32 %0, %1, !dbg !11
+  ret i32 %add, !dbg !11
+}
+
+; Function Attrs: uwtable
+define i32 @main() !dbg !7 {
+entry:
+  %retval = alloca i32, align 4
+  %s = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32 0, i32* %retval
+  store i32 0, i32* %i, align 4, !dbg !12
+  br label %while.cond, !dbg !13
+
+while.cond:                                       ; preds = %if.end, %entry
+  %0 = load i32, i32* %i, align 4, !dbg !14
+  %inc = add nsw i32 %0, 1, !dbg !14
+  store i32 %inc, i32* %i, align 4, !dbg !14
+  %cmp = icmp slt i32 %0, 400000000, !dbg !14
+  br i1 %cmp, label %while.body, label %while.end, !dbg !14
+
+while.body:                                       ; preds = %while.cond
+  %1 = load i32, i32* %i, align 4, !dbg !16
+  %cmp1 = icmp ne i32 %1, 100, !dbg !16
+  br i1 %cmp1, label %if.then, label %if.else, !dbg !16
+
+
+if.then:                                          ; preds = %while.body
+  %2 = load i32, i32* %i, align 4, !dbg !18
+  %3 = load i32, i32* %s, align 4, !dbg !18
+  %call = call i32 @_Z3sumii(i32 %2, i32 %3), !dbg !18
+  store i32 %call, i32* %s, align 4, !dbg !18
+  br label %if.end, !dbg !18
+
+if.else:                                          ; preds = %while.body
+  store i32 30, i32* %s, align 4, !dbg !20
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  br label %while.cond, !dbg !22
+
+while.end:                                        ; preds = %while.cond
+  %4 = load i32, i32* %s, align 4, !dbg !24
+  %call2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0), i32 %4), !dbg !24
+  ret i32 0, !dbg !25
+}
+
+declare i32 @printf(i8*, ...) #2
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!8, !9}
+!llvm.ident = !{!10}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.5 ", isOptimized: false, emissionKind: NoDebug, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2)
+!1 = !DIFile(filename: "calls.cc", directory: ".")
+!2 = !{}
+!4 = distinct !DISubprogram(name: "sum", line: 3, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 3, file: !1, scope: !5, type: !6, retainedNodes: !2)
+!5 = !DIFile(filename: "calls.cc", directory: ".")
+!6 = !DISubroutineType(types: !2)
+!7 = distinct !DISubprogram(name: "main", line: 7, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 7, file: !1, scope: !5, type: !6, retainedNodes: !2)
+!8 = !{i32 2, !"Dwarf Version", i32 4}
+!9 = !{i32 1, !"Debug Info Version", i32 3}
+!10 = !{!"clang version 3.5 "}
+!11 = !DILocation(line: 4, scope: !4)
+!12 = !DILocation(line: 8, scope: !7)
+!13 = !DILocation(line: 9, scope: !7)
+!14 = !DILocation(line: 9, scope: !15)
+!15 = !DILexicalBlockFile(discriminator: 2, file: !1, scope: !7)
+!16 = !DILocation(line: 10, scope: !17)
+!17 = distinct !DILexicalBlock(line: 10, column: 0, file: !1, scope: !7)
+!18 = !DILocation(line: 10, scope: !19)
+!19 = !DILexicalBlockFile(discriminator: 2, file: !1, scope: !17)
+!20 = !DILocation(line: 10, scope: !21)
+!21 = !DILexicalBlockFile(discriminator: 4, file: !1, scope: !17)
+!22 = !DILocation(line: 10, scope: !23)
+!23 = !DILexicalBlockFile(discriminator: 6, file: !1, scope: !17)
+!24 = !DILocation(line: 11, scope: !7)
+!25 = !DILocation(line: 12, scope: !7)

Modified: llvm/trunk/test/tools/llvm-profdata/roundtrip.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-profdata/roundtrip.test?rev=369798&r1=369797&r2=369798&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-profdata/roundtrip.test (original)
+++ llvm/trunk/test/tools/llvm-profdata/roundtrip.test Fri Aug 23 12:05:30 2019
@@ -6,4 +6,13 @@ RUN: llvm-profdata show -o %t.1.proftext
 RUN: diff %t.1.proftext %S/Inputs/IR_profile.proftext
 RUN: llvm-profdata merge --sample --binary -output=%t.2.profdata %S/Inputs/sample-profile.proftext
 RUN: llvm-profdata merge --sample --text -output=%t.2.proftext %t.2.profdata
-RUN: diff %t.2.proftext %S/Inputs/sample-profile.proftext
\ No newline at end of file
+RUN: diff %t.2.proftext %S/Inputs/sample-profile.proftext
+# Round trip from text --> extbinary --> text
+RUN: llvm-profdata merge --sample --extbinary -output=%t.3.profdata %S/Inputs/sample-profile.proftext
+RUN: llvm-profdata merge --sample --text -output=%t.3.proftext %t.3.profdata
+RUN: diff %t.3.proftext %S/Inputs/sample-profile.proftext
+# Round trip from text --> binary --> extbinary --> text
+RUN: llvm-profdata merge --sample --binary -output=%t.4.profdata %S/Inputs/sample-profile.proftext
+RUN: llvm-profdata merge --sample --extbinary -output=%t.5.profdata %t.4.profdata
+RUN: llvm-profdata merge --sample --text -output=%t.4.proftext %t.5.profdata
+RUN: diff %t.4.proftext %S/Inputs/sample-profile.proftext

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=369798&r1=369797&r2=369798&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-profdata/llvm-profdata.cpp (original)
+++ llvm/trunk/tools/llvm-profdata/llvm-profdata.cpp Fri Aug 23 12:05:30 2019
@@ -37,6 +37,7 @@ enum ProfileFormat {
   PF_None = 0,
   PF_Text,
   PF_Compact_Binary,
+  PF_Ext_Binary,
   PF_GCC,
   PF_Binary
 };
@@ -314,7 +315,7 @@ static void mergeInstrProfile(const Weig
     exitWithError("Cannot write indexed profdata format to stdout.");
 
   if (OutputFormat != PF_Binary && OutputFormat != PF_Compact_Binary &&
-      OutputFormat != PF_Text)
+      OutputFormat != PF_Ext_Binary && OutputFormat != PF_Text)
     exitWithError("Unknown format is specified.");
 
   std::mutex ErrorLock;
@@ -425,8 +426,12 @@ remapSamples(const sampleprof::FunctionS
 }
 
 static sampleprof::SampleProfileFormat FormatMap[] = {
-    sampleprof::SPF_None, sampleprof::SPF_Text, sampleprof::SPF_Compact_Binary,
-    sampleprof::SPF_GCC, sampleprof::SPF_Binary};
+    sampleprof::SPF_None,
+    sampleprof::SPF_Text,
+    sampleprof::SPF_Compact_Binary,
+    sampleprof::SPF_Ext_Binary,
+    sampleprof::SPF_GCC,
+    sampleprof::SPF_Binary};
 
 static void mergeSampleProfile(const WeightedFileVector &Inputs,
                                SymbolRemapper *Remapper,
@@ -583,12 +588,14 @@ static int merge_main(int argc, const ch
                  clEnumVal(sample, "Sample profile")));
   cl::opt<ProfileFormat> OutputFormat(
       cl::desc("Format of output profile"), cl::init(PF_Binary),
-      cl::values(clEnumValN(PF_Binary, "binary", "Binary encoding (default)"),
-                 clEnumValN(PF_Compact_Binary, "compbinary",
-                            "Compact binary encoding"),
-                 clEnumValN(PF_Text, "text", "Text encoding"),
-                 clEnumValN(PF_GCC, "gcc",
-                            "GCC encoding (only meaningful for -sample)")));
+      cl::values(
+          clEnumValN(PF_Binary, "binary", "Binary encoding (default)"),
+          clEnumValN(PF_Compact_Binary, "compbinary",
+                     "Compact binary encoding"),
+          clEnumValN(PF_Ext_Binary, "extbinary", "Extensible binary encoding"),
+          clEnumValN(PF_Text, "text", "Text encoding"),
+          clEnumValN(PF_GCC, "gcc",
+                     "GCC encoding (only meaningful for -sample)")));
   cl::opt<bool> OutputSparse("sparse", cl::init(false),
       cl::desc("Generate a sparse profile (only meaningful for -instr)"));
   cl::opt<unsigned> NumThreads(

Modified: llvm/trunk/unittests/ProfileData/SampleProfTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ProfileData/SampleProfTest.cpp?rev=369798&r1=369797&r2=369798&view=diff
==============================================================================
--- llvm/trunk/unittests/ProfileData/SampleProfTest.cpp (original)
+++ llvm/trunk/unittests/ProfileData/SampleProfTest.cpp Fri Aug 23 12:05:30 2019
@@ -285,6 +285,10 @@ TEST_F(SampleProfTest, roundtrip_compact
   testRoundTrip(SampleProfileFormat::SPF_Compact_Binary, false);
 }
 
+TEST_F(SampleProfTest, roundtrip_ext_binary_profile) {
+  testRoundTrip(SampleProfileFormat::SPF_Ext_Binary, false);
+}
+
 TEST_F(SampleProfTest, remap_text_profile) {
   testRoundTrip(SampleProfileFormat::SPF_Text, true);
 }
@@ -293,6 +297,10 @@ TEST_F(SampleProfTest, remap_raw_binary_
   testRoundTrip(SampleProfileFormat::SPF_Binary, true);
 }
 
+TEST_F(SampleProfTest, remap_ext_binary_profile) {
+  testRoundTrip(SampleProfileFormat::SPF_Ext_Binary, true);
+}
+
 TEST_F(SampleProfTest, sample_overflow_saturation) {
   const uint64_t Max = std::numeric_limits<uint64_t>::max();
   sampleprof_error Result;




More information about the llvm-commits mailing list