InstrProf: Support for value profiling in the indexed profile format
authorJustin Bogner <mail@justinbogner.com>
Tue, 29 Sep 2015 22:13:58 +0000 (22:13 +0000)
committerJustin Bogner <mail@justinbogner.com>
Tue, 29 Sep 2015 22:13:58 +0000 (22:13 +0000)
Add support to the indexed instrprof reader and writer for the format
that will be used for value profiling.

Patch by Betul Buyukkurt, with minor modifications.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@248833 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/ProfileData/InstrProf.h
include/llvm/ProfileData/InstrProfReader.h
include/llvm/ProfileData/InstrProfWriter.h
lib/ProfileData/InstrProf.cpp
lib/ProfileData/InstrProfIndexed.h
lib/ProfileData/InstrProfReader.cpp
lib/ProfileData/InstrProfWriter.cpp
tools/llvm-profdata/llvm-profdata.cpp
unittests/ProfileData/CoverageMappingTest.cpp
unittests/ProfileData/InstrProfTest.cpp

index 77055ba8726826d678bb70208695f34987a6756e..49780e4abab631a23bc5fc16c9b8184280c7cf77 100644 (file)
 #ifndef LLVM_PROFILEDATA_INSTRPROF_H_
 #define LLVM_PROFILEDATA_INSTRPROF_H_
 
-#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/ErrorHandling.h"
 #include <cstdint>
+#include <list>
 #include <system_error>
 #include <vector>
 
