diff options
author | Justin Bogner <mail@justinbogner.com> | 2014-09-20 15:31:56 +0000 |
---|---|---|
committer | Justin Bogner <mail@justinbogner.com> | 2014-09-20 15:31:56 +0000 |
commit | 953e2407edb956eb846a79fc0dce08d032ea0d66 (patch) | |
tree | 617f3d06bf359ec67e4b312f2755e0453ce6cf9b /llvm/tools/llvm-cov/CodeCoverage.cpp | |
parent | f584649ae397396016b1fbfc6fe8d8ea29e2ebf5 (diff) | |
download | bcm5719-llvm-953e2407edb956eb846a79fc0dce08d032ea0d66.tar.gz bcm5719-llvm-953e2407edb956eb846a79fc0dce08d032ea0d66.zip |
llvm-cov: Disentangle the coverage data logic from the display (NFC)
This splits the logic for actually looking up coverage information
from the logic that displays it. These were tangled rather thoroughly
so this change is a bit large, but it mostly consists of moving things
around. The coverage lookup logic itself now lives in the library,
rather than being spread between the library and the tool.
llvm-svn: 218184
Diffstat (limited to 'llvm/tools/llvm-cov/CodeCoverage.cpp')
-rw-r--r-- | llvm/tools/llvm-cov/CodeCoverage.cpp | 369 |
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()); |