comparison tools/llvm-cov/CodeCoverage.cpp @ 121:803732b1fca8

LLVM 5.0
author kono
date Fri, 27 Oct 2017 17:07:41 +0900
parents 1172e4bd9c6f
children 3a76565eade5
comparison
equal deleted inserted replaced
120:1172e4bd9c6f 121:803732b1fca8
13 // 13 //
14 //===----------------------------------------------------------------------===// 14 //===----------------------------------------------------------------------===//
15 15
16 #include "CoverageFilters.h" 16 #include "CoverageFilters.h"
17 #include "CoverageReport.h" 17 #include "CoverageReport.h"
18 #include "CoverageSummaryInfo.h"
18 #include "CoverageViewOptions.h" 19 #include "CoverageViewOptions.h"
19 #include "RenderingSupport.h" 20 #include "RenderingSupport.h"
20 #include "SourceCoverageView.h" 21 #include "SourceCoverageView.h"
21 #include "llvm/ADT/SmallString.h" 22 #include "llvm/ADT/SmallString.h"
22 #include "llvm/ADT/StringRef.h" 23 #include "llvm/ADT/StringRef.h"
29 #include "llvm/Support/MemoryBuffer.h" 30 #include "llvm/Support/MemoryBuffer.h"
30 #include "llvm/Support/Path.h" 31 #include "llvm/Support/Path.h"
31 #include "llvm/Support/Process.h" 32 #include "llvm/Support/Process.h"
32 #include "llvm/Support/Program.h" 33 #include "llvm/Support/Program.h"
33 #include "llvm/Support/ScopedPrinter.h" 34 #include "llvm/Support/ScopedPrinter.h"
35 #include "llvm/Support/Threading.h"
34 #include "llvm/Support/ThreadPool.h" 36 #include "llvm/Support/ThreadPool.h"
35 #include "llvm/Support/ToolOutputFile.h" 37 #include "llvm/Support/ToolOutputFile.h"
38
36 #include <functional> 39 #include <functional>
40 #include <map>
37 #include <system_error> 41 #include <system_error>
38 42
39 using namespace llvm; 43 using namespace llvm;
40 using namespace coverage; 44 using namespace coverage;
41 45
42 void exportCoverageDataToJson(const coverage::CoverageMapping &CoverageMapping, 46 void exportCoverageDataToJson(const coverage::CoverageMapping &CoverageMapping,
47 const CoverageViewOptions &Options,
43 raw_ostream &OS); 48 raw_ostream &OS);
44 49
45 namespace { 50 namespace {
46 /// \brief The implementation of the coverage tool. 51 /// \brief The implementation of the coverage tool.
47 class CodeCoverageTool { 52 class CodeCoverageTool {
90 createSourceFileView(StringRef SourceFile, const CoverageMapping &Coverage); 95 createSourceFileView(StringRef SourceFile, const CoverageMapping &Coverage);
91 96
92 /// \brief Load the coverage mapping data. Return nullptr if an error occurred. 97 /// \brief Load the coverage mapping data. Return nullptr if an error occurred.
93 std::unique_ptr<CoverageMapping> load(); 98 std::unique_ptr<CoverageMapping> load();
94 99
100 /// \brief Create a mapping from files in the Coverage data to local copies
101 /// (path-equivalence).
102 void remapPathNames(const CoverageMapping &Coverage);
103
95 /// \brief Remove input source files which aren't mapped by \p Coverage. 104 /// \brief Remove input source files which aren't mapped by \p Coverage.
96 void removeUnmappedInputs(const CoverageMapping &Coverage); 105 void removeUnmappedInputs(const CoverageMapping &Coverage);
97 106
98 /// \brief If a demangler is available, demangle all symbol names. 107 /// \brief If a demangler is available, demangle all symbol names.
99 void demangleSymbols(const CoverageMapping &Coverage); 108 void demangleSymbols(const CoverageMapping &Coverage);
100
101 /// \brief Demangle \p Sym if possible. Otherwise, just return \p Sym.
102 StringRef getSymbolForHumans(StringRef Sym) const;
103 109
104 /// \brief Write out a source file view to the filesystem. 110 /// \brief Write out a source file view to the filesystem.
105 void writeSourceFileView(StringRef SourceFile, CoverageMapping *Coverage, 111 void writeSourceFileView(StringRef SourceFile, CoverageMapping *Coverage,
106 CoveragePrinter *Printer, bool ShowFilenames); 112 CoveragePrinter *Printer, bool ShowFilenames);
107 113
124 std::string PGOFilename; 130 std::string PGOFilename;
125 131
126 /// A list of input source files. 132 /// A list of input source files.
127 std::vector<std::string> SourceFiles; 133 std::vector<std::string> SourceFiles;
128 134
129 /// Whether or not we're in -filename-equivalence mode. 135 /// In -path-equivalence mode, this maps the absolute paths from the coverage
130 bool CompareFilenamesOnly; 136 /// mapping data to the input source files.
131
132 /// In -filename-equivalence mode, this maps absolute paths from the
133 /// coverage mapping data to input source files.
134 StringMap<std::string> RemappedFilenames; 137 StringMap<std::string> RemappedFilenames;
135 138
139 /// The coverage data path to be remapped from, and the source path to be
140 /// remapped to, when using -path-equivalence.
141 Optional<std::pair<std::string, std::string>> PathRemapping;
142
136 /// The architecture the coverage mapping data targets. 143 /// The architecture the coverage mapping data targets.
137 std::string CoverageArch; 144 std::vector<StringRef> CoverageArches;
138 145
139 /// A cache for demangled symbol names. 146 /// A cache for demangled symbols.
140 StringMap<std::string> DemangledNames; 147 DemangleCache DC;
141 148
142 /// Errors and warnings which have not been printed. 149 /// A lock which guards printing to stderr.
143 std::mutex ErrsLock; 150 std::mutex ErrsLock;
144 151
145 /// A container for input source file buffers. 152 /// A container for input source file buffers.
146 std::mutex LoadedSourceFilesLock; 153 std::mutex LoadedSourceFilesLock;
147 std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>> 154 std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
148 LoadedSourceFiles; 155 LoadedSourceFiles;
156
157 /// Whitelist from -name-whitelist to be used for filtering.
158 std::unique_ptr<SpecialCaseList> NameWhitelist;
149 }; 159 };
150 } 160 }
151 161
152 static std::string getErrorString(const Twine &Message, StringRef Whence, 162 static std::string getErrorString(const Twine &Message, StringRef Whence,
153 bool Warning) { 163 bool Warning) {
170 ViewOpts.colored_ostream(errs(), raw_ostream::RED) 180 ViewOpts.colored_ostream(errs(), raw_ostream::RED)
171 << getErrorString(Message, Whence, true); 181 << getErrorString(Message, Whence, true);
172 } 182 }
173 183
174 void CodeCoverageTool::addCollectedPath(const std::string &Path) { 184 void CodeCoverageTool::addCollectedPath(const std::string &Path) {
175 if (CompareFilenamesOnly) { 185 SmallString<128> EffectivePath(Path);
176 SourceFiles.emplace_back(Path); 186 if (std::error_code EC = sys::fs::make_absolute(EffectivePath)) {
177 } else { 187 error(EC.message(), Path);
178 SmallString<128> EffectivePath(Path); 188 return;
179 if (std::error_code EC = sys::fs::make_absolute(EffectivePath)) { 189 }
180 error(EC.message(), Path); 190 sys::path::remove_dots(EffectivePath, /*remove_dot_dots=*/true);
181 return; 191 SourceFiles.emplace_back(EffectivePath.str());
182 }
183 sys::path::remove_dots(EffectivePath, /*remove_dot_dots=*/true);
184 SourceFiles.emplace_back(EffectivePath.str());
185 }
186 } 192 }
187 193
188 void CodeCoverageTool::collectPaths(const std::string &Path) { 194 void CodeCoverageTool::collectPaths(const std::string &Path) {
189 llvm::sys::fs::file_status Status; 195 llvm::sys::fs::file_status Status;
190 llvm::sys::fs::status(Path, Status); 196 llvm::sys::fs::status(Path, Status);
191 if (!llvm::sys::fs::exists(Status)) { 197 if (!llvm::sys::fs::exists(Status)) {
192 if (CompareFilenamesOnly) 198 if (PathRemapping)
193 addCollectedPath(Path); 199 addCollectedPath(Path);
194 else 200 else
195 error("Missing source file", Path); 201 error("Missing source file", Path);
196 return; 202 return;
197 } 203 }
265 auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename()); 271 auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename());
266 if (!SourceBuffer) 272 if (!SourceBuffer)
267 return nullptr; 273 return nullptr;
268 274
269 auto Expansions = FunctionCoverage.getExpansions(); 275 auto Expansions = FunctionCoverage.getExpansions();
270 auto View = SourceCoverageView::create(getSymbolForHumans(Function.Name), 276 auto View = SourceCoverageView::create(DC.demangle(Function.Name),
271 SourceBuffer.get(), ViewOpts, 277 SourceBuffer.get(), ViewOpts,
272 std::move(FunctionCoverage)); 278 std::move(FunctionCoverage));
273 attachExpansionSubViews(*View, Expansions, Coverage); 279 attachExpansionSubViews(*View, Expansions, Coverage);
274 280
275 return View; 281 return View;
287 293
288 auto Expansions = FileCoverage.getExpansions(); 294 auto Expansions = FileCoverage.getExpansions();
289 auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(), 295 auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(),
290 ViewOpts, std::move(FileCoverage)); 296 ViewOpts, std::move(FileCoverage));
291 attachExpansionSubViews(*View, Expansions, Coverage); 297 attachExpansionSubViews(*View, Expansions, Coverage);
292 298 if (!ViewOpts.ShowFunctionInstantiations)
293 for (const auto *Function : Coverage.getInstantiations(SourceFile)) { 299 return View;
294 std::unique_ptr<SourceCoverageView> SubView{nullptr}; 300
295 301 for (const auto &Group : Coverage.getInstantiationGroups(SourceFile)) {
296 StringRef Funcname = getSymbolForHumans(Function->Name); 302 // Skip functions which have a single instantiation.
297 303 if (Group.size() < 2)
298 if (Function->ExecutionCount > 0) { 304 continue;
299 auto SubViewCoverage = Coverage.getCoverageForFunction(*Function); 305
300 auto SubViewExpansions = SubViewCoverage.getExpansions(); 306 for (const FunctionRecord *Function : Group.getInstantiations()) {
301 SubView = SourceCoverageView::create( 307 std::unique_ptr<SourceCoverageView> SubView{nullptr};
302 Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage)); 308
303 attachExpansionSubViews(*SubView, SubViewExpansions, Coverage); 309 StringRef Funcname = DC.demangle(Function->Name);
304 } 310
305 311 if (Function->ExecutionCount > 0) {
306 unsigned FileID = Function->CountedRegions.front().FileID; 312 auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
307 unsigned Line = 0; 313 auto SubViewExpansions = SubViewCoverage.getExpansions();
308 for (const auto &CR : Function->CountedRegions) 314 SubView = SourceCoverageView::create(
309 if (CR.FileID == FileID) 315 Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
310 Line = std::max(CR.LineEnd, Line); 316 attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
311 View->addInstantiation(Funcname, Line, std::move(SubView)); 317 }
318
319 unsigned FileID = Function->CountedRegions.front().FileID;
320 unsigned Line = 0;
321 for (const auto &CR : Function->CountedRegions)
322 if (CR.FileID == FileID)
323 Line = std::max(CR.LineEnd, Line);
324 View->addInstantiation(Funcname, Line, std::move(SubView));
325 }
312 } 326 }
313 return View; 327 return View;
314 } 328 }
315 329
316 static bool modifiedTimeGT(StringRef LHS, StringRef RHS) { 330 static bool modifiedTimeGT(StringRef LHS, StringRef RHS) {
328 for (StringRef ObjectFilename : ObjectFilenames) 342 for (StringRef ObjectFilename : ObjectFilenames)
329 if (modifiedTimeGT(ObjectFilename, PGOFilename)) 343 if (modifiedTimeGT(ObjectFilename, PGOFilename))
330 warning("profile data may be out of date - object is newer", 344 warning("profile data may be out of date - object is newer",
331 ObjectFilename); 345 ObjectFilename);
332 auto CoverageOrErr = 346 auto CoverageOrErr =
333 CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArch); 347 CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArches);
334 if (Error E = CoverageOrErr.takeError()) { 348 if (Error E = CoverageOrErr.takeError()) {
335 error("Failed to load coverage: " + toString(std::move(E)), 349 error("Failed to load coverage: " + toString(std::move(E)),
336 join(ObjectFilenames.begin(), ObjectFilenames.end(), ", ")); 350 join(ObjectFilenames.begin(), ObjectFilenames.end(), ", "));
337 return nullptr; 351 return nullptr;
338 } 352 }
339 auto Coverage = std::move(CoverageOrErr.get()); 353 auto Coverage = std::move(CoverageOrErr.get());
340 unsigned Mismatched = Coverage->getMismatchedCount(); 354 unsigned Mismatched = Coverage->getMismatchedCount();
341 if (Mismatched) 355 if (Mismatched) {
342 warning(utostr(Mismatched) + " functions have mismatched data"); 356 warning(utostr(Mismatched) + " functions have mismatched data");
357
358 if (ViewOpts.Debug) {
359 for (const auto &HashMismatch : Coverage->getHashMismatches())
360 errs() << "hash-mismatch: "
361 << "No profile record found for '" << HashMismatch.first << "'"
362 << " with hash = 0x" << utohexstr(HashMismatch.second) << "\n";
363
364 for (const auto &CounterMismatch : Coverage->getCounterMismatches())
365 errs() << "counter-mismatch: "
366 << "Coverage mapping for " << CounterMismatch.first
367 << " only has " << CounterMismatch.second
368 << " valid counter expressions\n";
369 }
370 }
371
372 remapPathNames(*Coverage);
343 373
344 if (!SourceFiles.empty()) 374 if (!SourceFiles.empty())
345 removeUnmappedInputs(*Coverage); 375 removeUnmappedInputs(*Coverage);
346 376
347 demangleSymbols(*Coverage); 377 demangleSymbols(*Coverage);
348 378
349 return Coverage; 379 return Coverage;
350 } 380 }
351 381
382 void CodeCoverageTool::remapPathNames(const CoverageMapping &Coverage) {
383 if (!PathRemapping)
384 return;
385
386 // Convert remapping paths to native paths with trailing seperators.
387 auto nativeWithTrailing = [](StringRef Path) -> std::string {
388 if (Path.empty())
389 return "";
390 SmallString<128> NativePath;
391 sys::path::native(Path, NativePath);
392 if (!sys::path::is_separator(NativePath.back()))
393 NativePath += sys::path::get_separator();
394 return NativePath.c_str();
395 };
396 std::string RemapFrom = nativeWithTrailing(PathRemapping->first);
397 std::string RemapTo = nativeWithTrailing(PathRemapping->second);
398
399 // Create a mapping from coverage data file paths to local paths.
400 for (StringRef Filename : Coverage.getUniqueSourceFiles()) {
401 SmallString<128> NativeFilename;
402 sys::path::native(Filename, NativeFilename);
403 if (NativeFilename.startswith(RemapFrom)) {
404 RemappedFilenames[Filename] =
405 RemapTo + NativeFilename.substr(RemapFrom.size()).str();
406 }
407 }
408
409 // Convert input files from local paths to coverage data file paths.
410 StringMap<std::string> InvRemappedFilenames;
411 for (const auto &RemappedFilename : RemappedFilenames)
412 InvRemappedFilenames[RemappedFilename.getValue()] = RemappedFilename.getKey();
413
414 for (std::string &Filename : SourceFiles) {
415 SmallString<128> NativeFilename;
416 sys::path::native(Filename, NativeFilename);
417 auto CovFileName = InvRemappedFilenames.find(NativeFilename);
418 if (CovFileName != InvRemappedFilenames.end())
419 Filename = CovFileName->second;
420 }
421 }
422
352 void CodeCoverageTool::removeUnmappedInputs(const CoverageMapping &Coverage) { 423 void CodeCoverageTool::removeUnmappedInputs(const CoverageMapping &Coverage) {
353 std::vector<StringRef> CoveredFiles = Coverage.getUniqueSourceFiles(); 424 std::vector<StringRef> CoveredFiles = Coverage.getUniqueSourceFiles();
354 425
355 auto UncoveredFilesIt = SourceFiles.end(); 426 auto UncoveredFilesIt = SourceFiles.end();
356 if (!CompareFilenamesOnly) { 427 // The user may have specified source files which aren't in the coverage
357 // The user may have specified source files which aren't in the coverage 428 // mapping. Filter these files away.
358 // mapping. Filter these files away. 429 UncoveredFilesIt = std::remove_if(
359 UncoveredFilesIt = std::remove_if( 430 SourceFiles.begin(), SourceFiles.end(), [&](const std::string &SF) {
360 SourceFiles.begin(), SourceFiles.end(), [&](const std::string &SF) { 431 return !std::binary_search(CoveredFiles.begin(), CoveredFiles.end(),
361 return !std::binary_search(CoveredFiles.begin(), CoveredFiles.end(), 432 SF);
362 SF); 433 });
363 });
364 } else {
365 for (auto &SF : SourceFiles) {
366 StringRef SFBase = sys::path::filename(SF);
367 for (const auto &CF : CoveredFiles) {
368 if (SFBase == sys::path::filename(CF)) {
369 RemappedFilenames[CF] = SF;
370 SF = CF;
371 break;
372 }
373 }
374 }
375 UncoveredFilesIt = std::remove_if(
376 SourceFiles.begin(), SourceFiles.end(),
377 [&](const std::string &SF) { return !RemappedFilenames.count(SF); });
378 }
379 434
380 SourceFiles.erase(UncoveredFilesIt, SourceFiles.end()); 435 SourceFiles.erase(UncoveredFilesIt, SourceFiles.end());
381 } 436 }
382 437
383 void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) { 438 void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) {
391 sys::fs::createTemporaryFile("demangle-in", "list", InputFD, InputPath); 446 sys::fs::createTemporaryFile("demangle-in", "list", InputFD, InputPath);
392 if (EC) { 447 if (EC) {
393 error(InputPath, EC.message()); 448 error(InputPath, EC.message());
394 return; 449 return;
395 } 450 }
396 tool_output_file InputTOF{InputPath, InputFD}; 451 ToolOutputFile InputTOF{InputPath, InputFD};
397 452
398 unsigned NumSymbols = 0; 453 unsigned NumSymbols = 0;
399 for (const auto &Function : Coverage.getCoveredFunctions()) { 454 for (const auto &Function : Coverage.getCoveredFunctions()) {
400 InputTOF.os() << Function.Name << '\n'; 455 InputTOF.os() << Function.Name << '\n';
401 ++NumSymbols; 456 ++NumSymbols;
409 OutputPath); 464 OutputPath);
410 if (EC) { 465 if (EC) {
411 error(OutputPath, EC.message()); 466 error(OutputPath, EC.message());
412 return; 467 return;
413 } 468 }
414 tool_output_file OutputTOF{OutputPath, OutputFD}; 469 ToolOutputFile OutputTOF{OutputPath, OutputFD};
415 OutputTOF.os().close(); 470 OutputTOF.os().close();
416 471
417 // Invoke the demangler. 472 // Invoke the demangler.
418 std::vector<const char *> ArgsV; 473 std::vector<const char *> ArgsV;
419 for (const std::string &Arg : ViewOpts.DemanglerOpts) 474 for (const std::string &Arg : ViewOpts.DemanglerOpts)
420 ArgsV.push_back(Arg.c_str()); 475 ArgsV.push_back(Arg.c_str());
421 ArgsV.push_back(nullptr); 476 ArgsV.push_back(nullptr);
422 StringRef InputPathRef = InputPath.str(); 477 Optional<StringRef> Redirects[] = {InputPath.str(), OutputPath.str(), {""}};
423 StringRef OutputPathRef = OutputPath.str();
424 StringRef StderrRef;
425 const StringRef *Redirects[] = {&InputPathRef, &OutputPathRef, &StderrRef};
426 std::string ErrMsg; 478 std::string ErrMsg;
427 int RC = sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV.data(), 479 int RC = sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV.data(),
428 /*env=*/nullptr, Redirects, /*secondsToWait=*/0, 480 /*env=*/nullptr, Redirects, /*secondsToWait=*/0,
429 /*memoryLimit=*/0, &ErrMsg); 481 /*memoryLimit=*/0, &ErrMsg);
430 if (RC) { 482 if (RC) {
451 } 503 }
452 504
453 // Cache the demangled names. 505 // Cache the demangled names.
454 unsigned I = 0; 506 unsigned I = 0;
455 for (const auto &Function : Coverage.getCoveredFunctions()) 507 for (const auto &Function : Coverage.getCoveredFunctions())
456 DemangledNames[Function.Name] = Symbols[I++]; 508 // On Windows, lines in the demangler's output file end with "\r\n".
457 } 509 // Splitting by '\n' keeps '\r's, so cut them now.
458 510 DC.DemangledNames[Function.Name] = Symbols[I++].rtrim();
459 StringRef CodeCoverageTool::getSymbolForHumans(StringRef Sym) const {
460 const auto DemangledName = DemangledNames.find(Sym);
461 if (DemangledName == DemangledNames.end())
462 return Sym;
463 return DemangledName->getValue();
464 } 511 }
465 512
466 void CodeCoverageTool::writeSourceFileView(StringRef SourceFile, 513 void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
467 CoverageMapping *Coverage, 514 CoverageMapping *Coverage,
468 CoveragePrinter *Printer, 515 CoveragePrinter *Printer,
479 return; 526 return;
480 } 527 }
481 auto OS = std::move(OSOrErr.get()); 528 auto OS = std::move(OSOrErr.get());
482 529
483 View->print(*OS.get(), /*Wholefile=*/true, 530 View->print(*OS.get(), /*Wholefile=*/true,
484 /*ShowSourceName=*/ShowFilenames); 531 /*ShowSourceName=*/ShowFilenames,
532 /*ShowTitle=*/ViewOpts.hasOutputDirectory());
485 Printer->closeViewFile(std::move(OS)); 533 Printer->closeViewFile(std::move(OS));
486 } 534 }
487 535
488 int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { 536 int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
489 cl::opt<std::string> CovFilename( 537 cl::opt<std::string> CovFilename(
503 cl::opt<std::string, true> PGOFilename( 551 cl::opt<std::string, true> PGOFilename(
504 "instr-profile", cl::Required, cl::location(this->PGOFilename), 552 "instr-profile", cl::Required, cl::location(this->PGOFilename),
505 cl::desc( 553 cl::desc(
506 "File with the profile data obtained after an instrumented run")); 554 "File with the profile data obtained after an instrumented run"));
507 555
508 cl::opt<std::string> Arch( 556 cl::list<std::string> Arches(
509 "arch", cl::desc("architecture of the coverage mapping binary")); 557 "arch", cl::desc("architectures of the coverage mapping binaries"));
510 558
511 cl::opt<bool> DebugDump("dump", cl::Optional, 559 cl::opt<bool> DebugDump("dump", cl::Optional,
512 cl::desc("Show internal debug dump")); 560 cl::desc("Show internal debug dump"));
513 561
514 cl::opt<CoverageViewOptions::OutputFormat> Format( 562 cl::opt<CoverageViewOptions::OutputFormat> Format(
517 "Text output"), 565 "Text output"),
518 clEnumValN(CoverageViewOptions::OutputFormat::HTML, "html", 566 clEnumValN(CoverageViewOptions::OutputFormat::HTML, "html",
519 "HTML output")), 567 "HTML output")),
520 cl::init(CoverageViewOptions::OutputFormat::Text)); 568 cl::init(CoverageViewOptions::OutputFormat::Text));
521 569
522 cl::opt<bool> FilenameEquivalence( 570 cl::opt<std::string> PathRemap(
523 "filename-equivalence", cl::Optional, 571 "path-equivalence", cl::Optional,
524 cl::desc("Treat source files as equivalent to paths in the coverage data " 572 cl::desc("<from>,<to> Map coverage data paths to local source file "
525 "when the file names match, even if the full paths do not")); 573 "paths"));
526 574
527 cl::OptionCategory FilteringCategory("Function filtering options"); 575 cl::OptionCategory FilteringCategory("Function filtering options");
528 576
529 cl::list<std::string> NameFilters( 577 cl::list<std::string> NameFilters(
530 "name", cl::Optional, 578 "name", cl::Optional,
531 cl::desc("Show code coverage only for functions with the given name"), 579 cl::desc("Show code coverage only for functions with the given name"),
580 cl::ZeroOrMore, cl::cat(FilteringCategory));
581
582 cl::list<std::string> NameFilterFiles(
583 "name-whitelist", cl::Optional,
584 cl::desc("Show code coverage only for functions listed in the given "
585 "file"),
532 cl::ZeroOrMore, cl::cat(FilteringCategory)); 586 cl::ZeroOrMore, cl::cat(FilteringCategory));
533 587
534 cl::list<std::string> NameRegexFilters( 588 cl::list<std::string> NameRegexFilters(
535 "name-regex", cl::Optional, 589 "name-regex", cl::Optional,
536 cl::desc("Show code coverage only for functions that match the given " 590 cl::desc("Show code coverage only for functions that match the given "
566 cl::init(cl::BOU_UNSET)); 620 cl::init(cl::BOU_UNSET));
567 621
568 cl::list<std::string> DemanglerOpts( 622 cl::list<std::string> DemanglerOpts(
569 "Xdemangler", cl::desc("<demangler-path>|<demangler-option>")); 623 "Xdemangler", cl::desc("<demangler-path>|<demangler-option>"));
570 624
625 cl::opt<bool> RegionSummary(
626 "show-region-summary", cl::Optional,
627 cl::desc("Show region statistics in summary table"),
628 cl::init(true));
629
630 cl::opt<bool> InstantiationSummary(
631 "show-instantiation-summary", cl::Optional,
632 cl::desc("Show instantiation statistics in summary table"));
633
571 auto commandLineParser = [&, this](int argc, const char **argv) -> int { 634 auto commandLineParser = [&, this](int argc, const char **argv) -> int {
572 cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); 635 cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
573 ViewOpts.Debug = DebugDump; 636 ViewOpts.Debug = DebugDump;
574 CompareFilenamesOnly = FilenameEquivalence;
575 637
576 if (!CovFilename.empty()) 638 if (!CovFilename.empty())
577 ObjectFilenames.emplace_back(CovFilename); 639 ObjectFilenames.emplace_back(CovFilename);
578 for (const std::string &Filename : CovFilenames) 640 for (const std::string &Filename : CovFilenames)
579 ObjectFilenames.emplace_back(Filename); 641 ObjectFilenames.emplace_back(Filename);
594 errs() << "Color output cannot be disabled when generating html.\n"; 656 errs() << "Color output cannot be disabled when generating html.\n";
595 ViewOpts.Colors = true; 657 ViewOpts.Colors = true;
596 break; 658 break;
597 } 659 }
598 660
661 // If path-equivalence was given and is a comma seperated pair then set
662 // PathRemapping.
663 auto EquivPair = StringRef(PathRemap).split(',');
664 if (!(EquivPair.first.empty() && EquivPair.second.empty()))
665 PathRemapping = EquivPair;
666
599 // If a demangler is supplied, check if it exists and register it. 667 // If a demangler is supplied, check if it exists and register it.
600 if (DemanglerOpts.size()) { 668 if (DemanglerOpts.size()) {
601 auto DemanglerPathOrErr = sys::findProgramByName(DemanglerOpts[0]); 669 auto DemanglerPathOrErr = sys::findProgramByName(DemanglerOpts[0]);
602 if (!DemanglerPathOrErr) { 670 if (!DemanglerPathOrErr) {
603 error("Could not find the demangler!", 671 error("Could not find the demangler!",
606 } 674 }
607 DemanglerOpts[0] = *DemanglerPathOrErr; 675 DemanglerOpts[0] = *DemanglerPathOrErr;
608 ViewOpts.DemanglerOpts.swap(DemanglerOpts); 676 ViewOpts.DemanglerOpts.swap(DemanglerOpts);
609 } 677 }
610 678
679 // Read in -name-whitelist files.
680 if (!NameFilterFiles.empty()) {
681 std::string SpecialCaseListErr;
682 NameWhitelist =
683 SpecialCaseList::create(NameFilterFiles, SpecialCaseListErr);
684 if (!NameWhitelist)
685 error(SpecialCaseListErr);
686 }
687
611 // Create the function filters 688 // Create the function filters
612 if (!NameFilters.empty() || !NameRegexFilters.empty()) { 689 if (!NameFilters.empty() || NameWhitelist || !NameRegexFilters.empty()) {
613 auto NameFilterer = new CoverageFilters; 690 auto NameFilterer = llvm::make_unique<CoverageFilters>();
614 for (const auto &Name : NameFilters) 691 for (const auto &Name : NameFilters)
615 NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name)); 692 NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name));
693 if (NameWhitelist)
694 NameFilterer->push_back(
695 llvm::make_unique<NameWhitelistCoverageFilter>(*NameWhitelist));
616 for (const auto &Regex : NameRegexFilters) 696 for (const auto &Regex : NameRegexFilters)
617 NameFilterer->push_back( 697 NameFilterer->push_back(
618 llvm::make_unique<NameRegexCoverageFilter>(Regex)); 698 llvm::make_unique<NameRegexCoverageFilter>(Regex));
619 Filters.push_back(std::unique_ptr<CoverageFilter>(NameFilterer)); 699 Filters.push_back(std::move(NameFilterer));
620 } 700 }
621 if (RegionCoverageLtFilter.getNumOccurrences() || 701 if (RegionCoverageLtFilter.getNumOccurrences() ||
622 RegionCoverageGtFilter.getNumOccurrences() || 702 RegionCoverageGtFilter.getNumOccurrences() ||
623 LineCoverageLtFilter.getNumOccurrences() || 703 LineCoverageLtFilter.getNumOccurrences() ||
624 LineCoverageGtFilter.getNumOccurrences()) { 704 LineCoverageGtFilter.getNumOccurrences()) {
625 auto StatFilterer = new CoverageFilters; 705 auto StatFilterer = llvm::make_unique<CoverageFilters>();
626 if (RegionCoverageLtFilter.getNumOccurrences()) 706 if (RegionCoverageLtFilter.getNumOccurrences())
627 StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>( 707 StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
628 RegionCoverageFilter::LessThan, RegionCoverageLtFilter)); 708 RegionCoverageFilter::LessThan, RegionCoverageLtFilter));
629 if (RegionCoverageGtFilter.getNumOccurrences()) 709 if (RegionCoverageGtFilter.getNumOccurrences())
630 StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>( 710 StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
633 StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>( 713 StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
634 LineCoverageFilter::LessThan, LineCoverageLtFilter)); 714 LineCoverageFilter::LessThan, LineCoverageLtFilter));
635 if (LineCoverageGtFilter.getNumOccurrences()) 715 if (LineCoverageGtFilter.getNumOccurrences())
636 StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>( 716 StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
637 RegionCoverageFilter::GreaterThan, LineCoverageGtFilter)); 717 RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
638 Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer)); 718 Filters.push_back(std::move(StatFilterer));
639 } 719 }
640 720
641 if (!Arch.empty() && 721 if (!Arches.empty()) {
642 Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) { 722 for (const std::string &Arch : Arches) {
643 error("Unknown architecture: " + Arch); 723 if (Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) {
644 return 1; 724 error("Unknown architecture: " + Arch);
645 } 725 return 1;
646 CoverageArch = Arch; 726 }
727 CoverageArches.emplace_back(Arch);
728 }
729 if (CoverageArches.size() != ObjectFilenames.size()) {
730 error("Number of architectures doesn't match the number of objects");
731 return 1;
732 }
733 }
647 734
648 for (const std::string &File : InputSourceFiles) 735 for (const std::string &File : InputSourceFiles)
649 collectPaths(File); 736 collectPaths(File);
650 737
651 if (DebugDumpCollectedPaths) { 738 if (DebugDumpCollectedPaths) {
652 for (const std::string &SF : SourceFiles) 739 for (const std::string &SF : SourceFiles)
653 outs() << SF << '\n'; 740 outs() << SF << '\n';
654 ::exit(0); 741 ::exit(0);
655 } 742 }
743
744 ViewOpts.ShowRegionSummary = RegionSummary;
745 ViewOpts.ShowInstantiationSummary = InstantiationSummary;
656 746
657 return 0; 747 return 0;
658 }; 748 };
659 749
660 switch (Cmd) { 750 switch (Cmd) {
693 cl::desc("Show expanded source regions"), 783 cl::desc("Show expanded source regions"),
694 cl::cat(ViewCategory)); 784 cl::cat(ViewCategory));
695 785
696 cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional, 786 cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional,
697 cl::desc("Show function instantiations"), 787 cl::desc("Show function instantiations"),
698 cl::cat(ViewCategory)); 788 cl::init(true), cl::cat(ViewCategory));
699 789
700 cl::opt<std::string> ShowOutputDirectory( 790 cl::opt<std::string> ShowOutputDirectory(
701 "output-dir", cl::init(""), 791 "output-dir", cl::init(""),
702 cl::desc("Directory in which coverage information is written out")); 792 cl::desc("Directory in which coverage information is written out"));
703 cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"), 793 cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
710 800
711 cl::opt<std::string> ProjectTitle( 801 cl::opt<std::string> ProjectTitle(
712 "project-title", cl::Optional, 802 "project-title", cl::Optional,
713 cl::desc("Set project title for the coverage report")); 803 cl::desc("Set project title for the coverage report"));
714 804
805 cl::opt<unsigned> NumThreads(
806 "num-threads", cl::init(0),
807 cl::desc("Number of merge threads to use (default: autodetect)"));
808 cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"),
809 cl::aliasopt(NumThreads));
810
715 auto Err = commandLineParser(argc, argv); 811 auto Err = commandLineParser(argc, argv);
716 if (Err) 812 if (Err)
717 return Err; 813 return Err;
718 814
719 ViewOpts.ShowLineNumbers = true; 815 ViewOpts.ShowLineNumbers = true;
720 ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 || 816 ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
721 !ShowRegions || ShowBestLineRegionsCounts; 817 !ShowRegions || ShowBestLineRegionsCounts;
722 ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts; 818 ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
723 ViewOpts.ShowLineStatsOrRegionMarkers = ShowBestLineRegionsCounts;
724 ViewOpts.ShowExpandedRegions = ShowExpansions; 819 ViewOpts.ShowExpandedRegions = ShowExpansions;
725 ViewOpts.ShowFunctionInstantiations = ShowInstantiations; 820 ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
726 ViewOpts.ShowOutputDirectory = ShowOutputDirectory; 821 ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
727 ViewOpts.TabSize = TabSize; 822 ViewOpts.TabSize = TabSize;
728 ViewOpts.ProjectTitle = ProjectTitle; 823 ViewOpts.ProjectTitle = ProjectTitle;
740 return 1; 835 return 1;
741 } 836 }
742 837
743 auto ModifiedTime = Status.getLastModificationTime(); 838 auto ModifiedTime = Status.getLastModificationTime();
744 std::string ModifiedTimeStr = to_string(ModifiedTime); 839 std::string ModifiedTimeStr = to_string(ModifiedTime);
745 size_t found = ModifiedTimeStr.rfind(":"); 840 size_t found = ModifiedTimeStr.rfind(':');
746 ViewOpts.CreatedTimeStr = (found != std::string::npos) 841 ViewOpts.CreatedTimeStr = (found != std::string::npos)
747 ? "Created: " + ModifiedTimeStr.substr(0, found) 842 ? "Created: " + ModifiedTimeStr.substr(0, found)
748 : "Created: " + ModifiedTimeStr; 843 : "Created: " + ModifiedTimeStr;
749 844
750 auto Coverage = load(); 845 auto Coverage = load();
751 if (!Coverage) 846 if (!Coverage)
752 return 1; 847 return 1;
753 848
754 auto Printer = CoveragePrinter::create(ViewOpts); 849 auto Printer = CoveragePrinter::create(ViewOpts);
755 850
851 if (SourceFiles.empty())
852 // Get the source files from the function coverage mapping.
853 for (StringRef Filename : Coverage->getUniqueSourceFiles())
854 SourceFiles.push_back(Filename);
855
856 // Create an index out of the source files.
857 if (ViewOpts.hasOutputDirectory()) {
858 if (Error E = Printer->createIndexFile(SourceFiles, *Coverage, Filters)) {
859 error("Could not create index file!", toString(std::move(E)));
860 return 1;
861 }
862 }
863
756 if (!Filters.empty()) { 864 if (!Filters.empty()) {
757 auto OSOrErr = Printer->createViewFile("functions", /*InToplevel=*/true); 865 // Build the map of filenames to functions.
758 if (Error E = OSOrErr.takeError()) { 866 std::map<llvm::StringRef, std::vector<const FunctionRecord *>>
759 error("Could not create view file!", toString(std::move(E))); 867 FilenameFunctionMap;
760 return 1; 868 for (const auto &SourceFile : SourceFiles)
761 } 869 for (const auto &Function : Coverage->getCoveredFunctions(SourceFile))
762 auto OS = std::move(OSOrErr.get()); 870 if (Filters.matches(*Coverage.get(), Function))
763 871 FilenameFunctionMap[SourceFile].push_back(&Function);
764 // Show functions. 872
765 for (const auto &Function : Coverage->getCoveredFunctions()) { 873 // Only print filter matching functions for each file.
766 if (!Filters.matches(Function)) 874 for (const auto &FileFunc : FilenameFunctionMap) {
767 continue; 875 StringRef File = FileFunc.first;
768 876 const auto &Functions = FileFunc.second;
769 auto mainView = createFunctionView(Function, *Coverage); 877
770 if (!mainView) { 878 auto OSOrErr = Printer->createViewFile(File, /*InToplevel=*/false);
771 warning("Could not read coverage for '" + Function.Name + "'."); 879 if (Error E = OSOrErr.takeError()) {
772 continue; 880 error("Could not create view file!", toString(std::move(E)));
881 return 1;
773 } 882 }
774 883 auto OS = std::move(OSOrErr.get());
775 mainView->print(*OS.get(), /*WholeFile=*/false, /*ShowSourceName=*/true); 884
776 } 885 bool ShowTitle = ViewOpts.hasOutputDirectory();
777 886 for (const auto *Function : Functions) {
778 Printer->closeViewFile(std::move(OS)); 887 auto FunctionView = createFunctionView(*Function, *Coverage);
888 if (!FunctionView) {
889 warning("Could not read coverage for '" + Function->Name + "'.");
890 continue;
891 }
892 FunctionView->print(*OS.get(), /*WholeFile=*/false,
893 /*ShowSourceName=*/true, ShowTitle);
894 ShowTitle = false;
895 }
896
897 Printer->closeViewFile(std::move(OS));
898 }
779 return 0; 899 return 0;
780 } 900 }
781 901
782 // Show files 902 // Show files
783 bool ShowFilenames = 903 bool ShowFilenames =
784 (SourceFiles.size() != 1) || ViewOpts.hasOutputDirectory() || 904 (SourceFiles.size() != 1) || ViewOpts.hasOutputDirectory() ||
785 (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML); 905 (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML);
786 906
787 if (SourceFiles.empty()) 907 // If NumThreads is not specified, auto-detect a good default.
788 // Get the source files from the function coverage mapping. 908 if (NumThreads == 0)
789 for (StringRef Filename : Coverage->getUniqueSourceFiles()) 909 NumThreads =
790 SourceFiles.push_back(Filename); 910 std::max(1U, std::min(llvm::heavyweight_hardware_concurrency(),
791 911 unsigned(SourceFiles.size())));
792 // Create an index out of the source files. 912
793 if (ViewOpts.hasOutputDirectory()) { 913 if (!ViewOpts.hasOutputDirectory() || NumThreads == 1) {
794 if (Error E = Printer->createIndexFile(SourceFiles, *Coverage)) {
795 error("Could not create index file!", toString(std::move(E)));
796 return 1;
797 }
798 }
799
800 // FIXME: Sink the hardware_concurrency() == 1 check into ThreadPool.
801 if (!ViewOpts.hasOutputDirectory() ||
802 std::thread::hardware_concurrency() == 1) {
803 for (const std::string &SourceFile : SourceFiles) 914 for (const std::string &SourceFile : SourceFiles)
804 writeSourceFileView(SourceFile, Coverage.get(), Printer.get(), 915 writeSourceFileView(SourceFile, Coverage.get(), Printer.get(),
805 ShowFilenames); 916 ShowFilenames);
806 } else { 917 } else {
807 // In -output-dir mode, it's safe to use multiple threads to print files. 918 // In -output-dir mode, it's safe to use multiple threads to print files.
808 ThreadPool Pool; 919 ThreadPool Pool(NumThreads);
809 for (const std::string &SourceFile : SourceFiles) 920 for (const std::string &SourceFile : SourceFiles)
810 Pool.async(&CodeCoverageTool::writeSourceFileView, this, SourceFile, 921 Pool.async(&CodeCoverageTool::writeSourceFileView, this, SourceFile,
811 Coverage.get(), Printer.get(), ShowFilenames); 922 Coverage.get(), Printer.get(), ShowFilenames);
812 Pool.wait(); 923 Pool.wait();
813 } 924 }
815 return 0; 926 return 0;
816 } 927 }
817 928
818 int CodeCoverageTool::report(int argc, const char **argv, 929 int CodeCoverageTool::report(int argc, const char **argv,
819 CommandLineParserType commandLineParser) { 930 CommandLineParserType commandLineParser) {
931 cl::opt<bool> ShowFunctionSummaries(
932 "show-functions", cl::Optional, cl::init(false),
933 cl::desc("Show coverage summaries for each function"));
934
820 auto Err = commandLineParser(argc, argv); 935 auto Err = commandLineParser(argc, argv);
821 if (Err) 936 if (Err)
822 return Err; 937 return Err;
823 938
824 if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML) 939 if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML) {
825 error("HTML output for summary reports is not yet supported."); 940 error("HTML output for summary reports is not yet supported.");
941 return 1;
942 }
826 943
827 auto Coverage = load(); 944 auto Coverage = load();
828 if (!Coverage) 945 if (!Coverage)
829 return 1; 946 return 1;
830 947
831 CoverageReport Report(ViewOpts, *Coverage.get()); 948 CoverageReport Report(ViewOpts, *Coverage.get());
832 if (SourceFiles.empty()) 949 if (!ShowFunctionSummaries) {
833 Report.renderFileReports(llvm::outs()); 950 if (SourceFiles.empty())
834 else 951 Report.renderFileReports(llvm::outs());
835 Report.renderFunctionReports(SourceFiles, llvm::outs()); 952 else
953 Report.renderFileReports(llvm::outs(), SourceFiles);
954 } else {
955 if (SourceFiles.empty()) {
956 error("Source files must be specified when -show-functions=true is "
957 "specified");
958 return 1;
959 }
960
961 Report.renderFunctionReports(SourceFiles, DC, llvm::outs());
962 }
836 return 0; 963 return 0;
837 } 964 }
838 965
839 int CodeCoverageTool::export_(int argc, const char **argv, 966 int CodeCoverageTool::export_(int argc, const char **argv,
840 CommandLineParserType commandLineParser) { 967 CommandLineParserType commandLineParser) {
841 968
842 auto Err = commandLineParser(argc, argv); 969 auto Err = commandLineParser(argc, argv);
843 if (Err) 970 if (Err)
844 return Err; 971 return Err;
972
973 if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text) {
974 error("Coverage data can only be exported as textual JSON.");
975 return 1;
976 }
845 977
846 auto Coverage = load(); 978 auto Coverage = load();
847 if (!Coverage) { 979 if (!Coverage) {
848 error("Could not load coverage information"); 980 error("Could not load coverage information");
849 return 1; 981 return 1;
850 } 982 }
851 983
852 exportCoverageDataToJson(*Coverage.get(), outs()); 984 exportCoverageDataToJson(*Coverage.get(), ViewOpts, outs());
853 985
854 return 0; 986 return 0;
855 } 987 }
856 988
857 int showMain(int argc, const char *argv[]) { 989 int showMain(int argc, const char *argv[]) {