1 //===- CodeCoverage.cpp - Coverage tool based on profiling instrumentation-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // The 'CodeCoverageTool' class implements a command line tool to analyze and 11 // report coverage information using the profiling instrumentation and code 12 // coverage mapping. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "CoverageFilters.h" 17 #include "CoverageReport.h" 18 #include "CoverageSummaryInfo.h" 19 #include "CoverageViewOptions.h" 20 #include "RenderingSupport.h" 21 #include "SourceCoverageView.h" 22 #include "llvm/ADT/SmallString.h" 23 #include "llvm/ADT/StringRef.h" 24 #include "llvm/ADT/Triple.h" 25 #include "llvm/ProfileData/Coverage/CoverageMapping.h" 26 #include "llvm/ProfileData/InstrProfReader.h" 27 #include "llvm/Support/CommandLine.h" 28 #include "llvm/Support/FileSystem.h" 29 #include "llvm/Support/Format.h" 30 #include "llvm/Support/MemoryBuffer.h" 31 #include "llvm/Support/Path.h" 32 #include "llvm/Support/Process.h" 33 #include "llvm/Support/Program.h" 34 #include "llvm/Support/ScopedPrinter.h" 35 #include "llvm/Support/Threading.h" 36 #include "llvm/Support/ThreadPool.h" 37 #include "llvm/Support/ToolOutputFile.h" 38 #include <functional> 39 #include <system_error> 40 41 using namespace llvm; 42 using namespace coverage; 43 44 void exportCoverageDataToJson(const coverage::CoverageMapping &CoverageMapping, 45 raw_ostream &OS); 46 47 namespace { 48 /// \brief The implementation of the coverage tool. 49 class CodeCoverageTool { 50 public: 51 enum Command { 52 /// \brief The show command. 53 Show, 54 /// \brief The report command. 55 Report, 56 /// \brief The export command. 57 Export 58 }; 59 60 int run(Command Cmd, int argc, const char **argv); 61 62 private: 63 /// \brief Print the error message to the error output stream. 64 void error(const Twine &Message, StringRef Whence = ""); 65 66 /// \brief Print the warning message to the error output stream. 67 void warning(const Twine &Message, StringRef Whence = ""); 68 69 /// \brief Convert \p Path into an absolute path and append it to the list 70 /// of collected paths. 71 void addCollectedPath(const std::string &Path); 72 73 /// \brief If \p Path is a regular file, collect the path. If it's a 74 /// directory, recursively collect all of the paths within the directory. 75 void collectPaths(const std::string &Path); 76 77 /// \brief Return a memory buffer for the given source file. 78 ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile); 79 80 /// \brief Create source views for the expansions of the view. 81 void attachExpansionSubViews(SourceCoverageView &View, 82 ArrayRef<ExpansionRecord> Expansions, 83 const CoverageMapping &Coverage); 84 85 /// \brief Create the source view of a particular function. 86 std::unique_ptr<SourceCoverageView> 87 createFunctionView(const FunctionRecord &Function, 88 const CoverageMapping &Coverage); 89 90 /// \brief Create the main source view of a particular source file. 91 std::unique_ptr<SourceCoverageView> 92 createSourceFileView(StringRef SourceFile, const CoverageMapping &Coverage); 93 94 /// \brief Load the coverage mapping data. Return nullptr if an error occurred. 95 std::unique_ptr<CoverageMapping> load(); 96 97 /// \brief Create a mapping from files in the Coverage data to local copies 98 /// (path-equivalence). 99 void remapPathNames(const CoverageMapping &Coverage); 100 101 /// \brief Remove input source files which aren't mapped by \p Coverage. 102 void removeUnmappedInputs(const CoverageMapping &Coverage); 103 104 /// \brief If a demangler is available, demangle all symbol names. 105 void demangleSymbols(const CoverageMapping &Coverage); 106 107 /// \brief Write out a source file view to the filesystem. 108 void writeSourceFileView(StringRef SourceFile, CoverageMapping *Coverage, 109 CoveragePrinter *Printer, bool ShowFilenames); 110 111 typedef llvm::function_ref<int(int, const char **)> CommandLineParserType; 112 113 int show(int argc, const char **argv, 114 CommandLineParserType commandLineParser); 115 116 int report(int argc, const char **argv, 117 CommandLineParserType commandLineParser); 118 119 int export_(int argc, const char **argv, 120 CommandLineParserType commandLineParser); 121 122 std::vector<StringRef> ObjectFilenames; 123 CoverageViewOptions ViewOpts; 124 CoverageFiltersMatchAll Filters; 125 126 /// The path to the indexed profile. 127 std::string PGOFilename; 128 129 /// A list of input source files. 130 std::vector<std::string> SourceFiles; 131 132 /// In -path-equivalence mode, this maps the absolute paths from the coverage 133 /// mapping data to the input source files. 134 StringMap<std::string> RemappedFilenames; 135 136 /// The coverage data path to be remapped from, and the source path to be 137 /// remapped to, when using -path-equivalence. 138 Optional<std::pair<std::string, std::string>> PathRemapping; 139 140 /// The architecture the coverage mapping data targets. 141 std::vector<StringRef> CoverageArches; 142 143 /// A cache for demangled symbols. 144 DemangleCache DC; 145 146 /// A lock which guards printing to stderr. 147 std::mutex ErrsLock; 148 149 /// A container for input source file buffers. 150 std::mutex LoadedSourceFilesLock; 151 std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>> 152 LoadedSourceFiles; 153 154 /// Whitelist from -name-whitelist to be used for filtering. 155 std::unique_ptr<SpecialCaseList> NameWhitelist; 156 }; 157 } 158 159 static std::string getErrorString(const Twine &Message, StringRef Whence, 160 bool Warning) { 161 std::string Str = (Warning ? "warning" : "error"); 162 Str += ": "; 163 if (!Whence.empty()) 164 Str += Whence.str() + ": "; 165 Str += Message.str() + "\n"; 166 return Str; 167 } 168 169 void CodeCoverageTool::error(const Twine &Message, StringRef Whence) { 170 std::unique_lock<std::mutex> Guard{ErrsLock}; 171 ViewOpts.colored_ostream(errs(), raw_ostream::RED) 172 << getErrorString(Message, Whence, false); 173 } 174 175 void CodeCoverageTool::warning(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, true); 179 } 180 181 void CodeCoverageTool::addCollectedPath(const std::string &Path) { 182 SmallString<128> EffectivePath(Path); 183 if (std::error_code EC = sys::fs::make_absolute(EffectivePath)) { 184 error(EC.message(), Path); 185 return; 186 } 187 sys::path::remove_dots(EffectivePath, /*remove_dot_dots=*/true); 188 SourceFiles.emplace_back(EffectivePath.str()); 189 } 190 191 void CodeCoverageTool::collectPaths(const std::string &Path) { 192 llvm::sys::fs::file_status Status; 193 llvm::sys::fs::status(Path, Status); 194 if (!llvm::sys::fs::exists(Status)) { 195 if (PathRemapping) 196 addCollectedPath(Path); 197 else 198 error("Missing source file", Path); 199 return; 200 } 201 202 if (llvm::sys::fs::is_regular_file(Status)) { 203 addCollectedPath(Path); 204 return; 205 } 206 207 if (llvm::sys::fs::is_directory(Status)) { 208 std::error_code EC; 209 for (llvm::sys::fs::recursive_directory_iterator F(Path, EC), E; 210 F != E && !EC; F.increment(EC)) { 211 if (llvm::sys::fs::is_regular_file(F->path())) 212 addCollectedPath(F->path()); 213 } 214 if (EC) 215 warning(EC.message(), Path); 216 } 217 } 218 219 ErrorOr<const MemoryBuffer &> 220 CodeCoverageTool::getSourceFile(StringRef SourceFile) { 221 // If we've remapped filenames, look up the real location for this file. 222 std::unique_lock<std::mutex> Guard{LoadedSourceFilesLock}; 223 if (!RemappedFilenames.empty()) { 224 auto Loc = RemappedFilenames.find(SourceFile); 225 if (Loc != RemappedFilenames.end()) 226 SourceFile = Loc->second; 227 } 228 for (const auto &Files : LoadedSourceFiles) 229 if (sys::fs::equivalent(SourceFile, Files.first)) 230 return *Files.second; 231 auto Buffer = MemoryBuffer::getFile(SourceFile); 232 if (auto EC = Buffer.getError()) { 233 error(EC.message(), SourceFile); 234 return EC; 235 } 236 LoadedSourceFiles.emplace_back(SourceFile, std::move(Buffer.get())); 237 return *LoadedSourceFiles.back().second; 238 } 239 240 void CodeCoverageTool::attachExpansionSubViews( 241 SourceCoverageView &View, ArrayRef<ExpansionRecord> Expansions, 242 const CoverageMapping &Coverage) { 243 if (!ViewOpts.ShowExpandedRegions) 244 return; 245 for (const auto &Expansion : Expansions) { 246 auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion); 247 if (ExpansionCoverage.empty()) 248 continue; 249 auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename()); 250 if (!SourceBuffer) 251 continue; 252 253 auto SubViewExpansions = ExpansionCoverage.getExpansions(); 254 auto SubView = 255 SourceCoverageView::create(Expansion.Function.Name, SourceBuffer.get(), 256 ViewOpts, std::move(ExpansionCoverage)); 257 attachExpansionSubViews(*SubView, SubViewExpansions, Coverage); 258 View.addExpansion(Expansion.Region, std::move(SubView)); 259 } 260 } 261 262 std::unique_ptr<SourceCoverageView> 263 CodeCoverageTool::createFunctionView(const FunctionRecord &Function, 264 const CoverageMapping &Coverage) { 265 auto FunctionCoverage = Coverage.getCoverageForFunction(Function); 266 if (FunctionCoverage.empty()) 267 return nullptr; 268 auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename()); 269 if (!SourceBuffer) 270 return nullptr; 271 272 auto Expansions = FunctionCoverage.getExpansions(); 273 auto View = SourceCoverageView::create(DC.demangle(Function.Name), 274 SourceBuffer.get(), ViewOpts, 275 std::move(FunctionCoverage)); 276 attachExpansionSubViews(*View, Expansions, Coverage); 277 278 return View; 279 } 280 281 std::unique_ptr<SourceCoverageView> 282 CodeCoverageTool::createSourceFileView(StringRef SourceFile, 283 const CoverageMapping &Coverage) { 284 auto SourceBuffer = getSourceFile(SourceFile); 285 if (!SourceBuffer) 286 return nullptr; 287 auto FileCoverage = Coverage.getCoverageForFile(SourceFile); 288 if (FileCoverage.empty()) 289 return nullptr; 290 291 auto Expansions = FileCoverage.getExpansions(); 292 auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(), 293 ViewOpts, std::move(FileCoverage)); 294 attachExpansionSubViews(*View, Expansions, Coverage); 295 if (!ViewOpts.ShowFunctionInstantiations) 296 return View; 297 298 for (const auto &Group : Coverage.getInstantiationGroups(SourceFile)) { 299 // Skip functions which have a single instantiation. 300 if (Group.size() < 2) 301 continue; 302 303 for (const FunctionRecord *Function : Group.getInstantiations()) { 304 std::unique_ptr<SourceCoverageView> SubView{nullptr}; 305 306 StringRef Funcname = DC.demangle(Function->Name); 307 308 if (Function->ExecutionCount > 0) { 309 auto SubViewCoverage = Coverage.getCoverageForFunction(*Function); 310 auto SubViewExpansions = SubViewCoverage.getExpansions(); 311 SubView = SourceCoverageView::create( 312 Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage)); 313 attachExpansionSubViews(*SubView, SubViewExpansions, Coverage); 314 } 315 316 unsigned FileID = Function->CountedRegions.front().FileID; 317 unsigned Line = 0; 318 for (const auto &CR : Function->CountedRegions) 319 if (CR.FileID == FileID) 320 Line = std::max(CR.LineEnd, Line); 321 View->addInstantiation(Funcname, Line, std::move(SubView)); 322 } 323 } 324 return View; 325 } 326 327 static bool modifiedTimeGT(StringRef LHS, StringRef RHS) { 328 sys::fs::file_status Status; 329 if (sys::fs::status(LHS, Status)) 330 return false; 331 auto LHSTime = Status.getLastModificationTime(); 332 if (sys::fs::status(RHS, Status)) 333 return false; 334 auto RHSTime = Status.getLastModificationTime(); 335 return LHSTime > RHSTime; 336 } 337 338 std::unique_ptr<CoverageMapping> CodeCoverageTool::load() { 339 for (StringRef ObjectFilename : ObjectFilenames) 340 if (modifiedTimeGT(ObjectFilename, PGOFilename)) 341 warning("profile data may be out of date - object is newer", 342 ObjectFilename); 343 auto CoverageOrErr = 344 CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArches); 345 if (Error E = CoverageOrErr.takeError()) { 346 error("Failed to load coverage: " + toString(std::move(E)), 347 join(ObjectFilenames.begin(), ObjectFilenames.end(), ", ")); 348 return nullptr; 349 } 350 auto Coverage = std::move(CoverageOrErr.get()); 351 unsigned Mismatched = Coverage->getMismatchedCount(); 352 if (Mismatched) 353 warning(utostr(Mismatched) + " functions have mismatched data"); 354 355 remapPathNames(*Coverage); 356 357 if (!SourceFiles.empty()) 358 removeUnmappedInputs(*Coverage); 359 360 demangleSymbols(*Coverage); 361 362 return Coverage; 363 } 364 365 void CodeCoverageTool::remapPathNames(const CoverageMapping &Coverage) { 366 if (!PathRemapping) 367 return; 368 369 // Convert remapping paths to native paths with trailing seperators. 370 auto nativeWithTrailing = [](StringRef Path) -> std::string { 371 if (Path.empty()) 372 return ""; 373 SmallString<128> NativePath; 374 sys::path::native(Path, NativePath); 375 if (!sys::path::is_separator(NativePath.back())) 376 NativePath += sys::path::get_separator(); 377 return NativePath.c_str(); 378 }; 379 std::string RemapFrom = nativeWithTrailing(PathRemapping->first); 380 std::string RemapTo = nativeWithTrailing(PathRemapping->second); 381 382 // Create a mapping from coverage data file paths to local paths. 383 for (StringRef Filename : Coverage.getUniqueSourceFiles()) { 384 SmallString<128> NativeFilename; 385 sys::path::native(Filename, NativeFilename); 386 if (NativeFilename.startswith(RemapFrom)) { 387 RemappedFilenames[Filename] = 388 RemapTo + NativeFilename.substr(RemapFrom.size()).str(); 389 } 390 } 391 392 // Convert input files from local paths to coverage data file paths. 393 StringMap<std::string> InvRemappedFilenames; 394 for (const auto &RemappedFilename : RemappedFilenames) 395 InvRemappedFilenames[RemappedFilename.getValue()] = RemappedFilename.getKey(); 396 397 for (std::string &Filename : SourceFiles) { 398 SmallString<128> NativeFilename; 399 sys::path::native(Filename, NativeFilename); 400 auto CovFileName = InvRemappedFilenames.find(NativeFilename); 401 if (CovFileName != InvRemappedFilenames.end()) 402 Filename = CovFileName->second; 403 } 404 } 405 406 void CodeCoverageTool::removeUnmappedInputs(const CoverageMapping &Coverage) { 407 std::vector<StringRef> CoveredFiles = Coverage.getUniqueSourceFiles(); 408 409 auto UncoveredFilesIt = SourceFiles.end(); 410 // The user may have specified source files which aren't in the coverage 411 // mapping. Filter these files away. 412 UncoveredFilesIt = std::remove_if( 413 SourceFiles.begin(), SourceFiles.end(), [&](const std::string &SF) { 414 return !std::binary_search(CoveredFiles.begin(), CoveredFiles.end(), 415 SF); 416 }); 417 418 SourceFiles.erase(UncoveredFilesIt, SourceFiles.end()); 419 } 420 421 void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) { 422 if (!ViewOpts.hasDemangler()) 423 return; 424 425 // Pass function names to the demangler in a temporary file. 426 int InputFD; 427 SmallString<256> InputPath; 428 std::error_code EC = 429 sys::fs::createTemporaryFile("demangle-in", "list", InputFD, InputPath); 430 if (EC) { 431 error(InputPath, EC.message()); 432 return; 433 } 434 tool_output_file InputTOF{InputPath, InputFD}; 435 436 unsigned NumSymbols = 0; 437 for (const auto &Function : Coverage.getCoveredFunctions()) { 438 InputTOF.os() << Function.Name << '\n'; 439 ++NumSymbols; 440 } 441 InputTOF.os().close(); 442 443 // Use another temporary file to store the demangler's output. 444 int OutputFD; 445 SmallString<256> OutputPath; 446 EC = sys::fs::createTemporaryFile("demangle-out", "list", OutputFD, 447 OutputPath); 448 if (EC) { 449 error(OutputPath, EC.message()); 450 return; 451 } 452 tool_output_file OutputTOF{OutputPath, OutputFD}; 453 OutputTOF.os().close(); 454 455 // Invoke the demangler. 456 std::vector<const char *> ArgsV; 457 for (const std::string &Arg : ViewOpts.DemanglerOpts) 458 ArgsV.push_back(Arg.c_str()); 459 ArgsV.push_back(nullptr); 460 StringRef InputPathRef = InputPath.str(); 461 StringRef OutputPathRef = OutputPath.str(); 462 StringRef StderrRef; 463 const StringRef *Redirects[] = {&InputPathRef, &OutputPathRef, &StderrRef}; 464 std::string ErrMsg; 465 int RC = sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV.data(), 466 /*env=*/nullptr, Redirects, /*secondsToWait=*/0, 467 /*memoryLimit=*/0, &ErrMsg); 468 if (RC) { 469 error(ErrMsg, ViewOpts.DemanglerOpts[0]); 470 return; 471 } 472 473 // Parse the demangler's output. 474 auto BufOrError = MemoryBuffer::getFile(OutputPath); 475 if (!BufOrError) { 476 error(OutputPath, BufOrError.getError().message()); 477 return; 478 } 479 480 std::unique_ptr<MemoryBuffer> DemanglerBuf = std::move(*BufOrError); 481 482 SmallVector<StringRef, 8> Symbols; 483 StringRef DemanglerData = DemanglerBuf->getBuffer(); 484 DemanglerData.split(Symbols, '\n', /*MaxSplit=*/NumSymbols, 485 /*KeepEmpty=*/false); 486 if (Symbols.size() != NumSymbols) { 487 error("Demangler did not provide expected number of symbols"); 488 return; 489 } 490 491 // Cache the demangled names. 492 unsigned I = 0; 493 for (const auto &Function : Coverage.getCoveredFunctions()) 494 // On Windows, lines in the demangler's output file end with "\r\n". 495 // Splitting by '\n' keeps '\r's, so cut them now. 496 DC.DemangledNames[Function.Name] = Symbols[I++].rtrim(); 497 } 498 499 void CodeCoverageTool::writeSourceFileView(StringRef SourceFile, 500 CoverageMapping *Coverage, 501 CoveragePrinter *Printer, 502 bool ShowFilenames) { 503 auto View = createSourceFileView(SourceFile, *Coverage); 504 if (!View) { 505 warning("The file '" + SourceFile + "' isn't covered."); 506 return; 507 } 508 509 auto OSOrErr = Printer->createViewFile(SourceFile, /*InToplevel=*/false); 510 if (Error E = OSOrErr.takeError()) { 511 error("Could not create view file!", toString(std::move(E))); 512 return; 513 } 514 auto OS = std::move(OSOrErr.get()); 515 516 View->print(*OS.get(), /*Wholefile=*/true, 517 /*ShowSourceName=*/ShowFilenames); 518 Printer->closeViewFile(std::move(OS)); 519 } 520 521 int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { 522 cl::opt<std::string> CovFilename( 523 cl::Positional, cl::desc("Covered executable or object file.")); 524 525 cl::list<std::string> CovFilenames( 526 "object", cl::desc("Coverage executable or object file"), cl::ZeroOrMore, 527 cl::CommaSeparated); 528 529 cl::list<std::string> InputSourceFiles( 530 cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore); 531 532 cl::opt<bool> DebugDumpCollectedPaths( 533 "dump-collected-paths", cl::Optional, cl::Hidden, 534 cl::desc("Show the collected paths to source files")); 535 536 cl::opt<std::string, true> PGOFilename( 537 "instr-profile", cl::Required, cl::location(this->PGOFilename), 538 cl::desc( 539 "File with the profile data obtained after an instrumented run")); 540 541 cl::list<std::string> Arches( 542 "arch", cl::desc("architectures of the coverage mapping binaries")); 543 544 cl::opt<bool> DebugDump("dump", cl::Optional, 545 cl::desc("Show internal debug dump")); 546 547 cl::opt<CoverageViewOptions::OutputFormat> Format( 548 "format", cl::desc("Output format for line-based coverage reports"), 549 cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text, "text", 550 "Text output"), 551 clEnumValN(CoverageViewOptions::OutputFormat::HTML, "html", 552 "HTML output")), 553 cl::init(CoverageViewOptions::OutputFormat::Text)); 554 555 cl::opt<std::string> PathRemap( 556 "path-equivalence", cl::Optional, 557 cl::desc("<from>,<to> Map coverage data paths to local source file " 558 "paths")); 559 560 cl::OptionCategory FilteringCategory("Function filtering options"); 561 562 cl::list<std::string> NameFilters( 563 "name", cl::Optional, 564 cl::desc("Show code coverage only for functions with the given name"), 565 cl::ZeroOrMore, cl::cat(FilteringCategory)); 566 567 cl::list<std::string> NameFilterFiles( 568 "name-whitelist", cl::Optional, 569 cl::desc("Show code coverage only for functions listed in the given " 570 "file"), 571 cl::ZeroOrMore, cl::cat(FilteringCategory)); 572 573 cl::list<std::string> NameRegexFilters( 574 "name-regex", cl::Optional, 575 cl::desc("Show code coverage only for functions that match the given " 576 "regular expression"), 577 cl::ZeroOrMore, cl::cat(FilteringCategory)); 578 579 cl::opt<double> RegionCoverageLtFilter( 580 "region-coverage-lt", cl::Optional, 581 cl::desc("Show code coverage only for functions with region coverage " 582 "less than the given threshold"), 583 cl::cat(FilteringCategory)); 584 585 cl::opt<double> RegionCoverageGtFilter( 586 "region-coverage-gt", cl::Optional, 587 cl::desc("Show code coverage only for functions with region coverage " 588 "greater than the given threshold"), 589 cl::cat(FilteringCategory)); 590 591 cl::opt<double> LineCoverageLtFilter( 592 "line-coverage-lt", cl::Optional, 593 cl::desc("Show code coverage only for functions with line coverage less " 594 "than the given threshold"), 595 cl::cat(FilteringCategory)); 596 597 cl::opt<double> LineCoverageGtFilter( 598 "line-coverage-gt", cl::Optional, 599 cl::desc("Show code coverage only for functions with line coverage " 600 "greater than the given threshold"), 601 cl::cat(FilteringCategory)); 602 603 cl::opt<cl::boolOrDefault> UseColor( 604 "use-color", cl::desc("Emit colored output (default=autodetect)"), 605 cl::init(cl::BOU_UNSET)); 606 607 cl::list<std::string> DemanglerOpts( 608 "Xdemangler", cl::desc("<demangler-path>|<demangler-option>")); 609 610 auto commandLineParser = [&, this](int argc, const char **argv) -> int { 611 cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); 612 ViewOpts.Debug = DebugDump; 613 614 if (!CovFilename.empty()) 615 ObjectFilenames.emplace_back(CovFilename); 616 for (const std::string &Filename : CovFilenames) 617 ObjectFilenames.emplace_back(Filename); 618 if (ObjectFilenames.empty()) { 619 errs() << "No filenames specified!\n"; 620 ::exit(1); 621 } 622 623 ViewOpts.Format = Format; 624 switch (ViewOpts.Format) { 625 case CoverageViewOptions::OutputFormat::Text: 626 ViewOpts.Colors = UseColor == cl::BOU_UNSET 627 ? sys::Process::StandardOutHasColors() 628 : UseColor == cl::BOU_TRUE; 629 break; 630 case CoverageViewOptions::OutputFormat::HTML: 631 if (UseColor == cl::BOU_FALSE) 632 errs() << "Color output cannot be disabled when generating html.\n"; 633 ViewOpts.Colors = true; 634 break; 635 } 636 637 // If path-equivalence was given and is a comma seperated pair then set 638 // PathRemapping. 639 auto EquivPair = StringRef(PathRemap).split(','); 640 if (!(EquivPair.first.empty() && EquivPair.second.empty())) 641 PathRemapping = EquivPair; 642 643 // If a demangler is supplied, check if it exists and register it. 644 if (DemanglerOpts.size()) { 645 auto DemanglerPathOrErr = sys::findProgramByName(DemanglerOpts[0]); 646 if (!DemanglerPathOrErr) { 647 error("Could not find the demangler!", 648 DemanglerPathOrErr.getError().message()); 649 return 1; 650 } 651 DemanglerOpts[0] = *DemanglerPathOrErr; 652 ViewOpts.DemanglerOpts.swap(DemanglerOpts); 653 } 654 655 // Read in -name-whitelist files. 656 if (!NameFilterFiles.empty()) { 657 std::string SpecialCaseListErr; 658 NameWhitelist = 659 SpecialCaseList::create(NameFilterFiles, SpecialCaseListErr); 660 if (!NameWhitelist) 661 error(SpecialCaseListErr); 662 } 663 664 // Create the function filters 665 if (!NameFilters.empty() || NameWhitelist || !NameRegexFilters.empty()) { 666 auto NameFilterer = llvm::make_unique<CoverageFilters>(); 667 for (const auto &Name : NameFilters) 668 NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name)); 669 if (NameWhitelist) 670 NameFilterer->push_back( 671 llvm::make_unique<NameWhitelistCoverageFilter>(*NameWhitelist)); 672 for (const auto &Regex : NameRegexFilters) 673 NameFilterer->push_back( 674 llvm::make_unique<NameRegexCoverageFilter>(Regex)); 675 Filters.push_back(std::move(NameFilterer)); 676 } 677 if (RegionCoverageLtFilter.getNumOccurrences() || 678 RegionCoverageGtFilter.getNumOccurrences() || 679 LineCoverageLtFilter.getNumOccurrences() || 680 LineCoverageGtFilter.getNumOccurrences()) { 681 auto StatFilterer = llvm::make_unique<CoverageFilters>(); 682 if (RegionCoverageLtFilter.getNumOccurrences()) 683 StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>( 684 RegionCoverageFilter::LessThan, RegionCoverageLtFilter)); 685 if (RegionCoverageGtFilter.getNumOccurrences()) 686 StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>( 687 RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter)); 688 if (LineCoverageLtFilter.getNumOccurrences()) 689 StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>( 690 LineCoverageFilter::LessThan, LineCoverageLtFilter)); 691 if (LineCoverageGtFilter.getNumOccurrences()) 692 StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>( 693 RegionCoverageFilter::GreaterThan, LineCoverageGtFilter)); 694 Filters.push_back(std::move(StatFilterer)); 695 } 696 697 if (!Arches.empty()) { 698 for (const std::string &Arch : Arches) { 699 if (Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) { 700 error("Unknown architecture: " + Arch); 701 return 1; 702 } 703 CoverageArches.emplace_back(Arch); 704 } 705 if (CoverageArches.size() != ObjectFilenames.size()) { 706 error("Number of architectures doesn't match the number of objects"); 707 return 1; 708 } 709 } 710 711 for (const std::string &File : InputSourceFiles) 712 collectPaths(File); 713 714 if (DebugDumpCollectedPaths) { 715 for (const std::string &SF : SourceFiles) 716 outs() << SF << '\n'; 717 ::exit(0); 718 } 719 720 return 0; 721 }; 722 723 switch (Cmd) { 724 case Show: 725 return show(argc, argv, commandLineParser); 726 case Report: 727 return report(argc, argv, commandLineParser); 728 case Export: 729 return export_(argc, argv, commandLineParser); 730 } 731 return 0; 732 } 733 734 int CodeCoverageTool::show(int argc, const char **argv, 735 CommandLineParserType commandLineParser) { 736 737 cl::OptionCategory ViewCategory("Viewing options"); 738 739 cl::opt<bool> ShowLineExecutionCounts( 740 "show-line-counts", cl::Optional, 741 cl::desc("Show the execution counts for each line"), cl::init(true), 742 cl::cat(ViewCategory)); 743 744 cl::opt<bool> ShowRegions( 745 "show-regions", cl::Optional, 746 cl::desc("Show the execution counts for each region"), 747 cl::cat(ViewCategory)); 748 749 cl::opt<bool> ShowBestLineRegionsCounts( 750 "show-line-counts-or-regions", cl::Optional, 751 cl::desc("Show the execution counts for each line, or the execution " 752 "counts for each region on lines that have multiple regions"), 753 cl::cat(ViewCategory)); 754 755 cl::opt<bool> ShowExpansions("show-expansions", cl::Optional, 756 cl::desc("Show expanded source regions"), 757 cl::cat(ViewCategory)); 758 759 cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional, 760 cl::desc("Show function instantiations"), 761 cl::init(true), cl::cat(ViewCategory)); 762 763 cl::opt<std::string> ShowOutputDirectory( 764 "output-dir", cl::init(""), 765 cl::desc("Directory in which coverage information is written out")); 766 cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"), 767 cl::aliasopt(ShowOutputDirectory)); 768 769 cl::opt<uint32_t> TabSize( 770 "tab-size", cl::init(2), 771 cl::desc( 772 "Set tab expansion size for html coverage reports (default = 2)")); 773 774 cl::opt<std::string> ProjectTitle( 775 "project-title", cl::Optional, 776 cl::desc("Set project title for the coverage report")); 777 778 cl::opt<unsigned> NumThreads( 779 "num-threads", cl::init(0), 780 cl::desc("Number of merge threads to use (default: autodetect)")); 781 cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"), 782 cl::aliasopt(NumThreads)); 783 784 auto Err = commandLineParser(argc, argv); 785 if (Err) 786 return Err; 787 788 ViewOpts.ShowLineNumbers = true; 789 ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 || 790 !ShowRegions || ShowBestLineRegionsCounts; 791 ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts; 792 ViewOpts.ShowExpandedRegions = ShowExpansions; 793 ViewOpts.ShowFunctionInstantiations = ShowInstantiations; 794 ViewOpts.ShowOutputDirectory = ShowOutputDirectory; 795 ViewOpts.TabSize = TabSize; 796 ViewOpts.ProjectTitle = ProjectTitle; 797 798 if (ViewOpts.hasOutputDirectory()) { 799 if (auto E = sys::fs::create_directories(ViewOpts.ShowOutputDirectory)) { 800 error("Could not create output directory!", E.message()); 801 return 1; 802 } 803 } 804 805 sys::fs::file_status Status; 806 if (sys::fs::status(PGOFilename, Status)) { 807 error("profdata file error: can not get the file status. \n"); 808 return 1; 809 } 810 811 auto ModifiedTime = Status.getLastModificationTime(); 812 std::string ModifiedTimeStr = to_string(ModifiedTime); 813 size_t found = ModifiedTimeStr.rfind(':'); 814 ViewOpts.CreatedTimeStr = (found != std::string::npos) 815 ? "Created: " + ModifiedTimeStr.substr(0, found) 816 : "Created: " + ModifiedTimeStr; 817 818 auto Coverage = load(); 819 if (!Coverage) 820 return 1; 821 822 auto Printer = CoveragePrinter::create(ViewOpts); 823 824 if (!Filters.empty()) { 825 auto OSOrErr = Printer->createViewFile("functions", /*InToplevel=*/true); 826 if (Error E = OSOrErr.takeError()) { 827 error("Could not create view file!", toString(std::move(E))); 828 return 1; 829 } 830 auto OS = std::move(OSOrErr.get()); 831 832 // Show functions. 833 for (const auto &Function : Coverage->getCoveredFunctions()) { 834 if (!Filters.matches(Function)) 835 continue; 836 837 auto mainView = createFunctionView(Function, *Coverage); 838 if (!mainView) { 839 warning("Could not read coverage for '" + Function.Name + "'."); 840 continue; 841 } 842 843 mainView->print(*OS.get(), /*WholeFile=*/false, /*ShowSourceName=*/true); 844 } 845 846 Printer->closeViewFile(std::move(OS)); 847 return 0; 848 } 849 850 // Show files 851 bool ShowFilenames = 852 (SourceFiles.size() != 1) || ViewOpts.hasOutputDirectory() || 853 (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML); 854 855 if (SourceFiles.empty()) 856 // Get the source files from the function coverage mapping. 857 for (StringRef Filename : Coverage->getUniqueSourceFiles()) 858 SourceFiles.push_back(Filename); 859 860 // Create an index out of the source files. 861 if (ViewOpts.hasOutputDirectory()) { 862 if (Error E = Printer->createIndexFile(SourceFiles, *Coverage)) { 863 error("Could not create index file!", toString(std::move(E))); 864 return 1; 865 } 866 } 867 868 // If NumThreads is not specified, auto-detect a good default. 869 if (NumThreads == 0) 870 NumThreads = 871 std::max(1U, std::min(llvm::heavyweight_hardware_concurrency(), 872 unsigned(SourceFiles.size()))); 873 874 if (!ViewOpts.hasOutputDirectory() || NumThreads == 1) { 875 for (const std::string &SourceFile : SourceFiles) 876 writeSourceFileView(SourceFile, Coverage.get(), Printer.get(), 877 ShowFilenames); 878 } else { 879 // In -output-dir mode, it's safe to use multiple threads to print files. 880 ThreadPool Pool(NumThreads); 881 for (const std::string &SourceFile : SourceFiles) 882 Pool.async(&CodeCoverageTool::writeSourceFileView, this, SourceFile, 883 Coverage.get(), Printer.get(), ShowFilenames); 884 Pool.wait(); 885 } 886 887 return 0; 888 } 889 890 int CodeCoverageTool::report(int argc, const char **argv, 891 CommandLineParserType commandLineParser) { 892 cl::opt<bool> ShowFunctionSummaries( 893 "show-functions", cl::Optional, cl::init(false), 894 cl::desc("Show coverage summaries for each function")); 895 896 auto Err = commandLineParser(argc, argv); 897 if (Err) 898 return Err; 899 900 if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML) { 901 error("HTML output for summary reports is not yet supported."); 902 return 1; 903 } 904 905 auto Coverage = load(); 906 if (!Coverage) 907 return 1; 908 909 CoverageReport Report(ViewOpts, *Coverage.get()); 910 if (!ShowFunctionSummaries) 911 Report.renderFileReports(llvm::outs()); 912 else 913 Report.renderFunctionReports(SourceFiles, DC, llvm::outs()); 914 return 0; 915 } 916 917 int CodeCoverageTool::export_(int argc, const char **argv, 918 CommandLineParserType commandLineParser) { 919 920 auto Err = commandLineParser(argc, argv); 921 if (Err) 922 return Err; 923 924 if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text) { 925 error("Coverage data can only be exported as textual JSON."); 926 return 1; 927 } 928 929 auto Coverage = load(); 930 if (!Coverage) { 931 error("Could not load coverage information"); 932 return 1; 933 } 934 935 exportCoverageDataToJson(*Coverage.get(), outs()); 936 937 return 0; 938 } 939 940 int showMain(int argc, const char *argv[]) { 941 CodeCoverageTool Tool; 942 return Tool.run(CodeCoverageTool::Show, argc, argv); 943 } 944 945 int reportMain(int argc, const char *argv[]) { 946 CodeCoverageTool Tool; 947 return Tool.run(CodeCoverageTool::Report, argc, argv); 948 } 949 950 int exportMain(int argc, const char *argv[]) { 951 CodeCoverageTool Tool; 952 return Tool.run(CodeCoverageTool::Export, argc, argv); 953 } 954