[llvm] r284251 - [Coverage] Support loading multiple binaries into a CoverageMapping

Vedant Kumar via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 14 10:16:53 PDT 2016


Author: vedantk
Date: Fri Oct 14 12:16:53 2016
New Revision: 284251

URL: http://llvm.org/viewvc/llvm-project?rev=284251&view=rev
Log:
[Coverage] Support loading multiple binaries into a CoverageMapping

Add support for loading multiple coverage readers into a single
CoverageMapping instance. This should make it easier to prepare a
unified coverage report for multiple binaries.

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

Modified:
    llvm/trunk/include/llvm/ProfileData/Coverage/CoverageMapping.h
    llvm/trunk/lib/ProfileData/Coverage/CoverageMapping.cpp
    llvm/trunk/unittests/ProfileData/CoverageMappingTest.cpp

Modified: llvm/trunk/include/llvm/ProfileData/Coverage/CoverageMapping.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/Coverage/CoverageMapping.h?rev=284251&r1=284250&r2=284251&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ProfileData/Coverage/CoverageMapping.h (original)
+++ llvm/trunk/include/llvm/ProfileData/Coverage/CoverageMapping.h Fri Oct 14 12:16:53 2016
@@ -18,6 +18,7 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/ADT/iterator.h"
 #include "llvm/ProfileData/InstrProf.h"
@@ -428,6 +429,7 @@ public:
 /// This is the main interface to get coverage information, using a profile to
 /// fill out execution counts.
 class CoverageMapping {
+  StringSet<> FunctionNames;
   std::vector<FunctionRecord> Functions;
   unsigned MismatchedFunctionCount;
 
@@ -446,9 +448,19 @@ public:
   load(CoverageMappingReader &CoverageReader,
        IndexedInstrProfReader &ProfileReader);
 
+  static Expected<std::unique_ptr<CoverageMapping>>
+  load(ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
+       IndexedInstrProfReader &ProfileReader);
+
   /// \brief Load the coverage mapping from the given files.
   static Expected<std::unique_ptr<CoverageMapping>>
   load(StringRef ObjectFilename, StringRef ProfileFilename,
+       StringRef Arch = StringRef()) {
+    return load(ArrayRef<StringRef>(ObjectFilename), ProfileFilename, Arch);
+  }
+
+  static Expected<std::unique_ptr<CoverageMapping>>
+  load(ArrayRef<StringRef> ObjectFilenames, StringRef ProfileFilename,
        StringRef Arch = StringRef());
 
   /// \brief The number of functions that couldn't have their profiles mapped.

Modified: llvm/trunk/lib/ProfileData/Coverage/CoverageMapping.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/Coverage/CoverageMapping.cpp?rev=284251&r1=284250&r2=284251&view=diff
==============================================================================
--- llvm/trunk/lib/ProfileData/Coverage/CoverageMapping.cpp (original)
+++ llvm/trunk/lib/ProfileData/Coverage/CoverageMapping.cpp Fri Oct 14 12:16:53 2016
@@ -186,6 +186,16 @@ void FunctionRecordIterator::skipOtherFi
 Error CoverageMapping::loadFunctionRecord(
     const CoverageMappingRecord &Record,
     IndexedInstrProfReader &ProfileReader) {
+  StringRef OrigFuncName = Record.FunctionName;
+  if (Record.Filenames.empty())
+    OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName);
+  else
+    OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
+
+  // Don't load records for functions we've already seen.
+  if (!FunctionNames.insert(OrigFuncName).second)
+    return Error::success();
+
   CounterMappingContext Ctx(Record.Expressions);
 
   std::vector<uint64_t> Counts;
@@ -203,11 +213,6 @@ Error CoverageMapping::loadFunctionRecor
 
   assert(!Record.MappingRegions.empty() && "Function has no regions");
 
-  StringRef OrigFuncName = Record.FunctionName;
-  if (Record.Filenames.empty())
-    OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName);
-  else
-    OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
   FunctionRecord Function(OrigFuncName, Record.Filenames);
   for (const auto &Region : Record.MappingRegions) {
     Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
@@ -238,22 +243,41 @@ CoverageMapping::load(CoverageMappingRea
   return std::move(Coverage);
 }
 
+Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
+    ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
+    IndexedInstrProfReader &ProfileReader) {
+  auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
+
+  for (const auto &CoverageReader : CoverageReaders)
+    for (const auto &Record : *CoverageReader)
+      if (Error E = Coverage->loadFunctionRecord(Record, ProfileReader))
+        return std::move(E);
+
+  return std::move(Coverage);
+}
+
 Expected<std::unique_ptr<CoverageMapping>>
