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