CodeCoverage.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  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. #include "RenderingSupport.h"
  16. #include "CoverageFilters.h"
  17. #include "CoverageReport.h"
  18. #include "CoverageViewOptions.h"
  19. #include "SourceCoverageView.h"
  20. #include "llvm/ADT/SmallString.h"
  21. #include "llvm/ADT/StringRef.h"
  22. #include "llvm/ADT/Triple.h"
  23. #include "llvm/ProfileData/CoverageMapping.h"
  24. #include "llvm/ProfileData/InstrProfReader.h"
  25. #include "llvm/Support/CommandLine.h"
  26. #include "llvm/Support/FileSystem.h"
  27. #include "llvm/Support/Format.h"
  28. #include "llvm/Support/ManagedStatic.h"
  29. #include "llvm/Support/Path.h"
  30. #include "llvm/Support/PrettyStackTrace.h"
  31. #include "llvm/Support/Process.h"
  32. #include "llvm/Support/Signals.h"
  33. #include <functional>
  34. #include <system_error>
  35. using namespace llvm;
  36. using namespace coverage;
  37. namespace {
  38. /// \brief The implementation of the coverage tool.
  39. class CodeCoverageTool {
  40. public:
  41. enum Command {
  42. /// \brief The show command.
  43. Show,
  44. /// \brief The report command.
  45. Report
  46. };
  47. /// \brief Print the error message to the error output stream.
  48. void error(const Twine &Message, StringRef Whence = "");
  49. /// \brief Return a memory buffer for the given source file.
  50. ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
  51. /// \brief Create source views for the expansions of the view.
  52. void attachExpansionSubViews(SourceCoverageView &View,
  53. ArrayRef<ExpansionRecord> Expansions,
  54. CoverageMapping &Coverage);
  55. /// \brief Create the source view of a particular function.
  56. std::unique_ptr<SourceCoverageView>
  57. createFunctionView(const FunctionRecord &Function, CoverageMapping &Coverage);
  58. /// \brief Create the main source view of a particular source file.
  59. std::unique_ptr<SourceCoverageView>
  60. createSourceFileView(StringRef SourceFile, CoverageMapping &Coverage);
  61. /// \brief Load the coverage mapping data. Return true if an error occured.
  62. std::unique_ptr<CoverageMapping> load();
  63. int run(Command Cmd, int argc, const char **argv);
  64. typedef std::function<int(int, const char **)> CommandLineParserType;
  65. int show(int argc, const char **argv,
  66. CommandLineParserType commandLineParser);
  67. int report(int argc, const char **argv,
  68. CommandLineParserType commandLineParser);
  69. std::string ObjectFilename;
  70. CoverageViewOptions ViewOpts;
  71. std::string PGOFilename;
  72. CoverageFiltersMatchAll Filters;
  73. std::vector<std::string> SourceFiles;
  74. std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
  75. LoadedSourceFiles;
  76. bool CompareFilenamesOnly;
  77. StringMap<std::string> RemappedFilenames;
  78. std::string CoverageArch;
  79. };
  80. }
  81. void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
  82. errs() << "error: ";
  83. if (!Whence.empty())
  84. errs() << Whence << ": ";
  85. errs() << Message << "\n";
  86. }
  87. ErrorOr<const MemoryBuffer &>
  88. CodeCoverageTool::getSourceFile(StringRef SourceFile) {
  89. // If we've remapped filenames, look up the real location for this file.
  90. if (!RemappedFilenames.empty()) {
  91. auto Loc = RemappedFilenames.find(SourceFile);
  92. if (Loc != RemappedFilenames.end())
  93. SourceFile = Loc->second;
  94. }
  95. for (const auto &Files : LoadedSourceFiles)
  96. if (sys::fs::equivalent(SourceFile, Files.first))
  97. return *Files.second;
  98. auto Buffer = MemoryBuffer::getFile(SourceFile);
  99. if (auto EC = Buffer.getError()) {
  100. error(EC.message(), SourceFile);
  101. return EC;
  102. }
  103. LoadedSourceFiles.emplace_back(SourceFile, std::move(Buffer.get()));
  104. return *LoadedSourceFiles.back().second;
  105. }
  106. void
  107. CodeCoverageTool::attachExpansionSubViews(SourceCoverageView &View,
  108. ArrayRef<ExpansionRecord> Expansions,
  109. CoverageMapping &Coverage) {
  110. if (!ViewOpts.ShowExpandedRegions)
  111. return;
  112. for (const auto &Expansion : Expansions) {
  113. auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
  114. if (ExpansionCoverage.empty())
  115. continue;
  116. auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename());
  117. if (!SourceBuffer)
  118. continue;
  119. auto SubViewExpansions = ExpansionCoverage.getExpansions();
  120. auto SubView = llvm::make_unique<SourceCoverageView>(
  121. SourceBuffer.get(), ViewOpts, std::move(ExpansionCoverage));
  122. attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
  123. View.addExpansion(Expansion.Region, std::move(SubView));
  124. }
  125. }
  126. std::unique_ptr<SourceCoverageView>
  127. CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
  128. CoverageMapping &Coverage) {
  129. auto FunctionCoverage = Coverage.getCoverageForFunction(Function);
  130. if (FunctionCoverage.empty())
  131. return nullptr;
  132. auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename());
  133. if (!SourceBuffer)
  134. return nullptr;
  135. auto Expansions = FunctionCoverage.getExpansions();
  136. auto View = llvm::make_unique<SourceCoverageView>(
  137. SourceBuffer.get(), ViewOpts, std::move(FunctionCoverage));
  138. attachExpansionSubViews(*View, Expansions, Coverage);
  139. return View;
  140. }
  141. std::unique_ptr<SourceCoverageView>
  142. CodeCoverageTool::createSourceFileView(StringRef SourceFile,
  143. CoverageMapping &Coverage) {
  144. auto SourceBuffer = getSourceFile(SourceFile);
  145. if (!SourceBuffer)
  146. return nullptr;
  147. auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
  148. if (FileCoverage.empty())
  149. return nullptr;
  150. auto Expansions = FileCoverage.getExpansions();
  151. auto View = llvm::make_unique<SourceCoverageView>(
  152. SourceBuffer.get(), ViewOpts, std::move(FileCoverage));
  153. attachExpansionSubViews(*View, Expansions, Coverage);
  154. for (auto Function : Coverage.getInstantiations(SourceFile)) {
  155. auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
  156. auto SubViewExpansions = SubViewCoverage.getExpansions();
  157. auto SubView = llvm::make_unique<SourceCoverageView>(
  158. SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
  159. attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
  160. if (SubView) {
  161. unsigned FileID = Function->CountedRegions.front().FileID;
  162. unsigned Line = 0;
  163. for (const auto &CR : Function->CountedRegions)
  164. if (CR.FileID == FileID)
  165. Line = std::max(CR.LineEnd, Line);
  166. View->addInstantiation(Function->Name, Line, std::move(SubView));
  167. }
  168. }
  169. return View;
  170. }
  171. static bool modifiedTimeGT(StringRef LHS, StringRef RHS) {
  172. sys::fs::file_status Status;
  173. if (sys::fs::status(LHS, Status))
  174. return false;
  175. auto LHSTime = Status.getLastModificationTime();
  176. if (sys::fs::status(RHS, Status))
  177. return false;
  178. auto RHSTime = Status.getLastModificationTime();
  179. return LHSTime > RHSTime;
  180. }
  181. std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
  182. if (modifiedTimeGT(ObjectFilename, PGOFilename))
  183. errs() << "warning: profile data may be out of date - object is newer\n";
  184. auto CoverageOrErr = CoverageMapping::load(ObjectFilename, PGOFilename,
  185. CoverageArch);
  186. if (std::error_code EC = CoverageOrErr.getError()) {
  187. colored_ostream(errs(), raw_ostream::RED)
  188. << "error: Failed to load coverage: " << EC.message();
  189. errs() << "\n";
  190. return nullptr;
  191. }
  192. auto Coverage = std::move(CoverageOrErr.get());
  193. unsigned Mismatched = Coverage->getMismatchedCount();
  194. if (Mismatched) {
  195. colored_ostream(errs(), raw_ostream::RED)
  196. << "warning: " << Mismatched << " functions have mismatched data. ";
  197. errs() << "\n";
  198. }
  199. if (CompareFilenamesOnly) {
  200. auto CoveredFiles = Coverage.get()->getUniqueSourceFiles();
  201. for (auto &SF : SourceFiles) {
  202. StringRef SFBase = sys::path::filename(SF);
  203. for (const auto &CF : CoveredFiles)
  204. if (SFBase == sys::path::filename(CF)) {
  205. RemappedFilenames[CF] = SF;
  206. SF = CF;
  207. break;
  208. }
  209. }
  210. }
  211. return Coverage;
  212. }
  213. int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
  214. // Print a stack trace if we signal out.
  215. sys::PrintStackTraceOnErrorSignal();
  216. PrettyStackTraceProgram X(argc, argv);
  217. llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
  218. cl::opt<std::string, true> ObjectFilename(
  219. cl::Positional, cl::Required, cl::location(this->ObjectFilename),
  220. cl::desc("Covered executable or object file."));
  221. cl::list<std::string> InputSourceFiles(
  222. cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore);
  223. cl::opt<std::string, true> PGOFilename(
  224. "instr-profile", cl::Required, cl::location(this->PGOFilename),
  225. cl::desc(
  226. "File with the profile data obtained after an instrumented run"));
  227. cl::opt<std::string> Arch(
  228. "arch", cl::desc("architecture of the coverage mapping binary"));
  229. cl::opt<bool> DebugDump("dump", cl::Optional,
  230. cl::desc("Show internal debug dump"));
  231. cl::opt<bool> FilenameEquivalence(
  232. "filename-equivalence", cl::Optional,
  233. cl::desc("Treat source files as equivalent to paths in the coverage data "
  234. "when the file names match, even if the full paths do not"));
  235. cl::OptionCategory FilteringCategory("Function filtering options");
  236. cl::list<std::string> NameFilters(
  237. "name", cl::Optional,
  238. cl::desc("Show code coverage only for functions with the given name"),
  239. cl::ZeroOrMore, cl::cat(FilteringCategory));
  240. cl::list<std::string> NameRegexFilters(
  241. "name-regex", cl::Optional,
  242. cl::desc("Show code coverage only for functions that match the given "
  243. "regular expression"),
  244. cl::ZeroOrMore, cl::cat(FilteringCategory));
  245. cl::opt<double> RegionCoverageLtFilter(
  246. "region-coverage-lt", cl::Optional,
  247. cl::desc("Show code coverage only for functions with region coverage "
  248. "less than the given threshold"),
  249. cl::cat(FilteringCategory));
  250. cl::opt<double> RegionCoverageGtFilter(
  251. "region-coverage-gt", cl::Optional,
  252. cl::desc("Show code coverage only for functions with region coverage "
  253. "greater than the given threshold"),
  254. cl::cat(FilteringCategory));
  255. cl::opt<double> LineCoverageLtFilter(
  256. "line-coverage-lt", cl::Optional,
  257. cl::desc("Show code coverage only for functions with line coverage less "
  258. "than the given threshold"),
  259. cl::cat(FilteringCategory));
  260. cl::opt<double> LineCoverageGtFilter(
  261. "line-coverage-gt", cl::Optional,
  262. cl::desc("Show code coverage only for functions with line coverage "
  263. "greater than the given threshold"),
  264. cl::cat(FilteringCategory));
  265. cl::opt<cl::boolOrDefault> UseColor(
  266. "use-color", cl::desc("Emit colored output (default=autodetect)"),
  267. cl::init(cl::BOU_UNSET));
  268. auto commandLineParser = [&, this](int argc, const char **argv) -> int {
  269. cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
  270. ViewOpts.Debug = DebugDump;
  271. CompareFilenamesOnly = FilenameEquivalence;
  272. ViewOpts.Colors = UseColor == cl::BOU_UNSET
  273. ? sys::Process::StandardOutHasColors()
  274. : UseColor == cl::BOU_TRUE;
  275. // Create the function filters
  276. if (!NameFilters.empty() || !NameRegexFilters.empty()) {
  277. auto NameFilterer = new CoverageFilters;
  278. for (const auto &Name : NameFilters)
  279. NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name));
  280. for (const auto &Regex : NameRegexFilters)
  281. NameFilterer->push_back(
  282. llvm::make_unique<NameRegexCoverageFilter>(Regex));
  283. Filters.push_back(std::unique_ptr<CoverageFilter>(NameFilterer));
  284. }
  285. if (RegionCoverageLtFilter.getNumOccurrences() ||
  286. RegionCoverageGtFilter.getNumOccurrences() ||
  287. LineCoverageLtFilter.getNumOccurrences() ||
  288. LineCoverageGtFilter.getNumOccurrences()) {
  289. auto StatFilterer = new CoverageFilters;
  290. if (RegionCoverageLtFilter.getNumOccurrences())
  291. StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
  292. RegionCoverageFilter::LessThan, RegionCoverageLtFilter));
  293. if (RegionCoverageGtFilter.getNumOccurrences())
  294. StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
  295. RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter));
  296. if (LineCoverageLtFilter.getNumOccurrences())
  297. StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
  298. LineCoverageFilter::LessThan, LineCoverageLtFilter));
  299. if (LineCoverageGtFilter.getNumOccurrences())
  300. StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
  301. RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
  302. Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer));
  303. }
  304. if (!Arch.empty() &&
  305. Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) {
  306. errs() << "error: Unknown architecture: " << Arch << "\n";
  307. return 1;
  308. }
  309. CoverageArch = Arch;
  310. for (const auto &File : InputSourceFiles) {
  311. SmallString<128> Path(File);
  312. if (!CompareFilenamesOnly)
  313. if (std::error_code EC = sys::fs::make_absolute(Path)) {
  314. errs() << "error: " << File << ": " << EC.message();
  315. return 1;
  316. }
  317. SourceFiles.push_back(Path.str());
  318. }
  319. return 0;
  320. };
  321. switch (Cmd) {
  322. case Show:
  323. return show(argc, argv, commandLineParser);
  324. case Report:
  325. return report(argc, argv, commandLineParser);
  326. }
  327. return 0;
  328. }
  329. int CodeCoverageTool::show(int argc, const char **argv,
  330. CommandLineParserType commandLineParser) {
  331. cl::OptionCategory ViewCategory("Viewing options");
  332. cl::opt<bool> ShowLineExecutionCounts(
  333. "show-line-counts", cl::Optional,
  334. cl::desc("Show the execution counts for each line"), cl::init(true),
  335. cl::cat(ViewCategory));
  336. cl::opt<bool> ShowRegions(
  337. "show-regions", cl::Optional,
  338. cl::desc("Show the execution counts for each region"),
  339. cl::cat(ViewCategory));
  340. cl::opt<bool> ShowBestLineRegionsCounts(
  341. "show-line-counts-or-regions", cl::Optional,
  342. cl::desc("Show the execution counts for each line, or the execution "
  343. "counts for each region on lines that have multiple regions"),
  344. cl::cat(ViewCategory));
  345. cl::opt<bool> ShowExpansions("show-expansions", cl::Optional,
  346. cl::desc("Show expanded source regions"),
  347. cl::cat(ViewCategory));
  348. cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional,
  349. cl::desc("Show function instantiations"),
  350. cl::cat(ViewCategory));
  351. auto Err = commandLineParser(argc, argv);
  352. if (Err)
  353. return Err;
  354. ViewOpts.ShowLineNumbers = true;
  355. ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
  356. !ShowRegions || ShowBestLineRegionsCounts;
  357. ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
  358. ViewOpts.ShowLineStatsOrRegionMarkers = ShowBestLineRegionsCounts;
  359. ViewOpts.ShowExpandedRegions = ShowExpansions;
  360. ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
  361. auto Coverage = load();
  362. if (!Coverage)
  363. return 1;
  364. if (!Filters.empty()) {
  365. // Show functions
  366. for (const auto &Function : Coverage->getCoveredFunctions()) {
  367. if (!Filters.matches(Function))
  368. continue;
  369. auto mainView = createFunctionView(Function, *Coverage);
  370. if (!mainView) {
  371. ViewOpts.colored_ostream(outs(), raw_ostream::RED)
  372. << "warning: Could not read coverage for '" << Function.Name;
  373. outs() << "\n";
  374. continue;
  375. }
  376. ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << Function.Name
  377. << ":";
  378. outs() << "\n";
  379. mainView->render(outs(), /*WholeFile=*/false);
  380. outs() << "\n";
  381. }
  382. return 0;
  383. }
  384. // Show files
  385. bool ShowFilenames = SourceFiles.size() != 1;
  386. if (SourceFiles.empty())
  387. // Get the source files from the function coverage mapping
  388. for (StringRef Filename : Coverage->getUniqueSourceFiles())
  389. SourceFiles.push_back(Filename);
  390. for (const auto &SourceFile : SourceFiles) {
  391. auto mainView = createSourceFileView(SourceFile, *Coverage);
  392. if (!mainView) {
  393. ViewOpts.colored_ostream(outs(), raw_ostream::RED)
  394. << "warning: The file '" << SourceFile << "' isn't covered.";
  395. outs() << "\n";
  396. continue;
  397. }
  398. if (ShowFilenames) {
  399. ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << SourceFile << ":";
  400. outs() << "\n";
  401. }
  402. mainView->render(outs(), /*Wholefile=*/true);
  403. if (SourceFiles.size() > 1)
  404. outs() << "\n";
  405. }
  406. return 0;
  407. }
  408. int CodeCoverageTool::report(int argc, const char **argv,
  409. CommandLineParserType commandLineParser) {
  410. auto Err = commandLineParser(argc, argv);
  411. if (Err)
  412. return Err;
  413. auto Coverage = load();
  414. if (!Coverage)
  415. return 1;
  416. CoverageReport Report(ViewOpts, std::move(Coverage));
  417. if (SourceFiles.empty())
  418. Report.renderFileReports(llvm::outs());
  419. else
  420. Report.renderFunctionReports(SourceFiles, llvm::outs());
  421. return 0;
  422. }
  423. int showMain(int argc, const char *argv[]) {
  424. CodeCoverageTool Tool;
  425. return Tool.run(CodeCoverageTool::Show, argc, argv);
  426. }
  427. int reportMain(int argc, const char *argv[]) {
  428. CodeCoverageTool Tool;
  429. return Tool.run(CodeCoverageTool::Report, argc, argv);
  430. }