| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 | 2 |
| 3 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 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 | 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 from matplotlib.font_manager import FontProperties | 9 try: |
| 10 import matplotlib.pyplot as plt | 10 from matplotlib.font_manager import FontProperties |
| 11 import matplotlib.pyplot as plt |
| 12 except ImportError: |
| 13 print 'Warning: no matplotlib. ' + \ |
| 14 'Please ignore if you are running buildbot smoketests.' |
| 15 import optparse |
| 11 import os | 16 import os |
| 12 import platform | 17 import platform |
| 13 import shutil | 18 import shutil |
| 14 import subprocess | 19 import subprocess |
| 15 import time | 20 import time |
| 16 import traceback | 21 import traceback |
| 17 | 22 |
| 18 """This script runs to track performance and correctness progress of | 23 """This script runs to track performance and correctness progress of |
| 19 different svn revisions. It tests to see if there a newer version of the code on | 24 different svn revisions. It tests to see if there a newer version of the code on |
| 20 the server, and will sync and run the performance tests if so.""" | 25 the server, and will sync and run the performance tests if so.""" |
| 21 | 26 |
| 22 DART_INSTALL_LOCATION = os.path.join(os.path.dirname(os.path.abspath(__file__)), | 27 DART_INSTALL_LOCATION = os.path.join(os.path.dirname(os.path.abspath(__file__)), |
| 23 '..', '..', '..') | 28 '..', '..', '..') |
| 24 V8_MEAN = 'V8 Mean' | 29 V8_MEAN = 'V8 Mean' |
| 25 FROG_MEAN = 'frog Mean' | 30 FROG_MEAN = 'frog Mean' |
| 26 COMMAND_LINE = 'commandline' | 31 COMMAND_LINE = 'commandline' |
| 27 V8 = 'v8' | 32 V8 = 'v8' |
| 28 FROG = 'frog' | 33 FROG = 'frog' |
| 29 V8_AND_FROG = [V8, FROG] | 34 V8_AND_FROG = [V8, FROG] |
| 30 CORRECTNESS = 'Percent passing' | 35 CORRECTNESS = 'Percent passing' |
| 31 BENCHMARKS = ['Mandelbrot', 'DeltaBlue', 'Richards', 'NBody', | 36 BENCHMARKS = ['Mandelbrot', 'DeltaBlue', 'Richards', 'NBody', |
| 32 'BinaryTrees', 'Fannkuch', 'Meteor', 'BubbleSort', 'Fibonacci', | 37 'BinaryTrees', 'Fannkuch', 'Meteor', 'BubbleSort', 'Fibonacci', |
| 33 'Loop', 'Permute', 'Queens', 'QuickSort', 'Recurse', 'Sieve', 'Sum', | 38 'Loop', 'Permute', 'Queens', 'QuickSort', 'Recurse', 'Sieve', 'Sum', |
| 34 'Tak', 'Takl', 'Towers', 'TreeSort'] | 39 'Tak', 'Takl', 'Towers', 'TreeSort'] |
| 35 COLORS = ['blue', 'green', 'red', 'cyan', 'magenta', 'black'] | 40 COLORS = ['blue', 'green', 'red', 'cyan', 'magenta', 'black'] |
| 36 GRAPH_OUT_DIR = 'graphs' | 41 GRAPH_OUT_DIR = 'graphs' |
| 42 SLEEP_TIME = 200 |
| 43 PERFBOT_MODE = False |
| 44 VERBOSE = False |
| 37 | 45 |
| 38 """First, some utility methods.""" | 46 """First, some utility methods.""" |
| 39 | 47 |
| 40 def RunCmd(string): | 48 def RunCmd(cmd_list, outfile=None, append=False): |
| 41 """Run the specified command and print out any output to stdout. | 49 """Run the specified command and print out any output to stdout. |
| 42 Args: | 50 Args: |
| 43 string the command to run""" | 51 cmd_list a list of strings that make up the command to run |
| 44 p = subprocess.Popen(string, stdout = subprocess.PIPE, | 52 outfile a string indicating the name of the file that we should write stdout |
| 45 stderr = subprocess.STDOUT, close_fds=True) | 53 to |
| 54 append True if we want to append to the file instead of overwriting it""" |
| 55 if VERBOSE: |
| 56 print ' '.join(cmd_list) |
| 57 out = subprocess.PIPE |
| 58 if outfile: |
| 59 mode = 'w' |
| 60 if append: |
| 61 mode = 'a' |
| 62 out = open(outfile, mode) |
| 63 p = subprocess.Popen(cmd_list, stdout = out, |
| 64 stderr = subprocess.PIPE, close_fds=True) |
| 46 output, not_used = p.communicate(); | 65 output, not_used = p.communicate(); |
| 47 print output: | 66 if output: |
| 48 return lines | 67 print output |
| 68 return output |
| 49 | 69 |
| 50 def TimeCmd(self, cmd): | 70 def TimeCmd(cmd): |
| 71 """Determine the amount of (real) time it takes to execute a given command.""" |
| 51 start = time.time() | 72 start = time.time() |
| 52 RunCmd(cmd) | 73 RunCmd(cmd) |
| 53 return time.time() - start | 74 return time.time() - start |
| 54 | 75 |
| 55 def SyncAndBuild(failed_once=False): | 76 def SyncAndBuild(failed_once=False): |
| 56 """Make sure we have the latest version of of the repo, and build it. We | 77 """Make sure we have the latest version of of the repo, and build it. We |
| 57 begin and end standing in DART_INSTALL_LOCATION. | 78 begin and end standing in DART_INSTALL_LOCATION. |
| 58 Args: | 79 Args: |
| 59 failed_once True if we have attempted to build this once before, and we've | 80 failed_once True if we have attempted to build this once before, and we've |
| 60 failed, indicating .""" | 81 failed, indicating the build is broken.""" |
| 61 os.chdir(DART_INSTALL_LOCATION) | 82 os.chdir(DART_INSTALL_LOCATION) |
| 62 #Revert our newly built frogsh to prevent conflicts when we update | 83 #Revert our newly built frogsh to prevent conflicts when we update |
| 63 RunCmd('svn revert ' + os.path.join(os.getcwd(), 'frog', 'frogsh')) | 84 RunCmd(['svn', 'revert', os.path.join(os.getcwd(), 'frog', 'frogsh')]) |
| 64 | 85 |
| 65 RunCmd('gclient sync') | 86 RunCmd(['gclient', 'sync']) |
| 66 lines = RunCmd('%s -m release' % os.path.join('.', 'tools', 'build.py')) | 87 lines = RunCmd([os.path.join('.', 'tools', 'build.py'), '-m', 'release']) |
| 67 os.chdir('frog') | 88 os.chdir('frog') |
| 68 lines += RunCmd('%s -m debug,release' % os.path.join('..', 'tools', | 89 lines += RunCmd([os.path.join('..', 'tools', 'build.py'), '-m', |
| 69 'build.py')) | 90 'debug,release']) |
| 70 os.chdir('..') | 91 os.chdir('..') |
| 71 | 92 |
| 72 for line in lines: | 93 for line in lines: |
| 73 if '** BUILD FAILED **' in lines: | 94 if 'BUILD FAILED' in lines: |
| 74 if TestRunner.failed_once: | 95 if failed_once: |
| 75 # Someone checked in a broken build! Just stop trying to make it work | 96 # Someone checked in a broken build! Just stop trying to make it work |
| 76 # and wait for the next hour to try again. | 97 # and wait for the next hour to try again. |
| 77 print 'Broken Build' | 98 print 'Broken Build' |
| 78 sys.exit(0) | 99 sys.exit(0) |
| 79 #Remove the xcode directory and attempt to build again. If it still | 100 #Remove the xcode directory and attempt to build again. If it still |
| 80 #fails, abort, and try again next hour. | 101 #fails, abort, and try again next hour. |
| 81 out_dir = 'out' | 102 out_dir = 'out' |
| 82 if platform.system() == 'Darwin': | 103 if platform.system() == 'Darwin': |
| 83 out_dir = 'xcodebuild' | 104 out_dir = 'xcodebuild' |
| 84 os.removedirs(os.getcwd() + os.path.join('dart', out_dir, 'Release_ia32')) | 105 shutil.rmtree(os.path.join(os.getcwd(), out_dir, 'Release_ia32')) |
| 85 os.removedirs(os.getcwd() + os.path.join('dart', 'frog', out_dir, | 106 shutil.rmtree(os.path.join(os.getcwd(), 'frog', out_dir, |
| 107 'Debug_ia32')) |
| 108 shutil.rmtree(os.path.join(os.getcwd(), 'frog', out_dir, |
| 86 'Release_ia32')) | 109 'Release_ia32')) |
| 87 os.removedirs(os.getcwd() + os.path.join('dart', 'frog', out_dir, | 110 SyncAndBuild(True) |
| 88 'Debug_ia32')) | |
| 89 TestRunner.failed_once = True | |
| 90 SyncAndBuild() | |
| 91 | 111 |
| 92 def EnsureOutputDirectory(dir_name): | 112 def EnsureOutputDirectory(dir_name): |
| 93 """Test that the listed directory name exists, and if not, create one for | 113 """Test that the listed directory name exists, and if not, create one for |
| 94 our output to be placed.""" | 114 our output to be placed. |
| 115 Args: |
| 116 dir_name the directory we will create if it does not exist.""" |
| 95 dir_path = os.path.join(DART_INSTALL_LOCATION, 'tools', 'testing', | 117 dir_path = os.path.join(DART_INSTALL_LOCATION, 'tools', 'testing', |
| 96 'perf_testing', dir_name) | 118 'perf_testing', dir_name) |
| 97 if not os.path.exists(dir_path): | 119 if not os.path.exists(dir_path): |
| 98 os.mkdir(dir_path) | 120 os.mkdir(dir_path) |
| 99 print 'Creating output directory ', dir_path | 121 print 'Creating output directory ', dir_path |
| 100 | 122 |
| 101 def HasNewCode(): | 123 def HasNewCode(): |
| 102 """Tests if there are any newer versions of files on the server.""" | 124 """Tests if there are any newer versions of files on the server.""" |
| 103 os.chdir(DART_INSTALL_LOCATION) | 125 os.chdir(DART_INSTALL_LOCATION) |
| 104 results = RunCmd('svn st -u') | 126 results = RunCmd(['svn', 'st', '-u']) |
| 105 for line in results: | 127 for line in results: |
| 106 if '*' in line: | 128 if '*' in line: |
| 107 return True | 129 return True |
| 108 return False | 130 return False |
| 109 | 131 |
| 110 def GetBrowsers(): | 132 def GetBrowsers(): |
| 133 if not PERFBOT_MODE: |
| 134 # Only Firefox (and Chrome, but we have Dump Render Tree) works in Linux |
| 135 return ['ff'] |
| 111 browsers = ['ff', 'chrome'] | 136 browsers = ['ff', 'chrome'] |
| 112 if platform.system() == 'Windows': | 137 if platform.system() == 'Windows': |
| 113 browsers += ['ie'] | 138 browsers += ['ie'] |
| 114 return browsers | 139 return browsers |
| 115 | 140 |
| 141 def GetVersions(): |
| 142 if not PERFBOT_MODE: |
| 143 return [FROG] |
| 144 else: |
| 145 return V8_AND_FROG |
| 146 |
| 116 class TestRunner(object): | 147 class TestRunner(object): |
| 117 """The base clas to provide shared code for different tests we will run and | 148 """The base clas to provide shared code for different tests we will run and |
| 118 graph.""" | 149 graph.""" |
| 119 | 150 |
| 120 def __init__(self, result_folder_name, platform_list, v8_and_or_frog_list, | 151 def __init__(self, result_folder_name, platform_list, v8_and_or_frog_list, |
| 121 values_list): | 152 values_list): |
| 122 """Args: | 153 """Args: |
| 123 result_folder_name the name of the folder where a tracefile of | 154 result_folder_name the name of the folder where a tracefile of |
| 124 performance results will be stored. | 155 performance results will be stored. |
| 125 platform_list a list containing the platform(s) that our data has been | 156 platform_list a list containing the platform(s) that our data has been |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 fontP = FontProperties() | 222 fontP = FontProperties() |
| 192 fontP.set_size('small') | 223 fontP.set_size('small') |
| 193 plt.legend(loc=legend_loc, prop = fontP) | 224 plt.legend(loc=legend_loc, prop = fontP) |
| 194 | 225 |
| 195 fig = plt.gcf() | 226 fig = plt.gcf() |
| 196 fig.set_size_inches(size_x, size_y) | 227 fig.set_size_inches(size_x, size_y) |
| 197 fig.savefig(os.path.join(GRAPH_OUT_DIR, filename)) | 228 fig.savefig(os.path.join(GRAPH_OUT_DIR, filename)) |
| 198 | 229 |
| 199 def AddSvnRevisionToTrace(self, outfile): | 230 def AddSvnRevisionToTrace(self, outfile): |
| 200 """Add the svn version number to the provided tracefile.""" | 231 """Add the svn version number to the provided tracefile.""" |
| 201 p = subprocess.Popen('svn info ', stdout = subprocess.PIPE, | 232 p = subprocess.Popen(['svn', 'info'], stdout = subprocess.PIPE, |
| 202 stderr = subprocess.STDOUT, close_fds=True) | 233 stderr = subprocess.STDOUT, close_fds=True) |
| 203 output, not_used = p.communicate() | 234 output, not_used = p.communicate() |
| 204 for line in output.split('\n'): | 235 for line in output.split('\n'): |
| 205 if 'Revision' in line: | 236 if 'Revision' in line: |
| 206 RunCmd('echo "%s" > %s' % (line.strip(), outfile)) | 237 RunCmd(['echo', line.strip()], outfile) |
| 207 | 238 |
| 208 def WriteHtml(self, delimiter, rev_nums, label_1, dict_1, label_2, dict_2, | 239 def WriteHtml(self, delimiter, rev_nums, label_1, dict_1, label_2, dict_2, |
| 209 cleanFile=False): | 240 cleanFile=False): |
| 210 """Adds an html table to the webpage to display the data values. This method | 241 """Adds an html table to the webpage to display the data values. This method |
| 211 will be removed when we have a nicer way to display data values.""" | 242 will be removed when we have a nicer way to display data values.""" |
| 212 #TODO(efortuna): fix this. | 243 #TODO(efortuna): fix this. |
| 213 return | 244 return |
| 214 #TODO(efortuna): Take this method out when have finalized where the data is | 245 #TODO(efortuna): Take this method out when have finalized where the data is |
| 215 # going to be displayed. | 246 # going to be displayed. |
| 216 f = '' | 247 f = '' |
| (...skipping 30 matching lines...) Expand all Loading... |
| 247 geo_mean += math.log(self.values_dict[platform][frog_or_v8][benchmark][ | 278 geo_mean += math.log(self.values_dict[platform][frog_or_v8][benchmark][ |
| 248 len(self.values_dict[platform][frog_or_v8][benchmark]) - 1]) | 279 len(self.values_dict[platform][frog_or_v8][benchmark]) - 1]) |
| 249 | 280 |
| 250 mean = V8_MEAN | 281 mean = V8_MEAN |
| 251 if frog_or_v8 == FROG: | 282 if frog_or_v8 == FROG: |
| 252 mean = FROG_MEAN | 283 mean = FROG_MEAN |
| 253 self.values_dict[platform][frog_or_v8][mean] += \ | 284 self.values_dict[platform][frog_or_v8][mean] += \ |
| 254 [math.pow(math.e, geo_mean / len(BENCHMARKS))] | 285 [math.pow(math.e, geo_mean / len(BENCHMARKS))] |
| 255 self.revision_dict[platform][frog_or_v8][mean] += [svn_revision] | 286 self.revision_dict[platform][frog_or_v8][mean] += [svn_revision] |
| 256 | 287 |
| 288 def Cleanup(self): |
| 289 pass |
| 290 |
| 257 def Run(self): | 291 def Run(self): |
| 258 """Run the benchmarks/tests from the command line and plot the | 292 """Run the benchmarks/tests from the command line and plot the |
| 259 results.""" | 293 results.""" |
| 260 plt.cla() # cla = clear current axes | 294 plt.cla() # cla = clear current axes |
| 261 os.chdir(DART_INSTALL_LOCATION) | 295 os.chdir(DART_INSTALL_LOCATION) |
| 262 EnsureOutputDirectory(self.result_folder_name) | 296 EnsureOutputDirectory(self.result_folder_name) |
| 263 EnsureOutputDirectory(GRAPH_OUT_DIR) | 297 EnsureOutputDirectory(GRAPH_OUT_DIR) |
| 264 self.RunTests() | 298 self.RunTests() |
| 265 os.chdir(os.path.join('tools', 'testing', 'perf_testing')) | 299 os.chdir(os.path.join('tools', 'testing', 'perf_testing')) |
| 266 | 300 |
| 267 # TODO(efortuna): You will want to make this only use a subset of the files | 301 # TODO(efortuna): You will want to make this only use a subset of the files |
| 268 # eventually. | 302 # eventually. |
| 269 files = os.listdir(self.result_folder_name) | 303 files = os.listdir(self.result_folder_name) |
| 270 | 304 |
| 271 for afile in files: | 305 if PERFBOT_MODE: |
| 272 if not afile.startswith('.'): | 306 for afile in files: |
| 273 self.ProcessFile(afile) | 307 if not afile.startswith('.'): |
| 274 self.PlotResults('%s.png' % self.result_folder_name) | 308 self.ProcessFile(afile) |
| 309 |
| 310 self.PlotResults('%s.png' % self.result_folder_name) |
| 311 self.Cleanup(); |
| 275 | 312 |
| 276 class PerformanceTestRunner(TestRunner): | 313 class PerformanceTestRunner(TestRunner): |
| 277 """Super class for all performance testing.""" | 314 """Super class for all performance testing.""" |
| 278 def __init__(self, result_folder_name, platform_list, platform_type): | 315 def __init__(self, result_folder_name, platform_list, platform_type): |
| 279 super(PerformanceTestRunner, self).__init__(result_folder_name, | 316 super(PerformanceTestRunner, self).__init__(result_folder_name, |
| 280 platform_list, V8_AND_FROG, BENCHMARKS) | 317 platform_list, GetVersions(), BENCHMARKS) |
| 281 self.platform_list = platform_list | 318 self.platform_list = platform_list |
| 282 self.platform_type = platform_type | 319 self.platform_type = platform_type |
| 283 | 320 |
| 284 def PlotAllPerf(self, png_filename): | 321 def PlotAllPerf(self, png_filename): |
| 285 """Create a plot that shows the performance changes of individual benchmarks | 322 """Create a plot that shows the performance changes of individual benchmarks |
| 286 run by V8 and generated by frog, over svn history.""" | 323 run by V8 and generated by frog, over svn history.""" |
| 287 for benchmark in BENCHMARKS: | 324 for benchmark in BENCHMARKS: |
| 288 self.StyleAndSavePerfPlot( | 325 self.StyleAndSavePerfPlot( |
| 289 'Performance of %s over time on the %s' % (benchmark, | 326 'Performance of %s over time on the %s' % (benchmark, |
| 290 self.platform_type), 'Speed (bigger = better)', 16, 14, 'lower left', | 327 self.platform_type), 'Speed (bigger = better)', 16, 14, 'lower left', |
| 291 benchmark + png_filename, self.platform_list, V8_AND_FROG, | 328 benchmark + png_filename, self.platform_list, GetVersions(), |
| 292 [benchmark]) | 329 [benchmark]) |
| 293 | 330 |
| 294 def PlotAvgPerf(self, png_filename): | 331 def PlotAvgPerf(self, png_filename): |
| 295 """Generate a plot that shows the performance changes of the geomentric mean | 332 """Generate a plot that shows the performance changes of the geomentric mean |
| 296 of V8 and frog benchmark performance over svn history.""" | 333 of V8 and frog benchmark performance over svn history.""" |
| 297 (title, y_axis, size_x, size_y, loc, filename) = \ | 334 (title, y_axis, size_x, size_y, loc, filename) = \ |
| 298 ('Geometric Mean of benchmark %s performance' % self.platform_type, | 335 ('Geometric Mean of benchmark %s performance' % self.platform_type, |
| 299 'Speed (bigger = better)', 16, 5, 'center', 'avg'+png_filename) | 336 'Speed (bigger = better)', 16, 5, 'center', 'avg'+png_filename) |
| 300 for platform in self.platform_list: | 337 for platform in self.platform_list: |
| 301 self.StyleAndSavePerfPlot(title, y_axis, size_x, size_y, loc, filename, | 338 self.StyleAndSavePerfPlot(title, y_axis, size_x, size_y, loc, filename, |
| 302 [platform], [V8], [V8_MEAN], True) | 339 [platform], [V8], [V8_MEAN], True) |
| 303 self.StyleAndSavePerfPlot(title, y_axis, size_x, size_y, loc, filename, | 340 self.StyleAndSavePerfPlot(title, y_axis, size_x, size_y, loc, filename, |
| 304 [platform], [FROG], [FROG_MEAN], False) | 341 [platform], [FROG], [FROG_MEAN], False) |
| 305 self.WriteHtml('table', | 342 self.WriteHtml('table', |
| 306 self.revision_dict[platform][V8], | 343 self.revision_dict[platform][V8], |
| 307 'V8 mean', self.values_dict[platform][V8][V8_MEAN], | 344 'V8 mean', self.values_dict[platform][V8][V8_MEAN], |
| 308 'Frog mean', self.values_dict[platform][FROG][FROG_MEAN], | 345 'Frog mean', self.values_dict[platform][FROG][FROG_MEAN], |
| 309 True) | 346 True) |
| 310 | 347 |
| 311 def PlotResults(self, png_filename): | 348 def PlotResults(self, png_filename): |
| 312 self.PlotAllPerf(png_filename) | 349 self.PlotAllPerf(png_filename) |
| 313 self.PlotAvgPerf('2' + png_filename) | 350 self.PlotAvgPerf('2' + png_filename) |
| 314 | 351 |
| 352 |
| 315 class CommandLinePerformanceTestRunner(PerformanceTestRunner): | 353 class CommandLinePerformanceTestRunner(PerformanceTestRunner): |
| 316 """Run performance tests from the command line.""" | 354 """Run performance tests from the command line.""" |
| 317 | 355 |
| 318 def __init__(self, result_folder_name): | 356 def __init__(self, result_folder_name): |
| 319 super(CommandLinePerformanceTestRunner, self).__init__(result_folder_name, | 357 super(CommandLinePerformanceTestRunner, self).__init__(result_folder_name, |
| 320 [COMMAND_LINE], 'command line') | 358 [COMMAND_LINE], 'command line') |
| 321 | 359 |
| 322 def ProcessFile(self, afile): | 360 def ProcessFile(self, afile): |
| 323 """Pull all the relevant information out of a given tracefile. | 361 """Pull all the relevant information out of a given tracefile. |
| 324 | 362 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 349 self.revision_dict[COMMAND_LINE][FROG][benchmark] += [revision_num] | 387 self.revision_dict[COMMAND_LINE][FROG][benchmark] += [revision_num] |
| 350 self.values_dict[COMMAND_LINE][FROG][benchmark] += [frog_value] | 388 self.values_dict[COMMAND_LINE][FROG][benchmark] += [frog_value] |
| 351 f.close() | 389 f.close() |
| 352 | 390 |
| 353 self.CalculateGeometricMean(COMMAND_LINE, FROG, revision_num) | 391 self.CalculateGeometricMean(COMMAND_LINE, FROG, revision_num) |
| 354 self.CalculateGeometricMean(COMMAND_LINE, V8, revision_num) | 392 self.CalculateGeometricMean(COMMAND_LINE, V8, revision_num) |
| 355 | 393 |
| 356 def RunTests(self): | 394 def RunTests(self): |
| 357 """Run a performance test on our updated system.""" | 395 """Run a performance test on our updated system.""" |
| 358 os.chdir('frog') | 396 os.chdir('frog') |
| 359 file_path = os.path.join('..', 'tools', 'testing', 'perf_testing', | 397 self.trace_file = os.path.join('..', 'tools', 'testing', 'perf_testing', |
| 360 self.result_folder_name, 'result') | 398 self.result_folder_name, 'result' + self.cur_time) |
| 361 RunCmd('python %s > %s%s' % (os.path.join('benchmarks', | 399 RunCmd(['python', os.path.join('benchmarks', 'perf_tests.py')], |
| 362 'perf_tests.py'), file_path, self.cur_time)) | 400 self.trace_file) |
| 363 os.chdir('..') | 401 os.chdir('..') |
| 364 | 402 |
| 365 | 403 |
| 366 class BrowserPerformanceTestRunner(PerformanceTestRunner): | 404 class BrowserPerformanceTestRunner(PerformanceTestRunner): |
| 367 """Runs performance tests, in the browser.""" | 405 """Runs performance tests, in the browser.""" |
| 368 | 406 |
| 369 def __init__(self, result_folder_name): | 407 def __init__(self, result_folder_name): |
| 370 super(BrowserPerformanceTestRunner, self).__init__( | 408 super(BrowserPerformanceTestRunner, self).__init__( |
| 371 result_folder_name, GetBrowsers(), 'browser') | 409 result_folder_name, GetBrowsers(), 'browser') |
| 372 | 410 |
| 373 def RunTests(self): | 411 def RunTests(self): |
| 374 """Run a performance test in the browser.""" | 412 """Run a performance test in the browser.""" |
| 375 os.chdir('frog') | 413 os.chdir('frog') |
| 376 RunCmd('python benchmarks/make_web_benchmarks.py') | 414 RunCmd(['python', os.path.join('benchmarks', 'make_web_benchmarks.py')]) |
| 377 os.chdir('..') | 415 os.chdir('..') |
| 378 | 416 |
| 379 for browser in GetBrowsers(): | 417 for browser in GetBrowsers(): |
| 380 for version in V8_AND_FROG: | 418 for version in GetVersions(): |
| 381 self.AddSvnRevisionToTrace(os.path.join('tools', 'testing', | 419 self.trace_file = os.path.join('tools', 'testing', 'perf_testing', |
| 382 'perf_testing', self.result_folder_name, | 420 self.result_folder_name, |
| 383 'perf-%s-%s-%s' % (self.cur_time, browser, version))) | 421 'perf-%s-%s-%s' % (self.cur_time, browser, version)) |
| 384 RunCmd('python %s --out %s --browser %s --timeout 1000 --perf >> %s' % | 422 self.AddSvnRevisionToTrace(self.trace_file) |
| 385 (os.path.join('tools', 'testing', 'run_selenium.py'), | 423 RunCmd(['python', os.path.join('tools', 'testing', 'run_selenium.py'), |
| 386 os.path.join(os.getcwd(), 'internal', 'browserBenchmarks', | 424 '--out', os.path.join(os.getcwd(), 'internal', 'browserBenchmarks', |
| 387 'benchmark_page_%s.html' % version), | 425 'benchmark_page_%s.html' % version), '--browser', browser, |
| 388 browser, | 426 '--timeout', '600', '--perf'], self.trace_file, append=True) |
| 389 os.path.join('tools', 'testing', 'perf_testing', | |
| 390 self.result_folder_name, 'perf-%s-%s-%s' % (self.cur_time, browser, | |
| 391 version)))) | |
| 392 | 427 |
| 393 def ProcessFile(self, afile): | 428 def ProcessFile(self, afile): |
| 394 """Comb through the html to find the performance results.""" | 429 """Comb through the html to find the performance results.""" |
| 395 parts = afile.split('-') | 430 parts = afile.split('-') |
| 396 browser = parts[2] | 431 browser = parts[2] |
| 397 version = parts[3] | 432 version = parts[3] |
| 398 f = open(os.path.join(self.result_folder_name, afile)) | 433 f = open(os.path.join(self.result_folder_name, afile)) |
| 399 lines = f.readlines() | 434 lines = f.readlines() |
| 400 line = '' | 435 line = '' |
| 401 i = 0 | 436 i = 0 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 431 self.revision_dict[browser][version][name] += [revision_num] | 466 self.revision_dict[browser][version][name] += [revision_num] |
| 432 | 467 |
| 433 f.close() | 468 f.close() |
| 434 self.CalculateGeometricMean(browser, version, revision_num) | 469 self.CalculateGeometricMean(browser, version, revision_num) |
| 435 | 470 |
| 436 def WriteHtml(self, delimiter, rev_nums, label_1, dict_1, label_2, dict_2, | 471 def WriteHtml(self, delimiter, rev_nums, label_1, dict_1, label_2, dict_2, |
| 437 cleanFile=False): | 472 cleanFile=False): |
| 438 #TODO(efortuna) | 473 #TODO(efortuna) |
| 439 pass | 474 pass |
| 440 | 475 |
| 476 |
| 477 def Cleanup(): |
| 478 # Kill the zombie chromedriver processes. |
| 479 RunCmd(['killall', 'chromedriver']) |
| 480 |
| 481 |
| 441 class BrowserCorrectnessTestRunner(TestRunner): | 482 class BrowserCorrectnessTestRunner(TestRunner): |
| 442 def __init__(self, test_type, result_folder_name): | 483 def __init__(self, test_type, result_folder_name): |
| 443 super(BrowserCorrectnessTestRunner, self).__init__(result_folder_name, | 484 super(BrowserCorrectnessTestRunner, self).__init__(result_folder_name, |
| 444 GetBrowsers(), [FROG], [CORRECTNESS]) | 485 GetBrowsers(), [FROG], [CORRECTNESS]) |
| 445 self.test_type = test_type | 486 self.test_type = test_type |
| 446 | 487 |
| 447 def RunTests(self): | 488 def RunTests(self): |
| 448 """Run a test of the latest svn revision.""" | 489 """Run a test of the latest svn revision.""" |
| 449 for browser in GetBrowsers(): | 490 for browser in GetBrowsers(): |
| 450 current_file = 'correctness%s-%s' % (self.cur_time, browser) | 491 current_file = 'correctness%s-%s' % (self.cur_time, browser) |
| 451 current_file_path = os.path.join('tools', 'testing', | 492 self.trace_file = os.path.join('tools', 'testing', |
| 452 'perf_testing', self.result_folder_name, current_file) | 493 'perf_testing', self.result_folder_name, current_file) |
| 453 self.AddSvnRevisionToTrace(current_file_path) | 494 self.AddSvnRevisionToTrace(self.trace_file) |
| 454 RunCmd(os.path.join('.', 'tools', 'test.py') + | 495 RunCmd([os.path.join('.', 'tools', 'test.py'), |
| 455 ' --component=webdriver --flag=%s --report --timeout=20 ' % browser + | 496 '--component=webdriver', '--flag=%s' % browser, '--report', |
| 456 '--progress=color --mode=release -j1 %s >>' % self.test_type + | 497 '--timeout=20', '--progress=color', '--mode=release', '-j1', |
| 457 current_file_path) | 498 self.test_type], self.trace_file, append=True) |
| 458 | 499 |
| 459 def ProcessFile(self, afile): | 500 def ProcessFile(self, afile): |
| 460 """Given a trace file, extract all the relevant information out of it to | 501 """Given a trace file, extract all the relevant information out of it to |
| 461 determine the number of correctly passing tests. | 502 determine the number of correctly passing tests. |
| 462 | 503 |
| 463 Arguments: | 504 Arguments: |
| 464 afile the filename string""" | 505 afile the filename string""" |
| 465 browser = afile.rpartition('-')[2] | 506 browser = afile.rpartition('-')[2] |
| 466 f = open(os.path.join(self.result_folder_name, afile)) | 507 f = open(os.path.join(self.result_folder_name, afile)) |
| 467 revision_num = 0 | 508 revision_num = 0 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 489 f.close() | 530 f.close() |
| 490 | 531 |
| 491 def PlotResults(self, png_filename): | 532 def PlotResults(self, png_filename): |
| 492 first_time = True | 533 first_time = True |
| 493 for browser in GetBrowsers(): | 534 for browser in GetBrowsers(): |
| 494 self.StyleAndSavePerfPlot('Percentage of language tests passing in ' | 535 self.StyleAndSavePerfPlot('Percentage of language tests passing in ' |
| 495 'different browsers', '% of tests passed', 8, 8, 'lower left', | 536 'different browsers', '% of tests passed', 8, 8, 'lower left', |
| 496 png_filename, [browser], [FROG], [CORRECTNESS], first_time) | 537 png_filename, [browser], [FROG], [CORRECTNESS], first_time) |
| 497 first_time = False | 538 first_time = False |
| 498 | 539 |
| 540 def Cleanup(): |
| 541 # Kill the zombie chromedriver processes. |
| 542 RunCmd(['killall', 'chromedriver']) |
| 499 | 543 |
| 500 class CompileTimeAndSizeTestRunner(TestRunner): | 544 class CompileTimeAndSizeTestRunner(TestRunner): |
| 501 """Run tests to determine how long frogsh takes to compile, and the compiled | 545 """Run tests to determine how long frogsh takes to compile, and the compiled |
| 502 file output size of some benchmarking files.""" | 546 file output size of some benchmarking files.""" |
| 503 def __init__(self, result_folder_name): | 547 def __init__(self, result_folder_name): |
| 504 super(CompileTimeAndSizeTestRunner, self).__init__(result_folder_name, | 548 super(CompileTimeAndSizeTestRunner, self).__init__(result_folder_name, |
| 505 [COMMAND_LINE], [FROG], ['Compiling on Dart VM', 'Bootstrapping', | 549 [COMMAND_LINE], [FROG], ['Compiling on Dart VM', 'Bootstrapping', |
| 506 'frogsh', 'swarm', 'total']) | 550 'frogsh', 'swarm', 'total']) |
| 507 self.failure_threshold = {'Compiling on Dart VM' : 1, 'Bootstrapping' : .5, | 551 self.failure_threshold = {'Compiling on Dart VM' : 1, 'Bootstrapping' : .5, |
| 508 'frogsh' : 100, 'swarm' : 100, 'total' : 100} | 552 'frogsh' : 100, 'swarm' : 100, 'total' : 100} |
| 509 | 553 |
| 510 def RunTests(self): | 554 def RunTests(self): |
| 511 os.chdir('frog') | 555 os.chdir('frog') |
| 512 current_file_path = os.path.join('..', 'tools', 'testing', 'perf_testing', | 556 self.trace_file = os.path.join('..', 'tools', 'testing', 'perf_testing', |
| 513 self.result_folder_name, self.result_folder_name + self.cur_time) | 557 self.result_folder_name, self.result_folder_name + self.cur_time) |
| 514 | 558 |
| 515 self.AddSvnRevisionToTrace(current_file_path) | 559 self.AddSvnRevisionToTrace(self.trace_file) |
| 516 | 560 |
| 517 elapsed = TimeCmd(os.path.join('.', 'frog.py') + | 561 elapsed = TimeCmd([os.path.join('.', 'frog.py'), |
| 518 ' --vm_flags="--compile_all --enable_type_checks --enable_asserts" --' | 562 '--vm_flags="--compile_all --enable_type_checks --enable_asserts"', |
| 519 ' --compile_all --enable_type_checks --out=frogsh frog.dart') | 563 '--', '--compile_all', '--enable_type_checks', '--out=frogsh', |
| 520 RunCmd('echo "%f Compiling on Dart VM in checked mode in' % elapsed + | 564 'frog.dart']) |
| 521 ' seconds" >> %s' % current_file_path) | 565 RunCmd(['echo', '%f Compiling on Dart VM in checked mode in seconds' |
| 522 RunCmd('chmod +x frogsh') | 566 % elapsed], self.trace_file, append=True) |
| 523 elapsed = TimeCmd(os.path.join('.', 'frogsh') + ' --out=frogsh ' | 567 elapsed = TimeCmd([os.path.join('.', 'frogsh'), '--out=frogsh', |
| 524 '--enable_type_checks frog.dart --enable_type_checks ' + | 568 '--enable_type_checks', 'frog.dart', '--enable_type_checks', |
| 525 os.path.join('tests', 'hello.dart')) | 569 os.path.join('tests', 'hello.dart')]) |
| 526 if elapsed < self.failure_threshold['Bootstrapping']: | 570 if elapsed < self.failure_threshold['Bootstrapping']: |
| 527 #frogsh didn't compile correctly. Stop testing now, because subsequent | 571 #frogsh didn't compile correctly. Stop testing now, because subsequent |
| 528 #numbers will be meaningless. | 572 #numbers will be meaningless. |
| 529 return | 573 return |
| 530 size = os.path.getsize('frogsh') | 574 size = os.path.getsize('frogsh') |
| 531 RunCmd('echo "%f Bootstrapping time in seconds in checked mode"' % | 575 RunCmd(['echo', '%f Bootstrapping time in seconds in checked mode' % |
| 532 elapsed + ' >> %s' % current_file_path) | 576 elapsed], self.trace_file, append=True) |
| 533 RunCmd('echo "%d Generated checked frogsh size "' % size + | 577 RunCmd(['echo', '%d Generated checked frogsh size' % size], |
| 534 ' >> %s' % current_file_path) | 578 self.trace_file, append=True) |
| 535 | 579 |
| 536 RunCmd(os.path.join('.', 'frogsh') + ' --out=swarm-result ' | 580 RunCmd([os.path.join('.', 'frogsh'), ' --out=swarm-result ', |
| 537 '--compile-only ' + os.path.join('..', 'client', 'samples', 'swarm', | 581 '--compile-only', os.path.join('..', 'client', 'samples', 'swarm', |
| 538 'swarm.dart')) | 582 'swarm.dart')]) |
| 539 swarm_size = 0 | 583 swarm_size = 0 |
| 540 try: | 584 try: |
| 541 swarm_size = os.path.getsize('swarm-result') | 585 swarm_size = os.path.getsize('swarm-result') |
| 542 except OSError: | 586 except OSError: |
| 543 pass #If compilation failed, continue on running other tests. | 587 pass #If compilation failed, continue on running other tests. |
| 544 | 588 |
| 545 RunCmd(os.path.join('.', 'frogsh') + ' --out=total-result ' | 589 RunCmd([os.path.join('.', 'frogsh'), '--out=total-result', |
| 546 '--compile-only ' + os.path.join('..', 'client', 'samples', 'total', | 590 '--compile-only', os.path.join('..', 'client', 'samples', 'total', |
| 547 'src', 'Total.dart')) | 591 'src', 'Total.dart')]) |
| 548 total_size = 0 | 592 total_size = 0 |
| 549 try: | 593 try: |
| 550 total_size = os.path.getsize('total-result') | 594 total_size = os.path.getsize('total-result') |
| 551 except OSError: | 595 except OSError: |
| 552 pass #If compilation failed, continue on running other tests. | 596 pass #If compilation failed, continue on running other tests. |
| 553 | 597 |
| 554 RunCmd('echo "%d Generated checked swarm size "' % swarm_size + | 598 RunCmd(['echo', '%d Generated checked swarm size' % swarm_size], |
| 555 ' >> %s' % current_file_path) | 599 self.trace_file, append=True) |
| 556 | 600 |
| 557 RunCmd('echo "%d Generated checked total size "' % total_size + | 601 RunCmd(['echo', '%d Generated checked total size' % total_size], |
| 558 ' >> %s' % current_file_path) | 602 self.trace_file, append=True) |
| 559 os.chdir('..') | 603 os.chdir('..') |
| 560 | 604 |
| 561 def ProcessFile(self, afile): | 605 def ProcessFile(self, afile): |
| 562 """Pull all the relevant information out of a given tracefile. | 606 """Pull all the relevant information out of a given tracefile. |
| 563 Args: | 607 Args: |
| 564 afile is the filename string we will be processing.""" | 608 afile is the filename string we will be processing.""" |
| 565 f = open(os.path.join(self.result_folder_name, afile)) | 609 f = open(os.path.join(self.result_folder_name, afile)) |
| 566 tabulate_data = False | 610 tabulate_data = False |
| 567 revision_num = 0 | 611 revision_num = 0 |
| 568 for line in f.readlines(): | 612 for line in f.readlines(): |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 600 'frogsh size', self.values_dict[COMMAND_LINE][FROG]['frogsh'], '', []) | 644 'frogsh size', self.values_dict[COMMAND_LINE][FROG]['frogsh'], '', []) |
| 601 | 645 |
| 602 self.StyleAndSavePerfPlot('Time to compile and bootstrap', | 646 self.StyleAndSavePerfPlot('Time to compile and bootstrap', |
| 603 'Seconds', 10, 10, 'center', '2' + png_filename, [COMMAND_LINE], [FROG], | 647 'Seconds', 10, 10, 'center', '2' + png_filename, [COMMAND_LINE], [FROG], |
| 604 ['Bootstrapping', 'Compiling on Dart VM']) | 648 ['Bootstrapping', 'Compiling on Dart VM']) |
| 605 self.WriteHtml('baz', | 649 self.WriteHtml('baz', |
| 606 self.revision_dict[COMMAND_LINE][FROG]['Bootstrapping'], | 650 self.revision_dict[COMMAND_LINE][FROG]['Bootstrapping'], |
| 607 'Bootstrapping', self.values_dict[COMMAND_LINE][FROG]['Bootstrapping'], | 651 'Bootstrapping', self.values_dict[COMMAND_LINE][FROG]['Bootstrapping'], |
| 608 'Compiling on Dart VM', | 652 'Compiling on Dart VM', |
| 609 self.values_dict[COMMAND_LINE][FROG]['Compiling on Dart VM']) | 653 self.values_dict[COMMAND_LINE][FROG]['Compiling on Dart VM']) |
| 610 | 654 |
| 655 |
| 656 def ParseArgs(): |
| 657 parser = optparse.OptionParser() |
| 658 parser.add_option('--command-line', '-c', dest='cl', |
| 659 help = 'Run the command line tests', |
| 660 action = 'store_true', default = False) |
| 661 parser.add_option('--size-time', '-s', dest = 'size', |
| 662 help = 'Run the code size and timing tests', |
| 663 action = 'store_true', default = False) |
| 664 parser.add_option('--language', '-l', dest = 'language', |
| 665 help = 'Run the language correctness tests', |
| 666 action = 'store_true', default = False) |
| 667 parser.add_option('--browser-perf', '-b', dest = 'perf', |
| 668 help = 'Run the browser performance tests', |
| 669 action = 'store_true', default = False) |
| 670 parser.add_option('--forever', '-f', dest = 'continuous', |
| 671 help = 'Run this script forever, always checking for the next svn ' |
| 672 'checkin', action = 'store_true', default = False) |
| 673 parser.add_option('--perfbot', '-p', dest = 'perfbot', |
| 674 help = "Run in perfbot mode. (Generate plots, and remove trace files)", |
| 675 action = 'store_true', default = False) |
| 676 parser.add_option('--verbose', '-v', dest = 'verbose', |
| 677 help = 'Print extra debug output', action = 'store_true', default = False) |
| 678 |
| 679 args, ignored = parser.parse_args() |
| 680 if not (args.cl or args.size or args.language or args.perf): |
| 681 args.cl = args.size = args.language = args.perf = True |
| 682 return (args.cl, args.size, args.language, args.perf, args.continuous, |
| 683 args.perfbot, args.verbose) |
| 684 |
| 685 def RunTestSequence(cl, size, language, perf): |
| 686 if PERFBOT_MODE: |
| 687 # The buildbot already builds and syncs to a specific revision. Don't fight |
| 688 # with it or replicate work. |
| 689 SyncAndBuild() |
| 690 if cl: |
| 691 CommandLinePerformanceTestRunner('cl-results').Run() |
| 692 if size: |
| 693 CompileTimeAndSizeTestRunner('code-time-size').Run() |
| 694 if language: |
| 695 BrowserCorrectnessTestRunner('language', 'browser-correctness').Run() |
| 696 if perf: |
| 697 BrowserPerformanceTestRunner('browser-perf').Run() |
| 611 | 698 |
| 612 def main(): | 699 def main(): |
| 613 if HasNewCode(): | 700 global PERFBOT_MODE, VERBOSE |
| 614 SyncAndBuild() | 701 (cl, size, language, perf, continuous, perfbot, verbose) = ParseArgs() |
| 615 CommandLinePerformanceTestRunner('cl-results').Run() | 702 PERFBOT_MODE = perfbot |
| 616 CompileTimeAndSizeTestRunner('code-time-size').Run() | 703 VERBOSE = verbose |
| 617 BrowserCorrectnessTestRunner('language', 'browser-correctness').Run() | 704 if continuous: |
| 618 BrowserPerformanceTestRunner('browser-perf').Run() | 705 while True: |
| 706 if HasNewCode(): |
| 707 RunTestSequence(cl, size, language, perf) |
| 708 else: |
| 709 time.sleep(SLEEP_TIME) |
| 710 else: |
| 711 RunTestSequence(cl, size, language, perf) |
| 619 | 712 |
| 620 if __name__ == '__main__': | 713 if __name__ == '__main__': |
| 621 main() | 714 main() |
| 622 | 715 |
| OLD | NEW |