Statistics.cpp revision 360784
1#include "llvm/ADT/DenseMap.h"
2#include "llvm/ADT/StringExtras.h"
3#include "llvm/ADT/StringSet.h"
4#include "llvm/DebugInfo/DIContext.h"
5#include "llvm/DebugInfo/DWARF/DWARFContext.h"
6#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
7#include "llvm/Object/ObjectFile.h"
8#include "llvm/Support/JSON.h"
9
10#define DEBUG_TYPE "dwarfdump"
11using namespace llvm;
12using namespace object;
13
14/// This represents the number of categories of debug location coverage being
15/// calculated. The first category is the number of variables with 0% location
16/// coverage, but the last category is the number of variables with 100%
17/// location coverage.
18constexpr int NumOfCoverageCategories = 12;
19
20/// Holds statistics for one function (or other entity that has a PC range and
21/// contains variables, such as a compile unit).
22struct PerFunctionStats {
23  /// Number of inlined instances of this function.
24  unsigned NumFnInlined = 0;
25  /// Number of inlined instances that have abstract origins.
26  unsigned NumAbstractOrigins = 0;
27  /// Number of variables and parameters with location across all inlined
28  /// instances.
29  unsigned TotalVarWithLoc = 0;
30  /// Number of constants with location across all inlined instances.
31  unsigned ConstantMembers = 0;
32  /// List of all Variables and parameters in this function.
33  StringSet<> VarsInFunction;
34  /// Compile units also cover a PC range, but have this flag set to false.
35  bool IsFunction = false;
36  /// Verify function definition has PC addresses (for detecting when
37  /// a function has been inlined everywhere).
38  bool HasPCAddresses = false;
39  /// Function has source location information.
40  bool HasSourceLocation = false;
41  /// Number of function parameters.
42  unsigned NumParams = 0;
43  /// Number of function parameters with source location.
44  unsigned NumParamSourceLocations = 0;
45  /// Number of function parameters with type.
46  unsigned NumParamTypes = 0;
47  /// Number of function parameters with a DW_AT_location.
48  unsigned NumParamLocations = 0;
49  /// Number of variables.
50  unsigned NumVars = 0;
51  /// Number of variables with source location.
52  unsigned NumVarSourceLocations = 0;
53  /// Number of variables with type.
54  unsigned NumVarTypes = 0;
55  /// Number of variables with DW_AT_location.
56  unsigned NumVarLocations = 0;
57};
58
59/// Holds accumulated global statistics about DIEs.
60struct GlobalStats {
61  /// Total number of PC range bytes covered by DW_AT_locations.
62  unsigned ScopeBytesCovered = 0;
63  /// Total number of PC range bytes in each variable's enclosing scope.
64  unsigned ScopeBytes = 0;
65  /// Total number of PC range bytes covered by DW_AT_locations with
66  /// the debug entry values (DW_OP_entry_value).
67  unsigned ScopeEntryValueBytesCovered = 0;
68  /// Total number of PC range bytes covered by DW_AT_locations of
69  /// formal parameters.
70  unsigned ParamScopeBytesCovered = 0;
71  /// Total number of PC range bytes in each variable's enclosing scope
72  /// (only for parameters).
73  unsigned ParamScopeBytes = 0;
74  /// Total number of PC range bytes covered by DW_AT_locations with
75  /// the debug entry values (DW_OP_entry_value) (only for parameters).
76  unsigned ParamScopeEntryValueBytesCovered = 0;
77  /// Total number of PC range bytes covered by DW_AT_locations (only for local
78  /// variables).
79  unsigned VarScopeBytesCovered = 0;
80  /// Total number of PC range bytes in each variable's enclosing scope
81  /// (only for local variables).
82  unsigned VarScopeBytes = 0;
83  /// Total number of PC range bytes covered by DW_AT_locations with
84  /// the debug entry values (DW_OP_entry_value) (only for local variables).
85  unsigned VarScopeEntryValueBytesCovered = 0;
86  /// Total number of call site entries (DW_AT_call_file & DW_AT_call_line).
87  unsigned CallSiteEntries = 0;
88  /// Total number of call site DIEs (DW_TAG_call_site).
89  unsigned CallSiteDIEs = 0;
90  /// Total number of call site parameter DIEs (DW_TAG_call_site_parameter).
91  unsigned CallSiteParamDIEs = 0;
92  /// Total byte size of concrete functions. This byte size includes
93  /// inline functions contained in the concrete functions.
94  unsigned FunctionSize = 0;
95  /// Total byte size of inlined functions. This is the total number of bytes
96  /// for the top inline functions within concrete functions. This can help
97  /// tune the inline settings when compiling to match user expectations.
98  unsigned InlineFunctionSize = 0;
99};
100
101/// Holds accumulated debug location statistics about local variables and
102/// formal parameters.
103struct LocationStats {
104  /// Map the scope coverage decile to the number of variables in the decile.
105  /// The first element of the array (at the index zero) represents the number
106  /// of variables with the no debug location at all, but the last element
107  /// in the vector represents the number of fully covered variables within
108  /// its scope.
109  std::vector<unsigned> VarParamLocStats{
110      std::vector<unsigned>(NumOfCoverageCategories, 0)};
111  /// Map non debug entry values coverage.
112  std::vector<unsigned> VarParamNonEntryValLocStats{
113      std::vector<unsigned>(NumOfCoverageCategories, 0)};
114  /// The debug location statistics for formal parameters.
115  std::vector<unsigned> ParamLocStats{
116      std::vector<unsigned>(NumOfCoverageCategories, 0)};
117  /// Map non debug entry values coverage for formal parameters.
118  std::vector<unsigned> ParamNonEntryValLocStats{
119      std::vector<unsigned>(NumOfCoverageCategories, 0)};
120  /// The debug location statistics for local variables.
121  std::vector<unsigned> VarLocStats{
122      std::vector<unsigned>(NumOfCoverageCategories, 0)};
123  /// Map non debug entry values coverage for local variables.
124  std::vector<unsigned> VarNonEntryValLocStats{
125      std::vector<unsigned>(NumOfCoverageCategories, 0)};
126  /// Total number of local variables and function parameters processed.
127  unsigned NumVarParam = 0;
128  /// Total number of formal parameters processed.
129  unsigned NumParam = 0;
130  /// Total number of local variables processed.
131  unsigned NumVar = 0;
132};
133
134/// Collect debug location statistics for one DIE.
135static void collectLocStats(uint64_t BytesCovered, uint64_t BytesInScope,
136                            std::vector<unsigned> &VarParamLocStats,
137                            std::vector<unsigned> &ParamLocStats,
138                            std::vector<unsigned> &VarLocStats, bool IsParam,
139                            bool IsLocalVar) {
140  auto getCoverageBucket = [BytesCovered, BytesInScope]() -> unsigned {
141    // No debug location at all for the variable.
142    if (BytesCovered == 0)
143      return 0;
144    // Fully covered variable within its scope.
145    if (BytesCovered >= BytesInScope)
146      return NumOfCoverageCategories - 1;
147    // Get covered range (e.g. 20%-29%).
148    unsigned LocBucket = 100 * (double)BytesCovered / BytesInScope;
149    LocBucket /= 10;
150    return LocBucket + 1;
151  };
152
153  unsigned CoverageBucket = getCoverageBucket();
154  VarParamLocStats[CoverageBucket]++;
155  if (IsParam)
156    ParamLocStats[CoverageBucket]++;
157  else if (IsLocalVar)
158    VarLocStats[CoverageBucket]++;
159}
160
161/// Collect debug info quality metrics for one DIE.
162static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,
163                               std::string VarPrefix, uint64_t BytesInScope,
164                               uint32_t InlineDepth,
165                               StringMap<PerFunctionStats> &FnStatMap,
166                               GlobalStats &GlobalStats,
167                               LocationStats &LocStats) {
168  bool HasLoc = false;
169  bool HasSrcLoc = false;
170  bool HasType = false;
171  bool IsArtificial = false;
172  uint64_t BytesCovered = 0;
173  uint64_t BytesEntryValuesCovered = 0;
174  auto &FnStats = FnStatMap[FnPrefix];
175  bool IsParam = Die.getTag() == dwarf::DW_TAG_formal_parameter;
176  bool IsLocalVar = Die.getTag() == dwarf::DW_TAG_variable;
177
178  if (Die.getTag() == dwarf::DW_TAG_call_site ||
179      Die.getTag() == dwarf::DW_TAG_GNU_call_site) {
180    GlobalStats.CallSiteDIEs++;
181    return;
182  }
183
184  if (Die.getTag() == dwarf::DW_TAG_call_site_parameter ||
185      Die.getTag() == dwarf::DW_TAG_GNU_call_site_parameter) {
186    GlobalStats.CallSiteParamDIEs++;
187    return;
188  }
189
190  if (!IsParam && !IsLocalVar && Die.getTag() != dwarf::DW_TAG_member) {
191    // Not a variable or constant member.
192    return;
193  }
194
195  if (Die.findRecursively(dwarf::DW_AT_decl_file) &&
196      Die.findRecursively(dwarf::DW_AT_decl_line))
197    HasSrcLoc = true;
198
199  if (Die.findRecursively(dwarf::DW_AT_type))
200    HasType = true;
201
202  if (Die.find(dwarf::DW_AT_artificial))
203    IsArtificial = true;
204
205  auto IsEntryValue = [&](ArrayRef<uint8_t> D) -> bool {
206    DWARFUnit *U = Die.getDwarfUnit();
207    DataExtractor Data(toStringRef(D),
208                       Die.getDwarfUnit()->getContext().isLittleEndian(), 0);
209    DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize());
210    // Consider the expression containing the DW_OP_entry_value as
211    // an entry value.
212    return llvm::any_of(Expression, [](DWARFExpression::Operation &Op) {
213      return Op.getCode() == dwarf::DW_OP_entry_value ||
214             Op.getCode() == dwarf::DW_OP_GNU_entry_value;
215    });
216  };
217
218  if (Die.find(dwarf::DW_AT_const_value)) {
219    // This catches constant members *and* variables.
220    HasLoc = true;
221    BytesCovered = BytesInScope;
222  } else {
223    if (Die.getTag() == dwarf::DW_TAG_member) {
224      // Non-const member.
225      return;
226    }
227    // Handle variables and function arguments.
228    Expected<std::vector<DWARFLocationExpression>> Loc =
229        Die.getLocations(dwarf::DW_AT_location);
230    if (!Loc) {
231      consumeError(Loc.takeError());
232    } else {
233      HasLoc = true;
234      // Get PC coverage.
235      auto Default = find_if(
236          *Loc, [](const DWARFLocationExpression &L) { return !L.Range; });
237      if (Default != Loc->end()) {
238        // Assume the entire range is covered by a single location.
239        BytesCovered = BytesInScope;
240      } else {
241        for (auto Entry : *Loc) {
242          uint64_t BytesEntryCovered = Entry.Range->HighPC - Entry.Range->LowPC;
243          BytesCovered += BytesEntryCovered;
244          if (IsEntryValue(Entry.Expr))
245            BytesEntryValuesCovered += BytesEntryCovered;
246        }
247      }
248    }
249  }
250
251  // Calculate the debug location statistics.
252  if (BytesInScope) {
253    LocStats.NumVarParam++;
254    if (IsParam)
255      LocStats.NumParam++;
256    else if (IsLocalVar)
257      LocStats.NumVar++;
258
259    collectLocStats(BytesCovered, BytesInScope, LocStats.VarParamLocStats,
260                    LocStats.ParamLocStats, LocStats.VarLocStats, IsParam,
261                    IsLocalVar);
262    // Non debug entry values coverage statistics.
263    collectLocStats(BytesCovered - BytesEntryValuesCovered, BytesInScope,
264                    LocStats.VarParamNonEntryValLocStats,
265                    LocStats.ParamNonEntryValLocStats,
266                    LocStats.VarNonEntryValLocStats, IsParam, IsLocalVar);
267  }
268
269  // Collect PC range coverage data.
270  if (DWARFDie D =
271          Die.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin))
272    Die = D;
273  // By using the variable name + the path through the lexical block tree, the
274  // keys are consistent across duplicate abstract origins in different CUs.
275  std::string VarName = StringRef(Die.getName(DINameKind::ShortName));
276  FnStats.VarsInFunction.insert(VarPrefix + VarName);
277  if (BytesInScope) {
278    FnStats.TotalVarWithLoc += (unsigned)HasLoc;
279    // Turns out we have a lot of ranges that extend past the lexical scope.
280    GlobalStats.ScopeBytesCovered += std::min(BytesInScope, BytesCovered);
281    GlobalStats.ScopeBytes += BytesInScope;
282    GlobalStats.ScopeEntryValueBytesCovered += BytesEntryValuesCovered;
283    if (IsParam) {
284      GlobalStats.ParamScopeBytesCovered +=
285          std::min(BytesInScope, BytesCovered);
286      GlobalStats.ParamScopeBytes += BytesInScope;
287      GlobalStats.ParamScopeEntryValueBytesCovered += BytesEntryValuesCovered;
288    } else if (IsLocalVar) {
289      GlobalStats.VarScopeBytesCovered += std::min(BytesInScope, BytesCovered);
290      GlobalStats.VarScopeBytes += BytesInScope;
291      GlobalStats.VarScopeEntryValueBytesCovered += BytesEntryValuesCovered;
292    }
293    assert(GlobalStats.ScopeBytesCovered <= GlobalStats.ScopeBytes);
294  } else if (Die.getTag() == dwarf::DW_TAG_member) {
295    FnStats.ConstantMembers++;
296  } else {
297    FnStats.TotalVarWithLoc += (unsigned)HasLoc;
298  }
299  if (!IsArtificial) {
300    if (IsParam) {
301      FnStats.NumParams++;
302      if (HasType)
303        FnStats.NumParamTypes++;
304      if (HasSrcLoc)
305        FnStats.NumParamSourceLocations++;
306      if (HasLoc)
307        FnStats.NumParamLocations++;
308    } else if (IsLocalVar) {
309      FnStats.NumVars++;
310      if (HasType)
311        FnStats.NumVarTypes++;
312      if (HasSrcLoc)
313        FnStats.NumVarSourceLocations++;
314      if (HasLoc)
315        FnStats.NumVarLocations++;
316    }
317  }
318}
319
320/// Recursively collect debug info quality metrics.
321static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix,
322                                  std::string VarPrefix, uint64_t BytesInScope,
323                                  uint32_t InlineDepth,
324                                  StringMap<PerFunctionStats> &FnStatMap,
325                                  GlobalStats &GlobalStats,
326                                  LocationStats &LocStats) {
327  // Handle any kind of lexical scope.
328  const dwarf::Tag Tag = Die.getTag();
329  const bool IsFunction = Tag == dwarf::DW_TAG_subprogram;
330  const bool IsBlock = Tag == dwarf::DW_TAG_lexical_block;
331  const bool IsInlinedFunction = Tag == dwarf::DW_TAG_inlined_subroutine;
332  if (IsFunction || IsInlinedFunction || IsBlock) {
333
334    // Reset VarPrefix when entering a new function.
335    if (Die.getTag() == dwarf::DW_TAG_subprogram ||
336        Die.getTag() == dwarf::DW_TAG_inlined_subroutine)
337      VarPrefix = "v";
338
339    // Ignore forward declarations.
340    if (Die.find(dwarf::DW_AT_declaration))
341      return;
342
343    // Check for call sites.
344    if (Die.find(dwarf::DW_AT_call_file) && Die.find(dwarf::DW_AT_call_line))
345      GlobalStats.CallSiteEntries++;
346
347    // PC Ranges.
348    auto RangesOrError = Die.getAddressRanges();
349    if (!RangesOrError) {
350      llvm::consumeError(RangesOrError.takeError());
351      return;
352    }
353
354    auto Ranges = RangesOrError.get();
355    uint64_t BytesInThisScope = 0;
356    for (auto Range : Ranges)
357      BytesInThisScope += Range.HighPC - Range.LowPC;
358
359    // Count the function.
360    if (!IsBlock) {
361      StringRef Name = Die.getName(DINameKind::LinkageName);
362      if (Name.empty())
363        Name = Die.getName(DINameKind::ShortName);
364      FnPrefix = Name;
365      // Skip over abstract origins.
366      if (Die.find(dwarf::DW_AT_inline))
367        return;
368      // We've seen an (inlined) instance of this function.
369      auto &FnStats = FnStatMap[Name];
370      if (IsInlinedFunction) {
371        FnStats.NumFnInlined++;
372        if (Die.findRecursively(dwarf::DW_AT_abstract_origin))
373          FnStats.NumAbstractOrigins++;
374      }
375      FnStats.IsFunction = true;
376      if (BytesInThisScope && !IsInlinedFunction)
377        FnStats.HasPCAddresses = true;
378      std::string FnName = StringRef(Die.getName(DINameKind::ShortName));
379      if (Die.findRecursively(dwarf::DW_AT_decl_file) &&
380          Die.findRecursively(dwarf::DW_AT_decl_line))
381        FnStats.HasSourceLocation = true;
382    }
383
384    if (BytesInThisScope) {
385      BytesInScope = BytesInThisScope;
386      if (IsFunction)
387        GlobalStats.FunctionSize += BytesInThisScope;
388      else if (IsInlinedFunction && InlineDepth == 0)
389        GlobalStats.InlineFunctionSize += BytesInThisScope;
390    }
391  } else {
392    // Not a scope, visit the Die itself. It could be a variable.
393    collectStatsForDie(Die, FnPrefix, VarPrefix, BytesInScope, InlineDepth,
394                       FnStatMap, GlobalStats, LocStats);
395  }
396
397  // Set InlineDepth correctly for child recursion
398  if (IsFunction)
399    InlineDepth = 0;
400  else if (IsInlinedFunction)
401    ++InlineDepth;
402
403  // Traverse children.
404  unsigned LexicalBlockIndex = 0;
405  DWARFDie Child = Die.getFirstChild();
406  while (Child) {
407    std::string ChildVarPrefix = VarPrefix;
408    if (Child.getTag() == dwarf::DW_TAG_lexical_block)
409      ChildVarPrefix += toHex(LexicalBlockIndex++) + '.';
410
411    collectStatsRecursive(Child, FnPrefix, ChildVarPrefix, BytesInScope,
412                          InlineDepth, FnStatMap, GlobalStats, LocStats);
413    Child = Child.getSibling();
414  }
415}
416
417/// Print machine-readable output.
418/// The machine-readable format is single-line JSON output.
419/// \{
420static void printDatum(raw_ostream &OS, const char *Key, json::Value Value) {
421  OS << ",\"" << Key << "\":" << Value;
422  LLVM_DEBUG(llvm::dbgs() << Key << ": " << Value << '\n');
423}
424static void printLocationStats(raw_ostream &OS,
425                               const char *Key,
426                               std::vector<unsigned> &LocationStats) {
427  OS << ",\"" << Key << " with 0% of its scope covered\":"
428     << LocationStats[0];
429  LLVM_DEBUG(llvm::dbgs() << Key << " with 0% of its scope covered: "
430                          << LocationStats[0] << '\n');
431  OS << ",\"" << Key << " with (0%,10%) of its scope covered\":"
432     << LocationStats[1];
433  LLVM_DEBUG(llvm::dbgs() << Key << " with (0%,10%) of its scope covered: "
434                          << LocationStats[1] << '\n');
435  for (unsigned i = 2; i < NumOfCoverageCategories - 1; ++i) {
436    OS << ",\"" << Key << " with [" << (i - 1) * 10 << "%," << i * 10
437       << "%) of its scope covered\":" << LocationStats[i];
438    LLVM_DEBUG(llvm::dbgs()
439               << Key << " with [" << (i - 1) * 10 << "%," << i * 10
440               << "%) of its scope covered: " << LocationStats[i]);
441  }
442  OS << ",\"" << Key << " with 100% of its scope covered\":"
443     << LocationStats[NumOfCoverageCategories - 1];
444  LLVM_DEBUG(llvm::dbgs() << Key << " with 100% of its scope covered: "
445                          << LocationStats[NumOfCoverageCategories - 1]);
446}
447/// \}
448
449/// Collect debug info quality metrics for an entire DIContext.
450///
451/// Do the impossible and reduce the quality of the debug info down to a few
452/// numbers. The idea is to condense the data into numbers that can be tracked
453/// over time to identify trends in newer compiler versions and gauge the effect
454/// of particular optimizations. The raw numbers themselves are not particularly
455/// useful, only the delta between compiling the same program with different
456/// compilers is.
457bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
458                               Twine Filename, raw_ostream &OS) {
459  StringRef FormatName = Obj.getFileFormatName();
460  GlobalStats GlobalStats;
461  LocationStats LocStats;
462  StringMap<PerFunctionStats> Statistics;
463  for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units())
464    if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false))
465      collectStatsRecursive(CUDie, "/", "g", 0, 0, Statistics, GlobalStats,
466                            LocStats);
467
468  /// The version number should be increased every time the algorithm is changed
469  /// (including bug fixes). New metrics may be added without increasing the
470  /// version.
471  unsigned Version = 4;
472  unsigned VarParamTotal = 0;
473  unsigned VarParamUnique = 0;
474  unsigned VarParamWithLoc = 0;
475  unsigned NumFunctions = 0;
476  unsigned NumInlinedFunctions = 0;
477  unsigned NumFuncsWithSrcLoc = 0;
478  unsigned NumAbstractOrigins = 0;
479  unsigned ParamTotal = 0;
480  unsigned ParamWithType = 0;
481  unsigned ParamWithLoc = 0;
482  unsigned ParamWithSrcLoc = 0;
483  unsigned VarTotal = 0;
484  unsigned VarWithType = 0;
485  unsigned VarWithSrcLoc = 0;
486  unsigned VarWithLoc = 0;
487  for (auto &Entry : Statistics) {
488    PerFunctionStats &Stats = Entry.getValue();
489    unsigned TotalVars = Stats.VarsInFunction.size() * Stats.NumFnInlined;
490    // Count variables in concrete out-of-line functions and in global scope.
491    if (Stats.HasPCAddresses || !Stats.IsFunction)
492      TotalVars += Stats.VarsInFunction.size();
493    unsigned Constants = Stats.ConstantMembers;
494    VarParamWithLoc += Stats.TotalVarWithLoc + Constants;
495    VarParamTotal += TotalVars;
496    VarParamUnique += Stats.VarsInFunction.size();
497    LLVM_DEBUG(for (auto &V
498                    : Stats.VarsInFunction) llvm::dbgs()
499               << Entry.getKey() << ": " << V.getKey() << "\n");
500    NumFunctions += Stats.IsFunction;
501    NumFuncsWithSrcLoc += Stats.HasSourceLocation;
502    NumInlinedFunctions += Stats.IsFunction * Stats.NumFnInlined;
503    NumAbstractOrigins += Stats.IsFunction * Stats.NumAbstractOrigins;
504    ParamTotal += Stats.NumParams;
505    ParamWithType += Stats.NumParamTypes;
506    ParamWithLoc += Stats.NumParamLocations;
507    ParamWithSrcLoc += Stats.NumParamSourceLocations;
508    VarTotal += Stats.NumVars;
509    VarWithType += Stats.NumVarTypes;
510    VarWithLoc += Stats.NumVarLocations;
511    VarWithSrcLoc += Stats.NumVarSourceLocations;
512  }
513
514  // Print summary.
515  OS.SetBufferSize(1024);
516  OS << "{\"version\":" << Version;
517  LLVM_DEBUG(llvm::dbgs() << "Variable location quality metrics\n";
518             llvm::dbgs() << "---------------------------------\n");
519  printDatum(OS, "file", Filename.str());
520  printDatum(OS, "format", FormatName);
521  printDatum(OS, "source functions", NumFunctions);
522  printDatum(OS, "source functions with location", NumFuncsWithSrcLoc);
523  printDatum(OS, "inlined functions", NumInlinedFunctions);
524  printDatum(OS, "inlined funcs with abstract origins", NumAbstractOrigins);
525  printDatum(OS, "unique source variables", VarParamUnique);
526  printDatum(OS, "source variables", VarParamTotal);
527  printDatum(OS, "variables with location", VarParamWithLoc);
528  printDatum(OS, "call site entries", GlobalStats.CallSiteEntries);
529  printDatum(OS, "call site DIEs", GlobalStats.CallSiteDIEs);
530  printDatum(OS, "call site parameter DIEs", GlobalStats.CallSiteParamDIEs);
531  printDatum(OS, "scope bytes total", GlobalStats.ScopeBytes);
532  printDatum(OS, "scope bytes covered", GlobalStats.ScopeBytesCovered);
533  printDatum(OS, "entry value scope bytes covered",
534             GlobalStats.ScopeEntryValueBytesCovered);
535  printDatum(OS, "formal params scope bytes total",
536             GlobalStats.ParamScopeBytes);
537  printDatum(OS, "formal params scope bytes covered",
538             GlobalStats.ParamScopeBytesCovered);
539  printDatum(OS, "formal params entry value scope bytes covered",
540             GlobalStats.ParamScopeEntryValueBytesCovered);
541  printDatum(OS, "vars scope bytes total", GlobalStats.VarScopeBytes);
542  printDatum(OS, "vars scope bytes covered", GlobalStats.VarScopeBytesCovered);
543  printDatum(OS, "vars entry value scope bytes covered",
544             GlobalStats.VarScopeEntryValueBytesCovered);
545  printDatum(OS, "total function size", GlobalStats.FunctionSize);
546  printDatum(OS, "total inlined function size", GlobalStats.InlineFunctionSize);
547  printDatum(OS, "total formal params", ParamTotal);
548  printDatum(OS, "formal params with source location", ParamWithSrcLoc);
549  printDatum(OS, "formal params with type", ParamWithType);
550  printDatum(OS, "formal params with binary location", ParamWithLoc);
551  printDatum(OS, "total vars", VarTotal);
552  printDatum(OS, "vars with source location", VarWithSrcLoc);
553  printDatum(OS, "vars with type", VarWithType);
554  printDatum(OS, "vars with binary location", VarWithLoc);
555  printDatum(OS, "total variables procesed by location statistics",
556             LocStats.NumVarParam);
557  printLocationStats(OS, "variables", LocStats.VarParamLocStats);
558  printLocationStats(OS, "variables (excluding the debug entry values)",
559                     LocStats.VarParamNonEntryValLocStats);
560  printDatum(OS, "total params procesed by location statistics",
561             LocStats.NumParam);
562  printLocationStats(OS, "params", LocStats.ParamLocStats);
563  printLocationStats(OS, "params (excluding the debug entry values)",
564                     LocStats.ParamNonEntryValLocStats);
565  printDatum(OS, "total vars procesed by location statistics", LocStats.NumVar);
566  printLocationStats(OS, "vars", LocStats.VarLocStats);
567  printLocationStats(OS, "vars (excluding the debug entry values)",
568                     LocStats.VarNonEntryValLocStats);
569  OS << "}\n";
570  LLVM_DEBUG(
571      llvm::dbgs() << "Total Availability: "
572                   << (int)std::round((VarParamWithLoc * 100.0) / VarParamTotal)
573                   << "%\n";
574      llvm::dbgs() << "PC Ranges covered: "
575                   << (int)std::round((GlobalStats.ScopeBytesCovered * 100.0) /
576                                      GlobalStats.ScopeBytes)
577                   << "%\n");
578  return true;
579}
580