diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 |
commit | 71d5a2540a98c81f5bcaeb48805e0e2881f530ef (patch) | |
tree | 5343938942df402b49ec7300a1c25a2d4ccd5821 /tools/llvm-cov | |
parent | 31bbf64f3a4974a2d6c8b3b27ad2f519caf74057 (diff) |
Notes
Diffstat (limited to 'tools/llvm-cov')
-rw-r--r-- | tools/llvm-cov/CodeCoverage.cpp | 42 | ||||
-rw-r--r-- | tools/llvm-cov/CoverageReport.cpp | 69 | ||||
-rw-r--r-- | tools/llvm-cov/CoverageReport.h | 6 | ||||
-rw-r--r-- | tools/llvm-cov/CoverageSummaryInfo.h | 13 | ||||
-rw-r--r-- | tools/llvm-cov/TestingSupport.cpp | 7 | ||||
-rw-r--r-- | tools/llvm-cov/gcov.cpp | 2 |
6 files changed, 97 insertions, 42 deletions
diff --git a/tools/llvm-cov/CodeCoverage.cpp b/tools/llvm-cov/CodeCoverage.cpp index 0a9807ab00334..6179c760d5b20 100644 --- a/tools/llvm-cov/CodeCoverage.cpp +++ b/tools/llvm-cov/CodeCoverage.cpp @@ -15,6 +15,7 @@ #include "CoverageFilters.h" #include "CoverageReport.h" +#include "CoverageSummaryInfo.h" #include "CoverageViewOptions.h" #include "RenderingSupport.h" #include "SourceCoverageView.h" @@ -98,9 +99,6 @@ private: /// \brief If a demangler is available, demangle all symbol names. void demangleSymbols(const CoverageMapping &Coverage); - /// \brief Demangle \p Sym if possible. Otherwise, just return \p Sym. - StringRef getSymbolForHumans(StringRef Sym) const; - /// \brief Write out a source file view to the filesystem. void writeSourceFileView(StringRef SourceFile, CoverageMapping *Coverage, CoveragePrinter *Printer, bool ShowFilenames); @@ -136,10 +134,10 @@ private: /// The architecture the coverage mapping data targets. std::string CoverageArch; - /// A cache for demangled symbol names. - StringMap<std::string> DemangledNames; + /// A cache for demangled symbols. + DemangleCache DC; - /// Errors and warnings which have not been printed. + /// A lock which guards printing to stderr. std::mutex ErrsLock; /// A container for input source file buffers. @@ -267,7 +265,7 @@ CodeCoverageTool::createFunctionView(const FunctionRecord &Function, return nullptr; auto Expansions = FunctionCoverage.getExpansions(); - auto View = SourceCoverageView::create(getSymbolForHumans(Function.Name), + auto View = SourceCoverageView::create(DC.demangle(Function.Name), SourceBuffer.get(), ViewOpts, std::move(FunctionCoverage)); attachExpansionSubViews(*View, Expansions, Coverage); @@ -293,7 +291,7 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile, for (const auto *Function : Coverage.getInstantiations(SourceFile)) { std::unique_ptr<SourceCoverageView> SubView{nullptr}; - StringRef Funcname = getSymbolForHumans(Function->Name); + StringRef Funcname = DC.demangle(Function->Name); if (Function->ExecutionCount > 0) { auto SubViewCoverage = Coverage.getCoverageForFunction(*Function); @@ -453,14 +451,9 @@ void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) { // Cache the demangled names. unsigned I = 0; for (const auto &Function : Coverage.getCoveredFunctions()) - DemangledNames[Function.Name] = Symbols[I++]; -} - -StringRef CodeCoverageTool::getSymbolForHumans(StringRef Sym) const { - const auto DemangledName = DemangledNames.find(Sym); - if (DemangledName == DemangledNames.end()) - return Sym; - return DemangledName->getValue(); + // On Windows, lines in the demangler's output file end with "\r\n". + // Splitting by '\n' keeps '\r's, so cut them now. + DC.DemangledNames[Function.Name] = Symbols[I++].rtrim(); } void CodeCoverageTool::writeSourceFileView(StringRef SourceFile, @@ -817,22 +810,28 @@ int CodeCoverageTool::show(int argc, const char **argv, int CodeCoverageTool::report(int argc, const char **argv, CommandLineParserType commandLineParser) { + cl::opt<bool> ShowFunctionSummaries( + "show-functions", cl::Optional, cl::init(false), + cl::desc("Show coverage summaries for each function")); + auto Err = commandLineParser(argc, argv); if (Err) return Err; - if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML) + if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML) { error("HTML output for summary reports is not yet supported."); + return 1; + } auto Coverage = load(); if (!Coverage) return 1; CoverageReport Report(ViewOpts, *Coverage.get()); - if (SourceFiles.empty()) + if (!ShowFunctionSummaries) Report.renderFileReports(llvm::outs()); else - Report.renderFunctionReports(SourceFiles, llvm::outs()); + Report.renderFunctionReports(SourceFiles, DC, llvm::outs()); return 0; } @@ -843,6 +842,11 @@ int CodeCoverageTool::export_(int argc, const char **argv, if (Err) return Err; + if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text) { + error("Coverage data can only be exported as textual JSON."); + return 1; + } + auto Coverage = load(); if (!Coverage) { error("Could not load coverage information"); diff --git a/tools/llvm-cov/CoverageReport.cpp b/tools/llvm-cov/CoverageReport.cpp index e88cb186acd66..c68bb9048df1b 100644 --- a/tools/llvm-cov/CoverageReport.cpp +++ b/tools/llvm-cov/CoverageReport.cpp @@ -118,19 +118,51 @@ raw_ostream::Colors determineCoveragePercentageColor(const T &Info) { : raw_ostream::RED; } -/// \brief Determine the length of the longest common prefix of the strings in -/// \p Strings. -unsigned getLongestCommonPrefixLen(ArrayRef<std::string> Strings) { - unsigned LCP = Strings[0].size(); - for (unsigned I = 1, E = Strings.size(); LCP > 0 && I < E; ++I) { - unsigned Cursor; - StringRef S = Strings[I]; - for (Cursor = 0; Cursor < LCP && Cursor < S.size(); ++Cursor) - if (Strings[0][Cursor] != S[Cursor]) +/// \brief Get the number of redundant path components in each path in \p Paths. +unsigned getNumRedundantPathComponents(ArrayRef<std::string> Paths) { + // To start, set the number of redundant path components to the maximum + // possible value. + SmallVector<StringRef, 8> FirstPathComponents{sys::path::begin(Paths[0]), + sys::path::end(Paths[0])}; + unsigned NumRedundant = FirstPathComponents.size(); + + for (unsigned I = 1, E = Paths.size(); NumRedundant > 0 && I < E; ++I) { + StringRef Path = Paths[I]; + for (const auto &Component : + enumerate(make_range(sys::path::begin(Path), sys::path::end(Path)))) { + // Do not increase the number of redundant components: that would remove + // useful parts of already-visited paths. + if (Component.index() >= NumRedundant) break; - LCP = std::min(LCP, Cursor); + + // Lower the number of redundant components when there's a mismatch + // between the first path, and the path under consideration. + if (FirstPathComponents[Component.index()] != Component.value()) { + NumRedundant = Component.index(); + break; + } + } + } + + return NumRedundant; +} + +/// \brief Determine the length of the longest redundant prefix of the paths in +/// \p Paths. +unsigned getRedundantPrefixLen(ArrayRef<std::string> Paths) { + // If there's at most one path, no path components are redundant. + if (Paths.size() <= 1) + return 0; + + unsigned PrefixLen = 0; + unsigned NumRedundant = getNumRedundantPathComponents(Paths); + auto Component = sys::path::begin(Paths[0]); + for (unsigned I = 0; I < NumRedundant; ++I) { + auto LastComponent = Component; + ++Component; + PrefixLen += Component - LastComponent; } - return LCP; + return PrefixLen; } } // end anonymous namespace @@ -200,12 +232,14 @@ void CoverageReport::render(const FileCoverageSummary &File, } void CoverageReport::render(const FunctionCoverageSummary &Function, + const DemangleCache &DC, raw_ostream &OS) const { auto FuncCoverageColor = determineCoveragePercentageColor(Function.RegionCoverage); auto LineCoverageColor = determineCoveragePercentageColor(Function.LineCoverage); - OS << column(Function.Name, FunctionReportColumns[0], Column::RightTrim) + OS << column(DC.demangle(Function.Name), FunctionReportColumns[0], + Column::RightTrim) << format("%*u", FunctionReportColumns[1], (unsigned)Function.RegionCoverage.NumRegions); Options.colored_ostream(OS, FuncCoverageColor) @@ -230,6 +264,7 @@ void CoverageReport::render(const FunctionCoverageSummary &Function, } void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files, + const DemangleCache &DC, raw_ostream &OS) { bool isFirst = true; for (StringRef Filename : Files) { @@ -242,7 +277,7 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files, std::vector<StringRef> Funcnames; for (const auto &F : Functions) - Funcnames.emplace_back(F.Name); + Funcnames.emplace_back(DC.demangle(F.Name)); adjustColumnWidths({}, Funcnames); OS << "File '" << Filename << "':\n"; @@ -262,12 +297,12 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files, ++Totals.ExecutionCount; Totals.RegionCoverage += Function.RegionCoverage; Totals.LineCoverage += Function.LineCoverage; - render(Function, OS); + render(Function, DC, OS); } if (Totals.ExecutionCount) { renderDivider(FunctionReportColumns, OS); OS << "\n"; - render(Totals, OS); + render(Totals, DC, OS); } } } @@ -277,9 +312,7 @@ CoverageReport::prepareFileReports(const coverage::CoverageMapping &Coverage, FileCoverageSummary &Totals, ArrayRef<std::string> Files) { std::vector<FileCoverageSummary> FileReports; - unsigned LCP = 0; - if (Files.size() > 1) - LCP = getLongestCommonPrefixLen(Files); + unsigned LCP = getRedundantPrefixLen(Files); for (StringRef Filename : Files) { FileCoverageSummary Summary(Filename.drop_front(LCP)); diff --git a/tools/llvm-cov/CoverageReport.h b/tools/llvm-cov/CoverageReport.h index 7a416497e258e..071be2e21594c 100644 --- a/tools/llvm-cov/CoverageReport.h +++ b/tools/llvm-cov/CoverageReport.h @@ -25,14 +25,16 @@ class CoverageReport { const coverage::CoverageMapping &Coverage; void render(const FileCoverageSummary &File, raw_ostream &OS) const; - void render(const FunctionCoverageSummary &Function, raw_ostream &OS) const; + void render(const FunctionCoverageSummary &Function, const DemangleCache &DC, + raw_ostream &OS) const; public: CoverageReport(const CoverageViewOptions &Options, const coverage::CoverageMapping &Coverage) : Options(Options), Coverage(Coverage) {} - void renderFunctionReports(ArrayRef<std::string> Files, raw_ostream &OS); + void renderFunctionReports(ArrayRef<std::string> Files, + const DemangleCache &DC, raw_ostream &OS); /// Prepare file reports for the files specified in \p Files. static std::vector<FileCoverageSummary> diff --git a/tools/llvm-cov/CoverageSummaryInfo.h b/tools/llvm-cov/CoverageSummaryInfo.h index c04a4d42ccd74..680fc3757686f 100644 --- a/tools/llvm-cov/CoverageSummaryInfo.h +++ b/tools/llvm-cov/CoverageSummaryInfo.h @@ -160,6 +160,19 @@ struct FileCoverageSummary { } }; +/// \brief A cache for demangled symbols. +struct DemangleCache { + StringMap<std::string> DemangledNames; + + /// \brief Demangle \p Sym if possible. Otherwise, just return \p Sym. + StringRef demangle(StringRef Sym) const { + const auto DemangledName = DemangledNames.find(Sym); + if (DemangledName == DemangledNames.end()) + return Sym; + return DemangledName->getValue(); + } +}; + } // namespace llvm #endif // LLVM_COV_COVERAGESUMMARYINFO_H diff --git a/tools/llvm-cov/TestingSupport.cpp b/tools/llvm-cov/TestingSupport.cpp index 72768f4fd583f..4713d75f17dd4 100644 --- a/tools/llvm-cov/TestingSupport.cpp +++ b/tools/llvm-cov/TestingSupport.cpp @@ -48,13 +48,16 @@ int convertForTestingMain(int argc, const char *argv[]) { // Look for the sections that we are interested in. int FoundSectionCount = 0; SectionRef ProfileNames, CoverageMapping; + auto ObjFormat = OF->getTripleObjectFormat(); for (const auto &Section : OF->sections()) { StringRef Name; if (Section.getName(Name)) return 1; - if (Name == llvm::getInstrProfNameSectionName(false)) { + if (Name == llvm::getInstrProfSectionName(IPSK_name, ObjFormat, + /*AddSegmentInfo=*/false)) { ProfileNames = Section; - } else if (Name == llvm::getInstrProfCoverageSectionName(false)) { + } else if (Name == llvm::getInstrProfSectionName( + IPSK_covmap, ObjFormat, /*AddSegmentInfo=*/false)) { CoverageMapping = Section; } else continue; diff --git a/tools/llvm-cov/gcov.cpp b/tools/llvm-cov/gcov.cpp index 4652fed2a384e..4df7f015fd188 100644 --- a/tools/llvm-cov/gcov.cpp +++ b/tools/llvm-cov/gcov.cpp @@ -74,7 +74,7 @@ static void reportCoverage(StringRef SourceFile, StringRef ObjectDir, } if (DumpGCOV) - GF.dump(); + GF.print(errs()); FileInfo FI(Options); GF.collectLineCounts(FI); |