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

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

Issue 9706088: Some changes to performance test script. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 9 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
OLDNEW
(Empty)
1 #!/usr/bin/python
2
3 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
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.
6
7 import datetime
8 import math
9 from matplotlib.font_manager import FontProperties
10 import matplotlib.pyplot as plt
11 import optparse
12 import os
13 from os.path import dirname, abspath
14 import platform
15 import shutil
16 import subprocess
17 import time
18 import traceback
19 import sys
20
21 TOOLS_PATH = os.path.join(dirname(dirname(dirname(abspath(__file__)))))
22 sys.path.append(TOOLS_PATH)
23 import utils
24
25 """This script runs to track performance and correctness progress of
26 different svn revisions. It tests to see if there a newer version of the code on
27 the server, and will sync and run the performance tests if so."""
28
29 DART_INSTALL_LOCATION = os.path.join(dirname(abspath(__file__)),
30 '..', '..', '..')
31 V8_MEAN = 'V8 Mean'
32 FROG_MEAN = 'frog Mean'
33 COMMAND_LINE = 'commandline'
34 V8 = 'v8'
35 FROG = 'frog'
36 V8_AND_FROG = [V8, FROG]
37 CORRECTNESS = 'Percent passing'
38 COLORS = ['blue', 'green', 'red', 'cyan', 'magenta', 'black']
39 GRAPH_OUT_DIR = 'graphs'
40
41 BROWSER_PERF = 'browser-perf'
42 TIME_SIZE = 'code-time-size'
43 CL_PERF = 'cl-results'
44 BROWSER_CORRECTNESS = 'browser-correctness'
45
46 SLEEP_TIME = 200
47 VERBOSE = False
48 HAS_SHELL = False
49 if platform.system() == 'Windows':
50 # On Windows, shell must be true to get the correct environment variables.
51 HAS_SHELL = True
52
53 """First, some utility methods."""
54
55 def run_cmd(cmd_list, outfile=None, append=False):
56 """Run the specified command and print out any output to stdout.
57
58 Args:
59 cmd_list: a list of strings that make up the command to run
60 outfile: a string indicating the name of the file that we should write
61 stdout to
62 append: True if we want to append to the file instead of overwriting it"""
63 if VERBOSE:
64 print ' '.join(cmd_list)
65 out = subprocess.PIPE
66 if outfile:
67 mode = 'w'
68 if append:
69 mode = 'a'
70 out = open(outfile, mode)
71 if append:
72 # Annoying Windows "feature" -- append doesn't actually append unless you
73 # explicitly go to the end of the file.
74 # http://mail.python.org/pipermail/python-list/2009-October/1221859.html
75 out.seek(0, os.SEEK_END)
76 p = subprocess.Popen(cmd_list, stdout = out, stderr = subprocess.PIPE,
77 shell=HAS_SHELL)
78 output, not_used = p.communicate();
79 if output:
80 print output
81 return output
82
83 def time_cmd(cmd):
84 """Determine the amount of (real) time it takes to execute a given command."""
85 start = time.time()
86 run_cmd(cmd)
87 return time.time() - start
88
89 def sync_and_build():
90 """Make sure we have the latest version of of the repo, and build it. We
91 begin and end standing in DART_INSTALL_LOCATION.
92
93 Returns:
94 err_code = 1 if there was a problem building."""
95 os.chdir(DART_INSTALL_LOCATION)
96 #Revert our newly built minfrog to prevent conflicts when we update
97 run_cmd(['svn', 'revert', os.path.join(os.getcwd(), 'frog', 'minfrog')])
98
99 run_cmd(['gclient', 'sync'])
100
101 # On Windows, the output directory is marked as "Read Only," which causes an
102 # error to be thrown when we use shutil.rmtree. This helper function changes
103 # the permissions so we can still delete the directory.
104 def on_rm_error(func, path, exc_info):
105 os.chmod(path, stat.S_IWRITE)
106 os.unlink(path)
107 # TODO(efortuna): building the sdk locally is a band-aid until all build
108 # platform SDKs are hosted in Google storage. Pull from https://sandbox.
109 # google.com/storage/?arg=dart-dump-render-tree#dart-dump-render-tree%2Fsdk
110 # eventually.
111 # TODO(efortuna): Currently always building ia32 architecture because we don't
112 # have test statistics for what's passing on x64. Eliminate arch specification
113 # when we have tests running on x64, too.
114 shutil.rmtree(os.path.join(os.getcwd(),
115 utils.GetBuildRoot(utils.GuessOS(), 'release', 'ia32')),
116 onerror=on_rm_error)
117 lines = run_cmd([os.path.join('.', 'tools', 'build.py'), '-m', 'release',
118 '--arch=ia32', 'create_sdk'])
119
120 for line in lines:
121 if 'BUILD FAILED' in lines:
122 # Someone checked in a broken build! Just stop trying to make it work
123 # and wait to try again.
124 print 'Broken Build'
125 return 1
126 return 0
127
128 def ensure_output_directory(dir_name):
129 """Test that the listed directory name exists, and if not, create one for
130 our output to be placed.
131
132 Args:
133 dir_name: the directory we will create if it does not exist."""
134 dir_path = os.path.join(DART_INSTALL_LOCATION, 'tools', 'testing',
135 'perf_testing', dir_name)
136 if not os.path.exists(dir_path):
137 os.mkdir(dir_path)
138 print 'Creating output directory ', dir_path
139
140 def has_new_code():
141 """Tests if there are any newer versions of files on the server."""
142 os.chdir(DART_INSTALL_LOCATION)
143 results = run_cmd(['svn', 'st', '-u'])
144 for line in results:
145 if '*' in line:
146 return True
147 return False
148
149 def get_browsers():
150 browsers = ['ff', 'chrome']
151 if platform.system() == 'Darwin':
152 browsers += ['safari']
153 if platform.system() == 'Windows':
154 browsers += ['ie']
155 return browsers
156
157 def get_versions():
158 return V8_AND_FROG
159
160 def get_benchmarks():
161 return ['Mandelbrot', 'DeltaBlue', 'Richards', 'NBody', 'BinaryTrees',
162 'Fannkuch', 'Meteor', 'BubbleSort', 'Fibonacci', 'Loop', 'Permute',
163 'Queens', 'QuickSort', 'Recurse', 'Sieve', 'Sum', 'Tak', 'Takl', 'Towers',
164 'TreeSort']
165
166 def get_os_directory():
167 """Specifies the name of the directory for the testing build of dart, which
168 has yet a different naming convention from utils.getBuildRoot(...)."""
169 if platform.system() == 'Windows':
170 return 'windows'
171 elif platform.system() == 'Darwin':
172 return 'macos'
173 else:
174 return 'linux'
175
176 def upload_to_app_engine():
177 """Upload our results to our appengine server."""
178 # TODO(efortuna): This is the most basic way to get the data up
179 # for others to view. Revisit this once we're serving nicer graphs (Google
180 # Chart Tools) and from multiple perfbots and once we're in a position to
181 # organize the data in a useful manner(!!).
182 os.chdir(os.path.join(DART_INSTALL_LOCATION, 'tools', 'testing',
183 'perf_testing'))
184 shutil.rmtree(os.path.join('appengine', 'static', 'graphs'),
185 ignore_errors=True)
186 shutil.copytree('graphs', os.path.join('appengine', 'static', 'graphs'))
187 shutil.copyfile('index.html', os.path.join('appengine', 'static',
188 'index.html'))
189 run_cmd(['../../../third_party/appengine-python/1.5.4/appcfg.py', 'update',
190 'appengine/'])
191
192 class TestRunner(object):
193 """The base clas to provide shared code for different tests we will run and
194 graph."""
195
196 def __init__(self, result_folder_name, platform_list, v8_and_or_frog_list,
197 values_list):
198 """Args:
199 result_folder_name the name of the folder where a tracefile of
200 performance results will be stored.
201 platform_list a list containing the platform(s) that our data has been
202 run on. (command line, firefox, chrome, etc)
203 v8_and_or_frog_list a list specifying whether we hold data about Frog
204 generated code, plain JS code (v8), or a combination of both.
205 values_list a list containing the type of data we will be graphing
206 (benchmarks, percentage passing, etc)"""
207 self.result_folder_name = result_folder_name
208 # cur_time is used as a timestamp of when this performance test was run.
209 self.cur_time = str(time.mktime(datetime.datetime.now().timetuple()))
210 self.browser_color = {'chrome': 'green', 'ie': 'blue', 'ff': 'red',
211 'safari':'black'}
212 self.values_list = values_list
213 self.platform_list = platform_list
214 self.revision_dict = dict()
215 self.values_dict = dict()
216 self.color_index = 0
217 for platform in platform_list:
218 self.revision_dict[platform] = dict()
219 self.values_dict[platform] = dict()
220 for f in v8_and_or_frog_list:
221 self.revision_dict[platform][f] = dict()
222 self.values_dict[platform][f] = dict()
223 for val in values_list:
224 self.revision_dict[platform][f][val] = []
225 self.values_dict[platform][f][val] = []
226 if V8 in v8_and_or_frog_list:
227 self.revision_dict[platform][V8][V8_MEAN] = []
228 self.values_dict[platform][V8][V8_MEAN] = []
229 if FROG in v8_and_or_frog_list:
230 self.revision_dict[platform][FROG][FROG_MEAN] = []
231 self.values_dict[platform][FROG][FROG_MEAN] = []
232
233 def get_color(self):
234 color = COLORS[self.color_index]
235 self.color_index = (self.color_index + 1) % len(COLORS)
236 return color
237
238 def style_and_save_perf_plot(self, chart_title, y_axis_label, size_x, size_y,
239 legend_loc, filename, platform_list, v8_and_or_frog_list, values_list,
240 should_clear_axes=True):
241 """Sets style preferences for chart boilerplate that is consistent across
242 all charts, and saves the chart as a png.
243
244 Args:
245 size_x: the size of the printed chart, in inches, in the horizontal
246 direction
247 size_y: the size of the printed chart, in inches in the vertical direction
248 legend_loc: the location of the legend in on the chart. See suitable
249 arguments for the loc argument in matplotlib
250 filename: the filename that we want to save the resulting chart as
251 platform_list: a list containing the platform(s) that our data has been
252 run on. (command line, firefox, chrome, etc)
253 values_list: a list containing the type of data we will be graphing
254 (performance, percentage passing, etc)
255 should_clear_axes: True if we want to create a fresh graph, instead of
256 plotting additional lines on the current graph."""
257 if should_clear_axes:
258 plt.cla() # cla = clear current axes
259 for platform in platform_list:
260 for f in v8_and_or_frog_list:
261 for val in values_list:
262 plt.plot(self.revision_dict[platform][f][val],
263 self.values_dict[platform][f][val],
264 color=self.get_color(), label='%s-%s-%s' % (platform, f, val))
265
266 plt.xlabel('Revision Number')
267 plt.ylabel(y_axis_label)
268 plt.title(chart_title)
269 fontP = FontProperties()
270 fontP.set_size('small')
271 plt.legend(loc=legend_loc, prop = fontP)
272
273 fig = plt.gcf()
274 fig.set_size_inches(size_x, size_y)
275 fig.savefig(os.path.join(GRAPH_OUT_DIR, filename))
276
277 def add_svn_revision_to_trace(self, outfile):
278 """Add the svn version number to the provided tracefile."""
279 def search_for_revision(svn_info_command):
280 p = subprocess.Popen(svn_info_command, stdout = subprocess.PIPE,
281 stderr = subprocess.STDOUT, shell = HAS_SHELL)
282 output, _ = p.communicate()
283 for line in output.split('\n'):
284 if 'Revision' in line:
285 run_cmd(['echo', line.strip()], outfile)
286 return True
287 return False
288
289 if not search_for_revision(['svn', 'info']):
290 if not search_for_revision(['git', 'svn', 'info']):
291 run_cmd(['echo', 'Revision: unknown'], outfile)
292
293 def write_html(self, delimiter, rev_nums, label_1, dict_1, label_2, dict_2,
294 cleanFile=False):
295 """Adds an html table to the webpage to display the data values. This method
296 will be removed when we have a nicer way to display data values."""
297 #TODO(efortuna): fix this.
298 return
299 #TODO(efortuna): Take this method out when have finalized where the data is
300 # going to be displayed.
301 f = ''
302 out = ''
303 if cleanFile:
304 f = open('template.html')
305 else:
306 shutil.copy('index.html', 'temp.html')
307 f = open('temp.html')
308 out = open('index.html', 'w')
309 inTable = False
310 for line in f.readlines():
311 if not inTable:
312 out.write(line)
313 if delimiter in line:
314 inTable = not inTable
315 if inTable:
316 out.write('<table border="1"> <tr> <td> svn revision </td>')
317 for revision in rev_nums:
318 out.write('<td>%d</td>' % revision)
319 out.write('</tr>\n<tr><td> %s</td>' % label_1)
320 for perf in dict_1:
321 out.write('<td>%f</td>' % perf)
322 out.write('</tr>\n<tr><td> %s</td>' % label_2)
323 for perf in dict_2:
324 out.write('<td>%f</td>' % perf)
325 out.write('</tr> </table>')
326
327 def calculate_geometric_mean(self, platform, frog_or_v8, svn_revision):
328 """Calculate the aggregate geometric mean for V8 and frog benchmark sets,
329 given two benchmark dictionaries."""
330 geo_mean = 0
331 for benchmark in get_benchmarks():
332 geo_mean += math.log(self.values_dict[platform][frog_or_v8][benchmark][
333 len(self.values_dict[platform][frog_or_v8][benchmark]) - 1])
334
335 mean = V8_MEAN
336 if frog_or_v8 == FROG:
337 mean = FROG_MEAN
338 self.values_dict[platform][frog_or_v8][mean] += \
339 [math.pow(math.e, geo_mean / len(get_benchmarks()))]
340 self.revision_dict[platform][frog_or_v8][mean] += [svn_revision]
341
342 def run(self):
343 """Run the benchmarks/tests from the command line and plot the
344 results."""
345 plt.cla() # cla = clear current axes
346 os.chdir(DART_INSTALL_LOCATION)
347 ensure_output_directory(self.result_folder_name)
348 ensure_output_directory(GRAPH_OUT_DIR)
349 self.run_tests()
350 os.chdir(os.path.join('tools', 'testing', 'perf_testing'))
351
352 # TODO(efortuna): You will want to make this only use a subset of the files
353 # eventually.
354 files = os.listdir(self.result_folder_name)
355
356 for afile in files:
357 if not afile.startswith('.'):
358 self.process_file(afile)
359
360 self.plot_results('%s.png' % self.result_folder_name)
361
362 class PerformanceTest(TestRunner):
363 """Super class for all performance testing."""
364 def __init__(self, result_folder_name, platform_list, platform_type):
365 super(PerformanceTest, self).__init__(result_folder_name,
366 platform_list, get_versions(), get_benchmarks())
367 self.platform_list = platform_list
368 self.platform_type = platform_type
369
370 def plot_all_perf(self, png_filename):
371 """Create a plot that shows the performance changes of individual benchmarks
372 run by V8 and generated by frog, over svn history."""
373 for benchmark in get_benchmarks():
374 self.style_and_save_perf_plot(
375 'Performance of %s over time on the %s' % (benchmark,
376 self.platform_type), 'Speed (bigger = better)', 16, 14, 'lower left',
377 benchmark + png_filename, self.platform_list, get_versions(),
378 [benchmark])
379
380 def plot_avg_perf(self, png_filename):
381 """Generate a plot that shows the performance changes of the geomentric mean
382 of V8 and frog benchmark performance over svn history."""
383 (title, y_axis, size_x, size_y, loc, filename) = \
384 ('Geometric Mean of benchmark %s performance' % self.platform_type,
385 'Speed (bigger = better)', 16, 5, 'center', 'avg'+png_filename)
386 clear_axis = True
387 for platform in self.platform_list:
388 self.style_and_save_perf_plot(title, y_axis, size_x, size_y, loc,
389 filename, [platform], [V8], [V8_MEAN], clear_axis)
390 clear_axis = False
391 self.style_and_save_perf_plot(title, y_axis, size_x, size_y, loc,
392 filename, [platform], [FROG], [FROG_MEAN], clear_axis)
393
394 def plot_results(self, png_filename):
395 self.plot_all_perf(png_filename)
396 self.plot_avg_perf('2' + png_filename)
397
398
399 class CommandLinePerformanceTest(PerformanceTest):
400 """Run performance tests from the command line."""
401
402 def __init__(self, result_folder_name):
403 super(CommandLinePerformanceTest, self).__init__(result_folder_name,
404 [COMMAND_LINE], 'command line')
405
406 def process_file(self, afile):
407 """Pull all the relevant information out of a given tracefile.
408
409 Args:
410 afile: The filename string we will be processing."""
411 f = open(os.path.join(self.result_folder_name, afile))
412 tabulate_data = False
413 revision_num = 0
414 for line in f.readlines():
415 if 'Revision' in line:
416 revision_num = int(line.split()[1])
417 elif 'Benchmark' in line:
418 tabulate_data = True
419 elif tabulate_data:
420 tokens = line.split()
421 if len(tokens) < 4 or tokens[0] not in get_benchmarks():
422 #Done tabulating data.
423 break
424 v8_value = float(tokens[1])
425 frog_value = float(tokens[3])
426 if v8_value == 0 or frog_value == 0:
427 #Then there was an error when this performance test was run. Do not
428 #count it in our numbers.
429 return
430 benchmark = tokens[0]
431 self.revision_dict[COMMAND_LINE][V8][benchmark] += [revision_num]
432 self.values_dict[COMMAND_LINE][V8][benchmark] += [v8_value]
433 self.revision_dict[COMMAND_LINE][FROG][benchmark] += [revision_num]
434 self.values_dict[COMMAND_LINE][FROG][benchmark] += [frog_value]
435 f.close()
436
437 self.calculate_geometric_mean(COMMAND_LINE, FROG, revision_num)
438 self.calculate_geometric_mean(COMMAND_LINE, V8, revision_num)
439
440 def run_tests(self):
441 """Run a performance test on our updated system."""
442 os.chdir('frog')
443 self.trace_file = os.path.join('..', 'tools', 'testing', 'perf_testing',
444 self.result_folder_name, 'result' + self.cur_time)
445 run_cmd(['python', os.path.join('benchmarks', 'perf_tests.py')],
446 self.trace_file)
447 os.chdir('..')
448
449
450 class BrowserPerformanceTest(PerformanceTest):
451 """Runs performance tests, in the browser."""
452
453 def __init__(self, result_folder_name):
454 super(BrowserPerformanceTest, self).__init__(
455 result_folder_name, get_browsers(), 'browser')
456
457 def run_tests(self):
458 """Run a performance test in the browser."""
459
460 os.chdir('frog')
461 run_cmd(['python', os.path.join('benchmarks', 'make_web_benchmarks.py')])
462 os.chdir('..')
463
464 for browser in get_browsers():
465 for version in get_versions():
466 self.trace_file = os.path.join('tools', 'testing', 'perf_testing',
467 self.result_folder_name,
468 'perf-%s-%s-%s' % (self.cur_time, browser, version))
469 self.add_svn_revision_to_trace(self.trace_file)
470 file_path = os.path.join(os.getcwd(), 'internal', 'browserBenchmarks',
471 'benchmark_page_%s.html' % version)
472 run_cmd(['python', os.path.join('tools', 'testing', 'run_selenium.py'),
473 '--out', file_path, '--browser', browser,
474 '--timeout', '600', '--perf'], self.trace_file, append=True)
475
476 def process_file(self, afile):
477 """Comb through the html to find the performance results."""
478 parts = afile.split('-')
479 browser = parts[2]
480 version = parts[3]
481 f = open(os.path.join(self.result_folder_name, afile))
482 lines = f.readlines()
483 line = ''
484 i = 0
485 revision_num = 0
486 while '<div id="results">' not in line and i < len(lines):
487 if 'Revision' in line:
488 revision_num = int(line.split()[1])
489 line = lines[i]
490 i += 1
491
492 if i >= len(lines) or revision_num == 0:
493 # Then this run did not complete. Ignore this tracefile.
494 return
495
496 line = lines[i]
497 i += 1
498 results = []
499 if line.find('<br>') > -1:
500 results = line.split('<br>')
501 else:
502 results = line.split('<br />')
503 for result in results:
504 name_and_score = result.split(':')
505 if len(name_and_score) < 2:
506 break
507 name = name_and_score[0].strip()
508 score = name_and_score[1].strip()
509 if version == V8:
510 bench_dict = self.values_dict[browser][V8]
511 else:
512 bench_dict = self.values_dict[browser][FROG]
513 bench_dict[name] += [float(score)]
514 self.revision_dict[browser][version][name] += [revision_num]
515
516 f.close()
517 self.calculate_geometric_mean(browser, version, revision_num)
518
519 def write_html(self, delimiter, rev_nums, label_1, dict_1, label_2, dict_2,
520 cleanFile=False):
521 #TODO(efortuna)
522 pass
523
524
525 class BrowserCorrectnessTest(TestRunner):
526 def __init__(self, test_type, result_folder_name):
527 super(BrowserCorrectnessTest, self).__init__(result_folder_name,
528 get_browsers(), [FROG], [CORRECTNESS])
529 self.test_type = test_type
530
531 def run_tests(self):
532 """Run a test of the latest svn revision."""
533 system = get_os_directory()
534 suffix = ''
535 if platform.system() == 'Windows':
536 suffix = '.exe'
537 for browser in get_browsers():
538 current_file = 'correctness%s-%s' % (self.cur_time, browser)
539 self.trace_file = os.path.join('tools', 'testing',
540 'perf_testing', self.result_folder_name, current_file)
541 self.add_svn_revision_to_trace(self.trace_file)
542 dart_sdk = os.path.join(os.getcwd(), utils.GetBuildRoot(utils.GuessOS(),
543 'release', 'ia32'), 'dart-sdk')
544 run_cmd([os.path.join('.', 'tools', 'testing', 'bin', system,
545 'dart' + suffix), os.path.join('tools', 'test.dart'),
546 '--component=webdriver',
547 '--browser=%s' % browser, '--frog=%s' % os.path.join(dart_sdk, 'bin',
548 'frogc'), '--froglib=%s' % os.path.join(dart_sdk, 'lib'), '--report',
549 '--timeout=20', '--progress=color', '--mode=release', '-j1',
550 self.test_type], self.trace_file, append=True)
551
552 def process_file(self, afile):
553 """Given a trace file, extract all the relevant information out of it to
554 determine the number of correctly passing tests.
555
556 Arguments:
557 afile: the filename string"""
558 browser = afile.rpartition('-')[2]
559 f = open(os.path.join(self.result_folder_name, afile))
560 revision_num = 0
561 lines = f.readlines()
562 total_tests = 0
563 num_failed = 0
564 expect_fail = 0
565 for line in lines:
566 if 'Total:' in line:
567 total_tests = int(line.split('Total: ')[1].split()[0])
568 if 'will be skipped' in line:
569 total_tests -= int(line.split()[1])
570 if 'we should fix' in line:
571 expect_fail += int(line.split()[1])
572 if 'Revision' in line:
573 revision_num = int(line.split()[1])
574 if '--- TIMEOUT ---' in line or 'FAIL:' in line or 'PASS' in line:
575 # (A printed out 'PASS' indicates we incorrectly passed a negative
576 # test.)
577 num_failed += 1
578
579 self.revision_dict[browser][FROG][CORRECTNESS] += [revision_num]
580 self.values_dict[browser][FROG][CORRECTNESS] += [100.0 *
581 (((float)(total_tests - (expect_fail + num_failed))) /total_tests)]
582 f.close()
583
584 def plot_results(self, png_filename):
585 first_time = True
586 for browser in get_browsers():
587 self.style_and_save_perf_plot('Percentage of language tests passing in '
588 'different browsers', '% of tests passed', 8, 8, 'lower left',
589 png_filename, [browser], [FROG], [CORRECTNESS], first_time)
590 first_time = False
591
592
593 class CompileTimeAndSizeTest(TestRunner):
594 """Run tests to determine how long minfrog takes to compile, and the compiled
595 file output size of some benchmarking files."""
596 def __init__(self, result_folder_name):
597 super(CompileTimeAndSizeTest, self).__init__(result_folder_name,
598 [COMMAND_LINE], [FROG], ['Compiling on Dart VM', 'Bootstrapping',
599 'minfrog', 'swarm', 'total'])
600 self.failure_threshold = {'Compiling on Dart VM' : 1, 'Bootstrapping' : .5,
601 'minfrog' : 100, 'swarm' : 100, 'total' : 100}
602
603 def run_tests(self):
604 os.chdir('frog')
605 self.trace_file = os.path.join('..', 'tools', 'testing', 'perf_testing',
606 self.result_folder_name, self.result_folder_name + self.cur_time)
607
608 self.add_svn_revision_to_trace(self.trace_file)
609
610 suffix = ''
611 if platform.system() == 'Windows':
612 suffix = '.exe'
613 elapsed = time_cmd([os.path.join('..', utils.GetBuildRoot(utils.GuessOS(),
614 'release', 'ia32'), 'dart' + suffix), os.path.join('.', 'minfrogc.dart'),
615 '--out=minfrog', 'minfrog.dart'])
616 run_cmd(['echo', '%f Compiling on Dart VM in production mode in seconds'
617 % elapsed], self.trace_file, append=True)
618 elapsed = time_cmd([os.path.join('.', 'minfrog'), '--out=minfrog',
619 'minfrog.dart', os.path.join('tests', 'hello.dart')])
620 if elapsed < self.failure_threshold['Bootstrapping']:
621 #minfrog didn't compile correctly. Stop testing now, because subsequent
622 #numbers will be meaningless.
623 return
624 size = os.path.getsize('minfrog')
625 run_cmd(['echo', '%f Bootstrapping time in seconds in production mode' %
626 elapsed], self.trace_file, append=True)
627 run_cmd(['echo', '%d Generated checked minfrog size' % size],
628 self.trace_file, append=True)
629
630 run_cmd([os.path.join('.', 'minfrog'), '--out=swarm-result',
631 '--compile-only', os.path.join('..', 'samples', 'swarm',
632 'swarm.dart')])
633 swarm_size = 0
634 try:
635 swarm_size = os.path.getsize('swarm-result')
636 except OSError:
637 pass #If compilation failed, continue on running other tests.
638
639 run_cmd([os.path.join('.', 'minfrog'), '--out=total-result',
640 '--compile-only', os.path.join('..', 'samples', 'total',
641 'client', 'Total.dart')])
642 total_size = 0
643 try:
644 total_size = os.path.getsize('total-result')
645 except OSError:
646 pass #If compilation failed, continue on running other tests.
647
648 run_cmd(['echo', '%d Generated checked swarm size' % swarm_size],
649 self.trace_file, append=True)
650
651 run_cmd(['echo', '%d Generated checked total size' % total_size],
652 self.trace_file, append=True)
653 os.chdir('..')
654
655 def process_file(self, afile):
656 """Pull all the relevant information out of a given tracefile.
657
658 Args:
659 afile: is the filename string we will be processing."""
660 f = open(os.path.join(self.result_folder_name, afile))
661 tabulate_data = False
662 revision_num = 0
663 for line in f.readlines():
664 tokens = line.split()
665 if 'Revision' in line:
666 revision_num = int(line.split()[1])
667 else:
668 for metric in self.values_list:
669 if metric in line:
670 num = tokens[0]
671 if num.find('.') == -1:
672 num = int(num)
673 else:
674 num = float(num)
675 self.values_dict[COMMAND_LINE][FROG][metric] += [num]
676 self.revision_dict[COMMAND_LINE][FROG][metric] += [revision_num]
677
678 if revision_num != 0:
679 for metric in self.values_list:
680 self.revision_dict[COMMAND_LINE][FROG][metric].pop()
681 self.revision_dict[COMMAND_LINE][FROG][metric] += [revision_num]
682 # Fill in 0 if compilation failed.
683 if self.values_dict[COMMAND_LINE][FROG][metric][-1] < \
684 self.failure_threshold[metric]:
685 self.values_dict[COMMAND_LINE][FROG][metric] += [0]
686 self.revision_dict[COMMAND_LINE][FROG][metric] += [revision_num]
687
688 f.close()
689
690 def plot_results(self, png_filename):
691 self.style_and_save_perf_plot('Compiled minfrog Sizes',
692 'Size (in bytes)', 10, 10, 'center', png_filename, [COMMAND_LINE],
693 [FROG], ['swarm', 'total', 'minfrog'])
694 self.write_html('bar', self.revision_dict[COMMAND_LINE][FROG]['minfrog'],
695 'minfrog size', self.values_dict[COMMAND_LINE][FROG]['minfrog'], '', [])
696
697 self.style_and_save_perf_plot('Time to compile and bootstrap',
698 'Seconds', 10, 10, 'center', '2' + png_filename, [COMMAND_LINE], [FROG],
699 ['Bootstrapping', 'Compiling on Dart VM'])
700 self.write_html('baz',
701 self.revision_dict[COMMAND_LINE][FROG]['Bootstrapping'],
702 'Bootstrapping', self.values_dict[COMMAND_LINE][FROG]['Bootstrapping'],
703 'Compiling on Dart VM',
704 self.values_dict[COMMAND_LINE][FROG]['Compiling on Dart VM'])
705
706
707 def parse_args():
708 parser = optparse.OptionParser()
709 parser.add_option('--command-line', '-c', dest='cl',
710 help = 'Run the command line tests',
711 action = 'store_true', default = False)
712 parser.add_option('--size-time', '-s', dest = 'size',
713 help = 'Run the code size and timing tests',
714 action = 'store_true', default = False)
715 parser.add_option('--language', '-l', dest = 'language',
716 help = 'Run the language correctness tests',
717 action = 'store_true', default = False)
718 parser.add_option('--browser-perf', '-b', dest = 'perf',
719 help = 'Run the browser performance tests',
720 action = 'store_true', default = False)
721 parser.add_option('--forever', '-f', dest = 'continuous',
722 help = 'Run this script forever, always checking for the next svn '
723 'checkin', action = 'store_true', default = False)
724 parser.add_option('--verbose', '-v', dest = 'verbose',
725 help = 'Print extra debug output', action = 'store_true', default = False)
726
727 args, ignored = parser.parse_args()
728 if not (args.cl or args.size or args.language or args.perf):
729 args.cl = args.size = args.language = args.perf = True
730 return (args.cl, args.size, args.language, args.perf, args.continuous,
731 args.verbose)
732
733 def run_test_sequence(cl, size, language, perf):
734 # The buildbot already builds and syncs to a specific revision. Don't fight
735 # with it or replicate work.
736 if sync_and_build() == 1:
737 return # The build is broken.
738 if size:
739 CompileTimeAndSizeTest(TIME_SIZE).run()
740 if cl:
741 CommandLinePerformanceTest(CL_PERF).run()
742 if language:
743 BrowserCorrectnessTest('language', BROWSER_CORRECTNESS).run()
744 if perf:
745 BrowserPerformanceTest(BROWSER_PERF).run()
746
747 # TODO(efortuna): Temporarily disabled until you make a safe way to provide
748 # your username/password for the uploading process.
749 #upload_to_app_engine()
750
751 def main():
752 global VERBOSE
753 (cl, size, language, perf, continuous, verbose) = parse_args()
754 VERBOSE = verbose
755 if continuous:
756 while True:
757 if has_new_code():
758 run_test_sequence(cl, size, language, perf)
759 else:
760 time.sleep(SLEEP_TIME)
761 else:
762 run_test_sequence(cl, size, language, perf)
763
764 if __name__ == '__main__':
765 main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698