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