#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"
/// 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;
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.
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;
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);
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 {
#include "gtest/gtest.h"
#include <ostream>
+#include <utility>
using namespace llvm;
using namespace coverage;
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;
std::unique_ptr<CoverageMapping> LoadedCoverage;
void SetUp() override {
- ProfileWriter.setOutputSparse(GetParam());
+ ProfileWriter.setOutputSparse(GetParam().first);
+ UseMultipleReaders = GetParam().second;
}
unsigned getGlobalFileIndex(StringRef Name) {
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());
}
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