summaryrefslogtreecommitdiff
path: root/src/3rdparty/v8/tools/gc-nvp-trace-processor.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/v8/tools/gc-nvp-trace-processor.py')
-rwxr-xr-xsrc/3rdparty/v8/tools/gc-nvp-trace-processor.py389
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])