llvm.org GIT mirror llvm / 4964f4e
[utils] Implement the llvm-locstats tool The tool reports verbose output for the DWARF debug location coverage. The llvm-locstats for each variable or formal parameter DIE computes what percentage from the code section bytes, where it is in scope, it has location description. The line 0 shows the number (and the percentage) of DIEs with no location information, but the line 100 shows the number (and the percentage) of DIEs where there is location information in all code section bytes (where the variable or parameter is in the scope). The line 50..59 shows the number (and the percentage) of DIEs where the location information is in between 50 and 59 percentage of its scope covered. The tool will be very useful for tracking improvements regarding the "debugging optimized code" support with LLVM ecosystem. Differential Revision: https://reviews.llvm.org/D66526 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@371520 91177308-0d34-0410-b5e6-96231b3b80d8 Djordje Todorovic a month ago
6 changed file(s) with 315 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
11041104 add_subdirectory(utils/benchmark)
11051105 add_subdirectory(benchmarks)
11061106 endif()
1107
1108 if (LLVM_INCLUDE_UTILS)
1109 add_subdirectory(utils/llvm-locstats)
1110 endif()
7373 llvm-build
7474 llvm-exegesis
7575 llvm-pdbutil
76 llvm-locstats
0 llvm-locstats - calculate statistics on DWARF debug location
1 ============================================================
2
3 .. program:: llvm-locstats
4
5 SYNOPSIS
6 --------
7
8 :program:`llvm-locstats` [*options*] [*filename*]
9
10 DESCRIPTION
11 -----------
12
13 :program:`llvm-locstats` works like a wrapper around :program:`llvm-dwarfdump`.
14 It parses :program:`llvm-dwarfdump` statistics regarding debug location by
15 pretty printing it in a more human readable way.
16
17 The line 0% shows the number and the percentage of DIEs with no location
18 information, but the line 100% shows the information for DIEs where there is
19 location information in all code section bytes (where the variable or parameter
20 is in the scope). The line 50-59% shows the number and the percentage of DIEs
21 where the location information is between 50 and 59 percentage of its scope
22 covered.
23
24 OPTIONS
25 -------
26
27 .. option:: -only-variables
28
29 Calculate the location statistics only for local variables.
30
31 .. option:: -only-formal-parameters
32
33 Calculate the location statistics only for formal parameters.
34
35 .. option:: -ignore-debug-entry-values
36
37 Ignore the location statistics on locations containing the
38 debug entry values DWARF operation.
39
40 EXIT STATUS
41 -----------
42
43 :program:`llvm-locstats` returns 0 if the input file were parsed
44 successfully. Otherwise, it returns 1.
45
46 OUTPUT EXAMPLE
47 --------------
48
49 .. code-block:: none
50
51 =================================================
52 Debug Location Statistics
53 =================================================
54 cov% samples percentage(~)
55 -------------------------------------------------
56 0% 1 16%
57 1-9% 0 0%
58 10-19% 0 0%
59 20-29% 0 0%
60 30-39% 0 0%
61 40-49% 0 0%
62 50-99% 1 16%
63 60-69% 0 0%
64 70-79% 0 0%
65 80-89% 1 16%
66 90-99% 0 0%
67 100% 3 50%
68 =================================================
69 -the number of debug variables processed: 6
70 -PC ranges covered: 81%
71 -------------------------------------------------
72 -total availability: 83%
73 =================================================
74
75 SEE ALSO
76 --------
77
78 :manpage:`llvm-dwarfdump(1)`
0 ; RUN: llc -debug-entry-values %s -o - -filetype=obj \
11 ; RUN: | llvm-dwarfdump -statistics - | FileCheck %s
2 ;
3 ; RUN: llc -debug-entry-values %s -o %t0.o -filetype=obj \
4 ; RUN: | llvm-locstats %t0.o | FileCheck %s --check-prefix=LOCSTATS
25 ;
36 ; CHECK: "entry value scope bytes covered":5
47 ; CHECK: "formal params scope bytes total":20
8386 ; CHECK: "vars (excluding the debug entry values) with 90-99% of its scope covered":0
8487 ; CHECK: "vars (excluding the debug entry values) with 100% of its scope covered":1}
8588 ;
89 ; Test the llvm-locstats output.
90 ; LOCSTATS: 0% 1 16%
91 ; LOCSTATS: 1-9% 0 0%
92 ; LOCSTATS: 10-19% 0 0%
93 ; LOCSTATS: 20-29% 0 0%
94 ; LOCSTATS: 30-39% 0 0%
95 ; LOCSTATS: 40-49% 0 0%
96 ; LOCSTATS: 50-59% 1 16%
97 ; LOCSTATS: 60-69% 0 0%
98 ; LOCSTATS: 70-79% 0 0%
99 ; LOCSTATS: 80-89% 1 16%
100 ; LOCSTATS: 90-99% 0 0%
101 ; LOCSTATS: 100% 3 50%
102 ;
86103 ; The source code of the test case:
87104 ; extern void fn3(int *);
88105 ; extern void fn2 (int);
0 if (LLVM_BUILD_UTILS)
1 add_custom_target(llvm-locstats ALL
2 COMMAND ${CMAKE_COMMAND} -E copy ${LLVM_MAIN_SRC_DIR}/utils/llvm-locstats/llvm-locstats.py ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/llvm-locstats
3 )
4 set_target_properties(llvm-locstats PROPERTIES FOLDER "Utils")
5 endif()
0 #!/usr/bin/env python
1 #
2 # This is a tool that works like debug location coverage calculator.
3 # It parses the llvm-dwarfdump --statistics output by reporting it
4 # in a more human readable way.
5 #
6
7 from __future__ import print_function
8 import argparse
9 import os
10 import sys
11 from json import loads
12 from math import ceil
13 from subprocess import Popen, PIPE
14
15 def coverage_buckets():
16 yield '0%'
17 yield '1-9%'
18 for start in range(10, 91, 10):
19 yield '{0}-{1}%'.format(start, start + 9)
20 yield '100%'
21
22 def locstats_output(
23 variables_total,
24 variables_total_locstats,
25 variables_with_loc,
26 scope_bytes_covered,
27 scope_bytes_from_first_def,
28 variables_coverage_map
29 ):
30
31 pc_ranges_covered = int(ceil(scope_bytes_covered * 100.0)
32 / scope_bytes_from_first_def)
33 variables_coverage_per_map = {}
34 for cov_bucket in coverage_buckets():
35 variables_coverage_per_map[cov_bucket] = \
36 int(ceil(variables_coverage_map[cov_bucket] * 100.0) \
37 / variables_total_locstats)
38
39 print (' =================================================')
40 print (' Debug Location Statistics ')
41 print (' =================================================')
42 print (' cov% samples percentage(~) ')
43 print (' -------------------------------------------------')
44 for cov_bucket in coverage_buckets():
45 print (' {0:6} {1:8d} {2:3d}%'. \
46 format(cov_bucket, variables_coverage_map[cov_bucket], \
47 variables_coverage_per_map[cov_bucket]))
48 print (' =================================================')
49 print (' -the number of debug variables processed: ' \
50 + str(variables_total_locstats))
51 print (' -PC ranges covered: ' + str(pc_ranges_covered) + '%')
52
53 # Only if we are processing all the variables output the total
54 # availability.
55 if variables_total and variables_with_loc:
56 total_availability = int(ceil(variables_with_loc * 100.0) \
57 / variables_total)
58 print (' -------------------------------------------------')
59 print (' -total availability: ' + str(total_availability) + '%')
60 print (' =================================================')
61
62 def parse_program_args(parser):
63 parser.add_argument('-only-variables', action='store_true',
64 default=False,
65 help='calculate the location statistics only for '
66 'local variables'
67 )
68 parser.add_argument('-only-formal-parameters', action='store_true',
69 default=False,
70 help='calculate the location statistics only for '
71 'formal parameters'
72 )
73 parser.add_argument('-ignore-debug-entry-values', action='store_true',
74 default=False,
75 help='ignore the location statistics on locations with '
76 'entry values'
77 )
78 parser.add_argument('file_name', type=str, help='file to process')
79 return parser.parse_args()
80
81
82 def Main():
83 parser = argparse.ArgumentParser()
84 results = parse_program_args(parser)
85
86 if len(sys.argv) < 2:
87 print ('error: Too few arguments.')
88 parser.print_help()
89 sys.exit(1)
90
91 if results.only_variables and results.only_formal_parameters:
92 print ('error: Please use just one only* option.')
93 parser.print_help()
94 sys.exit(1)
95
96 # These will be different due to different options enabled.
97 variables_total = None
98 variables_total_locstats = None
99 variables_with_loc = None
100 variables_scope_bytes_covered = None
101 variables_scope_bytes_from_first_def = None
102 variables_scope_bytes_entry_values = None
103 variables_coverage_map = {}
104 binary = results.file_name
105
106 # Get the directory of the LLVM tools.
107 llvm_dwarfdump_cmd = os.path.join(os.path.dirname(__file__), \
108 "llvm-dwarfdump")
109 # The statistics llvm-dwarfdump option.
110 llvm_dwarfdump_stats_opt = "--statistics"
111
112 subproc = Popen([llvm_dwarfdump_cmd, llvm_dwarfdump_stats_opt, binary], \
113 stdin=PIPE, stdout=PIPE, stderr=PIPE, \
114 universal_newlines = True)
115 cmd_stdout, cmd_stderr = subproc.communicate()
116
117 # Get the JSON and parse it.
118 json_parsed = None
119
120 try:
121 json_parsed = loads(cmd_stdout)
122 except:
123 print ('error: No valid llvm-dwarfdump statistics found.')
124 sys.exit(1)
125
126 if results.only_variables:
127 # Read the JSON only for local variables.
128 variables_total_locstats = \
129 json_parsed['total vars procesed by location statistics']
130 variables_scope_bytes_covered = \
131 json_parsed['vars scope bytes covered']
132 variables_scope_bytes_from_first_def = \
133 json_parsed['vars scope bytes total']
134 if not results.ignore_debug_entry_values:
135 for cov_bucket in coverage_buckets():
136 cov_category = "vars with {} of its scope covered".format(cov_bucket)
137 variables_coverage_map[cov_bucket] = json_parsed[cov_category]
138 else:
139 variables_scope_bytes_entry_values = \
140 json_parsed['vars entry value scope bytes covered']
141 variables_scope_bytes_covered = variables_scope_bytes_covered \
142 - variables_scope_bytes_entry_values
143 for cov_bucket in coverage_buckets():
144 cov_category = \
145 "vars (excluding the debug entry values) " \
146 "with {} of its scope covered".format(cov_bucket)
147 variables_coverage_map[cov_bucket] = json_parsed[cov_category]
148 elif results.only_formal_parameters:
149 # Read the JSON only for formal parameters.
150 variables_total_locstats = \
151 json_parsed['total params procesed by location statistics']
152 variables_scope_bytes_covered = \
153 json_parsed['formal params scope bytes covered']
154 variables_scope_bytes_from_first_def = \
155 json_parsed['formal params scope bytes total']
156 if not results.ignore_debug_entry_values:
157 for cov_bucket in coverage_buckets():
158 cov_category = "params with {} of its scope covered".format(cov_bucket)
159 variables_coverage_map[cov_bucket] = json_parsed[cov_category]
160 else:
161 variables_scope_bytes_entry_values = \
162 json_parsed['formal params entry value scope bytes covered']
163 variables_scope_bytes_covered = variables_scope_bytes_covered \
164 - variables_scope_bytes_entry_values
165 for cov_bucket in coverage_buckets():
166 cov_category = \
167 "params (excluding the debug entry values) " \
168 "with {} of its scope covered".format(cov_bucket)
169 else:
170 # Read the JSON for both local variables and formal parameters.
171 variables_total = \
172 json_parsed['source variables']
173 variables_with_loc = json_parsed['variables with location']
174 variables_total_locstats = \
175 json_parsed['total variables procesed by location statistics']
176 variables_scope_bytes_covered = \
177 json_parsed['scope bytes covered']
178 variables_scope_bytes_from_first_def = \
179 json_parsed['scope bytes total']
180 if not results.ignore_debug_entry_values:
181 for cov_bucket in coverage_buckets():
182 cov_category = "variables with {} of its scope covered". \
183 format(cov_bucket)
184 variables_coverage_map[cov_bucket] = json_parsed[cov_category]
185 else:
186 variables_scope_bytes_entry_values = \
187 json_parsed['entry value scope bytes covered']
188 variables_scope_bytes_covered = variables_scope_bytes_covered \
189 - variables_scope_bytes_entry_values
190 for cov_bucket in coverage_buckets():
191 cov_category = "variables (excluding the debug entry values) " \
192 "with {} of its scope covered". format(cov_bucket)
193 variables_coverage_map[cov_bucket] = json_parsed[cov_category]
194
195 # Pretty print collected info.
196 locstats_output(
197 variables_total,
198 variables_total_locstats,
199 variables_with_loc,
200 variables_scope_bytes_covered,
201 variables_scope_bytes_from_first_def,
202 variables_coverage_map
203 )
204
205 if __name__ == '__main__':
206 Main()
207 sys.exit(0)