@@ -25,25 +27,84 @@ namespace llvm {
 const std::error_category &instrprof_category();
 
 enum class instrprof_error {
-    success = 0,
-    eof,
-    bad_magic,
-    bad_header,
-    unsupported_version,
-    unsupported_hash_type,
-    too_large,
-    truncated,
-    malformed,
-    unknown_function,
-    hash_mismatch,
-    count_mismatch,
-    counter_overflow
+  success = 0,
+  eof,
+  bad_magic,
+  bad_header,
+  unsupported_version,
+  unsupported_hash_type,
+  too_large,
+  truncated,
+  malformed,
+  unknown_function,
+  hash_mismatch,
+  count_mismatch,
+  counter_overflow,
+  value_site_count_mismatch
 };
 
 inline std::error_code make_error_code(instrprof_error E) {
   return std::error_code(static_cast<int>(E), instrprof_category());
 }
 
+enum InstrProfValueKind : uint32_t {
+  IPVK_IndirectCallTarget = 0,
+
+  IPVK_First = IPVK_IndirectCallTarget,
+  IPVK_Last = IPVK_IndirectCallTarget
+};
+
+struct InstrProfStringTable {
+  // Set of string values in profiling data.
+  StringSet<> StringValueSet;
+  InstrProfStringTable() { StringValueSet.clear(); }
+  // Get a pointer to internal storage of a string in set
+  const char *getStringData(StringRef Str) {
+    auto Result = StringValueSet.find(Str);
+    return (Result == StringValueSet.end()) ? nullptr : Result->first().data();
+  }
+  // Insert a string to StringTable
+  const char *insertString(StringRef Str) {
+    auto Result = StringValueSet.insert(Str);
+    return Result.first->first().data();
+  }
+};
+
+struct InstrProfValueSiteRecord {
+  /// Typedef for a single TargetValue-NumTaken pair.
+  typedef std::pair<uint64_t, uint64_t> ValueDataPair;
+  /// Value profiling data pairs at a given value site.
+  std::list<ValueDataPair> ValueData;
+
+  InstrProfValueSiteRecord() { ValueData.clear(); }
+
+  /// Sort ValueData ascending by TargetValue
+  void sortByTargetValues() {
+    ValueData.sort([](const ValueDataPair &left, const ValueDataPair &right) {
+      return left.first < right.first;
+    });
+  }
+
+  /// Merge data from another InstrProfValueSiteRecord
+  void mergeValueData(InstrProfValueSiteRecord &Input) {
+    this->sortByTargetValues();
+    Input.sortByTargetValues();
+    auto I = ValueData.begin();
+    auto IE = ValueData.end();
+    for (auto J = Input.ValueData.begin(), JE = Input.ValueData.end(); J != JE;
+         ++J) {
+      while (I != IE && I->first < J->first)
+        ++I;
+      if (I != IE && I->first == J->first) {
+        I->second += J->second;
+        ++I;
+        continue;
+      }
+      ValueData.insert(I, *J);
+    }
+  }
+};
+
 /// Profiling information for a single function.
 struct InstrProfRecord {
   InstrProfRecord() {}
@@ -52,6 +113,22 @@ struct InstrProfRecord {
   StringRef Name;
   uint64_t Hash;
   std::vector<uint64_t> Counts;
+  std::vector<InstrProfValueSiteRecord> IndirectCallSites;
+
+  const std::vector<InstrProfValueSiteRecord> &
+  getValueSitesForKind(uint32_t ValueKind) const {
+    switch (ValueKind) {
+    case IPVK_IndirectCallTarget:
+      return IndirectCallSites;
+    }
+    llvm_unreachable("Unknown value kind!");
+  }
+
+  std::vector<InstrProfValueSiteRecord> &
+  getValueSitesForKind(uint32_t ValueKind) {
+    return const_cast<std::vector<InstrProfValueSiteRecord> &>(
+        this->getValueSitesForKind(ValueKind));
+  }
 };
 
 } // end namespace llvm
index f937e7d08d5444ceec42a63c64c72563fa906c6b..c0585d6f6d2c5bb3bb27157b368b4a246d229319 100644 (file)
@@ -65,6 +65,9 @@ public:
   InstrProfIterator end() { return InstrProfIterator(); }
 
 protected:
+  /// String table for holding a unique copy of all the strings in the profile.
+  InstrProfStringTable StringTable;
+
   /// Set the current std::error_code and return same.
   std::error_code error(std::error_code EC) {
     LastError = EC;
@@ -195,6 +198,7 @@ class InstrProfLookupTrait {
   std::vector<InstrProfRecord> DataBuffer;
   IndexedInstrProf::HashT HashType;
   unsigned FormatVersion;
+  std::vector<std::pair<uint64_t, const char *>> HashKeys;
 
 public:
   InstrProfLookupTrait(IndexedInstrProf::HashT HashType, unsigned FormatVersion)
@@ -209,9 +213,13 @@ public:
 
   static bool EqualKey(StringRef A, StringRef B) { return A == B; }
   static StringRef GetInternalKey(StringRef K) { return K; }
+  static StringRef GetExternalKey(StringRef K) { return K; }
 
   hash_value_type ComputeHash(StringRef K);
 
+  void setHashKeys(std::vector<std::pair<uint64_t, const char *>> HashKeys) {
+    this->HashKeys = std::move(HashKeys);
+  }
   static std::pair<offset_type, offset_type>
   ReadKeyDataLength(const unsigned char *&D) {
     using namespace support;
@@ -224,6 +232,8 @@ public:
     return StringRef((const char *)D, N);
   }
 
+  bool ReadValueProfilingData(const unsigned char *&D,
+                              const unsigned char *const End);
   data_type ReadData(StringRef K, const unsigned char *D, offset_type N);
 };
 
index ce0bb524249884753587f41750fd7cf87fe26f4b..da0d956e8a9871896855ebede64b6fe3f1dd8aad 100644 (file)
 #ifndef LLVM_PROFILEDATA_INSTRPROFWRITER_H
 #define LLVM_PROFILEDATA_INSTRPROFWRITER_H
 
-#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringMap.h"
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/Support/DataTypes.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/raw_ostream.h"
-#include <vector>
 
 namespace llvm {
 
 /// Writer for instrumentation based profile data.
 class InstrProfWriter {
 public:
-  typedef SmallDenseMap<uint64_t, std::vector<uint64_t>, 1> CounterData;
+  typedef SmallDenseMap<uint64_t, InstrProfRecord, 1> ProfilingData;
+
 private:
-  StringMap<CounterData> FunctionData;
+  InstrProfStringTable StringTable;
+  StringMap<ProfilingData> FunctionData;
   uint64_t MaxFunctionCount;
 public:
   InstrProfWriter() : MaxFunctionCount(0) {}
 
+  /// Update string entries in profile data with references to StringTable.
+  void updateStringTableReferences(InstrProfRecord &I);
   /// Add function counts for the given function. If there are already counts
   /// for this function and the hash and number of counts match, each counter is
   /// summed.
-  std::error_code addFunctionCounts(StringRef FunctionName,
-                                    uint64_t FunctionHash,
-                                    ArrayRef<uint64_t> Counters);
+  std::error_code addRecord(InstrProfRecord &&I);
   /// Write the profile to \c OS
   void write(raw_fd_ostream &OS);
   /// Write the profile, returning the raw data. For testing.
index 92822a71402fc8d4eca92d71e3c26fc1aea8d14a..9652ba88483363c4d532a1582c82c0341381f898 100644 (file)
@@ -50,6 +50,8 @@ class InstrProfErrorCategoryType : public std::error_category {
       return "Function count mismatch";
     case instrprof_error::counter_overflow:
       return "Counter overflow";
+    case instrprof_error::value_site_count_mismatch:
+      return "Function's value site counts mismatch";
     }
     llvm_unreachable("A value of instrprof_error has no message.");
   }
index ebca7b22fbfbf16e44e7c365a678103cba56b3a9..fe0b04ed008d9ff4e339aff193df3567f8bd856b 100644 (file)
@@ -47,7 +47,7 @@ static inline uint64_t ComputeHash(HashT Type, StringRef K) {
 }
 
 const uint64_t Magic = 0x8169666f72706cff; // "\xfflprofi\x81"
-const uint64_t Version = 2;
+const uint64_t Version = 3;
 const HashT HashType = HashT::MD5;
 }
 
index 8a529a000c537de6f558c01a52672ab92f986b54..062c337d4ee7821ff89f310150a13572b0df74ee 100644 (file)
@@ -302,42 +302,102 @@ InstrProfLookupTrait::ComputeHash(StringRef K) {
 typedef InstrProfLookupTrait::data_type data_type;
 typedef InstrProfLookupTrait::offset_type offset_type;
 
+bool InstrProfLookupTrait::ReadValueProfilingData(
+    const unsigned char *&D, const unsigned char *const End) {
+
+  using namespace support;
+  // Read number of value kinds with value sites.
+  if (D + sizeof(uint64_t) > End)
+    return false;
+  uint64_t ValueKindCount = endian::readNext<uint64_t, little, unaligned>(D);
+
+  for (uint32_t Kind = 0; Kind < ValueKindCount; ++Kind) {
+
+    // Read value kind and number of value sites for kind.
+    if (D + 2 * sizeof(uint64_t) > End)
+      return false;
+    uint64_t ValueKind = endian::readNext<uint64_t, little, unaligned>(D);
+    uint64_t ValueSiteCount = endian::readNext<uint64_t, little, unaligned>(D);
+
+    std::vector<InstrProfValueSiteRecord> &ValueSites =
+        DataBuffer.back().getValueSitesForKind(ValueKind);
+    ValueSites.reserve(ValueSiteCount);
+    for (uint64_t VSite = 0; VSite < ValueSiteCount; ++VSite) {
+      // Read number of value data pairs at value site.
+      if (D + sizeof(uint64_t) > End)
+        return false;
+      uint64_t ValueDataCount =
+          endian::readNext<uint64_t, little, unaligned>(D);
+
+      // Check if there are as many ValueDataPairs as ValueDataCount in memory.
+      if (D + (ValueDataCount << 1) * sizeof(uint64_t) > End)
+        return false;
+
+      InstrProfValueSiteRecord VSiteRecord;
+      for (uint64_t VCount = 0; VCount < ValueDataCount; ++VCount) {
+        uint64_t Value = endian::readNext<uint64_t, little, unaligned>(D);
+        uint64_t NumTaken = endian::readNext<uint64_t, little, unaligned>(D);
+        switch (ValueKind) {
+        case IPVK_IndirectCallTarget: {
+          auto Result =
+              std::lower_bound(HashKeys.begin(), HashKeys.end(), Value,
+                               [](const std::pair<uint64_t, const char *> &LHS,
+                                  uint64_t RHS) { return LHS.first < RHS; });
+          assert(Result != HashKeys.end() &&
+                 "Hash does not match any known keys\n");
+          Value = (uint64_t)Result->second;
+          break;
+        }
+        }
+        VSiteRecord.ValueData.push_back(std::make_pair(Value, NumTaken));
+      }
+      ValueSites.push_back(std::move(VSiteRecord));
+    }
+  }
+  return true;
+}
+
 data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D,
                                          offset_type N) {
-
   // Check if the data is corrupt. If so, don't try to read it.
   if (N % sizeof(uint64_t))
     return data_type();
 
   DataBuffer.clear();
-  uint64_t NumCounts;
-  uint64_t NumEntries = N / sizeof(uint64_t);
   std::vector<uint64_t> CounterBuffer;
-  for (uint64_t I = 0; I < NumEntries; I += NumCounts) {
-    using namespace support;
-    // The function hash comes first.
-    uint64_t Hash = endian::readNext<uint64_t, little, unaligned>(D);
 
-    if (++I >= NumEntries)
+  using namespace support;
+  const unsigned char *End = D + N;
+  while (D < End) {
+    // Read hash
+    if (D + sizeof(uint64_t) >= End)
       return data_type();
+    uint64_t Hash = endian::readNext<uint64_t, little, unaligned>(D);
 
-    // In v1, we have at least one count.
-    // Later, we have the number of counts.
-    NumCounts = (1 == FormatVersion)
-                    ? NumEntries - I
-                    : endian::readNext<uint64_t, little, unaligned>(D);
-    if (1 != FormatVersion)
-      ++I;
-
-    // If we have more counts than data, this is bogus.
-    if (I + NumCounts > NumEntries)
+    // Initialize number of counters for FormatVersion == 1
+    uint64_t CountsSize = N / sizeof(uint64_t) - 1;
+    // If format version is different then read number of counters
+    if (FormatVersion != 1) {
+      if (D + sizeof(uint64_t) > End)
+        return data_type();
+      CountsSize = endian::readNext<uint64_t, little, unaligned>(D);
+    }
+    // Read counter values
+    if (D + CountsSize * sizeof(uint64_t) > End)
       return data_type();
 
     CounterBuffer.clear();
-    for (unsigned J = 0; J < NumCounts; ++J)
+    CounterBuffer.reserve(CountsSize);
+    for (uint64_t J = 0; J < CountsSize; ++J)
       CounterBuffer.push_back(endian::readNext<uint64_t, little, unaligned>(D));
 
     DataBuffer.push_back(InstrProfRecord(K, Hash, std::move(CounterBuffer)));
+
+    // Read value profiling data
+    if (FormatVersion > 2 && !ReadValueProfilingData(D, End)) {
+      DataBuffer.clear();
+      return data_type();
+    }
   }
   return DataBuffer;
 }
@@ -384,6 +444,18 @@ std::error_code IndexedInstrProfReader::readHeader() {
   Index.reset(InstrProfReaderIndex::Create(
       Start + HashOffset, Cur, Start,
       InstrProfLookupTrait(HashType, FormatVersion)));
+
+  // Form the map of hash values to const char* keys in profiling data.
+  std::vector<std::pair<uint64_t, const char *>> HashKeys;
+  for (auto Key : Index->keys()) {
+    const char *KeyTableRef = StringTable.insertString(Key);
+    HashKeys.push_back(std::make_pair(ComputeHash(HashType, Key), KeyTableRef));
+  }
+  std::sort(HashKeys.begin(), HashKeys.end(), less_first());
+  std::unique(HashKeys.begin(), HashKeys.end(), less_first());
+  HashKeys.erase(std::unique(HashKeys.begin(), HashKeys.end()), HashKeys.end());
+  // Set the hash key map for the InstrLookupTrait
+  Index->getInfoObj().setHashKeys(std::move(HashKeys));
   // Set up our iterator for readNextRecord.
   RecordIterator = Index->data_begin();
 
index 2188543ed61c3002f93825dddca18940026b8534..856194d77760b8e667d447ecdb65187fa1051d80 100644 (file)
@@ -26,8 +26,8 @@ public:
   typedef StringRef key_type;
   typedef StringRef key_type_ref;
 
-  typedef const InstrProfWriter::CounterData *const data_type;
-  typedef const InstrProfWriter::CounterData *const data_type_ref;
+  typedef const InstrProfWriter::ProfilingData *const data_type;
+  typedef const InstrProfWriter::ProfilingData *const data_type_ref;
 
   typedef uint64_t hash_value_type;
   typedef uint64_t offset_type;
@@ -45,8 +45,26 @@ public:
     LE.write<offset_type>(N);
 
     offset_type M = 0;
-    for (const auto &Counts : *V)
-      M += (2 + Counts.second.size()) * sizeof(uint64_t);
+    for (const auto &ProfileData : *V) {
+      M += sizeof(uint64_t); // The function hash
+      M += sizeof(uint64_t); // The size of the Counts vector
+      M += ProfileData.second.Counts.size() * sizeof(uint64_t);
+
+      // Value data
+      M += sizeof(uint64_t); // Number of value kinds with value sites.
+      for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
+        const std::vector<InstrProfValueSiteRecord> &ValueSites =
+            ProfileData.second.getValueSitesForKind(Kind);
+        if (ValueSites.empty())
+          continue;
+        M += sizeof(uint64_t); // Value kind
+        M += sizeof(uint64_t); // The number of value sites for given value kind
+        for (InstrProfValueSiteRecord I : ValueSites) {
+          M += sizeof(uint64_t); // Number of value data pairs at a value site
+          M += 2 * sizeof(uint64_t) * I.ValueData.size(); // Value data pairs
+        }
+      }
+    }
     LE.write<offset_type>(M);
 
     return std::make_pair(N, M);
@@ -60,52 +78,114 @@ public:
                        offset_type) {
     using namespace llvm::support;
     endian::Writer<little> LE(Out);
-
-    for (const auto &Counts : *V) {
-      LE.write<uint64_t>(Counts.first);
-      LE.write<uint64_t>(Counts.second.size());
-      for (uint64_t I : Counts.second)
+    for (const auto &ProfileData : *V) {
+      LE.write<uint64_t>(ProfileData.first); // Function hash
+      LE.write<uint64_t>(ProfileData.second.Counts.size());
+      for (uint64_t I : ProfileData.second.Counts)
         LE.write<uint64_t>(I);
+
+      // Compute the number of value kinds with value sites.
+      uint64_t NumValueKinds = 0;
+      for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
+        NumValueKinds +=
+            !(ProfileData.second.getValueSitesForKind(Kind).empty());
+      LE.write<uint64_t>(NumValueKinds);
+
+      // Write value data
+      for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
+        const std::vector<InstrProfValueSiteRecord> &ValueSites =
+            ProfileData.second.getValueSitesForKind(Kind);
+        if (ValueSites.empty())
+          continue;
+        LE.write<uint64_t>(Kind); // Write value kind
+        // Write number of value sites for current value kind
+        LE.write<uint64_t>(ValueSites.size());
+        for (InstrProfValueSiteRecord I : ValueSites) {
+          // Write number of value data pairs at this value site
+          LE.write<uint64_t>(I.ValueData.size());
+          for (auto V : I.ValueData) {
+            if (Kind == IPVK_IndirectCallTarget)
+              LE.write<uint64_t>(ComputeHash((const char *)V.first));
+            else
+              LE.write<uint64_t>(V.first);
+            LE.write<uint64_t>(V.second);
+          }
+        }
+      }
     }
   }
 };
 }
 
