1 //===- CodeCoverage.cpp - Coverage tool based on profiling instrumentation-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // The 'CodeCoverageTool' class implements a command line tool to analyze and
10 // report coverage information using the profiling instrumentation and code
13 //===----------------------------------------------------------------------===//
15 #include "CoverageExporterJson.h"
16 #include "CoverageExporterLcov.h"
17 #include "CoverageFilters.h"
18 #include "CoverageReport.h"
19 #include "CoverageSummaryInfo.h"
20 #include "CoverageViewOptions.h"
21 #include "RenderingSupport.h"
22 #include "SourceCoverageView.h"
23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/ADT/StringRef.h"
25 #include "llvm/ADT/Triple.h"
26 #include "llvm/ProfileData/Coverage/CoverageMapping.h"
27 #include "llvm/ProfileData/InstrProfReader.h"
28 #include "llvm/Support/CommandLine.h"
29 #include "llvm/Support/FileSystem.h"
30 #include "llvm/Support/Format.h"
31 #include "llvm/Support/MemoryBuffer.h"
32 #include "llvm/Support/Path.h"
33 #include "llvm/Support/Process.h"
34 #include "llvm/Support/Program.h"
35 #include "llvm/Support/ScopedPrinter.h"
36 #include "llvm/Support/ThreadPool.h"
37 #include "llvm/Support/Threading.h"
38 #include "llvm/Support/ToolOutputFile.h"
42 #include <system_error>
45 using namespace coverage
;
47 void exportCoverageDataToJson(const coverage::CoverageMapping
&CoverageMapping
,
48 const CoverageViewOptions
&Options
,
52 /// The implementation of the coverage tool.
53 class CodeCoverageTool
{
58 /// The report command.
60 /// The export command.
64 int run(Command Cmd
, int argc
, const char **argv
);
67 /// Print the error message to the error output stream.
68 void error(const Twine
&Message
, StringRef Whence
= "");
70 /// Print the warning message to the error output stream.
71 void warning(const Twine
&Message
, StringRef Whence
= "");
73 /// Convert \p Path into an absolute path and append it to the list
74 /// of collected paths.
75 void addCollectedPath(const std::string
&Path
);
77 /// If \p Path is a regular file, collect the path. If it's a
78 /// directory, recursively collect all of the paths within the directory.
79 void collectPaths(const std::string
&Path
);
81 /// Return a memory buffer for the given source file.
82 ErrorOr
<const MemoryBuffer
&> getSourceFile(StringRef SourceFile
);
84 /// Create source views for the expansions of the view.
85 void attachExpansionSubViews(SourceCoverageView
&View
,
86 ArrayRef
<ExpansionRecord
> Expansions
,
87 const CoverageMapping
&Coverage
);
89 /// Create the source view of a particular function.
90 std::unique_ptr
<SourceCoverageView
>
91 createFunctionView(const FunctionRecord
&Function
,
92 const CoverageMapping
&Coverage
);
94 /// Create the main source view of a particular source file.
95 std::unique_ptr
<SourceCoverageView
>
96 createSourceFileView(StringRef SourceFile
, const CoverageMapping
&Coverage
);
98 /// Load the coverage mapping data. Return nullptr if an error occurred.
99 std::unique_ptr
<CoverageMapping
> load();
101 /// Create a mapping from files in the Coverage data to local copies
102 /// (path-equivalence).
103 void remapPathNames(const CoverageMapping
&Coverage
);
105 /// Remove input source files which aren't mapped by \p Coverage.
106 void removeUnmappedInputs(const CoverageMapping
&Coverage
);
108 /// If a demangler is available, demangle all symbol names.
109 void demangleSymbols(const CoverageMapping
&Coverage
);
111 /// Write out a source file view to the filesystem.
112 void writeSourceFileView(StringRef SourceFile
, CoverageMapping
*Coverage
,
113 CoveragePrinter
*Printer
, bool ShowFilenames
);
115 typedef llvm::function_ref
<int(int, const char **)> CommandLineParserType
;
117 int doShow(int argc
, const char **argv
,
118 CommandLineParserType commandLineParser
);
120 int doReport(int argc
, const char **argv
,
121 CommandLineParserType commandLineParser
);
123 int doExport(int argc
, const char **argv
,
124 CommandLineParserType commandLineParser
);
126 std::vector
<StringRef
> ObjectFilenames
;
127 CoverageViewOptions ViewOpts
;
128 CoverageFiltersMatchAll Filters
;
129 CoverageFilters IgnoreFilenameFilters
;
131 /// The path to the indexed profile.
132 std::string PGOFilename
;
134 /// A list of input source files.
135 std::vector
<std::string
> SourceFiles
;
137 /// In -path-equivalence mode, this maps the absolute paths from the coverage
138 /// mapping data to the input source files.
139 StringMap
<std::string
> RemappedFilenames
;
141 /// The coverage data path to be remapped from, and the source path to be
142 /// remapped to, when using -path-equivalence.
143 Optional
<std::pair
<std::string
, std::string
>> PathRemapping
;
145 /// The architecture the coverage mapping data targets.
146 std::vector
<StringRef
> CoverageArches
;
148 /// A cache for demangled symbols.
151 /// A lock which guards printing to stderr.
154 /// A container for input source file buffers.
155 std::mutex LoadedSourceFilesLock
;
156 std::vector
<std::pair
<std::string
, std::unique_ptr
<MemoryBuffer
>>>
159 /// Whitelist from -name-whitelist to be used for filtering.
160 std::unique_ptr
<SpecialCaseList
> NameWhitelist
;
164 static std::string
getErrorString(const Twine
&Message
, StringRef Whence
,
166 std::string Str
= (Warning
? "warning" : "error");
169 Str
+= Whence
.str() + ": ";
170 Str
+= Message
.str() + "\n";
174 void CodeCoverageTool::error(const Twine
&Message
, StringRef Whence
) {
175 std::unique_lock
<std::mutex
> Guard
{ErrsLock
};
176 ViewOpts
.colored_ostream(errs(), raw_ostream::RED
)
177 << getErrorString(Message
, Whence
, false);
180 void CodeCoverageTool::warning(const Twine
&Message
, StringRef Whence
) {
181 std::unique_lock
<std::mutex
> Guard
{ErrsLock
};
182 ViewOpts
.colored_ostream(errs(), raw_ostream::RED
)
183 << getErrorString(Message
, Whence
, true);
186 void CodeCoverageTool::addCollectedPath(const std::string
&Path
) {
187 SmallString
<128> EffectivePath(Path
);
188 if (std::error_code EC
= sys::fs::make_absolute(EffectivePath
)) {
189 error(EC
.message(), Path
);
192 sys::path::remove_dots(EffectivePath
, /*remove_dot_dots=*/true);
193 if (!IgnoreFilenameFilters
.matchesFilename(EffectivePath
))
194 SourceFiles
.emplace_back(EffectivePath
.str());
197 void CodeCoverageTool::collectPaths(const std::string
&Path
) {
198 llvm::sys::fs::file_status Status
;
199 llvm::sys::fs::status(Path
, Status
);
200 if (!llvm::sys::fs::exists(Status
)) {
202 addCollectedPath(Path
);
204 warning("Source file doesn't exist, proceeded by ignoring it.", Path
);
208 if (llvm::sys::fs::is_regular_file(Status
)) {
209 addCollectedPath(Path
);
213 if (llvm::sys::fs::is_directory(Status
)) {
215 for (llvm::sys::fs::recursive_directory_iterator
F(Path
, EC
), E
;
216 F
!= E
; F
.increment(EC
)) {
218 auto Status
= F
->status();
220 warning(Status
.getError().message(), F
->path());
224 if (Status
->type() == llvm::sys::fs::file_type::regular_file
)
225 addCollectedPath(F
->path());
230 ErrorOr
<const MemoryBuffer
&>
231 CodeCoverageTool::getSourceFile(StringRef SourceFile
) {
232 // If we've remapped filenames, look up the real location for this file.
233 std::unique_lock
<std::mutex
> Guard
{LoadedSourceFilesLock
};
234 if (!RemappedFilenames
.empty()) {
235 auto Loc
= RemappedFilenames
.find(SourceFile
);
236 if (Loc
!= RemappedFilenames
.end())
237 SourceFile
= Loc
->second
;
239 for (const auto &Files
: LoadedSourceFiles
)
240 if (sys::fs::equivalent(SourceFile
, Files
.first
))
241 return *Files
.second
;
242 auto Buffer
= MemoryBuffer::getFile(SourceFile
);
243 if (auto EC
= Buffer
.getError()) {
244 error(EC
.message(), SourceFile
);
247 LoadedSourceFiles
.emplace_back(SourceFile
, std::move(Buffer
.get()));
248 return *LoadedSourceFiles
.back().second
;
251 void CodeCoverageTool::attachExpansionSubViews(
252 SourceCoverageView
&View
, ArrayRef
<ExpansionRecord
> Expansions
,
253 const CoverageMapping
&Coverage
) {
254 if (!ViewOpts
.ShowExpandedRegions
)
256 for (const auto &Expansion
: Expansions
) {
257 auto ExpansionCoverage
= Coverage
.getCoverageForExpansion(Expansion
);
258 if (ExpansionCoverage
.empty())
260 auto SourceBuffer
= getSourceFile(ExpansionCoverage
.getFilename());
264 auto SubViewExpansions
= ExpansionCoverage
.getExpansions();
266 SourceCoverageView::create(Expansion
.Function
.Name
, SourceBuffer
.get(),
267 ViewOpts
, std::move(ExpansionCoverage
));
268 attachExpansionSubViews(*SubView
, SubViewExpansions
, Coverage
);
269 View
.addExpansion(Expansion
.Region
, std::move(SubView
));
273 std::unique_ptr
<SourceCoverageView
>
274 CodeCoverageTool::createFunctionView(const FunctionRecord
&Function
,
275 const CoverageMapping
&Coverage
) {
276 auto FunctionCoverage
= Coverage
.getCoverageForFunction(Function
);
277 if (FunctionCoverage
.empty())
279 auto SourceBuffer
= getSourceFile(FunctionCoverage
.getFilename());
283 auto Expansions
= FunctionCoverage
.getExpansions();
284 auto View
= SourceCoverageView::create(DC
.demangle(Function
.Name
),
285 SourceBuffer
.get(), ViewOpts
,
286 std::move(FunctionCoverage
));
287 attachExpansionSubViews(*View
, Expansions
, Coverage
);
292 std::unique_ptr
<SourceCoverageView
>
293 CodeCoverageTool::createSourceFileView(StringRef SourceFile
,
294 const CoverageMapping
&Coverage
) {
295 auto SourceBuffer
= getSourceFile(SourceFile
);
298 auto FileCoverage
= Coverage
.getCoverageForFile(SourceFile
);
299 if (FileCoverage
.empty())
302 auto Expansions
= FileCoverage
.getExpansions();
303 auto View
= SourceCoverageView::create(SourceFile
, SourceBuffer
.get(),
304 ViewOpts
, std::move(FileCoverage
));
305 attachExpansionSubViews(*View
, Expansions
, Coverage
);
306 if (!ViewOpts
.ShowFunctionInstantiations
)
309 for (const auto &Group
: Coverage
.getInstantiationGroups(SourceFile
)) {
310 // Skip functions which have a single instantiation.
311 if (Group
.size() < 2)
314 for (const FunctionRecord
*Function
: Group
.getInstantiations()) {
315 std::unique_ptr
<SourceCoverageView
> SubView
{nullptr};
317 StringRef Funcname
= DC
.demangle(Function
->Name
);
319 if (Function
->ExecutionCount
> 0) {
320 auto SubViewCoverage
= Coverage
.getCoverageForFunction(*Function
);
321 auto SubViewExpansions
= SubViewCoverage
.getExpansions();
322 SubView
= SourceCoverageView::create(
323 Funcname
, SourceBuffer
.get(), ViewOpts
, std::move(SubViewCoverage
));
324 attachExpansionSubViews(*SubView
, SubViewExpansions
, Coverage
);
327 unsigned FileID
= Function
->CountedRegions
.front().FileID
;
329 for (const auto &CR
: Function
->CountedRegions
)
330 if (CR
.FileID
== FileID
)
331 Line
= std::max(CR
.LineEnd
, Line
);
332 View
->addInstantiation(Funcname
, Line
, std::move(SubView
));
338 static bool modifiedTimeGT(StringRef LHS
, StringRef RHS
) {
339 sys::fs::file_status Status
;
340 if (sys::fs::status(LHS
, Status
))
342 auto LHSTime
= Status
.getLastModificationTime();
343 if (sys::fs::status(RHS
, Status
))
345 auto RHSTime
= Status
.getLastModificationTime();
346 return LHSTime
> RHSTime
;
349 std::unique_ptr
<CoverageMapping
> CodeCoverageTool::load() {
350 for (StringRef ObjectFilename
: ObjectFilenames
)
351 if (modifiedTimeGT(ObjectFilename
, PGOFilename
))
352 warning("profile data may be out of date - object is newer",
355 CoverageMapping::load(ObjectFilenames
, PGOFilename
, CoverageArches
);
356 if (Error E
= CoverageOrErr
.takeError()) {
357 error("Failed to load coverage: " + toString(std::move(E
)),
358 join(ObjectFilenames
.begin(), ObjectFilenames
.end(), ", "));
361 auto Coverage
= std::move(CoverageOrErr
.get());
362 unsigned Mismatched
= Coverage
->getMismatchedCount();
364 warning(Twine(Mismatched
) + " functions have mismatched data");
366 if (ViewOpts
.Debug
) {
367 for (const auto &HashMismatch
: Coverage
->getHashMismatches())
368 errs() << "hash-mismatch: "
369 << "No profile record found for '" << HashMismatch
.first
<< "'"
370 << " with hash = 0x" << Twine::utohexstr(HashMismatch
.second
)
375 remapPathNames(*Coverage
);
377 if (!SourceFiles
.empty())
378 removeUnmappedInputs(*Coverage
);
380 demangleSymbols(*Coverage
);
385 void CodeCoverageTool::remapPathNames(const CoverageMapping
&Coverage
) {
389 // Convert remapping paths to native paths with trailing seperators.
390 auto nativeWithTrailing
= [](StringRef Path
) -> std::string
{
393 SmallString
<128> NativePath
;
394 sys::path::native(Path
, NativePath
);
395 if (!sys::path::is_separator(NativePath
.back()))
396 NativePath
+= sys::path::get_separator();
397 return NativePath
.c_str();
399 std::string RemapFrom
= nativeWithTrailing(PathRemapping
->first
);
400 std::string RemapTo
= nativeWithTrailing(PathRemapping
->second
);
402 // Create a mapping from coverage data file paths to local paths.
403 for (StringRef Filename
: Coverage
.getUniqueSourceFiles()) {
404 SmallString
<128> NativeFilename
;
405 sys::path::native(Filename
, NativeFilename
);
406 if (NativeFilename
.startswith(RemapFrom
)) {
407 RemappedFilenames
[Filename
] =
408 RemapTo
+ NativeFilename
.substr(RemapFrom
.size()).str();
412 // Convert input files from local paths to coverage data file paths.
413 StringMap
<std::string
> InvRemappedFilenames
;
414 for (const auto &RemappedFilename
: RemappedFilenames
)
415 InvRemappedFilenames
[RemappedFilename
.getValue()] = RemappedFilename
.getKey();
417 for (std::string
&Filename
: SourceFiles
) {
418 SmallString
<128> NativeFilename
;
419 sys::path::native(Filename
, NativeFilename
);
420 auto CovFileName
= InvRemappedFilenames
.find(NativeFilename
);
421 if (CovFileName
!= InvRemappedFilenames
.end())
422 Filename
= CovFileName
->second
;
426 void CodeCoverageTool::removeUnmappedInputs(const CoverageMapping
&Coverage
) {
427 std::vector
<StringRef
> CoveredFiles
= Coverage
.getUniqueSourceFiles();
429 auto UncoveredFilesIt
= SourceFiles
.end();
430 // The user may have specified source files which aren't in the coverage
431 // mapping. Filter these files away.
432 UncoveredFilesIt
= std::remove_if(
433 SourceFiles
.begin(), SourceFiles
.end(), [&](const std::string
&SF
) {
434 return !std::binary_search(CoveredFiles
.begin(), CoveredFiles
.end(),
438 SourceFiles
.erase(UncoveredFilesIt
, SourceFiles
.end());
441 void CodeCoverageTool::demangleSymbols(const CoverageMapping
&Coverage
) {
442 if (!ViewOpts
.hasDemangler())
445 // Pass function names to the demangler in a temporary file.
447 SmallString
<256> InputPath
;
449 sys::fs::createTemporaryFile("demangle-in", "list", InputFD
, InputPath
);
451 error(InputPath
, EC
.message());
454 ToolOutputFile InputTOF
{InputPath
, InputFD
};
456 unsigned NumSymbols
= 0;
457 for (const auto &Function
: Coverage
.getCoveredFunctions()) {
458 InputTOF
.os() << Function
.Name
<< '\n';
461 InputTOF
.os().close();
463 // Use another temporary file to store the demangler's output.
465 SmallString
<256> OutputPath
;
466 EC
= sys::fs::createTemporaryFile("demangle-out", "list", OutputFD
,
469 error(OutputPath
, EC
.message());
472 ToolOutputFile OutputTOF
{OutputPath
, OutputFD
};
473 OutputTOF
.os().close();
475 // Invoke the demangler.
476 std::vector
<StringRef
> ArgsV
;
477 for (StringRef Arg
: ViewOpts
.DemanglerOpts
)
478 ArgsV
.push_back(Arg
);
479 Optional
<StringRef
> Redirects
[] = {InputPath
.str(), OutputPath
.str(), {""}};
481 int RC
= sys::ExecuteAndWait(ViewOpts
.DemanglerOpts
[0], ArgsV
,
482 /*env=*/None
, Redirects
, /*secondsToWait=*/0,
483 /*memoryLimit=*/0, &ErrMsg
);
485 error(ErrMsg
, ViewOpts
.DemanglerOpts
[0]);
489 // Parse the demangler's output.
490 auto BufOrError
= MemoryBuffer::getFile(OutputPath
);
492 error(OutputPath
, BufOrError
.getError().message());
496 std::unique_ptr
<MemoryBuffer
> DemanglerBuf
= std::move(*BufOrError
);
498 SmallVector
<StringRef
, 8> Symbols
;
499 StringRef DemanglerData
= DemanglerBuf
->getBuffer();
500 DemanglerData
.split(Symbols
, '\n', /*MaxSplit=*/NumSymbols
,
501 /*KeepEmpty=*/false);
502 if (Symbols
.size() != NumSymbols
) {
503 error("Demangler did not provide expected number of symbols");
507 // Cache the demangled names.
509 for (const auto &Function
: Coverage
.getCoveredFunctions())
510 // On Windows, lines in the demangler's output file end with "\r\n".
511 // Splitting by '\n' keeps '\r's, so cut them now.
512 DC
.DemangledNames
[Function
.Name
] = Symbols
[I
++].rtrim();
515 void CodeCoverageTool::writeSourceFileView(StringRef SourceFile
,
516 CoverageMapping
*Coverage
,
517 CoveragePrinter
*Printer
,
518 bool ShowFilenames
) {
519 auto View
= createSourceFileView(SourceFile
, *Coverage
);
521 warning("The file '" + SourceFile
+ "' isn't covered.");
525 auto OSOrErr
= Printer
->createViewFile(SourceFile
, /*InToplevel=*/false);
526 if (Error E
= OSOrErr
.takeError()) {
527 error("Could not create view file!", toString(std::move(E
)));
530 auto OS
= std::move(OSOrErr
.get());
532 View
->print(*OS
.get(), /*Wholefile=*/true,
533 /*ShowSourceName=*/ShowFilenames
,
534 /*ShowTitle=*/ViewOpts
.hasOutputDirectory());
535 Printer
->closeViewFile(std::move(OS
));
538 int CodeCoverageTool::run(Command Cmd
, int argc
, const char **argv
) {
539 cl::opt
<std::string
> CovFilename(
540 cl::Positional
, cl::desc("Covered executable or object file."));
542 cl::list
<std::string
> CovFilenames(
543 "object", cl::desc("Coverage executable or object file"), cl::ZeroOrMore
,
546 cl::list
<std::string
> InputSourceFiles(
547 cl::Positional
, cl::desc("<Source files>"), cl::ZeroOrMore
);
549 cl::opt
<bool> DebugDumpCollectedPaths(
550 "dump-collected-paths", cl::Optional
, cl::Hidden
,
551 cl::desc("Show the collected paths to source files"));
553 cl::opt
<std::string
, true> PGOFilename(
554 "instr-profile", cl::Required
, cl::location(this->PGOFilename
),
556 "File with the profile data obtained after an instrumented run"));
558 cl::list
<std::string
> Arches(
559 "arch", cl::desc("architectures of the coverage mapping binaries"));
561 cl::opt
<bool> DebugDump("dump", cl::Optional
,
562 cl::desc("Show internal debug dump"));
564 cl::opt
<CoverageViewOptions::OutputFormat
> Format(
565 "format", cl::desc("Output format for line-based coverage reports"),
566 cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text
, "text",
568 clEnumValN(CoverageViewOptions::OutputFormat::HTML
, "html",
570 clEnumValN(CoverageViewOptions::OutputFormat::Lcov
, "lcov",
571 "lcov tracefile output")),
572 cl::init(CoverageViewOptions::OutputFormat::Text
));
574 cl::opt
<std::string
> PathRemap(
575 "path-equivalence", cl::Optional
,
576 cl::desc("<from>,<to> Map coverage data paths to local source file "
579 cl::OptionCategory
FilteringCategory("Function filtering options");
581 cl::list
<std::string
> NameFilters(
582 "name", cl::Optional
,
583 cl::desc("Show code coverage only for functions with the given name"),
584 cl::ZeroOrMore
, cl::cat(FilteringCategory
));
586 cl::list
<std::string
> NameFilterFiles(
587 "name-whitelist", cl::Optional
,
588 cl::desc("Show code coverage only for functions listed in the given "
590 cl::ZeroOrMore
, cl::cat(FilteringCategory
));
592 cl::list
<std::string
> NameRegexFilters(
593 "name-regex", cl::Optional
,
594 cl::desc("Show code coverage only for functions that match the given "
595 "regular expression"),
596 cl::ZeroOrMore
, cl::cat(FilteringCategory
));
598 cl::list
<std::string
> IgnoreFilenameRegexFilters(
599 "ignore-filename-regex", cl::Optional
,
600 cl::desc("Skip source code files with file paths that match the given "
601 "regular expression"),
602 cl::ZeroOrMore
, cl::cat(FilteringCategory
));
604 cl::opt
<double> RegionCoverageLtFilter(
605 "region-coverage-lt", cl::Optional
,
606 cl::desc("Show code coverage only for functions with region coverage "
607 "less than the given threshold"),
608 cl::cat(FilteringCategory
));
610 cl::opt
<double> RegionCoverageGtFilter(
611 "region-coverage-gt", cl::Optional
,
612 cl::desc("Show code coverage only for functions with region coverage "
613 "greater than the given threshold"),
614 cl::cat(FilteringCategory
));
616 cl::opt
<double> LineCoverageLtFilter(
617 "line-coverage-lt", cl::Optional
,
618 cl::desc("Show code coverage only for functions with line coverage less "
619 "than the given threshold"),
620 cl::cat(FilteringCategory
));
622 cl::opt
<double> LineCoverageGtFilter(
623 "line-coverage-gt", cl::Optional
,
624 cl::desc("Show code coverage only for functions with line coverage "
625 "greater than the given threshold"),
626 cl::cat(FilteringCategory
));
628 cl::opt
<cl::boolOrDefault
> UseColor(
629 "use-color", cl::desc("Emit colored output (default=autodetect)"),
630 cl::init(cl::BOU_UNSET
));
632 cl::list
<std::string
> DemanglerOpts(
633 "Xdemangler", cl::desc("<demangler-path>|<demangler-option>"));
635 cl::opt
<bool> RegionSummary(
636 "show-region-summary", cl::Optional
,
637 cl::desc("Show region statistics in summary table"),
640 cl::opt
<bool> InstantiationSummary(
641 "show-instantiation-summary", cl::Optional
,
642 cl::desc("Show instantiation statistics in summary table"));
644 cl::opt
<bool> SummaryOnly(
645 "summary-only", cl::Optional
,
646 cl::desc("Export only summary information for each source file"));
648 cl::opt
<unsigned> NumThreads(
649 "num-threads", cl::init(0),
650 cl::desc("Number of merge threads to use (default: autodetect)"));
651 cl::alias
NumThreadsA("j", cl::desc("Alias for --num-threads"),
652 cl::aliasopt(NumThreads
));
654 auto commandLineParser
= [&, this](int argc
, const char **argv
) -> int {
655 cl::ParseCommandLineOptions(argc
, argv
, "LLVM code coverage tool\n");
656 ViewOpts
.Debug
= DebugDump
;
658 if (!CovFilename
.empty())
659 ObjectFilenames
.emplace_back(CovFilename
);
660 for (const std::string
&Filename
: CovFilenames
)
661 ObjectFilenames
.emplace_back(Filename
);
662 if (ObjectFilenames
.empty()) {
663 errs() << "No filenames specified!\n";
667 ViewOpts
.Format
= Format
;
668 switch (ViewOpts
.Format
) {
669 case CoverageViewOptions::OutputFormat::Text
:
670 ViewOpts
.Colors
= UseColor
== cl::BOU_UNSET
671 ? sys::Process::StandardOutHasColors()
672 : UseColor
== cl::BOU_TRUE
;
674 case CoverageViewOptions::OutputFormat::HTML
:
675 if (UseColor
== cl::BOU_FALSE
)
676 errs() << "Color output cannot be disabled when generating html.\n";
677 ViewOpts
.Colors
= true;
679 case CoverageViewOptions::OutputFormat::Lcov
:
680 if (UseColor
== cl::BOU_TRUE
)
681 errs() << "Color output cannot be enabled when generating lcov.\n";
682 ViewOpts
.Colors
= false;
686 // If path-equivalence was given and is a comma seperated pair then set
688 auto EquivPair
= StringRef(PathRemap
).split(',');
689 if (!(EquivPair
.first
.empty() && EquivPair
.second
.empty()))
690 PathRemapping
= EquivPair
;
692 // If a demangler is supplied, check if it exists and register it.
693 if (!DemanglerOpts
.empty()) {
694 auto DemanglerPathOrErr
= sys::findProgramByName(DemanglerOpts
[0]);
695 if (!DemanglerPathOrErr
) {
696 error("Could not find the demangler!",
697 DemanglerPathOrErr
.getError().message());
700 DemanglerOpts
[0] = *DemanglerPathOrErr
;
701 ViewOpts
.DemanglerOpts
.swap(DemanglerOpts
);
704 // Read in -name-whitelist files.
705 if (!NameFilterFiles
.empty()) {
706 std::string SpecialCaseListErr
;
708 SpecialCaseList::create(NameFilterFiles
, SpecialCaseListErr
);
710 error(SpecialCaseListErr
);
713 // Create the function filters
714 if (!NameFilters
.empty() || NameWhitelist
|| !NameRegexFilters
.empty()) {
715 auto NameFilterer
= llvm::make_unique
<CoverageFilters
>();
716 for (const auto &Name
: NameFilters
)
717 NameFilterer
->push_back(llvm::make_unique
<NameCoverageFilter
>(Name
));
719 NameFilterer
->push_back(
720 llvm::make_unique
<NameWhitelistCoverageFilter
>(*NameWhitelist
));
721 for (const auto &Regex
: NameRegexFilters
)
722 NameFilterer
->push_back(
723 llvm::make_unique
<NameRegexCoverageFilter
>(Regex
));
724 Filters
.push_back(std::move(NameFilterer
));
727 if (RegionCoverageLtFilter
.getNumOccurrences() ||
728 RegionCoverageGtFilter
.getNumOccurrences() ||
729 LineCoverageLtFilter
.getNumOccurrences() ||
730 LineCoverageGtFilter
.getNumOccurrences()) {
731 auto StatFilterer
= llvm::make_unique
<CoverageFilters
>();
732 if (RegionCoverageLtFilter
.getNumOccurrences())
733 StatFilterer
->push_back(llvm::make_unique
<RegionCoverageFilter
>(
734 RegionCoverageFilter::LessThan
, RegionCoverageLtFilter
));
735 if (RegionCoverageGtFilter
.getNumOccurrences())
736 StatFilterer
->push_back(llvm::make_unique
<RegionCoverageFilter
>(
737 RegionCoverageFilter::GreaterThan
, RegionCoverageGtFilter
));
738 if (LineCoverageLtFilter
.getNumOccurrences())
739 StatFilterer
->push_back(llvm::make_unique
<LineCoverageFilter
>(
740 LineCoverageFilter::LessThan
, LineCoverageLtFilter
));
741 if (LineCoverageGtFilter
.getNumOccurrences())
742 StatFilterer
->push_back(llvm::make_unique
<LineCoverageFilter
>(
743 RegionCoverageFilter::GreaterThan
, LineCoverageGtFilter
));
744 Filters
.push_back(std::move(StatFilterer
));
747 // Create the ignore filename filters.
748 for (const auto &RE
: IgnoreFilenameRegexFilters
)
749 IgnoreFilenameFilters
.push_back(
750 llvm::make_unique
<NameRegexCoverageFilter
>(RE
));
752 if (!Arches
.empty()) {
753 for (const std::string
&Arch
: Arches
) {
754 if (Triple(Arch
).getArch() == llvm::Triple::ArchType::UnknownArch
) {
755 error("Unknown architecture: " + Arch
);
758 CoverageArches
.emplace_back(Arch
);
760 if (CoverageArches
.size() != ObjectFilenames
.size()) {
761 error("Number of architectures doesn't match the number of objects");
766 // IgnoreFilenameFilters are applied even when InputSourceFiles specified.
767 for (const std::string
&File
: InputSourceFiles
)
770 if (DebugDumpCollectedPaths
) {
771 for (const std::string
&SF
: SourceFiles
)
772 outs() << SF
<< '\n';
776 ViewOpts
.ShowRegionSummary
= RegionSummary
;
777 ViewOpts
.ShowInstantiationSummary
= InstantiationSummary
;
778 ViewOpts
.ExportSummaryOnly
= SummaryOnly
;
779 ViewOpts
.NumThreads
= NumThreads
;
786 return doShow(argc
, argv
, commandLineParser
);
788 return doReport(argc
, argv
, commandLineParser
);
790 return doExport(argc
, argv
, commandLineParser
);
795 int CodeCoverageTool::doShow(int argc
, const char **argv
,
796 CommandLineParserType commandLineParser
) {
798 cl::OptionCategory
ViewCategory("Viewing options");
800 cl::opt
<bool> ShowLineExecutionCounts(
801 "show-line-counts", cl::Optional
,
802 cl::desc("Show the execution counts for each line"), cl::init(true),
803 cl::cat(ViewCategory
));
805 cl::opt
<bool> ShowRegions(
806 "show-regions", cl::Optional
,
807 cl::desc("Show the execution counts for each region"),
808 cl::cat(ViewCategory
));
810 cl::opt
<bool> ShowBestLineRegionsCounts(
811 "show-line-counts-or-regions", cl::Optional
,
812 cl::desc("Show the execution counts for each line, or the execution "
813 "counts for each region on lines that have multiple regions"),
814 cl::cat(ViewCategory
));
816 cl::opt
<bool> ShowExpansions("show-expansions", cl::Optional
,
817 cl::desc("Show expanded source regions"),
818 cl::cat(ViewCategory
));
820 cl::opt
<bool> ShowInstantiations("show-instantiations", cl::Optional
,
821 cl::desc("Show function instantiations"),
822 cl::init(true), cl::cat(ViewCategory
));
824 cl::opt
<std::string
> ShowOutputDirectory(
825 "output-dir", cl::init(""),
826 cl::desc("Directory in which coverage information is written out"));
827 cl::alias
ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
828 cl::aliasopt(ShowOutputDirectory
));
830 cl::opt
<uint32_t> TabSize(
831 "tab-size", cl::init(2),
833 "Set tab expansion size for html coverage reports (default = 2)"));
835 cl::opt
<std::string
> ProjectTitle(
836 "project-title", cl::Optional
,
837 cl::desc("Set project title for the coverage report"));
839 auto Err
= commandLineParser(argc
, argv
);
843 if (ViewOpts
.Format
== CoverageViewOptions::OutputFormat::Lcov
) {
844 error("Lcov format should be used with 'llvm-cov export'.");
848 ViewOpts
.ShowLineNumbers
= true;
849 ViewOpts
.ShowLineStats
= ShowLineExecutionCounts
.getNumOccurrences() != 0 ||
850 !ShowRegions
|| ShowBestLineRegionsCounts
;
851 ViewOpts
.ShowRegionMarkers
= ShowRegions
|| ShowBestLineRegionsCounts
;
852 ViewOpts
.ShowExpandedRegions
= ShowExpansions
;
853 ViewOpts
.ShowFunctionInstantiations
= ShowInstantiations
;
854 ViewOpts
.ShowOutputDirectory
= ShowOutputDirectory
;
855 ViewOpts
.TabSize
= TabSize
;
856 ViewOpts
.ProjectTitle
= ProjectTitle
;
858 if (ViewOpts
.hasOutputDirectory()) {
859 if (auto E
= sys::fs::create_directories(ViewOpts
.ShowOutputDirectory
)) {
860 error("Could not create output directory!", E
.message());
865 sys::fs::file_status Status
;
866 if (sys::fs::status(PGOFilename
, Status
)) {
867 error("profdata file error: can not get the file status. \n");
871 auto ModifiedTime
= Status
.getLastModificationTime();
872 std::string ModifiedTimeStr
= to_string(ModifiedTime
);
873 size_t found
= ModifiedTimeStr
.rfind(':');
874 ViewOpts
.CreatedTimeStr
= (found
!= std::string::npos
)
875 ? "Created: " + ModifiedTimeStr
.substr(0, found
)
876 : "Created: " + ModifiedTimeStr
;
878 auto Coverage
= load();
882 auto Printer
= CoveragePrinter::create(ViewOpts
);
884 if (SourceFiles
.empty())
885 // Get the source files from the function coverage mapping.
886 for (StringRef Filename
: Coverage
->getUniqueSourceFiles()) {
887 if (!IgnoreFilenameFilters
.matchesFilename(Filename
))
888 SourceFiles
.push_back(Filename
);
891 // Create an index out of the source files.
892 if (ViewOpts
.hasOutputDirectory()) {
893 if (Error E
= Printer
->createIndexFile(SourceFiles
, *Coverage
, Filters
)) {
894 error("Could not create index file!", toString(std::move(E
)));
899 if (!Filters
.empty()) {
900 // Build the map of filenames to functions.
901 std::map
<llvm::StringRef
, std::vector
<const FunctionRecord
*>>
903 for (const auto &SourceFile
: SourceFiles
)
904 for (const auto &Function
: Coverage
->getCoveredFunctions(SourceFile
))
905 if (Filters
.matches(*Coverage
.get(), Function
))
906 FilenameFunctionMap
[SourceFile
].push_back(&Function
);
908 // Only print filter matching functions for each file.
909 for (const auto &FileFunc
: FilenameFunctionMap
) {
910 StringRef File
= FileFunc
.first
;
911 const auto &Functions
= FileFunc
.second
;
913 auto OSOrErr
= Printer
->createViewFile(File
, /*InToplevel=*/false);
914 if (Error E
= OSOrErr
.takeError()) {
915 error("Could not create view file!", toString(std::move(E
)));
918 auto OS
= std::move(OSOrErr
.get());
920 bool ShowTitle
= ViewOpts
.hasOutputDirectory();
921 for (const auto *Function
: Functions
) {
922 auto FunctionView
= createFunctionView(*Function
, *Coverage
);
924 warning("Could not read coverage for '" + Function
->Name
+ "'.");
927 FunctionView
->print(*OS
.get(), /*WholeFile=*/false,
928 /*ShowSourceName=*/true, ShowTitle
);
932 Printer
->closeViewFile(std::move(OS
));
939 (SourceFiles
.size() != 1) || ViewOpts
.hasOutputDirectory() ||
940 (ViewOpts
.Format
== CoverageViewOptions::OutputFormat::HTML
);
942 auto NumThreads
= ViewOpts
.NumThreads
;
944 // If NumThreads is not specified, auto-detect a good default.
947 std::max(1U, std::min(llvm::heavyweight_hardware_concurrency(),
948 unsigned(SourceFiles
.size())));
950 if (!ViewOpts
.hasOutputDirectory() || NumThreads
== 1) {
951 for (const std::string
&SourceFile
: SourceFiles
)
952 writeSourceFileView(SourceFile
, Coverage
.get(), Printer
.get(),
955 // In -output-dir mode, it's safe to use multiple threads to print files.
956 ThreadPool
Pool(NumThreads
);
957 for (const std::string
&SourceFile
: SourceFiles
)
958 Pool
.async(&CodeCoverageTool::writeSourceFileView
, this, SourceFile
,
959 Coverage
.get(), Printer
.get(), ShowFilenames
);
966 int CodeCoverageTool::doReport(int argc
, const char **argv
,
967 CommandLineParserType commandLineParser
) {
968 cl::opt
<bool> ShowFunctionSummaries(
969 "show-functions", cl::Optional
, cl::init(false),
970 cl::desc("Show coverage summaries for each function"));
972 auto Err
= commandLineParser(argc
, argv
);
976 if (ViewOpts
.Format
== CoverageViewOptions::OutputFormat::HTML
) {
977 error("HTML output for summary reports is not yet supported.");
979 } else if (ViewOpts
.Format
== CoverageViewOptions::OutputFormat::Lcov
) {
980 error("Lcov format should be used with 'llvm-cov export'.");
984 auto Coverage
= load();
988 CoverageReport
Report(ViewOpts
, *Coverage
.get());
989 if (!ShowFunctionSummaries
) {
990 if (SourceFiles
.empty())
991 Report
.renderFileReports(llvm::outs(), IgnoreFilenameFilters
);
993 Report
.renderFileReports(llvm::outs(), SourceFiles
);
995 if (SourceFiles
.empty()) {
996 error("Source files must be specified when -show-functions=true is "
1001 Report
.renderFunctionReports(SourceFiles
, DC
, llvm::outs());
1006 int CodeCoverageTool::doExport(int argc
, const char **argv
,
1007 CommandLineParserType commandLineParser
) {
1009 cl::OptionCategory
ExportCategory("Exporting options");
1011 cl::opt
<bool> SkipExpansions("skip-expansions", cl::Optional
,
1012 cl::desc("Don't export expanded source regions"),
1013 cl::cat(ExportCategory
));
1015 cl::opt
<bool> SkipFunctions("skip-functions", cl::Optional
,
1016 cl::desc("Don't export per-function data"),
1017 cl::cat(ExportCategory
));
1019 auto Err
= commandLineParser(argc
, argv
);
1023 ViewOpts
.SkipExpansions
= SkipExpansions
;
1024 ViewOpts
.SkipFunctions
= SkipFunctions
;
1026 if (ViewOpts
.Format
!= CoverageViewOptions::OutputFormat::Text
&&
1027 ViewOpts
.Format
!= CoverageViewOptions::OutputFormat::Lcov
) {
1028 error("Coverage data can only be exported as textual JSON or an "
1033 auto Coverage
= load();
1035 error("Could not load coverage information");
1039 std::unique_ptr
<CoverageExporter
> Exporter
;
1041 switch (ViewOpts
.Format
) {
1042 case CoverageViewOptions::OutputFormat::Text
:
1043 Exporter
= llvm::make_unique
<CoverageExporterJson
>(*Coverage
.get(),
1046 case CoverageViewOptions::OutputFormat::HTML
:
1047 // Unreachable because we should have gracefully terminated with an error
1049 llvm_unreachable("Export in HTML is not supported!");
1050 case CoverageViewOptions::OutputFormat::Lcov
:
1051 Exporter
= llvm::make_unique
<CoverageExporterLcov
>(*Coverage
.get(),
1056 if (SourceFiles
.empty())
1057 Exporter
->renderRoot(IgnoreFilenameFilters
);
1059 Exporter
->renderRoot(SourceFiles
);
1064 int showMain(int argc
, const char *argv
[]) {
1065 CodeCoverageTool Tool
;
1066 return Tool
.run(CodeCoverageTool::Show
, argc
, argv
);
1069 int reportMain(int argc
, const char *argv
[]) {
1070 CodeCoverageTool Tool
;
1071 return Tool
.run(CodeCoverageTool::Report
, argc
, argv
);
1074 int exportMain(int argc
, const char *argv
[]) {
1075 CodeCoverageTool Tool
;
1076 return Tool
.run(CodeCoverageTool::Export
, argc
, argv
);