OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2010 the V8 project authors. All rights reserved. | 3 # Copyright 2010 the V8 project authors. All rights reserved. |
4 # Redistribution and use in source and binary forms, with or without | 4 # Redistribution and use in source and binary forms, with or without |
5 # modification, are permitted provided that the following conditions are | 5 # modification, are permitted provided that the following conditions are |
6 # met: | 6 # met: |
7 # | 7 # |
8 # * Redistributions of source code must retain the above copyright | 8 # * Redistributions of source code must retain the above copyright |
9 # notice, this list of conditions and the following disclaimer. | 9 # notice, this list of conditions and the following disclaimer. |
10 # * Redistributions in binary form must reproduce the above | 10 # * Redistributions in binary form must reproduce the above |
(...skipping 29 matching lines...) Expand all Loading... |
40 from __future__ import with_statement | 40 from __future__ import with_statement |
41 import sys, types, re, subprocess | 41 import sys, types, re, subprocess |
42 | 42 |
43 def flatten(l): | 43 def flatten(l): |
44 flat = [] | 44 flat = [] |
45 for i in l: flat.extend(i) | 45 for i in l: flat.extend(i) |
46 return flat | 46 return flat |
47 | 47 |
48 def split_nvp(s): | 48 def split_nvp(s): |
49 t = {} | 49 t = {} |
50 for m in re.finditer(r"(\w+)=(-?\d+)", s): | 50 for (name, value) in re.findall(r"(\w+)=([-\w]+)", s): |
51 t[m.group(1)] = int(m.group(2)) | 51 try: |
| 52 t[name] = int(value) |
| 53 except ValueError: |
| 54 t[name] = value |
| 55 |
52 return t | 56 return t |
53 | 57 |
54 def parse_gc_trace(input): | 58 def parse_gc_trace(input): |
55 trace = [] | 59 trace = [] |
56 with open(input) as f: | 60 with open(input) as f: |
57 for line in f: | 61 for line in f: |
58 info = split_nvp(line) | 62 info = split_nvp(line) |
59 if info and 'pause' in info and info['pause'] > 0: | 63 if info and 'pause' in info and info['pause'] > 0: |
60 info['i'] = len(trace) | 64 info['i'] = len(trace) |
61 trace.append(info) | 65 trace.append(info) |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
204 charts.append(outfilename) | 208 charts.append(outfilename) |
205 script = generate_script_and_datafile(plot, trace, '~datafile', outfilename) | 209 script = generate_script_and_datafile(plot, trace, '~datafile', outfilename) |
206 print 'Plotting %s...' % outfilename | 210 print 'Plotting %s...' % outfilename |
207 gnuplot(script) | 211 gnuplot(script) |
208 | 212 |
209 return charts | 213 return charts |
210 | 214 |
211 def reclaimed_bytes(row): | 215 def reclaimed_bytes(row): |
212 return row['total_size_before'] - row['total_size_after'] | 216 return row['total_size_before'] - row['total_size_after'] |
213 | 217 |
| 218 def other_scope(r): |
| 219 return r['pause'] - r['mark'] - r['sweep'] - r['compact'] - r['flushcode'] |
| 220 |
214 plots = [ | 221 plots = [ |
215 [ | 222 [ |
216 Set('style fill solid 0.5 noborder'), | 223 Set('style fill solid 0.5 noborder'), |
217 Set('style histogram rowstacked'), | 224 Set('style histogram rowstacked'), |
218 Set('style data histograms'), | 225 Set('style data histograms'), |
219 Plot(Item('Marking', 'mark', lc = 'purple'), | 226 Plot(Item('Marking', 'mark', lc = 'purple'), |
220 Item('Sweep', 'sweep', lc = 'blue'), | 227 Item('Sweep', 'sweep', lc = 'blue'), |
221 Item('Compaction', 'compact', lc = 'red'), | 228 Item('Compaction', 'compact', lc = 'red'), |
222 Item('Other', | 229 Item('Flush Code', 'flushcode', lc = 'yellow'), |
223 lambda r: r['pause'] - r['mark'] - r['sweep'] - r['compact'], | 230 Item('Other', other_scope, lc = 'grey')) |
224 lc = 'grey')) | |
225 ], | 231 ], |
226 [ | 232 [ |
227 Set('style histogram rowstacked'), | 233 Set('style histogram rowstacked'), |
228 Set('style data histograms'), | 234 Set('style data histograms'), |
229 Plot(Item('Heap Size (before GC)', 'total_size_before', x1y2, | 235 Plot(Item('Heap Size (before GC)', 'total_size_before', x1y2, |
230 fs = 'solid 0.4 noborder', | 236 fs = 'solid 0.4 noborder', |
231 lc = 'green'), | 237 lc = 'green'), |
232 Item('Total holes (after GC)', 'holes_size_before', x1y2, | 238 Item('Total holes (after GC)', 'holes_size_before', x1y2, |
233 fs = 'solid 0.4 noborder', | 239 fs = 'solid 0.4 noborder', |
234 lc = 'red'), | 240 lc = 'red'), |
(...skipping 14 matching lines...) Expand all Loading... |
249 ], | 255 ], |
250 [ | 256 [ |
251 Set('style fill solid 0.5 noborder'), | 257 Set('style fill solid 0.5 noborder'), |
252 Set('style data histograms'), | 258 Set('style data histograms'), |
253 Plot(Item('Allocated', 'allocated'), | 259 Plot(Item('Allocated', 'allocated'), |
254 Item('Reclaimed', reclaimed_bytes), | 260 Item('Reclaimed', reclaimed_bytes), |
255 Item('Promoted', 'promoted', style = 'lines', lc = 'black')) | 261 Item('Promoted', 'promoted', style = 'lines', lc = 'black')) |
256 ], | 262 ], |
257 ] | 263 ] |
258 | 264 |
| 265 def calc_total(trace, field): |
| 266 return reduce(lambda t,r: t + r[field], trace, 0) |
| 267 |
| 268 def calc_max(trace, field): |
| 269 return reduce(lambda t,r: max(t, r[field]), trace, 0) |
| 270 |
259 def process_trace(filename): | 271 def process_trace(filename): |
260 trace = parse_gc_trace(filename) | 272 trace = parse_gc_trace(filename) |
261 total_gc = reduce(lambda t,r: t + r['pause'], trace, 0) | 273 total_gc = calc_total(trace, 'pause') |
262 max_gc = reduce(lambda t,r: max(t, r['pause']), trace, 0) | 274 max_gc = calc_max(trace, 'pause') |
263 avg_gc = total_gc / len(trace) | 275 avg_gc = total_gc / len(trace) |
264 | 276 |
| 277 total_sweep = calc_total(trace, 'sweep') |
| 278 max_sweep = calc_max(trace, 'sweep') |
| 279 |
| 280 total_mark = calc_total(trace, 'mark') |
| 281 max_mark = calc_max(trace, 'mark') |
| 282 |
| 283 scavenges = filter(lambda r: r['gc'] == 's', trace) |
| 284 total_scavenge = calc_total(scavenges, 'pause') |
| 285 max_scavenge = calc_max(scavenges, 'pause') |
| 286 avg_scavenge = total_scavenge / len(scavenges) |
| 287 |
265 charts = plot_all(plots, trace, filename) | 288 charts = plot_all(plots, trace, filename) |
266 | 289 |
267 with open(filename + '.html', 'w') as out: | 290 with open(filename + '.html', 'w') as out: |
268 out.write('<html><body>') | 291 out.write('<html><body>') |
| 292 out.write('<table><tr><td>') |
269 out.write('Total in GC: <b>%d</b><br/>' % total_gc) | 293 out.write('Total in GC: <b>%d</b><br/>' % total_gc) |
270 out.write('Max in GC: <b>%d</b><br/>' % max_gc) | 294 out.write('Max in GC: <b>%d</b><br/>' % max_gc) |
271 out.write('Avg in GC: <b>%d</b><br/>' % avg_gc) | 295 out.write('Avg in GC: <b>%d</b><br/>' % avg_gc) |
| 296 out.write('</td><td>') |
| 297 out.write('Total in Scavenge: <b>%d</b><br/>' % total_scavenge) |
| 298 out.write('Max in Scavenge: <b>%d</b><br/>' % max_scavenge) |
| 299 out.write('Avg in Scavenge: <b>%d</b><br/>' % avg_scavenge) |
| 300 out.write('</td><td>') |
| 301 out.write('Total in Sweep: <b>%d</b><br/>' % total_sweep) |
| 302 out.write('Max in Sweep: <b>%d</b><br/>' % max_sweep) |
| 303 out.write('</td><td>') |
| 304 out.write('Total in Mark: <b>%d</b><br/>' % total_mark) |
| 305 out.write('Max in Mark: <b>%d</b><br/>' % max_mark) |
| 306 out.write('</td></tr></table>') |
272 for chart in charts: | 307 for chart in charts: |
273 out.write('<img src="%s">' % chart) | 308 out.write('<img src="%s">' % chart) |
274 out.write('</body></html>') | 309 out.write('</body></html>') |
275 | 310 |
276 print "%s generated." % (filename + '.html') | 311 print "%s generated." % (filename + '.html') |
277 | 312 |
278 if len(sys.argv) != 2: | 313 if len(sys.argv) != 2: |
279 print "Usage: %s <GC-trace-filename>" % sys.argv[0] | 314 print "Usage: %s <GC-trace-filename>" % sys.argv[0] |
280 sys.exit(1) | 315 sys.exit(1) |
281 | 316 |
282 process_trace(sys.argv[1]) | 317 process_trace(sys.argv[1]) |
OLD | NEW |