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

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
« no previous file with comments | « 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
12 import pickle
17 import platform 13 import platform
18 import re 14 import re
19 import shutil 15 import shutil
20 import stat 16 import stat
21 import subprocess 17 import subprocess
22 import sys 18 import sys
23 import time 19 import time
24 20
25 TOOLS_PATH = os.path.join(dirname(dirname(dirname(abspath(__file__))))) 21 TOOLS_PATH = os.path.join(dirname(dirname(dirname(abspath(__file__)))))
26 DART_INSTALL_LOCATION = abspath(os.path.join(dirname(abspath(__file__)), 22 DART_INSTALL_LOCATION = abspath(os.path.join(dirname(abspath(__file__)),
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 if append: 56 if append:
61 mode = 'a' 57 mode = 'a'
62 out = open(outfile, mode) 58 out = open(outfile, mode)
63 if append: 59 if append:
64 # Annoying Windows "feature" -- append doesn't actually append unless 60 # Annoying Windows "feature" -- append doesn't actually append unless
65 # you explicitly go to the end of the file. 61 # you explicitly go to the end of the file.
66 # http://mail.python.org/pipermail/python-list/2009-October/1221859.html 62 # http://mail.python.org/pipermail/python-list/2009-October/1221859.html
67 out.seek(0, os.SEEK_END) 63 out.seek(0, os.SEEK_END)
68 p = subprocess.Popen(cmd_list, stdout = out, stderr=subprocess.PIPE, 64 p = subprocess.Popen(cmd_list, stdout = out, stderr=subprocess.PIPE,
69 stdin=subprocess.PIPE, shell=self.has_shell) 65 stdin=subprocess.PIPE, shell=self.has_shell)
70 output, stderr = p.communicate(std_in); 66 output, stderr = p.communicate(std_in)
71 if output: 67 if output:
72 print output 68 print output
73 if stderr: 69 if stderr:
74 print stderr 70 print stderr
75 return output 71 return output, stderr
76 72
77 def time_cmd(self, cmd): 73 def time_cmd(self, cmd):
78 """Determine the amount of (real) time it takes to execute a given 74 """Determine the amount of (real) time it takes to execute a given
79 command.""" 75 command."""
80 start = time.time() 76 start = time.time()
81 self.run_cmd(cmd) 77 self.run_cmd(cmd)
82 return time.time() - start 78 return time.time() - start
83 79
84 @staticmethod 80 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 81 """Make sure we have the latest version of of the repo, and build it. We
100 begin and end standing in DART_INSTALL_LOCATION. 82 begin and end standing in DART_INSTALL_LOCATION.
101 83
102 Args: 84 Args:
103 suites: The set of suites that we wish to build. 85 suites: The set of suites that we wish to build.
104 86
105 Returns: 87 Returns:
106 err_code = 1 if there was a problem building.""" 88 err_code = 1 if there was a problem building."""
107 os.chdir(DART_INSTALL_LOCATION) 89 os.chdir(DART_INSTALL_LOCATION)
90
91 if revision_num == '':
92 self.run_cmd(['gclient', 'sync'])
93 else:
94 self.run_cmd(['gclient', 'sync', '-r', revision_num, '-t'])
108 95
109 self.run_cmd(['gclient', 'sync']) 96 if revision_num == '':
110 97 revision_num = search_for_revision(['svn', 'info'])
111 # On Windows, the output directory is marked as "Read Only," which causes an 98 if revision_num == -1:
112 # error to be thrown when we use shutil.rmtree. This helper function changes 99 revision_num = search_for_revision(['git', 'svn', 'info'])
113 # the permissions so we can still delete the directory. 100 _, stderr = self.run_cmd(['python', os.path.join(DART_INSTALL_LOCATION,
114 def on_rm_error(func, path, exc_info): 101 'tools', 'get_archive.py'), 'sdk', '-r', revision_num])
115 if os.path.exists(path): 102 if 'InvalidUriError' in stderr:
116 os.chmod(path, stat.S_IWRITE) 103 return 1
117 os.unlink(path)
118 # TODO(efortuna): building the sdk locally is a band-aid until all build
119 # platform SDKs are hosted in Google storage. Pull from https://sandbox.
120 # google.com/storage/?arg=dart-dump-render-tree/sdk/#dart-dump-render-tree
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 104 return 0
140 105
141 def ensure_output_directory(self, dir_name): 106 def ensure_output_directory(self, dir_name):
142 """Test that the listed directory name exists, and if not, create one for 107 """Test that the listed directory name exists, and if not, create one for
143 our output to be placed. 108 our output to be placed.
144 109
145 Args: 110 Args:
146 dir_name: the directory we will create if it does not exist.""" 111 dir_name: the directory we will create if it does not exist."""
147 dir_path = os.path.join(DART_INSTALL_LOCATION, 'tools', 112 dir_path = os.path.join(DART_INSTALL_LOCATION, 'tools',
148 'testing', 'perf_testing', dir_name) 113 'testing', 'perf_testing', dir_name)
149 if not os.path.exists(dir_path): 114 if not os.path.exists(dir_path):
150 os.makedirs(dir_path) 115 os.makedirs(dir_path)
151 print 'Creating output directory ', dir_path 116 print 'Creating output directory ', dir_path
152 117
153 def has_new_code(self): 118 def has_new_code(self):
154 """Tests if there are any newer versions of files on the server.""" 119 """Tests if there are any newer versions of files on the server."""
155 os.chdir(DART_INSTALL_LOCATION) 120 os.chdir(DART_INSTALL_LOCATION)
156 # Pass 'p' in if we have a new certificate for the svn server, we want to 121 # Pass 'p' in if we have a new certificate for the svn server, we want to
157 # (p)ermanently accept it. 122 # (p)ermanently accept it.
158 results = self.run_cmd(['svn', 'st', '-u'], std_in='p\r\n') 123 results, _ = self.run_cmd(['svn', 'st', '-u'], std_in='p\r\n')
159 for line in results: 124 for line in results:
160 if '*' in line: 125 if '*' in line:
161 return True 126 return True
162 return False 127 return False
163 128
164 def get_os_directory(self): 129 def get_os_directory(self):
165 """Specifies the name of the directory for the testing build of dart, which 130 """Specifies the name of the directory for the testing build of dart, which
166 has yet a different naming convention from utils.getBuildRoot(...).""" 131 has yet a different naming convention from utils.getBuildRoot(...)."""
167 if platform.system() == 'Windows': 132 if platform.system() == 'Windows':
168 return 'windows' 133 return 'windows'
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 print ('Error: Invalid suite %s not in ' % name) + \ 169 print ('Error: Invalid suite %s not in ' % name) + \
205 '%s' % ','.join(TestBuilder.available_suite_names()) 170 '%s' % ','.join(TestBuilder.available_suite_names())
206 sys.exit(1) 171 sys.exit(1)
207 self.suite_names = suites 172 self.suite_names = suites
208 self.no_build = args.no_build 173 self.no_build = args.no_build
209 self.no_upload = args.no_upload 174 self.no_upload = args.no_upload
210 self.no_test = args.no_test 175 self.no_test = args.no_test
211 self.verbose = args.verbose 176 self.verbose = args.verbose
212 return args.continuous 177 return args.continuous
213 178
214 def run_test_sequence(self): 179 def run_test_sequence(self, revision_num='', num_reruns=1):
215 """Run the set of commands to (possibly) build, run, and graph the results 180 """Run the set of commands to (possibly) build, run, and post the results
216 of our tests. 181 of our tests. Returns 0 on a successful run, 1 if we fail to post results or
182 the run failed, -1 if the build is broken.
217 """ 183 """
218 suites = [] 184 suites = []
185 success = True
219 for name in self.suite_names: 186 for name in self.suite_names:
220 suites += [TestBuilder.make_test(name, self)] 187 for run in range(num_reruns):
188 suites += [TestBuilder.make_test(name, self)]
221 189
222 if not self.no_build and self.sync_and_build(suites) == 1: 190 if not self.no_build and self.sync_and_build(suites, revision_num) == 1:
223 return # The build is broken. 191 return -1 # The build is broken.
224 192
225 for test in suites: 193 for test in suites:
226 test.run() 194 success = success and test.run()
195 if success:
196 return 0
197 else:
198 return 1
227 199
228 200
229 class Test(object): 201 class Test(object):
230 """The base class to provide shared code for different tests we will run and 202 """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 203 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.""" 204 file_processor) that perform operations on the test object."""
233 205
234 def __init__(self, result_folder_name, platform_list, variants, 206 def __init__(self, result_folder_name, platform_list, variants,
235 values_list, test_runner, tester, file_processor, grapher, 207 values_list, test_runner, tester, file_processor,
236 extra_metrics=['Geo-Mean'], build_targets=['create_sdk']): 208 extra_metrics=['Geo-Mean']):
237 """Args: 209 """Args:
238 result_folder_name: The name of the folder where a tracefile of 210 result_folder_name: The name of the folder where a tracefile of
239 performance results will be stored. 211 performance results will be stored.
240 platform_list: A list containing the platform(s) that our data has been 212 platform_list: A list containing the platform(s) that our data has been
241 run on. (command line, firefox, chrome, etc) 213 run on. (command line, firefox, chrome, etc)
242 variants: A list specifying whether we hold data about Frog 214 variants: A list specifying whether we hold data about Frog
243 generated code, plain JS code, or a combination of both, or 215 generated code, plain JS code, or a combination of both, or
244 Dart depending on the test. 216 Dart depending on the test.
245 values_list: A list containing the type of data we will be graphing 217 values_list: A list containing the type of data we will be graphing
246 (benchmarks, percentage passing, etc). 218 (benchmarks, percentage passing, etc).
247 test_runner: Reference to the parent test runner object that notifies a 219 test_runner: Reference to the parent test runner object that notifies a
248 test when to run. 220 test when to run.
249 tester: The visitor that actually performs the test running mechanics. 221 tester: The visitor that actually performs the test running mechanics.
250 file_processor: The visitor that processes files in the format 222 file_processor: The visitor that processes files in the format
251 appropriate for this test. 223 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 224 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). 225 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 226 self.result_folder_name = result_folder_name
258 # cur_time is used as a timestamp of when this performance test was run. 227 # 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())) 228 self.cur_time = str(time.mktime(datetime.datetime.now().timetuple()))
260 self.values_list = values_list 229 self.values_list = values_list
261 self.platform_list = platform_list 230 self.platform_list = platform_list
262 self.test_runner = test_runner 231 self.test_runner = test_runner
263 self.tester = tester 232 self.tester = tester
264 self.file_processor = file_processor 233 self.file_processor = file_processor
265 self.build_targets = build_targets
266 self.revision_dict = dict() 234 self.revision_dict = dict()
267 self.values_dict = dict() 235 self.values_dict = dict()
268 self.grapher = grapher
269 self.extra_metrics = extra_metrics 236 self.extra_metrics = extra_metrics
270 # Initialize our values store. 237 # Initialize our values store.
271 for platform in platform_list: 238 for platform in platform_list:
272 self.revision_dict[platform] = dict() 239 self.revision_dict[platform] = dict()
273 self.values_dict[platform] = dict() 240 self.values_dict[platform] = dict()
274 for f in variants: 241 for f in variants:
275 self.revision_dict[platform][f] = dict() 242 self.revision_dict[platform][f] = dict()
276 self.values_dict[platform][f] = dict() 243 self.values_dict[platform][f] = dict()
277 for val in values_list: 244 for val in values_list:
278 self.revision_dict[platform][f][val] = [] 245 self.revision_dict[platform][f][val] = []
279 self.values_dict[platform][f][val] = [] 246 self.values_dict[platform][f][val] = []
280 for extra_metric in extra_metrics: 247 for extra_metric in extra_metrics:
281 self.revision_dict[platform][f][extra_metric] = [] 248 self.revision_dict[platform][f][extra_metric] = []
282 self.values_dict[platform][f][extra_metric] = [] 249 self.values_dict[platform][f][extra_metric] = []
283 250
284 def is_valid_combination(self, platform, variant): 251 def is_valid_combination(self, platform, variant):
285 """Check whether data should be captured for this platform/variant 252 """Check whether data should be captured for this platform/variant
286 combination. 253 combination.
287 """ 254 """
288 return True 255 return True
289 256
290 def run(self): 257 def run(self):
291 """Run the benchmarks/tests from the command line and plot the 258 """Run the benchmarks/tests from the command line and plot the
292 results. 259 results.
293 """ 260 """
294 for visitor in [self.tester, self.file_processor, self.grapher]: 261 for visitor in [self.tester, self.file_processor]:
295 visitor.prepare() 262 visitor.prepare()
296 263
297 os.chdir(DART_INSTALL_LOCATION) 264 os.chdir(DART_INSTALL_LOCATION)
298 self.test_runner.ensure_output_directory(self.result_folder_name) 265 self.test_runner.ensure_output_directory(self.result_folder_name)
299 self.test_runner.ensure_output_directory(os.path.join( 266 self.test_runner.ensure_output_directory(os.path.join(
300 'old', self.result_folder_name)) 267 'old', self.result_folder_name))
301 if not self.test_runner.no_test: 268 if not self.test_runner.no_test:
302 self.tester.run_tests() 269 self.tester.run_tests()
303 270
304 os.chdir(os.path.join('tools', 'testing', 'perf_testing')) 271 os.chdir(os.path.join('tools', 'testing', 'perf_testing'))
305 272
306 for afile in os.listdir(os.path.join('old', self.result_folder_name)): 273 for afile in os.listdir(os.path.join('old', self.result_folder_name)):
307 if not afile.startswith('.'): 274 if not afile.startswith('.'):
308 self.file_processor.process_file(afile, False) 275 self.file_processor.process_file(afile, False)
309 276
310 files = os.listdir(self.result_folder_name) 277 files = os.listdir(self.result_folder_name)
278 post_success = True
311 for afile in files: 279 for afile in files:
312 if not afile.startswith('.'): 280 if not afile.startswith('.'):
313 should_move_file = self.file_processor.process_file(afile, True) 281 should_move_file = self.file_processor.process_file(afile, True)
314 if should_move_file: 282 if should_move_file:
315 shutil.move(os.path.join(self.result_folder_name, afile), 283 shutil.move(os.path.join(self.result_folder_name, afile),
316 os.path.join('old', self.result_folder_name, afile)) 284 os.path.join('old', self.result_folder_name, afile))
285 else:
286 post_success = False
317 287
318 if 'plt' in globals(): 288 return post_success
319 # Only run Matplotlib if it is installed.
320 self.grapher.plot_results('%s.png' % self.result_folder_name)
321 289
322 290
323 class Tester(object): 291 class Tester(object):
324 """The base level visitor class that runs tests. It contains convenience 292 """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 293 methods that many Tester objects use. Any class that would like to be a
326 TesterVisitor must implement the run_tests() method.""" 294 TesterVisitor must implement the run_tests() method."""
327 295
328 def __init__(self, test): 296 def __init__(self, test):
329 self.test = test 297 self.test = test
330 298
331 def prepare(self): 299 def prepare(self):
332 """Perform any initial setup required before the test is run.""" 300 """Perform any initial setup required before the test is run."""
333 pass 301 pass
334 302
335 def add_svn_revision_to_trace(self, outfile, browser = None): 303 def add_svn_revision_to_trace(self, outfile, browser = None):
336 """Add the svn version number to the provided tracefile.""" 304 """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(): 305 def get_dartium_revision():
349 version_file_name = os.path.join(DART_INSTALL_LOCATION, 'client', 'tests', 306 version_file_name = os.path.join(DART_INSTALL_LOCATION, 'client', 'tests',
350 'dartium', 'LAST_VERSION') 307 'dartium', 'LAST_VERSION')
351 version_file = open(version_file_name, 'r') 308 version_file = open(version_file_name, 'r')
352 version = version_file.read().split('.')[-2] 309 version = version_file.read().split('.')[-2]
353 version_file.close() 310 version_file.close()
354 return version 311 return version
355 312
356 if browser and browser == 'dartium': 313 if browser and browser == 'dartium':
357 revision = get_dartium_revision() 314 revision = get_dartium_revision()
358 self.test.test_runner.run_cmd(['echo', 'Revision: ' + revision], outfile) 315 self.test.test_runner.run_cmd(['echo', 'Revision: ' + revision], outfile)
359 elif not search_for_revision(['svn', 'info']): 316 else:
360 if not search_for_revision(['git', 'svn', 'info']): 317 revision = search_for_revision(['svn', 'info'])
361 self.test.test_runner.run_cmd(['echo', 'Revision: unknown'], outfile) 318 if revision == -1:
319 revision = search_for_revision(['git', 'svn', 'info'])
320 self.test.test_runner.run_cmd(['echo', 'Revision: ' + revision], outfile)
362 321
363 322
364 class Processor(object): 323 class Processor(object):
365 """The base level vistor class that processes tests. It contains convenience 324 """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 325 methods that many File Processor objects use. Any class that would like to be
367 a ProcessorVisitor must implement the process_file() method.""" 326 a ProcessorVisitor must implement the process_file() method."""
368 327
369 SCORE = 'Score' 328 SCORE = 'Score'
370 COMPILE_TIME = 'CompileTime' 329 COMPILE_TIME = 'CompileTime'
371 CODE_SIZE = 'CodeSize' 330 CODE_SIZE = 'CodeSize'
(...skipping 30 matching lines...) Expand all
402 dartium). 361 dartium).
403 362
404 Returns: True if the post was successful file.""" 363 Returns: True if the post was successful file."""
405 return post_results.report_results(benchmark_name, score, platform, variant, 364 return post_results.report_results(benchmark_name, score, platform, variant,
406 revision_number, metric) 365 revision_number, metric)
407 366
408 def calculate_geometric_mean(self, platform, variant, svn_revision): 367 def calculate_geometric_mean(self, platform, variant, svn_revision):
409 """Calculate the aggregate geometric mean for JS and frog benchmark sets, 368 """Calculate the aggregate geometric mean for JS and frog benchmark sets,
410 given two benchmark dictionaries.""" 369 given two benchmark dictionaries."""
411 geo_mean = 0 370 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): 371 if self.test.is_valid_combination(platform, variant):
415 for benchmark in self.test.values_list: 372 for benchmark in self.test.values_list:
416 geo_mean += math.log( 373 geo_mean += math.log(
417 self.test.values_dict[platform][variant][benchmark][ 374 self.test.values_dict[platform][variant][benchmark][
418 len(self.test.values_dict[platform][variant][benchmark]) - 1]) 375 len(self.test.values_dict[platform][variant][benchmark]) - 1])
419 376
420 self.test.values_dict[platform][variant]['Geo-Mean'] += \ 377 self.test.values_dict[platform][variant]['Geo-Mean'] += \
421 [math.pow(math.e, geo_mean / len(self.test.values_list))] 378 [math.pow(math.e, geo_mean / len(self.test.values_list))]
422 self.test.revision_dict[platform][variant]['Geo-Mean'] += [svn_revision] 379 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 380
430 graph_out_dir = 'graphs' 381 def get_score_type(self, benchmark_name):
382 """Determine the type of score for posting -- default is 'Score' (aka
383 Runtime), other options are CompileTime and CodeSize."""
384 return self.SCORE
431 385
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 386
503 class RuntimePerformanceTest(Test): 387 class RuntimePerformanceTest(Test):
504 """Super class for all runtime performance testing.""" 388 """Super class for all runtime performance testing."""
505 389
506 def __init__(self, result_folder_name, platform_list, platform_type, 390 def __init__(self, result_folder_name, platform_list, platform_type,
507 versions, benchmarks, test_runner, tester, file_processor, 391 versions, benchmarks, test_runner, tester, file_processor):
508 build_targets=['create_sdk']):
509 """Args: 392 """Args:
510 result_folder_name: The name of the folder where a tracefile of 393 result_folder_name: The name of the folder where a tracefile of
511 performance results will be stored. 394 performance results will be stored.
512 platform_list: A list containing the platform(s) that our data has been 395 platform_list: A list containing the platform(s) that our data has been
513 run on. (command line, firefox, chrome, etc) 396 run on. (command line, firefox, chrome, etc)
514 variants: A list specifying whether we hold data about Frog 397 variants: A list specifying whether we hold data about Frog
515 generated code, plain JS code, or a combination of both, or 398 generated code, plain JS code, or a combination of both, or
516 Dart depending on the test. 399 Dart depending on the test.
517 values_list: A list containing the type of data we will be graphing 400 values_list: A list containing the type of data we will be graphing
518 (benchmarks, percentage passing, etc). 401 (benchmarks, percentage passing, etc).
519 test_runner: Reference to the parent test runner object that notifies a 402 test_runner: Reference to the parent test runner object that notifies a
520 test when to run. 403 test when to run.
521 tester: The visitor that actually performs the test running mechanics. 404 tester: The visitor that actually performs the test running mechanics.
522 file_processor: The visitor that processes files in the format 405 file_processor: The visitor that processes files in the format
523 appropriate for this test. 406 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 407 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). 408 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, 409 super(RuntimePerformanceTest, self).__init__(result_folder_name,
530 platform_list, versions, benchmarks, test_runner, tester, 410 platform_list, versions, benchmarks, test_runner, tester,
531 file_processor, RuntimePerfGrapher(self), 411 file_processor)
532 build_targets=build_targets)
533 self.platform_list = platform_list 412 self.platform_list = platform_list
534 self.platform_type = platform_type 413 self.platform_type = platform_type
535 self.versions = versions 414 self.versions = versions
536 self.benchmarks = benchmarks 415 self.benchmarks = benchmarks
537 416
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 417
575 class BrowserTester(Tester): 418 class BrowserTester(Tester):
576 @staticmethod 419 @staticmethod
577 def get_browsers(add_dartium=True): 420 def get_browsers(add_dartium=True):
578 browsers = ['ff', 'chrome'] 421 browsers = ['ff', 'chrome']
579 if add_dartium: 422 if add_dartium:
580 browsers += ['dartium'] 423 browsers += ['dartium']
581 has_shell = False 424 has_shell = False
582 if platform.system() == 'Darwin': 425 if platform.system() == 'Darwin':
583 browsers += ['safari'] 426 browsers += ['safari']
584 if platform.system() == 'Windows': 427 if platform.system() == 'Windows':
585 browsers += ['ie'] 428 browsers += ['ie']
586 has_shell = True 429 has_shell = True
587 if 'dartium' in browsers: 430 if 'dartium' in browsers:
588 # Fetch it if necessary. 431 # Fetch it if necessary.
589 get_dartium = ['python', 432 get_dartium = ['python',
590 os.path.join(DART_INSTALL_LOCATION, 'tools', 'get_drt.py'), 433 os.path.join(DART_INSTALL_LOCATION, 'tools',
591 '--dartium'] 434 'get_archive.py'), 'dartium']
592 # TODO(vsm): It's inconvenient that run_cmd isn't in scope here. 435 # 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. 436 # Perhaps there is a better place to put that or this.
594 subprocess.call(get_dartium, stdout=sys.stdout, stderr=sys.stderr, 437 subprocess.call(get_dartium, stdout=sys.stdout, stderr=sys.stderr,
595 shell=has_shell) 438 shell=has_shell)
596 return browsers 439 return browsers
597 440
598 441
599 class CommonBrowserTest(RuntimePerformanceTest): 442 class CommonBrowserTest(RuntimePerformanceTest):
600 """Runs this basic performance tests (Benchpress, some V8 benchmarks) in the 443 """Runs this basic performance tests (Benchpress, some V8 benchmarks) in the
601 browser.""" 444 browser."""
(...skipping 15 matching lines...) Expand all
617 @staticmethod 460 @staticmethod
618 def get_standalone_benchmarks(): 461 def get_standalone_benchmarks():
619 return ['Mandelbrot', 'DeltaBlue', 'Richards', 'NBody', 'BinaryTrees', 462 return ['Mandelbrot', 'DeltaBlue', 'Richards', 'NBody', 'BinaryTrees',
620 'Fannkuch', 'Meteor', 'BubbleSort', 'Fibonacci', 'Loop', 'Permute', 463 'Fannkuch', 'Meteor', 'BubbleSort', 'Fibonacci', 'Loop', 'Permute',
621 'Queens', 'QuickSort', 'Recurse', 'Sieve', 'Sum', 'Tak', 'Takl', 'Towers', 464 'Queens', 'QuickSort', 'Recurse', 'Sieve', 'Sum', 'Tak', 'Takl', 'Towers',
622 'TreeSort'] 465 'TreeSort']
623 466
624 class CommonBrowserTester(BrowserTester): 467 class CommonBrowserTester(BrowserTester):
625 def run_tests(self): 468 def run_tests(self):
626 """Run a performance test in the browser.""" 469 """Run a performance test in the browser."""
627 os.chdir('frog') 470 self.test.test_runner.run_cmd([
628 self.test.test_runner.run_cmd(['python', os.path.join('benchmarks', 471 'python', os.path.join('internal', 'browserBenchmarks',
629 'make_web_benchmarks.py')]) 472 'make_web_benchmarks.py')])
630 os.chdir('..')
631 473
632 for browser in self.test.platform_list: 474 for browser in self.test.platform_list:
633 for version in self.test.versions: 475 for version in self.test.versions:
634 if not self.test.is_valid_combination(browser, version): 476 if not self.test.is_valid_combination(browser, version):
635 continue 477 continue
636 self.test.trace_file = os.path.join( 478 self.test.trace_file = os.path.join(
637 'tools', 'testing', 'perf_testing', self.test.result_folder_name, 479 'tools', 'testing', 'perf_testing', self.test.result_folder_name,
638 'perf-%s-%s-%s' % (self.test.cur_time, browser, version)) 480 'perf-%s-%s-%s' % (self.test.cur_time, browser, version))
639 self.add_svn_revision_to_trace(self.test.trace_file, browser) 481 self.add_svn_revision_to_trace(self.test.trace_file, browser)
640 file_path = os.path.join( 482 file_path = os.path.join(
641 os.getcwd(), 'internal', 'browserBenchmarks', 483 os.getcwd(), 'internal', 'browserBenchmarks',
642 'benchmark_page_%s.html' % version) 484 'benchmark_page_%s.html' % version)
643 self.test.test_runner.run_cmd( 485 self.test.test_runner.run_cmd(
644 ['python', os.path.join('tools', 'testing', 'run_selenium.py'), 486 ['python', os.path.join('tools', 'testing', 'run_selenium.py'),
645 '--out', file_path, '--browser', browser, 487 '--out', file_path, '--browser', browser,
646 '--timeout', '600', '--mode', 'perf'], self.test.trace_file, 488 '--timeout', '600', '--mode', 'perf'], self.test.trace_file,
647 append=True) 489 append=True)
648 490
649 class CommonBrowserFileProcessor(Processor): 491 class CommonBrowserFileProcessor(Processor):
492
650 def process_file(self, afile, should_post_file): 493 def process_file(self, afile, should_post_file):
651 """Comb through the html to find the performance results. 494 """Comb through the html to find the performance results.
652 Returns: True if we successfully posted our data to storage and/or we can 495 Returns: True if we successfully posted our data to storage and/or we can
653 delete the trace file.""" 496 delete the trace file."""
654 os.chdir(os.path.join(DART_INSTALL_LOCATION, 'tools', 497 os.chdir(os.path.join(DART_INSTALL_LOCATION, 'tools',
655 'testing', 'perf_testing')) 498 'testing', 'perf_testing'))
656 parts = afile.split('-') 499 parts = afile.split('-')
657 browser = parts[2] 500 browser = parts[2]
658 version = parts[3] 501 version = parts[3]
659 f = self.open_trace_file(afile, should_post_file) 502 f = self.open_trace_file(afile, should_post_file)
(...skipping 27 matching lines...) Expand all
687 break 530 break
688 name = name_and_score[0].strip() 531 name = name_and_score[0].strip()
689 score = name_and_score[1].strip() 532 score = name_and_score[1].strip()
690 if version == 'js' or version == 'v8': 533 if version == 'js' or version == 'v8':
691 version = 'js' 534 version = 'js'
692 bench_dict = self.test.values_dict[browser][version] 535 bench_dict = self.test.values_dict[browser][version]
693 bench_dict[name] += [float(score)] 536 bench_dict[name] += [float(score)]
694 self.test.revision_dict[browser][version][name] += [revision_num] 537 self.test.revision_dict[browser][version][name] += [revision_num]
695 if not self.test.test_runner.no_upload and should_post_file: 538 if not self.test.test_runner.no_upload and should_post_file:
696 upload_success = upload_success and self.report_results( 539 upload_success = upload_success and self.report_results(
697 name, score, browser, version, revision_num, self.SCORE) 540 name, score, browser, version, revision_num,
541 self.get_score_type(name))
698 else: 542 else:
699 upload_success = False 543 upload_success = False
700 544
701 f.close() 545 f.close()
702 self.calculate_geometric_mean(browser, version, revision_num) 546 self.calculate_geometric_mean(browser, version, revision_num)
703 return upload_success 547 return upload_success
704 548
705 549
706 class DromaeoTester(Tester): 550 class DromaeoTester(Tester):
707 DROMAEO_BENCHMARKS = { 551 DROMAEO_BENCHMARKS = {
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
771 @staticmethod 615 @staticmethod
772 def get_dromaeo_versions(): 616 def get_dromaeo_versions():
773 return ['js', 'frog_dom', 'frog_html', 'dart2js_dom', 'dart2js_html'] 617 return ['js', 'frog_dom', 'frog_html', 'dart2js_dom', 'dart2js_html']
774 618
775 619
776 class DromaeoTest(RuntimePerformanceTest): 620 class DromaeoTest(RuntimePerformanceTest):
777 """Runs Dromaeo tests, in the browser.""" 621 """Runs Dromaeo tests, in the browser."""
778 def __init__(self, test_runner): 622 def __init__(self, test_runner):
779 super(DromaeoTest, self).__init__( 623 super(DromaeoTest, self).__init__(
780 self.name(), 624 self.name(),
781 filter(lambda x: x != 'ie', BrowserTester.get_browsers()), 625 BrowserTester.get_browsers(),
782 'browser', 626 'browser',
783 DromaeoTester.get_dromaeo_versions(), 627 DromaeoTester.get_dromaeo_versions(),
784 DromaeoTester.get_dromaeo_benchmarks(), test_runner, 628 DromaeoTester.get_dromaeo_benchmarks(), test_runner,
785 self.DromaeoPerfTester(self), 629 self.DromaeoPerfTester(self),
786 self.DromaeoFileProcessor(self)) 630 self.DromaeoFileProcessor(self))
787 # TODO(vsm): These tester/grapher/processor classes should be
788 # cleaner to override.
789 self.grapher = self.DromaeoPerfGrapher(self)
790 631
791 @staticmethod 632 @staticmethod
792 def name(): 633 def name():
793 return 'dromaeo' 634 return 'dromaeo'
794 635
795 def is_valid_combination(self, browser, version): 636 def is_valid_combination(self, browser, version):
796 # TODO(vsm): This avoids a bug in 32-bit Chrome (dartium) 637 # TODO(vsm): This avoids a bug in 32-bit Chrome (dartium)
797 # running JS dromaeo. 638 # running JS dromaeo.
798 if browser == 'dartium' and version == 'js': 639 if browser == 'dartium' and version == 'js':
799 return False 640 return False
800 # dart:dom has been removed from Dartium. 641 # dart:dom has been removed from Dartium.
801 if browser == 'dartium' and 'dom' in version: 642 if browser == 'dartium' and 'dom' in version:
802 return False 643 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 644 return True
807 645
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 646
822 class DromaeoPerfTester(DromaeoTester): 647 class DromaeoPerfTester(DromaeoTester):
823 def move_chrome_driver_if_needed(self, browser): 648 def move_chrome_driver_if_needed(self, browser):
824 """Move the appropriate version of ChromeDriver onto the path. 649 """Move the appropriate version of ChromeDriver onto the path.
825 TODO(efortuna): This is a total hack because the latest version of Chrome 650 TODO(efortuna): This is a total hack because the latest version of Chrome
826 (Dartium builds) requires a different version of ChromeDriver, that is 651 (Dartium builds) requires a different version of ChromeDriver, that is
827 incompatible with the release or beta Chrome and vice versa. Remove these 652 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 653 shenanigans once we're back to both versions of Chrome using the same
829 version of ChromeDriver. IMPORTANT NOTE: This assumes your chromedriver is 654 version of ChromeDriver. IMPORTANT NOTE: This assumes your chromedriver is
830 in the default location (inside depot_tools). 655 in the default location (inside depot_tools).
831 """ 656 """
832 current_dir = os.getcwd() 657 current_dir = os.getcwd()
833 os.chdir(DART_INSTALL_LOCATION) 658 os.chdir(DART_INSTALL_LOCATION)
834 self.test.test_runner.run_cmd(['python', os.path.join( 659 self.test.test_runner.run_cmd(['python', os.path.join(
835 'tools', 'get_drt.py'), '--chromedriver']) 660 'tools', 'get_archive.py'), 'chromedriver'])
836 path = os.environ['PATH'].split(os.pathsep) 661 path = os.environ['PATH'].split(os.pathsep)
837 orig_chromedriver_path = os.path.join('tools', 'testing', 662 orig_chromedriver_path = os.path.join('tools', 'testing',
838 'orig-chromedriver') 663 'orig-chromedriver')
839 dartium_chromedriver_path = os.path.join('tools', 'testing', 664 dartium_chromedriver_path = os.path.join('tools', 'testing',
840 'dartium-chromedriver') 665 'dartium-chromedriver')
841 extension = '' 666 extension = ''
842 if platform.system() == 'Windows': 667 if platform.system() == 'Windows':
843 extension = '.exe' 668 extension = '.exe'
844 669
845 def move_chromedriver(depot_tools, copy_to_depot_tools_dir=True, 670 def move_chromedriver(depot_tools, copy_to_depot_tools_dir=True,
(...skipping 15 matching lines...) Expand all
861 shutil.copyfile(from_dir, to_dir) 686 shutil.copyfile(from_dir, to_dir)
862 687
863 for loc in path: 688 for loc in path:
864 if 'depot_tools' in loc: 689 if 'depot_tools' in loc:
865 if browser == 'chrome': 690 if browser == 'chrome':
866 if os.path.exists(orig_chromedriver_path): 691 if os.path.exists(orig_chromedriver_path):
867 move_chromedriver(loc) 692 move_chromedriver(loc)
868 elif browser == 'dartium': 693 elif browser == 'dartium':
869 if not os.path.exists(dartium_chromedriver_path): 694 if not os.path.exists(dartium_chromedriver_path):
870 self.test.test_runner.run_cmd(['python', 695 self.test.test_runner.run_cmd(['python',
871 os.path.join('tools', 'get_drt.py'), '--chromedriver']) 696 os.path.join('tools', 'get_archive.py'), 'chromedriver'])
872 # Move original chromedriver for storage. 697 # Move original chromedriver for storage.
873 if not os.path.exists(orig_chromedriver_path): 698 if not os.path.exists(orig_chromedriver_path):
874 move_chromedriver(loc, copy_to_depot_tools_dir=False) 699 move_chromedriver(loc, copy_to_depot_tools_dir=False)
875 # Copy Dartium chromedriver into depot_tools 700 # Copy Dartium chromedriver into depot_tools
876 move_chromedriver(loc, from_path=os.path.join( 701 move_chromedriver(loc, from_path=os.path.join(
877 dartium_chromedriver_path, 'chromedriver')) 702 dartium_chromedriver_path, 'chromedriver'))
878 os.chdir(current_dir) 703 os.chdir(current_dir)
879 704
880 def run_tests(self): 705 def run_tests(self):
881 """Run dromaeo in the browser.""" 706 """Run dromaeo in the browser."""
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
951 if results: 776 if results:
952 for result in results: 777 for result in results:
953 r = re.match(result_pattern, result) 778 r = re.match(result_pattern, result)
954 name = DromaeoTester.legalize_filename(r.group(1).strip(':')) 779 name = DromaeoTester.legalize_filename(r.group(1).strip(':'))
955 score = float(r.group(2)) 780 score = float(r.group(2))
956 bench_dict[name] += [float(score)] 781 bench_dict[name] += [float(score)]
957 self.test.revision_dict[browser][version][name] += \ 782 self.test.revision_dict[browser][version][name] += \
958 [revision_num] 783 [revision_num]
959 if not self.test.test_runner.no_upload and should_post_file: 784 if not self.test.test_runner.no_upload and should_post_file:
960 upload_success = upload_success and self.report_results( 785 upload_success = upload_success and self.report_results(
961 name, score, browser, version, revision_num, self.SCORE) 786 name, score, browser, version, revision_num,
787 self.get_score_type(name))
962 else: 788 else:
963 upload_success = False 789 upload_success = False
964 790
965 f.close() 791 f.close()
966 self.calculate_geometric_mean(browser, version, revision_num) 792 self.calculate_geometric_mean(browser, version, revision_num)
967 return upload_success 793 return upload_success
968 794
969 795
970 class DromaeoSizeTest(Test): 796 class DromaeoSizeTest(Test):
971 """Run tests to determine the compiled file output size of Dromaeo.""" 797 """Run tests to determine the compiled file output size of Dromaeo."""
972 def __init__(self, test_runner): 798 def __init__(self, test_runner):
973 super(DromaeoSizeTest, self).__init__( 799 super(DromaeoSizeTest, self).__init__(
974 self.name(), 800 self.name(),
975 ['commandline'], ['dart', 'frog_dom', 'frog_html', 801 ['commandline'], ['dart', 'frog_dom', 'frog_html',
976 'frog_htmlidiomatic'], 802 'frog_htmlidiomatic'],
977 DromaeoTester.DROMAEO_BENCHMARKS.keys(), test_runner, 803 DromaeoTester.DROMAEO_BENCHMARKS.keys(), test_runner,
978 self.DromaeoSizeTester(self), 804 self.DromaeoSizeTester(self),
979 self.DromaeoSizeProcessor(self), 805 self.DromaeoSizeProcessor(self), extra_metrics=['sum'])
980 self.DromaeoSizeGrapher(self), extra_metrics=['sum'])
981 806
982 @staticmethod 807 @staticmethod
983 def name(): 808 def name():
984 return 'dromaeo-size' 809 return 'dromaeo-size'
985 810
986 811
987 class DromaeoSizeTester(DromaeoTester): 812 class DromaeoSizeTester(DromaeoTester):
988 def run_tests(self): 813 def run_tests(self):
989 # Build tests. 814 # Build tests.
990 dromaeo_path = os.path.join('samples', 'third_party', 'dromaeo') 815 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: 903 if num.find('.') == -1:
1079 num = int(num) 904 num = int(num)
1080 else: 905 else:
1081 num = float(num) 906 num = float(num)
1082 self.test.values_dict['commandline'][variant][metric] += [num] 907 self.test.values_dict['commandline'][variant][metric] += [num]
1083 self.test.revision_dict['commandline'][variant][metric] += \ 908 self.test.revision_dict['commandline'][variant][metric] += \
1084 [revision_num] 909 [revision_num]
1085 if not self.test.test_runner.no_upload and should_post_file: 910 if not self.test.test_runner.no_upload and should_post_file:
1086 upload_success = upload_success and self.report_results( 911 upload_success = upload_success and self.report_results(
1087 metric, num, 'commandline', variant, revision_num, 912 metric, num, 'commandline', variant, revision_num,
1088 self.CODE_SIZE) 913 self.get_score_type(metric))
1089 else: 914 else:
1090 upload_success = False 915 upload_success = False
1091 916
1092 f.close() 917 f.close()
1093 return upload_success 918 return upload_success
919
920 def get_score_type(self, metric):
921 return self.CODE_SIZE
1094 922
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 923
1111 class CompileTimeAndSizeTest(Test): 924 class CompileTimeAndSizeTest(Test):
1112 """Run tests to determine how long frogc takes to compile, and the compiled 925 """Run tests to determine how long frogc takes to compile, and the compiled
1113 file output size of some benchmarking files. 926 file output size of some benchmarking files.
1114 Note: This test is now 'deprecated' since frog is no longer in the sdk. We 927 Note: This test is now 'deprecated' since frog is no longer in the sdk. We
1115 just return the last numbers found for frog.""" 928 just return the last numbers found for frog."""
1116 def __init__(self, test_runner): 929 def __init__(self, test_runner):
1117 """Reference to the test_runner object that notifies us when to begin 930 """Reference to the test_runner object that notifies us when to begin
1118 testing.""" 931 testing."""
1119 super(CompileTimeAndSizeTest, self).__init__( 932 super(CompileTimeAndSizeTest, self).__init__(
1120 self.name(), ['commandline'], ['frog'], ['swarm', 'total'], 933 self.name(), ['commandline'], ['frog'], ['swarm', 'total'],
1121 test_runner, self.CompileTester(self), 934 test_runner, self.CompileTester(self),
1122 self.CompileProcessor(self), self.CompileGrapher(self)) 935 self.CompileProcessor(self))
1123 self.dart_compiler = os.path.join( 936 self.dart_compiler = os.path.join(
1124 DART_INSTALL_LOCATION, utils.GetBuildRoot(utils.GuessOS(), 937 DART_INSTALL_LOCATION, utils.GetBuildRoot(utils.GuessOS(),
1125 'release', 'ia32'), 'dart-sdk', 'bin', 'frogc') 938 'release', 'ia32'), 'dart-sdk', 'bin', 'frogc')
1126 _suffix = '' 939 _suffix = ''
1127 if platform.system() == 'Windows': 940 if platform.system() == 'Windows':
1128 _suffix = '.exe' 941 _suffix = '.exe'
1129 self.dart_vm = os.path.join( 942 self.dart_vm = os.path.join(
1130 DART_INSTALL_LOCATION, utils.GetBuildRoot(utils.GuessOS(), 943 DART_INSTALL_LOCATION, utils.GetBuildRoot(utils.GuessOS(),
1131 'release', 'ia32'), 'dart-sdk', 'bin','dart' + _suffix) 944 'release', 'ia32'), 'dart-sdk', 'bin','dart' + _suffix)
1132 self.failure_threshold = {'swarm' : 100, 'total' : 100} 945 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: 1003 for metric in self.test.values_list:
1191 if metric in line: 1004 if metric in line:
1192 num = tokens[0] 1005 num = tokens[0]
1193 if num.find('.') == -1: 1006 if num.find('.') == -1:
1194 num = int(num) 1007 num = int(num)
1195 else: 1008 else:
1196 num = float(num) 1009 num = float(num)
1197 self.test.values_dict['commandline']['frog'][metric] += [num] 1010 self.test.values_dict['commandline']['frog'][metric] += [num]
1198 self.test.revision_dict['commandline']['frog'][metric] += \ 1011 self.test.revision_dict['commandline']['frog'][metric] += \
1199 [revision_num] 1012 [revision_num]
1200 score_type = self.CODE_SIZE 1013 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: 1014 if not self.test.test_runner.no_upload and should_post_file:
1204 if num < self.test.failure_threshold[metric]: 1015 if num < self.test.failure_threshold[metric]:
1205 num = 0 1016 num = 0
1206 upload_success = upload_success and self.report_results( 1017 upload_success = upload_success and self.report_results(
1207 metric, num, 'commandline', 'frog', revision_num, 1018 metric, num, 'commandline', 'frog', revision_num,
1208 score_type) 1019 score_type)
1209 else: 1020 else:
1210 upload_success = False 1021 upload_success = False
1211 if revision_num != 0: 1022 if revision_num != 0:
1212 for metric in self.test.values_list: 1023 for metric in self.test.values_list:
1213 try: 1024 try:
1214 self.test.revision_dict['commandline']['frog'][metric].pop() 1025 self.test.revision_dict['commandline']['frog'][metric].pop()
1215 self.test.revision_dict['commandline']['frog'][metric] += \ 1026 self.test.revision_dict['commandline']['frog'][metric] += \
1216 [revision_num] 1027 [revision_num]
1217 # Fill in 0 if compilation failed. 1028 # Fill in 0 if compilation failed.
1218 if self.test.values_dict['commandline']['frog'][metric][-1] < \ 1029 if self.test.values_dict['commandline']['frog'][metric][-1] < \
1219 self.test.failure_threshold[metric]: 1030 self.test.failure_threshold[metric]:
1220 self.test.values_dict['commandline']['frog'][metric] += [0] 1031 self.test.values_dict['commandline']['frog'][metric] += [0]
1221 self.test.revision_dict['commandline']['frog'][metric] += \ 1032 self.test.revision_dict['commandline']['frog'][metric] += \
1222 [revision_num] 1033 [revision_num]
1223 except IndexError: 1034 except IndexError:
1224 # We tried to pop from an empty list. This happens if the first 1035 # We tried to pop from an empty list. This happens if the first
1225 # trace file we encounter is incomplete. 1036 # trace file we encounter is incomplete.
1226 pass 1037 pass
1227 1038
1228 f.close() 1039 f.close()
1229 return upload_success 1040 return upload_success
1230 1041
1231 class CompileGrapher(Grapher): 1042 def get_score_type(self, metric):
1232 1043 if 'Compiling' in metric or 'Bootstrapping' in metric:
1233 def plot_results(self, png_filename):» » 1044 return self.COMPILE_TIME
1234 self.style_and_save_perf_plot(» » 1045 return self.CODE_SIZE
1235 'Compiled frog sizes', 'Size (in bytes)', 10, 10, 'lower left',
1236 png_filename, ['commandline'], ['frog'], ['swarm', 'total'])
1237 » »
1238 1046
1239 class TestBuilder(object): 1047 class TestBuilder(object):
1240 """Construct the desired test object.""" 1048 """Construct the desired test object."""
1241 available_suites = dict((suite.name(), suite) for suite in [ 1049 available_suites = dict((suite.name(), suite) for suite in [
1242 CompileTimeAndSizeTest, CommonBrowserTest, DromaeoTest, DromaeoSizeTest]) 1050 CompileTimeAndSizeTest, CommonBrowserTest, DromaeoTest, DromaeoSizeTest])
1243 1051
1244 @staticmethod 1052 @staticmethod
1245 def make_test(test_name, test_runner): 1053 def make_test(test_name, test_runner):
1246 return TestBuilder.available_suites[test_name](test_runner) 1054 return TestBuilder.available_suites[test_name](test_runner)
1247 1055
1248 @staticmethod 1056 @staticmethod
1249 def available_suite_names(): 1057 def available_suite_names():
1250 return TestBuilder.available_suites.keys() 1058 return TestBuilder.available_suites.keys()
1251 1059
1060 def search_for_revision(svn_info_command):
1061 p = subprocess.Popen(svn_info_command, stdout = subprocess.PIPE,
1062 stderr = subprocess.STDOUT,
1063 shell = (platform.system() == 'Windows'))
1064 output, _ = p.communicate()
1065 for line in output.split('\n'):
1066 if 'Revision' in line:
1067 return line.split()[1]
1068 return -1
1069
1070 def update_set_of_done_cls(revision_num=None):
1071 """Update the set of CLs that do not need additional performance runs.
1072 Args:
1073 revision_num: an additional number to be added to the 'done set'
1074 """
1075 filename = os.path.join(dirname(abspath(__file__)), 'cached_results.txt')
1076 if not os.path.exists(filename):
1077 f = open(filename, 'w')
1078 results = set()
1079 pickle.dump(results, f)
1080 f.close()
1081 f = open(filename)
1082 result_set = pickle.load(f)
1083 if revision_num:
1084 f.seek(0)
1085 result_set.add(revision_num)
1086 pickle.dump(result_set, f)
1087 f.close()
1088 return result_set
1252 1089
1253 def main(): 1090 def main():
1254 runner = TestRunner() 1091 runner = TestRunner()
1255 continuous = runner.parse_args() 1092 continuous = runner.parse_args()
1256 if continuous: 1093 if continuous:
1257 while True: 1094 while True:
1095 results_set = update_set_of_done_cls()
1258 if runner.has_new_code(): 1096 if runner.has_new_code():
1259 runner.run_test_sequence() 1097 runner.run_test_sequence()
1260 else: 1098 else:
1099 # Try to get up to 10 runs of each CL, starting with the most recent CL
1100 # that does not yet have 10 runs. But only perform a set of extra runs
1101 # at most 10 at a time (get all the extra runs for one CL) before
1102 # checking to see if new code has been checked in.
1103 has_run_extra = False
1104 revision_num = int(search_for_revision(['svn', 'info']))
1105 if revision_num == -1:
1106 revision_num = int(search_for_revision(['git', 'svn', 'info']))
1107
1108 # No need to track the performance before revision 3000. That's way in
1109 # the past.
1110 while revision_num > 3000 and not has_run_extra:
ricow1 2012/08/06 11:10:03 This will take us back in time really really slow,
Emily Fortuna 2012/08/06 17:39:34 Right, so when this was originally designed, I tho
1111 if revision_num not in results_set:
1112 a_test = TestBuilder.make_test(runner.suite_names[0], runner)
1113 benchmark_name = a_test.values_list[0]
1114 platform_name = a_test.platform_list[0]
1115 variant = a_test.values_dict[platform_name].keys()[0]
1116 number_of_results = post_results.get_num_results(benchmark_name,
1117 platform_name, variant, revision_num,
1118 a_test.file_processor.get_score_type(benchmark_name))
1119 if number_of_results < 10 and number_of_results >= 0:
1120 run = runner.run_test_sequence(revision_num=str(revision_num),
1121 num_reruns=(10-number_of_results))
1122 if run == 0:
1123 has_run_extra = True
1124 results_set = update_set_of_done_cls(revision_num)
1125 elif run == -1:
1126 # This revision is a broken build. Don't try to run it again.
1127 results_set = update_set_of_done_cls(revision_num)
1128 revision_num -= 1
1129 # No more extra back-runs to do (for now). Wait for new code.
1261 time.sleep(200) 1130 time.sleep(200)
1262 else: 1131 else:
1263 runner.run_test_sequence() 1132 runner.run_test_sequence()
1264 1133
1265 if __name__ == '__main__': 1134 if __name__ == '__main__':
1266 main() 1135 main()
OLDNEW
« no previous file with comments | « tools/testing/dart/drt_updater.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698