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"
10 #define DEBUG_TYPE "dwarfdump"
12 using namespace object
;
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;
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
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.
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;
59 /// Holds accumulated global statistics about DIEs.
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
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
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;
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
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.
136 /// Extract the low pc from a Die.
137 static uint64_t getLowPC(DWARFDie Die
) {
138 auto RangesOrError
= Die
.getAddressRanges();
139 DWARFAddressRangesVector Ranges
;
141 Ranges
= RangesOrError
.get();
143 llvm::consumeError(RangesOrError
.takeError());
145 return Ranges
[0].LowPC
;
146 return dwarf::toAddress(Die
.find(dwarf::DW_AT_low_pc
), 0);
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
,
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.
160 } else if (LocBucket
== 100 || BytesCovered
> BytesInScope
) {
161 // Fully covered variable within its scope.
162 return NumOfCoverageCategories
- 1;
164 // Get covered range (e.g. 20%-29%).
166 return LocBucket
+ 1;
170 unsigned CoverageBucket
= getCoverageBucket();
171 VarParamLocStats
[CoverageBucket
]++;
173 ParamLocStats
[CoverageBucket
]++;
175 VarLocStats
[CoverageBucket
]++;
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
) {
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
;
196 if (Die
.getTag() == dwarf::DW_TAG_call_site
||
197 Die
.getTag() == dwarf::DW_TAG_GNU_call_site
) {
198 GlobalStats
.CallSiteDIEs
++;
202 if (Die
.getTag() == dwarf::DW_TAG_call_site_parameter
||
203 Die
.getTag() == dwarf::DW_TAG_GNU_call_site_parameter
) {
204 GlobalStats
.CallSiteParamDIEs
++;
208 if (!IsParam
&& !IsLocalVar
&& Die
.getTag() != dwarf::DW_TAG_member
) {
209 // Not a variable or constant member.
213 if (Die
.findRecursively(dwarf::DW_AT_decl_file
) &&
214 Die
.findRecursively(dwarf::DW_AT_decl_line
))
217 if (Die
.findRecursively(dwarf::DW_AT_type
))
220 if (Die
.find(dwarf::DW_AT_artificial
))
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
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
;
236 if (Die
.find(dwarf::DW_AT_const_value
)) {
237 // This catches constant members *and* variables.
239 BytesCovered
= BytesInScope
;
241 if (Die
.getTag() == dwarf::DW_TAG_member
) {
245 // Handle variables and function arguments.
246 auto FormValue
= Die
.find(dwarf::DW_AT_location
);
247 HasLoc
= FormValue
.hasValue();
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
;
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;
270 assert(BytesInScope
);
272 // Assume the entire range is covered by a single location.
273 BytesCovered
= BytesInScope
;
278 // Calculate the debug location statistics.
280 LocStats
.NumVarParam
++;
286 collectLocStats(BytesCovered
, BytesInScope
, LocStats
.VarParamLocStats
,
287 LocStats
.ParamLocStats
, LocStats
.VarLocStats
, IsParam
,
289 // Non debug entry values coverage statistics.
290 collectLocStats(BytesCovered
- BytesEntryValuesCovered
, BytesInScope
,
291 LocStats
.VarParamNonEntryValLocStats
,
292 LocStats
.ParamNonEntryValLocStats
,
293 LocStats
.VarNonEntryValLocStats
, IsParam
, IsLocalVar
);
296 // Collect PC range coverage data.
298 Die
.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin
))
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
);
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
;
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
;
323 assert(GlobalStats
.ScopeBytesCovered
<=
324 GlobalStats
.ScopeBytesFromFirstDefinition
);
325 } else if (Die
.getTag() == dwarf::DW_TAG_member
) {
326 FnStats
.ConstantMembers
++;
328 FnStats
.TotalVarWithLoc
+= (unsigned)HasLoc
;
334 FnStats
.NumParamTypes
++;
336 FnStats
.NumParamSourceLocations
++;
338 FnStats
.NumParamLocations
++;
339 } else if (IsLocalVar
) {
342 FnStats
.NumVarTypes
++;
344 FnStats
.NumVarSourceLocations
++;
346 FnStats
.NumVarLocations
++;
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
) {
365 // Reset VarPrefix when entering a new function.
366 if (Die
.getTag() == dwarf::DW_TAG_subprogram
||
367 Die
.getTag() == dwarf::DW_TAG_inlined_subroutine
)
370 // Ignore forward declarations.
371 if (Die
.find(dwarf::DW_AT_declaration
))
374 // Check for call sites.
375 if (Die
.find(dwarf::DW_AT_call_file
) && Die
.find(dwarf::DW_AT_call_line
))
376 GlobalStats
.CallSiteEntries
++;
379 auto RangesOrError
= Die
.getAddressRanges();
380 if (!RangesOrError
) {
381 llvm::consumeError(RangesOrError
.takeError());
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
);
391 // Count the function.
393 StringRef Name
= Die
.getName(DINameKind::LinkageName
);
395 Name
= Die
.getName(DINameKind::ShortName
);
397 // Skip over abstract origins.
398 if (Die
.find(dwarf::DW_AT_inline
))
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
++;
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;
416 if (BytesInThisScope
) {
417 BytesInScope
= BytesInThisScope
;
419 GlobalStats
.FunctionSize
+= BytesInThisScope
;
420 else if (IsInlinedFunction
&& InlineDepth
== 0)
421 GlobalStats
.InlineFunctionSize
+= BytesInThisScope
;
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
);
429 // Set InlineDepth correctly for child recursion
432 else if (IsInlinedFunction
)
435 // Traverse children.
436 unsigned LexicalBlockIndex
= 0;
437 DWARFDie Child
= Die
.getFirstChild();
439 std::string ChildVarPrefix
= VarPrefix
;
440 if (Child
.getTag() == dwarf::DW_TAG_lexical_block
)
441 ChildVarPrefix
+= toHex(LexicalBlockIndex
++) + '.';
443 collectStatsRecursive(Child
, UnitLowPC
, FnPrefix
, ChildVarPrefix
, ScopeLowPC
,
444 BytesInScope
, InlineDepth
, FnStatMap
, GlobalStats
,
446 Child
= Child
.getSibling();
450 /// Print machine-readable output.
451 /// The machine-readable format is single-line JSON output.
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');
457 static void printLocationStats(raw_ostream
&OS
,
459 std::vector
<unsigned> &LocationStats
) {
460 OS
<< ",\"" << Key
<< " with 0% of its scope covered\":"
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\":"
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
]);
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]);
482 /// Collect debug info quality metrics for an entire DIContext.
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
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
);
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
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
;
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",
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
);
606 llvm::dbgs() << "Total Availability: "
607 << (int)std::round((VarParamWithLoc
* 100.0) / VarParamTotal
)
609 llvm::dbgs() << "PC Ranges covered: "
610 << (int)std::round((GlobalStats
.ScopeBytesCovered
* 100.0) /
611 GlobalStats
.ScopeBytesFromFirstDefinition
)