Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(251)

Side by Side Diff: tools/testing/perf_testing/run_perf_tests.py

Issue 10828077: Rerun each CL 10 times to smooth out noise in perf testing. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« tools/get_archive.py ('K') | « tools/testing/dart/drt_updater.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 2
3 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 3 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
4 # for details. All rights reserved. Use of this source code is governed by a 4 # for details. All rights reserved. Use of this source code is governed by a
5 # BSD-style license that can be found in the LICENSE file. 5 # BSD-style license that can be found in the LICENSE file.
6 6
7 import datetime 7 import datetime
8 import math 8 import math
9 try:
10 from matplotlib.font_manager import FontProperties
11 import matplotlib.pyplot as plt
12 except ImportError:
13 pass # Only needed if we want to make graphs.
14 import optparse 9 import optparse
15 import os 10 import os
16 from os.path import dirname, abspath 11 from os.path import dirname, abspath
17 import platform 12 import platform
18 import re 13 import re
19 import shutil 14 import shutil
20 import stat 15 import stat
21 import subprocess 16 import subprocess
22 import sys 17 import sys
23 import time 18 import time
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 if append: 55 if append:
61 mode = 'a' 56 mode = 'a'
62 out = open(outfile, mode) 57 out = open(outfile, mode)
63 if append: 58 if append:
64 # Annoying Windows "feature" -- append doesn't actually append unless 59 # Annoying Windows "feature" -- append doesn't actually append unless
65 # you explicitly go to the end of the file. 60 # you explicitly go to the end of the file.
66 # http://mail.python.org/pipermail/python-list/2009-October/1221859.html 61 # http://mail.python.org/pipermail/python-list/2009-October/1221859.html
67 out.seek(0, os.SEEK_END) 62 out.seek(0, os.SEEK_END)
68 p = subprocess.Popen(cmd_list, stdout = out, stderr=subprocess.PIPE, 63 p = subprocess.Popen(cmd_list, stdout = out, stderr=subprocess.PIPE,
69 stdin=subprocess.PIPE, shell=self.has_shell) 64 stdin=subprocess.PIPE, shell=self.has_shell)
70 output, stderr = p.communicate(std_in); 65 output, stderr = p.communicate(std_in)
71 if output: 66 if output:
72 print output 67 print output
73 if stderr: 68 if stderr:
74 print stderr 69 print stderr
75 return output 70 return output, stderr
76 71
77 def time_cmd(self, cmd): 72 def time_cmd(self, cmd):
78 """Determine the amount of (real) time it takes to execute a given 73 """Determine the amount of (real) time it takes to execute a given
79 command.""" 74 command."""
80 start = time.time() 75 start = time.time()
81 self.run_cmd(cmd) 76 self.run_cmd(cmd)
82 return time.time() - start 77 return time.time() - start
83 78
84 @staticmethod 79 def sync_and_build(self, suites, revision_num=''):
85 def get_build_targets(suites):
86 """Loop through a set of tests that we want to run and find the build
87 targets that are necessary.
88
89 Args:
90 suites: The test suites that we wish to run."""
91 build_targets = set()
92 for test in suites:
93 if test.build_targets is not None:
94 for target in test.build_targets:
95 build_targets.add(target)
96 return build_targets
97
98 def sync_and_build(self, suites):
99 """Make sure we have the latest version of of the repo, and build it. We 80 """Make sure we have the latest version of of the repo, and build it. We
100 begin and end standing in DART_INSTALL_LOCATION. 81 begin and end standing in DART_INSTALL_LOCATION.
101 82
102 Args: 83 Args:
103 suites: The set of suites that we wish to build. 84 suites: The set of suites that we wish to build.
104 85
105 Returns: 86 Returns:
106 err_code = 1 if there was a problem building.""" 87 err_code = 1 if there was a problem building."""
107 os.chdir(DART_INSTALL_LOCATION) 88 os.chdir(DART_INSTALL_LOCATION)
108 89
109 self.run_cmd(['gclient', 'sync']) 90 cmd = ['python', os.path.join(DART_INSTALL_LOCATION, 'tools',
110 91 'get_archive.py'), 'sdk']
111 # On Windows, the output directory is marked as "Read Only," which causes an 92 if revision_num != '':
112 # error to be thrown when we use shutil.rmtree. This helper function changes 93 cmd += ['-r', revision_num]
113 # the permissions so we can still delete the directory. 94 _, stderr = self.run_cmd(cmd)
114 def on_rm_error(func, path, exc_info): 95 if 'InvalidUriError' in stderr:
115 if os.path.exists(path): 96 return 1
116 os.chmod(path, stat.S_IWRITE) 97
117 os.unlink(path) 98 if revision_num == '':
118 # TODO(efortuna): building the sdk locally is a band-aid until all build 99 self.run_cmd(['gclient', 'sync'])
119 # platform SDKs are hosted in Google storage. Pull from https://sandbox. 100 else:
120 # google.com/storage/?arg=dart-dump-render-tree/sdk/#dart-dump-render-tree 101 self.run_cmd(['gclient', 'sync', '-r', revision_num, '-t'])
121 # %2Fsdk eventually.
122 # TODO(efortuna): Currently always building ia32 architecture because we
123 # don't have test statistics for what's passing on x64. Eliminate arch
124 # specification when we have tests running on x64, too.
125 shutil.rmtree(os.path.join(os.getcwd(),
126 utils.GetBuildRoot(utils.GuessOS(), 'release', 'ia32')),
127 onerror=on_rm_error)
128
129 for target in TestRunner.get_build_targets(suites):
130 lines = self.run_cmd([os.path.join('.', 'tools', 'build.py'), '-m',
131 'release', '--arch=ia32', target])
132
133 for line in lines:
134 if 'BUILD FAILED' in lines:
135 # Someone checked in a broken build! Stop trying to make it work
136 # and wait to try again.
137 print 'Broken Build'
138 return 1
139 return 0 102 return 0
140 103
141 def ensure_output_directory(self, dir_name): 104 def ensure_output_directory(self, dir_name):
142 """Test that the listed directory name exists, and if not, create one for 105 """Test that the listed directory name exists, and if not, create one for
143 our output to be placed. 106 our output to be placed.
144 107
145 Args: 108 Args:
146 dir_name: the directory we will create if it does not exist.""" 109 dir_name: the directory we will create if it does not exist."""
147 dir_path = os.path.join(DART_INSTALL_LOCATION, 'tools', 110 dir_path = os.path.join(DART_INSTALL_LOCATION, 'tools',
148 'testing', 'perf_testing', dir_name) 111 'testing', 'perf_testing', dir_name)
149 if not os.path.exists(dir_path): 112 if not os.path.exists(dir_path):
150 os.makedirs(dir_path) 113 os.makedirs(dir_path)
151 print 'Creating output directory ', dir_path 114 print 'Creating output directory ', dir_path
152 115
153 def has_new_code(self): 116 def has_new_code(self):
154 """Tests if there are any newer versions of files on the server.""" 117 """Tests if there are any newer versions of files on the server."""
155 os.chdir(DART_INSTALL_LOCATION) 118 os.chdir(DART_INSTALL_LOCATION)
156 # Pass 'p' in if we have a new certificate for the svn server, we want to 119 # Pass 'p' in if we have a new certificate for the svn server, we want to
157 # (p)ermanently accept it. 120 # (p)ermanently accept it.
158 results = self.run_cmd(['svn', 'st', '-u'], std_in='p\r\n') 121 results, _ = self.run_cmd(['svn', 'st', '-u'], std_in='p\r\n')
159 for line in results: 122 for line in results:
160 if '*' in line: 123 if '*' in line:
161 return True 124 return True
162 return False 125 return False
163 126
164 def get_os_directory(self): 127 def get_os_directory(self):
165 """Specifies the name of the directory for the testing build of dart, which 128 """Specifies the name of the directory for the testing build of dart, which
166 has yet a different naming convention from utils.getBuildRoot(...).""" 129 has yet a different naming convention from utils.getBuildRoot(...)."""
167 if platform.system() == 'Windows': 130 if platform.system() == 'Windows':
168 return 'windows' 131 return 'windows'
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 print ('Error: Invalid suite %s not in ' % name) + \ 167 print ('Error: Invalid suite %s not in ' % name) + \
205 '%s' % ','.join(TestBuilder.available_suite_names()) 168 '%s' % ','.join(TestBuilder.available_suite_names())
206 sys.exit(1) 169 sys.exit(1)
207 self.suite_names = suites 170 self.suite_names = suites
208 self.no_build = args.no_build 171 self.no_build = args.no_build
209 self.no_upload = args.no_upload 172 self.no_upload = args.no_upload
210 self.no_test = args.no_test 173 self.no_test = args.no_test
211 self.verbose = args.verbose 174 self.verbose = args.verbose
212 return args.continuous 175 return args.continuous
213 176
214 def run_test_sequence(self): 177 def run_test_sequence(self, revision_num='', num_reruns=1):
215 """Run the set of commands to (possibly) build, run, and graph the results 178 """Run the set of commands to (possibly) build, run, and post the results
216 of our tests. 179 of our tests. Returns true on a successful run.
217 """ 180 """
218 suites = [] 181 suites = []
182 success = True
219 for name in self.suite_names: 183 for name in self.suite_names:
220 suites += [TestBuilder.make_test(name, self)] 184 for run in range(num_reruns):
185 suites += [TestBuilder.make_test(name, self)]
221 186
222 if not self.no_build and self.sync_and_build(suites) == 1: 187 if not self.no_build and self.sync_and_build(suites, revision_num) == 1:
223 return # The build is broken. 188 return False # The build is broken.
224 189
225 for test in suites: 190 for test in suites:
226 test.run() 191 success = success and test.run()
192 return success
227 193
228 194
229 class Test(object): 195 class Test(object):
230 """The base class to provide shared code for different tests we will run and 196 """The base class to provide shared code for different tests we will run and
231 graph. At a high level, each test has three visitors (the tester, the 197 post. At a high level, each test has three visitors (the tester and the
232 file_processor and the grapher) that perform operations on the test object.""" 198 file_processor) that perform operations on the test object."""
233 199
234 def __init__(self, result_folder_name, platform_list, variants, 200 def __init__(self, result_folder_name, platform_list, variants,
235 values_list, test_runner, tester, file_processor, grapher, 201 values_list, test_runner, tester, file_processor,
236 extra_metrics=['Geo-Mean'], build_targets=['create_sdk']): 202 extra_metrics=['Geo-Mean']):
237 """Args: 203 """Args:
238 result_folder_name: The name of the folder where a tracefile of 204 result_folder_name: The name of the folder where a tracefile of
239 performance results will be stored. 205 performance results will be stored.
240 platform_list: A list containing the platform(s) that our data has been 206 platform_list: A list containing the platform(s) that our data has been
241 run on. (command line, firefox, chrome, etc) 207 run on. (command line, firefox, chrome, etc)
242 variants: A list specifying whether we hold data about Frog 208 variants: A list specifying whether we hold data about Frog
243 generated code, plain JS code, or a combination of both, or 209 generated code, plain JS code, or a combination of both, or
244 Dart depending on the test. 210 Dart depending on the test.
245 values_list: A list containing the type of data we will be graphing 211 values_list: A list containing the type of data we will be graphing
246 (benchmarks, percentage passing, etc). 212 (benchmarks, percentage passing, etc).
247 test_runner: Reference to the parent test runner object that notifies a 213 test_runner: Reference to the parent test runner object that notifies a
248 test when to run. 214 test when to run.
249 tester: The visitor that actually performs the test running mechanics. 215 tester: The visitor that actually performs the test running mechanics.
250 file_processor: The visitor that processes files in the format 216 file_processor: The visitor that processes files in the format
251 appropriate for this test. 217 appropriate for this test.
252 grapher: The visitor that generates graphs given our test result data.
253 extra_metrics: A list of any additional measurements we wish to keep 218 extra_metrics: A list of any additional measurements we wish to keep
254 track of (such as the geometric mean of a set, the sum, etc). 219 track of (such as the geometric mean of a set, the sum, etc)."""
255 build_targets: The targets necessary to build to run these tests
256 (default target is create_sdk)."""
257 self.result_folder_name = result_folder_name 220 self.result_folder_name = result_folder_name
258 # cur_time is used as a timestamp of when this performance test was run. 221 # cur_time is used as a timestamp of when this performance test was run.
259 self.cur_time = str(time.mktime(datetime.datetime.now().timetuple())) 222 self.cur_time = str(time.mktime(datetime.datetime.now().timetuple()))
260 self.values_list = values_list 223 self.values_list = values_list
261 self.platform_list = platform_list 224 self.platform_list = platform_list
262 self.test_runner = test_runner 225 self.test_runner = test_runner
263 self.tester = tester 226 self.tester = tester
264 self.file_processor = file_processor 227 self.file_processor = file_processor
265 self.build_targets = build_targets
266 self.revision_dict = dict() 228 self.revision_dict = dict()
267 self.values_dict = dict() 229 self.values_dict = dict()
268 self.grapher = grapher
269 self.extra_metrics = extra_metrics 230 self.extra_metrics = extra_metrics
270 # Initialize our values store. 231 # Initialize our values store.
271 for platform in platform_list: 232 for platform in platform_list:
272 self.revision_dict[platform] = dict() 233 self.revision_dict[platform] = dict()
273 self.values_dict[platform] = dict() 234 self.values_dict[platform] = dict()
274 for f in variants: 235 for f in variants:
275 self.revision_dict[platform][f] = dict() 236 self.revision_dict[platform][f] = dict()
276 self.values_dict[platform][f] = dict() 237 self.values_dict[platform][f] = dict()
277 for val in values_list: 238 for val in values_list:
278 self.revision_dict[platform][f][val] = [] 239 self.revision_dict[platform][f][val] = []
279 self.values_dict[platform][f][val] = [] 240 self.values_dict[platform][f][val] = []
280 for extra_metric in extra_metrics: 241 for extra_metric in extra_metrics:
281 self.revision_dict[platform][f][extra_metric] = [] 242 self.revision_dict[platform][f][extra_metric] = []
282 self.values_dict[platform][f][extra_metric] = [] 243 self.values_dict[platform][f][extra_metric] = []
283 244
284 def is_valid_combination(self, platform, variant): 245 def is_valid_combination(self, platform, variant):
285 """Check whether data should be captured for this platform/variant 246 """Check whether data should be captured for this platform/variant
286 combination. 247 combination.
287 """ 248 """
288 return True 249 return True
289 250
290 def run(self): 251 def run(self):
291 """Run the benchmarks/tests from the command line and plot the 252 """Run the benchmarks/tests from the command line and plot the
292 results. 253 results.
293 """ 254 """
294 for visitor in [self.tester, self.file_processor, self.grapher]: 255 for visitor in [self.tester, self.file_processor]:
295 visitor.prepare() 256 visitor.prepare()
296 257
297 os.chdir(DART_INSTALL_LOCATION) 258 os.chdir(DART_INSTALL_LOCATION)
298 self.test_runner.ensure_output_directory(self.result_folder_name) 259 self.test_runner.ensure_output_directory(self.result_folder_name)
299 self.test_runner.ensure_output_directory(os.path.join( 260 self.test_runner.ensure_output_directory(os.path.join(
300 'old', self.result_folder_name)) 261 'old', self.result_folder_name))
301 if not self.test_runner.no_test: 262 if not self.test_runner.no_test:
302 self.tester.run_tests() 263 self.tester.run_tests()
303 264
304 os.chdir(os.path.join('tools', 'testing', 'perf_testing')) 265 os.chdir(os.path.join('tools', 'testing', 'perf_testing'))
305 266
306 for afile in os.listdir(os.path.join('old', self.result_folder_name)): 267 for afile in os.listdir(os.path.join('old', self.result_folder_name)):
307 if not afile.startswith('.'): 268 if not afile.startswith('.'):
308 self.file_processor.process_file(afile, False) 269 self.file_processor.process_file(afile, False)
309 270
310 files = os.listdir(self.result_folder_name) 271 files = os.listdir(self.result_folder_name)
272 post_success = True
311 for afile in files: 273 for afile in files:
312 if not afile.startswith('.'): 274 if not afile.startswith('.'):
313 should_move_file = self.file_processor.process_file(afile, True) 275 should_move_file = self.file_processor.process_file(afile, True)
314 if should_move_file: 276 if should_move_file:
315 shutil.move(os.path.join(self.result_folder_name, afile), 277 shutil.move(os.path.join(self.result_folder_name, afile),
316 os.path.join('old', self.result_folder_name, afile)) 278 os.path.join('old', self.result_folder_name, afile))
279 else:
280 post_success = False
317 281
318 if 'plt' in globals(): 282 return post_success
319 # Only run Matplotlib if it is installed.
320 self.grapher.plot_results('%s.png' % self.result_folder_name)
321 283
322 284
323 class Tester(object): 285 class Tester(object):
324 """The base level visitor class that runs tests. It contains convenience 286 """The base level visitor class that runs tests. It contains convenience
325 methods that many Tester objects use. Any class that would like to be a 287 methods that many Tester objects use. Any class that would like to be a
326 TesterVisitor must implement the run_tests() method.""" 288 TesterVisitor must implement the run_tests() method."""
327 289
328 def __init__(self, test): 290 def __init__(self, test):
329 self.test = test 291 self.test = test
330 292
331 def prepare(self): 293 def prepare(self):
332 """Perform any initial setup required before the test is run.""" 294 """Perform any initial setup required before the test is run."""
333 pass 295 pass
334 296
335 def add_svn_revision_to_trace(self, outfile, browser = None): 297 def add_svn_revision_to_trace(self, outfile, browser = None):
336 """Add the svn version number to the provided tracefile.""" 298 """Add the svn version number to the provided tracefile."""
337 def search_for_revision(svn_info_command):
338 p = subprocess.Popen(svn_info_command, stdout = subprocess.PIPE,
339 stderr = subprocess.STDOUT, shell =
340 self.test.test_runner.has_shell)
341 output, _ = p.communicate()
342 for line in output.split('\n'):
343 if 'Revision' in line:
344 self.test.test_runner.run_cmd(['echo', line.strip()], outfile)
345 return True
346 return False
347
348 def get_dartium_revision(): 299 def get_dartium_revision():
349 version_file_name = os.path.join(DART_INSTALL_LOCATION, 'client', 'tests', 300 version_file_name = os.path.join(DART_INSTALL_LOCATION, 'client', 'tests',
350 'dartium', 'LAST_VERSION') 301 'dartium', 'LAST_VERSION')
351 version_file = open(version_file_name, 'r') 302 version_file = open(version_file_name, 'r')
352 version = version_file.read().split('.')[-2] 303 version = version_file.read().split('.')[-2]
353 version_file.close() 304 version_file.close()
354 return version 305 return version
355 306
356 if browser and browser == 'dartium': 307 if browser and browser == 'dartium':
357 revision = get_dartium_revision() 308 revision = get_dartium_revision()
358 self.test.test_runner.run_cmd(['echo', 'Revision: ' + revision], outfile) 309 self.test.test_runner.run_cmd(['echo', 'Revision: ' + revision], outfile)
359 elif not search_for_revision(['svn', 'info']): 310 else:
360 if not search_for_revision(['git', 'svn', 'info']): 311 revision = search_for_revision(['svn', 'info'])
361 self.test.test_runner.run_cmd(['echo', 'Revision: unknown'], outfile) 312 if revision == -1:
313 revision = search_for_revision(['git', 'svn', 'info'])
314 self.test.test_runner.run_cmd(['echo', 'Revision: ' + revision], outfile)
362 315
363 316
364 class Processor(object): 317 class Processor(object):
365 """The base level vistor class that processes tests. It contains convenience 318 """The base level vistor class that processes tests. It contains convenience
366 methods that many File Processor objects use. Any class that would like to be 319 methods that many File Processor objects use. Any class that would like to be
367 a ProcessorVisitor must implement the process_file() method.""" 320 a ProcessorVisitor must implement the process_file() method."""
368 321
369 SCORE = 'Score' 322 SCORE = 'Score'
370 COMPILE_TIME = 'CompileTime' 323 COMPILE_TIME = 'CompileTime'
371 CODE_SIZE = 'CodeSize' 324 CODE_SIZE = 'CodeSize'
(...skipping 30 matching lines...) Expand all
402 dartium). 355 dartium).
403 356
404 Returns: True if the post was successful file.""" 357 Returns: True if the post was successful file."""
405 return post_results.report_results(benchmark_name, score, platform, variant, 358 return post_results.report_results(benchmark_name, score, platform, variant,
406 revision_number, metric) 359 revision_number, metric)
407 360
408 def calculate_geometric_mean(self, platform, variant, svn_revision): 361 def calculate_geometric_mean(self, platform, variant, svn_revision):
409 """Calculate the aggregate geometric mean for JS and frog benchmark sets, 362 """Calculate the aggregate geometric mean for JS and frog benchmark sets,
410 given two benchmark dictionaries.""" 363 given two benchmark dictionaries."""
411 geo_mean = 0 364 geo_mean = 0
412 # TODO(vsm): Suppress graphing this combination altogether. For
413 # now, we feed a geomean of 0.
414 if self.test.is_valid_combination(platform, variant): 365 if self.test.is_valid_combination(platform, variant):
415 for benchmark in self.test.values_list: 366 for benchmark in self.test.values_list:
416 geo_mean += math.log( 367 geo_mean += math.log(
417 self.test.values_dict[platform][variant][benchmark][ 368 self.test.values_dict[platform][variant][benchmark][
418 len(self.test.values_dict[platform][variant][benchmark]) - 1]) 369 len(self.test.values_dict[platform][variant][benchmark]) - 1])
419 370
420 self.test.values_dict[platform][variant]['Geo-Mean'] += \ 371 self.test.values_dict[platform][variant]['Geo-Mean'] += \
421 [math.pow(math.e, geo_mean / len(self.test.values_list))] 372 [math.pow(math.e, geo_mean / len(self.test.values_list))]
422 self.test.revision_dict[platform][variant]['Geo-Mean'] += [svn_revision] 373 self.test.revision_dict[platform][variant]['Geo-Mean'] += [svn_revision]
423
424
425 class Grapher(object):
426 """The base level visitor class that generates graphs for data. It contains
427 convenience methods that many Grapher objects use. Any class that would like
428 to be a GrapherVisitor must implement the plot_results() method."""
429 374
430 graph_out_dir = 'graphs' 375 def get_score_type(self, benchmark_name):
376 """Determine the type of score for posting -- default is 'Score' (aka
377 Runtime), other options are CompileTime and CodeSize."""
378 return self.SCORE
431 379
432 def __init__(self, test):
433 self.color_index = 0
434 self.test = test
435
436 def prepare(self):
437 """Perform any initial setup required before the test is run."""
438 if 'plt' in globals():
439 plt.cla() # cla = clear current axes
440 else:
441 print 'Unable to import Matplotlib and therefore unable to generate ' + \
442 'graphs. Please install it for this version of Python.'
443 self.test.test_runner.ensure_output_directory(Grapher.graph_out_dir)
444
445 def style_and_save_perf_plot(self, chart_title, y_axis_label, size_x, size_y,
446 legend_loc, filename, platform_list, variants,
447 values_list, should_clear_axes=True):
448 """Sets style preferences for chart boilerplate that is consistent across
449 all charts, and saves the chart as a png.
450 Args:
451 size_x: the size of the printed chart, in inches, in the horizontal
452 direction
453 size_y: the size of the printed chart, in inches in the vertical direction
454 legend_loc: the location of the legend in on the chart. See suitable
455 arguments for the loc argument in matplotlib
456 filename: the filename that we want to save the resulting chart as
457 platform_list: a list containing the platform(s) that our data has been
458 run on. (command line, firefox, chrome, etc)
459 values_list: a list containing the type of data we will be graphing
460 (performance, percentage passing, etc)
461 should_clear_axes: True if we want to create a fresh graph, instead of
462 plotting additional lines on the current graph."""
463 if should_clear_axes:
464 plt.cla() # cla = clear current axes
465 for platform in platform_list:
466 for f in variants:
467 for val in values_list:
468 plt.plot(self.test.revision_dict[platform][f][val],
469 self.test.values_dict[platform][f][val],
470 color=self.get_color(), label='%s-%s-%s' % (platform, f, val))
471
472 plt.xlabel('Revision Number')
473 plt.ylabel(y_axis_label)
474 plt.title(chart_title)
475 fontP = FontProperties()
476 fontP.set_size('small')
477 plt.legend(loc=legend_loc, prop = fontP)
478
479 fig = plt.gcf()
480 fig.set_size_inches(size_x, size_y)
481 fig.savefig(os.path.join(Grapher.graph_out_dir, filename))
482
483 def get_color(self):
484 # Just a bunch of distinct colors for a potentially large number of values
485 # we wish to graph.
486 colors = [
487 'blue', 'green', 'red', 'cyan', 'magenta', 'black', '#3366CC',
488 '#DC3912', '#FF9900', '#109618', '#990099', '#0099C6', '#DD4477',
489 '#66AA00', '#B82E2E', '#316395', '#994499', '#22AA99', '#AAAA11',
490 '#6633CC', '#E67300', '#8B0707', '#651067', '#329262', '#5574A6',
491 '#3B3EAC', '#B77322', '#16D620', '#B91383', '#F4359E', '#9C5935',
492 '#A9C413', '#2A778D', '#668D1C', '#BEA413', '#0C5922', '#743411',
493 '#45AFE2', '#FF3300', '#FFCC00', '#14C21D', '#DF51FD', '#15CBFF',
494 '#FF97D2', '#97FB00', '#DB6651', '#518BC6', '#BD6CBD', '#35D7C2',
495 '#E9E91F', '#9877DD', '#FF8F20', '#D20B0B', '#B61DBA', '#40BD7E',
496 '#6AA7C4', '#6D70CD', '#DA9136', '#2DEA36', '#E81EA6', '#F558AE',
497 '#C07145', '#D7EE53', '#3EA7C6', '#97D129', '#E9CA1D', '#149638',
498 '#C5571D']
499 color = colors[self.color_index]
500 self.color_index = (self.color_index + 1) % len(colors)
501 return color
502 380
503 class RuntimePerformanceTest(Test): 381 class RuntimePerformanceTest(Test):
504 """Super class for all runtime performance testing.""" 382 """Super class for all runtime performance testing."""
505 383
506 def __init__(self, result_folder_name, platform_list, platform_type, 384 def __init__(self, result_folder_name, platform_list, platform_type,
507 versions, benchmarks, test_runner, tester, file_processor, 385 versions, benchmarks, test_runner, tester, file_processor):
508 build_targets=['create_sdk']):
509 """Args: 386 """Args:
510 result_folder_name: The name of the folder where a tracefile of 387 result_folder_name: The name of the folder where a tracefile of
511 performance results will be stored. 388 performance results will be stored.
512 platform_list: A list containing the platform(s) that our data has been 389 platform_list: A list containing the platform(s) that our data has been
513 run on. (command line, firefox, chrome, etc) 390 run on. (command line, firefox, chrome, etc)
514 variants: A list specifying whether we hold data about Frog 391 variants: A list specifying whether we hold data about Frog
515 generated code, plain JS code, or a combination of both, or 392 generated code, plain JS code, or a combination of both, or
516 Dart depending on the test. 393 Dart depending on the test.
517 values_list: A list containing the type of data we will be graphing 394 values_list: A list containing the type of data we will be graphing
518 (benchmarks, percentage passing, etc). 395 (benchmarks, percentage passing, etc).
519 test_runner: Reference to the parent test runner object that notifies a 396 test_runner: Reference to the parent test runner object that notifies a
520 test when to run. 397 test when to run.
521 tester: The visitor that actually performs the test running mechanics. 398 tester: The visitor that actually performs the test running mechanics.
522 file_processor: The visitor that processes files in the format 399 file_processor: The visitor that processes files in the format
523 appropriate for this test. 400 appropriate for this test.
524 grapher: The visitor that generates graphs given our test result data.
525 extra_metrics: A list of any additional measurements we wish to keep 401 extra_metrics: A list of any additional measurements we wish to keep
526 track of (such as the geometric mean of a set, the sum, etc). 402 track of (such as the geometric mean of a set, the sum, etc)."""
527 build_targets: The targets necessary to build to run these tests
528 (default target is create_sdk)."""
529 super(RuntimePerformanceTest, self).__init__(result_folder_name, 403 super(RuntimePerformanceTest, self).__init__(result_folder_name,
530 platform_list, versions, benchmarks, test_runner, tester, 404 platform_list, versions, benchmarks, test_runner, tester,
531 file_processor, RuntimePerfGrapher(self), 405 file_processor)
532 build_targets=build_targets)
533 self.platform_list = platform_list 406 self.platform_list = platform_list
534 self.platform_type = platform_type 407 self.platform_type = platform_type
535 self.versions = versions 408 self.versions = versions
536 self.benchmarks = benchmarks 409 self.benchmarks = benchmarks
537 410
538 class RuntimePerfGrapher(Grapher):
539 def plot_all_perf(self, png_filename):
540 """Create a plot that shows the performance changes of individual
541 benchmarks run by JS and generated by frog, over svn history."""
542 for benchmark in self.test.benchmarks:
543 self.style_and_save_perf_plot(
544 'Performance of %s over time on the %s on %s' % (benchmark,
545 self.test.platform_type, utils.GuessOS()),
546 'Speed (bigger = better)', 16, 14, 'lower left',
547 benchmark + png_filename, self.test.platform_list,
548 self.test.versions, [benchmark])
549
550 def plot_avg_perf(self, png_filename, platforms=None, versions=None):
551 """Generate a plot that shows the performance changes of the geomentric
552 mean of JS and frog benchmark performance over svn history."""
553 if platforms == None:
554 platforms = self.test.platform_list
555 if versions == None:
556 versions = self.test.versions
557 (title, y_axis, size_x, size_y, loc, filename) = \
558 ('Geometric Mean of benchmark %s performance on %s ' %
559 (self.test.platform_type, utils.GuessOS()), 'Speed (bigger = better)',
560 16, 5, 'lower left', 'avg'+png_filename)
561 clear_axis = True
562 for platform in platforms:
563 for version in versions:
564 if self.test.is_valid_combination(platform, version):
565 for metric in self.test.extra_metrics:
566 self.style_and_save_perf_plot(title, y_axis, size_x, size_y, loc,
567 filename, [platform], [version],
568 [metric], clear_axis)
569 clear_axis = False
570
571 def plot_results(self, png_filename):
572 self.plot_all_perf(png_filename)
573 self.plot_avg_perf('2' + png_filename)
574 411
575 class BrowserTester(Tester): 412 class BrowserTester(Tester):
576 @staticmethod 413 @staticmethod
577 def get_browsers(add_dartium=True): 414 def get_browsers(add_dartium=True):
578 browsers = ['ff', 'chrome'] 415 browsers = ['ff', 'chrome']
579 if add_dartium: 416 if add_dartium:
580 browsers += ['dartium'] 417 browsers += ['dartium']
581 has_shell = False 418 has_shell = False
582 if platform.system() == 'Darwin': 419 if platform.system() == 'Darwin':
583 browsers += ['safari'] 420 browsers += ['safari']
584 if platform.system() == 'Windows': 421 if platform.system() == 'Windows':
585 browsers += ['ie'] 422 browsers += ['ie']
586 has_shell = True 423 has_shell = True
587 if 'dartium' in browsers: 424 if 'dartium' in browsers:
588 # Fetch it if necessary. 425 # Fetch it if necessary.
589 get_dartium = ['python', 426 get_dartium = ['python',
590 os.path.join(DART_INSTALL_LOCATION, 'tools', 'get_drt.py'), 427 os.path.join(DART_INSTALL_LOCATION, 'tools',
591 '--dartium'] 428 'get_archive.py'), 'dartium']
592 # TODO(vsm): It's inconvenient that run_cmd isn't in scope here. 429 # TODO(vsm): It's inconvenient that run_cmd isn't in scope here.
593 # Perhaps there is a better place to put that or this. 430 # Perhaps there is a better place to put that or this.
594 subprocess.call(get_dartium, stdout=sys.stdout, stderr=sys.stderr, 431 subprocess.call(get_dartium, stdout=sys.stdout, stderr=sys.stderr,
595 shell=has_shell) 432 shell=has_shell)
596 return browsers 433 return browsers
597 434
598 435
599 class CommonBrowserTest(RuntimePerformanceTest): 436 class CommonBrowserTest(RuntimePerformanceTest):
600 """Runs this basic performance tests (Benchpress, some V8 benchmarks) in the 437 """Runs this basic performance tests (Benchpress, some V8 benchmarks) in the
601 browser.""" 438 browser."""
(...skipping 15 matching lines...) Expand all
617 @staticmethod 454 @staticmethod
618 def get_standalone_benchmarks(): 455 def get_standalone_benchmarks():
619 return ['Mandelbrot', 'DeltaBlue', 'Richards', 'NBody', 'BinaryTrees', 456 return ['Mandelbrot', 'DeltaBlue', 'Richards', 'NBody', 'BinaryTrees',
620 'Fannkuch', 'Meteor', 'BubbleSort', 'Fibonacci', 'Loop', 'Permute', 457 'Fannkuch', 'Meteor', 'BubbleSort', 'Fibonacci', 'Loop', 'Permute',
621 'Queens', 'QuickSort', 'Recurse', 'Sieve', 'Sum', 'Tak', 'Takl', 'Towers', 458 'Queens', 'QuickSort', 'Recurse', 'Sieve', 'Sum', 'Tak', 'Takl', 'Towers',
622 'TreeSort'] 459 'TreeSort']
623 460
624 class CommonBrowserTester(BrowserTester): 461 class CommonBrowserTester(BrowserTester):
625 def run_tests(self): 462 def run_tests(self):
626 """Run a performance test in the browser.""" 463 """Run a performance test in the browser."""
627 os.chdir('frog') 464 self.test.test_runner.run_cmd([
628 self.test.test_runner.run_cmd(['python', os.path.join('benchmarks', 465 'python', os.path.join('internal', 'browserBenchmarks',
629 'make_web_benchmarks.py')]) 466 'make_web_benchmarks.py')])
630 os.chdir('..')
631 467
632 for browser in self.test.platform_list: 468 for browser in self.test.platform_list:
633 for version in self.test.versions: 469 for version in self.test.versions:
634 if not self.test.is_valid_combination(browser, version): 470 if not self.test.is_valid_combination(browser, version):
635 continue 471 continue
636 self.test.trace_file = os.path.join( 472 self.test.trace_file = os.path.join(
637 'tools', 'testing', 'perf_testing', self.test.result_folder_name, 473 'tools', 'testing', 'perf_testing', self.test.result_folder_name,
638 'perf-%s-%s-%s' % (self.test.cur_time, browser, version)) 474 'perf-%s-%s-%s' % (self.test.cur_time, browser, version))
639 self.add_svn_revision_to_trace(self.test.trace_file, browser) 475 self.add_svn_revision_to_trace(self.test.trace_file, browser)
640 file_path = os.path.join( 476 file_path = os.path.join(
641 os.getcwd(), 'internal', 'browserBenchmarks', 477 os.getcwd(), 'internal', 'browserBenchmarks',
642 'benchmark_page_%s.html' % version) 478 'benchmark_page_%s.html' % version)
643 self.test.test_runner.run_cmd( 479 self.test.test_runner.run_cmd(
644 ['python', os.path.join('tools', 'testing', 'run_selenium.py'), 480 ['python', os.path.join('tools', 'testing', 'run_selenium.py'),
645 '--out', file_path, '--browser', browser, 481 '--out', file_path, '--browser', browser,
646 '--timeout', '600', '--mode', 'perf'], self.test.trace_file, 482 '--timeout', '600', '--mode', 'perf'], self.test.trace_file,
647 append=True) 483 append=True)
648 484
649 class CommonBrowserFileProcessor(Processor): 485 class CommonBrowserFileProcessor(Processor):
486
650 def process_file(self, afile, should_post_file): 487 def process_file(self, afile, should_post_file):
651 """Comb through the html to find the performance results. 488 """Comb through the html to find the performance results.
652 Returns: True if we successfully posted our data to storage and/or we can 489 Returns: True if we successfully posted our data to storage and/or we can
653 delete the trace file.""" 490 delete the trace file."""
654 os.chdir(os.path.join(DART_INSTALL_LOCATION, 'tools', 491 os.chdir(os.path.join(DART_INSTALL_LOCATION, 'tools',
655 'testing', 'perf_testing')) 492 'testing', 'perf_testing'))
656 parts = afile.split('-') 493 parts = afile.split('-')
657 browser = parts[2] 494 browser = parts[2]
658 version = parts[3] 495 version = parts[3]
659 f = self.open_trace_file(afile, should_post_file) 496 f = self.open_trace_file(afile, should_post_file)
(...skipping 27 matching lines...) Expand all
687 break 524 break
688 name = name_and_score[0].strip() 525 name = name_and_score[0].strip()
689 score = name_and_score[1].strip() 526 score = name_and_score[1].strip()
690 if version == 'js' or version == 'v8': 527 if version == 'js' or version == 'v8':
691 version = 'js' 528 version = 'js'
692 bench_dict = self.test.values_dict[browser][version] 529 bench_dict = self.test.values_dict[browser][version]
693 bench_dict[name] += [float(score)] 530 bench_dict[name] += [float(score)]
694 self.test.revision_dict[browser][version][name] += [revision_num] 531 self.test.revision_dict[browser][version][name] += [revision_num]
695 if not self.test.test_runner.no_upload and should_post_file: 532 if not self.test.test_runner.no_upload and should_post_file:
696 upload_success = upload_success and self.report_results( 533 upload_success = upload_success and self.report_results(
697 name, score, browser, version, revision_num, self.SCORE) 534 name, score, browser, version, revision_num,
535 self.get_score_type(name))
698 else: 536 else:
699 upload_success = False 537 upload_success = False
700 538
701 f.close() 539 f.close()
702 self.calculate_geometric_mean(browser, version, revision_num) 540 self.calculate_geometric_mean(browser, version, revision_num)
703 return upload_success 541 return upload_success
704 542
705 543
706 class DromaeoTester(Tester): 544 class DromaeoTester(Tester):
707 DROMAEO_BENCHMARKS = { 545 DROMAEO_BENCHMARKS = {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
771 @staticmethod 609 @staticmethod
772 def get_dromaeo_versions(): 610 def get_dromaeo_versions():
773 return ['js', 'frog_dom', 'frog_html', 'dart2js_dom', 'dart2js_html'] 611 return ['js', 'frog_dom', 'frog_html', 'dart2js_dom', 'dart2js_html']
774 612
775 613
776 class DromaeoTest(RuntimePerformanceTest): 614 class DromaeoTest(RuntimePerformanceTest):
777 """Runs Dromaeo tests, in the browser.""" 615 """Runs Dromaeo tests, in the browser."""
778 def __init__(self, test_runner): 616 def __init__(self, test_runner):
779 super(DromaeoTest, self).__init__( 617 super(DromaeoTest, self).__init__(
780 self.name(), 618 self.name(),
781 filter(lambda x: x != 'ie', BrowserTester.get_browsers()), 619 BrowserTester.get_browsers(),
782 'browser', 620 'browser',
783 DromaeoTester.get_dromaeo_versions(), 621 DromaeoTester.get_dromaeo_versions(),
784 DromaeoTester.get_dromaeo_benchmarks(), test_runner, 622 DromaeoTester.get_dromaeo_benchmarks(), test_runner,
785 self.DromaeoPerfTester(self), 623 self.DromaeoPerfTester(self),
786 self.DromaeoFileProcessor(self)) 624 self.DromaeoFileProcessor(self))
787 # TODO(vsm): These tester/grapher/processor classes should be
788 # cleaner to override.
789 self.grapher = self.DromaeoPerfGrapher(self)
790 625
791 @staticmethod 626 @staticmethod
792 def name(): 627 def name():
793 return 'dromaeo' 628 return 'dromaeo'
794 629
795 def is_valid_combination(self, browser, version): 630 def is_valid_combination(self, browser, version):
796 # TODO(vsm): This avoids a bug in 32-bit Chrome (dartium) 631 # TODO(vsm): This avoids a bug in 32-bit Chrome (dartium)
797 # running JS dromaeo. 632 # running JS dromaeo.
798 if browser == 'dartium' and version == 'js': 633 if browser == 'dartium' and version == 'js':
799 return False 634 return False
800 # dart:dom has been removed from Dartium. 635 # dart:dom has been removed from Dartium.
801 if browser == 'dartium' and 'dom' in version: 636 if browser == 'dartium' and 'dom' in version:
802 return False 637 return False
803 if browser == 'ff':
804 # TODO(vsm): We are waiting on a fix from Issue 3152 from dart2js.
805 return False
806 return True 638 return True
807 639
808 class DromaeoPerfGrapher(RuntimePerfGrapher):
809 def plot_results(self, png_filename):
810 self.plot_all_perf(png_filename)
811 self.plot_avg_perf('2' + png_filename)
812 self.plot_avg_perf('3' + png_filename, ['chrome', 'dartium'],
813 ['js', 'frog_dom', 'frog_html'])
814 self.plot_avg_perf('4' + png_filename, ['chrome'],
815 ['js', 'frog_dom', 'dart2js_dom'])
816 self.plot_avg_perf('5' + png_filename, ['chrome'],
817 ['js', 'dart2js_dom', 'dart2js_html'])
818 self.plot_avg_perf('6' + png_filename, ['chrome'],
819 ['js', 'frog_dom', 'frog_html', 'dart2js_dom',
820 'dart2js_html'])
821 640
822 class DromaeoPerfTester(DromaeoTester): 641 class DromaeoPerfTester(DromaeoTester):
823 def move_chrome_driver_if_needed(self, browser): 642 def move_chrome_driver_if_needed(self, browser):
824 """Move the appropriate version of ChromeDriver onto the path. 643 """Move the appropriate version of ChromeDriver onto the path.
825 TODO(efortuna): This is a total hack because the latest version of Chrome 644 TODO(efortuna): This is a total hack because the latest version of Chrome
826 (Dartium builds) requires a different version of ChromeDriver, that is 645 (Dartium builds) requires a different version of ChromeDriver, that is
827 incompatible with the release or beta Chrome and vice versa. Remove these 646 incompatible with the release or beta Chrome and vice versa. Remove these
828 shenanigans once we're back to both versions of Chrome using the same 647 shenanigans once we're back to both versions of Chrome using the same
829 version of ChromeDriver. IMPORTANT NOTE: This assumes your chromedriver is 648 version of ChromeDriver. IMPORTANT NOTE: This assumes your chromedriver is
830 in the default location (inside depot_tools). 649 in the default location (inside depot_tools).
831 """ 650 """
832 current_dir = os.getcwd() 651 current_dir = os.getcwd()
833 os.chdir(DART_INSTALL_LOCATION) 652 os.chdir(DART_INSTALL_LOCATION)
834 self.test.test_runner.run_cmd(['python', os.path.join( 653 self.test.test_runner.run_cmd(['python', os.path.join(
835 'tools', 'get_drt.py'), '--chromedriver']) 654 'tools', 'get_archive.py'), 'chromedriver'])
836 path = os.environ['PATH'].split(os.pathsep) 655 path = os.environ['PATH'].split(os.pathsep)
837 orig_chromedriver_path = os.path.join('tools', 'testing', 656 orig_chromedriver_path = os.path.join('tools', 'testing',
838 'orig-chromedriver') 657 'orig-chromedriver')
839 dartium_chromedriver_path = os.path.join('tools', 'testing', 658 dartium_chromedriver_path = os.path.join('tools', 'testing',
840 'dartium-chromedriver') 659 'dartium-chromedriver')
841 extension = '' 660 extension = ''
842 if platform.system() == 'Windows': 661 if platform.system() == 'Windows':
843 extension = '.exe' 662 extension = '.exe'
844 663
845 def move_chromedriver(depot_tools, copy_to_depot_tools_dir=True, 664 def move_chromedriver(depot_tools, copy_to_depot_tools_dir=True,
(...skipping 15 matching lines...) Expand all
861 shutil.copyfile(from_dir, to_dir) 680 shutil.copyfile(from_dir, to_dir)
862 681
863 for loc in path: 682 for loc in path:
864 if 'depot_tools' in loc: 683 if 'depot_tools' in loc:
865 if browser == 'chrome': 684 if browser == 'chrome':
866 if os.path.exists(orig_chromedriver_path): 685 if os.path.exists(orig_chromedriver_path):
867 move_chromedriver(loc) 686 move_chromedriver(loc)
868 elif browser == 'dartium': 687 elif browser == 'dartium':
869 if not os.path.exists(dartium_chromedriver_path): 688 if not os.path.exists(dartium_chromedriver_path):
870 self.test.test_runner.run_cmd(['python', 689 self.test.test_runner.run_cmd(['python',
871 os.path.join('tools', 'get_drt.py'), '--chromedriver']) 690 os.path.join('tools', 'get_archive.py'), 'chromedriver'])
872 # Move original chromedriver for storage. 691 # Move original chromedriver for storage.
873 if not os.path.exists(orig_chromedriver_path): 692 if not os.path.exists(orig_chromedriver_path):
874 move_chromedriver(loc, copy_to_depot_tools_dir=False) 693 move_chromedriver(loc, copy_to_depot_tools_dir=False)
875 # Copy Dartium chromedriver into depot_tools 694 # Copy Dartium chromedriver into depot_tools
876 move_chromedriver(loc, from_path=os.path.join( 695 move_chromedriver(loc, from_path=os.path.join(
877 dartium_chromedriver_path, 'chromedriver')) 696 dartium_chromedriver_path, 'chromedriver'))
878 os.chdir(current_dir) 697 os.chdir(current_dir)
879 698
880 def run_tests(self): 699 def run_tests(self):
881 """Run dromaeo in the browser.""" 700 """Run dromaeo in the browser."""
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
951 if results: 770 if results:
952 for result in results: 771 for result in results:
953 r = re.match(result_pattern, result) 772 r = re.match(result_pattern, result)
954 name = DromaeoTester.legalize_filename(r.group(1).strip(':')) 773 name = DromaeoTester.legalize_filename(r.group(1).strip(':'))
955 score = float(r.group(2)) 774 score = float(r.group(2))
956 bench_dict[name] += [float(score)] 775 bench_dict[name] += [float(score)]
957 self.test.revision_dict[browser][version][name] += \ 776 self.test.revision_dict[browser][version][name] += \
958 [revision_num] 777 [revision_num]
959 if not self.test.test_runner.no_upload and should_post_file: 778 if not self.test.test_runner.no_upload and should_post_file:
960 upload_success = upload_success and self.report_results( 779 upload_success = upload_success and self.report_results(
961 name, score, browser, version, revision_num, self.SCORE) 780 name, score, browser, version, revision_num,
781 self.get_score_type(name))
962 else: 782 else:
963 upload_success = False 783 upload_success = False
964 784
965 f.close() 785 f.close()
966 self.calculate_geometric_mean(browser, version, revision_num) 786 self.calculate_geometric_mean(browser, version, revision_num)
967 return upload_success 787 return upload_success
968 788
969 789
970 class DromaeoSizeTest(Test): 790 class DromaeoSizeTest(Test):
971 """Run tests to determine the compiled file output size of Dromaeo.""" 791 """Run tests to determine the compiled file output size of Dromaeo."""
972 def __init__(self, test_runner): 792 def __init__(self, test_runner):
973 super(DromaeoSizeTest, self).__init__( 793 super(DromaeoSizeTest, self).__init__(
974 self.name(), 794 self.name(),
975 ['commandline'], ['dart', 'frog_dom', 'frog_html', 795 ['commandline'], ['dart', 'frog_dom', 'frog_html',
976 'frog_htmlidiomatic'], 796 'frog_htmlidiomatic'],
977 DromaeoTester.DROMAEO_BENCHMARKS.keys(), test_runner, 797 DromaeoTester.DROMAEO_BENCHMARKS.keys(), test_runner,
978 self.DromaeoSizeTester(self), 798 self.DromaeoSizeTester(self),
979 self.DromaeoSizeProcessor(self), 799 self.DromaeoSizeProcessor(self), extra_metrics=['sum'])
980 self.DromaeoSizeGrapher(self), extra_metrics=['sum'])
981 800
982 @staticmethod 801 @staticmethod
983 def name(): 802 def name():
984 return 'dromaeo-size' 803 return 'dromaeo-size'
985 804
986 805
987 class DromaeoSizeTester(DromaeoTester): 806 class DromaeoSizeTester(DromaeoTester):
988 def run_tests(self): 807 def run_tests(self):
989 # Build tests. 808 # Build tests.
990 dromaeo_path = os.path.join('samples', 'third_party', 'dromaeo') 809 dromaeo_path = os.path.join('samples', 'third_party', 'dromaeo')
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
1078 if num.find('.') == -1: 897 if num.find('.') == -1:
1079 num = int(num) 898 num = int(num)
1080 else: 899 else:
1081 num = float(num) 900 num = float(num)
1082 self.test.values_dict['commandline'][variant][metric] += [num] 901 self.test.values_dict['commandline'][variant][metric] += [num]
1083 self.test.revision_dict['commandline'][variant][metric] += \ 902 self.test.revision_dict['commandline'][variant][metric] += \
1084 [revision_num] 903 [revision_num]
1085 if not self.test.test_runner.no_upload and should_post_file: 904 if not self.test.test_runner.no_upload and should_post_file:
1086 upload_success = upload_success and self.report_results( 905 upload_success = upload_success and self.report_results(
1087 metric, num, 'commandline', variant, revision_num, 906 metric, num, 'commandline', variant, revision_num,
1088 self.CODE_SIZE) 907 self.get_score_type(metric))
1089 else: 908 else:
1090 upload_success = False 909 upload_success = False
1091 910
1092 f.close() 911 f.close()
1093 return upload_success 912 return upload_success
913
914 def get_score_type(self, metric):
915 return self.CODE_SIZE
1094 916
1095 class DromaeoSizeGrapher(Grapher):
1096 def plot_results(self, png_filename):
1097 self.style_and_save_perf_plot(
1098 'Compiled Dromaeo Sizes',
1099 'Size (in bytes)', 10, 10, 'lower left', png_filename,
1100 ['commandline'],
1101 ['dart', 'frog_dom', 'frog_html', 'frog_htmlidiomatic'],
1102 DromaeoTester.DROMAEO_BENCHMARKS.keys())
1103
1104 self.style_and_save_perf_plot(
1105 'Compiled Dromaeo Sizes',
1106 'Size (in bytes)', 10, 10, 'lower left', '2' + png_filename,
1107 ['commandline'],
1108 ['dart', 'frog_dom', 'frog_html', 'frog_htmlidiomatic'],
1109 [self.test.extra_metrics[0]])
1110 917
1111 class CompileTimeAndSizeTest(Test): 918 class CompileTimeAndSizeTest(Test):
1112 """Run tests to determine how long frogc takes to compile, and the compiled 919 """Run tests to determine how long frogc takes to compile, and the compiled
1113 file output size of some benchmarking files. 920 file output size of some benchmarking files.
1114 Note: This test is now 'deprecated' since frog is no longer in the sdk. We 921 Note: This test is now 'deprecated' since frog is no longer in the sdk. We
1115 just return the last numbers found for frog.""" 922 just return the last numbers found for frog."""
1116 def __init__(self, test_runner): 923 def __init__(self, test_runner):
1117 """Reference to the test_runner object that notifies us when to begin 924 """Reference to the test_runner object that notifies us when to begin
1118 testing.""" 925 testing."""
1119 super(CompileTimeAndSizeTest, self).__init__( 926 super(CompileTimeAndSizeTest, self).__init__(
1120 self.name(), ['commandline'], ['frog'], ['swarm', 'total'], 927 self.name(), ['commandline'], ['frog'], ['swarm', 'total'],
1121 test_runner, self.CompileTester(self), 928 test_runner, self.CompileTester(self),
1122 self.CompileProcessor(self), self.CompileGrapher(self)) 929 self.CompileProcessor(self))
1123 self.dart_compiler = os.path.join( 930 self.dart_compiler = os.path.join(
1124 DART_INSTALL_LOCATION, utils.GetBuildRoot(utils.GuessOS(), 931 DART_INSTALL_LOCATION, utils.GetBuildRoot(utils.GuessOS(),
1125 'release', 'ia32'), 'dart-sdk', 'bin', 'frogc') 932 'release', 'ia32'), 'dart-sdk', 'bin', 'frogc')
1126 _suffix = '' 933 _suffix = ''
1127 if platform.system() == 'Windows': 934 if platform.system() == 'Windows':
1128 _suffix = '.exe' 935 _suffix = '.exe'
1129 self.dart_vm = os.path.join( 936 self.dart_vm = os.path.join(
1130 DART_INSTALL_LOCATION, utils.GetBuildRoot(utils.GuessOS(), 937 DART_INSTALL_LOCATION, utils.GetBuildRoot(utils.GuessOS(),
1131 'release', 'ia32'), 'dart-sdk', 'bin','dart' + _suffix) 938 'release', 'ia32'), 'dart-sdk', 'bin','dart' + _suffix)
1132 self.failure_threshold = {'swarm' : 100, 'total' : 100} 939 self.failure_threshold = {'swarm' : 100, 'total' : 100}
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
1190 for metric in self.test.values_list: 997 for metric in self.test.values_list:
1191 if metric in line: 998 if metric in line:
1192 num = tokens[0] 999 num = tokens[0]
1193 if num.find('.') == -1: 1000 if num.find('.') == -1:
1194 num = int(num) 1001 num = int(num)
1195 else: 1002 else:
1196 num = float(num) 1003 num = float(num)
1197 self.test.values_dict['commandline']['frog'][metric] += [num] 1004 self.test.values_dict['commandline']['frog'][metric] += [num]
1198 self.test.revision_dict['commandline']['frog'][metric] += \ 1005 self.test.revision_dict['commandline']['frog'][metric] += \
1199 [revision_num] 1006 [revision_num]
1200 score_type = self.CODE_SIZE 1007 score_type = self.get_score_type(metric)
1201 if 'Compiling' in metric or 'Bootstrapping' in metric:
1202 score_type = self.COMPILE_TIME
1203 if not self.test.test_runner.no_upload and should_post_file: 1008 if not self.test.test_runner.no_upload and should_post_file:
1204 if num < self.test.failure_threshold[metric]: 1009 if num < self.test.failure_threshold[metric]:
1205 num = 0 1010 num = 0
1206 upload_success = upload_success and self.report_results( 1011 upload_success = upload_success and self.report_results(
1207 metric, num, 'commandline', 'frog', revision_num, 1012 metric, num, 'commandline', 'frog', revision_num,
1208 score_type) 1013 score_type)
1209 else: 1014 else:
1210 upload_success = False 1015 upload_success = False
1211 if revision_num != 0: 1016 if revision_num != 0:
1212 for metric in self.test.values_list: 1017 for metric in self.test.values_list:
1213 try: 1018 try:
1214 self.test.revision_dict['commandline']['frog'][metric].pop() 1019 self.test.revision_dict['commandline']['frog'][metric].pop()
1215 self.test.revision_dict['commandline']['frog'][metric] += \ 1020 self.test.revision_dict['commandline']['frog'][metric] += \
1216 [revision_num] 1021 [revision_num]
1217 # Fill in 0 if compilation failed. 1022 # Fill in 0 if compilation failed.
1218 if self.test.values_dict['commandline']['frog'][metric][-1] < \ 1023 if self.test.values_dict['commandline']['frog'][metric][-1] < \
1219 self.test.failure_threshold[metric]: 1024 self.test.failure_threshold[metric]:
1220 self.test.values_dict['commandline']['frog'][metric] += [0] 1025 self.test.values_dict['commandline']['frog'][metric] += [0]
1221 self.test.revision_dict['commandline']['frog'][metric] += \ 1026 self.test.revision_dict['commandline']['frog'][metric] += \
1222 [revision_num] 1027 [revision_num]
1223 except IndexError: 1028 except IndexError:
1224 # We tried to pop from an empty list. This happens if the first 1029 # We tried to pop from an empty list. This happens if the first
1225 # trace file we encounter is incomplete. 1030 # trace file we encounter is incomplete.
1226 pass 1031 pass
1227 1032
1228 f.close() 1033 f.close()
1229 return upload_success 1034 return upload_success
1230 1035
1231 class CompileGrapher(Grapher): 1036 def get_score_type(self, metric):
1232 1037 if 'Compiling' in metric or 'Bootstrapping' in metric:
1233 def plot_results(self, png_filename):» » 1038 return self.COMPILE_TIME
1234 self.style_and_save_perf_plot(» » 1039 return self.CODE_SIZE
1235 'Compiled frog sizes', 'Size (in bytes)', 10, 10, 'lower left',
1236 png_filename, ['commandline'], ['frog'], ['swarm', 'total'])
1237 » »
1238 1040
1239 class TestBuilder(object): 1041 class TestBuilder(object):
1240 """Construct the desired test object.""" 1042 """Construct the desired test object."""
1241 available_suites = dict((suite.name(), suite) for suite in [ 1043 available_suites = dict((suite.name(), suite) for suite in [
1242 CompileTimeAndSizeTest, CommonBrowserTest, DromaeoTest, DromaeoSizeTest]) 1044 CompileTimeAndSizeTest, CommonBrowserTest, DromaeoTest, DromaeoSizeTest])
1243 1045
1244 @staticmethod 1046 @staticmethod
1245 def make_test(test_name, test_runner): 1047 def make_test(test_name, test_runner):
1246 return TestBuilder.available_suites[test_name](test_runner) 1048 return TestBuilder.available_suites[test_name](test_runner)
1247 1049
1248 @staticmethod 1050 @staticmethod
1249 def available_suite_names(): 1051 def available_suite_names():
1250 return TestBuilder.available_suites.keys() 1052 return TestBuilder.available_suites.keys()
1251 1053
1054 def search_for_revision(svn_info_command):
1055 p = subprocess.Popen(svn_info_command, stdout = subprocess.PIPE,
1056 stderr = subprocess.STDOUT,
1057 shell = (platform.system() == 'Windows'))
1058 output, _ = p.communicate()
1059 for line in output.split('\n'):
1060 if 'Revision' in line:
1061 return line.split()[1]
1062 return -1
1252 1063
1253 def main(): 1064 def main():
1254 runner = TestRunner() 1065 runner = TestRunner()
1255 continuous = runner.parse_args() 1066 continuous = runner.parse_args()
1256 if continuous: 1067 if continuous:
1257 while True: 1068 while True:
1258 if runner.has_new_code(): 1069 if runner.has_new_code():
1259 runner.run_test_sequence() 1070 runner.run_test_sequence()
1260 else: 1071 else:
1072 # Try to get up to 10 runs of each CL, starting with the most recent.
1073 # But only perform these extra runs at most 10 at a time (get all the
1074 # extra runs for one CL) before checking again to see if new code has
1075 # been checked in.
vsm 2012/07/30 23:22:05 Isn't this going to run (some) CLs well more than
vsm 2012/07/30 23:27:53 Nevermind. I see what I missed. Perhaps a commen
Emily Fortuna 2012/07/31 20:16:20 Clarified (hopefully).
1076 has_run_extra = False
1077 revision_num = int(search_for_revision(['svn', 'info']))
1078 if revision_num == -1:
1079 revision_num = int(search_for_revision(['git', 'svn', 'info']))
1080
1081 # No need to track the performance before revision 3000. That's way in
1082 # the past.
1083 while revision_num > 3000 and not has_run_extra:
1084 a_test = TestBuilder.make_test(runner.suite_names[0], runner)
1085 benchmark_name = a_test.values_list[0]
1086 platform_name = a_test.platform_list[0]
1087 variant = a_test.values_dict[platform_name].keys()[0]
1088 successful_build = True
1089 number_of_results = post_results.get_num_results(benchmark_name,
1090 platform_name, variant, revision_num,
1091 a_test.file_processor.get_score_type(benchmark_name))
vsm 2012/07/30 23:27:53 Not sure if perf is a concern, but consider cachin
Emily Fortuna 2012/07/31 20:16:20 That's a good idea. I'll change my code to do that
1092 while number_of_results < 10 and number_of_results >= 0 \
1093 and successful_build:
1094 successful_build = (
1095 runner.run_test_sequence(revision_num=str(revision_num)))
1096 if successful_build:
1097 has_run_extra = True
1098 revision_num -= 1
1099 # No more extra back-runs to do (for now). Wait for new code.
1261 time.sleep(200) 1100 time.sleep(200)
1262 else: 1101 else:
1263 runner.run_test_sequence() 1102 runner.run_test_sequence()
1264 1103
1265 if __name__ == '__main__': 1104 if __name__ == '__main__':
1266 main() 1105 main()
OLDNEW
« tools/get_archive.py ('K') | « tools/testing/dart/drt_updater.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698