summaryrefslogtreecommitdiffstats
path: root/llvm/tools/llvm-cov/CodeCoverage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-cov/CodeCoverage.cpp')
-rw-r--r--llvm/tools/llvm-cov/CodeCoverage.cpp369
1 files changed, 96 insertions, 273 deletions
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index 1a5d6a50f9e..5fc5a849cec 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -16,15 +16,11 @@
#include "RenderingSupport.h"
#include "CoverageViewOptions.h"
#include "CoverageFilters.h"
-#include "SourceCoverageDataManager.h"
#include "SourceCoverageView.h"
#include "CoverageSummary.h"
#include "CoverageReport.h"
-#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/ProfileData/CoverageMapping.h"
#include "llvm/ProfileData/CoverageMappingReader.h"
@@ -43,34 +39,6 @@ using namespace llvm;
using namespace coverage;
namespace {
-/// \brief Distribute the functions into instantiation sets.
-///
-/// An instantiation set is a collection of functions that have the same source
-/// code, ie, template functions specializations.
-class FunctionInstantiationSetCollector {
- typedef DenseMap<std::pair<unsigned, unsigned>,
- std::vector<const FunctionCoverageMapping *>> MapT;
- MapT InstantiatedFunctions;
-
-public:
- void insert(const FunctionCoverageMapping &Function, unsigned FileID) {
- auto I = Function.CountedRegions.begin(), E = Function.CountedRegions.end();
- while (I != E && I->FileID != FileID)
- ++I;
- assert(I != E && "function does not cover the given file");
- auto &Functions = InstantiatedFunctions[I->startLoc()];
- Functions.push_back(&Function);
- }
-
- MapT::iterator begin() {
- return InstantiatedFunctions.begin();
- }
-
- MapT::iterator end() {
- return InstantiatedFunctions.end();
- }
-};
-
/// \brief The implementation of the coverage tool.
class CodeCoverageTool {
public:
@@ -87,43 +55,21 @@ public:
/// \brief Return a memory buffer for the given source file.
ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
- /// \brief Collect a set of function's file ids which correspond to the
- /// given source file. Return false if the set is empty.
- bool gatherInterestingFileIDs(StringRef SourceFile,
- const FunctionCoverageMapping &Function,
- SmallSet<unsigned, 8> &InterestingFileIDs);
+ /// \brief Create source views for the expansions of the view.
+ void attachExpansionSubViews(SourceCoverageView &View,
+ ArrayRef<ExpansionRecord> Expansions,
+ CoverageMapping &Coverage);
- /// \brief Find the file id which is not an expanded file id.
- bool findMainViewFileID(StringRef SourceFile,
- const FunctionCoverageMapping &Function,
- unsigned &MainViewFileID);
-
- bool findMainViewFileID(const FunctionCoverageMapping &Function,
- unsigned &MainViewFileID);
-
- /// \brief Create a source view which shows coverage for an expansion
- /// of a file.
- std::unique_ptr<SourceCoverageView>
- createExpansionSubView(const CountedRegion &ExpandedRegion,
- const FunctionCoverageMapping &Function);
-
- void attachExpansionSubViews(SourceCoverageView &View, unsigned ViewFileID,
- const FunctionCoverageMapping &Function);
-
- /// \brief Create a source view which shows coverage for an instantiation
- /// of a funciton.
+ /// \brief Create the source view of a particular function.
std::unique_ptr<SourceCoverageView>
- createInstantiationSubView(StringRef SourceFile,
- const FunctionCoverageMapping &Function);
+ createFunctionView(const FunctionRecord &Function, CoverageMapping &Coverage);
/// \brief Create the main source view of a particular source file.
std::unique_ptr<SourceCoverageView>
- createSourceFileView(StringRef SourceFile,
- ArrayRef<FunctionCoverageMapping> FunctionMappingRecords,
- bool UseOnlyRegionsInMainFile = false);
+ createSourceFileView(StringRef SourceFile, CoverageMapping &Coverage);
/// \brief Load the coverage mapping data. Return true if an error occured.
- bool load();
+ std::unique_ptr<CoverageMapping> load();
int run(Command Cmd, int argc, const char **argv);
@@ -137,29 +83,16 @@ public:
StringRef ObjectFilename;
CoverageViewOptions ViewOpts;
- std::unique_ptr<IndexedInstrProfReader> PGOReader;
+ std::string PGOFilename;
CoverageFiltersMatchAll Filters;
std::vector<std::string> SourceFiles;
std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
LoadedSourceFiles;
- std::vector<FunctionCoverageMapping> FunctionMappingRecords;
bool CompareFilenamesOnly;
StringMap<std::string> RemappedFilenames;
};
}
-static std::vector<StringRef>
-getUniqueFilenames(ArrayRef<FunctionCoverageMapping> FunctionMappingRecords) {
- std::vector<StringRef> Filenames;
- for (const auto &Function : FunctionMappingRecords)
- for (const auto &Filename : Function.Filenames)
- Filenames.push_back(Filename);
- std::sort(Filenames.begin(), Filenames.end());
- auto Last = std::unique(Filenames.begin(), Filenames.end());
- Filenames.erase(Last, Filenames.end());
- return Filenames;
-}
-
void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
errs() << "error: ";
if (!Whence.empty())
@@ -188,219 +121,115 @@ CodeCoverageTool::getSourceFile(StringRef SourceFile) {
return *LoadedSourceFiles.back().second;
}
-bool CodeCoverageTool::gatherInterestingFileIDs(
- StringRef SourceFile, const FunctionCoverageMapping &Function,
- SmallSet<unsigned, 8> &InterestingFileIDs) {
- bool Interesting = false;
- for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
- if (SourceFile == Function.Filenames[I]) {
- InterestingFileIDs.insert(I);
- Interesting = true;
- }
- }
- return Interesting;
-}
-
-bool
-CodeCoverageTool::findMainViewFileID(StringRef SourceFile,
- const FunctionCoverageMapping &Function,
- unsigned &MainViewFileID) {
- llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(), false);
- llvm::SmallVector<bool, 8> FilenameEquivalence(Function.Filenames.size(),
- false);
- for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
- if (SourceFile == Function.Filenames[I])
- FilenameEquivalence[I] = true;
- }
- for (const auto &CR : Function.CountedRegions) {
- if (CR.Kind == CounterMappingRegion::ExpansionRegion &&
- FilenameEquivalence[CR.FileID])
- IsExpandedFile[CR.ExpandedFileID] = true;
- }
- for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
- if (!FilenameEquivalence[I] || IsExpandedFile[I])
- continue;
- MainViewFileID = I;
- return false;
- }
- return true;
-}
-
-bool
-CodeCoverageTool::findMainViewFileID(const FunctionCoverageMapping &Function,
- unsigned &MainViewFileID) {
- llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(), false);
- for (const auto &CR : Function.CountedRegions) {
- if (CR.Kind == CounterMappingRegion::ExpansionRegion)
- IsExpandedFile[CR.ExpandedFileID] = true;
- }
- for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
- if (IsExpandedFile[I])
- continue;
- MainViewFileID = I;
- return false;
- }
- return true;
-}
-
-std::unique_ptr<SourceCoverageView> CodeCoverageTool::createExpansionSubView(
- const CountedRegion &ExpandedRegion,
- const FunctionCoverageMapping &Function) {
- auto SourceBuffer =
- getSourceFile(Function.Filenames[ExpandedRegion.ExpandedFileID]);
- if (!SourceBuffer)
- return nullptr;
- auto RegionManager = llvm::make_unique<SourceCoverageDataManager>();
- for (const auto &CR : Function.CountedRegions) {
- if (CR.FileID == ExpandedRegion.ExpandedFileID)
- RegionManager->insert(CR);
- }
- auto SubView = llvm::make_unique<SourceCoverageView>(SourceBuffer.get(),
- ViewOpts);
- SubView->load(std::move(RegionManager));
- attachExpansionSubViews(*SubView, ExpandedRegion.ExpandedFileID, Function);
- return SubView;
-}
-
-void CodeCoverageTool::attachExpansionSubViews(
- SourceCoverageView &View, unsigned ViewFileID,
- const FunctionCoverageMapping &Function) {
+void
+CodeCoverageTool::attachExpansionSubViews(SourceCoverageView &View,
+ ArrayRef<ExpansionRecord> Expansions,
+ CoverageMapping &Coverage) {
if (!ViewOpts.ShowExpandedRegions)
return;
- for (const auto &CR : Function.CountedRegions) {
- if (CR.Kind != CounterMappingRegion::ExpansionRegion)
+ for (const auto &Expansion : Expansions) {
+ auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
+ if (ExpansionCoverage.empty())
continue;
- if (CR.FileID != ViewFileID)
+ auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename());
+ if (!SourceBuffer)
continue;
- auto SubView = createExpansionSubView(CR, Function);
- if (SubView)
- View.addExpansion(CR, std::move(SubView));
+
+ auto SubViewExpansions = ExpansionCoverage.getExpansions();
+ auto SubView = llvm::make_unique<SourceCoverageView>(
+ SourceBuffer.get(), ViewOpts, std::move(ExpansionCoverage));
+ attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
+ View.addExpansion(Expansion.Region, std::move(SubView));
}
}
std::unique_ptr<SourceCoverageView>
-CodeCoverageTool::createInstantiationSubView(
- StringRef SourceFile, const FunctionCoverageMapping &Function) {
- auto RegionManager = llvm::make_unique<SourceCoverageDataManager>();
- SmallSet<unsigned, 8> InterestingFileIDs;
- if (!gatherInterestingFileIDs(SourceFile, Function, InterestingFileIDs))
+CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
+ CoverageMapping &Coverage) {
+ auto FunctionCoverage = Coverage.getCoverageForFunction(Function);
+ if (FunctionCoverage.empty())
return nullptr;
- // Get the interesting regions
- for (const auto &CR : Function.CountedRegions) {
- if (InterestingFileIDs.count(CR.FileID))
- RegionManager->insert(CR);
- }
-
- auto SourceBuffer = getSourceFile(SourceFile);
+ auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename());
if (!SourceBuffer)
return nullptr;
- auto SubView = llvm::make_unique<SourceCoverageView>(SourceBuffer.get(),
- ViewOpts);
- SubView->load(std::move(RegionManager));
- unsigned MainFileID;
- if (!findMainViewFileID(SourceFile, Function, MainFileID))
- attachExpansionSubViews(*SubView, MainFileID, Function);
- return SubView;
-}
-std::unique_ptr<SourceCoverageView> CodeCoverageTool::createSourceFileView(
- StringRef SourceFile,
- ArrayRef<FunctionCoverageMapping> FunctionMappingRecords,
- bool UseOnlyRegionsInMainFile) {
- auto RegionManager = llvm::make_unique<SourceCoverageDataManager>();
- FunctionInstantiationSetCollector InstantiationSetCollector;
+ auto Expansions = FunctionCoverage.getExpansions();
+ auto View = llvm::make_unique<SourceCoverageView>(
+ SourceBuffer.get(), ViewOpts, std::move(FunctionCoverage));
+ attachExpansionSubViews(*View, Expansions, Coverage);
+
+ return View;
+}
+std::unique_ptr<SourceCoverageView>
+CodeCoverageTool::createSourceFileView(StringRef SourceFile,
+ CoverageMapping &Coverage) {
auto SourceBuffer = getSourceFile(SourceFile);
if (!SourceBuffer)
return nullptr;
- auto View =
- llvm::make_unique<SourceCoverageView>(SourceBuffer.get(), ViewOpts);
-
- for (const auto &Function : FunctionMappingRecords) {
- unsigned MainFileID;
- if (findMainViewFileID(SourceFile, Function, MainFileID))
- continue;
- SmallSet<unsigned, 8> InterestingFileIDs;
- if (UseOnlyRegionsInMainFile) {
- InterestingFileIDs.insert(MainFileID);
- } else if (!gatherInterestingFileIDs(SourceFile, Function,
- InterestingFileIDs))
- continue;
- // Get the interesting regions
- for (const auto &CR : Function.CountedRegions) {
- if (InterestingFileIDs.count(CR.FileID))
- RegionManager->insert(CR);
- }
- InstantiationSetCollector.insert(Function, MainFileID);
- attachExpansionSubViews(*View, MainFileID, Function);
- }
- if (RegionManager->getCoverageSegments().empty())
+ auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
+ if (FileCoverage.empty())
return nullptr;
- View->load(std::move(RegionManager));
- // Show instantiations
- if (!ViewOpts.ShowFunctionInstantiations)
- return View;
- for (const auto &InstantiationSet : InstantiationSetCollector) {
- if (InstantiationSet.second.size() < 2)
- continue;
- for (auto Function : InstantiationSet.second) {
+
+ auto Expansions = FileCoverage.getExpansions();
+ auto View = llvm::make_unique<SourceCoverageView>(
+ SourceBuffer.get(), ViewOpts, std::move(FileCoverage));
+ attachExpansionSubViews(*View, Expansions, Coverage);
+
+ for (auto Function : Coverage.getInstantiations(SourceFile)) {
+ auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
+ auto SubViewExpansions = SubViewCoverage.getExpansions();
+ auto SubView = llvm::make_unique<SourceCoverageView>(
+ SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
+ attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
+
+ if (SubView) {
unsigned FileID = Function->CountedRegions.front().FileID;
unsigned Line = 0;
for (const auto &CR : Function->CountedRegions)
if (CR.FileID == FileID)
Line = std::max(CR.LineEnd, Line);
- auto SubView = createInstantiationSubView(SourceFile, *Function);
- if (SubView)
- View->addInstantiation(Function->Name, Line, std::move(SubView));
+ View->addInstantiation(Function->Name, Line, std::move(SubView));
}
}
return View;
}
-bool CodeCoverageTool::load() {
+std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
auto CounterMappingBuff = MemoryBuffer::getFileOrSTDIN(ObjectFilename);
if (auto EC = CounterMappingBuff.getError()) {
error(EC.message(), ObjectFilename);
- return true;
+ return nullptr;
}
ObjectFileCoverageMappingReader MappingReader(CounterMappingBuff.get());
if (auto EC = MappingReader.readHeader()) {
error(EC.message(), ObjectFilename);
- return true;
+ return nullptr;
}
- std::vector<uint64_t> Counts;
- for (const auto &I : MappingReader) {
- FunctionCoverageMapping Function(I.FunctionName, I.Filenames);
-
- // Create the mapping regions with evaluated execution counts
- Counts.clear();
- PGOReader->getFunctionCounts(Function.Name, I.FunctionHash, Counts);
-
- // Get the biggest referenced counters
- bool RegionError = false;
- CounterMappingContext Ctx(I.Expressions, Counts);
- for (const auto &R : I.MappingRegions) {
- ErrorOr<int64_t> ExecutionCount = Ctx.evaluate(R.Count);
- if (ExecutionCount) {
- Function.CountedRegions.push_back(CountedRegion(R, *ExecutionCount));
- } else if (!RegionError) {
- colored_ostream(errs(), raw_ostream::RED)
- << "error: Regions and counters don't match in a function '"
- << Function.Name << "' (re-run the instrumented binary).";
- errs() << "\n";
- RegionError = true;
- }
- }
-
- if (RegionError || !Filters.matches(Function))
- continue;
+ std::unique_ptr<IndexedInstrProfReader> PGOReader;
+ if (auto EC = IndexedInstrProfReader::create(PGOFilename, PGOReader)) {
+ error(EC.message(), PGOFilename);
+ return nullptr;
+ }
- FunctionMappingRecords.push_back(Function);
+ auto CoverageOrErr = CoverageMapping::load(MappingReader, *PGOReader);
+ if (std::error_code EC = CoverageOrErr.getError()) {
+ colored_ostream(errs(), raw_ostream::RED)
+ << "error: Failed to load coverage: " << EC.message();
+ errs() << "\n";
+ return nullptr;
+ }
+ auto Coverage = std::move(CoverageOrErr.get());
+ unsigned Mismatched = Coverage->getMismatchedCount();
+ if (Mismatched) {
+ colored_ostream(errs(), raw_ostream::RED)
+ << "warning: " << Mismatched << " functions have mismatched data. ";
+ errs() << "\n";
}
if (CompareFilenamesOnly) {
- auto CoveredFiles = getUniqueFilenames(FunctionMappingRecords);
+ auto CoveredFiles = Coverage.get()->getUniqueSourceFiles();
for (auto &SF : SourceFiles) {
StringRef SFBase = sys::path::filename(SF);
for (const auto &CF : CoveredFiles)
@@ -412,7 +241,7 @@ bool CodeCoverageTool::load() {
}
}
- return false;
+ return Coverage;
}
int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
@@ -424,8 +253,8 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
cl::list<std::string> InputSourceFiles(
cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore);
- cl::opt<std::string> PGOFilename(
- "instr-profile", cl::Required,
+ cl::opt<std::string, true> PGOFilename(
+ "instr-profile", cl::Required, cl::location(this->PGOFilename),
cl::desc(
"File with the profile data obtained after an instrumented run"));
@@ -479,11 +308,6 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
ViewOpts.Debug = DebugDump;
CompareFilenamesOnly = FilenameEquivalence;
- if (auto EC = IndexedInstrProfReader::create(PGOFilename, PGOReader)) {
- error(EC.message(), PGOFilename);
- return 1;
- }
-
// Create the function filters
if (!NameFilters.empty() || !NameRegexFilters.empty()) {
auto NameFilterer = new CoverageFilters;
@@ -597,30 +421,28 @@ int CodeCoverageTool::show(int argc, const char **argv,
ViewOpts.ShowExpandedRegions = ShowExpansions;
ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
- if (load())
+ auto Coverage = load();
+ if (!Coverage)
return 1;
if (!Filters.empty()) {
// Show functions
- for (const auto &Function : FunctionMappingRecords) {
- unsigned MainFileID;
- if (findMainViewFileID(Function, MainFileID))
+ for (const auto &Function : Coverage->getCoveredFunctions()) {
+ if (!Filters.matches(Function))
continue;
- StringRef SourceFile = Function.Filenames[MainFileID];
- auto mainView = createSourceFileView(SourceFile, Function, true);
+
+ auto mainView = createFunctionView(Function, *Coverage);
if (!mainView) {
ViewOpts.colored_ostream(outs(), raw_ostream::RED)
- << "warning: Could not read coverage for '" << Function.Name
- << " from " << SourceFile;
+ << "warning: Could not read coverage for '" << Function.Name;
outs() << "\n";
continue;
}
- ViewOpts.colored_ostream(outs(), raw_ostream::CYAN)
- << Function.Name << " from " << SourceFile << ":";
+ ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << Function.Name
+ << ":";
outs() << "\n";
mainView->render(outs(), /*WholeFile=*/false);
- if (FunctionMappingRecords.size() > 1)
- outs() << "\n";
+ outs() << "\n";
}
return 0;
}
@@ -630,11 +452,11 @@ int CodeCoverageTool::show(int argc, const char **argv,
if (SourceFiles.empty())
// Get the source files from the function coverage mapping
- for (StringRef Filename : getUniqueFilenames(FunctionMappingRecords))
+ for (StringRef Filename : Coverage->getUniqueSourceFiles())
SourceFiles.push_back(Filename);
for (const auto &SourceFile : SourceFiles) {
- auto mainView = createSourceFileView(SourceFile, FunctionMappingRecords);
+ auto mainView = createSourceFileView(SourceFile, *Coverage);
if (!mainView) {
ViewOpts.colored_ostream(outs(), raw_ostream::RED)
<< "warning: The file '" << SourceFile << "' isn't covered.";
@@ -665,11 +487,12 @@ int CodeCoverageTool::report(int argc, const char **argv,
ViewOpts.Colors = !NoColors;
- if (load())
+ auto Coverage = load();
+ if (!Coverage)
return 1;
CoverageSummary Summarizer;
- Summarizer.createSummaries(FunctionMappingRecords);
+ Summarizer.createSummaries(Coverage->getCoveredFunctions());
CoverageReport Report(ViewOpts, Summarizer);
if (SourceFiles.empty() && Filters.empty()) {
Report.renderFileReports(llvm::outs());
OpenPOWER on IntegriCloud