1 //===- CodeCoverage.cpp - Coverage tool based on profiling instrumentation-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // The 'CodeCoverageTool' class implements a command line tool to analyze and
11 // report coverage information using the profiling instrumentation and code
14 //===----------------------------------------------------------------------===//
16 #include "CoverageExporterJson.h"
17 #include "CoverageExporterLcov.h"
18 #include "CoverageFilters.h"
19 #include "CoverageReport.h"
20 #include "CoverageSummaryInfo.h"
21 #include "CoverageViewOptions.h"
22 #include "RenderingSupport.h"
23 #include "SourceCoverageView.h"
24 #include "llvm/ADT/SmallString.h"
25 #include "llvm/ADT/StringRef.h"
26 #include "llvm/ADT/Triple.h"
27 #include "llvm/ProfileData/Coverage/CoverageMapping.h"
28 #include "llvm/ProfileData/InstrProfReader.h"
29 #include "llvm/Support/CommandLine.h"
30 #include "llvm/Support/FileSystem.h"
31 #include "llvm/Support/Format.h"
32 #include "llvm/Support/MemoryBuffer.h"
33 #include "llvm/Support/Path.h"
34 #include "llvm/Support/Process.h"
35 #include "llvm/Support/Program.h"
36 #include "llvm/Support/ScopedPrinter.h"
37 #include "llvm/Support/ThreadPool.h"
38 #include "llvm/Support/Threading.h"
39 #include "llvm/Support/ToolOutputFile.h"
43 #include <system_error>
46 using namespace coverage
;
48 void exportCoverageDataToJson(const coverage::CoverageMapping
&CoverageMapping
,
49 const CoverageViewOptions
&Options
,
53 /// The implementation of the coverage tool.
54 class CodeCoverageTool
{
59 /// The report command.
61 /// The export command.
65 int run(Command Cmd
, int argc
, const char **argv
);
68 /// Print the error message to the error output stream.
69 void error(const Twine
&Message
, StringRef Whence
= "");
71 /// Print the warning message to the error output stream.
72 void warning(const Twine
&Message
, StringRef Whence
= "");
74 /// Convert \p Path into an absolute path and append it to the list
75 /// of collected paths.
76 void addCollectedPath(const std::string
&Path
);
78 /// If \p Path is a regular file, collect the path. If it's a
79 /// directory, recursively collect all of the paths within the directory.
80 void collectPaths(const std::string
&Path
);
82 /// Return a memory buffer for the given source file.
83 ErrorOr
<const MemoryBuffer
&> getSourceFile(StringRef SourceFile
);
85 /// Create source views for the expansions of the view.
86 void attachExpansionSubViews(SourceCoverageView
&View
,
87 ArrayRef
<ExpansionRecord
> Expansions
,
88 const CoverageMapping
&Coverage
);
90 /// Create the source view of a particular function.
91 std::unique_ptr
<SourceCoverageView
>
92 createFunctionView(const FunctionRecord
&Function
,
93 const CoverageMapping
&Coverage
);
95 /// Create the main source view of a particular source file.
96 std::unique_ptr
<SourceCoverageView
>
97 createSourceFileView(StringRef SourceFile
, const CoverageMapping
&Coverage
);
99 /// Load the coverage mapping data. Return nullptr if an error occurred.
100 std::unique_ptr
<CoverageMapping
> load();
102 /// Create a mapping from files in the Coverage data to local copies
103 /// (path-equivalence).
104 void remapPathNames(const CoverageMapping
&Coverage
);
106 /// Remove input source files which aren't mapped by \p Coverage.
107 void removeUnmappedInputs(const CoverageMapping
&Coverage
);
109 /// If a demangler is available, demangle all symbol names.
110 void demangleSymbols(const CoverageMapping
&Coverage
);
112 /// Write out a source file view to the filesystem.
113 void writeSourceFileView(StringRef SourceFile
, CoverageMapping
*Coverage
,
114 CoveragePrinter
*Printer
, bool ShowFilenames
);
116 typedef llvm::function_ref
<int(int, const char **)> CommandLineParserType
;
118 int doShow(int argc
, const char **argv
,
119 CommandLineParserType commandLineParser
);
121 int doReport(int argc
, const char **argv
,
122 CommandLineParserType commandLineParser
);
124 int doExport(int argc
, const char **argv
,
125 CommandLineParserType commandLineParser
);
127 std::vector
<StringRef
> ObjectFilenames
;
128 CoverageViewOptions ViewOpts
;
129 CoverageFiltersMatchAll Filters
;
130 CoverageFilters IgnoreFilenameFilters
;
132 /// The path to the indexed profile.
133 std::string PGOFilename
;
135 /// A list of input source files.
136 std::vector
<std::string
> SourceFiles
;
138 /// In -path-equivalence mode, this maps the absolute paths from the coverage
139 /// mapping data to the input source files.
140 StringMap
<std::string
> RemappedFilenames
;
142 /// The coverage data path to be remapped from, and the source path to be
143 /// remapped to, when using -path-equivalence.
144 Optional
<std::pair
<std::string
, std::string
>> PathRemapping
;
146 /// The architecture the coverage mapping data targets.
147 std::vector
<StringRef
> CoverageArches
;
149 /// A cache for demangled symbols.
152 /// A lock which guards printing to stderr.
155 /// A container for input source file buffers.
156 std::mutex LoadedSourceFilesLock
;
157 std::vector
<std::pair
<std::string
, std::unique_ptr
<MemoryBuffer
>>>
160 /// Whitelist from -name-whitelist to be used for filtering.
161 std::unique_ptr
<SpecialCaseList
> NameWhitelist
;
165 static std::string
getErrorString(const Twine
&Message
, StringRef Whence
,
167 std::string Str
= (Warning
? "warning" : "error");
170 Str
+= Whence
.str() + ": ";
171 Str
+= Message
.str() + "\n";
175 void CodeCoverageTool::error(const Twine
&Message
, StringRef Whence
) {
176 std::unique_lock
<std::mutex
> Guard
{ErrsLock
};
177 ViewOpts
.colored_ostream(errs(), raw_ostream::RED
)
178 << getErrorString(Message
, Whence
, false);
181 void CodeCoverageTool::warning(const Twine
&Message
, StringRef Whence
) {
182 std::unique_lock
<std::mutex
> Guard
{ErrsLock
};
183 ViewOpts
.colored_ostream(errs(), raw_ostream::RED
)
184 << getErrorString(Message
, Whence
, true);
187 void CodeCoverageTool::addCollectedPath(const std::string
&Path
) {
188 SmallString
<128> EffectivePath(Path
);
189 if (std::error_code EC
= sys::fs::make_absolute(EffectivePath
)) {
190 error(EC
.message(), Path
);
193 sys::path::remove_dots(EffectivePath
, /*remove_dot_dots=*/true);
194 if (!IgnoreFilenameFilters
.matchesFilename(EffectivePath
))
195 SourceFiles
.emplace_back(EffectivePath
.str());
198 void CodeCoverageTool::collectPaths(const std::string
&Path
) {
199 llvm::sys::fs::file_status Status
;
200 llvm::sys::fs::status(Path
, Status
);
201 if (!llvm::sys::fs::exists(Status
)) {
203 addCollectedPath(Path
);
205 warning("Source file doesn't exist, proceeded by ignoring it.", Path
);
209 if (llvm::sys::fs::is_regular_file(Status
)) {
210 addCollectedPath(Path
);
214 if (llvm::sys::fs::is_directory(Status
)) {
216 for (llvm::sys::fs::recursive_directory_iterator
F(Path
, EC
), E
;
217 F
!= E
; F
.increment(EC
)) {
219 auto Status
= F
->status();
221 warning(Status
.getError().message(), F
->path());
225 if (Status
->type() == llvm::sys::fs::file_type::regular_file
)
226 addCollectedPath(F
->path());
231 ErrorOr
<const MemoryBuffer
&>
232 CodeCoverageTool::getSourceFile(StringRef SourceFile
) {
233 // If we've remapped filenames, look up the real location for this file.
234 std::unique_lock
<std::mutex
> Guard
{LoadedSourceFilesLock
};
235 if (!RemappedFilenames
.empty()) {
236 auto Loc
= RemappedFilenames
.find(SourceFile
);
237 if (Loc
!= RemappedFilenames
.end())
238 SourceFile
= Loc
->second
;
240 for (const auto &Files
: LoadedSourceFiles
)
241 if (sys::fs::equivalent(SourceFile
, Files
.first
))
242 return *Files
.second
;
243 auto Buffer
= MemoryBuffer::getFile(SourceFile
);
244 if (auto EC
= Buffer
.getError()) {
245 error(EC
.message(), SourceFile
);
248 LoadedSourceFiles
.emplace_back(SourceFile
, std::move(Buffer
.get()));
249 return *LoadedSourceFiles
.back().second
;
252 void CodeCoverageTool::attachExpansionSubViews(
253 SourceCoverageView
&View
, ArrayRef
<ExpansionRecord
> Expansions
,
254 const CoverageMapping
&Coverage
) {
255 if (!ViewOpts
.ShowExpandedRegions
)
257 for (const auto &Expansion
: Expansions
) {
258 auto ExpansionCoverage
= Coverage
.getCoverageForExpansion(Expansion
);
259 if (ExpansionCoverage
.empty())
261 auto SourceBuffer
= getSourceFile(ExpansionCoverage
.getFilename());
265 auto SubViewExpansions
= ExpansionCoverage
.getExpansions();
267 SourceCoverageView::create(Expansion
.Function
.Name
, SourceBuffer
.get(),
268 ViewOpts
, std::move(ExpansionCoverage
));
269 attachExpansionSubViews(*SubView
, SubViewExpansions
, Coverage
);
270 View
.addExpansion(Expansion
.Region
, std::move(SubView
));
274 std::unique_ptr
<SourceCoverageView
>
275 CodeCoverageTool::createFunctionView(const FunctionRecord
&Function
,
276 const CoverageMapping
&Coverage
) {
277 auto FunctionCoverage
= Coverage
.getCoverageForFunction(Function
);
278 if (FunctionCoverage
.empty())
280 auto SourceBuffer
= getSourceFile(FunctionCoverage
.getFilename());
284 auto Expansions
= FunctionCoverage
.getExpansions();
285 auto View
= SourceCoverageView::create(DC
.demangle(Function
.Name
),
286 SourceBuffer
.get(), ViewOpts
,
287 std::move(FunctionCoverage
));
288 attachExpansionSubViews(*View
, Expansions
, Coverage
);
293 std::unique_ptr
<SourceCoverageView
>
294 CodeCoverageTool::createSourceFileView(StringRef SourceFile
,
295 const CoverageMapping
&Coverage
) {
296 auto SourceBuffer
= getSourceFile(SourceFile
);
299 auto FileCoverage
= Coverage
.getCoverageForFile(SourceFile
);
300 if (FileCoverage
.empty())
303 auto Expansions
= FileCoverage
.getExpansions();
304 auto View
= SourceCoverageView::create(SourceFile
, SourceBuffer
.get(),
305 ViewOpts
, std::move(FileCoverage
));
306 attachExpansionSubViews(*View
, Expansions
, Coverage
);
307 if (!ViewOpts
.ShowFunctionInstantiations
)
310 for (const auto &Group
: Coverage
.getInstantiationGroups(SourceFile
)) {
311 // Skip functions which have a single instantiation.
312 if (Group
.size() < 2)
315 for (const FunctionRecord
*Function
: Group
.getInstantiations()) {
316 std::unique_ptr
<SourceCoverageView
> SubView
{nullptr};
318 StringRef Funcname
= DC
.demangle(Function
->Name
);
320 if (Function
->ExecutionCount
> 0) {
321 auto SubViewCoverage
= Coverage
.getCoverageForFunction(*Function
);
322 auto SubViewExpansions
= SubViewCoverage
.getExpansions();
323 SubView
= SourceCoverageView::create(
324 Funcname
, SourceBuffer
.get(), ViewOpts
, std::move(SubViewCoverage
));
325 attachExpansionSubViews(*SubView
, SubViewExpansions
, Coverage
);
328 unsigned FileID
= Function
->CountedRegions
.front().FileID
;
330 for (const auto &CR
: Function
->CountedRegions
)
331 if (CR
.FileID
== FileID
)
332 Line
= std::max(CR
.LineEnd
, Line
);
333 View
->addInstantiation(Funcname
, Line
, std::move(SubView
));
339 static bool modifiedTimeGT(StringRef LHS
, StringRef RHS
) {
340 sys::fs::file_status Status
;
341 if (sys::fs::status(LHS
, Status
))
343 auto LHSTime
= Status
.getLastModificationTime();
344 if (sys::fs::status(RHS
, Status
))
346 auto RHSTime
= Status
.getLastModificationTime();
347 return LHSTime
> RHSTime
;
350 std::unique_ptr
<CoverageMapping
> CodeCoverageTool::load() {
351 for (StringRef ObjectFilename
: ObjectFilenames
)
352 if (modifiedTimeGT(ObjectFilename
, PGOFilename
))
353 warning("profile data may be out of date - object is newer",
356 CoverageMapping::load(ObjectFilenames
, PGOFilename
, CoverageArches
);
357 if (Error E
= CoverageOrErr
.takeError()) {
358 error("Failed to load coverage: " + toString(std::move(E
)),
359 join(ObjectFilenames
.begin(), ObjectFilenames
.end(), ", "));
362 auto Coverage
= std::move(CoverageOrErr
.get());
363 unsigned Mismatched
= Coverage
->getMismatchedCount();
365 warning(Twine(Mismatched
) + " functions have mismatched data");
367 if (ViewOpts
.Debug
) {
368 for (const auto &HashMismatch
: Coverage
->getHashMismatches())
369 errs() << "hash-mismatch: "
370 << "No profile record found for '" << HashMismatch
.first
<< "'"
371 << " with hash = 0x" << Twine::utohexstr(HashMismatch
.second
)
376 remapPathNames(*Coverage
);
378 if (!SourceFiles
.empty())
379 removeUnmappedInputs(*Coverage
);
381 demangleSymbols(*Coverage
);
386 void CodeCoverageTool::remapPathNames(const CoverageMapping
&Coverage
) {
390 // Convert remapping paths to native paths with trailing seperators.
391 auto nativeWithTrailing
= [](StringRef Path
) -> std::string
{
394 SmallString
<128> NativePath
;
395 sys::path::native(Path
, NativePath
);
396 if (!sys::path::is_separator(NativePath
.back()))
397 NativePath
+= sys::path::get_separator();
398 return NativePath
.c_str();
400 std::string RemapFrom
= nativeWithTrailing(PathRemapping
->first
);
401 std::string RemapTo
= nativeWithTrailing(PathRemapping
->second
);
403 // Create a mapping from coverage data file paths to local paths.
404 for (StringRef Filename
: Coverage
.getUniqueSourceFiles()) {
405 SmallString
<128> NativeFilename
;
406 sys::path::native(Filename
, NativeFilename
);
407 if (NativeFilename
.startswith(RemapFrom
)) {
408 RemappedFilenames
[Filename
] =
409 RemapTo
+ NativeFilename
.substr(RemapFrom
.size()).str();
413 // Convert input files from local paths to coverage data file paths.
414 StringMap
<std::string
> InvRemappedFilenames
;
415 for (const auto &RemappedFilename
: RemappedFilenames
)
416 InvRemappedFilenames
[RemappedFilename
.getValue()] = RemappedFilename
.getKey();
418 for (std::string
&Filename
: SourceFiles
) {
419 SmallString
<128> NativeFilename
;
420 sys::path::native(Filename
, NativeFilename
);
421 auto CovFileName
= InvRemappedFilenames
.find(NativeFilename
);
422 if (CovFileName
!= InvRemappedFilenames
.end())
423 Filename
= CovFileName
->second
;
427 void CodeCoverageTool::removeUnmappedInputs(const CoverageMapping
&Coverage
) {
428 std::vector
<StringRef
> CoveredFiles
= Coverage
.getUniqueSourceFiles();
430 auto UncoveredFilesIt
= SourceFiles
.end();
431 // The user may have specified source files which aren't in the coverage
432 // mapping. Filter these files away.
433 UncoveredFilesIt
= std::remove_if(
434 SourceFiles
.begin(), SourceFiles
.end(), [&](const std::string
&SF
) {
435 return !std::binary_search(CoveredFiles
.begin(), CoveredFiles
.end(),
439 SourceFiles
.erase(UncoveredFilesIt
, SourceFiles
.end());
442 void CodeCoverageTool::demangleSymbols(const CoverageMapping
&Coverage
) {
443 if (!ViewOpts
.hasDemangler())
446 // Pass function names to the demangler in a temporary file.
448 SmallString
<256> InputPath
;
450 sys::fs::createTemporaryFile("demangle-in", "list", InputFD
, InputPath
);
452 error(InputPath
, EC
.message());
455 ToolOutputFile InputTOF
{InputPath
, InputFD
};
457 unsigned NumSymbols
= 0;
458 for (const auto &Function
: Coverage
.getCoveredFunctions()) {
459 InputTOF
.os() << Function
.Name
<< '\n';
462 InputTOF
.os().close();
464 // Use another temporary file to store the demangler's output.
466 SmallString
<256> OutputPath
;
467 EC
= sys::fs::createTemporaryFile("demangle-out", "list", OutputFD
,
470 error(OutputPath
, EC
.message());
473 ToolOutputFile OutputTOF
{OutputPath
, OutputFD
};
474 OutputTOF
.os().close();
476 // Invoke the demangler.
477 std::vector
<StringRef
> ArgsV
;
478 for (StringRef Arg
: ViewOpts
.DemanglerOpts
)
479 ArgsV
.push_back(Arg
);
480 Optional
<StringRef
> Redirects
[] = {InputPath
.str(), OutputPath
.str(), {""}};
482 int RC
= sys::ExecuteAndWait(ViewOpts
.DemanglerOpts
[0], ArgsV
,
483 /*env=*/None
, Redirects
, /*secondsToWait=*/0,
484 /*memoryLimit=*/0, &ErrMsg
);
486 error(ErrMsg
, ViewOpts
.DemanglerOpts
[0]);
490 // Parse the demangler's output.
491 auto BufOrError
= MemoryBuffer::getFile(OutputPath
);
493 error(OutputPath
, BufOrError
.getError().message());
497 std::unique_ptr
<MemoryBuffer
> DemanglerBuf
= std::move(*BufOrError
);
499 SmallVector
<StringRef
, 8> Symbols
;
500 StringRef DemanglerData
= DemanglerBuf
->getBuffer();
501 DemanglerData
.split(Symbols
, '\n', /*MaxSplit=*/NumSymbols
,
502 /*KeepEmpty=*/false);
503 if (Symbols
.size() != NumSymbols
) {
504 error("Demangler did not provide expected number of symbols");
508 // Cache the demangled names.
510 for (const auto &Function
: Coverage
.getCoveredFunctions())
511 // On Windows, lines in the demangler's output file end with "\r\n".
512 // Splitting by '\n' keeps '\r's, so cut them now.
513 DC
.DemangledNames
[Function
.Name
] = Symbols
[I
++].rtrim();
516 void CodeCoverageTool::writeSourceFileView(StringRef SourceFile
,
517 CoverageMapping
*Coverage
,
518 CoveragePrinter
*Printer
,
519 bool ShowFilenames
) {
520 auto View
= createSourceFileView(SourceFile
, *Coverage
);
522 warning("The file '" + SourceFile
+ "' isn't covered.");
526 auto OSOrErr
= Printer
->createViewFile(SourceFile
, /*InToplevel=*/false);
527 if (Error E
= OSOrErr
.takeError()) {
528 error("Could not create view file!", toString(std::move(E
)));
531 auto OS
= std::move(OSOrErr
.get());
533 View
->print(*OS
.get(), /*Wholefile=*/true,
534 /*ShowSourceName=*/ShowFilenames
,
535 /*ShowTitle=*/ViewOpts
.hasOutputDirectory());
536 Printer
->closeViewFile(std::move(OS
));
539 int CodeCoverageTool::run(Command Cmd
, int argc
, const char **argv
) {
540 cl::opt
<std::string
> CovFilename(
541 cl::Positional
, cl::desc("Covered executable or object file."));
543 cl::list
<std::string
> CovFilenames(
544 "object", cl::desc("Coverage executable or object file"), cl::ZeroOrMore
,
547 cl::list
<std::string
> InputSourceFiles(
548 cl::Positional
, cl::desc("<Source files>"), cl::ZeroOrMore
);
550 cl::opt
<bool> DebugDumpCollectedPaths(
551 "dump-collected-paths", cl::Optional
, cl::Hidden
,
552 cl::desc("Show the collected paths to source files"));
554 cl::opt
<std::string
, true> PGOFilename(
555 "instr-profile", cl::Required
, cl::location(this->PGOFilename
),
557 "File with the profile data obtained after an instrumented run"));
559 cl::list
<std::string
> Arches(
560 "arch", cl::desc("architectures of the coverage mapping binaries"));
562 cl::opt
<bool> DebugDump("dump", cl::Optional
,
563 cl::desc("Show internal debug dump"));
565 cl::opt
<CoverageViewOptions::OutputFormat
> Format(
566 "format", cl::desc("Output format for line-based coverage reports"),
567 cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text
, "text",
569 clEnumValN(CoverageViewOptions::OutputFormat::HTML
, "html",
571 clEnumValN(CoverageViewOptions::OutputFormat::Lcov
, "lcov",
572 "lcov tracefile output")),
573 cl::init(CoverageViewOptions::OutputFormat::Text
));
575 cl::opt
<std::string
> PathRemap(
576 "path-equivalence", cl::Optional
,
577 cl::desc("<from>,<to> Map coverage data paths to local source file "
580 cl::OptionCategory
FilteringCategory("Function filtering options");
582 cl::list
<std::string
> NameFilters(
583 "name", cl::Optional
,
584 cl::desc("Show code coverage only for functions with the given name"),
585 cl::ZeroOrMore
, cl::cat(FilteringCategory
));
587 cl::list
<std::string
> NameFilterFiles(
588 "name-whitelist", cl::Optional
,
589 cl::desc("Show code coverage only for functions listed in the given "
591 cl::ZeroOrMore
, cl::cat(FilteringCategory
));
593 cl::list
<std::string
> NameRegexFilters(
594 "name-regex", cl::Optional
,
595 cl::desc("Show code coverage only for functions that match the given "
596 "regular expression"),
597 cl::ZeroOrMore
, cl::cat(FilteringCategory
));
599 cl::list
<std::string
> IgnoreFilenameRegexFilters(
600 "ignore-filename-regex", cl::Optional
,
601 cl::desc("Skip source code files with file paths that match the given "
602 "regular expression"),
603 cl::ZeroOrMore
, cl::cat(FilteringCategory
));
605 cl::opt
<double> RegionCoverageLtFilter(
606 "region-coverage-lt", cl::Optional
,
607 cl::desc("Show code coverage only for functions with region coverage "
608 "less than the given threshold"),
609 cl::cat(FilteringCategory
));
611 cl::opt
<double> RegionCoverageGtFilter(
612 "region-coverage-gt", cl::Optional
,
613 cl::desc("Show code coverage only for functions with region coverage "
614 "greater than the given threshold"),
615 cl::cat(FilteringCategory
));
617 cl::opt
<double> LineCoverageLtFilter(
618 "line-coverage-lt", cl::Optional
,
619 cl::desc("Show code coverage only for functions with line coverage less "
620 "than the given threshold"),
621 cl::cat(FilteringCategory
));
623 cl::opt
<double> LineCoverageGtFilter(
624 "line-coverage-gt", cl::Optional
,
625 cl::desc("Show code coverage only for functions with line coverage "
626 "greater than the given threshold"),
627 cl::cat(FilteringCategory
));
629 cl::opt
<cl::boolOrDefault
> UseColor(
630 "use-color", cl::desc("Emit colored output (default=autodetect)"),
631 cl::init(cl::BOU_UNSET
));
633 cl::list
<std::string
> DemanglerOpts(
634 "Xdemangler", cl::desc("<demangler-path>|<demangler-option>"));
636 cl::opt
<bool> RegionSummary(
637 "show-region-summary", cl::Optional
,
638 cl::desc("Show region statistics in summary table"),
641 cl::opt
<bool> InstantiationSummary(
642 "show-instantiation-summary", cl::Optional
,
643 cl::desc("Show instantiation statistics in summary table"));
645 cl::opt
<bool> SummaryOnly(
646 "summary-only", cl::Optional
,
647 cl::desc("Export only summary information for each source file"));
649 cl::opt
<unsigned> NumThreads(
650 "num-threads", cl::init(0),
651 cl::desc("Number of merge threads to use (default: autodetect)"));
652 cl::alias
NumThreadsA("j", cl::desc("Alias for --num-threads"),
653 cl::aliasopt(NumThreads
));
655 auto commandLineParser
= [&, this](int argc
, const char **argv
) -> int {
656 cl::ParseCommandLineOptions(argc
, argv
, "LLVM code coverage tool\n");
657 ViewOpts
.Debug
= DebugDump
;
659 if (!CovFilename
.empty())
660 ObjectFilenames
.emplace_back(CovFilename
);
661 for (const std::string
&Filename
: CovFilenames
)
662 ObjectFilenames
.emplace_back(Filename
);
663 if (ObjectFilenames
.empty()) {
664 errs() << "No filenames specified!\n";
668 ViewOpts
.Format
= Format
;
669 switch (ViewOpts
.Format
) {
670 case CoverageViewOptions::OutputFormat::Text
:
671 ViewOpts
.Colors
= UseColor
== cl::BOU_UNSET
672 ? sys::Process::StandardOutHasColors()
673 : UseColor
== cl::BOU_TRUE
;
675 case CoverageViewOptions::OutputFormat::HTML
:
676 if (UseColor
== cl::BOU_FALSE
)
677 errs() << "Color output cannot be disabled when generating html.\n";
678 ViewOpts
.Colors
= true;
680 case CoverageViewOptions::OutputFormat::Lcov
:
681 if (UseColor
== cl::BOU_TRUE
)
682 errs() << "Color output cannot be enabled when generating lcov.\n";
683 ViewOpts
.Colors
= false;
687 // If path-equivalence was given and is a comma seperated pair then set
689 auto EquivPair
= StringRef(PathRemap
).split(',');
690 if (!(EquivPair
.first
.empty() && EquivPair
.second
.empty()))
691 PathRemapping
= EquivPair
;
693 // If a demangler is supplied, check if it exists and register it.
694 if (!DemanglerOpts
.empty()) {
695 auto DemanglerPathOrErr
= sys::findProgramByName(DemanglerOpts
[0]);
696 if (!DemanglerPathOrErr
) {
697 error("Could not find the demangler!",
698 DemanglerPathOrErr
.getError().message());
701 DemanglerOpts
[0] = *DemanglerPathOrErr
;
702 ViewOpts
.DemanglerOpts
.swap(DemanglerOpts
);
705 // Read in -name-whitelist files.
706 if (!NameFilterFiles
.empty()) {
707 std::string SpecialCaseListErr
;
709 SpecialCaseList::create(NameFilterFiles
, SpecialCaseListErr
);
711 error(SpecialCaseListErr
);
714 // Create the function filters
715 if (!NameFilters
.empty() || NameWhitelist
|| !NameRegexFilters
.empty()) {
716 auto NameFilterer
= llvm::make_unique
<CoverageFilters
>();
717 for (const auto &Name
: NameFilters
)
718 NameFilterer
->push_back(llvm::make_unique
<NameCoverageFilter
>(Name
));
720 NameFilterer
->push_back(
721 llvm::make_unique
<NameWhitelistCoverageFilter
>(*NameWhitelist
));
722 for (const auto &Regex
: NameRegexFilters
)
723 NameFilterer
->push_back(
724 llvm::make_unique
<NameRegexCoverageFilter
>(Regex
));
725 Filters
.push_back(std::move(NameFilterer
));
728 if (RegionCoverageLtFilter
.getNumOccurrences() ||
729 RegionCoverageGtFilter
.getNumOccurrences() ||
730 LineCoverageLtFilter
.getNumOccurrences() ||
731 LineCoverageGtFilter
.getNumOccurrences()) {
732 auto StatFilterer
= llvm::make_unique
<CoverageFilters
>();
733 if (RegionCoverageLtFilter
.getNumOccurrences())
734 StatFilterer
->push_back(llvm::make_unique
<RegionCoverageFilter
>(
735 RegionCoverageFilter::LessThan
, RegionCoverageLtFilter
));
736 if (RegionCoverageGtFilter
.getNumOccurrences())
737 StatFilterer
->push_back(llvm::make_unique
<RegionCoverageFilter
>(
738 RegionCoverageFilter::GreaterThan
, RegionCoverageGtFilter
));
739 if (LineCoverageLtFilter
.getNumOccurrences())
740 StatFilterer
->push_back(llvm::make_unique
<LineCoverageFilter
>(
741 LineCoverageFilter::LessThan
, LineCoverageLtFilter
));
742 if (LineCoverageGtFilter
.getNumOccurrences())
743 StatFilterer
->push_back(llvm::make_unique
<LineCoverageFilter
>(
744 RegionCoverageFilter::GreaterThan
, LineCoverageGtFilter
));
745 Filters
.push_back(std::move(StatFilterer
));
748 // Create the ignore filename filters.
749 for (const auto &RE
: IgnoreFilenameRegexFilters
)
750 IgnoreFilenameFilters
.push_back(
751 llvm::make_unique
<NameRegexCoverageFilter
>(RE
));
753 if (!Arches
.empty()) {
754 for (const std::string
&Arch
: Arches
) {
755 if (Triple(Arch
).getArch() == llvm::Triple::ArchType::UnknownArch
) {
756 error("Unknown architecture: " + Arch
);
759 CoverageArches
.emplace_back(Arch
);
761 if (CoverageArches
.size() != ObjectFilenames
.size()) {
762 error("Number of architectures doesn't match the number of objects");
767 // IgnoreFilenameFilters are applied even when InputSourceFiles specified.
768 for (const std::string
&File
: InputSourceFiles
)
771 if (DebugDumpCollectedPaths
) {
772 for (const std::string
&SF
: SourceFiles
)
773 outs() << SF
<< '\n';
777 ViewOpts
.ShowRegionSummary
= RegionSummary
;
778 ViewOpts
.ShowInstantiationSummary
= InstantiationSummary
;
779 ViewOpts
.ExportSummaryOnly
= SummaryOnly
;
780 ViewOpts
.NumThreads
= NumThreads
;
787 return doShow(argc
, argv
, commandLineParser
);
789 return doReport(argc
, argv
, commandLineParser
);
791 return doExport(argc
, argv
, commandLineParser
);
796 int CodeCoverageTool::doShow(int argc
, const char **argv
,
797 CommandLineParserType commandLineParser
) {
799 cl::OptionCategory
ViewCategory("Viewing options");
801 cl::opt
<bool> ShowLineExecutionCounts(
802 "show-line-counts", cl::Optional
,
803 cl::desc("Show the execution counts for each line"), cl::init(true),
804 cl::cat(ViewCategory
));
806 cl::opt
<bool> ShowRegions(
807 "show-regions", cl::Optional
,
808 cl::desc("Show the execution counts for each region"),
809 cl::cat(ViewCategory
));
811 cl::opt
<bool> ShowBestLineRegionsCounts(
812 "show-line-counts-or-regions", cl::Optional
,
813 cl::desc("Show the execution counts for each line, or the execution "
814 "counts for each region on lines that have multiple regions"),
815 cl::cat(ViewCategory
));
817 cl::opt
<bool> ShowExpansions("show-expansions", cl::Optional
,
818 cl::desc("Show expanded source regions"),
819 cl::cat(ViewCategory
));
821 cl::opt
<bool> ShowInstantiations("show-instantiations", cl::Optional
,
822 cl::desc("Show function instantiations"),
823 cl::init(true), cl::cat(ViewCategory
));
825 cl::opt
<std::string
> ShowOutputDirectory(
826 "output-dir", cl::init(""),
827 cl::desc("Directory in which coverage information is written out"));
828 cl::alias
ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
829 cl::aliasopt(ShowOutputDirectory
));
831 cl::opt
<uint32_t> TabSize(
832 "tab-size", cl::init(2),
834 "Set tab expansion size for html coverage reports (default = 2)"));
836 cl::opt
<std::string
> ProjectTitle(
837 "project-title", cl::Optional
,
838 cl::desc("Set project title for the coverage report"));
840 auto Err
= commandLineParser(argc
, argv
);
844 if (ViewOpts
.Format
== CoverageViewOptions::OutputFormat::Lcov
) {
845 error("Lcov format should be used with 'llvm-cov export'.");
849 ViewOpts
.ShowLineNumbers
= true;
850 ViewOpts
.ShowLineStats
= ShowLineExecutionCounts
.getNumOccurrences() != 0 ||
851 !ShowRegions
|| ShowBestLineRegionsCounts
;
852 ViewOpts
.ShowRegionMarkers
= ShowRegions
|| ShowBestLineRegionsCounts
;
853 ViewOpts
.ShowExpandedRegions
= ShowExpansions
;
854 ViewOpts
.ShowFunctionInstantiations
= ShowInstantiations
;
855 ViewOpts
.ShowOutputDirectory
= ShowOutputDirectory
;
856 ViewOpts
.TabSize
= TabSize
;
857 ViewOpts
.ProjectTitle
= ProjectTitle
;
859 if (ViewOpts
.hasOutputDirectory()) {
860 if (auto E
= sys::fs::create_directories(ViewOpts
.ShowOutputDirectory
)) {
861 error("Could not create output directory!", E
.message());
866 sys::fs::file_status Status
;
867 if (sys::fs::status(PGOFilename
, Status
)) {
868 error("profdata file error: can not get the file status. \n");
872 auto ModifiedTime
= Status
.getLastModificationTime();
873 std::string ModifiedTimeStr
= to_string(ModifiedTime
);
874 size_t found
= ModifiedTimeStr
.rfind(':');
875 ViewOpts
.CreatedTimeStr
= (found
!= std::string::npos
)
876 ? "Created: " + ModifiedTimeStr
.substr(0, found
)
877 : "Created: " + ModifiedTimeStr
;
879 auto Coverage
= load();
883 auto Printer
= CoveragePrinter::create(ViewOpts
);
885 if (SourceFiles
.empty())
886 // Get the source files from the function coverage mapping.
887 for (StringRef Filename
: Coverage
->getUniqueSourceFiles()) {
888 if (!IgnoreFilenameFilters
.matchesFilename(Filename
))
889 SourceFiles
.push_back(Filename
);
892 // Create an index out of the source files.
893 if (ViewOpts
.hasOutputDirectory()) {
894 if (Error E
= Printer
->createIndexFile(SourceFiles
, *Coverage
, Filters
)) {
895 error("Could not create index file!", toString(std::move(E
)));
900 if (!Filters
.empty()) {
901 // Build the map of filenames to functions.
902 std::map
<llvm::StringRef
, std::vector
<const FunctionRecord
*>>
904 for (const auto &SourceFile
: SourceFiles
)
905 for (const auto &Function
: Coverage
->getCoveredFunctions(SourceFile
))
906 if (Filters
.matches(*Coverage
.get(), Function
))
907 FilenameFunctionMap
[SourceFile
].push_back(&Function
);
909 // Only print filter matching functions for each file.
910 for (const auto &FileFunc
: FilenameFunctionMap
) {
911 StringRef File
= FileFunc
.first
;
912 const auto &Functions
= FileFunc
.second
;
914 auto OSOrErr
= Printer
->createViewFile(File
, /*InToplevel=*/false);
915 if (Error E
= OSOrErr
.takeError()) {
916 error("Could not create view file!", toString(std::move(E
)));
919 auto OS
= std::move(OSOrErr
.get());
921 bool ShowTitle
= ViewOpts
.hasOutputDirectory();
922 for (const auto *Function
: Functions
) {
923 auto FunctionView
= createFunctionView(*Function
, *Coverage
);
925 warning("Could not read coverage for '" + Function
->Name
+ "'.");
928 FunctionView
->print(*OS
.get(), /*WholeFile=*/false,
929 /*ShowSourceName=*/true, ShowTitle
);
933 Printer
->closeViewFile(std::move(OS
));
940 (SourceFiles
.size() != 1) || ViewOpts
.hasOutputDirectory() ||
941 (ViewOpts
.Format
== CoverageViewOptions::OutputFormat::HTML
);
943 auto NumThreads
= ViewOpts
.NumThreads
;
945 // If NumThreads is not specified, auto-detect a good default.
948 std::max(1U, std::min(llvm::heavyweight_hardware_concurrency(),
949 unsigned(SourceFiles
.size())));
951 if (!ViewOpts
.hasOutputDirectory() || NumThreads
== 1) {
952 for (const std::string
&SourceFile
: SourceFiles
)
953 writeSourceFileView(SourceFile
, Coverage
.get(), Printer
.get(),
956 // In -output-dir mode, it's safe to use multiple threads to print files.
957 ThreadPool
Pool(NumThreads
);
958 for (const std::string
&SourceFile
: SourceFiles
)
959 Pool
.async(&CodeCoverageTool::writeSourceFileView
, this, SourceFile
,
960 Coverage
.get(), Printer
.get(), ShowFilenames
);
967 int CodeCoverageTool::doReport(int argc
, const char **argv
,
968 CommandLineParserType commandLineParser
) {
969 cl::opt
<bool> ShowFunctionSummaries(
970 "show-functions", cl::Optional
, cl::init(false),
971 cl::desc("Show coverage summaries for each function"));
973 auto Err
= commandLineParser(argc
, argv
);
977 if (ViewOpts
.Format
== CoverageViewOptions::OutputFormat::HTML
) {
978 error("HTML output for summary reports is not yet supported.");
980 } else if (ViewOpts
.Format
== CoverageViewOptions::OutputFormat::Lcov
) {
981 error("Lcov format should be used with 'llvm-cov export'.");
985 auto Coverage
= load();
989 CoverageReport
Report(ViewOpts
, *Coverage
.get());
990 if (!ShowFunctionSummaries
) {
991 if (SourceFiles
.empty())
992 Report
.renderFileReports(llvm::outs(), IgnoreFilenameFilters
);
994 Report
.renderFileReports(llvm::outs(), SourceFiles
);
996 if (SourceFiles
.empty()) {
997 error("Source files must be specified when -show-functions=true is "
1002 Report
.renderFunctionReports(SourceFiles
, DC
, llvm::outs());
1007 int CodeCoverageTool::doExport(int argc
, const char **argv
,
1008 CommandLineParserType commandLineParser
) {
1010 auto Err
= commandLineParser(argc
, argv
);
1014 if (ViewOpts
.Format
!= CoverageViewOptions::OutputFormat::Text
&&
1015 ViewOpts
.Format
!= CoverageViewOptions::OutputFormat::Lcov
) {
1016 error("Coverage data can only be exported as textual JSON or an "
1021 auto Coverage
= load();
1023 error("Could not load coverage information");
1027 std::unique_ptr
<CoverageExporter
> Exporter
;
1029 switch (ViewOpts
.Format
) {
1030 case CoverageViewOptions::OutputFormat::Text
:
1031 Exporter
= llvm::make_unique
<CoverageExporterJson
>(*Coverage
.get(),
1034 case CoverageViewOptions::OutputFormat::HTML
:
1035 // Unreachable because we should have gracefully terminated with an error
1037 llvm_unreachable("Export in HTML is not supported!");
1038 case CoverageViewOptions::OutputFormat::Lcov
:
1039 Exporter
= llvm::make_unique
<CoverageExporterLcov
>(*Coverage
.get(),
1044 if (SourceFiles
.empty())
1045 Exporter
->renderRoot(IgnoreFilenameFilters
);
1047 Exporter
->renderRoot(SourceFiles
);
1052 int showMain(int argc
, const char *argv
[]) {
1053 CodeCoverageTool Tool
;
1054 return Tool
.run(CodeCoverageTool::Show
, argc
, argv
);
1057 int reportMain(int argc
, const char *argv
[]) {
1058 CodeCoverageTool Tool
;
1059 return Tool
.run(CodeCoverageTool::Report
, argc
, argv
);
1062 int exportMain(int argc
, const char *argv
[]) {
1063 CodeCoverageTool Tool
;
1064 return Tool
.run(CodeCoverageTool::Export
, argc
, argv
);