diff options
Diffstat (limited to 'llvm/tools/llvm-cov')
-rw-r--r-- | llvm/tools/llvm-cov/CodeCoverage.cpp | 42 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/CoverageExporterJson.cpp | 3 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/CoverageExporterLcov.cpp | 5 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/CoverageSummaryInfo.cpp | 6 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/CoverageSummaryInfo.h | 5 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/CoverageViewOptions.h | 1 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/TestingSupport.cpp | 19 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/gcov.cpp | 6 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/llvm-cov.cpp | 2 |
9 files changed, 71 insertions, 18 deletions
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp index baa968820b63..02c0106cbc29 100644 --- a/llvm/tools/llvm-cov/CodeCoverage.cpp +++ b/llvm/tools/llvm-cov/CodeCoverage.cpp @@ -80,6 +80,12 @@ private: /// directory, recursively collect all of the paths within the directory. void collectPaths(const std::string &Path); + /// Check if the two given files are the same file. + bool isEquivalentFile(StringRef FilePath1, StringRef FilePath2); + + /// Retrieve a file status with a cache. + Optional<sys::fs::file_status> getFileStatus(StringRef FilePath); + /// Return a memory buffer for the given source file. ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile); @@ -153,6 +159,9 @@ private: /// remapped to, when using -path-equivalence. Optional<std::pair<std::string, std::string>> PathRemapping; + /// File status cache used when finding the same file. + StringMap<Optional<sys::fs::file_status>> FileStatusCache; + /// The architecture the coverage mapping data targets. std::vector<StringRef> CoverageArches; @@ -239,6 +248,27 @@ void CodeCoverageTool::collectPaths(const std::string &Path) { } } +Optional<sys::fs::file_status> +CodeCoverageTool::getFileStatus(StringRef FilePath) { + auto It = FileStatusCache.try_emplace(FilePath); + auto &CachedStatus = It.first->getValue(); + if (!It.second) + return CachedStatus; + + sys::fs::file_status Status; + if (!sys::fs::status(FilePath, Status)) + CachedStatus = Status; + return CachedStatus; +} + +bool CodeCoverageTool::isEquivalentFile(StringRef FilePath1, + StringRef FilePath2) { + auto Status1 = getFileStatus(FilePath1); + auto Status2 = getFileStatus(FilePath2); + return Status1.hasValue() && Status2.hasValue() && + sys::fs::equivalent(Status1.getValue(), Status2.getValue()); +} + ErrorOr<const MemoryBuffer &> CodeCoverageTool::getSourceFile(StringRef SourceFile) { // If we've remapped filenames, look up the real location for this file. @@ -249,7 +279,7 @@ CodeCoverageTool::getSourceFile(StringRef SourceFile) { SourceFile = Loc->second; } for (const auto &Files : LoadedSourceFiles) - if (sys::fs::equivalent(SourceFile, Files.first)) + if (isEquivalentFile(SourceFile, Files.first)) return *Files.second; auto Buffer = MemoryBuffer::getFile(SourceFile); if (auto EC = Buffer.getError()) { @@ -404,7 +434,8 @@ std::unique_ptr<CoverageMapping> CodeCoverageTool::load() { warning("profile data may be out of date - object is newer", ObjectFilename); auto CoverageOrErr = - CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArches); + CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArches, + ViewOpts.CompilationDirectory); if (Error E = CoverageOrErr.takeError()) { error("Failed to load coverage: " + toString(std::move(E)), join(ObjectFilenames.begin(), ObjectFilenames.end(), ", ")); @@ -445,7 +476,7 @@ void CodeCoverageTool::remapPathNames(const CoverageMapping &Coverage) { SmallString<128> NativePath; sys::path::native(Path, NativePath); sys::path::remove_dots(NativePath, true); - if (!sys::path::is_separator(NativePath.back())) + if (!NativePath.empty() && !sys::path::is_separator(NativePath.back())) NativePath += sys::path::get_separator(); return NativePath.c_str(); }; @@ -709,6 +740,10 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"), cl::aliasopt(NumThreads)); + cl::opt<std::string> CompilationDirectory( + "compilation-dir", cl::init(""), + cl::desc("Directory used as a base for relative coverage mapping paths")); + auto commandLineParser = [&, this](int argc, const char **argv) -> int { cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); ViewOpts.Debug = DebugDump; @@ -843,6 +878,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { ViewOpts.ShowInstantiationSummary = InstantiationSummary; ViewOpts.ExportSummaryOnly = SummaryOnly; ViewOpts.NumThreads = NumThreads; + ViewOpts.CompilationDirectory = CompilationDirectory; return 0; }; diff --git a/llvm/tools/llvm-cov/CoverageExporterJson.cpp b/llvm/tools/llvm-cov/CoverageExporterJson.cpp index d1446f379f00..d341abe8dfc8 100644 --- a/llvm/tools/llvm-cov/CoverageExporterJson.cpp +++ b/llvm/tools/llvm-cov/CoverageExporterJson.cpp @@ -123,8 +123,7 @@ collectNestedBranches(const coverage::CoverageMapping &Coverage, // Recursively collect branches from nested expansions. auto NestedExpansions = ExpansionCoverage.getExpansions(); auto NestedExBranches = collectNestedBranches(Coverage, NestedExpansions); - Branches.insert(Branches.end(), NestedExBranches.begin(), - NestedExBranches.end()); + append_range(Branches, NestedExBranches); // Add branches from this level of expansion. auto ExBranches = ExpansionCoverage.getBranches(); diff --git a/llvm/tools/llvm-cov/CoverageExporterLcov.cpp b/llvm/tools/llvm-cov/CoverageExporterLcov.cpp index 99ca037e7b5e..6cf5d9285b90 100644 --- a/llvm/tools/llvm-cov/CoverageExporterLcov.cpp +++ b/llvm/tools/llvm-cov/CoverageExporterLcov.cpp @@ -91,8 +91,7 @@ collectNestedBranches(const coverage::CoverageMapping &Coverage, auto NestedExpansions = ExpansionCoverage.getExpansions(); auto NestedExBranches = collectNestedBranches(Coverage, NestedExpansions, ViewDepth + 1, SrcLine); - Branches.insert(Branches.end(), NestedExBranches.begin(), - NestedExBranches.end()); + append_range(Branches, NestedExBranches); // Add branches from this level of expansion. auto ExBranches = ExpansionCoverage.getBranches(); @@ -123,7 +122,7 @@ void renderBranchExecutionCounts(raw_ostream &OS, collectNestedBranches(Coverage, FileCoverage.getExpansions()); // Append Expansion Branches to Source Branches. - Branches.insert(Branches.end(), ExBranches.begin(), ExBranches.end()); + append_range(Branches, ExBranches); // Sort branches based on line number to ensure branches corresponding to the // same source line are counted together. diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp index 4a0a86168908..10e059adeb7d 100644 --- a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp +++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp @@ -100,11 +100,7 @@ FunctionCoverageSummary::get(const InstantiationGroup &Group, for (const auto &FCS : Summaries.drop_front()) { Summary.RegionCoverage.merge(FCS.RegionCoverage); Summary.LineCoverage.merge(FCS.LineCoverage); - - // Sum branch coverage across instantiation groups for the summary rather - // than "merge" the maximum count. This is a clearer view into whether all - // created branches are covered. - Summary.BranchCoverage += FCS.BranchCoverage; + Summary.BranchCoverage.merge(FCS.BranchCoverage); } return Summary; } diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.h b/llvm/tools/llvm-cov/CoverageSummaryInfo.h index 4bc1c24a079f..62e7cad1012b 100644 --- a/llvm/tools/llvm-cov/CoverageSummaryInfo.h +++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.h @@ -123,6 +123,11 @@ public: return *this; } + void merge(const BranchCoverageInfo &RHS) { + Covered = std::max(Covered, RHS.Covered); + NumBranches = std::max(NumBranches, RHS.NumBranches); + } + size_t getCovered() const { return Covered; } size_t getNumBranches() const { return NumBranches; } diff --git a/llvm/tools/llvm-cov/CoverageViewOptions.h b/llvm/tools/llvm-cov/CoverageViewOptions.h index eee4ba74e165..045fb1787bce 100644 --- a/llvm/tools/llvm-cov/CoverageViewOptions.h +++ b/llvm/tools/llvm-cov/CoverageViewOptions.h @@ -49,6 +49,7 @@ struct CoverageViewOptions { std::string ProjectTitle; std::string CreatedTimeStr; unsigned NumThreads; + std::string CompilationDirectory; /// Change the output's stream color if the colors are enabled. ColoredRawOstream colored_ostream(raw_ostream &OS, diff --git a/llvm/tools/llvm-cov/TestingSupport.cpp b/llvm/tools/llvm-cov/TestingSupport.cpp index b99bd83157d0..9c6b25f2f585 100644 --- a/llvm/tools/llvm-cov/TestingSupport.cpp +++ b/llvm/tools/llvm-cov/TestingSupport.cpp @@ -10,6 +10,7 @@ #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Alignment.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/raw_ostream.h" #include <functional> @@ -47,7 +48,7 @@ int convertForTestingMain(int argc, const char *argv[]) { // Look for the sections that we are interested in. int FoundSectionCount = 0; - SectionRef ProfileNames, CoverageMapping; + SectionRef ProfileNames, CoverageMapping, CoverageRecords; auto ObjFormat = OF->getTripleObjectFormat(); for (const auto &Section : OF->sections()) { StringRef Name; @@ -64,16 +65,20 @@ int convertForTestingMain(int argc, const char *argv[]) { } else if (Name == llvm::getInstrProfSectionName( IPSK_covmap, ObjFormat, /*AddSegmentInfo=*/false)) { CoverageMapping = Section; + } else if (Name == llvm::getInstrProfSectionName( + IPSK_covfun, ObjFormat, /*AddSegmentInfo=*/false)) { + CoverageRecords = Section; } else continue; ++FoundSectionCount; } - if (FoundSectionCount != 2) + if (FoundSectionCount != 3) return 1; // Get the contents of the given sections. uint64_t ProfileNamesAddress = ProfileNames.getAddress(); StringRef CoverageMappingData; + StringRef CoverageRecordsData; StringRef ProfileNamesData; if (Expected<StringRef> E = CoverageMapping.getContents()) CoverageMappingData = *E; @@ -81,6 +86,12 @@ int convertForTestingMain(int argc, const char *argv[]) { consumeError(E.takeError()); return 1; } + if (Expected<StringRef> E = CoverageRecords.getContents()) + CoverageRecordsData = *E; + else { + consumeError(E.takeError()); + return 1; + } if (Expected<StringRef> E = ProfileNames.getContents()) ProfileNamesData = *E; else { @@ -103,6 +114,10 @@ int convertForTestingMain(int argc, const char *argv[]) { for (unsigned Pad = offsetToAlignment(OS.tell(), Align(8)); Pad; --Pad) OS.write(uint8_t(0)); OS << CoverageMappingData; + // Coverage records data is expected to have an alignment of 8. + for (unsigned Pad = offsetToAlignment(OS.tell(), Align(8)); Pad; --Pad) + OS.write(uint8_t(0)); + OS << CoverageRecordsData; return 0; } diff --git a/llvm/tools/llvm-cov/gcov.cpp b/llvm/tools/llvm-cov/gcov.cpp index d42e7cd3b551..9a1ebebc87fc 100644 --- a/llvm/tools/llvm-cov/gcov.cpp +++ b/llvm/tools/llvm-cov/gcov.cpp @@ -46,7 +46,8 @@ static void reportCoverage(StringRef SourceFile, StringRef ObjectDir, // Open .gcda and .gcda without requiring a NUL terminator. The concurrent // modification may nullify the NUL terminator condition. ErrorOr<std::unique_ptr<MemoryBuffer>> GCNO_Buff = - MemoryBuffer::getFileOrSTDIN(GCNO, -1, /*RequiresNullTerminator=*/false); + MemoryBuffer::getFileOrSTDIN(GCNO, /*IsText=*/false, + /*RequiresNullTerminator=*/false); if (std::error_code EC = GCNO_Buff.getError()) { errs() << GCNO << ": " << EC.message() << "\n"; return; @@ -58,7 +59,8 @@ static void reportCoverage(StringRef SourceFile, StringRef ObjectDir, } ErrorOr<std::unique_ptr<MemoryBuffer>> GCDA_Buff = - MemoryBuffer::getFileOrSTDIN(GCDA, -1, /*RequiresNullTerminator=*/false); + MemoryBuffer::getFileOrSTDIN(GCDA, /*IsText=*/false, + /*RequiresNullTerminator=*/false); if (std::error_code EC = GCDA_Buff.getError()) { if (EC != errc::no_such_file_or_directory) { errs() << GCDA << ": " << EC.message() << "\n"; diff --git a/llvm/tools/llvm-cov/llvm-cov.cpp b/llvm/tools/llvm-cov/llvm-cov.cpp index 172ec9f3cedf..0e320c0965f9 100644 --- a/llvm/tools/llvm-cov/llvm-cov.cpp +++ b/llvm/tools/llvm-cov/llvm-cov.cpp @@ -60,7 +60,7 @@ int main(int argc, const char **argv) { InitLLVM X(argc, argv); // If argv[0] is or ends with 'gcov', always be gcov compatible - if (sys::path::stem(argv[0]).endswith_lower("gcov")) + if (sys::path::stem(argv[0]).endswith_insensitive("gcov")) return gcovMain(argc, argv); // Check if we are invoking a specific tool command. |