aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-cov
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-cov')
-rw-r--r--llvm/tools/llvm-cov/CodeCoverage.cpp42
-rw-r--r--llvm/tools/llvm-cov/CoverageExporterJson.cpp3
-rw-r--r--llvm/tools/llvm-cov/CoverageExporterLcov.cpp5
-rw-r--r--llvm/tools/llvm-cov/CoverageSummaryInfo.cpp6
-rw-r--r--llvm/tools/llvm-cov/CoverageSummaryInfo.h5
-rw-r--r--llvm/tools/llvm-cov/CoverageViewOptions.h1
-rw-r--r--llvm/tools/llvm-cov/TestingSupport.cpp19
-rw-r--r--llvm/tools/llvm-cov/gcov.cpp6
-rw-r--r--llvm/tools/llvm-cov/llvm-cov.cpp2
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.