blob: 408513c319161aa10d67eeabe98f284fad458caa [file] [log] [blame]
Djordje Todorovic2ef18fb2019-10-02 07:00:01 +00001#!/usr/bin/env python
2#
3# This is a tool that works like debug location coverage calculator.
4# It parses the llvm-dwarfdump --statistics output by reporting it
5# in a more human readable way.
6#
7
8from __future__ import print_function
9import argparse
10import os
11import sys
12from json import loads
13from math import ceil
14from subprocess import Popen, PIPE
15
16def coverage_buckets():
17 yield '0%'
18 yield '1-9%'
19 for start in range(10, 91, 10):
20 yield '{0}-{1}%'.format(start, start + 9)
21 yield '100%'
22
23def locstats_output(
24 variables_total,
25 variables_total_locstats,
26 variables_with_loc,
27 scope_bytes_covered,
Kristina Bessonova68f464a2019-11-19 13:28:21 +030028 scope_bytes,
Djordje Todorovic2ef18fb2019-10-02 07:00:01 +000029 variables_coverage_map
30 ):
31
Djordje Todorovicbaea9132019-12-12 14:31:50 +010032 if scope_bytes == 0:
33 print ('No scope bytes found.')
34 sys.exit(0)
35
Djordje Todorovic2ef18fb2019-10-02 07:00:01 +000036 pc_ranges_covered = int(ceil(scope_bytes_covered * 100.0)
Kristina Bessonova68f464a2019-11-19 13:28:21 +030037 / scope_bytes)
Djordje Todorovic2ef18fb2019-10-02 07:00:01 +000038 variables_coverage_per_map = {}
39 for cov_bucket in coverage_buckets():
40 variables_coverage_per_map[cov_bucket] = \
41 int(ceil(variables_coverage_map[cov_bucket] * 100.0) \
42 / variables_total_locstats)
43
44 print (' =================================================')
45 print (' Debug Location Statistics ')
46 print (' =================================================')
47 print (' cov% samples percentage(~) ')
48 print (' -------------------------------------------------')
49 for cov_bucket in coverage_buckets():
50 print (' {0:6} {1:8d} {2:3d}%'. \
51 format(cov_bucket, variables_coverage_map[cov_bucket], \
52 variables_coverage_per_map[cov_bucket]))
53 print (' =================================================')
54 print (' -the number of debug variables processed: ' \
55 + str(variables_total_locstats))
56 print (' -PC ranges covered: ' + str(pc_ranges_covered) + '%')
57
58 # Only if we are processing all the variables output the total
59 # availability.
60 if variables_total and variables_with_loc:
61 total_availability = int(ceil(variables_with_loc * 100.0) \
62 / variables_total)
63 print (' -------------------------------------------------')
64 print (' -total availability: ' + str(total_availability) + '%')
65 print (' =================================================')
66
67def parse_program_args(parser):
68 parser.add_argument('-only-variables', action='store_true',
69 default=False,
70 help='calculate the location statistics only for '
71 'local variables'
72 )
73 parser.add_argument('-only-formal-parameters', action='store_true',
74 default=False,
75 help='calculate the location statistics only for '
76 'formal parameters'
77 )
78 parser.add_argument('-ignore-debug-entry-values', action='store_true',
79 default=False,
80 help='ignore the location statistics on locations with '
81 'entry values'
82 )
83 parser.add_argument('file_name', type=str, help='file to process')
84 return parser.parse_args()
85
86
87def Main():
88 parser = argparse.ArgumentParser()
89 results = parse_program_args(parser)
90
91 if len(sys.argv) < 2:
92 print ('error: Too few arguments.')
93 parser.print_help()
94 sys.exit(1)
95
96 if results.only_variables and results.only_formal_parameters:
97 print ('error: Please use just one only* option.')
98 parser.print_help()
99 sys.exit(1)
100
101 # These will be different due to different options enabled.
102 variables_total = None
103 variables_total_locstats = None
104 variables_with_loc = None
105 variables_scope_bytes_covered = None
Kristina Bessonova68f464a2019-11-19 13:28:21 +0300106 variables_scope_bytes = None
Djordje Todorovic2ef18fb2019-10-02 07:00:01 +0000107 variables_scope_bytes_entry_values = None
108 variables_coverage_map = {}
109 binary = results.file_name
110
111 # Get the directory of the LLVM tools.
112 llvm_dwarfdump_cmd = os.path.join(os.path.dirname(__file__), \
113 "llvm-dwarfdump")
114 # The statistics llvm-dwarfdump option.
115 llvm_dwarfdump_stats_opt = "--statistics"
116
117 subproc = Popen([llvm_dwarfdump_cmd, llvm_dwarfdump_stats_opt, binary], \
118 stdin=PIPE, stdout=PIPE, stderr=PIPE, \
119 universal_newlines = True)
120 cmd_stdout, cmd_stderr = subproc.communicate()
121
122 # Get the JSON and parse it.
123 json_parsed = None
124
125 try:
126 json_parsed = loads(cmd_stdout)
127 except:
128 print ('error: No valid llvm-dwarfdump statistics found.')
129 sys.exit(1)
130
131 if results.only_variables:
132 # Read the JSON only for local variables.
133 variables_total_locstats = \
134 json_parsed['total vars procesed by location statistics']
135 variables_scope_bytes_covered = \
136 json_parsed['vars scope bytes covered']
Kristina Bessonova68f464a2019-11-19 13:28:21 +0300137 variables_scope_bytes = \
Djordje Todorovic2ef18fb2019-10-02 07:00:01 +0000138 json_parsed['vars scope bytes total']
139 if not results.ignore_debug_entry_values:
140 for cov_bucket in coverage_buckets():
141 cov_category = "vars with {} of its scope covered".format(cov_bucket)
142 variables_coverage_map[cov_bucket] = json_parsed[cov_category]
143 else:
144 variables_scope_bytes_entry_values = \
145 json_parsed['vars entry value scope bytes covered']
146 variables_scope_bytes_covered = variables_scope_bytes_covered \
147 - variables_scope_bytes_entry_values
148 for cov_bucket in coverage_buckets():
149 cov_category = \
150 "vars (excluding the debug entry values) " \
151 "with {} of its scope covered".format(cov_bucket)
152 variables_coverage_map[cov_bucket] = json_parsed[cov_category]
153 elif results.only_formal_parameters:
154 # Read the JSON only for formal parameters.
155 variables_total_locstats = \
156 json_parsed['total params procesed by location statistics']
157 variables_scope_bytes_covered = \
158 json_parsed['formal params scope bytes covered']
Kristina Bessonova68f464a2019-11-19 13:28:21 +0300159 variables_scope_bytes = \
Djordje Todorovic2ef18fb2019-10-02 07:00:01 +0000160 json_parsed['formal params scope bytes total']
161 if not results.ignore_debug_entry_values:
162 for cov_bucket in coverage_buckets():
163 cov_category = "params with {} of its scope covered".format(cov_bucket)
164 variables_coverage_map[cov_bucket] = json_parsed[cov_category]
165 else:
166 variables_scope_bytes_entry_values = \
167 json_parsed['formal params entry value scope bytes covered']
168 variables_scope_bytes_covered = variables_scope_bytes_covered \
169 - variables_scope_bytes_entry_values
170 for cov_bucket in coverage_buckets():
171 cov_category = \
172 "params (excluding the debug entry values) " \
173 "with {} of its scope covered".format(cov_bucket)
Djordje Todorovic095531e2019-10-15 10:12:14 +0000174 variables_coverage_map[cov_bucket] = json_parsed[cov_category]
Djordje Todorovic2ef18fb2019-10-02 07:00:01 +0000175 else:
176 # Read the JSON for both local variables and formal parameters.
177 variables_total = \
178 json_parsed['source variables']
179 variables_with_loc = json_parsed['variables with location']
180 variables_total_locstats = \
181 json_parsed['total variables procesed by location statistics']
182 variables_scope_bytes_covered = \
183 json_parsed['scope bytes covered']
Kristina Bessonova68f464a2019-11-19 13:28:21 +0300184 variables_scope_bytes = \
Djordje Todorovic2ef18fb2019-10-02 07:00:01 +0000185 json_parsed['scope bytes total']
186 if not results.ignore_debug_entry_values:
187 for cov_bucket in coverage_buckets():
188 cov_category = "variables with {} of its scope covered". \
189 format(cov_bucket)
190 variables_coverage_map[cov_bucket] = json_parsed[cov_category]
191 else:
192 variables_scope_bytes_entry_values = \
193 json_parsed['entry value scope bytes covered']
194 variables_scope_bytes_covered = variables_scope_bytes_covered \
195 - variables_scope_bytes_entry_values
196 for cov_bucket in coverage_buckets():
197 cov_category = "variables (excluding the debug entry values) " \
198 "with {} of its scope covered". format(cov_bucket)
199 variables_coverage_map[cov_bucket] = json_parsed[cov_category]
200
201 # Pretty print collected info.
202 locstats_output(
203 variables_total,
204 variables_total_locstats,
205 variables_with_loc,
206 variables_scope_bytes_covered,
Kristina Bessonova68f464a2019-11-19 13:28:21 +0300207 variables_scope_bytes,
Djordje Todorovic2ef18fb2019-10-02 07:00:01 +0000208 variables_coverage_map
209 )
210
211if __name__ == '__main__':
212 Main()
213 sys.exit(0)