11cb0ef41Sopenharmony_ci#!/usr/bin/env python
21cb0ef41Sopenharmony_ci#
31cb0ef41Sopenharmony_ci# Copyright 2010 the V8 project authors. All rights reserved.
41cb0ef41Sopenharmony_ci# Redistribution and use in source and binary forms, with or without
51cb0ef41Sopenharmony_ci# modification, are permitted provided that the following conditions are
61cb0ef41Sopenharmony_ci# met:
71cb0ef41Sopenharmony_ci#
81cb0ef41Sopenharmony_ci#     * Redistributions of source code must retain the above copyright
91cb0ef41Sopenharmony_ci#       notice, this list of conditions and the following disclaimer.
101cb0ef41Sopenharmony_ci#     * Redistributions in binary form must reproduce the above
111cb0ef41Sopenharmony_ci#       copyright notice, this list of conditions and the following
121cb0ef41Sopenharmony_ci#       disclaimer in the documentation and/or other materials provided
131cb0ef41Sopenharmony_ci#       with the distribution.
141cb0ef41Sopenharmony_ci#     * Neither the name of Google Inc. nor the names of its
151cb0ef41Sopenharmony_ci#       contributors may be used to endorse or promote products derived
161cb0ef41Sopenharmony_ci#       from this software without specific prior written permission.
171cb0ef41Sopenharmony_ci#
181cb0ef41Sopenharmony_ci# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
191cb0ef41Sopenharmony_ci# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
201cb0ef41Sopenharmony_ci# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
211cb0ef41Sopenharmony_ci# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
221cb0ef41Sopenharmony_ci# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
231cb0ef41Sopenharmony_ci# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
241cb0ef41Sopenharmony_ci# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
251cb0ef41Sopenharmony_ci# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
261cb0ef41Sopenharmony_ci# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
271cb0ef41Sopenharmony_ci# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
281cb0ef41Sopenharmony_ci# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
291cb0ef41Sopenharmony_ci#
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci#
321cb0ef41Sopenharmony_ci# This is an utility for plotting charts based on GC traces produced by V8 when
331cb0ef41Sopenharmony_ci# run with flags --trace-gc --trace-gc-nvp. Relies on gnuplot for actual
341cb0ef41Sopenharmony_ci# plotting.
351cb0ef41Sopenharmony_ci#
361cb0ef41Sopenharmony_ci# Usage: gc-nvp-trace-processor.py <GC-trace-filename>
371cb0ef41Sopenharmony_ci#
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci# for py2/py3 compatibility
411cb0ef41Sopenharmony_cifrom __future__ import with_statement
421cb0ef41Sopenharmony_cifrom __future__ import print_function
431cb0ef41Sopenharmony_cifrom functools import reduce
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ciimport sys, types, subprocess, math
461cb0ef41Sopenharmony_ciimport gc_nvp_common
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_citry:
501cb0ef41Sopenharmony_ci  long        # Python 2
511cb0ef41Sopenharmony_ciexcept NameError:
521cb0ef41Sopenharmony_ci  long = int  # Python 3
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_cidef flatten(l):
561cb0ef41Sopenharmony_ci  flat = []
571cb0ef41Sopenharmony_ci  for i in l: flat.extend(i)
581cb0ef41Sopenharmony_ci  return flat
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_cidef gnuplot(script):
611cb0ef41Sopenharmony_ci  gnuplot = subprocess.Popen(["gnuplot"], stdin=subprocess.PIPE)
621cb0ef41Sopenharmony_ci  gnuplot.stdin.write(script)
631cb0ef41Sopenharmony_ci  gnuplot.stdin.close()
641cb0ef41Sopenharmony_ci  gnuplot.wait()
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_cix1y1 = 'x1y1'
671cb0ef41Sopenharmony_cix1y2 = 'x1y2'
681cb0ef41Sopenharmony_cix2y1 = 'x2y1'
691cb0ef41Sopenharmony_cix2y2 = 'x2y2'
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ciclass Item(object):
721cb0ef41Sopenharmony_ci  def __init__(self, title, field, axis = x1y1, **keywords):
731cb0ef41Sopenharmony_ci    self.title = title
741cb0ef41Sopenharmony_ci    self.axis = axis
751cb0ef41Sopenharmony_ci    self.props = keywords
761cb0ef41Sopenharmony_ci    if type(field) is list:
771cb0ef41Sopenharmony_ci      self.field = field
781cb0ef41Sopenharmony_ci    else:
791cb0ef41Sopenharmony_ci      self.field = [field]
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  def fieldrefs(self):
821cb0ef41Sopenharmony_ci    return self.field
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci  def to_gnuplot(self, context):
851cb0ef41Sopenharmony_ci    args = ['"%s"' % context.datafile,
861cb0ef41Sopenharmony_ci            'using %s' % context.format_fieldref(self.field),
871cb0ef41Sopenharmony_ci            'title "%s"' % self.title,
881cb0ef41Sopenharmony_ci            'axis %s' % self.axis]
891cb0ef41Sopenharmony_ci    if 'style' in self.props:
901cb0ef41Sopenharmony_ci      args.append('with %s' % self.props['style'])
911cb0ef41Sopenharmony_ci    if 'lc' in self.props:
921cb0ef41Sopenharmony_ci      args.append('lc rgb "%s"' % self.props['lc'])
931cb0ef41Sopenharmony_ci    if 'fs' in self.props:
941cb0ef41Sopenharmony_ci      args.append('fs %s' % self.props['fs'])
951cb0ef41Sopenharmony_ci    return ' '.join(args)
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ciclass Plot(object):
981cb0ef41Sopenharmony_ci  def __init__(self, *items):
991cb0ef41Sopenharmony_ci    self.items = items
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci  def fieldrefs(self):
1021cb0ef41Sopenharmony_ci    return flatten([item.fieldrefs() for item in self.items])
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci  def to_gnuplot(self, ctx):
1051cb0ef41Sopenharmony_ci    return 'plot ' + ', '.join([item.to_gnuplot(ctx) for item in self.items])
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_ciclass Set(object):
1081cb0ef41Sopenharmony_ci  def __init__(self, value):
1091cb0ef41Sopenharmony_ci    self.value = value
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci  def to_gnuplot(self, ctx):
1121cb0ef41Sopenharmony_ci    return 'set ' + self.value
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci  def fieldrefs(self):
1151cb0ef41Sopenharmony_ci    return []
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ciclass Context(object):
1181cb0ef41Sopenharmony_ci  def __init__(self, datafile, field_to_index):
1191cb0ef41Sopenharmony_ci    self.datafile = datafile
1201cb0ef41Sopenharmony_ci    self.field_to_index = field_to_index
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci  def format_fieldref(self, fieldref):
1231cb0ef41Sopenharmony_ci    return ':'.join([str(self.field_to_index[field]) for field in fieldref])
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_cidef collect_fields(plot):
1261cb0ef41Sopenharmony_ci  field_to_index = {}
1271cb0ef41Sopenharmony_ci  fields = []
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  def add_field(field):
1301cb0ef41Sopenharmony_ci    if field not in field_to_index:
1311cb0ef41Sopenharmony_ci      fields.append(field)
1321cb0ef41Sopenharmony_ci      field_to_index[field] = len(fields)
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci  for field in flatten([item.fieldrefs() for item in plot]):
1351cb0ef41Sopenharmony_ci    add_field(field)
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci  return (fields, field_to_index)
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_cidef is_y2_used(plot):
1401cb0ef41Sopenharmony_ci  for subplot in plot:
1411cb0ef41Sopenharmony_ci    if isinstance(subplot, Plot):
1421cb0ef41Sopenharmony_ci      for item in subplot.items:
1431cb0ef41Sopenharmony_ci        if item.axis == x1y2 or item.axis == x2y2:
1441cb0ef41Sopenharmony_ci          return True
1451cb0ef41Sopenharmony_ci  return False
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_cidef get_field(trace_line, field):
1481cb0ef41Sopenharmony_ci  t = type(field)
1491cb0ef41Sopenharmony_ci  if t is bytes:
1501cb0ef41Sopenharmony_ci    return trace_line[field]
1511cb0ef41Sopenharmony_ci  elif t is types.FunctionType:
1521cb0ef41Sopenharmony_ci    return field(trace_line)
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_cidef generate_datafile(datafile_name, trace, fields):
1551cb0ef41Sopenharmony_ci  with open(datafile_name, 'w') as datafile:
1561cb0ef41Sopenharmony_ci    for line in trace:
1571cb0ef41Sopenharmony_ci      data_line = [str(get_field(line, field)) for field in fields]
1581cb0ef41Sopenharmony_ci      datafile.write('\t'.join(data_line))
1591cb0ef41Sopenharmony_ci      datafile.write('\n')
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_cidef generate_script_and_datafile(plot, trace, datafile, output):
1621cb0ef41Sopenharmony_ci  (fields, field_to_index) = collect_fields(plot)
1631cb0ef41Sopenharmony_ci  generate_datafile(datafile, trace, fields)
1641cb0ef41Sopenharmony_ci  script = [
1651cb0ef41Sopenharmony_ci      'set terminal png',
1661cb0ef41Sopenharmony_ci      'set output "%s"' % output,
1671cb0ef41Sopenharmony_ci      'set autoscale',
1681cb0ef41Sopenharmony_ci      'set ytics nomirror',
1691cb0ef41Sopenharmony_ci      'set xtics nomirror',
1701cb0ef41Sopenharmony_ci      'set key below'
1711cb0ef41Sopenharmony_ci  ]
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_ci  if is_y2_used(plot):
1741cb0ef41Sopenharmony_ci    script.append('set autoscale y2')
1751cb0ef41Sopenharmony_ci    script.append('set y2tics')
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci  context = Context(datafile, field_to_index)
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ci  for item in plot:
1801cb0ef41Sopenharmony_ci    script.append(item.to_gnuplot(context))
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci  return '\n'.join(script)
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_cidef plot_all(plots, trace, prefix):
1851cb0ef41Sopenharmony_ci  charts = []
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ci  for plot in plots:
1881cb0ef41Sopenharmony_ci    outfilename = "%s_%d.png" % (prefix, len(charts))
1891cb0ef41Sopenharmony_ci    charts.append(outfilename)
1901cb0ef41Sopenharmony_ci    script = generate_script_and_datafile(plot, trace, '~datafile', outfilename)
1911cb0ef41Sopenharmony_ci    print('Plotting %s...' % outfilename)
1921cb0ef41Sopenharmony_ci    gnuplot(script)
1931cb0ef41Sopenharmony_ci
1941cb0ef41Sopenharmony_ci  return charts
1951cb0ef41Sopenharmony_ci
1961cb0ef41Sopenharmony_cidef reclaimed_bytes(row):
1971cb0ef41Sopenharmony_ci  return row['total_size_before'] - row['total_size_after']
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_cidef other_scope(r):
2001cb0ef41Sopenharmony_ci  if r['gc'] == 's':
2011cb0ef41Sopenharmony_ci    # there is no 'other' scope for scavenging collections.
2021cb0ef41Sopenharmony_ci    return 0
2031cb0ef41Sopenharmony_ci  return r['pause'] - r['mark'] - r['sweep'] - r['external']
2041cb0ef41Sopenharmony_ci
2051cb0ef41Sopenharmony_cidef scavenge_scope(r):
2061cb0ef41Sopenharmony_ci  if r['gc'] == 's':
2071cb0ef41Sopenharmony_ci    return r['pause'] - r['external']
2081cb0ef41Sopenharmony_ci  return 0
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_cidef real_mutator(r):
2121cb0ef41Sopenharmony_ci  return r['mutator'] - r['steps_took']
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ciplots = [
2151cb0ef41Sopenharmony_ci  [
2161cb0ef41Sopenharmony_ci    Set('style fill solid 0.5 noborder'),
2171cb0ef41Sopenharmony_ci    Set('style histogram rowstacked'),
2181cb0ef41Sopenharmony_ci    Set('style data histograms'),
2191cb0ef41Sopenharmony_ci    Plot(Item('Scavenge', scavenge_scope, lc = 'green'),
2201cb0ef41Sopenharmony_ci         Item('Marking', 'mark', lc = 'purple'),
2211cb0ef41Sopenharmony_ci         Item('Sweep', 'sweep', lc = 'blue'),
2221cb0ef41Sopenharmony_ci         Item('External', 'external', lc = '#489D43'),
2231cb0ef41Sopenharmony_ci         Item('Other', other_scope, lc = 'grey'),
2241cb0ef41Sopenharmony_ci         Item('IGC Steps', 'steps_took', lc = '#FF6347'))
2251cb0ef41Sopenharmony_ci  ],
2261cb0ef41Sopenharmony_ci  [
2271cb0ef41Sopenharmony_ci    Set('style fill solid 0.5 noborder'),
2281cb0ef41Sopenharmony_ci    Set('style histogram rowstacked'),
2291cb0ef41Sopenharmony_ci    Set('style data histograms'),
2301cb0ef41Sopenharmony_ci    Plot(Item('Scavenge', scavenge_scope, lc = 'green'),
2311cb0ef41Sopenharmony_ci         Item('Marking', 'mark', lc = 'purple'),
2321cb0ef41Sopenharmony_ci         Item('Sweep', 'sweep', lc = 'blue'),
2331cb0ef41Sopenharmony_ci         Item('External', 'external', lc = '#489D43'),
2341cb0ef41Sopenharmony_ci         Item('Other', other_scope, lc = '#ADD8E6'),
2351cb0ef41Sopenharmony_ci         Item('External', 'external', lc = '#D3D3D3'))
2361cb0ef41Sopenharmony_ci  ],
2371cb0ef41Sopenharmony_ci
2381cb0ef41Sopenharmony_ci  [
2391cb0ef41Sopenharmony_ci    Plot(Item('Mutator', real_mutator, lc = 'black', style = 'lines'))
2401cb0ef41Sopenharmony_ci  ],
2411cb0ef41Sopenharmony_ci  [
2421cb0ef41Sopenharmony_ci    Set('style histogram rowstacked'),
2431cb0ef41Sopenharmony_ci    Set('style data histograms'),
2441cb0ef41Sopenharmony_ci    Plot(Item('Heap Size (before GC)', 'total_size_before', x1y2,
2451cb0ef41Sopenharmony_ci              fs = 'solid 0.4 noborder',
2461cb0ef41Sopenharmony_ci              lc = 'green'),
2471cb0ef41Sopenharmony_ci         Item('Total holes (after GC)', 'holes_size_before', x1y2,
2481cb0ef41Sopenharmony_ci              fs = 'solid 0.4 noborder',
2491cb0ef41Sopenharmony_ci              lc = 'red'),
2501cb0ef41Sopenharmony_ci         Item('GC Time', ['i', 'pause'], style = 'lines', lc = 'red'))
2511cb0ef41Sopenharmony_ci  ],
2521cb0ef41Sopenharmony_ci  [
2531cb0ef41Sopenharmony_ci    Set('style histogram rowstacked'),
2541cb0ef41Sopenharmony_ci    Set('style data histograms'),
2551cb0ef41Sopenharmony_ci    Plot(Item('Heap Size (after GC)', 'total_size_after', x1y2,
2561cb0ef41Sopenharmony_ci              fs = 'solid 0.4 noborder',
2571cb0ef41Sopenharmony_ci              lc = 'green'),
2581cb0ef41Sopenharmony_ci         Item('Total holes (after GC)', 'holes_size_after', x1y2,
2591cb0ef41Sopenharmony_ci              fs = 'solid 0.4 noborder',
2601cb0ef41Sopenharmony_ci              lc = 'red'),
2611cb0ef41Sopenharmony_ci         Item('GC Time', ['i', 'pause'],
2621cb0ef41Sopenharmony_ci              style = 'lines',
2631cb0ef41Sopenharmony_ci              lc = 'red'))
2641cb0ef41Sopenharmony_ci  ],
2651cb0ef41Sopenharmony_ci  [
2661cb0ef41Sopenharmony_ci    Set('style fill solid 0.5 noborder'),
2671cb0ef41Sopenharmony_ci    Set('style data histograms'),
2681cb0ef41Sopenharmony_ci    Plot(Item('Allocated', 'allocated'),
2691cb0ef41Sopenharmony_ci         Item('Reclaimed', reclaimed_bytes),
2701cb0ef41Sopenharmony_ci         Item('Promoted', 'promoted', style = 'lines', lc = 'black'))
2711cb0ef41Sopenharmony_ci  ],
2721cb0ef41Sopenharmony_ci]
2731cb0ef41Sopenharmony_ci
2741cb0ef41Sopenharmony_cidef freduce(f, field, trace, init):
2751cb0ef41Sopenharmony_ci  return reduce(lambda t,r: f(t, r[field]), trace, init)
2761cb0ef41Sopenharmony_ci
2771cb0ef41Sopenharmony_cidef calc_total(trace, field):
2781cb0ef41Sopenharmony_ci  return freduce(lambda t,v: t + long(v), field, trace, long(0))
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_cidef calc_max(trace, field):
2811cb0ef41Sopenharmony_ci  return freduce(lambda t,r: max(t, r), field, trace, 0)
2821cb0ef41Sopenharmony_ci
2831cb0ef41Sopenharmony_cidef count_nonzero(trace, field):
2841cb0ef41Sopenharmony_ci  return freduce(lambda t,r: t if r == 0 else t + 1, field, trace, 0)
2851cb0ef41Sopenharmony_ci
2861cb0ef41Sopenharmony_ci
2871cb0ef41Sopenharmony_cidef process_trace(filename):
2881cb0ef41Sopenharmony_ci  trace = gc_nvp_common.parse_gc_trace(filename)
2891cb0ef41Sopenharmony_ci
2901cb0ef41Sopenharmony_ci  marksweeps = filter(lambda r: r['gc'] == 'ms', trace)
2911cb0ef41Sopenharmony_ci  scavenges = filter(lambda r: r['gc'] == 's', trace)
2921cb0ef41Sopenharmony_ci  globalgcs = filter(lambda r: r['gc'] != 's', trace)
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ci
2951cb0ef41Sopenharmony_ci  charts = plot_all(plots, trace, filename)
2961cb0ef41Sopenharmony_ci
2971cb0ef41Sopenharmony_ci  def stats(out, prefix, trace, field):
2981cb0ef41Sopenharmony_ci    n = len(trace)
2991cb0ef41Sopenharmony_ci    total = calc_total(trace, field)
3001cb0ef41Sopenharmony_ci    max = calc_max(trace, field)
3011cb0ef41Sopenharmony_ci    if n > 0:
3021cb0ef41Sopenharmony_ci      avg = total / n
3031cb0ef41Sopenharmony_ci    else:
3041cb0ef41Sopenharmony_ci      avg = 0
3051cb0ef41Sopenharmony_ci    if n > 1:
3061cb0ef41Sopenharmony_ci      dev = math.sqrt(freduce(lambda t,r: t + (r - avg) ** 2, field, trace, 0) /
3071cb0ef41Sopenharmony_ci                      (n - 1))
3081cb0ef41Sopenharmony_ci    else:
3091cb0ef41Sopenharmony_ci      dev = 0
3101cb0ef41Sopenharmony_ci
3111cb0ef41Sopenharmony_ci    out.write('<tr><td>%s</td><td>%d</td><td>%d</td>'
3121cb0ef41Sopenharmony_ci              '<td>%d</td><td>%d [dev %f]</td></tr>' %
3131cb0ef41Sopenharmony_ci              (prefix, n, total, max, avg, dev))
3141cb0ef41Sopenharmony_ci
3151cb0ef41Sopenharmony_ci  def HumanReadable(size):
3161cb0ef41Sopenharmony_ci    suffixes = ['bytes', 'kB', 'MB', 'GB']
3171cb0ef41Sopenharmony_ci    power = 1
3181cb0ef41Sopenharmony_ci    for i in range(len(suffixes)):
3191cb0ef41Sopenharmony_ci      if size < power*1024:
3201cb0ef41Sopenharmony_ci        return "%.1f" % (float(size) / power) + " " + suffixes[i]
3211cb0ef41Sopenharmony_ci      power *= 1024
3221cb0ef41Sopenharmony_ci
3231cb0ef41Sopenharmony_ci  def throughput(name, trace):
3241cb0ef41Sopenharmony_ci    total_live_after = calc_total(trace, 'total_size_after')
3251cb0ef41Sopenharmony_ci    total_live_before = calc_total(trace, 'total_size_before')
3261cb0ef41Sopenharmony_ci    total_gc = calc_total(trace, 'pause')
3271cb0ef41Sopenharmony_ci    if total_gc == 0:
3281cb0ef41Sopenharmony_ci      return
3291cb0ef41Sopenharmony_ci    out.write('GC %s Throughput (after): %s / %s ms = %s/ms<br/>' %
3301cb0ef41Sopenharmony_ci              (name,
3311cb0ef41Sopenharmony_ci               HumanReadable(total_live_after),
3321cb0ef41Sopenharmony_ci               total_gc,
3331cb0ef41Sopenharmony_ci               HumanReadable(total_live_after / total_gc)))
3341cb0ef41Sopenharmony_ci    out.write('GC %s Throughput (before): %s / %s ms = %s/ms<br/>' %
3351cb0ef41Sopenharmony_ci              (name,
3361cb0ef41Sopenharmony_ci               HumanReadable(total_live_before),
3371cb0ef41Sopenharmony_ci               total_gc,
3381cb0ef41Sopenharmony_ci               HumanReadable(total_live_before / total_gc)))
3391cb0ef41Sopenharmony_ci
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_ci  with open(filename + '.html', 'w') as out:
3421cb0ef41Sopenharmony_ci    out.write('<html><body>')
3431cb0ef41Sopenharmony_ci    out.write('<table>')
3441cb0ef41Sopenharmony_ci    out.write('<tr><td>Phase</td><td>Count</td><td>Time (ms)</td>')
3451cb0ef41Sopenharmony_ci    out.write('<td>Max</td><td>Avg</td></tr>')
3461cb0ef41Sopenharmony_ci    stats(out, 'Total in GC', trace, 'pause')
3471cb0ef41Sopenharmony_ci    stats(out, 'Scavenge', scavenges, 'pause')
3481cb0ef41Sopenharmony_ci    stats(out, 'MarkSweep', marksweeps, 'pause')
3491cb0ef41Sopenharmony_ci    stats(out, 'Mark', filter(lambda r: r['mark'] != 0, trace), 'mark')
3501cb0ef41Sopenharmony_ci    stats(out, 'Sweep', filter(lambda r: r['sweep'] != 0, trace), 'sweep')
3511cb0ef41Sopenharmony_ci    stats(out,
3521cb0ef41Sopenharmony_ci          'External',
3531cb0ef41Sopenharmony_ci          filter(lambda r: r['external'] != 0, trace),
3541cb0ef41Sopenharmony_ci          'external')
3551cb0ef41Sopenharmony_ci    out.write('</table>')
3561cb0ef41Sopenharmony_ci    throughput('TOTAL', trace)
3571cb0ef41Sopenharmony_ci    throughput('MS', marksweeps)
3581cb0ef41Sopenharmony_ci    throughput('OLDSPACE', globalgcs)
3591cb0ef41Sopenharmony_ci    out.write('<br/>')
3601cb0ef41Sopenharmony_ci    for chart in charts:
3611cb0ef41Sopenharmony_ci      out.write('<img src="%s">' % chart)
3621cb0ef41Sopenharmony_ci      out.write('</body></html>')
3631cb0ef41Sopenharmony_ci
3641cb0ef41Sopenharmony_ci  print("%s generated." % (filename + '.html'))
3651cb0ef41Sopenharmony_ci
3661cb0ef41Sopenharmony_ciif len(sys.argv) != 2:
3671cb0ef41Sopenharmony_ci  print("Usage: %s <GC-trace-filename>" % sys.argv[0])
3681cb0ef41Sopenharmony_ci  sys.exit(1)
3691cb0ef41Sopenharmony_ci
3701cb0ef41Sopenharmony_ciprocess_trace(sys.argv[1])
371