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