blob: 6b2f491bf24c1907b21186503bb7d472bedf6e37 [file] [log] [blame]
bensong@google.comfa1d4ea2012-11-27 17:30:26 +00001#!/usr/bin/env python
2# Copyright (c) 2012 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be found
4# in the LICENSE file.
5
bensong@google.com29a159c2013-06-13 23:40:05 +00006""" Analyze recent SkPicture or Microbench data, and output suggested ranges.
bensong@google.comfa1d4ea2012-11-27 17:30:26 +00007
bensong@google.com7d9a21b2013-09-25 20:51:16 +00008The outputs can be edited and pasted to bench_expectations_<builder>.txt to
9trigger buildbot alerts if the actual benches are out of range. Details are
10documented in the corresponding .txt file for each builder.
bensong@google.comfa1d4ea2012-11-27 17:30:26 +000011
bensong@google.com7d9a21b2013-09-25 20:51:16 +000012Currently the easiest way to batch update bench_expectations_<builder>.txt is to
13delete all bench lines, run this script, and redirect outputs (">>") to be added
14to the corresponding .txt file for each perf builder.
bensong@google.com29a159c2013-06-13 23:40:05 +000015You can also just manually change a few lines of interest, of course.
bensong@google.comfa1d4ea2012-11-27 17:30:26 +000016
17Note: since input data are stored in Google Storage, you will need to set up
18the corresponding library.
19See http://developers.google.com/storage/docs/gspythonlibrary for details.
20"""
21
22__author__ = 'bensong@google.com (Ben Chen)'
23
24import bench_util
25import boto
26import cStringIO
27import optparse
28import re
29import shutil
30
31from oauth2_plugin import oauth2_plugin
32
33
34# Ratios for calculating suggested picture bench upper and lower bounds.
bensong@google.comdc2dd2e2012-11-27 21:52:32 +000035BENCH_UB = 1.1 # Allow for 10% room for normal variance on the up side.
robertphillips@google.combb51fab2013-03-13 15:25:30 +000036BENCH_LB = 0.9
bensong@google.comfa1d4ea2012-11-27 17:30:26 +000037
bensong@google.comcd63fb52012-11-30 04:42:59 +000038# Further allow for a fixed amount of noise. This is especially useful for
39# benches of smaller absolute value. Keeping this value small will not affect
40# performance tunings.
41BENCH_ALLOWED_NOISE = 10
42
borenet@google.come6598a02013-04-30 12:02:32 +000043# Name prefix for benchmark builders.
44BENCH_BUILDER_PREFIX = 'Perf-'
45
bensong@google.com92b0f512013-02-06 20:51:55 +000046# List of platforms to track. Feel free to change it to meet your needs.
borenet@google.come6598a02013-04-30 12:02:32 +000047PLATFORMS = ['Perf-Mac10.8-MacMini4.1-GeForce320M-x86-Release',
48 'Perf-Android-Nexus7-Tegra3-Arm7-Release',
49 'Perf-Ubuntu12-ShuttleA-ATI5770-x86-Release',
50 'Perf-Win7-ShuttleA-HD2000-x86-Release',
bensong@google.comfa1d4ea2012-11-27 17:30:26 +000051 ]
52
53# Filter for configs of no interest. They are old config names replaced by more
54# specific ones.
55CONFIGS_TO_FILTER = ['gpu', 'raster']
56
57# Template for gsutil uri.
58GOOGLE_STORAGE_URI_SCHEME = 'gs'
59URI_BUCKET = 'chromium-skia-gm'
60
61# Constants for optparse.
62USAGE_STRING = 'USAGE: %s [options]'
63HOWTO_STRING = """
64Feel free to revise PLATFORMS for your own needs. The default is the most common
65combination that we care most about. Platforms that did not run bench_pictures
bensong@google.com29a159c2013-06-13 23:40:05 +000066or benchmain in the given revision range will not have corresponding outputs.
bensong@google.comfa1d4ea2012-11-27 17:30:26 +000067Please check http://go/skpbench to choose a range that fits your needs.
bensong@google.comcd63fb52012-11-30 04:42:59 +000068BENCH_UB, BENCH_LB and BENCH_ALLOWED_NOISE can be changed to expand or narrow
69the permitted bench ranges without triggering buidbot alerts.
bensong@google.comfa1d4ea2012-11-27 17:30:26 +000070"""
71HELP_STRING = """
72Outputs expectation picture bench ranges for the latest revisions for the given
73revision range. For instance, --rev_range=6000:6000 will return only bench
bensong@google.com29a159c2013-06-13 23:40:05 +000074ranges for the bots that ran benches at rev 6000; --rev-range=6000:7000
bensong@google.comfa1d4ea2012-11-27 17:30:26 +000075may have multiple bench data points for each bench configuration, and the code
76returns bench data for the latest revision of all available (closer to 7000).
77""" + HOWTO_STRING
78
79OPTION_REVISION_RANGE = '--rev-range'
80OPTION_REVISION_RANGE_SHORT = '-r'
bensong@google.com29a159c2013-06-13 23:40:05 +000081# Bench representation algorithm flag.
bensong@google.comfa1d4ea2012-11-27 17:30:26 +000082OPTION_REPRESENTATION_ALG = '--algorithm'
83OPTION_REPRESENTATION_ALG_SHORT = '-a'
bensong@google.com29a159c2013-06-13 23:40:05 +000084# Bench type to examine. Either 'micro' or 'skp'.
85OPTION_BENCH_TYPE = '--bench-type'
86OPTION_BENCH_TYPE_SHORT = '-b'
bensong@google.comfa1d4ea2012-11-27 17:30:26 +000087
bensong@google.com29a159c2013-06-13 23:40:05 +000088# List of valid bench types.
89BENCH_TYPES = ['micro', 'skp']
bensong@google.comfa1d4ea2012-11-27 17:30:26 +000090# List of valid representation algorithms.
91REPRESENTATION_ALGS = ['avg', 'min', 'med', '25th']
92
bensong@google.com29a159c2013-06-13 23:40:05 +000093def OutputBenchExpectations(bench_type, rev_min, rev_max, representation_alg):
94 """Reads bench data from google storage, and outputs expectations.
bensong@google.comfa1d4ea2012-11-27 17:30:26 +000095
96 Ignores data with revisions outside [rev_min, rev_max] integer range. For
97 bench data with multiple revisions, we use higher revisions to calculate
98 expected bench values.
bensong@google.com29a159c2013-06-13 23:40:05 +000099 bench_type is either 'micro' or 'skp', according to the flag '-b'.
bensong@google.comfa1d4ea2012-11-27 17:30:26 +0000100 Uses the provided representation_alg for calculating bench representations.
101 """
bensong@google.com29a159c2013-06-13 23:40:05 +0000102 if bench_type not in BENCH_TYPES:
103 raise Exception('Not valid bench_type! (%s)' % BENCH_TYPES)
bensong@google.comfa1d4ea2012-11-27 17:30:26 +0000104 expectation_dic = {}
105 uri = boto.storage_uri(URI_BUCKET, GOOGLE_STORAGE_URI_SCHEME)
106 for obj in uri.get_bucket():
bensong@google.com29a159c2013-06-13 23:40:05 +0000107 # Filters out non-bench files.
borenet@google.come6598a02013-04-30 12:02:32 +0000108 if ((not obj.name.startswith('perfdata/%s' % BENCH_BUILDER_PREFIX) and
109 not obj.name.startswith(
110 'playback/perfdata/%s' % BENCH_BUILDER_PREFIX)) or
bensong@google.com29a159c2013-06-13 23:40:05 +0000111 obj.name.find('_data') < 0):
112 continue
113 if ((bench_type == 'micro' and obj.name.find('_data_skp_') > 0) or
114 (bench_type == 'skp' and obj.name.find('_skp_') < 0)):
115 # Skips wrong bench type.
bensong@google.comfa1d4ea2012-11-27 17:30:26 +0000116 continue
117 # Ignores uninterested platforms.
bensong@google.com6184c972013-02-08 19:02:21 +0000118 platform = obj.name.split('/')[1]
borenet@google.come6598a02013-04-30 12:02:32 +0000119 if not platform.startswith(BENCH_BUILDER_PREFIX):
bensong@google.com6184c972013-02-08 19:02:21 +0000120 platform = obj.name.split('/')[2]
borenet@google.come6598a02013-04-30 12:02:32 +0000121 if not platform.startswith(BENCH_BUILDER_PREFIX):
bensong@google.com6184c972013-02-08 19:02:21 +0000122 continue # Ignores non-platform object
bensong@google.comfa1d4ea2012-11-27 17:30:26 +0000123 if platform not in PLATFORMS:
124 continue
125 # Filters by revision.
bensong@google.com92b0f512013-02-06 20:51:55 +0000126 to_filter = True
bensong@google.comfa1d4ea2012-11-27 17:30:26 +0000127 for rev in range(rev_min, rev_max + 1):
bensong@google.com92b0f512013-02-06 20:51:55 +0000128 if '_r%s_' % rev in obj.name:
129 to_filter = False
130 break
131 if to_filter:
132 continue
bensong@google.comfa1d4ea2012-11-27 17:30:26 +0000133 contents = cStringIO.StringIO()
134 obj.get_file(contents)
135 for point in bench_util.parse('', contents.getvalue().split('\n'),
136 representation_alg):
137 if point.config in CONFIGS_TO_FILTER:
138 continue
bensong@google.comfa1d4ea2012-11-27 17:30:26 +0000139
140 key = '%s_%s_%s,%s-%s' % (point.bench, point.config, point.time_type,
141 platform, representation_alg)
142 # It is fine to have later revisions overwrite earlier benches, since we
143 # only use the latest bench within revision range to set expectations.
144 expectation_dic[key] = point.time
145 keys = expectation_dic.keys()
146 keys.sort()
147 for key in keys:
148 bench_val = expectation_dic[key]
149 # Prints out expectation lines.
bensong@google.comcd63fb52012-11-30 04:42:59 +0000150 print '%s,%.3f,%.3f,%.3f' % (key, bench_val,
151 bench_val * BENCH_LB - BENCH_ALLOWED_NOISE,
152 bench_val * BENCH_UB + BENCH_ALLOWED_NOISE)
bensong@google.comfa1d4ea2012-11-27 17:30:26 +0000153
154def main():
bensong@google.com29a159c2013-06-13 23:40:05 +0000155 """Parses flags and outputs expected Skia bench results."""
bensong@google.comfa1d4ea2012-11-27 17:30:26 +0000156 parser = optparse.OptionParser(USAGE_STRING % '%prog' + HELP_STRING)
157 parser.add_option(OPTION_REVISION_RANGE_SHORT, OPTION_REVISION_RANGE,
158 dest='rev_range',
159 help='(Mandatory) revision range separated by ":", e.g., 6000:6005')
bensong@google.com29a159c2013-06-13 23:40:05 +0000160 parser.add_option(OPTION_BENCH_TYPE_SHORT, OPTION_BENCH_TYPE,
161 dest='bench_type', default='skp',
162 help=('Bench type, either "skp" or "micro". Default to "skp".'))
bensong@google.comfa1d4ea2012-11-27 17:30:26 +0000163 parser.add_option(OPTION_REPRESENTATION_ALG_SHORT, OPTION_REPRESENTATION_ALG,
164 dest='alg', default='25th',
165 help=('Bench representation algorithm. One of '
166 '%s. Default to "25th".' % str(REPRESENTATION_ALGS)))
167 (options, args) = parser.parse_args()
168 if options.rev_range:
169 range_match = re.search('(\d+)\:(\d+)', options.rev_range)
170 if not range_match:
171 parser.error('Wrong format for rev-range [%s]' % options.rev_range)
172 else:
173 rev_min = int(range_match.group(1))
174 rev_max = int(range_match.group(2))
bensong@google.com29a159c2013-06-13 23:40:05 +0000175 OutputBenchExpectations(options.bench_type, rev_min, rev_max, options.alg)
bensong@google.comfa1d4ea2012-11-27 17:30:26 +0000176 else:
177 parser.error('Please provide mandatory flag %s' % OPTION_REVISION_RANGE)
178
179
180if '__main__' == __name__:
181 main()