Coverage Report

Created: 2017-10-03 07:32

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