180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#!/usr/bin/env python
280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru# Copyright (c) 2012 The Chromium Authors. All rights reserved.
380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru# Use of this source code is governed by a BSD-style license that can be found
480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru# in the LICENSE file.
580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru""" Analyze recent bench data from graphs, and output suggested ranges.
780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruThis script reads and parses Skia benchmark values from the xhtml files
980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querugenerated by bench_graph_svg.py, and outputs an html file containing suggested
1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querubench ranges to use in bench_expectations.txt, with analytical plots.
1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru"""
1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru__author__ = 'bensong@google.com (Ben Chen)'
1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruimport getopt
1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruimport math
1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruimport re
1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruimport sys
1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruimport urllib
2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querufrom datetime import datetime
2180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru# Constants for calculating suggested bench ranges.
2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruWINDOW = 5  # Moving average sliding window size.
2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru# We use moving average as expected bench value, and calculate average Variance
2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru# of bench from the moving average. Set range to be [X_UB * Variance above
2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru# moving average, X_LB * Variance below moving average] of latest revision.
2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruX_UB = 4.0
2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruX_LB = 5.0
3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru# List of platforms.
3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruPLATFORMS = ['GalaxyNexus_4-1_Float_Release',
3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru             'Mac_Float_NoDebug_32',
3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru             'Mac_Float_NoDebug_64',
3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru             'MacMiniLion_Float_NoDebug_32',
3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru             'MacMiniLion_Float_NoDebug_64',
3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru             'Nexus7_4-1_Float_Release',
3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru             'Shuttle_Ubuntu12_ATI5770_Float_Release_64',
3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru             'Shuttle_Win7_Intel_Float_Release_32',
4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru             'Shuttle_Win7_Intel_Float_Release_64',
4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru             'Xoom_4-1_Float_Release'
4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            ]
4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru# List of bench representation algorithms. Flag "-a" is chosen from the list.
4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruALGS = ['25th', 'avg', 'med', 'min']
4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru# Regular expressions for parsing bench/revision values.
4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruHEIGHT_RE = 'height (\d+\.\d+) corresponds to bench value (\d+\.\d+).-->'
4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruREV_RE = '<rect id="(\d+)" x="(\d+\.\d+)" y="'  # Revision corresponding x.
5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruLINE_RE = '<polyline id="(.*)".*points="(.*)"/>'  # Bench value lines.
5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru# Bench graph url pattern.
5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruINPUT_URL_TEMPLATE = ('http://chromium-skia-gm.commondatastorage.googleapis.com'
5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                      '/graph-Skia_%s-2.xhtml')
5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru# Output HTML elements and templates.
5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruHTML_HEAD = ('<html><head><title>Skia Bench Expected Ranges</title>'
5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru             '<script type="text/javascript" src="https://skia.googlecode.com/'
5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru             'svn/buildbot/dygraph-combined.js"></script></head><body>Please '
6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru             'adjust values as appropriate and update benches to monitor in '
6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru             'bench/bench_expectations.txt.<br><br>')
6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruHTML_SUFFIX = '</body></html>'
6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruGRAPH_PREFIX = ('<br>%s<br><div id="%s" style="width:400px;height:200px"></div>'
6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                '<script type="text/javascript">g%s=new Dygraph('
6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                'document.getElementById("%s"),"rev,bench,alert\\n')
6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruGRAPH_SUFFIX = ('",{customBars: true,"alert":{strokeWidth:0.0,drawPoints:true,'
6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                'pointSize:4,highlightCircleSize:6}});</script>')
6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querudef Usage():
7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  """Prints flag usage information."""
7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  print '-a <representation-algorithm>: defaults to "25th".'
7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  print '  If set, must be one of the list element in ALGS defined above.'
7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  print '-b <bench-prefix>: prefix of matching bench names to analyze.'
7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  print '  Only include benchmarks whose names start with this string.'
7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  print '  Cannot be empty, because there are too many benches overall.'
7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  print '-o <file>: html output filename. Output to STDOUT if not set.'
7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  print '-p <platform-prefix>: prefix of platform names to analyze.'
7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  print '  PLATFORMS has list of matching candidates. Matches all if not set.'
8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querudef GetBenchValues(page, bench_prefix):
8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  """Returns a dict of matching bench values from the given xhtml page.
8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  Args:
8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    page: substring used to construct the specific bench graph URL to fetch.
8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bench_prefix: only benches starting with this string will be included.
8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  Returns:
8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    a dict mapping benchmark name and revision combinations to bench values.
8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  """
9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  height = None
9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  max_bench = None
9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  height_scale = None
9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  revisions = []
9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  x_axes = []  # For calculating corresponding revisions.
9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  val_dic = {}  # dict[bench_name][revision] -> bench_value
9680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
9780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  lines = urllib.urlopen(INPUT_URL_TEMPLATE % page).readlines()
9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  for line in lines:
9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    height_match = re.search(HEIGHT_RE, line)
10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if height_match:
10180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      height = float(height_match.group(1))
10280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      max_bench = float(height_match.group(2))
10380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      height_scale = max_bench / height
10480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
10580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    rev_match = re.search(REV_RE, line)
10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if rev_match:
10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      revisions.append(int(rev_match.group(1)))
10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      x_axes.append(float(rev_match.group(2)))
10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    line_match = re.search(LINE_RE, line)
11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if not line_match:
11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      continue
11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bench = line_match.group(1)
11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bench = bench[:bench.find('_{')]
11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if not bench.startswith(bench_prefix):
11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      continue
11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if bench not in val_dic:
11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      val_dic[bench] = {}
11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
12080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    vals = line_match.group(2).strip().split(' ')
12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if len(vals) < WINDOW:  # Too few bench data points; skip.
12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      continue
12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    for val in vals:
12480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      x, y = [float(i) for i in val.split(',')]
12580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      for i in range(len(x_axes)):
12680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if x <= x_axes[i]:  # Found corresponding bench revision.
12780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          break
12880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      val_dic[bench][revisions[i]] = float(
12980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          '%.3f' % ((height - y) * height_scale))
13080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
13180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  return val_dic
13280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
13380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querudef CreateBenchOutput(page, bench, val_dic):
13480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  """Returns output for the given page and bench data in dict.
13580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  Args:
13680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    page: substring of bench graph webpage, to indicate the bench platform.
13780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bench: name of the benchmark to process.
13880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    val_dic: dict[bench_name][revision] -> bench_value.
13980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
14080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  Returns:
14180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    string of html/javascript as part of the whole script output for the bench.
14280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  """
14380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  revs = val_dic[bench].keys()
14480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  revs.sort()
14580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  # Uses moving average to calculate expected bench variance, then sets
14680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  # expectations and ranges accordingly.
14780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  variances = []
14880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  moving_avgs = []
14980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  points = []
15080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  for rev in revs:
15180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    points.append(val_dic[bench][rev])
15280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if len(points) >= WINDOW:
15380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      moving_avgs.append(sum(points[-WINDOW:]) / WINDOW)
15480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      variances.append(abs(points[-1] - moving_avgs[-1]))
15580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    else:  # For the first WINDOW-1 points, cannot calculate moving average.
15680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      moving_avgs.append(points[-1])  # Uses actual value as estimates.
15780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      variances.append(0)
15880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if len(variances) >= WINDOW:
15980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    for i in range(WINDOW - 1):
16080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      # Backfills estimated variances for the first WINDOW-1 points.
16180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      variances[i] = variances[WINDOW - 1]
16280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
16380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  avg_var = sum(variances) / len(variances)
16480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  for val in variances:  # Removes outlier variances. Only does one iter.
16580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if val > min(X_LB, X_UB) * avg_var:
16680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      variances.remove(val)
16780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  avg_var = sum(variances) / len(variances)
16880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
16980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  graph_id = '%s_%s' % (bench, page.replace('-', '_'))
17080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  expectations = '%s,%s,%.2f,%.2f,%.2f' % (bench, page, moving_avgs[-1],
17180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                           moving_avgs[-1] - X_LB * avg_var,
17280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                           moving_avgs[-1] + X_UB * avg_var)
17380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  out = GRAPH_PREFIX % (expectations, graph_id, graph_id, graph_id)
17480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  for i in range(len(revs)):
17580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    out += '%s,%.2f;%.2f;%.2f,' % (revs[i], moving_avgs[i] - X_LB * avg_var,
17680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                   points[i], moving_avgs[i] + X_UB * avg_var)
17780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (points[i] > moving_avgs[i] + X_UB * avg_var or
17880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        points[i] < moving_avgs[i] - X_LB * avg_var):  # Mark as alert point.
17980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      out += '%.2f;%.2f;%.2f\\n' % (points[i], points[i], points[i])
18080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    else:
18180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      out += 'NaN;NaN;NaN\\n'
18280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
18380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  return out
18480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
18580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querudef main():
18680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  """Parses flags and outputs analysis results."""
18780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  try:
18880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    opts, _ = getopt.getopt(sys.argv[1:], 'a:b:o:p:')
18980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  except getopt.GetoptError, err:
19080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    Usage()
19180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    sys.exit(2)
19280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
19380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  alg = '25th'
19480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  bench_prefix = None
19580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  out_file = None
19680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  platform_prefix = ''
19780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  for option, value in opts:
19880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if option == '-a':
19980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      if value not in ALGS:
20080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        raise Exception('Invalid flag -a (%s): must be set to one of %s.' %
20180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                        (value, str(ALGS)))
20280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      alg = value
20380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    elif option == '-b':
20480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      bench_prefix = value
20580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    elif option == '-o':
20680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      out_file = value
20780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    elif option == '-p':
20880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      platform_prefix = value
20980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    else:
21080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      Usage()
21180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      raise Exception('Error handling flags.')
21280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
21380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if not bench_prefix:
21480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    raise Exception('Must provide nonempty Flag -b (bench name prefix).')
21580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
21680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  pages = []
21780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  for platform in PLATFORMS:
21880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if not platform.startswith(platform_prefix):
21980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      continue
22080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pages.append('%s-%s' % (platform, alg))
22180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
22280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if not pages:  # No matching platform found.
22380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    raise Exception('Flag -p (platform prefix: %s) does not match any of %s.' %
22480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    (platform_prefix, str(PLATFORMS)))
22580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
22680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  body = ''
22780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  # Iterates through bench graph xhtml pages for oututting matching benches.
22880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  for page in pages:
22980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bench_value_dict = GetBenchValues(page, bench_prefix)
23080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    for bench in bench_value_dict:
23180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      body += CreateBenchOutput(page, bench, bench_value_dict) + GRAPH_SUFFIX
23280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
23380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if not body:
23480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    raise Exception('No bench outputs. Most likely there are no matching bench'
23580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    ' prefix (%s) in Flags -b for platforms %s.\nPlease also '
23680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                    'check if the bench graph URLs are valid at %s.' % (
23780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                        bench_prefix, str(PLATFORMS), INPUT_URL_TEMPLATE))
23880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if out_file:
23980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    f = open(out_file, 'w+')
24080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    f.write(HTML_HEAD + body + HTML_SUFFIX)
24180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    f.close()
24280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  else:
24380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    print HTML_HEAD + body + HTML_SUFFIX
24480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
24580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
24680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruif '__main__' == __name__:
24780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  main()
248