diff options
Diffstat (limited to 'src/3rdparty/v8/tools/gc-nvp-trace-processor.py')
-rwxr-xr-x | src/3rdparty/v8/tools/gc-nvp-trace-processor.py | 389 |
1 files changed, 0 insertions, 389 deletions
diff --git a/src/3rdparty/v8/tools/gc-nvp-trace-processor.py b/src/3rdparty/v8/tools/gc-nvp-trace-processor.py deleted file mode 100755 index fe5a7f3..0000000 --- a/src/3rdparty/v8/tools/gc-nvp-trace-processor.py +++ /dev/null @@ -1,389 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2010 the V8 project authors. All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -# -# This is an utility for plotting charts based on GC traces produced by V8 when -# run with flags --trace-gc --trace-gc-nvp. Relies on gnuplot for actual -# plotting. -# -# Usage: gc-nvp-trace-processor.py <GC-trace-filename> -# - - -from __future__ import with_statement -import sys, types, re, subprocess, math - -def flatten(l): - flat = [] - for i in l: flat.extend(i) - return flat - -def split_nvp(s): - t = {} - for (name, value) in re.findall(r"(\w+)=([-\w]+)", s): - try: - t[name] = int(value) - except ValueError: - t[name] = value - - return t - -def parse_gc_trace(input): - trace = [] - with open(input) as f: - for line in f: - info = split_nvp(line) - if info and 'pause' in info and info['pause'] > 0: - info['i'] = len(trace) - trace.append(info) - return trace - -def extract_field_names(script): - fields = { 'data': true, 'in': true } - - for m in re.finditer(r"$(\w+)", script): - field_name = m.group(1) - if field_name not in fields: - fields[field] = field_count - field_count = field_count + 1 - - return fields - -def gnuplot(script): - gnuplot = subprocess.Popen(["gnuplot"], stdin=subprocess.PIPE) - gnuplot.stdin.write(script) - gnuplot.stdin.close() - gnuplot.wait() - -x1y1 = 'x1y1' -x1y2 = 'x1y2' -x2y1 = 'x2y1' -x2y2 = 'x2y2' - -class Item(object): - def __init__(self, title, field, axis = x1y1, **keywords): - self.title = title - self.axis = axis - self.props = keywords - if type(field) is types.ListType: - self.field = field - else: - self.field = [field] - - def fieldrefs(self): - return self.field - - def to_gnuplot(self, context): - args = ['"%s"' % context.datafile, - 'using %s' % context.format_fieldref(self.field), - 'title "%s"' % self.title, - 'axis %s' % self.axis] - if 'style' in self.props: - args.append('with %s' % self.props['style']) - if 'lc' in self.props: - args.append('lc rgb "%s"' % self.props['lc']) - if 'fs' in self.props: - args.append('fs %s' % self.props['fs']) - return ' '.join(args) - -class Plot(object): - def __init__(self, *items): - self.items = items - - def fieldrefs(self): - return flatten([item.fieldrefs() for item in self.items]) - - def to_gnuplot(self, ctx): - return 'plot ' + ', '.join([item.to_gnuplot(ctx) for item in self.items]) - -class Set(object): - def __init__(self, value): - self.value = value - - def to_gnuplot(self, ctx): - return 'set ' + self.value - - def fieldrefs(self): - return [] - -class Context(object): - def __init__(self, datafile, field_to_index): - self.datafile = datafile - self.field_to_index = field_to_index - - def format_fieldref(self, fieldref): - return ':'.join([str(self.field_to_index[field]) for field in fieldref]) - -def collect_fields(plot): - field_to_index = {} - fields = [] - - def add_field(field): - if field not in field_to_index: - fields.append(field) - field_to_index[field] = len(fields) - - for field in flatten([item.fieldrefs() for item in plot]): - add_field(field) - - return (fields, field_to_index) - -def is_y2_used(plot): - for subplot in plot: - if isinstance(subplot, Plot): - for item in subplot.items: - if item.axis == x1y2 or item.axis == x2y2: - return True - return False - -def get_field(trace_line, field): - t = type(field) - if t is types.StringType: - return trace_line[field] - elif t is types.FunctionType: - return field(trace_line) - -def generate_datafile(datafile_name, trace, fields): - with open(datafile_name, 'w') as datafile: - for line in trace: - data_line = [str(get_field(line, field)) for field in fields] - datafile.write('\t'.join(data_line)) - datafile.write('\n') - -def generate_script_and_datafile(plot, trace, datafile, output): - (fields, field_to_index) = collect_fields(plot) - generate_datafile(datafile, trace, fields) - script = [ - 'set terminal png', - 'set output "%s"' % output, - 'set autoscale', - 'set ytics nomirror', - 'set xtics nomirror', - 'set key below' - ] - - if is_y2_used(plot): - script.append('set autoscale y2') - script.append('set y2tics') - - context = Context(datafile, field_to_index) - - for item in plot: - script.append(item.to_gnuplot(context)) - - return '\n'.join(script) - -def plot_all(plots, trace, prefix): - charts = [] - - for plot in plots: - outfilename = "%s_%d.png" % (prefix, len(charts)) - charts.append(outfilename) - script = generate_script_and_datafile(plot, trace, '~datafile', outfilename) - print 'Plotting %s...' % outfilename - gnuplot(script) - - return charts - -def reclaimed_bytes(row): - return row['total_size_before'] - row['total_size_after'] - -def other_scope(r): - if r['gc'] == 's': - # there is no 'other' scope for scavenging collections. - return 0 - return r['pause'] - r['mark'] - r['sweep'] - r['external'] - -def scavenge_scope(r): - if r['gc'] == 's': - return r['pause'] - r['external'] - return 0 - - -def real_mutator(r): - return r['mutator'] - r['stepstook'] - -plots = [ - [ - Set('style fill solid 0.5 noborder'), - Set('style histogram rowstacked'), - Set('style data histograms'), - Plot(Item('Scavenge', scavenge_scope, lc = 'green'), - Item('Marking', 'mark', lc = 'purple'), - Item('Sweep', 'sweep', lc = 'blue'), - Item('External', 'external', lc = '#489D43'), - Item('Other', other_scope, lc = 'grey'), - Item('IGC Steps', 'stepstook', lc = '#FF6347')) - ], - [ - Set('style fill solid 0.5 noborder'), - Set('style histogram rowstacked'), - Set('style data histograms'), - Plot(Item('Scavenge', scavenge_scope, lc = 'green'), - Item('Marking', 'mark', lc = 'purple'), - Item('Sweep', 'sweep', lc = 'blue'), - Item('External', 'external', lc = '#489D43'), - Item('Other', other_scope, lc = '#ADD8E6'), - Item('External', 'external', lc = '#D3D3D3')) - ], - - [ - Plot(Item('Mutator', real_mutator, lc = 'black', style = 'lines')) - ], - [ - Set('style histogram rowstacked'), - Set('style data histograms'), - Plot(Item('Heap Size (before GC)', 'total_size_before', x1y2, - fs = 'solid 0.4 noborder', - lc = 'green'), - Item('Total holes (after GC)', 'holes_size_before', x1y2, - fs = 'solid 0.4 noborder', - lc = 'red'), - Item('GC Time', ['i', 'pause'], style = 'lines', lc = 'red')) - ], - [ - Set('style histogram rowstacked'), - Set('style data histograms'), - Plot(Item('Heap Size (after GC)', 'total_size_after', x1y2, - fs = 'solid 0.4 noborder', - lc = 'green'), - Item('Total holes (after GC)', 'holes_size_after', x1y2, - fs = 'solid 0.4 noborder', - lc = 'red'), - Item('GC Time', ['i', 'pause'], - style = 'lines', - lc = 'red')) - ], - [ - Set('style fill solid 0.5 noborder'), - Set('style data histograms'), - Plot(Item('Allocated', 'allocated'), - Item('Reclaimed', reclaimed_bytes), - Item('Promoted', 'promoted', style = 'lines', lc = 'black')) - ], -] - -def freduce(f, field, trace, init): - return reduce(lambda t,r: f(t, r[field]), trace, init) - -def calc_total(trace, field): - return freduce(lambda t,v: t + long(v), field, trace, long(0)) - -def calc_max(trace, field): - return freduce(lambda t,r: max(t, r), field, trace, 0) - -def count_nonzero(trace, field): - return freduce(lambda t,r: t if r == 0 else t + 1, field, trace, 0) - - -def process_trace(filename): - trace = parse_gc_trace(filename) - - marksweeps = filter(lambda r: r['gc'] == 'ms', trace) - scavenges = filter(lambda r: r['gc'] == 's', trace) - globalgcs = filter(lambda r: r['gc'] != 's', trace) - - - charts = plot_all(plots, trace, filename) - - def stats(out, prefix, trace, field): - n = len(trace) - total = calc_total(trace, field) - max = calc_max(trace, field) - if n > 0: - avg = total / n - else: - avg = 0 - if n > 1: - dev = math.sqrt(freduce(lambda t,r: t + (r - avg) ** 2, field, trace, 0) / - (n - 1)) - else: - dev = 0 - - out.write('<tr><td>%s</td><td>%d</td><td>%d</td>' - '<td>%d</td><td>%d [dev %f]</td></tr>' % - (prefix, n, total, max, avg, dev)) - - def HumanReadable(size): - suffixes = ['bytes', 'kB', 'MB', 'GB'] - power = 1 - for i in range(len(suffixes)): - if size < power*1024: - return "%.1f" % (float(size) / power) + " " + suffixes[i] - power *= 1024 - - def throughput(name, trace): - total_live_after = calc_total(trace, 'total_size_after') - total_live_before = calc_total(trace, 'total_size_before') - total_gc = calc_total(trace, 'pause') - if total_gc == 0: - return - out.write('GC %s Throughput (after): %s / %s ms = %s/ms<br/>' % - (name, - HumanReadable(total_live_after), - total_gc, - HumanReadable(total_live_after / total_gc))) - out.write('GC %s Throughput (before): %s / %s ms = %s/ms<br/>' % - (name, - HumanReadable(total_live_before), - total_gc, - HumanReadable(total_live_before / total_gc))) - - - with open(filename + '.html', 'w') as out: - out.write('<html><body>') - out.write('<table>') - out.write('<tr><td>Phase</td><td>Count</td><td>Time (ms)</td>') - out.write('<td>Max</td><td>Avg</td></tr>') - stats(out, 'Total in GC', trace, 'pause') - stats(out, 'Scavenge', scavenges, 'pause') - stats(out, 'MarkSweep', marksweeps, 'pause') - stats(out, 'Mark', filter(lambda r: r['mark'] != 0, trace), 'mark') - stats(out, 'Sweep', filter(lambda r: r['sweep'] != 0, trace), 'sweep') - stats(out, - 'External', - filter(lambda r: r['external'] != 0, trace), - 'external') - out.write('</table>') - throughput('TOTAL', trace) - throughput('MS', marksweeps) - throughput('OLDSPACE', globalgcs) - out.write('<br/>') - for chart in charts: - out.write('<img src="%s">' % chart) - out.write('</body></html>') - - print "%s generated." % (filename + '.html') - -if len(sys.argv) != 2: - print "Usage: %s <GC-trace-filename>" % sys.argv[0] - sys.exit(1) - -process_trace(sys.argv[1]) |