| 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 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 if r['gc'] == 's': | 219 if r['gc'] == 's': |
| 220 # there is no 'other' scope for scavenging collections. | 220 # there is no 'other' scope for scavenging collections. |
| 221 return 0 | 221 return 0 |
| 222 return r['pause'] - r['mark'] - r['sweep'] - r['compact'] - r['external'] | 222 return r['pause'] - r['mark'] - r['sweep'] - r['compact'] - r['external'] |
| 223 | 223 |
| 224 def scavenge_scope(r): | 224 def scavenge_scope(r): |
| 225 if r['gc'] == 's': | 225 if r['gc'] == 's': |
| 226 return r['pause'] - r['external'] | 226 return r['pause'] - r['external'] |
| 227 return 0 | 227 return 0 |
| 228 | 228 |
| 229 |
| 230 def real_mutator(r): |
| 231 return r['mutator'] - r['stepstook'] |
| 232 |
| 229 plots = [ | 233 plots = [ |
| 230 [ | 234 [ |
| 231 Set('style fill solid 0.5 noborder'), | 235 Set('style fill solid 0.5 noborder'), |
| 232 Set('style histogram rowstacked'), | 236 Set('style histogram rowstacked'), |
| 233 Set('style data histograms'), | 237 Set('style data histograms'), |
| 234 Plot(Item('Scavenge', scavenge_scope, lc = 'green'), | 238 Plot(Item('Scavenge', scavenge_scope, lc = 'green'), |
| 235 Item('Marking', 'mark', lc = 'purple'), | 239 Item('Marking', 'mark', lc = 'purple'), |
| 236 Item('Sweep', 'sweep', lc = 'blue'), | 240 Item('Sweep', 'sweep', lc = 'blue'), |
| 237 Item('Compaction', 'compact', lc = 'red'), | 241 Item('Compaction', 'compact', lc = 'red'), |
| 238 Item('External', 'external', lc = '#489D43'), | 242 Item('External', 'external', lc = '#489D43'), |
| 239 Item('Other', other_scope, lc = 'grey')) | 243 Item('Other', other_scope, lc = 'grey'), |
| 244 Item('IGC Steps', 'stepstook', lc = '#FF6347')) |
| 245 ], |
| 246 [ |
| 247 Set('style fill solid 0.5 noborder'), |
| 248 Set('style histogram rowstacked'), |
| 249 Set('style data histograms'), |
| 250 Plot(Item('Scavenge', scavenge_scope, lc = 'green'), |
| 251 Item('Marking', 'mark', lc = 'purple'), |
| 252 Item('Sweep', 'sweep', lc = 'blue'), |
| 253 Item('Compaction', 'compact', lc = 'red'), |
| 254 Item('External', 'external', lc = '#489D43'), |
| 255 Item('Other', other_scope, lc = '#ADD8E6'), |
| 256 Item('External', 'external', lc = '#D3D3D3')) |
| 257 ], |
| 258 |
| 259 [ |
| 260 Plot(Item('Mutator', real_mutator, lc = 'black', style = 'lines')) |
| 240 ], | 261 ], |
| 241 [ | 262 [ |
| 242 Set('style histogram rowstacked'), | 263 Set('style histogram rowstacked'), |
| 243 Set('style data histograms'), | 264 Set('style data histograms'), |
| 244 Plot(Item('Heap Size (before GC)', 'total_size_before', x1y2, | 265 Plot(Item('Heap Size (before GC)', 'total_size_before', x1y2, |
| 245 fs = 'solid 0.4 noborder', | 266 fs = 'solid 0.4 noborder', |
| 246 lc = 'green'), | 267 lc = 'green'), |
| 247 Item('Total holes (after GC)', 'holes_size_before', x1y2, | 268 Item('Total holes (after GC)', 'holes_size_before', x1y2, |
| 248 fs = 'solid 0.4 noborder', | 269 fs = 'solid 0.4 noborder', |
| 249 lc = 'red'), | 270 lc = 'red'), |
| (...skipping 18 matching lines...) Expand all Loading... |
| 268 Plot(Item('Allocated', 'allocated'), | 289 Plot(Item('Allocated', 'allocated'), |
| 269 Item('Reclaimed', reclaimed_bytes), | 290 Item('Reclaimed', reclaimed_bytes), |
| 270 Item('Promoted', 'promoted', style = 'lines', lc = 'black')) | 291 Item('Promoted', 'promoted', style = 'lines', lc = 'black')) |
| 271 ], | 292 ], |
| 272 ] | 293 ] |
| 273 | 294 |
| 274 def freduce(f, field, trace, init): | 295 def freduce(f, field, trace, init): |
| 275 return reduce(lambda t,r: f(t, r[field]), trace, init) | 296 return reduce(lambda t,r: f(t, r[field]), trace, init) |
| 276 | 297 |
| 277 def calc_total(trace, field): | 298 def calc_total(trace, field): |
| 278 return freduce(lambda t,v: t + v, field, trace, 0) | 299 return freduce(lambda t,v: t + long(v), field, trace, long(0)) |
| 279 | 300 |
| 280 def calc_max(trace, field): | 301 def calc_max(trace, field): |
| 281 return freduce(lambda t,r: max(t, r), field, trace, 0) | 302 return freduce(lambda t,r: max(t, r), field, trace, 0) |
| 282 | 303 |
| 283 def count_nonzero(trace, field): | 304 def count_nonzero(trace, field): |
| 284 return freduce(lambda t,r: t if r == 0 else t + 1, field, trace, 0) | 305 return freduce(lambda t,r: t if r == 0 else t + 1, field, trace, 0) |
| 285 | 306 |
| 286 | 307 |
| 287 def process_trace(filename): | 308 def process_trace(filename): |
| 288 trace = parse_gc_trace(filename) | 309 trace = parse_gc_trace(filename) |
| 289 | 310 |
| 290 marksweeps = filter(lambda r: r['gc'] == 'ms', trace) | 311 marksweeps = filter(lambda r: r['gc'] == 'ms', trace) |
| 291 markcompacts = filter(lambda r: r['gc'] == 'mc', trace) | 312 markcompacts = filter(lambda r: r['gc'] == 'mc', trace) |
| 292 scavenges = filter(lambda r: r['gc'] == 's', trace) | 313 scavenges = filter(lambda r: r['gc'] == 's', trace) |
| 314 globalgcs = filter(lambda r: r['gc'] != 's', trace) |
| 315 |
| 293 | 316 |
| 294 charts = plot_all(plots, trace, filename) | 317 charts = plot_all(plots, trace, filename) |
| 295 | 318 |
| 296 def stats(out, prefix, trace, field): | 319 def stats(out, prefix, trace, field): |
| 297 n = len(trace) | 320 n = len(trace) |
| 298 total = calc_total(trace, field) | 321 total = calc_total(trace, field) |
| 299 max = calc_max(trace, field) | 322 max = calc_max(trace, field) |
| 300 if n > 0: | 323 if n > 0: |
| 301 avg = total / n | 324 avg = total / n |
| 302 else: | 325 else: |
| 303 avg = 0 | 326 avg = 0 |
| 304 if n > 1: | 327 if n > 1: |
| 305 dev = math.sqrt(freduce(lambda t,r: (r - avg) ** 2, field, trace, 0) / | 328 dev = math.sqrt(freduce(lambda t,r: t + (r - avg) ** 2, field, trace, 0) / |
| 306 (n - 1)) | 329 (n - 1)) |
| 307 else: | 330 else: |
| 308 dev = 0 | 331 dev = 0 |
| 309 | 332 |
| 310 out.write('<tr><td>%s</td><td>%d</td><td>%d</td>' | 333 out.write('<tr><td>%s</td><td>%d</td><td>%d</td>' |
| 311 '<td>%d</td><td>%d [dev %f]</td></tr>' % | 334 '<td>%d</td><td>%d [dev %f]</td></tr>' % |
| 312 (prefix, n, total, max, avg, dev)) | 335 (prefix, n, total, max, avg, dev)) |
| 313 | 336 |
| 337 def HumanReadable(size): |
| 338 suffixes = ['bytes', 'kB', 'MB', 'GB'] |
| 339 power = 1 |
| 340 for i in range(len(suffixes)): |
| 341 if size < power*1024: |
| 342 return "%.1f" % (float(size) / power) + " " + suffixes[i] |
| 343 power *= 1024 |
| 344 |
| 345 def throughput(name, trace): |
| 346 total_live_after = calc_total(trace, 'total_size_after') |
| 347 total_live_before = calc_total(trace, 'total_size_before') |
| 348 total_gc = calc_total(trace, 'pause') |
| 349 if total_gc == 0: |
| 350 return |
| 351 out.write('GC %s Throughput (after): %s / %s ms = %s/ms<br/>' % |
| 352 (name, |
| 353 HumanReadable(total_live_after), |
| 354 total_gc, |
| 355 HumanReadable(total_live_after / total_gc))) |
| 356 out.write('GC %s Throughput (before): %s / %s ms = %s/ms<br/>' % |
| 357 (name, |
| 358 HumanReadable(total_live_before), |
| 359 total_gc, |
| 360 HumanReadable(total_live_before / total_gc))) |
| 361 |
| 314 | 362 |
| 315 with open(filename + '.html', 'w') as out: | 363 with open(filename + '.html', 'w') as out: |
| 316 out.write('<html><body>') | 364 out.write('<html><body>') |
| 317 out.write('<table>') | 365 out.write('<table>') |
| 318 out.write('<tr><td>Phase</td><td>Count</td><td>Time (ms)</td>') | 366 out.write('<tr><td>Phase</td><td>Count</td><td>Time (ms)</td>') |
| 319 out.write('<td>Max</td><td>Avg</td></tr>') | 367 out.write('<td>Max</td><td>Avg</td></tr>') |
| 320 stats(out, 'Total in GC', trace, 'pause') | 368 stats(out, 'Total in GC', trace, 'pause') |
| 321 stats(out, 'Scavenge', scavenges, 'pause') | 369 stats(out, 'Scavenge', scavenges, 'pause') |
| 322 stats(out, 'MarkSweep', marksweeps, 'pause') | 370 stats(out, 'MarkSweep', marksweeps, 'pause') |
| 323 stats(out, 'MarkCompact', markcompacts, 'pause') | 371 stats(out, 'MarkCompact', markcompacts, 'pause') |
| 324 stats(out, 'Mark', filter(lambda r: r['mark'] != 0, trace), 'mark') | 372 stats(out, 'Mark', filter(lambda r: r['mark'] != 0, trace), 'mark') |
| 325 stats(out, 'Sweep', filter(lambda r: r['sweep'] != 0, trace), 'sweep') | 373 stats(out, 'Sweep', filter(lambda r: r['sweep'] != 0, trace), 'sweep') |
| 326 stats(out, 'Compact', filter(lambda r: r['compact'] != 0, trace), 'compact') | 374 stats(out, 'Compact', filter(lambda r: r['compact'] != 0, trace), 'compact') |
| 327 stats(out, | 375 stats(out, |
| 328 'External', | 376 'External', |
| 329 filter(lambda r: r['external'] != 0, trace), | 377 filter(lambda r: r['external'] != 0, trace), |
| 330 'external') | 378 'external') |
| 331 out.write('</table>') | 379 out.write('</table>') |
| 380 throughput('TOTAL', trace) |
| 381 throughput('MS', marksweeps) |
| 382 throughput('MC', markcompacts) |
| 383 throughput('OLDSPACE', globalgcs) |
| 384 out.write('<br/>') |
| 332 for chart in charts: | 385 for chart in charts: |
| 333 out.write('<img src="%s">' % chart) | 386 out.write('<img src="%s">' % chart) |
| 334 out.write('</body></html>') | 387 out.write('</body></html>') |
| 335 | 388 |
| 336 print "%s generated." % (filename + '.html') | 389 print "%s generated." % (filename + '.html') |
| 337 | 390 |
| 338 if len(sys.argv) != 2: | 391 if len(sys.argv) != 2: |
| 339 print "Usage: %s <GC-trace-filename>" % sys.argv[0] | 392 print "Usage: %s <GC-trace-filename>" % sys.argv[0] |
| 340 sys.exit(1) | 393 sys.exit(1) |
| 341 | 394 |
| 342 process_trace(sys.argv[1]) | 395 process_trace(sys.argv[1]) |
| OLD | NEW |