11
11
import sys
12
12
from json import loads
13
13
from math import ceil
14
+ from collections import OrderedDict
14
15
from subprocess import Popen , PIPE
15
16
16
17
# Holds the debug location statistics.
@@ -26,14 +27,19 @@ def __init__(self, file_name, variables_total, variables_total_locstats,
26
27
self .scope_bytes = variables_scope_bytes
27
28
self .variables_coverage_map = variables_coverage_map
28
29
30
+ # Get the PC ranges coverage.
31
+ def get_pc_coverage (self ):
32
+ pc_ranges_covered = int (ceil (self .scope_bytes_covered * 100.0 ) \
33
+ / self .scope_bytes )
34
+ return pc_ranges_covered
35
+
29
36
# Pretty print the debug location buckets.
30
37
def pretty_print (self ):
31
38
if self .scope_bytes == 0 :
32
39
print ('No scope bytes found.' )
33
40
return - 1
34
41
35
- pc_ranges_covered = int (ceil (self .scope_bytes_covered * 100.0 ) \
36
- / self .scope_bytes )
42
+ pc_ranges_covered = self .get_pc_coverage ()
37
43
variables_coverage_per_map = {}
38
44
for cov_bucket in coverage_buckets ():
39
45
variables_coverage_per_map [cov_bucket ] = \
@@ -65,6 +71,39 @@ def pretty_print(self):
65
71
66
72
return 0
67
73
74
+ # Draw a plot representing the location buckets.
75
+ def draw_plot (self ):
76
+ try :
77
+ import matplotlib
78
+ except ImportError :
79
+ print ('error: matplotlib not found.' )
80
+ sys .exit (1 )
81
+
82
+ from matplotlib import pyplot as plt
83
+
84
+ buckets = range (len (self .variables_coverage_map ))
85
+ plt .figure (figsize = (12 , 8 ))
86
+ plt .title ('Debug Location Statistics' , fontweight = 'bold' )
87
+ plt .xlabel ('location buckets' )
88
+ plt .ylabel ('number of variables in the location buckets' )
89
+ plt .bar (buckets , self .variables_coverage_map .values (), align = 'center' ,
90
+ tick_label = self .variables_coverage_map .keys (),
91
+ label = 'variables of {}' .format (self .file_name ))
92
+ plt .xticks (rotation = 45 , fontsize = 'x-small' )
93
+ plt .yticks ()
94
+
95
+ # Place the text box with the coverage info.
96
+ pc_ranges_covered = self .get_pc_coverage ()
97
+ props = dict (boxstyle = 'round' , facecolor = 'wheat' , alpha = 0.5 )
98
+ plt .text (0.02 , 0.90 , 'PC ranges covered: {}%' .format (pc_ranges_covered ),
99
+ transform = plt .gca ().transAxes , fontsize = 12 ,
100
+ verticalalignment = 'top' , bbox = props )
101
+ plt .legend ()
102
+ plt .grid (color = 'grey' , which = 'major' , axis = 'y' , linestyle = '-' , linewidth = 0.3 )
103
+
104
+ plt .savefig ('locstats.png' )
105
+ print ('The plot was saved within "locstats.png".' )
106
+
68
107
# Define the location buckets.
69
108
def coverage_buckets ():
70
109
yield '0%'
@@ -83,7 +122,7 @@ def parse_locstats(opts, binary):
83
122
variables_scope_bytes_covered = None
84
123
variables_scope_bytes = None
85
124
variables_scope_bytes_entry_values = None
86
- variables_coverage_map = {}
125
+ variables_coverage_map = OrderedDict ()
87
126
88
127
# Get the directory of the LLVM tools.
89
128
llvm_dwarfdump_cmd = os .path .join (os .path .dirname (__file__ ), \
@@ -191,6 +230,9 @@ def parse_program_args(parser):
191
230
default = False ,
192
231
help = 'ignore the location statistics on locations with '
193
232
'entry values' )
233
+ parser .add_argument ('--draw-plot' , action = 'store_true' , default = False ,
234
+ help = 'show histogram of location buckets generated (requires '
235
+ 'matplotlib)' )
194
236
parser .add_argument ('file_name' , type = str , help = 'file to process' )
195
237
196
238
return parser .parse_args ()
@@ -218,9 +260,13 @@ def Main():
218
260
binary = opts .file_name
219
261
locstats = parse_locstats (opts , binary )
220
262
221
- # Pretty print collected info.
222
- if locstats .pretty_print () == - 1 :
223
- sys .exit (0 )
263
+ if opts .draw_plot :
264
+ # Draw a histogram representing the location buckets.
265
+ locstats .draw_plot ()
266
+ else :
267
+ # Pretty print collected info on the standard output.
268
+ if locstats .pretty_print () == - 1 :
269
+ sys .exit (0 )
224
270
225
271
if __name__ == '__main__' :
226
272
Main ()
0 commit comments