1313from math import ceil
1414from subprocess import Popen , PIPE
1515
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.
1669def coverage_buckets ():
1770 yield '0%'
1871 yield '(0%,10%)'
1972 for start in range (10 , 91 , 10 ):
2073 yield '[{0}%,{1}%)' .format (start , start + 10 )
2174 yield '100%'
2275
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 ):
10179 # These will be different due to different options enabled.
10280 variables_total = None
10381 variables_total_locstats = None
@@ -106,14 +84,14 @@ def Main():
10684 variables_scope_bytes = None
10785 variables_scope_bytes_entry_values = None
10886 variables_coverage_map = {}
109- binary = results .file_name
11087
11188 # Get the directory of the LLVM tools.
11289 llvm_dwarfdump_cmd = os .path .join (os .path .dirname (__file__ ), \
11390 "llvm-dwarfdump" )
11491 # The statistics llvm-dwarfdump option.
11592 llvm_dwarfdump_stats_opt = "--statistics"
11693
94+ # Generate the stats with the llvm-dwarfdump.
11795 subproc = Popen ([llvm_dwarfdump_cmd , llvm_dwarfdump_stats_opt , binary ], \
11896 stdin = PIPE , stdout = PIPE , stderr = PIPE , \
11997 universal_newlines = True )
@@ -128,15 +106,15 @@ def Main():
128106 print ('error: No valid llvm-dwarfdump statistics found.' )
129107 sys .exit (1 )
130108
131- if results .only_variables :
109+ if opts .only_variables :
132110 # Read the JSON only for local variables.
133111 variables_total_locstats = \
134112 json_parsed ['total vars procesed by location statistics' ]
135113 variables_scope_bytes_covered = \
136114 json_parsed ['vars scope bytes covered' ]
137115 variables_scope_bytes = \
138116 json_parsed ['vars scope bytes total' ]
139- if not results .ignore_debug_entry_values :
117+ if not opts .ignore_debug_entry_values :
140118 for cov_bucket in coverage_buckets ():
141119 cov_category = "vars with {} of its scope covered" .format (cov_bucket )
142120 variables_coverage_map [cov_bucket ] = json_parsed [cov_category ]
@@ -150,15 +128,15 @@ def Main():
150128 "vars (excluding the debug entry values) " \
151129 "with {} of its scope covered" .format (cov_bucket )
152130 variables_coverage_map [cov_bucket ] = json_parsed [cov_category ]
153- elif results .only_formal_parameters :
131+ elif opts .only_formal_parameters :
154132 # Read the JSON only for formal parameters.
155133 variables_total_locstats = \
156134 json_parsed ['total params procesed by location statistics' ]
157135 variables_scope_bytes_covered = \
158136 json_parsed ['formal params scope bytes covered' ]
159137 variables_scope_bytes = \
160138 json_parsed ['formal params scope bytes total' ]
161- if not results .ignore_debug_entry_values :
139+ if not opts .ignore_debug_entry_values :
162140 for cov_bucket in coverage_buckets ():
163141 cov_category = "params with {} of its scope covered" .format (cov_bucket )
164142 variables_coverage_map [cov_bucket ] = json_parsed [cov_category ]
@@ -183,7 +161,7 @@ def Main():
183161 json_parsed ['scope bytes covered' ]
184162 variables_scope_bytes = \
185163 json_parsed ['scope bytes total' ]
186- if not results .ignore_debug_entry_values :
164+ if not opts .ignore_debug_entry_values :
187165 for cov_bucket in coverage_buckets ():
188166 cov_category = "variables with {} of its scope covered" . \
189167 format (cov_bucket )
@@ -198,15 +176,51 @@ def Main():
198176 "with {} of its scope covered" . format (cov_bucket )
199177 variables_coverage_map [cov_bucket ] = json_parsed [cov_category ]
200178
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+
201221 # 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 )
210224
211225if __name__ == '__main__' :
212226 Main ()
0 commit comments