Skip to content

Commit ada9646

Browse files
committed
[llvm-locstats] Add the --draw-plot option
When using the option, draw the histogram representing the debug location buckets. The resulting histogram will be saved in a png file. Differential Revision: https://reviews.llvm.org/D71869
1 parent 46d11e3 commit ada9646

File tree

2 files changed

+97
-30
lines changed

2 files changed

+97
-30
lines changed

llvm/docs/CommandGuide/llvm-locstats.rst

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,40 +38,61 @@ OPTIONS
3838
ignore the location statistics on locations containing the
3939
debug entry values DWARF operation
4040

41+
.. option:: --draw-plot
42+
43+
make histogram of location buckets generated (requires
44+
matplotlib)
45+
4146
EXIT STATUS
4247
-----------
4348

4449
:program:`llvm-locstats` returns 0 if the input file were parsed
4550
successfully. Otherwise, it returns 1.
4651

47-
OUTPUT EXAMPLE
52+
EXAMPLE 1
4853
--------------
4954

55+
Pretty print the location coverage on the standard output.
56+
5057
.. code-block:: none
5158
52-
=================================================
53-
Debug Location Statistics
54-
=================================================
55-
cov% samples percentage(~)
56-
-------------------------------------------------
57-
0% 1 16%
58-
(0%,10%) 0 0%
59-
[10%,20%) 0 0%
60-
[20%,30%) 0 0%
61-
[30%,40%) 0 0%
62-
[40%,50%) 0 0%
63-
[50%,60%) 1 16%
64-
[60%,70%) 0 0%
65-
[70%,80%) 0 0%
66-
[80%,90%) 1 16%
67-
[90%,100%) 0 0%
68-
100% 3 50%
69-
=================================================
70-
-the number of debug variables processed: 6
71-
-PC ranges covered: 81%
72-
-------------------------------------------------
73-
-total availability: 83%
74-
=================================================
59+
llvm-locstats a.out
60+
61+
=================================================
62+
Debug Location Statistics
63+
=================================================
64+
cov% samples percentage(~)
65+
-------------------------------------------------
66+
0% 1 16%
67+
(0%,10%) 0 0%
68+
[10%,20%) 0 0%
69+
[20%,30%) 0 0%
70+
[30%,40%) 0 0%
71+
[40%,50%) 0 0%
72+
[50%,60%) 1 16%
73+
[60%,70%) 0 0%
74+
[70%,80%) 0 0%
75+
[80%,90%) 1 16%
76+
[90%,100%) 0 0%
77+
100% 3 50%
78+
=================================================
79+
-the number of debug variables processed: 6
80+
-PC ranges covered: 81%
81+
-------------------------------------------------
82+
-total availability: 83%
83+
=================================================
84+
85+
EXAMPLE 2
86+
--------------
87+
88+
Generate a plot as an image file.
89+
90+
.. code-block:: none
91+
92+
llvm-locstats --draw-plot file1.out
93+
94+
.. image:: locstats-draw-plot.png
95+
:align: center
7596

7697
SEE ALSO
7798
--------

llvm/utils/llvm-locstats/llvm-locstats.py

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import sys
1212
from json import loads
1313
from math import ceil
14+
from collections import OrderedDict
1415
from subprocess import Popen, PIPE
1516

1617
# Holds the debug location statistics.
@@ -26,14 +27,19 @@ def __init__(self, file_name, variables_total, variables_total_locstats,
2627
self.scope_bytes = variables_scope_bytes
2728
self.variables_coverage_map = variables_coverage_map
2829

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+
2936
# Pretty print the debug location buckets.
3037
def pretty_print(self):
3138
if self.scope_bytes == 0:
3239
print ('No scope bytes found.')
3340
return -1
3441

35-
pc_ranges_covered = int(ceil(self.scope_bytes_covered * 100.0) \
36-
/ self.scope_bytes)
42+
pc_ranges_covered = self.get_pc_coverage()
3743
variables_coverage_per_map = {}
3844
for cov_bucket in coverage_buckets():
3945
variables_coverage_per_map[cov_bucket] = \
@@ -65,6 +71,39 @@ def pretty_print(self):
6571

6672
return 0
6773

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+
68107
# Define the location buckets.
69108
def coverage_buckets():
70109
yield '0%'
@@ -83,7 +122,7 @@ def parse_locstats(opts, binary):
83122
variables_scope_bytes_covered = None
84123
variables_scope_bytes = None
85124
variables_scope_bytes_entry_values = None
86-
variables_coverage_map = {}
125+
variables_coverage_map = OrderedDict()
87126

88127
# Get the directory of the LLVM tools.
89128
llvm_dwarfdump_cmd = os.path.join(os.path.dirname(__file__), \
@@ -191,6 +230,9 @@ def parse_program_args(parser):
191230
default=False,
192231
help='ignore the location statistics on locations with '
193232
'entry values')
233+
parser.add_argument('--draw-plot', action='store_true', default=False,
234+
help='show histogram of location buckets generated (requires '
235+
'matplotlib)')
194236
parser.add_argument('file_name', type=str, help='file to process')
195237

196238
return parser.parse_args()
@@ -218,9 +260,13 @@ def Main():
218260
binary = opts.file_name
219261
locstats = parse_locstats(opts, binary)
220262

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)
224270

225271
if __name__ == '__main__':
226272
Main()

0 commit comments

Comments
 (0)