-std::error_code
-InstrProfWriter::addFunctionCounts(StringRef FunctionName,
-                                   uint64_t FunctionHash,
-                                   ArrayRef<uint64_t> Counters) {
-  auto &CounterData = FunctionData[FunctionName];
+static std::error_code combineInstrProfRecords(InstrProfRecord &Dest,
+                                               InstrProfRecord &Source,
+                                               uint64_t &MaxFunctionCount) {
+  // If the number of counters doesn't match we either have bad data
+  // or a hash collision.
+  if (Dest.Counts.size() != Source.Counts.size())
+    return instrprof_error::count_mismatch;
 
-  auto Where = CounterData.find(FunctionHash);
-  if (Where == CounterData.end()) {
-    // We've never seen a function with this name and hash, add it.
-    CounterData[FunctionHash] = Counters;
-    // We keep track of the max function count as we go for simplicity.
-    if (Counters[0] > MaxFunctionCount)
-      MaxFunctionCount = Counters[0];
-    return instrprof_error::success;
+  for (size_t I = 0, E = Source.Counts.size(); I < E; ++I) {
+    if (Dest.Counts[I] + Source.Counts[I] < Dest.Counts[I])
+      return instrprof_error::counter_overflow;
+    Dest.Counts[I] += Source.Counts[I];
   }
 
-  // We're updating a function we've seen before.
-  auto &FoundCounters = Where->second;
-  // If the number of counters doesn't match we either have bad data or a hash
-  // collision.
-  if (FoundCounters.size() != Counters.size())
-    return instrprof_error::count_mismatch;
+  for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
 
-  for (size_t I = 0, E = Counters.size(); I < E; ++I) {
-    if (FoundCounters[I] + Counters[I] < FoundCounters[I])
-      return instrprof_error::counter_overflow;
-    FoundCounters[I] += Counters[I];
+    std::vector<InstrProfValueSiteRecord> &SourceValueSites =
+        Source.getValueSitesForKind(Kind);
+    if (SourceValueSites.empty())
+      continue;
+
+    std::vector<InstrProfValueSiteRecord> &DestValueSites =
+        Dest.getValueSitesForKind(Kind);
+
+    if (DestValueSites.empty()) {
+      DestValueSites.swap(SourceValueSites);
+      continue;
+    }
+
+    if (DestValueSites.size() != SourceValueSites.size())
+      return instrprof_error::value_site_count_mismatch;
+    for (size_t I = 0, E = SourceValueSites.size(); I < E; ++I)
+      DestValueSites[I].mergeValueData(SourceValueSites[I]);
   }
+
   // We keep track of the max function count as we go for simplicity.
-  if (FoundCounters[0] > MaxFunctionCount)
-    MaxFunctionCount = FoundCounters[0];
+  if (Dest.Counts[0] > MaxFunctionCount)
+    MaxFunctionCount = Dest.Counts[0];
 
   return instrprof_error::success;
 }
 
+void InstrProfWriter::updateStringTableReferences(InstrProfRecord &I) {
+  I.Name = StringTable.insertString(I.Name);
+  for (auto &VSite : I.IndirectCallSites)
+    for (auto &VData : VSite.ValueData)
+      VData.first =
+          (uint64_t)StringTable.insertString((const char *)VData.first);
+}
+
+std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I) {
+  updateStringTableReferences(I);
+  auto &ProfileDataMap = FunctionData[I.Name];
+
+  auto Where = ProfileDataMap.find(I.Hash);
+  if (Where == ProfileDataMap.end()) {
+    // We've never seen a function with this name and hash, add it.
+    ProfileDataMap[I.Hash] = I;
+
+    // We keep track of the max function count as we go for simplicity.
+    if (I.Counts[0] > MaxFunctionCount)
+      MaxFunctionCount = I.Counts[0];
+    return instrprof_error::success;
+  }
+
+  // We're updating a function we've seen before.
+  return combineInstrProfRecords(Where->second, I, MaxFunctionCount);
+}
+
 std::pair<uint64_t, uint64_t> InstrProfWriter::writeImpl(raw_ostream &OS) {
   OnDiskChainedHashTableGenerator<InstrProfRecordTrait> Generator;
 
index 23fa7b40f5014c07d23b4c97f8a66e2b5dc3cc34..fdf22c3642fd1d076a45cd104ea4e543cf14436e 100644 (file)
@@ -58,9 +58,8 @@ static void mergeInstrProfile(const cl::list<std::string> &Inputs,
       exitWithError(ec.message(), Filename);
 
     auto Reader = std::move(ReaderOrErr.get());
-    for (const auto &I : *Reader)
-      if (std::error_code EC =
-              Writer.addFunctionCounts(I.Name, I.Hash, I.Counts))
+    for (auto &I : *Reader)
+      if (std::error_code EC = Writer.addRecord(std::move(I)))
         errs() << Filename << ": " << I.Name << ": " << EC.message() << "\n";
     if (Reader->hasError())
       exitWithError(Reader->getError().message(), Filename);
@@ -134,8 +133,8 @@ static int merge_main(int argc, const char *argv[]) {
 }
 
 static int showInstrProfile(std::string Filename, bool ShowCounts,
-                            bool ShowAllFunctions, std::string ShowFunction,
-                            raw_fd_ostream &OS) {
+                            bool ShowIndirectCallTargets, bool ShowAllFunctions,
+                            std::string ShowFunction, raw_fd_ostream &OS) {
   auto ReaderOrErr = InstrProfReader::create(Filename);
   if (std::error_code EC = ReaderOrErr.getError())
     exitWithError(EC.message(), Filename);
@@ -162,6 +161,9 @@ static int showInstrProfile(std::string Filename, bool ShowCounts,
          << "    Hash: " << format("0x%016" PRIx64, Func.Hash) << "\n"
          << "    Counters: " << Func.Counts.size() << "\n"
          << "    Function count: " << Func.Counts[0] << "\n";
+      if (ShowIndirectCallTargets)
+        OS << "    Indirect Call Site Count: " << Func.IndirectCallSites.size()
+           << "\n";
     }
 
     if (Show && ShowCounts)
@@ -174,6 +176,16 @@ static int showInstrProfile(std::string Filename, bool ShowCounts,
     }
     if (Show && ShowCounts)
       OS << "]\n";
+
+    if (Show && ShowIndirectCallTargets) {
+      OS << "    Indirect Target Results: \n";
+      for (size_t I = 0, E = Func.IndirectCallSites.size(); I < E; ++I) {
+        for (auto V : Func.IndirectCallSites[I].ValueData) {
+          OS << "\t[ " << I << ", ";
+          OS << (const char *)V.first << ", " << V.second << " ]\n";
+        }
+      }
+    }
   }
   if (Reader->hasError())
     exitWithError(Reader->getError().message(), Filename);
@@ -212,6 +224,9 @@ static int show_main(int argc, const char *argv[]) {
 
   cl::opt<bool> ShowCounts("counts", cl::init(false),
                            cl::desc("Show counter values for shown functions"));
+  cl::opt<bool> ShowIndirectCallTargets(
+      "ic-targets", cl::init(false),
+      cl::desc("Show indirect call site target 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",
@@ -240,8 +255,8 @@ static int show_main(int argc, const char *argv[]) {
     errs() << "warning: -function argument ignored: showing all functions\n";
 
   if (ProfileKind == instr)
-    return showInstrProfile(Filename, ShowCounts, ShowAllFunctions,
-                            ShowFunction, OS);
+    return showInstrProfile(Filename, ShowCounts, ShowIndirectCallTargets,
+                            ShowAllFunctions, ShowFunction, OS);
   else
     return showSampleProfile(Filename, ShowCounts, ShowAllFunctions,
                              ShowFunction, OS);
index a0995fbbc0287d6a4f2d6b2c9a8276104ebade2b..35b8626c494a100026d3d117cbb7e0c07b1f1237 100644 (file)
@@ -188,7 +188,8 @@ TEST_F(CoverageMappingTest, expansion_gets_first_counter) {
 }
 
 TEST_F(CoverageMappingTest, basic_coverage_iteration) {
-  ProfileWriter.addFunctionCounts("func", 0x1234, {30, 20, 10, 0});
+  InstrProfRecord Record("func", 0x1234, {30, 20, 10, 0});
+  ProfileWriter.addRecord(std::move(Record));
   readProfCounts();
 
   addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
@@ -238,7 +239,8 @@ TEST_F(CoverageMappingTest, uncovered_function_with_mapping) {
 }
 
 TEST_F(CoverageMappingTest, combine_regions) {
-  ProfileWriter.addFunctionCounts("func", 0x1234, {10, 20, 30});
+  InstrProfRecord Record("func", 0x1234, {10, 20, 30});
+  ProfileWriter.addRecord(std::move(Record));
   readProfCounts();
 
   addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
@@ -256,7 +258,8 @@ TEST_F(CoverageMappingTest, combine_regions) {
 }
 
 TEST_F(CoverageMappingTest, dont_combine_expansions) {
-  ProfileWriter.addFunctionCounts("func", 0x1234, {10, 20});
+  InstrProfRecord Record("func", 0x1234, {10, 20});
+  ProfileWriter.addRecord(std::move(Record));
   readProfCounts();
 
   addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
@@ -275,7 +278,8 @@ TEST_F(CoverageMappingTest, dont_combine_expansions) {
 }
 
 TEST_F(CoverageMappingTest, strip_filename_prefix) {
-  ProfileWriter.addFunctionCounts("file1:func", 0x1234, {10});
+  InstrProfRecord Record("file1:func", 0x1234, {10});
+  ProfileWriter.addRecord(std::move(Record));
   readProfCounts();
 
   addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
index 2cedd593eb8c0c0f01e2549294da231276e84eea..0e0141b80ea2f5c959064276137a60f3874fbaf0 100644 (file)
@@ -50,7 +50,8 @@ TEST_F(InstrProfTest, write_and_read_empty_profile) {
 }
 
 TEST_F(InstrProfTest, write_and_read_one_function) {
-  Writer.addFunctionCounts("foo", 0x1234, {1, 2, 3, 4});
+  InstrProfRecord Record("foo", 0x1234, {1, 2, 3, 4});
+  Writer.addRecord(std::move(Record));
   auto Profile = Writer.writeBuffer();
   readProfile(std::move(Profile));
 
@@ -67,8 +68,10 @@ TEST_F(InstrProfTest, write_and_read_one_function) {
 }
 
 TEST_F(InstrProfTest, get_function_counts) {
-  Writer.addFunctionCounts("foo", 0x1234, {1, 2});
-  Writer.addFunctionCounts("foo", 0x1235, {3, 4});
+  InstrProfRecord Record1("foo", 0x1234, {1, 2});
+  InstrProfRecord Record2("foo", 0x1235, {3, 4});
+  Writer.addRecord(std::move(Record1));
+  Writer.addRecord(std::move(Record2));
   auto Profile = Writer.writeBuffer();
   readProfile(std::move(Profile));
 
@@ -92,9 +95,12 @@ TEST_F(InstrProfTest, get_function_counts) {
 }
 
 TEST_F(InstrProfTest, get_max_function_count) {
-  Writer.addFunctionCounts("foo", 0x1234, {1ULL << 31, 2});
-  Writer.addFunctionCounts("bar", 0, {1ULL << 63});
-  Writer.addFunctionCounts("baz", 0x5678, {0, 0, 0, 0});
+  InstrProfRecord Record1("foo", 0x1234, {1ULL << 31, 2});
+  InstrProfRecord Record2("bar", 0, {1ULL << 63});
+  InstrProfRecord Record3("baz", 0x5678, {0, 0, 0, 0});
+  Writer.addRecord(std::move(Record1));
+  Writer.addRecord(std::move(Record2));
+  Writer.addRecord(std::move(Record3));
   auto Profile = Writer.writeBuffer();
   readProfile(std::move(Profile));