From 94da968134a0b0705a264ba279099083f777bf0d Mon Sep 17 00:00:00 2001 From: Justin Bogner Date: Wed, 18 Feb 2015 18:01:14 +0000 Subject: [PATCH] InstrProf: Make CoverageMapping testable and add a basic unit test Make CoverageMapping easier to create, so that we can write targeted unit tests for its internals, and add a some infrastructure to write these tests. Finally, add a simple unit test for basic functionality. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@229709 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/ProfileData/CoverageMapping.h | 16 +++- .../llvm/ProfileData/CoverageMappingReader.h | 23 +++--- lib/ProfileData/CoverageMapping.cpp | 2 +- unittests/ProfileData/CoverageMappingTest.cpp | 82 +++++++++++++++++++ 4 files changed, 110 insertions(+), 13 deletions(-) diff --git a/include/llvm/ProfileData/CoverageMapping.h b/include/llvm/ProfileData/CoverageMapping.h index bf35a03f09f..147d17c3bd8 100644 --- a/include/llvm/ProfileData/CoverageMapping.h +++ b/include/llvm/ProfileData/CoverageMapping.h @@ -28,7 +28,7 @@ namespace llvm { class IndexedInstrProfReader; namespace coverage { -class ObjectFileCoverageMappingReader; +class CoverageMappingReader; class CoverageMapping; struct CounterExpressions; @@ -333,10 +333,22 @@ struct CoverageSegment { CoverageSegment(unsigned Line, unsigned Col, bool IsRegionEntry) : Line(Line), Col(Col), Count(0), HasCount(false), IsRegionEntry(IsRegionEntry) {} + + CoverageSegment(unsigned Line, unsigned Col, uint64_t Count, + bool IsRegionEntry) + : Line(Line), Col(Col), Count(Count), HasCount(true), + IsRegionEntry(IsRegionEntry) {} + + friend bool operator==(const CoverageSegment &L, const CoverageSegment &R) { + return std::tie(L.Line, L.Col, L.Count, L.HasCount, L.IsRegionEntry) == + std::tie(R.Line, R.Col, R.Count, R.HasCount, R.IsRegionEntry); + } + void setCount(uint64_t NewCount) { Count = NewCount; HasCount = true; } + void addCount(uint64_t NewCount) { setCount(Count + NewCount); } }; @@ -384,7 +396,7 @@ class CoverageMapping { public: /// \brief Load the coverage mapping using the given readers. static ErrorOr> - load(ObjectFileCoverageMappingReader &CoverageReader, + load(CoverageMappingReader &CoverageReader, IndexedInstrProfReader &ProfileReader); /// \brief Load the coverage mapping from the given files. diff --git a/include/llvm/ProfileData/CoverageMappingReader.h b/include/llvm/ProfileData/CoverageMappingReader.h index 65d7acd7b47..fe567dede94 100644 --- a/include/llvm/ProfileData/CoverageMappingReader.h +++ b/include/llvm/ProfileData/CoverageMappingReader.h @@ -27,7 +27,7 @@ namespace llvm { namespace coverage { -class ObjectFileCoverageMappingReader; +class CoverageMappingReader; /// \brief Coverage mapping information for a single function. struct CoverageMappingRecord { @@ -41,15 +41,14 @@ struct CoverageMappingRecord { /// \brief A file format agnostic iterator over coverage mapping data. class CoverageMappingIterator : public std::iterator { - ObjectFileCoverageMappingReader *Reader; + CoverageMappingReader *Reader; CoverageMappingRecord Record; void increment(); public: CoverageMappingIterator() : Reader(nullptr) {} - CoverageMappingIterator(ObjectFileCoverageMappingReader *Reader) - : Reader(Reader) { + CoverageMappingIterator(CoverageMappingReader *Reader) : Reader(Reader) { increment(); } @@ -67,6 +66,14 @@ public: CoverageMappingRecord *operator->() { return &Record; } }; +class CoverageMappingReader { +public: + virtual std::error_code readNextRecord(CoverageMappingRecord &Record) = 0; + CoverageMappingIterator begin() { return CoverageMappingIterator(this); } + CoverageMappingIterator end() { return CoverageMappingIterator(); } + virtual ~CoverageMappingReader() {} +}; + /// \brief Base class for the raw coverage mapping and filenames data readers. class RawCoverageReader { protected: @@ -135,7 +142,7 @@ private: /// \brief Reader for the coverage mapping data that is emitted by the /// frontend and stored in an object file. -class ObjectFileCoverageMappingReader { +class ObjectFileCoverageMappingReader : public CoverageMappingReader { public: struct ProfileMappingRecord { CoverageMappingVersion Version; @@ -184,11 +191,7 @@ public: sys::fs::file_magic Type = sys::fs::file_magic::unknown); std::error_code readHeader(); - std::error_code readNextRecord(CoverageMappingRecord &Record); - - /// Iterator over profile data. - CoverageMappingIterator begin() { return CoverageMappingIterator(this); } - CoverageMappingIterator end() { return CoverageMappingIterator(); } + std::error_code readNextRecord(CoverageMappingRecord &Record) override; /// \brief Return true if the reader has finished reading the profile data. bool isEOF() { return LastError == instrprof_error::eof; } diff --git a/lib/ProfileData/CoverageMapping.cpp b/lib/ProfileData/CoverageMapping.cpp index 9ff7f29f337..3c615d5b784 100644 --- a/lib/ProfileData/CoverageMapping.cpp +++ b/lib/ProfileData/CoverageMapping.cpp @@ -178,7 +178,7 @@ void FunctionRecordIterator::skipOtherFiles() { } ErrorOr> -CoverageMapping::load(ObjectFileCoverageMappingReader &CoverageReader, +CoverageMapping::load(CoverageMappingReader &CoverageReader, IndexedInstrProfReader &ProfileReader) { auto Coverage = std::unique_ptr(new CoverageMapping()); diff --git a/unittests/ProfileData/CoverageMappingTest.cpp b/unittests/ProfileData/CoverageMappingTest.cpp index 04bc19dc4e4..d079b479216 100644 --- a/unittests/ProfileData/CoverageMappingTest.cpp +++ b/unittests/ProfileData/CoverageMappingTest.cpp @@ -10,6 +10,8 @@ #include "llvm/ProfileData/CoverageMapping.h" #include "llvm/ProfileData/CoverageMappingReader.h" #include "llvm/ProfileData/CoverageMappingWriter.h" +#include "llvm/ProfileData/InstrProfReader.h" +#include "llvm/ProfileData/InstrProfWriter.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" @@ -35,11 +37,45 @@ void PrintTo(const Counter &C, ::std::ostream *os) { else *os << "Counter " << C.getCounterID(); } + +void PrintTo(const CoverageSegment &S, ::std::ostream *os) { + *os << "CoverageSegment(" << S.Line << ", " << S.Col << ", "; + if (S.HasCount) + *os << S.Count << ", "; + *os << (S.IsRegionEntry ? "true" : "false") << ")"; +} } } namespace { +struct OneFunctionCoverageReader : CoverageMappingReader { + StringRef Name; + uint64_t Hash; + std::vector Filenames; + ArrayRef Regions; + bool Done; + + OneFunctionCoverageReader(StringRef Name, uint64_t Hash, + ArrayRef Filenames, + ArrayRef Regions) + : Name(Name), Hash(Hash), Filenames(Filenames), Regions(Regions), + Done(false) {} + + std::error_code readNextRecord(CoverageMappingRecord &Record) override { + if (Done) + return instrprof_error::eof; + Done = true; + + Record.FunctionName = Name; + Record.FunctionHash = Hash; + Record.Filenames = Filenames; + Record.Expressions = {}; + Record.MappingRegions = Regions; + return instrprof_error::success; + } +}; + struct CoverageMappingTest : ::testing::Test { StringMap Files; unsigned NextFile; @@ -49,6 +85,11 @@ struct CoverageMappingTest : ::testing::Test { std::vector OutputExpressions; std::vector OutputCMRs; + InstrProfWriter ProfileWriter; + std::unique_ptr ProfileReader; + + std::unique_ptr LoadedCoverage; + void SetUp() override { NextFile = 0; } @@ -91,6 +132,26 @@ struct CoverageMappingTest : ::testing::Test { OutputExpressions, OutputCMRs); ASSERT_TRUE(NoError(Reader.read())); } + + void readProfCounts() { + auto Profile = ProfileWriter.writeBuffer(); + auto ReaderOrErr = IndexedInstrProfReader::create(std::move(Profile)); + ASSERT_TRUE(NoError(ReaderOrErr.getError())); + ProfileReader = std::move(ReaderOrErr.get()); + } + + void loadCoverageMapping(StringRef FuncName, uint64_t Hash) { + std::string Regions = writeCoverageRegions(); + readCoverageRegions(Regions); + + SmallVector Filenames; + for (const auto &E : Files) + Filenames.push_back(E.getKey()); + OneFunctionCoverageReader CovReader(FuncName, Hash, Filenames, OutputCMRs); + auto CoverageOrErr = CoverageMapping::load(CovReader, *ProfileReader); + ASSERT_TRUE(NoError(CoverageOrErr.getError())); + LoadedCoverage = std::move(CoverageOrErr.get()); + } }; TEST_F(CoverageMappingTest, basic_write_read) { @@ -126,5 +187,26 @@ TEST_F(CoverageMappingTest, expansion_gets_first_counter) { ASSERT_EQ(3U, OutputCMRs[2].LineStart); } +TEST_F(CoverageMappingTest, basic_coverage_iteration) { + ProfileWriter.addFunctionCounts("func", 0x1234, {30, 20, 10, 0}); + readProfCounts(); + + addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); + addCMR(Counter::getCounter(1), "file1", 1, 1, 4, 7); + addCMR(Counter::getCounter(2), "file1", 5, 8, 9, 1); + addCMR(Counter::getCounter(3), "file1", 10, 10, 11, 11); + loadCoverageMapping("func", 0x1234); + + CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); + std::vector Segments(Data.begin(), Data.end()); + ASSERT_EQ(7U, Segments.size()); + ASSERT_EQ(CoverageSegment(1, 1, 20, true), Segments[0]); + ASSERT_EQ(CoverageSegment(4, 7, 30, false), Segments[1]); + ASSERT_EQ(CoverageSegment(5, 8, 10, true), Segments[2]); + ASSERT_EQ(CoverageSegment(9, 1, 30, false), Segments[3]); + ASSERT_EQ(CoverageSegment(9, 9, false), Segments[4]); + ASSERT_EQ(CoverageSegment(10, 10, 0, true), Segments[5]); + ASSERT_EQ(CoverageSegment(11, 11, false), Segments[6]); +} } // end anonymous namespace -- 2.34.1