Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(971)

Side by Side Diff: tools/gc-nvp-trace-processor.py

Issue 2132005: Improved GC statistics (cumulative and per collection). (Closed)
Patch Set: fixed Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/mark-compact.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 #
3 # Copyright 2010 the V8 project authors. All rights reserved.
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7 #
8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following
12 # disclaimer in the documentation and/or other materials provided
13 # with the distribution.
14 # * Neither the name of Google Inc. nor the names of its
15 # contributors may be used to endorse or promote products derived
16 # from this software without specific prior written permission.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #
30
31 #
32 # This is an utility for plotting charts based on GC traces produced by V8 when
33 # run with flags --trace-gc --trace-gc-nvp. Relies on gnuplot for actual
34 # plotting.
35 #
36 # Usage: gc-nvp-trace-processor.py <GC-trace-filename>
37 #
38
39
40 from __future__ import with_statement
41 import sys, types, re, subprocess
42
43 def flatten(l):
44 flat = []
45 for i in l: flat.extend(i)
46 return flat
47
48 def split_nvp(s):
49 t = {}
50 for m in re.finditer(r"(\w+)=(-?\d+)", s):
51 t[m.group(1)] = int(m.group(2))
52 return t
53
54 def parse_gc_trace(input):
55 trace = []
56 with open(input) as f:
57 for line in f:
58 info = split_nvp(line)
59 if info and 'pause' in info and info['pause'] > 0:
60 info['i'] = len(trace)
61 trace.append(info)
62 return trace
63
64 def extract_field_names(script):
65 fields = { 'data': true, 'in': true }
66
67 for m in re.finditer(r"$(\w+)", script):
68 field_name = m.group(1)
69 if field_name not in fields:
70 fields[field] = field_count
71 field_count = field_count + 1
72
73 return fields
74
75 def gnuplot(script):
76 gnuplot = subprocess.Popen(["gnuplot"], stdin=subprocess.PIPE)
77 gnuplot.stdin.write(script)
78 gnuplot.stdin.close()
79 gnuplot.wait()
80
81 x1y1 = 'x1y1'
82 x1y2 = 'x1y2'
83 x2y1 = 'x2y1'
84 x2y2 = 'x2y2'
85
86 class Item(object):
87 def __init__(self, title, field, axis = x1y1, **keywords):
88 self.title = title
89 self.axis = axis
90 self.props = keywords
91 if type(field) is types.ListType:
92 self.field = field
93 else:
94 self.field = [field]
95
96 def fieldrefs(self):
97 return self.field
98
99 def to_gnuplot(self, context):
100 args = ['"%s"' % context.datafile,
101 'using %s' % context.format_fieldref(self.field),
102 'title "%s"' % self.title,
103 'axis %s' % self.axis]
104 if 'style' in self.props:
105 args.append('with %s' % self.props['style'])
106 if 'lc' in self.props:
107 args.append('lc rgb "%s"' % self.props['lc'])
108 if 'fs' in self.props:
109 args.append('fs %s' % self.props['fs'])
110 return ' '.join(args)
111
112 class Plot(object):
113 def __init__(self, *items):
114 self.items = items
115
116 def fieldrefs(self):
117 return flatten([item.fieldrefs() for item in self.items])
118
119 def to_gnuplot(self, ctx):
120 return 'plot ' + ', '.join([item.to_gnuplot(ctx) for item in self.items])
121
122 class Set(object):
123 def __init__(self, value):
124 self.value = value
125
126 def to_gnuplot(self, ctx):
127 return 'set ' + self.value
128
129 def fieldrefs(self):
130 return []
131
132 class Context(object):
133 def __init__(self, datafile, field_to_index):
134 self.datafile = datafile
135 self.field_to_index = field_to_index
136
137 def format_fieldref(self, fieldref):
138 return ':'.join([str(self.field_to_index[field]) for field in fieldref])
139
140 def collect_fields(plot):
141 field_to_index = {}
142 fields = []
143
144 def add_field(field):
145 if field not in field_to_index:
146 fields.append(field)
147 field_to_index[field] = len(fields)
148
149 for field in flatten([item.fieldrefs() for item in plot]):
150 add_field(field)
151
152 return (fields, field_to_index)
153
154 def is_y2_used(plot):
155 for subplot in plot:
156 if isinstance(subplot, Plot):
157 for item in subplot.items:
158 if item.axis == x1y2 or item.axis == x2y2:
159 return True
160 return False
161
162 def get_field(trace_line, field):
163 t = type(field)
164 if t is types.StringType:
165 return trace_line[field]
166 elif t is types.FunctionType:
167 return field(trace_line)
168
169 def generate_datafile(datafile_name, trace, fields):
170 with open(datafile_name, 'w') as datafile:
171 for line in trace:
172 data_line = [str(get_field(line, field)) for field in fields]
173 datafile.write('\t'.join(data_line))
174 datafile.write('\n')
175
176 def generate_script_and_datafile(plot, trace, datafile, output):
177 (fields, field_to_index) = collect_fields(plot)
178 generate_datafile(datafile, trace, fields)
179 script = [
180 'set terminal png',
181 'set output "%s"' % output,
182 'set autoscale',
183 'set ytics nomirror',
184 'set xtics nomirror',
185 'set key below'
186 ]
187
188 if is_y2_used(plot):
189 script.append('set autoscale y2')
190 script.append('set y2tics')
191
192 context = Context(datafile, field_to_index)
193
194 for item in plot:
195 script.append(item.to_gnuplot(context))
196
197 return '\n'.join(script)
198
199 def plot_all(plots, trace, prefix):
200 charts = []
201
202 for plot in plots:
203 outfilename = "%s_%d.png" % (prefix, len(charts))
204 charts.append(outfilename)
205 script = generate_script_and_datafile(plot, trace, '~datafile', outfilename)
206 print 'Plotting %s...' % outfilename
207 gnuplot(script)
208
209 return charts
210
211 def reclaimed_bytes(row):
212 return row['total_size_before'] - row['total_size_after']
213
214 plots = [
215 [
216 Set('style fill solid 0.5 noborder'),
217 Set('style histogram rowstacked'),
218 Set('style data histograms'),
219 Plot(Item('Marking', 'mark', lc = 'purple'),
220 Item('Sweep', 'sweep', lc = 'blue'),
221 Item('Compaction', 'compact', lc = 'red'),
222 Item('Other',
223 lambda r: r['pause'] - r['mark'] - r['sweep'] - r['compact'],
224 lc = 'grey'))
225 ],
226 [
227 Set('style histogram rowstacked'),
228 Set('style data histograms'),
229 Plot(Item('Heap Size (before GC)', 'total_size_before', x1y2,
230 fs = 'solid 0.4 noborder',
231 lc = 'green'),
232 Item('Total holes (after GC)', 'holes_size_before', x1y2,
233 fs = 'solid 0.4 noborder',
234 lc = 'red'),
235 Item('GC Time', ['i', 'pause'], style = 'lines', lc = 'red'))
236 ],
237 [
238 Set('style histogram rowstacked'),
239 Set('style data histograms'),
240 Plot(Item('Heap Size (after GC)', 'total_size_after', x1y2,
241 fs = 'solid 0.4 noborder',
242 lc = 'green'),
243 Item('Total holes (after GC)', 'holes_size_after', x1y2,
244 fs = 'solid 0.4 noborder',
245 lc = 'red'),
246 Item('GC Time', ['i', 'pause'],
247 style = 'lines',
248 lc = 'red'))
249 ],
250 [
251 Set('style fill solid 0.5 noborder'),
252 Set('style data histograms'),
253 Plot(Item('Allocated', 'allocated'),
254 Item('Reclaimed', reclaimed_bytes),
255 Item('Promoted', 'promoted', style = 'lines', lc = 'black'))
256 ],
257 ]
258
259 def process_trace(filename):
260 trace = parse_gc_trace(filename)
261 total_gc = reduce(lambda t,r: t + r['pause'], trace, 0)
262 max_gc = reduce(lambda t,r: max(t, r['pause']), trace, 0)
263 avg_gc = total_gc / len(trace)
264
265 charts = plot_all(plots, trace, filename)
266
267 with open(filename + '.html', 'w') as out:
268 out.write('<html><body>')
269 out.write('Total in GC: <b>%d</b><br/>' % total_gc)
270 out.write('Max in GC: <b>%d</b><br/>' % max_gc)
271 out.write('Avg in GC: <b>%d</b><br/>' % avg_gc)
272 for chart in charts:
273 out.write('<img src="%s">' % chart)
274 out.write('</body></html>')
275
276 print "%s generated." % (filename + '.html')
277
278 if len(sys.argv) != 2:
279 print "Usage: %s <GC-trace-filename>" % sys.argv[0]
280 sys.exit(1)
281
282 process_trace(sys.argv[1])
OLDNEW
« no previous file with comments | « src/mark-compact.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698