| 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 20 matching lines...) Expand all Loading... |
| 31 # | 31 # |
| 32 # This is an utility for plotting charts based on GC traces produced by V8 when | 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 | 33 # run with flags --trace-gc --trace-gc-nvp. Relies on gnuplot for actual |
| 34 # plotting. | 34 # plotting. |
| 35 # | 35 # |
| 36 # Usage: gc-nvp-trace-processor.py <GC-trace-filename> | 36 # Usage: gc-nvp-trace-processor.py <GC-trace-filename> |
| 37 # | 37 # |
| 38 | 38 |
| 39 | 39 |
| 40 from __future__ import with_statement | 40 from __future__ import with_statement |
| 41 import sys, types, re, subprocess | 41 import sys, types, re, subprocess, math |
| 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 (name, value) in re.findall(r"(\w+)=([-\w]+)", s): | 50 for (name, value) in re.findall(r"(\w+)=([-\w]+)", s): |
| 51 try: | 51 try: |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 ], | 255 ], |
| 256 [ | 256 [ |
| 257 Set('style fill solid 0.5 noborder'), | 257 Set('style fill solid 0.5 noborder'), |
| 258 Set('style data histograms'), | 258 Set('style data histograms'), |
| 259 Plot(Item('Allocated', 'allocated'), | 259 Plot(Item('Allocated', 'allocated'), |
| 260 Item('Reclaimed', reclaimed_bytes), | 260 Item('Reclaimed', reclaimed_bytes), |
| 261 Item('Promoted', 'promoted', style = 'lines', lc = 'black')) | 261 Item('Promoted', 'promoted', style = 'lines', lc = 'black')) |
| 262 ], | 262 ], |
| 263 ] | 263 ] |
| 264 | 264 |
| 265 def freduce(f, field, trace, init): |
| 266 return reduce(lambda t,r: f(t, r[field]), trace, init) |
| 267 |
| 265 def calc_total(trace, field): | 268 def calc_total(trace, field): |
| 266 return reduce(lambda t,r: t + r[field], trace, 0) | 269 return freduce(lambda t,v: t + v, field, trace, 0) |
| 267 | 270 |
| 268 def calc_max(trace, field): | 271 def calc_max(trace, field): |
| 269 return reduce(lambda t,r: max(t, r[field]), trace, 0) | 272 return freduce(lambda t,r: max(t, r), field, trace, 0) |
| 273 |
| 274 def count_nonzero(trace, field): |
| 275 return freduce(lambda t,r: t if r == 0 else t + 1, field, trace, 0) |
| 276 |
| 270 | 277 |
| 271 def process_trace(filename): | 278 def process_trace(filename): |
| 272 trace = parse_gc_trace(filename) | 279 trace = parse_gc_trace(filename) |
| 273 total_gc = calc_total(trace, 'pause') | |
| 274 max_gc = calc_max(trace, 'pause') | |
| 275 avg_gc = total_gc / len(trace) | |
| 276 | 280 |
| 277 total_sweep = calc_total(trace, 'sweep') | 281 marksweeps = filter(lambda r: r['gc'] == 'ms', trace) |
| 278 max_sweep = calc_max(trace, 'sweep') | 282 markcompacts = filter(lambda r: r['gc'] == 'mc', trace) |
| 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) | 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 | 284 |
| 288 charts = plot_all(plots, trace, filename) | 285 charts = plot_all(plots, trace, filename) |
| 289 | 286 |
| 287 def stats(out, prefix, trace, field): |
| 288 n = len(trace) |
| 289 total = calc_total(trace, field) |
| 290 max = calc_max(trace, field) |
| 291 avg = total / n |
| 292 if n > 1: |
| 293 dev = math.sqrt(freduce(lambda t,r: (r - avg) ** 2, field, trace, 0) / |
| 294 (n - 1)) |
| 295 else: |
| 296 dev = 0 |
| 297 |
| 298 out.write('<tr><td>%s</td><td>%d</td><td>%d</td>' |
| 299 '<td>%d</td><td>%d [dev %f]</td></tr>' % |
| 300 (prefix, n, total, max, avg, dev)) |
| 301 |
| 302 |
| 290 with open(filename + '.html', 'w') as out: | 303 with open(filename + '.html', 'w') as out: |
| 291 out.write('<html><body>') | 304 out.write('<html><body>') |
| 292 out.write('<table><tr><td>') | 305 out.write('<table>') |
| 293 out.write('Total in GC: <b>%d</b><br/>' % total_gc) | 306 out.write('<tr><td>Phase</td><td>Count</td><td>Time (ms)</td><td>Max</td><td
>Avg</td></tr>') |
| 294 out.write('Max in GC: <b>%d</b><br/>' % max_gc) | 307 stats(out, 'Total in GC', trace, 'pause') |
| 295 out.write('Avg in GC: <b>%d</b><br/>' % avg_gc) | 308 stats(out, 'Scavenge', scavenges, 'pause') |
| 296 out.write('</td><td>') | 309 stats(out, 'MarkSweep', marksweeps, 'pause') |
| 297 out.write('Total in Scavenge: <b>%d</b><br/>' % total_scavenge) | 310 stats(out, 'MarkCompact', markcompacts, 'pause') |
| 298 out.write('Max in Scavenge: <b>%d</b><br/>' % max_scavenge) | 311 stats(out, 'Mark', filter(lambda r: r['mark'] != 0, trace), 'mark') |
| 299 out.write('Avg in Scavenge: <b>%d</b><br/>' % avg_scavenge) | 312 stats(out, 'Sweep', filter(lambda r: r['sweep'] != 0, trace), 'sweep') |
| 300 out.write('</td><td>') | 313 stats(out, 'Flush Code', filter(lambda r: r['flushcode'] != 0, trace), 'flus
hcode') |
| 301 out.write('Total in Sweep: <b>%d</b><br/>' % total_sweep) | 314 stats(out, 'Compact', filter(lambda r: r['compact'] != 0, trace), 'compact') |
| 302 out.write('Max in Sweep: <b>%d</b><br/>' % max_sweep) | 315 out.write('</table>') |
| 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>') | |
| 307 for chart in charts: | 316 for chart in charts: |
| 308 out.write('<img src="%s">' % chart) | 317 out.write('<img src="%s">' % chart) |
| 309 out.write('</body></html>') | 318 out.write('</body></html>') |
| 310 | 319 |
| 311 print "%s generated." % (filename + '.html') | 320 print "%s generated." % (filename + '.html') |
| 312 | 321 |
| 313 if len(sys.argv) != 2: | 322 if len(sys.argv) != 2: |
| 314 print "Usage: %s <GC-trace-filename>" % sys.argv[0] | 323 print "Usage: %s <GC-trace-filename>" % sys.argv[0] |
| 315 sys.exit(1) | 324 sys.exit(1) |
| 316 | 325 |
| 317 process_trace(sys.argv[1]) | 326 process_trace(sys.argv[1]) |
| OLD | NEW |