llvm.org GIT mirror llvm / 1b050ab
[llvm-dwarfdump] Add additional stats fields The additional fields will be parsed by the llvm-locstats tool in order to produce more human readable output of the DWARF debug location quality generated. Differential Revision: https://reviews.llvm.org/D66525 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@371506 91177308-0d34-0410-b5e6-96231b3b80d8 Djordje Todorovic a month ago
2 changed file(s) with 416 addition(s) and 13 deletion(s). Raw diff Collapse all Expand all
0 ; RUN: llc -debug-entry-values %s -o - -filetype=obj \
1 ; RUN: | llvm-dwarfdump -statistics - | FileCheck %s
2 ;
3 ; CHECK: "entry value scope bytes covered":5
4 ; CHECK: "formal params scope bytes total":20
5 ; CHECK: "formal params scope bytes covered":20
6 ; CHECK: "formal params entry value scope bytes covered":5
7 ; CHECK: "vars scope bytes total":78
8 ; CHECK: "vars scope bytes covered":60
9 ; CHECK: "vars entry value scope bytes covered":0
10 ; CHECK: "total variables procesed by location statistics":6
11 ; CHECK: "variables with 0% of its scope covered":1
12 ; CHECK: "variables with 1-9% of its scope covered":0
13 ; CHECK: "variables with 10-19% of its scope covered":0
14 ; CHECK: "variables with 20-29% of its scope covered":0
15 ; CHECK: "variables with 30-39% of its scope covered":0
16 ; CHECK: "variables with 40-49% of its scope covered":0
17 ; CHECK: "variables with 50-59% of its scope covered":1
18 ; CHECK: "variables with 60-69% of its scope covered":0
19 ; CHECK: "variables with 70-79% of its scope covered":0
20 ; CHECK: "variables with 80-89% of its scope covered":1
21 ; CHECK: "variables with 90-99% of its scope covered":0
22 ; CHECK: "variables with 100% of its scope covered":3
23 ; CHECK: "variables (excluding the debug entry values) with 0% of its scope covered":1
24 ; CHECK: "variables (excluding the debug entry values) with 1-9% of its scope covered":0
25 ; CHECK: "variables (excluding the debug entry values) with 10-19% of its scope covered":0
26 ; CHECK: "variables (excluding the debug entry values) with 20-29% of its scope covered":0
27 ; CHECK: "variables (excluding the debug entry values) with 30-39% of its scope covered":0
28 ; CHECK: "variables (excluding the debug entry values) with 40-49% of its scope covered":0
29 ; CHECK: "variables (excluding the debug entry values) with 50-59% of its scope covered":2
30 ; CHECK: "variables (excluding the debug entry values) with 60-69% of its scope covered":0
31 ; CHECK: "variables (excluding the debug entry values) with 70-79% of its scope covered":0
32 ; CHECK: "variables (excluding the debug entry values) with 80-89% of its scope covered":1
33 ; CHECK: "variables (excluding the debug entry values) with 90-99% of its scope covered":0
34 ; CHECK: "variables (excluding the debug entry values) with 100% of its scope covered":2
35 ; CHECK: "total params procesed by location statistics":2
36 ; CHECK: "params with 0% of its scope covered":0
37 ; CHECK: "params with 1-9% of its scope covered":0
38 ; CHECK: "params with 10-19% of its scope covered":0
39 ; CHECK: "params with 20-29% of its scope covered":0
40 ; CHECK: "params with 30-39% of its scope covered":0
41 ; CHECK: "params with 40-49% of its scope covered":0
42 ; CHECK: "params with 50-59% of its scope covered":0
43 ; CHECK: "params with 60-69% of its scope covered":0
44 ; CHECK: "params with 70-79% of its scope covered":0
45 ; CHECK: "params with 80-89% of its scope covered":0
46 ; CHECK: "params with 90-99% of its scope covered":0
47 ; CHECK: "params with 100% of its scope covered":2
48 ; CHECK: "params (excluding the debug entry values) with 0% of its scope covered":0
49 ; CHECK: "params (excluding the debug entry values) with 1-9% of its scope covered":0
50 ; CHECK: "params (excluding the debug entry values) with 10-19% of its scope covered":0
51 ; CHECK: "params (excluding the debug entry values) with 20-29% of its scope covered":0
52 ; CHECK: "params (excluding the debug entry values) with 30-39% of its scope covered":0
53 ; CHECK: "params (excluding the debug entry values) with 40-49% of its scope covered":0
54 ; CHECK: "params (excluding the debug entry values) with 50-59% of its scope covered":1
55 ; CHECK: "params (excluding the debug entry values) with 60-69% of its scope covered":0
56 ; CHECK: "params (excluding the debug entry values) with 70-79% of its scope covered":0
57 ; CHECK: "params (excluding the debug entry values) with 80-89% of its scope covered":0
58 ; CHECK: "params (excluding the debug entry values) with 90-99% of its scope covered":0
59 ; CHECK: "params (excluding the debug entry values) with 100% of its scope covered":1
60 ; CHECK: "total vars procesed by location statistics":4
61 ; CHECK: "vars with 0% of its scope covered":1
62 ; CHECK: "vars with 1-9% of its scope covered":0
63 ; CHECK: "vars with 10-19% of its scope covered":0
64 ; CHECK: "vars with 20-29% of its scope covered":0
65 ; CHECK: "vars with 30-39% of its scope covered":0
66 ; CHECK: "vars with 40-49% of its scope covered":0
67 ; CHECK: "vars with 50-59% of its scope covered":1
68 ; CHECK: "vars with 60-69% of its scope covered":0
69 ; CHECK: "vars with 70-79% of its scope covered":0
70 ; CHECK: "vars with 80-89% of its scope covered":1
71 ; CHECK: "vars with 90-99% of its scope covered":0
72 ; CHECK: "vars with 100% of its scope covered":1
73 ; CHECK: "vars (excluding the debug entry values) with 0% of its scope covered":0
74 ; CHECK: "vars (excluding the debug entry values) with 1-9% of its scope covered":0
75 ; CHECK: "vars (excluding the debug entry values) with 10-19% of its scope covered":0
76 ; CHECK: "vars (excluding the debug entry values) with 20-29% of its scope covered":0
77 ; CHECK: "vars (excluding the debug entry values) with 30-39% of its scope covered":0
78 ; CHECK: "vars (excluding the debug entry values) with 40-49% of its scope covered":0
79 ; CHECK: "vars (excluding the debug entry values) with 50-59% of its scope covered":1
80 ; CHECK: "vars (excluding the debug entry values) with 60-69% of its scope covered":0
81 ; CHECK: "vars (excluding the debug entry values) with 70-79% of its scope covered":0
82 ; CHECK: "vars (excluding the debug entry values) with 80-89% of its scope covered":0
83 ; CHECK: "vars (excluding the debug entry values) with 90-99% of its scope covered":0
84 ; CHECK: "vars (excluding the debug entry values) with 100% of its scope covered":1}
85 ;
86 ; The source code of the test case:
87 ; extern void fn3(int *);
88 ; extern void fn2 (int);
89 ; __attribute__((noinline))
90 ; void
91 ; fn1 (int x, int y)
92 ; {
93 ; int u = x + y;
94 ; if (x > 1)
95 ; u += 1;
96 ; else
97 ; u += 2;
98 ; if (y > 4)
99 ; u += x;
100 ; int a = 7;
101 ; fn2 (a);
102 ; u --;
103 ; }
104 ;
105 ; __attribute__((noinline))
106 ; int f()
107 ; {
108 ; int l, k;
109 ; fn3(&l);
110 ; fn3(&k);
111 ; fn1 (l, k);
112 ; return 0;
113 ; }
114 ;
115 ; ModuleID = 'test.c'
116 source_filename = "test.c"
117 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
118 target triple = "x86_64-unknown-linux-gnu"
119
120 ; Function Attrs: noinline nounwind uwtable
121 define dso_local void @fn1(i32 %x, i32 %y) local_unnamed_addr !dbg !16 {
122 entry:
123 call void @llvm.dbg.value(metadata i32 %x, metadata !20, metadata !DIExpression()), !dbg !24
124 call void @llvm.dbg.value(metadata i32 %y, metadata !21, metadata !DIExpression()), !dbg !24
125 call void @llvm.dbg.value(metadata i32 undef, metadata !22, metadata !DIExpression()), !dbg !24
126 call void @llvm.dbg.value(metadata i32 undef, metadata !22, metadata !DIExpression()), !dbg !24
127 call void @llvm.dbg.value(metadata i32 7, metadata !23, metadata !DIExpression()), !dbg !24
128 tail call void @fn2(i32 7), !dbg !25
129 call void @llvm.dbg.value(metadata i32 undef, metadata !22, metadata !DIExpression(DW_OP_constu, 1, DW_OP_minus, DW_OP_stack_value)), !dbg !24
130 ret void, !dbg !26
131 }
132
133 ; Function Attrs: argmemonly nounwind willreturn
134 declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture)
135
136 declare !dbg !4 dso_local void @fn2(i32) local_unnamed_addr
137
138 ; Function Attrs: argmemonly nounwind willreturn
139 declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture)
140
141 ; Function Attrs: noinline nounwind uwtable
142 define dso_local i32 @f() local_unnamed_addr !dbg !27 {
143 entry:
144 %l = alloca i32, align 4
145 %k = alloca i32, align 4
146 %0 = bitcast i32* %l to i8*, !dbg !33
147 call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0), !dbg !33
148 %1 = bitcast i32* %k to i8*, !dbg !33
149 call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %1), !dbg !33
150 call void @llvm.dbg.value(metadata i32* %l, metadata !31, metadata !DIExpression(DW_OP_deref)), !dbg !34
151 call void @fn3(i32* nonnull %l), !dbg !35
152 call void @llvm.dbg.value(metadata i32* %k, metadata !32, metadata !DIExpression(DW_OP_deref)), !dbg !34
153 call void @fn3(i32* nonnull %k), !dbg !36
154 %2 = load i32, i32* %l, align 4, !dbg !37
155 call void @llvm.dbg.value(metadata i32 %2, metadata !31, metadata !DIExpression()), !dbg !34
156 %3 = load i32, i32* %k, align 4, !dbg !37
157 call void @llvm.dbg.value(metadata i32 %3, metadata !32, metadata !DIExpression()), !dbg !34
158 call void @fn1(i32 %2, i32 %3), !dbg !37
159 call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %1), !dbg !37
160 call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %0), !dbg !37
161 ret i32 0, !dbg !37
162 }
163
164 declare !dbg !8 dso_local void @fn3(i32*) local_unnamed_addr
165
166 ; Function Attrs: nounwind readnone speculatable willreturn
167 declare void @llvm.dbg.value(metadata, metadata, metadata)
168
169 !llvm.dbg.cu = !{!0}
170 !llvm.module.flags = !{!12, !13, !14}
171 !llvm.ident = !{!15}
172
173 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None)
174 !1 = !DIFile(filename: "test.c", directory: "/")
175 !2 = !{}
176 !3 = !{!4, !8}
177 !4 = !DISubprogram(name: "fn2", scope: !1, file: !1, line: 2, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
178 !5 = !DISubroutineType(types: !6)
179 !6 = !{null, !7}
180 !7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
181 !8 = !DISubprogram(name: "fn3", scope: !1, file: !1, line: 1, type: !9, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
182 !9 = !DISubroutineType(types: !10)
183 !10 = !{null, !11}
184 !11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
185 !12 = !{i32 2, !"Dwarf Version", i32 4}
186 !13 = !{i32 2, !"Debug Info Version", i32 3}
187 !14 = !{i32 1, !"wchar_size", i32 4}
188 !15 = !{!"clang version 10.0.0"}
189 !16 = distinct !DISubprogram(name: "fn1", scope: !1, file: !1, line: 6, type: !17, scopeLine: 7, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !19)
190 !17 = !DISubroutineType(types: !18)
191 !18 = !{null, !7, !7}
192 !19 = !{!20, !21, !22, !23}
193 !20 = !DILocalVariable(name: "x", arg: 1, scope: !16, file: !1, line: 6, type: !7, flags: DIFlagArgumentNotModified)
194 !21 = !DILocalVariable(name: "y", arg: 2, scope: !16, file: !1, line: 6, type: !7, flags: DIFlagArgumentNotModified)
195 !22 = !DILocalVariable(name: "u", scope: !16, file: !1, line: 8, type: !7)
196 !23 = !DILocalVariable(name: "a", scope: !16, file: !1, line: 18, type: !7)
197 !24 = !DILocation(line: 0, scope: !16)
198 !25 = !DILocation(line: 20, column: 3, scope: !16)
199 !26 = !DILocation(line: 22, column: 1, scope: !16)
200 !27 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 25, type: !28, scopeLine: 26, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !30)
201 !28 = !DISubroutineType(types: !29)
202 !29 = !{!7}
203 !30 = !{!31, !32}
204 !31 = !DILocalVariable(name: "l", scope: !27, file: !1, line: 27, type: !7)
205 !32 = !DILocalVariable(name: "k", scope: !27, file: !1, line: 27, type: !7)
206 !33 = !DILocation(line: 27, column: 3, scope: !27)
207 !34 = !DILocation(line: 0, scope: !27)
208 !35 = !DILocation(line: 29, column: 3, scope: !27)
209 !36 = !DILocation(line: 30, column: 3, scope: !27)
210 !37 = !DILocation(line: 32, column: 8, scope: !27)
88 #define DEBUG_TYPE "dwarfdump"
99 using namespace llvm;
1010 using namespace object;
11
12 /// This represents the number of categories of debug location coverage being
13 /// calculated. The first category is the number of variables with 0% location
14 /// coverage, but the last category is the number of variables with 100%
15 /// location coverage.
16 constexpr int NumOfCoverageCategories = 12;
1117
1218 /// Holds statistics for one function (or other entity that has a PC range and
1319 /// contains variables, such as a compile unit).
5561 /// Total number of PC range bytes in each variable's enclosing scope,
5662 /// starting from the first definition of the variable.
5763 unsigned ScopeBytesFromFirstDefinition = 0;
64 /// Total number of PC range bytes covered by DW_AT_locations with
65 /// the debug entry values (DW_OP_entry_value).
66 unsigned ScopeEntryValueBytesCovered = 0;
67 /// Total number of PC range bytes covered by DW_AT_locations of
68 /// formal parameters.
69 unsigned ParamScopeBytesCovered = 0;
70 /// Total number of PC range bytes in each variable's enclosing scope,
71 /// starting from the first definition of the variable (only for parameters).
72 unsigned ParamScopeBytesFromFirstDefinition = 0;
73 /// Total number of PC range bytes covered by DW_AT_locations with
74 /// the debug entry values (DW_OP_entry_value) (only for parameters).
75 unsigned ParamScopeEntryValueBytesCovered = 0;
76 /// Total number of PC range bytes covered by DW_AT_locations (only for local
77 /// variables).
78 unsigned VarScopeBytesCovered = 0;
79 /// Total number of PC range bytes in each variable's enclosing scope,
80 /// starting from the first definition of the variable (only for local
81 /// variables).
82 unsigned VarScopeBytesFromFirstDefinition = 0;
83 /// Total number of PC range bytes covered by DW_AT_locations with
84 /// the debug entry values (DW_OP_entry_value) (only for local variables).
85 unsigned VarScopeEntryValueBytesCovered = 0;
5886 /// Total number of call site entries (DW_AT_call_file & DW_AT_call_line).
5987 unsigned CallSiteEntries = 0;
6088 /// Total number of call site DIEs (DW_TAG_call_site).
7098 uint64_t InlineFunctionSize = 0;
7199 };
72100
101 /// Holds accumulated debug location statistics about local variables and
102 /// formal parameters.
103 struct LocationStats {
104 /// Map the scope coverage decile to the number of variables in the decile.
105 /// The first element of the array (at the index zero) represents the number
106 /// of variables with the no debug location at all, but the last element
107 /// in the vector represents the number of fully covered variables within
108 /// its scope.
109 std::vector VarParamLocStats{
110 std::vector(NumOfCoverageCategories, 0)};
111 /// Map non debug entry values coverage.
112 std::vector VarParamNonEntryValLocStats{
113 std::vector(NumOfCoverageCategories, 0)};
114 /// The debug location statistics for formal parameters.
115 std::vector ParamLocStats{
116 std::vector(NumOfCoverageCategories, 0)};
117 /// Map non debug entry values coverage for formal parameters.
118 std::vector ParamNonEntryValLocStats{
119 std::vector(NumOfCoverageCategories, 0)};
120 /// The debug location statistics for local variables.
121 std::vector VarLocStats{
122 std::vector(NumOfCoverageCategories, 0)};
123 /// Map non debug entry values coverage for local variables.
124 std::vector VarNonEntryValLocStats{
125 std::vector(NumOfCoverageCategories, 0)};
126 /// Total number of local variables and function parameters processed.
127 unsigned NumVarParam = 0;
128 /// Total number of formal parameters processed.
129 unsigned NumParam = 0;
130 /// Total number of local variables processed.
131 unsigned NumVar = 0;
132 };
133
73134 /// Extract the low pc from a Die.
74135 static uint64_t getLowPC(DWARFDie Die) {
75136 auto RangesOrError = Die.getAddressRanges();
83144 return dwarf::toAddress(Die.find(dwarf::DW_AT_low_pc), 0);
84145 }
85146
147 /// Collect debug location statistics for one DIE.
148 static void collectLocStats(uint64_t BytesCovered, uint64_t BytesInScope,
149 std::vector &VarParamLocStats,
150 std::vector &ParamLocStats,
151 std::vector &VarLocStats, bool IsParam,
152 bool IsLocalVar) {
153 auto getCoverageBucket = [BytesCovered, BytesInScope]() -> unsigned {
154 unsigned LocBucket = 100 * (double)BytesCovered / BytesInScope;
155 if (LocBucket == 0) {
156 // No debug location at all for the variable.
157 return 0;
158 } else if (LocBucket == 100 || BytesCovered > BytesInScope) {
159 // Fully covered variable within its scope.
160 return NumOfCoverageCategories - 1;
161 } else {
162 // Get covered range (e.g. 20%-29%).
163 LocBucket /= 10;
164 return LocBucket + 1;
165 }
166 };
167
168 unsigned CoverageBucket = getCoverageBucket();
169 VarParamLocStats[CoverageBucket]++;
170 if (IsParam)
171 ParamLocStats[CoverageBucket]++;
172 else if (IsLocalVar)
173 VarLocStats[CoverageBucket]++;
174 }
175
86176 /// Collect debug info quality metrics for one DIE.
87177 static void collectStatsForDie(DWARFDie Die, uint64_t UnitLowPC, std::string FnPrefix,
88178 std::string VarPrefix, uint64_t ScopeLowPC,
89179 uint64_t BytesInScope, uint32_t InlineDepth,
90180 StringMap &FnStatMap,
91 GlobalStats &GlobalStats) {
181 GlobalStats &GlobalStats,
182 LocationStats &LocStats) {
92183 bool HasLoc = false;
93184 bool HasSrcLoc = false;
94185 bool HasType = false;
95186 bool IsArtificial = false;
96187 uint64_t BytesCovered = 0;
188 uint64_t BytesEntryValuesCovered = 0;
97189 uint64_t OffsetToFirstDefinition = 0;
190 auto &FnStats = FnStatMap[FnPrefix];
191 bool IsParam = Die.getTag() == dwarf::DW_TAG_formal_parameter;
192 bool IsLocalVar = Die.getTag() == dwarf::DW_TAG_variable;
98193
99194 if (Die.getTag() == dwarf::DW_TAG_call_site ||
100195 Die.getTag() == dwarf::DW_TAG_GNU_call_site) {
108203 return;
109204 }
110205
111 if (Die.getTag() != dwarf::DW_TAG_formal_parameter &&
112 Die.getTag() != dwarf::DW_TAG_variable &&
113 Die.getTag() != dwarf::DW_TAG_member) {
206 if (!IsParam && !IsLocalVar && Die.getTag() != dwarf::DW_TAG_member) {
114207 // Not a variable or constant member.
115208 return;
116209 }
124217
125218 if (Die.find(dwarf::DW_AT_artificial))
126219 IsArtificial = true;
220
221 auto IsEntryValue = [&](ArrayRef D) -> bool {
222 DWARFUnit *U = Die.getDwarfUnit();
223 DataExtractor Data(toStringRef(D),
224 Die.getDwarfUnit()->getContext().isLittleEndian(), 0);
225 DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize());
226 // Consider the expression containing the DW_OP_entry_value as
227 // an entry value.
228 return llvm::any_of(Expression, [](DWARFExpression::Operation &Op) {
229 return Op.getCode() == dwarf::DW_OP_entry_value ||
230 Op.getCode() == dwarf::DW_OP_GNU_entry_value;
231 });
232 };
127233
128234 if (Die.find(dwarf::DW_AT_const_value)) {
129235 // This catches constant members *and* variables.
142248 if (auto DebugLocOffset = FormValue->getAsSectionOffset()) {
143249 auto *DebugLoc = Die.getDwarfUnit()->getContext().getDebugLoc();
144250 if (auto List = DebugLoc->getLocationListAtOffset(*DebugLocOffset)) {
145 for (auto Entry : List->Entries)
146 BytesCovered += Entry.End - Entry.Begin;
251 for (auto Entry : List->Entries) {
252 uint64_t BytesEntryCovered = Entry.End - Entry.Begin;
253 BytesCovered += BytesEntryCovered;
254 if (IsEntryValue(Entry.Loc))
255 BytesEntryValuesCovered += BytesEntryCovered;
256 }
147257 if (List->Entries.size()) {
148258 uint64_t FirstDef = List->Entries[0].Begin;
149259 uint64_t UnitOfs = UnitLowPC;
163273 }
164274 }
165275
276 // Calculate the debug location statistics.
277 if (BytesInScope) {
278 LocStats.NumVarParam++;
279 if (IsParam)
280 LocStats.NumParam++;
281 else if (IsLocalVar)
282 LocStats.NumVar++;
283
284 collectLocStats(BytesCovered, BytesInScope, LocStats.VarParamLocStats,
285 LocStats.ParamLocStats, LocStats.VarLocStats, IsParam,
286 IsLocalVar);
287 // Non debug entry values coverage statistics.
288 collectLocStats(BytesCovered - BytesEntryValuesCovered, BytesInScope,
289 LocStats.VarParamNonEntryValLocStats,
290 LocStats.ParamNonEntryValLocStats,
291 LocStats.VarNonEntryValLocStats, IsParam, IsLocalVar);
292 }
293
166294 // Collect PC range coverage data.
167 auto &FnStats = FnStatMap[FnPrefix];
168295 if (DWARFDie D =
169296 Die.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin))
170297 Die = D;
180307 // Turns out we have a lot of ranges that extend past the lexical scope.
181308 GlobalStats.ScopeBytesCovered += std::min(BytesInScope, BytesCovered);
182309 GlobalStats.ScopeBytesFromFirstDefinition += BytesInScope;
310 GlobalStats.ScopeEntryValueBytesCovered += BytesEntryValuesCovered;
311 if (IsParam) {
312 GlobalStats.ParamScopeBytesCovered +=
313 std::min(BytesInScope, BytesCovered);
314 GlobalStats.ParamScopeBytesFromFirstDefinition += BytesInScope;
315 GlobalStats.ParamScopeEntryValueBytesCovered += BytesEntryValuesCovered;
316 } else if (IsLocalVar) {
317 GlobalStats.VarScopeBytesCovered += std::min(BytesInScope, BytesCovered);
318 GlobalStats.VarScopeBytesFromFirstDefinition += BytesInScope;
319 GlobalStats.VarScopeEntryValueBytesCovered += BytesEntryValuesCovered;
320 }
183321 assert(GlobalStats.ScopeBytesCovered <=
184322 GlobalStats.ScopeBytesFromFirstDefinition);
185323 } else if (Die.getTag() == dwarf::DW_TAG_member) {
188326 FnStats.TotalVarWithLoc += (unsigned)HasLoc;
189327 }
190328 if (!IsArtificial) {
191 if (Die.getTag() == dwarf::DW_TAG_formal_parameter) {
329 if (IsParam) {
192330 FnStats.NumParams++;
193331 if (HasType)
194332 FnStats.NumParamTypes++;
196334 FnStats.NumParamSourceLocations++;
197335 if (HasLoc)
198336 FnStats.NumParamLocations++;
199 } else if (Die.getTag() == dwarf::DW_TAG_variable) {
337 } else if (IsLocalVar) {
200338 FnStats.NumVars++;
201339 if (HasType)
202340 FnStats.NumVarTypes++;
213351 std::string VarPrefix, uint64_t ScopeLowPC,
214352 uint64_t BytesInScope, uint32_t InlineDepth,
215353 StringMap &FnStatMap,
216 GlobalStats &GlobalStats) {
354 GlobalStats &GlobalStats,
355 LocationStats &LocStats) {
217356 // Handle any kind of lexical scope.
218357 const dwarf::Tag Tag = Die.getTag();
219358 const bool IsFunction = Tag == dwarf::DW_TAG_subprogram;
282421 } else {
283422 // Not a scope, visit the Die itself. It could be a variable.
284423 collectStatsForDie(Die, UnitLowPC, FnPrefix, VarPrefix, ScopeLowPC, BytesInScope,
285 InlineDepth, FnStatMap, GlobalStats);
424 InlineDepth, FnStatMap, GlobalStats, LocStats);
286425 }
287426
288427 // Set InlineDepth correctly for child recursion
300439 ChildVarPrefix += toHex(LexicalBlockIndex++) + '.';
301440
302441 collectStatsRecursive(Child, UnitLowPC, FnPrefix, ChildVarPrefix, ScopeLowPC,
303 BytesInScope, InlineDepth, FnStatMap, GlobalStats);
442 BytesInScope, InlineDepth, FnStatMap, GlobalStats,
443 LocStats);
304444 Child = Child.getSibling();
305445 }
306446 }
315455 static void printDatum(raw_ostream &OS, const char *Key, uint64_t Value) {
316456 OS << ",\"" << Key << "\":" << Value;
317457 LLVM_DEBUG(llvm::dbgs() << Key << ": " << Value << '\n');
458 }
459 static void printLocationStats(raw_ostream &OS,
460 const char *Key,
461 std::vector &LocationStats) {
462 OS << ",\"" << Key << " with 0% of its scope covered\":"
463 << LocationStats[0];
464 LLVM_DEBUG(llvm::dbgs() << Key << " with 0% of its scope covered: "
465 << LocationStats[0] << '\n');
466 OS << ",\"" << Key << " with 1-9% of its scope covered\":"
467 << LocationStats[1];
468 LLVM_DEBUG(llvm::dbgs() << Key << " with 1-9% of its scope covered: "
469 << LocationStats[1] << '\n');
470 for (unsigned i = 2; i < NumOfCoverageCategories - 1; ++i) {
471 OS << ",\"" << Key << " with " << (i - 1) * 10 << "-" << i * 10 - 1
472 << "% of its scope covered\":" << LocationStats[i];
473 LLVM_DEBUG(llvm::dbgs()
474 << Key << " with " << (i - 1) * 10 << "-" << i * 10 - 1
475 << "% of its scope covered: " << LocationStats[i]);
476 }
477 OS << ",\"" << Key << " with 100% of its scope covered\":"
478 << LocationStats[NumOfCoverageCategories - 1];
479 LLVM_DEBUG(llvm::dbgs() << Key << " with 100% of its scope covered: "
480 << LocationStats[NumOfCoverageCategories - 1]);
318481 }
319482 /// \}
320483
330493 Twine Filename, raw_ostream &OS) {
331494 StringRef FormatName = Obj.getFileFormatName();
332495 GlobalStats GlobalStats;
496 LocationStats LocStats;
333497 StringMap Statistics;
334498 for (const auto &CU : static_cast(&DICtx)->compile_units())
335499 if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false))
336 collectStatsRecursive(CUDie, getLowPC(CUDie), "/", "g", 0, 0, 0, Statistics, GlobalStats);
500 collectStatsRecursive(CUDie, getLowPC(CUDie), "/", "g", 0, 0, 0,
501 Statistics, GlobalStats, LocStats);
337502
338503 /// The version number should be increased every time the algorithm is changed
339504 /// (including bug fixes). New metrics may be added without increasing the
401566 printDatum(OS, "scope bytes total",
402567 GlobalStats.ScopeBytesFromFirstDefinition);
403568 printDatum(OS, "scope bytes covered", GlobalStats.ScopeBytesCovered);
569 printDatum(OS, "entry value scope bytes covered",
570 GlobalStats.ScopeEntryValueBytesCovered);
571 printDatum(OS, "formal params scope bytes total",
572 GlobalStats.ParamScopeBytesFromFirstDefinition);
573 printDatum(OS, "formal params scope bytes covered",
574 GlobalStats.ParamScopeBytesCovered);
575 printDatum(OS, "formal params entry value scope bytes covered",
576 GlobalStats.ParamScopeEntryValueBytesCovered);
577 printDatum(OS, "vars scope bytes total",
578 GlobalStats.VarScopeBytesFromFirstDefinition);
579 printDatum(OS, "vars scope bytes covered", GlobalStats.VarScopeBytesCovered);
580 printDatum(OS, "vars entry value scope bytes covered",
581 GlobalStats.VarScopeEntryValueBytesCovered);
404582 printDatum(OS, "total function size", GlobalStats.FunctionSize);
405583 printDatum(OS, "total inlined function size", GlobalStats.InlineFunctionSize);
406584 printDatum(OS, "total formal params", ParamTotal);
411589 printDatum(OS, "vars with source location", VarWithSrcLoc);
412590 printDatum(OS, "vars with type", VarWithType);
413591 printDatum(OS, "vars with binary location", VarWithLoc);
592 printDatum(OS, "total variables procesed by location statistics",
593 LocStats.NumVarParam);
594 printLocationStats(OS, "variables", LocStats.VarParamLocStats);
595 printLocationStats(OS, "variables (excluding the debug entry values)",
596 LocStats.VarParamNonEntryValLocStats);
597 printDatum(OS, "total params procesed by location statistics",
598 LocStats.NumParam);
599 printLocationStats(OS, "params", LocStats.ParamLocStats);
600 printLocationStats(OS, "params (excluding the debug entry values)",
601 LocStats.ParamNonEntryValLocStats);
602 printDatum(OS, "total vars procesed by location statistics", LocStats.NumVar);
603 printLocationStats(OS, "vars", LocStats.VarLocStats);
604 printLocationStats(OS, "vars (excluding the debug entry values)",
605 LocStats.ParamNonEntryValLocStats);
414606 OS << "}\n";
415607 LLVM_DEBUG(
416608 llvm::dbgs() << "Total Availability: "