13
13
from math import ceil
14
14
from subprocess import Popen , PIPE
15
15
16
+ # Holds the debug location statistics.
17
+ class LocationStats :
18
+ def __init__ (self , file_name , variables_total , variables_total_locstats ,
19
+ variables_with_loc , variables_scope_bytes_covered , variables_scope_bytes ,
20
+ variables_coverage_map ):
21
+ self .file_name = file_name
22
+ self .variables_total = variables_total
23
+ self .variables_total_locstats = variables_total_locstats
24
+ self .variables_with_loc = variables_with_loc
25
+ self .scope_bytes_covered = variables_scope_bytes_covered
26
+ self .scope_bytes = variables_scope_bytes
27
+ self .variables_coverage_map = variables_coverage_map
28
+
29
+ # Pretty print the debug location buckets.
30
+ def pretty_print (self ):
31
+ if self .scope_bytes == 0 :
32
+ print ('No scope bytes found.' )
33
+ return - 1
34
+
35
+ pc_ranges_covered = int (ceil (self .scope_bytes_covered * 100.0 ) \
36
+ / self .scope_bytes )
37
+ variables_coverage_per_map = {}
38
+ for cov_bucket in coverage_buckets ():
39
+ variables_coverage_per_map [cov_bucket ] = \
40
+ int (ceil (self .variables_coverage_map [cov_bucket ] * 100.0 ) \
41
+ / self .variables_total_locstats )
42
+
43
+ print (' =================================================' )
44
+ print (' Debug Location Statistics ' )
45
+ print (' =================================================' )
46
+ print (' cov% samples percentage(~) ' )
47
+ print (' -------------------------------------------------' )
48
+ for cov_bucket in coverage_buckets ():
49
+ print (' {0:10} {1:8d} {2:3d}%' . \
50
+ format (cov_bucket , self .variables_coverage_map [cov_bucket ], \
51
+ variables_coverage_per_map [cov_bucket ]))
52
+ print (' =================================================' )
53
+ print (' -the number of debug variables processed: ' \
54
+ + str (self .variables_total_locstats ))
55
+ print (' -PC ranges covered: ' + str (pc_ranges_covered ) + '%' )
56
+
57
+ # Only if we are processing all the variables output the total
58
+ # availability.
59
+ if self .variables_total and self .variables_with_loc :
60
+ total_availability = int (ceil (self .variables_with_loc * 100.0 ) \
61
+ / self .variables_total )
62
+ print (' -------------------------------------------------' )
63
+ print (' -total availability: ' + str (total_availability ) + '%' )
64
+ print (' =================================================' )
65
+
66
+ return 0
67
+
68
+ # Define the location buckets.
16
69
def coverage_buckets ():
17
70
yield '0%'
18
71
yield '(0%,10%)'
19
72
for start in range (10 , 91 , 10 ):
20
73
yield '[{0}%,{1}%)' .format (start , start + 10 )
21
74
yield '100%'
22
75
23
- def locstats_output (
24
- variables_total ,
25
- variables_total_locstats ,
26
- variables_with_loc ,
27
- scope_bytes_covered ,
28
- scope_bytes ,
29
- variables_coverage_map
30
- ):
31
-
32
- if scope_bytes == 0 :
33
- print ('No scope bytes found.' )
34
- sys .exit (0 )
35
-
36
- pc_ranges_covered = int (ceil (scope_bytes_covered * 100.0 )
37
- / scope_bytes )
38
- 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:10} {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
-
67
- def 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
-
87
- def 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
-
76
+ # Parse the JSON representing the debug statistics, and create a
77
+ # LocationStats object.
78
+ def parse_locstats (opts , binary ):
101
79
# These will be different due to different options enabled.
102
80
variables_total = None
103
81
variables_total_locstats = None
@@ -106,14 +84,14 @@ def Main():
106
84
variables_scope_bytes = None
107
85
variables_scope_bytes_entry_values = None
108
86
variables_coverage_map = {}
109
- binary = results .file_name
110
87
111
88
# Get the directory of the LLVM tools.
112
89
llvm_dwarfdump_cmd = os .path .join (os .path .dirname (__file__ ), \
113
90
"llvm-dwarfdump" )
114
91
# The statistics llvm-dwarfdump option.
115
92
llvm_dwarfdump_stats_opt = "--statistics"
116
93
94
+ # Generate the stats with the llvm-dwarfdump.
117
95
subproc = Popen ([llvm_dwarfdump_cmd , llvm_dwarfdump_stats_opt , binary ], \
118
96
stdin = PIPE , stdout = PIPE , stderr = PIPE , \
119
97
universal_newlines = True )
@@ -128,15 +106,15 @@ def Main():
128
106
print ('error: No valid llvm-dwarfdump statistics found.' )
129
107
sys .exit (1 )
130
108
131
- if results .only_variables :
109
+ if opts .only_variables :
132
110
# Read the JSON only for local variables.
133
111
variables_total_locstats = \
134
112
json_parsed ['total vars procesed by location statistics' ]
135
113
variables_scope_bytes_covered = \
136
114
json_parsed ['vars scope bytes covered' ]
137
115
variables_scope_bytes = \
138
116
json_parsed ['vars scope bytes total' ]
139
- if not results .ignore_debug_entry_values :
117
+ if not opts .ignore_debug_entry_values :
140
118
for cov_bucket in coverage_buckets ():
141
119
cov_category = "vars with {} of its scope covered" .format (cov_bucket )
142
120
variables_coverage_map [cov_bucket ] = json_parsed [cov_category ]
@@ -150,15 +128,15 @@ def Main():
150
128
"vars (excluding the debug entry values) " \
151
129
"with {} of its scope covered" .format (cov_bucket )
152
130
variables_coverage_map [cov_bucket ] = json_parsed [cov_category ]
153
- elif results .only_formal_parameters :
131
+ elif opts .only_formal_parameters :
154
132
# Read the JSON only for formal parameters.
155
133
variables_total_locstats = \
156
134
json_parsed ['total params procesed by location statistics' ]
157
135
variables_scope_bytes_covered = \
158
136
json_parsed ['formal params scope bytes covered' ]
159
137
variables_scope_bytes = \
160
138
json_parsed ['formal params scope bytes total' ]
161
- if not results .ignore_debug_entry_values :
139
+ if not opts .ignore_debug_entry_values :
162
140
for cov_bucket in coverage_buckets ():
163
141
cov_category = "params with {} of its scope covered" .format (cov_bucket )
164
142
variables_coverage_map [cov_bucket ] = json_parsed [cov_category ]
@@ -183,7 +161,7 @@ def Main():
183
161
json_parsed ['scope bytes covered' ]
184
162
variables_scope_bytes = \
185
163
json_parsed ['scope bytes total' ]
186
- if not results .ignore_debug_entry_values :
164
+ if not opts .ignore_debug_entry_values :
187
165
for cov_bucket in coverage_buckets ():
188
166
cov_category = "variables with {} of its scope covered" . \
189
167
format (cov_bucket )
@@ -198,15 +176,51 @@ def Main():
198
176
"with {} of its scope covered" . format (cov_bucket )
199
177
variables_coverage_map [cov_bucket ] = json_parsed [cov_category ]
200
178
179
+ return LocationStats (binary , variables_total , variables_total_locstats ,
180
+ variables_with_loc , variables_scope_bytes_covered ,
181
+ variables_scope_bytes , variables_coverage_map )
182
+
183
+ # Parse the program arguments.
184
+ def parse_program_args (parser ):
185
+ parser .add_argument ('--only-variables' , action = 'store_true' , default = False ,
186
+ help = 'calculate the location statistics only for local variables' )
187
+ parser .add_argument ('--only-formal-parameters' , action = 'store_true' ,
188
+ default = False ,
189
+ help = 'calculate the location statistics only for formal parameters' )
190
+ parser .add_argument ('--ignore-debug-entry-values' , action = 'store_true' ,
191
+ default = False ,
192
+ help = 'ignore the location statistics on locations with '
193
+ 'entry values' )
194
+ parser .add_argument ('file_name' , type = str , help = 'file to process' )
195
+
196
+ return parser .parse_args ()
197
+
198
+ # Verify that the program inputs meet the requirements.
199
+ def verify_program_inputs (opts ):
200
+ if len (sys .argv ) < 2 :
201
+ print ('error: Too few arguments.' )
202
+ return False
203
+
204
+ if opts .only_variables and opts .only_formal_parameters :
205
+ print ('error: Please use just one --only* option.' )
206
+ return False
207
+
208
+ return True
209
+
210
+ def Main ():
211
+ parser = argparse .ArgumentParser ()
212
+ opts = parse_program_args (parser )
213
+
214
+ if not verify_program_inputs (opts ):
215
+ parser .print_help ()
216
+ sys .exit (1 )
217
+
218
+ binary = opts .file_name
219
+ locstats = parse_locstats (opts , binary )
220
+
201
221
# Pretty print collected info.
202
- locstats_output (
203
- variables_total ,
204
- variables_total_locstats ,
205
- variables_with_loc ,
206
- variables_scope_bytes_covered ,
207
- variables_scope_bytes ,
208
- variables_coverage_map
209
- )
222
+ if locstats .pretty_print () == - 1 :
223
+ sys .exit (0 )
210
224
211
225
if __name__ == '__main__' :
212
226
Main ()
0 commit comments