-CoverageMapping::load(StringRef ObjectFilename, StringRef ProfileFilename,
-                      StringRef Arch) {
-  auto CounterMappingBuff = MemoryBuffer::getFileOrSTDIN(ObjectFilename);
-  if (std::error_code EC = CounterMappingBuff.getError())
-    return errorCodeToError(EC);
-  auto CoverageReaderOrErr =
-      BinaryCoverageReader::create(CounterMappingBuff.get(), Arch);
-  if (Error E = CoverageReaderOrErr.takeError())
-    return std::move(E);
-  auto CoverageReader = std::move(CoverageReaderOrErr.get());
+CoverageMapping::load(ArrayRef<StringRef> ObjectFilenames,
+                      StringRef ProfileFilename, StringRef Arch) {
   auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename);
   if (Error E = ProfileReaderOrErr.takeError())
     return std::move(E);
   auto ProfileReader = std::move(ProfileReaderOrErr.get());
-  return load(*CoverageReader, *ProfileReader);
+
+  SmallVector<std::unique_ptr<CoverageMappingReader>, 4> Readers;
+  SmallVector<std::unique_ptr<MemoryBuffer>, 4> Buffers;
+  for (StringRef ObjectFilename : ObjectFilenames) {
+    auto CovMappingBufOrErr = MemoryBuffer::getFileOrSTDIN(ObjectFilename);
+    if (std::error_code EC = CovMappingBufOrErr.getError())
+      return errorCodeToError(EC);
+    auto CoverageReaderOrErr =
+        BinaryCoverageReader::create(CovMappingBufOrErr.get(), Arch);
+    if (Error E = CoverageReaderOrErr.takeError())
+      return std::move(E);
+    Readers.push_back(std::move(CoverageReaderOrErr.get()));
+    Buffers.push_back(std::move(CovMappingBufOrErr.get()));
+  }
+  return load(Readers, *ProfileReader);
 }
 
 namespace {

Modified: llvm/trunk/unittests/ProfileData/CoverageMappingTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ProfileData/CoverageMappingTest.cpp?rev=284251&r1=284250&r2=284251&view=diff
==============================================================================
--- llvm/trunk/unittests/ProfileData/CoverageMappingTest.cpp (original)
+++ llvm/trunk/unittests/ProfileData/CoverageMappingTest.cpp Fri Oct 14 12:16:53 2016
@@ -16,6 +16,7 @@
 #include "gtest/gtest.h"
 
 #include <ostream>
+#include <utility>
 
 using namespace llvm;
 using namespace coverage;
@@ -118,7 +119,8 @@ struct InputFunctionCoverageData {
   InputFunctionCoverageData &operator=(InputFunctionCoverageData &&) = delete;
 };
 
-struct CoverageMappingTest : ::testing::TestWithParam<bool> {
+struct CoverageMappingTest : ::testing::TestWithParam<std::pair<bool, bool>> {
+  bool UseMultipleReaders;
   StringMap<unsigned> Files;
   std::vector<InputFunctionCoverageData> InputFunctions;
   std::vector<OutputFunctionCoverageData> OutputFunctions;
@@ -129,7 +131,8 @@ struct CoverageMappingTest : ::testing::
   std::unique_ptr<CoverageMapping> LoadedCoverage;
 
   void SetUp() override {
-    ProfileWriter.setOutputSparse(GetParam());
+    ProfileWriter.setOutputSparse(GetParam().first);
+    UseMultipleReaders = GetParam().second;
   }
 
   unsigned getGlobalFileIndex(StringRef Name) {
@@ -215,12 +218,24 @@ struct CoverageMappingTest : ::testing::
     ProfileReader = std::move(ReaderOrErr.get());
   }
 
+  Expected<std::unique_ptr<CoverageMapping>> readOutputFunctions() {
+    if (!UseMultipleReaders) {
+      CoverageMappingReaderMock CovReader(OutputFunctions);
+      return CoverageMapping::load(CovReader, *ProfileReader);
+    }
+
+    std::vector<std::unique_ptr<CoverageMappingReader>> CoverageReaders;
+    for (const auto &OF : OutputFunctions) {
+      ArrayRef<OutputFunctionCoverageData> Funcs(OF);
+      CoverageReaders.push_back(make_unique<CoverageMappingReaderMock>(Funcs));
+    }
+    return CoverageMapping::load(CoverageReaders, *ProfileReader);
+  }
+
   void loadCoverageMapping(bool EmitFilenames = true) {
     readProfCounts();
     writeAndReadCoverageRegions(EmitFilenames);
-
-    CoverageMappingReaderMock CovReader(OutputFunctions);
-    auto CoverageOrErr = CoverageMapping::load(CovReader, *ProfileReader);
+    auto CoverageOrErr = readOutputFunctions();
     ASSERT_TRUE(NoError(CoverageOrErr.takeError()));
     LoadedCoverage = std::move(CoverageOrErr.get());
   }
@@ -547,7 +562,28 @@ TEST_P(CoverageMappingTest, load_coverag
   EXPECT_EQ(CoverageSegment(1, 10, false), Segments[1]);
 }
 
+TEST_P(CoverageMappingTest, skip_duplicate_function_record) {
+  InstrProfRecord Record("func", 0x1234, {1});
+  NoError(ProfileWriter.addRecord(std::move(Record)));
+
+  startFunction("func", 0x1234);
+  addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
+
+  startFunction("func", 0x1234);
+  addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
+
+  loadCoverageMapping();
+
+  auto Funcs = LoadedCoverage->getCoveredFunctions();
+  unsigned NumFuncs = std::distance(Funcs.begin(), Funcs.end());
+  ASSERT_EQ(1U, NumFuncs);
+}
+
+// FIXME: Use ::testing::Combine() when llvm updates its copy of googletest.
 INSTANTIATE_TEST_CASE_P(ParameterizedCovMapTest, CoverageMappingTest,
-                        ::testing::Bool());
+                        ::testing::Values(std::pair<bool, bool>({false, false}),
+                                          std::pair<bool, bool>({false, true}),
+                                          std::pair<bool, bool>({true, false}),
+                                          std::pair<bool, bool>({true, true})));
 
 } // end anonymous namespace




More information about the llvm-commits mailing list