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 variables.
62   unsigned NumVars = 0;
63   /// Number of variables with source location.
64   unsigned NumVarSourceLocations = 0;
65   /// Number of variables with type.
66   unsigned NumVarTypes = 0;
67   /// Number of variables with DW_AT_location.
68   unsigned NumVarLocations = 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 variable's enclosing scope
84   /// (only for parameters).
85   unsigned ParamScopeBytes = 0;
86   /// Total number of PC range bytes covered by DW_AT_locations with
87   /// the debug entry values (DW_OP_entry_value) (only for parameters).
88   unsigned ParamScopeEntryValueBytesCovered = 0;
89   /// Total number of PC range bytes covered by DW_AT_locations (only for local
90   /// variables).
91   unsigned VarScopeBytesCovered = 0;
92   /// Total number of PC range bytes in each variable's enclosing scope
93   /// (only for local variables).
94   unsigned VarScopeBytes = 0;
95   /// Total number of PC range bytes covered by DW_AT_locations with
96   /// the debug entry values (DW_OP_entry_value) (only for local variables).
97   unsigned VarScopeEntryValueBytesCovered = 0;
98   /// Total number of call site entries (DW_AT_call_file & DW_AT_call_line).
99   unsigned CallSiteEntries = 0;
100   /// Total number of call site DIEs (DW_TAG_call_site).
101   unsigned CallSiteDIEs = 0;
102   /// Total number of call site parameter DIEs (DW_TAG_call_site_parameter).
103   unsigned CallSiteParamDIEs = 0;
104   /// Total byte size of concrete functions. This byte size includes
105   /// inline functions contained in the concrete functions.
106   unsigned FunctionSize = 0;
107   /// Total byte size of inlined functions. This is the total number of bytes
108   /// for the top inline functions within concrete functions. This can help
109   /// tune the inline settings when compiling to match user expectations.
110   unsigned InlineFunctionSize = 0;
111 };
112 
113 /// Holds accumulated debug location statistics about local variables and
114 /// formal parameters.
115 struct LocationStats {
116   /// Map the scope coverage decile to the number of variables in the decile.
117   /// The first element of the array (at the index zero) represents the number
118   /// of variables with the no debug location at all, but the last element
119   /// in the vector represents the number of fully covered variables within
120   /// its scope.
121   std::vector<unsigned> VarParamLocStats{
122       std::vector<unsigned>(NumOfCoverageCategories, 0)};
123   /// Map non debug entry values coverage.
124   std::vector<unsigned> VarParamNonEntryValLocStats{
125       std::vector<unsigned>(NumOfCoverageCategories, 0)};
126   /// The debug location statistics for formal parameters.
127   std::vector<unsigned> ParamLocStats{
128       std::vector<unsigned>(NumOfCoverageCategories, 0)};
129   /// Map non debug entry values coverage for formal parameters.
130   std::vector<unsigned> ParamNonEntryValLocStats{
131       std::vector<unsigned>(NumOfCoverageCategories, 0)};
132   /// The debug location statistics for local variables.
133   std::vector<unsigned> VarLocStats{
134       std::vector<unsigned>(NumOfCoverageCategories, 0)};
135   /// Map non debug entry values coverage for local variables.
136   std::vector<unsigned> VarNonEntryValLocStats{
137       std::vector<unsigned>(NumOfCoverageCategories, 0)};
138   /// Total number of local variables and function parameters processed.
139   unsigned NumVarParam = 0;
140   /// Total number of formal parameters processed.
141   unsigned NumParam = 0;
142   /// Total number of local variables processed.
143   unsigned NumVar = 0;
144 };
145 } // namespace
146 
147 /// Collect debug location statistics for one DIE.
148 static void collectLocStats(uint64_t BytesCovered, uint64_t BytesInScope,
149                             std::vector<unsigned> &VarParamLocStats,
150                             std::vector<unsigned> &ParamLocStats,
151                             std::vector<unsigned> &VarLocStats, bool IsParam,
152                             bool IsLocalVar) {
153   auto getCoverageBucket = [BytesCovered, BytesInScope]() -> unsigned {
154     // No debug location at all for the variable.
155     if (BytesCovered == 0)
156       return 0;
157     // Fully covered variable within its scope.
158     if (BytesCovered >= BytesInScope)
159       return NumOfCoverageCategories - 1;
160     // Get covered range (e.g. 20%-29%).
161     unsigned LocBucket = 100 * (double)BytesCovered / BytesInScope;
162     LocBucket /= 10;
163     return LocBucket + 1;
164   };
165 
166   unsigned CoverageBucket = getCoverageBucket();
167   VarParamLocStats[CoverageBucket]++;
168   if (IsParam)
169     ParamLocStats[CoverageBucket]++;
170   else if (IsLocalVar)
171     VarLocStats[CoverageBucket]++;
172 }
173 /// Construct an identifier for a given DIE from its Prefix, Name, DeclFileName
174 /// and DeclLine. The identifier aims to be unique for any unique entities,
175 /// but keeping the same among different instances of the same entity.
176 static std::string constructDieID(DWARFDie Die,
177                                   StringRef Prefix = StringRef()) {
178   std::string IDStr;
179   llvm::raw_string_ostream ID(IDStr);
180   ID << Prefix
181      << Die.getName(DINameKind::LinkageName);
182 
183   // Prefix + Name is enough for local variables and parameters.
184   if (!Prefix.empty() && !Prefix.equals("g"))
185     return ID.str();
186 
187   auto DeclFile = Die.findRecursively(dwarf::DW_AT_decl_file);
188   std::string File;
189   if (DeclFile) {
190     DWARFUnit *U = Die.getDwarfUnit();
191     if (const auto *LT = U->getContext().getLineTableForUnit(U))
192       if (LT->getFileNameByIndex(
193               dwarf::toUnsigned(DeclFile, 0), U->getCompilationDir(),
194               DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File))
195         File = std::string(sys::path::filename(File));
196   }
197   ID << ":" << (File.empty() ? "/" : File);
198   ID << ":"
199      << dwarf::toUnsigned(Die.findRecursively(dwarf::DW_AT_decl_line), 0);
200   return ID.str();
201 }
202 
203 /// Collect debug info quality metrics for one DIE.
204 static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,
205                                std::string VarPrefix, uint64_t BytesInScope,
206                                uint32_t InlineDepth,
207                                StringMap<PerFunctionStats> &FnStatMap,
208                                GlobalStats &GlobalStats,
209                                LocationStats &LocStats) {
210   bool HasLoc = false;
211   bool HasSrcLoc = false;
212   bool HasType = false;
213   uint64_t BytesCovered = 0;
214   uint64_t BytesEntryValuesCovered = 0;
215   auto &FnStats = FnStatMap[FnPrefix];
216   bool IsParam = Die.getTag() == dwarf::DW_TAG_formal_parameter;
217   bool IsVariable = Die.getTag() == dwarf::DW_TAG_variable;
218   bool IsConstantMember = Die.getTag() == dwarf::DW_TAG_member &&
219                           Die.find(dwarf::DW_AT_const_value);
220 
221   if (Die.getTag() == dwarf::DW_TAG_call_site ||
222       Die.getTag() == dwarf::DW_TAG_GNU_call_site) {
223     GlobalStats.CallSiteDIEs++;
224     return;
225   }
226 
227   if (Die.getTag() == dwarf::DW_TAG_call_site_parameter ||
228       Die.getTag() == dwarf::DW_TAG_GNU_call_site_parameter) {
229     GlobalStats.CallSiteParamDIEs++;
230     return;
231   }
232 
233   if (!IsParam && !IsVariable && !IsConstantMember) {
234     // Not a variable or constant member.
235     return;
236   }
237 
238   // Ignore declarations of global variables.
239   if (IsVariable && Die.find(dwarf::DW_AT_declaration))
240     return;
241 
242   if (Die.findRecursively(dwarf::DW_AT_decl_file) &&
243       Die.findRecursively(dwarf::DW_AT_decl_line))
244     HasSrcLoc = true;
245 
246   if (Die.findRecursively(dwarf::DW_AT_type))
247     HasType = true;
248 
249   auto IsEntryValue = [&](ArrayRef<uint8_t> D) -> bool {
250     DWARFUnit *U = Die.getDwarfUnit();
251     DataExtractor Data(toStringRef(D),
252                        Die.getDwarfUnit()->getContext().isLittleEndian(), 0);
253     DWARFExpression Expression(Data, U->getAddressByteSize());
254     // Consider the expression containing the DW_OP_entry_value as
255     // an entry value.
256     return llvm::any_of(Expression, [](DWARFExpression::Operation &Op) {
257       return Op.getCode() == dwarf::DW_OP_entry_value ||
258              Op.getCode() == dwarf::DW_OP_GNU_entry_value;
259     });
260   };
261 
262   if (Die.find(dwarf::DW_AT_const_value)) {
263     // This catches constant members *and* variables.
264     HasLoc = true;
265     BytesCovered = BytesInScope;
266   } else {
267     // Handle variables and function arguments.
268     Expected<std::vector<DWARFLocationExpression>> Loc =
269         Die.getLocations(dwarf::DW_AT_location);
270     if (!Loc) {
271       consumeError(Loc.takeError());
272     } else {
273       HasLoc = true;
274       // Get PC coverage.
275       auto Default = find_if(
276           *Loc, [](const DWARFLocationExpression &L) { return !L.Range; });
277       if (Default != Loc->end()) {
278         // Assume the entire range is covered by a single location.
279         BytesCovered = BytesInScope;
280       } else {
281         for (auto Entry : *Loc) {
282           uint64_t BytesEntryCovered = Entry.Range->HighPC - Entry.Range->LowPC;
283           BytesCovered += BytesEntryCovered;
284           if (IsEntryValue(Entry.Expr))
285             BytesEntryValuesCovered += BytesEntryCovered;
286         }
287       }
288     }
289   }
290 
291   // Calculate the debug location statistics.
292   if (BytesInScope) {
293     LocStats.NumVarParam++;
294     if (IsParam)
295       LocStats.NumParam++;
296     else if (IsVariable)
297       LocStats.NumVar++;
298 
299     collectLocStats(BytesCovered, BytesInScope, LocStats.VarParamLocStats,
300                     LocStats.ParamLocStats, LocStats.VarLocStats, IsParam,
301                     IsVariable);
302     // Non debug entry values coverage statistics.
303     collectLocStats(BytesCovered - BytesEntryValuesCovered, BytesInScope,
304                     LocStats.VarParamNonEntryValLocStats,
305                     LocStats.ParamNonEntryValLocStats,
306                     LocStats.VarNonEntryValLocStats, IsParam, IsVariable);
307   }
308 
309   // Collect PC range coverage data.
310   if (DWARFDie D =
311           Die.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin))
312     Die = D;
313 
314   std::string VarID = constructDieID(Die, VarPrefix);
315   FnStats.VarsInFunction.insert(VarID);
316 
317   if (BytesInScope) {
318     // Turns out we have a lot of ranges that extend past the lexical scope.
319     GlobalStats.ScopeBytesCovered += std::min(BytesInScope, BytesCovered);
320     GlobalStats.ScopeBytes += BytesInScope;
321     GlobalStats.ScopeEntryValueBytesCovered += BytesEntryValuesCovered;
322     if (IsParam) {
323       GlobalStats.ParamScopeBytesCovered +=
324           std::min(BytesInScope, BytesCovered);
325       GlobalStats.ParamScopeBytes += BytesInScope;
326       GlobalStats.ParamScopeEntryValueBytesCovered += BytesEntryValuesCovered;
327     } else if (IsVariable) {
328       GlobalStats.VarScopeBytesCovered += std::min(BytesInScope, BytesCovered);
329       GlobalStats.VarScopeBytes += BytesInScope;
330       GlobalStats.VarScopeEntryValueBytesCovered += 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 (IsVariable) {
356     FnStats.NumVars++;
357     if (HasType)
358       FnStats.NumVarTypes++;
359     if (HasSrcLoc)
360       FnStats.NumVarSourceLocations++;
361     if (HasLoc)
362       FnStats.NumVarLocations++;
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,
477                                const char *Key,
478                                std::vector<unsigned> &LocationStats) {
479   OS << ",\"" << Key << " with 0% of its scope covered\":"
480      << LocationStats[0];
481   LLVM_DEBUG(llvm::dbgs() << Key << " with 0% of its scope covered: "
482                           << LocationStats[0] << '\n');
483   OS << ",\"" << Key << " with (0%,10%) of its scope covered\":"
484      << LocationStats[1];
485   LLVM_DEBUG(llvm::dbgs() << Key << " with (0%,10%) of its scope covered: "
486                           << LocationStats[1] << '\n');
487   for (unsigned i = 2; i < NumOfCoverageCategories - 1; ++i) {
488     OS << ",\"" << Key << " with [" << (i - 1) * 10 << "%," << i * 10
489        << "%) of its scope covered\":" << LocationStats[i];
490     LLVM_DEBUG(llvm::dbgs()
491                << Key << " with [" << (i - 1) * 10 << "%," << i * 10
492                << "%) of its scope covered: " << LocationStats[i]);
493   }
494   OS << ",\"" << Key << " with 100% of its scope covered\":"
495      << LocationStats[NumOfCoverageCategories - 1];
496   LLVM_DEBUG(llvm::dbgs() << Key << " with 100% of its scope covered: "
497                           << LocationStats[NumOfCoverageCategories - 1]);
498 }
499 
500 static void printSectionSizes(raw_ostream &OS, const SectionSizes &Sizes) {
501   for (const auto &DebugSec : Sizes.DebugSectionSizes)
502     OS << ",\"size of " << DebugSec.getKey() << "\":" << DebugSec.getValue();
503 }
504 
505 /// \}
506 
507 /// Collect debug info quality metrics for an entire DIContext.
508 ///
509 /// Do the impossible and reduce the quality of the debug info down to a few
510 /// numbers. The idea is to condense the data into numbers that can be tracked
511 /// over time to identify trends in newer compiler versions and gauge the effect
512 /// of particular optimizations. The raw numbers themselves are not particularly
513 /// useful, only the delta between compiling the same program with different
514 /// compilers is.
515 bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
516                                           const Twine &Filename,
517                                           raw_ostream &OS) {
518   StringRef FormatName = Obj.getFileFormatName();
519   GlobalStats GlobalStats;
520   LocationStats LocStats;
521   StringMap<PerFunctionStats> Statistics;
522   for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units())
523     if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false))
524       collectStatsRecursive(CUDie, "/", "g", 0, 0, Statistics, GlobalStats,
525                             LocStats);
526 
527   /// Collect the sizes of debug sections.
528   SectionSizes Sizes;
529   calculateSectionSizes(Obj, Sizes, Filename);
530 
531   /// The version number should be increased every time the algorithm is changed
532   /// (including bug fixes). New metrics may be added without increasing the
533   /// version.
534   unsigned Version = 4;
535   unsigned VarParamTotal = 0;
536   unsigned VarParamUnique = 0;
537   unsigned VarParamWithLoc = 0;
538   unsigned NumFunctions = 0;
539   unsigned NumInlinedFunctions = 0;
540   unsigned NumFuncsWithSrcLoc = 0;
541   unsigned NumAbstractOrigins = 0;
542   unsigned ParamTotal = 0;
543   unsigned ParamWithType = 0;
544   unsigned ParamWithLoc = 0;
545   unsigned ParamWithSrcLoc = 0;
546   unsigned VarTotal = 0;
547   unsigned VarWithType = 0;
548   unsigned VarWithSrcLoc = 0;
549   unsigned VarWithLoc = 0;
550   for (auto &Entry : Statistics) {
551     PerFunctionStats &Stats = Entry.getValue();
552     unsigned TotalVars = Stats.VarsInFunction.size() *
553                          (Stats.NumFnInlined + Stats.NumFnOutOfLine);
554     // Count variables in global scope.
555     if (!Stats.IsFunction)
556       TotalVars = Stats.NumVars + Stats.ConstantMembers + Stats.NumArtificial;
557     unsigned Constants = Stats.ConstantMembers;
558     VarParamWithLoc += Stats.TotalVarWithLoc + Constants;
559     VarParamTotal += TotalVars;
560     VarParamUnique += Stats.VarsInFunction.size();
561     LLVM_DEBUG(for (auto &V
562                     : Stats.VarsInFunction) llvm::dbgs()
563                << Entry.getKey() << ": " << V.getKey() << "\n");
564     NumFunctions += Stats.IsFunction;
565     NumFuncsWithSrcLoc += Stats.HasSourceLocation;
566     NumInlinedFunctions += Stats.IsFunction * Stats.NumFnInlined;
567     NumAbstractOrigins += Stats.IsFunction * Stats.NumAbstractOrigins;
568     ParamTotal += Stats.NumParams;
569     ParamWithType += Stats.NumParamTypes;
570     ParamWithLoc += Stats.NumParamLocations;
571     ParamWithSrcLoc += Stats.NumParamSourceLocations;
572     VarTotal += Stats.NumVars;
573     VarWithType += Stats.NumVarTypes;
574     VarWithLoc += Stats.NumVarLocations;
575     VarWithSrcLoc += Stats.NumVarSourceLocations;
576   }
577 
578   // Print summary.
579   OS.SetBufferSize(1024);
580   OS << "{\"version\":" << Version;
581   LLVM_DEBUG(llvm::dbgs() << "Variable location quality metrics\n";
582              llvm::dbgs() << "---------------------------------\n");
583   printDatum(OS, "file", Filename.str());
584   printDatum(OS, "format", FormatName);
585   printDatum(OS, "source functions", NumFunctions);
586   printDatum(OS, "source functions with location", NumFuncsWithSrcLoc);
587   printDatum(OS, "inlined functions", NumInlinedFunctions);
588   printDatum(OS, "inlined funcs with abstract origins", NumAbstractOrigins);
589   printDatum(OS, "unique source variables", VarParamUnique);
590   printDatum(OS, "source variables", VarParamTotal);
591   printDatum(OS, "variables with location", VarParamWithLoc);
592   printDatum(OS, "call site entries", GlobalStats.CallSiteEntries);
593   printDatum(OS, "call site DIEs", GlobalStats.CallSiteDIEs);
594   printDatum(OS, "call site parameter DIEs", GlobalStats.CallSiteParamDIEs);
595   printDatum(OS, "scope bytes total", GlobalStats.ScopeBytes);
596   printDatum(OS, "scope bytes covered", GlobalStats.ScopeBytesCovered);
597   printDatum(OS, "entry value scope bytes covered",
598              GlobalStats.ScopeEntryValueBytesCovered);
599   printDatum(OS, "formal params scope bytes total",
600              GlobalStats.ParamScopeBytes);
601   printDatum(OS, "formal params scope bytes covered",
602              GlobalStats.ParamScopeBytesCovered);
603   printDatum(OS, "formal params entry value scope bytes covered",
604              GlobalStats.ParamScopeEntryValueBytesCovered);
605   printDatum(OS, "vars scope bytes total", GlobalStats.VarScopeBytes);
606   printDatum(OS, "vars scope bytes covered", GlobalStats.VarScopeBytesCovered);
607   printDatum(OS, "vars entry value scope bytes covered",
608              GlobalStats.VarScopeEntryValueBytesCovered);
609   printDatum(OS, "total function size", GlobalStats.FunctionSize);
610   printDatum(OS, "total inlined function size", GlobalStats.InlineFunctionSize);
611   printDatum(OS, "total formal params", ParamTotal);
612   printDatum(OS, "formal params with source location", ParamWithSrcLoc);
613   printDatum(OS, "formal params with type", ParamWithType);
614   printDatum(OS, "formal params with binary location", ParamWithLoc);
615   printDatum(OS, "total vars", VarTotal);
616   printDatum(OS, "vars with source location", VarWithSrcLoc);
617   printDatum(OS, "vars with type", VarWithType);
618   printDatum(OS, "vars with binary location", VarWithLoc);
619   printDatum(OS, "total variables procesed by location statistics",
620              LocStats.NumVarParam);
621   printSectionSizes(OS, Sizes);
622   printLocationStats(OS, "variables", LocStats.VarParamLocStats);
623   printLocationStats(OS, "variables (excluding the debug entry values)",
624                      LocStats.VarParamNonEntryValLocStats);
625   printDatum(OS, "total params procesed by location statistics",
626              LocStats.NumParam);
627   printLocationStats(OS, "params", LocStats.ParamLocStats);
628   printLocationStats(OS, "params (excluding the debug entry values)",
629                      LocStats.ParamNonEntryValLocStats);
630   printDatum(OS, "total vars procesed by location statistics", LocStats.NumVar);
631   printLocationStats(OS, "vars", LocStats.VarLocStats);
632   printLocationStats(OS, "vars (excluding the debug entry values)",
633                      LocStats.VarNonEntryValLocStats);
634   OS << "}\n";
635   LLVM_DEBUG(
636       llvm::dbgs() << "Total Availability: "
637                    << (int)std::round((VarParamWithLoc * 100.0) / VarParamTotal)
638                    << "%\n";
639       llvm::dbgs() << "PC Ranges covered: "
640                    << (int)std::round((GlobalStats.ScopeBytesCovered * 100.0) /
641                                       GlobalStats.ScopeBytes)
642                    << "%\n");
643   return true;
644 }
645