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 "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
)) {
219 warning(EC
.message(), F
->path());
223 if (llvm::sys::fs::is_regular_file(F
->path()))
224 addCollectedPath(F
->path());
229 ErrorOr
<const MemoryBuffer
&>
230 CodeCoverageTool::getSourceFile(StringRef SourceFile
) {
231 // If we've remapped filenames, look up the real location for this file.
232 std::unique_lock
<std::mutex
> Guard
{LoadedSourceFilesLock
};
233 if (!RemappedFilenames
.empty()) {
234 auto Loc
= RemappedFilenames
.find(SourceFile
);
235 if (Loc
!= RemappedFilenames
.end())
236 SourceFile
= Loc
->second
;
238 for (const auto &Files
: LoadedSourceFiles
)
239 if (sys::fs::equivalent(SourceFile
, Files
.first
))
240 return *Files
.second
;
241 auto Buffer
= MemoryBuffer::getFile(SourceFile
);
242 if (auto EC
= Buffer
.getError()) {
243 error(EC
.message(), SourceFile
);
246 LoadedSourceFiles
.emplace_back(SourceFile
, std::move(Buffer
.get()));
247 return *LoadedSourceFiles
.back().second
;
250 void CodeCoverageTool::attachExpansionSubViews(
251 SourceCoverageView
&View
, ArrayRef
<ExpansionRecord
> Expansions
,
252 const CoverageMapping
&Coverage
) {
253 if (!ViewOpts
.ShowExpandedRegions
)
255 for (const auto &Expansion
: Expansions
) {
256 auto ExpansionCoverage
= Coverage
.getCoverageForExpansion(Expansion
);
257 if (ExpansionCoverage
.empty())
259 auto SourceBuffer
= getSourceFile(ExpansionCoverage
.getFilename());
263 auto SubViewExpansions
= ExpansionCoverage
.getExpansions();
265 SourceCoverageView::create(Expansion
.Function
.Name
, SourceBuffer
.get(),
266 ViewOpts
, std::move(ExpansionCoverage
));
267 attachExpansionSubViews(*SubView
, SubViewExpansions
, Coverage
);
268 View
.addExpansion(Expansion
.Region
, std::move(SubView
));
272 std::unique_ptr
<SourceCoverageView
>
273 CodeCoverageTool::createFunctionView(const FunctionRecord
&Function
,
274 const CoverageMapping
&Coverage
) {
275 auto FunctionCoverage
= Coverage
.getCoverageForFunction(Function
);
276 if (FunctionCoverage
.empty())
278 auto SourceBuffer
= getSourceFile(FunctionCoverage
.getFilename());
282 auto Expansions
= FunctionCoverage
.getExpansions();
283 auto View
= SourceCoverageView::create(DC
.demangle(Function
.Name
),
284 SourceBuffer
.get(), ViewOpts
,
285 std::move(FunctionCoverage
));
286 attachExpansionSubViews(*View
, Expansions
, Coverage
);
291 std::unique_ptr
<SourceCoverageView
>
292 CodeCoverageTool::createSourceFileView(StringRef SourceFile
,
293 const CoverageMapping
&Coverage
) {
294 auto SourceBuffer
= getSourceFile(SourceFile
);
297 auto FileCoverage
= Coverage
.getCoverageForFile(SourceFile
);
298 if (FileCoverage
.empty())
301 auto Expansions
= FileCoverage
.getExpansions();
302 auto View
= SourceCoverageView::create(SourceFile
, SourceBuffer
.get(),
303 ViewOpts
, std::move(FileCoverage
));
304 attachExpansionSubViews(*View
, Expansions
, Coverage
);
305 if (!ViewOpts
.ShowFunctionInstantiations
)
308 for (const auto &Group
: Coverage
.getInstantiationGroups(SourceFile
)) {
309 // Skip functions which have a single instantiation.
310 if (Group
.size() < 2)
313 for (const FunctionRecord
*Function
: Group
.getInstantiations()) {
314 std::unique_ptr
<SourceCoverageView
> SubView
{nullptr};
316 StringRef Funcname
= DC
.demangle(Function
->Name
);
318 if (Function
->ExecutionCount
> 0) {
319 auto SubViewCoverage
= Coverage
.getCoverageForFunction(*Function
);
320 auto SubViewExpansions
= SubViewCoverage
.getExpansions();
321 SubView
= SourceCoverageView::create(
322 Funcname
, SourceBuffer
.get(), ViewOpts
, std::move(SubViewCoverage
));
323 attachExpansionSubViews(*SubView
, SubViewExpansions
, Coverage
);
326 unsigned FileID
= Function
->CountedRegions
.front().FileID
;
328 for (const auto &CR
: Function
->CountedRegions
)
329 if (CR
.FileID
== FileID
)
330 Line
= std::max(CR
.LineEnd
, Line
);
331 View
->addInstantiation(Funcname
, Line
, std::move(SubView
));
337 static bool modifiedTimeGT(StringRef LHS
, StringRef RHS
) {
338 sys::fs::file_status Status
;
339 if (sys::fs::status(LHS
, Status
))
341 auto LHSTime
= Status
.getLastModificationTime();
342 if (sys::fs::status(RHS
, Status
))
344 auto RHSTime
= Status
.getLastModificationTime();
345 return LHSTime
> RHSTime
;
348 std::unique_ptr
<CoverageMapping
> CodeCoverageTool::load() {
349 for (StringRef ObjectFilename
: ObjectFilenames
)
350 if (modifiedTimeGT(ObjectFilename
, PGOFilename
))
351 warning("profile data may be out of date - object is newer",
354 CoverageMapping::load(ObjectFilenames
, PGOFilename
, CoverageArches
);
355 if (Error E
= CoverageOrErr
.takeError()) {
356 error("Failed to load coverage: " + toString(std::move(E
)),
357 join(ObjectFilenames
.begin(), ObjectFilenames
.end(), ", "));
360 auto Coverage
= std::move(CoverageOrErr
.get());
361 unsigned Mismatched
= Coverage
->getMismatchedCount();
363 warning(Twine(Mismatched
) + " functions have mismatched data");
365 if (ViewOpts
.Debug
) {
366 for (const auto &HashMismatch
: Coverage
->getHashMismatches())
367 errs() << "hash-mismatch: "
368 << "No profile record found for '" << HashMismatch
.first
<< "'"
369 << " with hash = 0x" << Twine::utohexstr(HashMismatch
.second
)
372 for (const auto &CounterMismatch
: Coverage
->getCounterMismatches())
373 errs() << "counter-mismatch: "
374 << "Coverage mapping for " << CounterMismatch
.first
375 << " only has " << CounterMismatch
.second
376 << " valid counter expressions\n";
380 remapPathNames(*Coverage
);
382 if (!SourceFiles
.empty())
383 removeUnmappedInputs(*Coverage
);
385 demangleSymbols(*Coverage
);
390 void CodeCoverageTool::remapPathNames(const CoverageMapping
&Coverage
) {
394 // Convert remapping paths to native paths with trailing seperators.
395 auto nativeWithTrailing
= [](StringRef Path
) -> std::string
{
398 SmallString
<128> NativePath
;
399 sys::path::native(Path
, NativePath
);
400 if (!sys::path::is_separator(NativePath
.back()))
401 NativePath
+= sys::path::get_separator();
402 return NativePath
.c_str();
404 std::string RemapFrom
= nativeWithTrailing(PathRemapping
->first
);
405 std::string RemapTo
= nativeWithTrailing(PathRemapping
->second
);
407 // Create a mapping from coverage data file paths to local paths.
408 for (StringRef Filename
: Coverage
.getUniqueSourceFiles()) {
409 SmallString
<128> NativeFilename
;
410 sys::path::native(Filename
, NativeFilename
);
411 if (NativeFilename
.startswith(RemapFrom
)) {
412 RemappedFilenames
[Filename
] =
413 RemapTo
+ NativeFilename
.substr(RemapFrom
.size()).str();
417 // Convert input files from local paths to coverage data file paths.
418 StringMap
<std::string
> InvRemappedFilenames
;
419 for (const auto &RemappedFilename
: RemappedFilenames
)
420 InvRemappedFilenames
[RemappedFilename
.getValue()] = RemappedFilename
.getKey();
422 for (std::string
&Filename
: SourceFiles
) {
423 SmallString
<128> NativeFilename
;
424 sys::path::native(Filename
, NativeFilename
);
425 auto CovFileName
= InvRemappedFilenames
.find(NativeFilename
);
426 if (CovFileName
!= InvRemappedFilenames
.end())
427 Filename
= CovFileName
->second
;
431 void CodeCoverageTool::removeUnmappedInputs(const CoverageMapping
&Coverage
) {
432 std::vector
<StringRef
> CoveredFiles
= Coverage
.getUniqueSourceFiles();
434 auto UncoveredFilesIt
= SourceFiles
.end();
435 // The user may have specified source files which aren't in the coverage
436 // mapping. Filter these files away.
437 UncoveredFilesIt
= std::remove_if(
438 SourceFiles
.begin(), SourceFiles
.end(), [&](const std::string
&SF
) {
439 return !std::binary_search(CoveredFiles
.begin(), CoveredFiles
.end(),
443 SourceFiles
.erase(UncoveredFilesIt
, SourceFiles
.end());
446 void CodeCoverageTool::demangleSymbols(const CoverageMapping
&Coverage
) {
447 if (!ViewOpts
.hasDemangler())
450 // Pass function names to the demangler in a temporary file.
452 SmallString
<256> InputPath
;
454 sys::fs::createTemporaryFile("demangle-in", "list", InputFD
, InputPath
);
456 error(InputPath
, EC
.message());
459 ToolOutputFile InputTOF
{InputPath
, InputFD
};
461 unsigned NumSymbols
= 0;
462 for (const auto &Function
: Coverage
.getCoveredFunctions()) {
463 InputTOF
.os() << Function
.Name
<< '\n';
466 InputTOF
.os().close();
468 // Use another temporary file to store the demangler's output.
470 SmallString
<256> OutputPath
;
471 EC
= sys::fs::createTemporaryFile("demangle-out", "list", OutputFD
,
474 error(OutputPath
, EC
.message());
477 ToolOutputFile OutputTOF
{OutputPath
, OutputFD
};
478 OutputTOF
.os().close();
480 // Invoke the demangler.
481 std::vector
<StringRef
> ArgsV
;
482 for (StringRef Arg
: ViewOpts
.DemanglerOpts
)
483 ArgsV
.push_back(Arg
);
484 Optional
<StringRef
> Redirects
[] = {InputPath
.str(), OutputPath
.str(), {""}};
486 int RC
= sys::ExecuteAndWait(ViewOpts
.DemanglerOpts
[0], ArgsV
,
487 /*env=*/None
, Redirects
, /*secondsToWait=*/0,
488 /*memoryLimit=*/0, &ErrMsg
);
490 error(ErrMsg
, ViewOpts
.DemanglerOpts
[0]);
494 // Parse the demangler's output.
495 auto BufOrError
= MemoryBuffer::getFile(OutputPath
);
497 error(OutputPath
, BufOrError
.getError().message());
501 std::unique_ptr
<MemoryBuffer
> DemanglerBuf
= std::move(*BufOrError
);
503 SmallVector
<StringRef
, 8> Symbols
;
504 StringRef DemanglerData
= DemanglerBuf
->getBuffer();
505 DemanglerData
.split(Symbols
, '\n', /*MaxSplit=*/NumSymbols
,
506 /*KeepEmpty=*/false);
507 if (Symbols
.size() != NumSymbols
) {
508 error("Demangler did not provide expected number of symbols");
512 // Cache the demangled names.
514 for (const auto &Function
: Coverage
.getCoveredFunctions())
515 // On Windows, lines in the demangler's output file end with "\r\n".
516 // Splitting by '\n' keeps '\r's, so cut them now.
517 DC
.DemangledNames
[Function
.Name
] = Symbols
[I
++].rtrim();
520 void CodeCoverageTool::writeSourceFileView(StringRef SourceFile
,
521 CoverageMapping
*Coverage
,
522 CoveragePrinter
*Printer
,
523 bool ShowFilenames
) {
524 auto View
= createSourceFileView(SourceFile
, *Coverage
);
526 warning("The file '" + SourceFile
+ "' isn't covered.");
530 auto OSOrErr
= Printer
->createViewFile(SourceFile
, /*InToplevel=*/false);
531 if (Error E
= OSOrErr
.takeError()) {
532 error("Could not create view file!", toString(std::move(E
)));
535 auto OS
= std::move(OSOrErr
.get());
537 View
->print(*OS
.get(), /*Wholefile=*/true,
538 /*ShowSourceName=*/ShowFilenames
,
539 /*ShowTitle=*/ViewOpts
.hasOutputDirectory());
540 Printer
->closeViewFile(std::move(OS
));
543 int CodeCoverageTool::run(Command Cmd
, int argc
, const char **argv
) {
544 cl::opt
<std::string
> CovFilename(
545 cl::Positional
, cl::desc("Covered executable or object file."));
547 cl::list
<std::string
> CovFilenames(
548 "object", cl::desc("Coverage executable or object file"), cl::ZeroOrMore
,
551 cl::list
<std::string
> InputSourceFiles(
552 cl::Positional
, cl::desc("<Source files>"), cl::ZeroOrMore
);
554 cl::opt
<bool> DebugDumpCollectedPaths(
555 "dump-collected-paths", cl::Optional
, cl::Hidden
,
556 cl::desc("Show the collected paths to source files"));
558 cl::opt
<std::string
, true> PGOFilename(
559 "instr-profile", cl::Required
, cl::location(this->PGOFilename
),
561 "File with the profile data obtained after an instrumented run"));
563 cl::list
<std::string
> Arches(
564 "arch", cl::desc("architectures of the coverage mapping binaries"));
566 cl::opt
<bool> DebugDump("dump", cl::Optional
,
567 cl::desc("Show internal debug dump"));
569 cl::opt
<CoverageViewOptions::OutputFormat
> Format(
570 "format", cl::desc("Output format for line-based coverage reports"),
571 cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text
, "text",
573 clEnumValN(CoverageViewOptions::OutputFormat::HTML
, "html",
575 cl::init(CoverageViewOptions::OutputFormat::Text
));
577 cl::opt
<std::string
> PathRemap(
578 "path-equivalence", cl::Optional
,
579 cl::desc("<from>,<to> Map coverage data paths to local source file "
582 cl::OptionCategory
FilteringCategory("Function filtering options");
584 cl::list
<std::string
> NameFilters(
585 "name", cl::Optional
,
586 cl::desc("Show code coverage only for functions with the given name"),
587 cl::ZeroOrMore
, cl::cat(FilteringCategory
));
589 cl::list
<std::string
> NameFilterFiles(
590 "name-whitelist", cl::Optional
,
591 cl::desc("Show code coverage only for functions listed in the given "
593 cl::ZeroOrMore
, cl::cat(FilteringCategory
));
595 cl::list
<std::string
> NameRegexFilters(
596 "name-regex", cl::Optional
,
597 cl::desc("Show code coverage only for functions that match the given "
598 "regular expression"),
599 cl::ZeroOrMore
, cl::cat(FilteringCategory
));
601 cl::list
<std::string
> IgnoreFilenameRegexFilters(
602 "ignore-filename-regex", cl::Optional
,
603 cl::desc("Skip source code files with file paths that match the given "
604 "regular expression"),
605 cl::ZeroOrMore
, cl::cat(FilteringCategory
));
607 cl::opt
<double> RegionCoverageLtFilter(
608 "region-coverage-lt", cl::Optional
,
609 cl::desc("Show code coverage only for functions with region coverage "
610 "less than the given threshold"),
611 cl::cat(FilteringCategory
));
613 cl::opt
<double> RegionCoverageGtFilter(
614 "region-coverage-gt", cl::Optional
,
615 cl::desc("Show code coverage only for functions with region coverage "
616 "greater than the given threshold"),
617 cl::cat(FilteringCategory
));
619 cl::opt
<double> LineCoverageLtFilter(
620 "line-coverage-lt", cl::Optional
,
621 cl::desc("Show code coverage only for functions with line coverage less "
622 "than the given threshold"),
623 cl::cat(FilteringCategory
));
625 cl::opt
<double> LineCoverageGtFilter(
626 "line-coverage-gt", cl::Optional
,
627 cl::desc("Show code coverage only for functions with line coverage "
628 "greater than the given threshold"),
629 cl::cat(FilteringCategory
));
631 cl::opt
<cl::boolOrDefault
> UseColor(
632 "use-color", cl::desc("Emit colored output (default=autodetect)"),
633 cl::init(cl::BOU_UNSET
));
635 cl::list
<std::string
> DemanglerOpts(
636 "Xdemangler", cl::desc("<demangler-path>|<demangler-option>"));
638 cl::opt
<bool> RegionSummary(
639 "show-region-summary", cl::Optional
,
640 cl::desc("Show region statistics in summary table"),
643 cl::opt
<bool> InstantiationSummary(
644 "show-instantiation-summary", cl::Optional
,
645 cl::desc("Show instantiation statistics in summary table"));
647 cl::opt
<bool> SummaryOnly(
648 "summary-only", cl::Optional
,
649 cl::desc("Export only summary information for each source file"));
651 cl::opt
<unsigned> NumThreads(
652 "num-threads", cl::init(0),
653 cl::desc("Number of merge threads to use (default: autodetect)"));
654 cl::alias
NumThreadsA("j", cl::desc("Alias for --num-threads"),
655 cl::aliasopt(NumThreads
));
657 auto commandLineParser
= [&, this](int argc
, const char **argv
) -> int {
658 cl::ParseCommandLineOptions(argc
, argv
, "LLVM code coverage tool\n");
659 ViewOpts
.Debug
= DebugDump
;
661 if (!CovFilename
.empty())
662 ObjectFilenames
.emplace_back(CovFilename
);
663 for (const std::string
&Filename
: CovFilenames
)
664 ObjectFilenames
.emplace_back(Filename
);
665 if (ObjectFilenames
.empty()) {
666 errs() << "No filenames specified!\n";
670 ViewOpts
.Format
= Format
;
671 switch (ViewOpts
.Format
) {
672 case CoverageViewOptions::OutputFormat::Text
:
673 ViewOpts
.Colors
= UseColor
== cl::BOU_UNSET
674 ? sys::Process::StandardOutHasColors()
675 : UseColor
== cl::BOU_TRUE
;
677 case CoverageViewOptions::OutputFormat::HTML
:
678 if (UseColor
== cl::BOU_FALSE
)
679 errs() << "Color output cannot be disabled when generating html.\n";
680 ViewOpts
.Colors
= true;
684 // If path-equivalence was given and is a comma seperated pair then set
686 auto EquivPair
= StringRef(PathRemap
).split(',');
687 if (!(EquivPair
.first
.empty() && EquivPair
.second
.empty()))
688 PathRemapping
= EquivPair
;
690 // If a demangler is supplied, check if it exists and register it.
691 if (DemanglerOpts
.size()) {
692 auto DemanglerPathOrErr
= sys::findProgramByName(DemanglerOpts
[0]);
693 if (!DemanglerPathOrErr
) {
694 error("Could not find the demangler!",
695 DemanglerPathOrErr
.getError().message());
698 DemanglerOpts
[0] = *DemanglerPathOrErr
;
699 ViewOpts
.DemanglerOpts
.swap(DemanglerOpts
);
702 // Read in -name-whitelist files.
703 if (!NameFilterFiles
.empty()) {
704 std::string SpecialCaseListErr
;
706 SpecialCaseList::create(NameFilterFiles
, SpecialCaseListErr
);
708 error(SpecialCaseListErr
);
711 // Create the function filters
712 if (!NameFilters
.empty() || NameWhitelist
|| !NameRegexFilters
.empty()) {
713 auto NameFilterer
= llvm::make_unique
<CoverageFilters
>();
714 for (const auto &Name
: NameFilters
)
715 NameFilterer
->push_back(llvm::make_unique
<NameCoverageFilter
>(Name
));
717 NameFilterer
->push_back(
718 llvm::make_unique
<NameWhitelistCoverageFilter
>(*NameWhitelist
));
719 for (const auto &Regex
: NameRegexFilters
)
720 NameFilterer
->push_back(
721 llvm::make_unique
<NameRegexCoverageFilter
>(Regex
));
722 Filters
.push_back(std::move(NameFilterer
));
725 if (RegionCoverageLtFilter
.getNumOccurrences() ||
726 RegionCoverageGtFilter
.getNumOccurrences() ||
727 LineCoverageLtFilter
.getNumOccurrences() ||
728 LineCoverageGtFilter
.getNumOccurrences()) {
729 auto StatFilterer
= llvm::make_unique
<CoverageFilters
>();
730 if (RegionCoverageLtFilter
.getNumOccurrences())
731 StatFilterer
->push_back(llvm::make_unique
<RegionCoverageFilter
>(
732 RegionCoverageFilter::LessThan
, RegionCoverageLtFilter
));
733 if (RegionCoverageGtFilter
.getNumOccurrences())
734 StatFilterer
->push_back(llvm::make_unique
<RegionCoverageFilter
>(
735 RegionCoverageFilter::GreaterThan
, RegionCoverageGtFilter
));
736 if (LineCoverageLtFilter
.getNumOccurrences())
737 StatFilterer
->push_back(llvm::make_unique
<LineCoverageFilter
>(
738 LineCoverageFilter::LessThan
, LineCoverageLtFilter
));
739 if (LineCoverageGtFilter
.getNumOccurrences())
740 StatFilterer
->push_back(llvm::make_unique
<LineCoverageFilter
>(
741 RegionCoverageFilter::GreaterThan
, LineCoverageGtFilter
));
742 Filters
.push_back(std::move(StatFilterer
));
745 // Create the ignore filename filters.
746 for (const auto &RE
: IgnoreFilenameRegexFilters
)
747 IgnoreFilenameFilters
.push_back(
748 llvm::make_unique
<NameRegexCoverageFilter
>(RE
));
750 if (!Arches
.empty()) {
751 for (const std::string
&Arch
: Arches
) {
752 if (Triple(Arch
).getArch() == llvm::Triple::ArchType::UnknownArch
) {
753 error("Unknown architecture: " + Arch
);
756 CoverageArches
.emplace_back(Arch
);
758 if (CoverageArches
.size() != ObjectFilenames
.size()) {
759 error("Number of architectures doesn't match the number of objects");
764 // IgnoreFilenameFilters are applied even when InputSourceFiles specified.
765 for (const std::string
&File
: InputSourceFiles
)
768 if (DebugDumpCollectedPaths
) {
769 for (const std::string
&SF
: SourceFiles
)
770 outs() << SF
<< '\n';
774 ViewOpts
.ShowRegionSummary
= RegionSummary
;
775 ViewOpts
.ShowInstantiationSummary
= InstantiationSummary
;
776 ViewOpts
.ExportSummaryOnly
= SummaryOnly
;
777 ViewOpts
.NumThreads
= NumThreads
;
784 return doShow(argc
, argv
, commandLineParser
);
786 return doReport(argc
, argv
, commandLineParser
);
788 return doExport(argc
, argv
, commandLineParser
);
793 int CodeCoverageTool::doShow(int argc
, const char **argv
,
794 CommandLineParserType commandLineParser
) {
796 cl::OptionCategory
ViewCategory("Viewing options");
798 cl::opt
<bool> ShowLineExecutionCounts(
799 "show-line-counts", cl::Optional
,
800 cl::desc("Show the execution counts for each line"), cl::init(true),
801 cl::cat(ViewCategory
));
803 cl::opt
<bool> ShowRegions(
804 "show-regions", cl::Optional
,
805 cl::desc("Show the execution counts for each region"),
806 cl::cat(ViewCategory
));
808 cl::opt
<bool> ShowBestLineRegionsCounts(
809 "show-line-counts-or-regions", cl::Optional
,
810 cl::desc("Show the execution counts for each line, or the execution "
811 "counts for each region on lines that have multiple regions"),
812 cl::cat(ViewCategory
));
814 cl::opt
<bool> ShowExpansions("show-expansions", cl::Optional
,
815 cl::desc("Show expanded source regions"),
816 cl::cat(ViewCategory
));
818 cl::opt
<bool> ShowInstantiations("show-instantiations", cl::Optional
,
819 cl::desc("Show function instantiations"),
820 cl::init(true), cl::cat(ViewCategory
));
822 cl::opt
<std::string
> ShowOutputDirectory(
823 "output-dir", cl::init(""),
824 cl::desc("Directory in which coverage information is written out"));
825 cl::alias
ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
826 cl::aliasopt(ShowOutputDirectory
));
828 cl::opt
<uint32_t> TabSize(
829 "tab-size", cl::init(2),
831 "Set tab expansion size for html coverage reports (default = 2)"));
833 cl::opt
<std::string
> ProjectTitle(
834 "project-title", cl::Optional
,
835 cl::desc("Set project title for the coverage report"));
837 auto Err
= commandLineParser(argc
, argv
);
841 ViewOpts
.ShowLineNumbers
= true;
842 ViewOpts
.ShowLineStats
= ShowLineExecutionCounts
.getNumOccurrences() != 0 ||
843 !ShowRegions
|| ShowBestLineRegionsCounts
;
844 ViewOpts
.ShowRegionMarkers
= ShowRegions
|| ShowBestLineRegionsCounts
;
845 ViewOpts
.ShowExpandedRegions
= ShowExpansions
;
846 ViewOpts
.ShowFunctionInstantiations
= ShowInstantiations
;
847 ViewOpts
.ShowOutputDirectory
= ShowOutputDirectory
;
848 ViewOpts
.TabSize
= TabSize
;
849 ViewOpts
.ProjectTitle
= ProjectTitle
;
851 if (ViewOpts
.hasOutputDirectory()) {
852 if (auto E
= sys::fs::create_directories(ViewOpts
.ShowOutputDirectory
)) {
853 error("Could not create output directory!", E
.message());
858 sys::fs::file_status Status
;
859 if (sys::fs::status(PGOFilename
, Status
)) {
860 error("profdata file error: can not get the file status. \n");
864 auto ModifiedTime
= Status
.getLastModificationTime();
865 std::string ModifiedTimeStr
= to_string(ModifiedTime
);
866 size_t found
= ModifiedTimeStr
.rfind(':');
867 ViewOpts
.CreatedTimeStr
= (found
!= std::string::npos
)
868 ? "Created: " + ModifiedTimeStr
.substr(0, found
)
869 : "Created: " + ModifiedTimeStr
;
871 auto Coverage
= load();
875 auto Printer
= CoveragePrinter::create(ViewOpts
);
877 if (SourceFiles
.empty())
878 // Get the source files from the function coverage mapping.
879 for (StringRef Filename
: Coverage
->getUniqueSourceFiles()) {
880 if (!IgnoreFilenameFilters
.matchesFilename(Filename
))
881 SourceFiles
.push_back(Filename
);
884 // Create an index out of the source files.
885 if (ViewOpts
.hasOutputDirectory()) {
886 if (Error E
= Printer
->createIndexFile(SourceFiles
, *Coverage
, Filters
)) {
887 error("Could not create index file!", toString(std::move(E
)));
892 if (!Filters
.empty()) {
893 // Build the map of filenames to functions.
894 std::map
<llvm::StringRef
, std::vector
<const FunctionRecord
*>>
896 for (const auto &SourceFile
: SourceFiles
)
897 for (const auto &Function
: Coverage
->getCoveredFunctions(SourceFile
))
898 if (Filters
.matches(*Coverage
.get(), Function
))
899 FilenameFunctionMap
[SourceFile
].push_back(&Function
);
901 // Only print filter matching functions for each file.
902 for (const auto &FileFunc
: FilenameFunctionMap
) {
903 StringRef File
= FileFunc
.first
;
904 const auto &Functions
= FileFunc
.second
;
906 auto OSOrErr
= Printer
->createViewFile(File
, /*InToplevel=*/false);
907 if (Error E
= OSOrErr
.takeError()) {
908 error("Could not create view file!", toString(std::move(E
)));
911 auto OS
= std::move(OSOrErr
.get());
913 bool ShowTitle
= ViewOpts
.hasOutputDirectory();
914 for (const auto *Function
: Functions
) {
915 auto FunctionView
= createFunctionView(*Function
, *Coverage
);
917 warning("Could not read coverage for '" + Function
->Name
+ "'.");
920 FunctionView
->print(*OS
.get(), /*WholeFile=*/false,
921 /*ShowSourceName=*/true, ShowTitle
);
925 Printer
->closeViewFile(std::move(OS
));
932 (SourceFiles
.size() != 1) || ViewOpts
.hasOutputDirectory() ||
933 (ViewOpts
.Format
== CoverageViewOptions::OutputFormat::HTML
);
935 auto NumThreads
= ViewOpts
.NumThreads
;
937 // If NumThreads is not specified, auto-detect a good default.
940 std::max(1U, std::min(llvm::heavyweight_hardware_concurrency(),
941 unsigned(SourceFiles
.size())));
943 if (!ViewOpts
.hasOutputDirectory() || NumThreads
== 1) {
944 for (const std::string
&SourceFile
: SourceFiles
)
945 writeSourceFileView(SourceFile
, Coverage
.get(), Printer
.get(),
948 // In -output-dir mode, it's safe to use multiple threads to print files.
949 ThreadPool
Pool(NumThreads
);
950 for (const std::string
&SourceFile
: SourceFiles
)
951 Pool
.async(&CodeCoverageTool::writeSourceFileView
, this, SourceFile
,
952 Coverage
.get(), Printer
.get(), ShowFilenames
);
959 int CodeCoverageTool::doReport(int argc
, const char **argv
,
960 CommandLineParserType commandLineParser
) {
961 cl::opt
<bool> ShowFunctionSummaries(
962 "show-functions", cl::Optional
, cl::init(false),
963 cl::desc("Show coverage summaries for each function"));
965 auto Err
= commandLineParser(argc
, argv
);
969 if (ViewOpts
.Format
== CoverageViewOptions::OutputFormat::HTML
) {
970 error("HTML output for summary reports is not yet supported.");
974 auto Coverage
= load();
978 CoverageReport
Report(ViewOpts
, *Coverage
.get());
979 if (!ShowFunctionSummaries
) {
980 if (SourceFiles
.empty())
981 Report
.renderFileReports(llvm::outs(), IgnoreFilenameFilters
);
983 Report
.renderFileReports(llvm::outs(), SourceFiles
);
985 if (SourceFiles
.empty()) {
986 error("Source files must be specified when -show-functions=true is "
991 Report
.renderFunctionReports(SourceFiles
, DC
, llvm::outs());
996 int CodeCoverageTool::doExport(int argc
, const char **argv
,
997 CommandLineParserType commandLineParser
) {
999 auto Err
= commandLineParser(argc
, argv
);
1003 if (ViewOpts
.Format
!= CoverageViewOptions::OutputFormat::Text
) {
1004 error("Coverage data can only be exported as textual JSON.");
1008 auto Coverage
= load();
1010 error("Could not load coverage information");
1014 auto Exporter
= CoverageExporterJson(*Coverage
.get(), ViewOpts
, outs());
1016 if (SourceFiles
.empty())
1017 Exporter
.renderRoot(IgnoreFilenameFilters
);
1019 Exporter
.renderRoot(SourceFiles
);
1024 int showMain(int argc
, const char *argv
[]) {
1025 CodeCoverageTool Tool
;
1026 return Tool
.run(CodeCoverageTool::Show
, argc
, argv
);
1029 int reportMain(int argc
, const char *argv
[]) {
1030 CodeCoverageTool Tool
;
1031 return Tool
.run(CodeCoverageTool::Report
, argc
, argv
);
1034 int exportMain(int argc
, const char *argv
[]) {
1035 CodeCoverageTool Tool
;
1036 return Tool
.run(CodeCoverageTool::Export
, argc
, argv
);