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"
9 #define DEBUG_TYPE "dwarfdump"
11 using namespace object
;
13 /// This represents the number of categories of debug location coverage being
14 /// calculated. The first category is the number of variables with 0% location
15 /// coverage, but the last category is the number of variables with 100%
16 /// location coverage.
17 constexpr int NumOfCoverageCategories
= 12;
19 /// Holds statistics for one function (or other entity that has a PC range and
20 /// contains variables, such as a compile unit).
21 struct PerFunctionStats
{
22 /// Number of inlined instances of this function.
23 unsigned NumFnInlined
= 0;
24 /// Number of inlined instances that have abstract origins.
25 unsigned NumAbstractOrigins
= 0;
26 /// Number of variables and parameters with location across all inlined
28 unsigned TotalVarWithLoc
= 0;
29 /// Number of constants with location across all inlined instances.
30 unsigned ConstantMembers
= 0;
31 /// List of all Variables and parameters in this function.
32 StringSet
<> VarsInFunction
;
33 /// Compile units also cover a PC range, but have this flag set to false.
34 bool IsFunction
= false;
35 /// Verify function definition has PC addresses (for detecting when
36 /// a function has been inlined everywhere).
37 bool HasPCAddresses
= false;
38 /// Function has source location information.
39 bool HasSourceLocation
= false;
40 /// Number of function parameters.
41 unsigned NumParams
= 0;
42 /// Number of function parameters with source location.
43 unsigned NumParamSourceLocations
= 0;
44 /// Number of function parameters with type.
45 unsigned NumParamTypes
= 0;
46 /// Number of function parameters with a DW_AT_location.
47 unsigned NumParamLocations
= 0;
48 /// Number of variables.
50 /// Number of variables with source location.
51 unsigned NumVarSourceLocations
= 0;
52 /// Number of variables with type.
53 unsigned NumVarTypes
= 0;
54 /// Number of variables with DW_AT_location.
55 unsigned NumVarLocations
= 0;
58 /// Holds accumulated global statistics about DIEs.
60 /// Total number of PC range bytes covered by DW_AT_locations.
61 unsigned ScopeBytesCovered
= 0;
62 /// Total number of PC range bytes in each variable's enclosing scope,
63 /// starting from the first definition of the variable.
64 unsigned ScopeBytesFromFirstDefinition
= 0;
65 /// Total number of PC range bytes covered by DW_AT_locations with
66 /// the debug entry values (DW_OP_entry_value).
67 unsigned ScopeEntryValueBytesCovered
= 0;
68 /// Total number of PC range bytes covered by DW_AT_locations of
69 /// formal parameters.
70 unsigned ParamScopeBytesCovered
= 0;
71 /// Total number of PC range bytes in each variable's enclosing scope,
72 /// starting from the first definition of the variable (only for parameters).
73 unsigned ParamScopeBytesFromFirstDefinition
= 0;
74 /// Total number of PC range bytes covered by DW_AT_locations with
75 /// the debug entry values (DW_OP_entry_value) (only for parameters).
76 unsigned ParamScopeEntryValueBytesCovered
= 0;
77 /// Total number of PC range bytes covered by DW_AT_locations (only for local
79 unsigned VarScopeBytesCovered
= 0;
80 /// Total number of PC range bytes in each variable's enclosing scope,
81 /// starting from the first definition of the variable (only for local
83 unsigned VarScopeBytesFromFirstDefinition
= 0;
84 /// Total number of PC range bytes covered by DW_AT_locations with
85 /// the debug entry values (DW_OP_entry_value) (only for local variables).
86 unsigned VarScopeEntryValueBytesCovered
= 0;
87 /// Total number of call site entries (DW_AT_call_file & DW_AT_call_line).
88 unsigned CallSiteEntries
= 0;
89 /// Total number of call site DIEs (DW_TAG_call_site).
90 unsigned CallSiteDIEs
= 0;
91 /// Total number of call site parameter DIEs (DW_TAG_call_site_parameter).
92 unsigned CallSiteParamDIEs
= 0;
93 /// Total byte size of concrete functions. This byte size includes
94 /// inline functions contained in the concrete functions.
95 uint64_t FunctionSize
= 0;
96 /// Total byte size of inlined functions. This is the total number of bytes
97 /// for the top inline functions within concrete functions. This can help
98 /// tune the inline settings when compiling to match user expectations.
99 uint64_t InlineFunctionSize
= 0;
102 /// Holds accumulated debug location statistics about local variables and
103 /// formal parameters.
104 struct LocationStats
{
105 /// Map the scope coverage decile to the number of variables in the decile.
106 /// The first element of the array (at the index zero) represents the number
107 /// of variables with the no debug location at all, but the last element
108 /// in the vector represents the number of fully covered variables within
110 std::vector
<unsigned> VarParamLocStats
{
111 std::vector
<unsigned>(NumOfCoverageCategories
, 0)};
112 /// Map non debug entry values coverage.
113 std::vector
<unsigned> VarParamNonEntryValLocStats
{
114 std::vector
<unsigned>(NumOfCoverageCategories
, 0)};
115 /// The debug location statistics for formal parameters.
116 std::vector
<unsigned> ParamLocStats
{
117 std::vector
<unsigned>(NumOfCoverageCategories
, 0)};
118 /// Map non debug entry values coverage for formal parameters.
119 std::vector
<unsigned> ParamNonEntryValLocStats
{
120 std::vector
<unsigned>(NumOfCoverageCategories
, 0)};
121 /// The debug location statistics for local variables.
122 std::vector
<unsigned> VarLocStats
{
123 std::vector
<unsigned>(NumOfCoverageCategories
, 0)};
124 /// Map non debug entry values coverage for local variables.
125 std::vector
<unsigned> VarNonEntryValLocStats
{
126 std::vector
<unsigned>(NumOfCoverageCategories
, 0)};
127 /// Total number of local variables and function parameters processed.
128 unsigned NumVarParam
= 0;
129 /// Total number of formal parameters processed.
130 unsigned NumParam
= 0;
131 /// Total number of local variables processed.
135 /// Extract the low pc from a Die.
136 static uint64_t getLowPC(DWARFDie Die
) {
137 auto RangesOrError
= Die
.getAddressRanges();
138 DWARFAddressRangesVector Ranges
;
140 Ranges
= RangesOrError
.get();
142 llvm::consumeError(RangesOrError
.takeError());
144 return Ranges
[0].LowPC
;
145 return dwarf::toAddress(Die
.find(dwarf::DW_AT_low_pc
), 0);
148 /// Collect debug location statistics for one DIE.
149 static void collectLocStats(uint64_t BytesCovered
, uint64_t BytesInScope
,
150 std::vector
<unsigned> &VarParamLocStats
,
151 std::vector
<unsigned> &ParamLocStats
,
152 std::vector
<unsigned> &VarLocStats
, bool IsParam
,
154 auto getCoverageBucket
= [BytesCovered
, BytesInScope
]() -> unsigned {
155 unsigned LocBucket
= 100 * (double)BytesCovered
/ BytesInScope
;
156 if (LocBucket
== 0) {
157 // No debug location at all for the variable.
159 } else if (LocBucket
== 100 || BytesCovered
> BytesInScope
) {
160 // Fully covered variable within its scope.
161 return NumOfCoverageCategories
- 1;
163 // Get covered range (e.g. 20%-29%).
165 return LocBucket
+ 1;
169 unsigned CoverageBucket
= getCoverageBucket();
170 VarParamLocStats
[CoverageBucket
]++;
172 ParamLocStats
[CoverageBucket
]++;
174 VarLocStats
[CoverageBucket
]++;
177 /// Collect debug info quality metrics for one DIE.
178 static void collectStatsForDie(DWARFDie Die
, uint64_t UnitLowPC
, std::string FnPrefix
,
179 std::string VarPrefix
, uint64_t ScopeLowPC
,
180 uint64_t BytesInScope
, uint32_t InlineDepth
,
181 StringMap
<PerFunctionStats
> &FnStatMap
,
182 GlobalStats
&GlobalStats
,
183 LocationStats
&LocStats
) {
185 bool HasSrcLoc
= false;
186 bool HasType
= false;
187 bool IsArtificial
= false;
188 uint64_t BytesCovered
= 0;
189 uint64_t BytesEntryValuesCovered
= 0;
190 uint64_t OffsetToFirstDefinition
= 0;
191 auto &FnStats
= FnStatMap
[FnPrefix
];
192 bool IsParam
= Die
.getTag() == dwarf::DW_TAG_formal_parameter
;
193 bool IsLocalVar
= Die
.getTag() == dwarf::DW_TAG_variable
;
195 if (Die
.getTag() == dwarf::DW_TAG_call_site
||
196 Die
.getTag() == dwarf::DW_TAG_GNU_call_site
) {
197 GlobalStats
.CallSiteDIEs
++;
201 if (Die
.getTag() == dwarf::DW_TAG_call_site_parameter
||
202 Die
.getTag() == dwarf::DW_TAG_GNU_call_site_parameter
) {
203 GlobalStats
.CallSiteParamDIEs
++;
207 if (!IsParam
&& !IsLocalVar
&& Die
.getTag() != dwarf::DW_TAG_member
) {
208 // Not a variable or constant member.
212 if (Die
.findRecursively(dwarf::DW_AT_decl_file
) &&
213 Die
.findRecursively(dwarf::DW_AT_decl_line
))
216 if (Die
.findRecursively(dwarf::DW_AT_type
))
219 if (Die
.find(dwarf::DW_AT_artificial
))
222 auto IsEntryValue
= [&](ArrayRef
<uint8_t> D
) -> bool {
223 DWARFUnit
*U
= Die
.getDwarfUnit();
224 DataExtractor
Data(toStringRef(D
),
225 Die
.getDwarfUnit()->getContext().isLittleEndian(), 0);
226 DWARFExpression
Expression(Data
, U
->getVersion(), U
->getAddressByteSize());
227 // Consider the expression containing the DW_OP_entry_value as
229 return llvm::any_of(Expression
, [](DWARFExpression::Operation
&Op
) {
230 return Op
.getCode() == dwarf::DW_OP_entry_value
||
231 Op
.getCode() == dwarf::DW_OP_GNU_entry_value
;
235 if (Die
.find(dwarf::DW_AT_const_value
)) {
236 // This catches constant members *and* variables.
238 BytesCovered
= BytesInScope
;
240 if (Die
.getTag() == dwarf::DW_TAG_member
) {
244 // Handle variables and function arguments.
245 auto FormValue
= Die
.find(dwarf::DW_AT_location
);
246 HasLoc
= FormValue
.hasValue();
249 if (auto DebugLocOffset
= FormValue
->getAsSectionOffset()) {
250 auto *DebugLoc
= Die
.getDwarfUnit()->getContext().getDebugLoc();
251 if (auto List
= DebugLoc
->getLocationListAtOffset(*DebugLocOffset
)) {
252 for (auto Entry
: List
->Entries
) {
253 uint64_t BytesEntryCovered
= Entry
.End
- Entry
.Begin
;
254 BytesCovered
+= BytesEntryCovered
;
255 if (IsEntryValue(Entry
.Loc
))
256 BytesEntryValuesCovered
+= BytesEntryCovered
;
258 if (List
->Entries
.size()) {
259 uint64_t FirstDef
= List
->Entries
[0].Begin
;
260 uint64_t UnitOfs
= UnitLowPC
;
261 // Ranges sometimes start before the lexical scope.
262 if (UnitOfs
+ FirstDef
>= ScopeLowPC
)
263 OffsetToFirstDefinition
= UnitOfs
+ FirstDef
- ScopeLowPC
;
264 // Or even after it. Count that as a failure.
265 if (OffsetToFirstDefinition
> BytesInScope
)
266 OffsetToFirstDefinition
= 0;
269 assert(BytesInScope
);
271 // Assume the entire range is covered by a single location.
272 BytesCovered
= BytesInScope
;
277 // Calculate the debug location statistics.
279 LocStats
.NumVarParam
++;
285 collectLocStats(BytesCovered
, BytesInScope
, LocStats
.VarParamLocStats
,
286 LocStats
.ParamLocStats
, LocStats
.VarLocStats
, IsParam
,
288 // Non debug entry values coverage statistics.
289 collectLocStats(BytesCovered
- BytesEntryValuesCovered
, BytesInScope
,
290 LocStats
.VarParamNonEntryValLocStats
,
291 LocStats
.ParamNonEntryValLocStats
,
292 LocStats
.VarNonEntryValLocStats
, IsParam
, IsLocalVar
);
295 // Collect PC range coverage data.
297 Die
.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin
))
299 // By using the variable name + the path through the lexical block tree, the
300 // keys are consistent across duplicate abstract origins in different CUs.
301 std::string VarName
= StringRef(Die
.getName(DINameKind::ShortName
));
302 FnStats
.VarsInFunction
.insert(VarPrefix
+ VarName
);
304 FnStats
.TotalVarWithLoc
+= (unsigned)HasLoc
;
305 // Adjust for the fact the variables often start their lifetime in the
306 // middle of the scope.
307 BytesInScope
-= OffsetToFirstDefinition
;
308 // Turns out we have a lot of ranges that extend past the lexical scope.
309 GlobalStats
.ScopeBytesCovered
+= std::min(BytesInScope
, BytesCovered
);
310 GlobalStats
.ScopeBytesFromFirstDefinition
+= BytesInScope
;
311 GlobalStats
.ScopeEntryValueBytesCovered
+= BytesEntryValuesCovered
;
313 GlobalStats
.ParamScopeBytesCovered
+=
314 std::min(BytesInScope
, BytesCovered
);
315 GlobalStats
.ParamScopeBytesFromFirstDefinition
+= BytesInScope
;
316 GlobalStats
.ParamScopeEntryValueBytesCovered
+= BytesEntryValuesCovered
;
317 } else if (IsLocalVar
) {
318 GlobalStats
.VarScopeBytesCovered
+= std::min(BytesInScope
, BytesCovered
);
319 GlobalStats
.VarScopeBytesFromFirstDefinition
+= BytesInScope
;
320 GlobalStats
.VarScopeEntryValueBytesCovered
+= BytesEntryValuesCovered
;
322 assert(GlobalStats
.ScopeBytesCovered
<=
323 GlobalStats
.ScopeBytesFromFirstDefinition
);
324 } else if (Die
.getTag() == dwarf::DW_TAG_member
) {
325 FnStats
.ConstantMembers
++;
327 FnStats
.TotalVarWithLoc
+= (unsigned)HasLoc
;
333 FnStats
.NumParamTypes
++;
335 FnStats
.NumParamSourceLocations
++;
337 FnStats
.NumParamLocations
++;
338 } else if (IsLocalVar
) {
341 FnStats
.NumVarTypes
++;
343 FnStats
.NumVarSourceLocations
++;
345 FnStats
.NumVarLocations
++;
350 /// Recursively collect debug info quality metrics.
351 static void collectStatsRecursive(DWARFDie Die
, uint64_t UnitLowPC
, std::string FnPrefix
,
352 std::string VarPrefix
, uint64_t ScopeLowPC
,
353 uint64_t BytesInScope
, uint32_t InlineDepth
,
354 StringMap
<PerFunctionStats
> &FnStatMap
,
355 GlobalStats
&GlobalStats
,
356 LocationStats
&LocStats
) {
357 // Handle any kind of lexical scope.
358 const dwarf::Tag Tag
= Die
.getTag();
359 const bool IsFunction
= Tag
== dwarf::DW_TAG_subprogram
;
360 const bool IsBlock
= Tag
== dwarf::DW_TAG_lexical_block
;
361 const bool IsInlinedFunction
= Tag
== dwarf::DW_TAG_inlined_subroutine
;
362 if (IsFunction
|| IsInlinedFunction
|| IsBlock
) {
364 // Reset VarPrefix when entering a new function.
365 if (Die
.getTag() == dwarf::DW_TAG_subprogram
||
366 Die
.getTag() == dwarf::DW_TAG_inlined_subroutine
)
369 // Ignore forward declarations.
370 if (Die
.find(dwarf::DW_AT_declaration
))
373 // Check for call sites.
374 if (Die
.find(dwarf::DW_AT_call_file
) && Die
.find(dwarf::DW_AT_call_line
))
375 GlobalStats
.CallSiteEntries
++;
378 auto RangesOrError
= Die
.getAddressRanges();
379 if (!RangesOrError
) {
380 llvm::consumeError(RangesOrError
.takeError());
384 auto Ranges
= RangesOrError
.get();
385 uint64_t BytesInThisScope
= 0;
386 for (auto Range
: Ranges
)
387 BytesInThisScope
+= Range
.HighPC
- Range
.LowPC
;
388 ScopeLowPC
= getLowPC(Die
);
390 // Count the function.
392 StringRef Name
= Die
.getName(DINameKind::LinkageName
);
394 Name
= Die
.getName(DINameKind::ShortName
);
396 // Skip over abstract origins.
397 if (Die
.find(dwarf::DW_AT_inline
))
399 // We've seen an (inlined) instance of this function.
400 auto &FnStats
= FnStatMap
[Name
];
401 if (IsInlinedFunction
) {
402 FnStats
.NumFnInlined
++;
403 if (Die
.findRecursively(dwarf::DW_AT_abstract_origin
))
404 FnStats
.NumAbstractOrigins
++;
406 FnStats
.IsFunction
= true;
407 if (BytesInThisScope
&& !IsInlinedFunction
)
408 FnStats
.HasPCAddresses
= true;
409 std::string FnName
= StringRef(Die
.getName(DINameKind::ShortName
));
410 if (Die
.findRecursively(dwarf::DW_AT_decl_file
) &&
411 Die
.findRecursively(dwarf::DW_AT_decl_line
))
412 FnStats
.HasSourceLocation
= true;
415 if (BytesInThisScope
) {
416 BytesInScope
= BytesInThisScope
;
418 GlobalStats
.FunctionSize
+= BytesInThisScope
;
419 else if (IsInlinedFunction
&& InlineDepth
== 0)
420 GlobalStats
.InlineFunctionSize
+= BytesInThisScope
;
423 // Not a scope, visit the Die itself. It could be a variable.
424 collectStatsForDie(Die
, UnitLowPC
, FnPrefix
, VarPrefix
, ScopeLowPC
, BytesInScope
,
425 InlineDepth
, FnStatMap
, GlobalStats
, LocStats
);
428 // Set InlineDepth correctly for child recursion
431 else if (IsInlinedFunction
)
434 // Traverse children.
435 unsigned LexicalBlockIndex
= 0;
436 DWARFDie Child
= Die
.getFirstChild();
438 std::string ChildVarPrefix
= VarPrefix
;
439 if (Child
.getTag() == dwarf::DW_TAG_lexical_block
)
440 ChildVarPrefix
+= toHex(LexicalBlockIndex
++) + '.';
442 collectStatsRecursive(Child
, UnitLowPC
, FnPrefix
, ChildVarPrefix
, ScopeLowPC
,
443 BytesInScope
, InlineDepth
, FnStatMap
, GlobalStats
,
445 Child
= Child
.getSibling();
449 /// Print machine-readable output.
450 /// The machine-readable format is single-line JSON output.
452 static void printDatum(raw_ostream
&OS
, const char *Key
, StringRef Value
) {
453 OS
<< ",\"" << Key
<< "\":\"" << Value
<< '"';
454 LLVM_DEBUG(llvm::dbgs() << Key
<< ": " << Value
<< '\n');
456 static void printDatum(raw_ostream
&OS
, const char *Key
, uint64_t Value
) {
457 OS
<< ",\"" << Key
<< "\":" << Value
;
458 LLVM_DEBUG(llvm::dbgs() << Key
<< ": " << Value
<< '\n');
460 static void printLocationStats(raw_ostream
&OS
,
462 std::vector
<unsigned> &LocationStats
) {
463 OS
<< ",\"" << Key
<< " with 0% of its scope covered\":"
465 LLVM_DEBUG(llvm::dbgs() << Key
<< " with 0% of its scope covered: "
466 << LocationStats
[0] << '\n');
467 OS
<< ",\"" << Key
<< " with 1-9% of its scope covered\":"
469 LLVM_DEBUG(llvm::dbgs() << Key
<< " with 1-9% of its scope covered: "
470 << LocationStats
[1] << '\n');
471 for (unsigned i
= 2; i
< NumOfCoverageCategories
- 1; ++i
) {
472 OS
<< ",\"" << Key
<< " with " << (i
- 1) * 10 << "-" << i
* 10 - 1
473 << "% of its scope covered\":" << LocationStats
[i
];
474 LLVM_DEBUG(llvm::dbgs()
475 << Key
<< " with " << (i
- 1) * 10 << "-" << i
* 10 - 1
476 << "% of its scope covered: " << LocationStats
[i
]);
478 OS
<< ",\"" << Key
<< " with 100% of its scope covered\":"
479 << LocationStats
[NumOfCoverageCategories
- 1];
480 LLVM_DEBUG(llvm::dbgs() << Key
<< " with 100% of its scope covered: "
481 << LocationStats
[NumOfCoverageCategories
- 1]);
485 /// Collect debug info quality metrics for an entire DIContext.
487 /// Do the impossible and reduce the quality of the debug info down to a few
488 /// numbers. The idea is to condense the data into numbers that can be tracked
489 /// over time to identify trends in newer compiler versions and gauge the effect
490 /// of particular optimizations. The raw numbers themselves are not particularly
491 /// useful, only the delta between compiling the same program with different
493 bool collectStatsForObjectFile(ObjectFile
&Obj
, DWARFContext
&DICtx
,
494 Twine Filename
, raw_ostream
&OS
) {
495 StringRef FormatName
= Obj
.getFileFormatName();
496 GlobalStats GlobalStats
;
497 LocationStats LocStats
;
498 StringMap
<PerFunctionStats
> Statistics
;
499 for (const auto &CU
: static_cast<DWARFContext
*>(&DICtx
)->compile_units())
500 if (DWARFDie CUDie
= CU
->getNonSkeletonUnitDIE(false))
501 collectStatsRecursive(CUDie
, getLowPC(CUDie
), "/", "g", 0, 0, 0,
502 Statistics
, GlobalStats
, LocStats
);
504 /// The version number should be increased every time the algorithm is changed
505 /// (including bug fixes). New metrics may be added without increasing the
507 unsigned Version
= 3;
508 unsigned VarParamTotal
= 0;
509 unsigned VarParamUnique
= 0;
510 unsigned VarParamWithLoc
= 0;
511 unsigned NumFunctions
= 0;
512 unsigned NumInlinedFunctions
= 0;
513 unsigned NumFuncsWithSrcLoc
= 0;
514 unsigned NumAbstractOrigins
= 0;
515 unsigned ParamTotal
= 0;
516 unsigned ParamWithType
= 0;
517 unsigned ParamWithLoc
= 0;
518 unsigned ParamWithSrcLoc
= 0;
519 unsigned VarTotal
= 0;
520 unsigned VarWithType
= 0;
521 unsigned VarWithSrcLoc
= 0;
522 unsigned VarWithLoc
= 0;
523 for (auto &Entry
: Statistics
) {
524 PerFunctionStats
&Stats
= Entry
.getValue();
525 unsigned TotalVars
= Stats
.VarsInFunction
.size() * Stats
.NumFnInlined
;
526 // Count variables in concrete out-of-line functions and in global scope.
527 if (Stats
.HasPCAddresses
|| !Stats
.IsFunction
)
528 TotalVars
+= Stats
.VarsInFunction
.size();
529 unsigned Constants
= Stats
.ConstantMembers
;
530 VarParamWithLoc
+= Stats
.TotalVarWithLoc
+ Constants
;
531 VarParamTotal
+= TotalVars
;
532 VarParamUnique
+= Stats
.VarsInFunction
.size();
533 LLVM_DEBUG(for (auto &V
534 : Stats
.VarsInFunction
) llvm::dbgs()
535 << Entry
.getKey() << ": " << V
.getKey() << "\n");
536 NumFunctions
+= Stats
.IsFunction
;
537 NumFuncsWithSrcLoc
+= Stats
.HasSourceLocation
;
538 NumInlinedFunctions
+= Stats
.IsFunction
* Stats
.NumFnInlined
;
539 NumAbstractOrigins
+= Stats
.IsFunction
* Stats
.NumAbstractOrigins
;
540 ParamTotal
+= Stats
.NumParams
;
541 ParamWithType
+= Stats
.NumParamTypes
;
542 ParamWithLoc
+= Stats
.NumParamLocations
;
543 ParamWithSrcLoc
+= Stats
.NumParamSourceLocations
;
544 VarTotal
+= Stats
.NumVars
;
545 VarWithType
+= Stats
.NumVarTypes
;
546 VarWithLoc
+= Stats
.NumVarLocations
;
547 VarWithSrcLoc
+= Stats
.NumVarSourceLocations
;
551 OS
.SetBufferSize(1024);
552 OS
<< "{\"version\":" << Version
;
553 LLVM_DEBUG(llvm::dbgs() << "Variable location quality metrics\n";
554 llvm::dbgs() << "---------------------------------\n");
555 printDatum(OS
, "file", Filename
.str());
556 printDatum(OS
, "format", FormatName
);
557 printDatum(OS
, "source functions", NumFunctions
);
558 printDatum(OS
, "source functions with location", NumFuncsWithSrcLoc
);
559 printDatum(OS
, "inlined functions", NumInlinedFunctions
);
560 printDatum(OS
, "inlined funcs with abstract origins", NumAbstractOrigins
);
561 printDatum(OS
, "unique source variables", VarParamUnique
);
562 printDatum(OS
, "source variables", VarParamTotal
);
563 printDatum(OS
, "variables with location", VarParamWithLoc
);
564 printDatum(OS
, "call site entries", GlobalStats
.CallSiteEntries
);
565 printDatum(OS
, "call site DIEs", GlobalStats
.CallSiteDIEs
);
566 printDatum(OS
, "call site parameter DIEs", GlobalStats
.CallSiteParamDIEs
);
567 printDatum(OS
, "scope bytes total",
568 GlobalStats
.ScopeBytesFromFirstDefinition
);
569 printDatum(OS
, "scope bytes covered", GlobalStats
.ScopeBytesCovered
);
570 printDatum(OS
, "entry value scope bytes covered",
571 GlobalStats
.ScopeEntryValueBytesCovered
);
572 printDatum(OS
, "formal params scope bytes total",
573 GlobalStats
.ParamScopeBytesFromFirstDefinition
);
574 printDatum(OS
, "formal params scope bytes covered",
575 GlobalStats
.ParamScopeBytesCovered
);
576 printDatum(OS
, "formal params entry value scope bytes covered",
577 GlobalStats
.ParamScopeEntryValueBytesCovered
);
578 printDatum(OS
, "vars scope bytes total",
579 GlobalStats
.VarScopeBytesFromFirstDefinition
);
580 printDatum(OS
, "vars scope bytes covered", GlobalStats
.VarScopeBytesCovered
);
581 printDatum(OS
, "vars entry value scope bytes covered",
582 GlobalStats
.VarScopeEntryValueBytesCovered
);
583 printDatum(OS
, "total function size", GlobalStats
.FunctionSize
);
584 printDatum(OS
, "total inlined function size", GlobalStats
.InlineFunctionSize
);
585 printDatum(OS
, "total formal params", ParamTotal
);
586 printDatum(OS
, "formal params with source location", ParamWithSrcLoc
);
587 printDatum(OS
, "formal params with type", ParamWithType
);
588 printDatum(OS
, "formal params with binary location", ParamWithLoc
);
589 printDatum(OS
, "total vars", VarTotal
);
590 printDatum(OS
, "vars with source location", VarWithSrcLoc
);
591 printDatum(OS
, "vars with type", VarWithType
);
592 printDatum(OS
, "vars with binary location", VarWithLoc
);
593 printDatum(OS
, "total variables procesed by location statistics",
594 LocStats
.NumVarParam
);
595 printLocationStats(OS
, "variables", LocStats
.VarParamLocStats
);
596 printLocationStats(OS
, "variables (excluding the debug entry values)",
597 LocStats
.VarParamNonEntryValLocStats
);
598 printDatum(OS
, "total params procesed by location statistics",
600 printLocationStats(OS
, "params", LocStats
.ParamLocStats
);
601 printLocationStats(OS
, "params (excluding the debug entry values)",
602 LocStats
.ParamNonEntryValLocStats
);
603 printDatum(OS
, "total vars procesed by location statistics", LocStats
.NumVar
);
604 printLocationStats(OS
, "vars", LocStats
.VarLocStats
);
605 printLocationStats(OS
, "vars (excluding the debug entry values)",
606 LocStats
.ParamNonEntryValLocStats
);
609 llvm::dbgs() << "Total Availability: "
610 << (int)std::round((VarParamWithLoc
* 100.0) / VarParamTotal
)
612 llvm::dbgs() << "PC Ranges covered: "
613 << (int)std::round((GlobalStats
.ScopeBytesCovered
* 100.0) /
614 GlobalStats
.ScopeBytesFromFirstDefinition
)