| 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 try: | 9 try: |
| 10 from matplotlib.font_manager import FontProperties | 10 from matplotlib.font_manager import FontProperties |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 | 26 |
| 27 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__)), |
| 28 '..', '..', '..') | 28 '..', '..', '..') |
| 29 V8_MEAN = 'V8 Mean' | 29 V8_MEAN = 'V8 Mean' |
| 30 FROG_MEAN = 'frog Mean' | 30 FROG_MEAN = 'frog Mean' |
| 31 COMMAND_LINE = 'commandline' | 31 COMMAND_LINE = 'commandline' |
| 32 V8 = 'v8' | 32 V8 = 'v8' |
| 33 FROG = 'frog' | 33 FROG = 'frog' |
| 34 V8_AND_FROG = [V8, FROG] | 34 V8_AND_FROG = [V8, FROG] |
| 35 CORRECTNESS = 'Percent passing' | 35 CORRECTNESS = 'Percent passing' |
| 36 BENCHMARKS = ['Mandelbrot', 'DeltaBlue', 'Richards', 'NBody', | |
| 37 'BinaryTrees', 'Fannkuch', 'Meteor', 'BubbleSort', 'Fibonacci', | |
| 38 'Loop', 'Permute', 'Queens', 'QuickSort', 'Recurse', 'Sieve', 'Sum', | |
| 39 'Tak', 'Takl', 'Towers', 'TreeSort'] | |
| 40 COLORS = ['blue', 'green', 'red', 'cyan', 'magenta', 'black'] | 36 COLORS = ['blue', 'green', 'red', 'cyan', 'magenta', 'black'] |
| 41 GRAPH_OUT_DIR = 'graphs' | 37 GRAPH_OUT_DIR = 'graphs' |
| 42 SLEEP_TIME = 200 | 38 SLEEP_TIME = 200 |
| 43 PERFBOT_MODE = False | 39 PERFBOT_MODE = False |
| 44 VERBOSE = False | 40 VERBOSE = False |
| 45 | 41 |
| 46 """First, some utility methods.""" | 42 """First, some utility methods.""" |
| 47 | 43 |
| 48 def RunCmd(cmd_list, outfile=None, append=False): | 44 def RunCmd(cmd_list, outfile=None, append=False): |
| 49 """Run the specified command and print out any output to stdout. | 45 """Run the specified command and print out any output to stdout. |
| 50 Args: | 46 Args: |
| 51 cmd_list a list of strings that make up the command to run | 47 cmd_list a list of strings that make up the command to run |
| 52 outfile a string indicating the name of the file that we should write stdout | 48 outfile a string indicating the name of the file that we should write stdout |
| 53 to | 49 to |
| 54 append True if we want to append to the file instead of overwriting it""" | 50 append True if we want to append to the file instead of overwriting it""" |
| 55 if VERBOSE: | 51 if VERBOSE: |
| 56 print ' '.join(cmd_list) | 52 print ' '.join(cmd_list) |
| 57 out = subprocess.PIPE | 53 out = subprocess.PIPE |
| 58 if outfile: | 54 if outfile: |
| 59 mode = 'w' | 55 mode = 'w' |
| 60 if append: | 56 if append: |
| 61 mode = 'a' | 57 mode = 'a' |
| 62 out = open(outfile, mode) | 58 out = open(outfile, mode) |
| 63 p = subprocess.Popen(cmd_list, stdout = out, stderr = subprocess.PIPE) | 59 p = '' |
| 60 if platform.system() == 'Windows': |
| 61 # On Windows, shell must be true to get the correct environment variables. |
| 62 p = subprocess.Popen(cmd_list, stdout = out, stderr = subprocess.PIPE, |
| 63 shell=True) |
| 64 else: |
| 65 p = subprocess.Popen(cmd_list, stdout = out, stderr = subprocess.PIPE) |
| 64 output, not_used = p.communicate(); | 66 output, not_used = p.communicate(); |
| 65 if output: | 67 if output: |
| 66 print output | 68 print output |
| 67 return output | 69 return output |
| 68 | 70 |
| 69 def TimeCmd(cmd): | 71 def TimeCmd(cmd): |
| 70 """Determine the amount of (real) time it takes to execute a given command.""" | 72 """Determine the amount of (real) time it takes to execute a given command.""" |
| 71 start = time.time() | 73 start = time.time() |
| 72 RunCmd(cmd) | 74 RunCmd(cmd) |
| 73 return time.time() - start | 75 return time.time() - start |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 if platform.system() == 'Windows': | 144 if platform.system() == 'Windows': |
| 143 browsers += ['ie'] | 145 browsers += ['ie'] |
| 144 return browsers | 146 return browsers |
| 145 | 147 |
| 146 def GetVersions(): | 148 def GetVersions(): |
| 147 if not PERFBOT_MODE: | 149 if not PERFBOT_MODE: |
| 148 return [FROG] | 150 return [FROG] |
| 149 else: | 151 else: |
| 150 return V8_AND_FROG | 152 return V8_AND_FROG |
| 151 | 153 |
| 154 def GetBenchmarks(): |
| 155 if not PERFBOT_MODE: |
| 156 return ['Smoketest'] |
| 157 else: |
| 158 return ['Mandelbrot', 'DeltaBlue', 'Richards', 'NBody', 'BinaryTrees', |
| 159 'Fannkuch', 'Meteor', 'BubbleSort', 'Fibonacci', 'Loop', 'Permute', |
| 160 'Queens', 'QuickSort', 'Recurse', 'Sieve', 'Sum', 'Tak', 'Takl', 'Towers', |
| 161 'TreeSort'] |
| 162 |
| 152 def UploadToAppEngine(): | 163 def UploadToAppEngine(): |
| 153 """Upload our results to our appengine server.""" | 164 """Upload our results to our appengine server.""" |
| 154 # TODO(efortuna): This is the most basic way to get the data up | 165 # TODO(efortuna): This is the most basic way to get the data up |
| 155 # for others to view. Revisit this once we're serving nicer graphs (Google | 166 # for others to view. Revisit this once we're serving nicer graphs (Google |
| 156 # Chart Tools) and from multiple perfbots and once we're in a position to | 167 # Chart Tools) and from multiple perfbots and once we're in a position to |
| 157 # organize the data in a useful manner(!!). | 168 # organize the data in a useful manner(!!). |
| 158 os.chdir(os.path.join(DART_INSTALL_LOCATION, 'tools', 'testing', | 169 os.chdir(os.path.join(DART_INSTALL_LOCATION, 'tools', 'testing', |
| 159 'perf_testing')) | 170 'perf_testing')) |
| 160 shutil.rmtree(os.path.join('appengine', 'static', 'graphs'), | 171 shutil.rmtree(os.path.join('appengine', 'static', 'graphs'), |
| 161 ignore_errors=True) | 172 ignore_errors=True) |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 289 out.write('<td>%f</td>' % perf) | 300 out.write('<td>%f</td>' % perf) |
| 290 out.write('</tr>\n<tr><td> %s</td>' % label_2) | 301 out.write('</tr>\n<tr><td> %s</td>' % label_2) |
| 291 for perf in dict_2: | 302 for perf in dict_2: |
| 292 out.write('<td>%f</td>' % perf) | 303 out.write('<td>%f</td>' % perf) |
| 293 out.write('</tr> </table>') | 304 out.write('</tr> </table>') |
| 294 | 305 |
| 295 def CalculateGeometricMean(self, platform, frog_or_v8, svn_revision): | 306 def CalculateGeometricMean(self, platform, frog_or_v8, svn_revision): |
| 296 """Calculate the aggregate geometric mean for V8 and frog benchmark sets, | 307 """Calculate the aggregate geometric mean for V8 and frog benchmark sets, |
| 297 given two benchmark dictionaries.""" | 308 given two benchmark dictionaries.""" |
| 298 geo_mean = 0 | 309 geo_mean = 0 |
| 299 for benchmark in BENCHMARKS: | 310 for benchmark in GetBenchmarks(): |
| 300 geo_mean += math.log(self.values_dict[platform][frog_or_v8][benchmark][ | 311 geo_mean += math.log(self.values_dict[platform][frog_or_v8][benchmark][ |
| 301 len(self.values_dict[platform][frog_or_v8][benchmark]) - 1]) | 312 len(self.values_dict[platform][frog_or_v8][benchmark]) - 1]) |
| 302 | 313 |
| 303 mean = V8_MEAN | 314 mean = V8_MEAN |
| 304 if frog_or_v8 == FROG: | 315 if frog_or_v8 == FROG: |
| 305 mean = FROG_MEAN | 316 mean = FROG_MEAN |
| 306 self.values_dict[platform][frog_or_v8][mean] += \ | 317 self.values_dict[platform][frog_or_v8][mean] += \ |
| 307 [math.pow(math.e, geo_mean / len(BENCHMARKS))] | 318 [math.pow(math.e, geo_mean / len(GetBenchmarks()))] |
| 308 self.revision_dict[platform][frog_or_v8][mean] += [svn_revision] | 319 self.revision_dict[platform][frog_or_v8][mean] += [svn_revision] |
| 309 | 320 |
| 310 def Run(self): | 321 def Run(self): |
| 311 """Run the benchmarks/tests from the command line and plot the | 322 """Run the benchmarks/tests from the command line and plot the |
| 312 results.""" | 323 results.""" |
| 313 if PERFBOT_MODE: | 324 if PERFBOT_MODE: |
| 314 plt.cla() # cla = clear current axes | 325 plt.cla() # cla = clear current axes |
| 315 os.chdir(DART_INSTALL_LOCATION) | 326 os.chdir(DART_INSTALL_LOCATION) |
| 316 EnsureOutputDirectory(self.result_folder_name) | 327 EnsureOutputDirectory(self.result_folder_name) |
| 317 EnsureOutputDirectory(GRAPH_OUT_DIR) | 328 EnsureOutputDirectory(GRAPH_OUT_DIR) |
| 318 self.RunTests() | 329 self.RunTests() |
| 319 os.chdir(os.path.join('tools', 'testing', 'perf_testing')) | 330 os.chdir(os.path.join('tools', 'testing', 'perf_testing')) |
| 320 | 331 |
| 321 # TODO(efortuna): You will want to make this only use a subset of the files | 332 # TODO(efortuna): You will want to make this only use a subset of the files |
| 322 # eventually. | 333 # eventually. |
| 323 files = os.listdir(self.result_folder_name) | 334 files = os.listdir(self.result_folder_name) |
| 324 | 335 |
| 325 for afile in files: | 336 for afile in files: |
| 326 if not afile.startswith('.'): | 337 if not afile.startswith('.'): |
| 327 self.ProcessFile(afile) | 338 self.ProcessFile(afile) |
| 328 | 339 |
| 329 if PERFBOT_MODE: | 340 if PERFBOT_MODE: |
| 330 self.PlotResults('%s.png' % self.result_folder_name) | 341 self.PlotResults('%s.png' % self.result_folder_name) |
| 331 | 342 |
| 332 class PerformanceTestRunner(TestRunner): | 343 class PerformanceTestRunner(TestRunner): |
| 333 """Super class for all performance testing.""" | 344 """Super class for all performance testing.""" |
| 334 def __init__(self, result_folder_name, platform_list, platform_type): | 345 def __init__(self, result_folder_name, platform_list, platform_type): |
| 335 super(PerformanceTestRunner, self).__init__(result_folder_name, | 346 super(PerformanceTestRunner, self).__init__(result_folder_name, |
| 336 platform_list, GetVersions(), BENCHMARKS) | 347 platform_list, GetVersions(), GetBenchmarks()) |
| 337 self.platform_list = platform_list | 348 self.platform_list = platform_list |
| 338 self.platform_type = platform_type | 349 self.platform_type = platform_type |
| 339 | 350 |
| 340 def PlotAllPerf(self, png_filename): | 351 def PlotAllPerf(self, png_filename): |
| 341 """Create a plot that shows the performance changes of individual benchmarks | 352 """Create a plot that shows the performance changes of individual benchmarks |
| 342 run by V8 and generated by frog, over svn history.""" | 353 run by V8 and generated by frog, over svn history.""" |
| 343 for benchmark in BENCHMARKS: | 354 for benchmark in GetBenchmarks(): |
| 344 self.StyleAndSavePerfPlot( | 355 self.StyleAndSavePerfPlot( |
| 345 'Performance of %s over time on the %s' % (benchmark, | 356 'Performance of %s over time on the %s' % (benchmark, |
| 346 self.platform_type), 'Speed (bigger = better)', 16, 14, 'lower left', | 357 self.platform_type), 'Speed (bigger = better)', 16, 14, 'lower left', |
| 347 benchmark + png_filename, self.platform_list, GetVersions(), | 358 benchmark + png_filename, self.platform_list, GetVersions(), |
| 348 [benchmark]) | 359 [benchmark]) |
| 349 | 360 |
| 350 def PlotAvgPerf(self, png_filename): | 361 def PlotAvgPerf(self, png_filename): |
| 351 """Generate a plot that shows the performance changes of the geomentric mean | 362 """Generate a plot that shows the performance changes of the geomentric mean |
| 352 of V8 and frog benchmark performance over svn history.""" | 363 of V8 and frog benchmark performance over svn history.""" |
| 353 (title, y_axis, size_x, size_y, loc, filename) = \ | 364 (title, y_axis, size_x, size_y, loc, filename) = \ |
| (...skipping 30 matching lines...) Expand all Loading... |
| 384 f = open(os.path.join(self.result_folder_name, afile)) | 395 f = open(os.path.join(self.result_folder_name, afile)) |
| 385 tabulate_data = False | 396 tabulate_data = False |
| 386 revision_num = 0 | 397 revision_num = 0 |
| 387 for line in f.readlines(): | 398 for line in f.readlines(): |
| 388 if 'Revision' in line: | 399 if 'Revision' in line: |
| 389 revision_num = int(line.split()[1]) | 400 revision_num = int(line.split()[1]) |
| 390 elif 'Benchmark' in line: | 401 elif 'Benchmark' in line: |
| 391 tabulate_data = True | 402 tabulate_data = True |
| 392 elif tabulate_data: | 403 elif tabulate_data: |
| 393 tokens = line.split() | 404 tokens = line.split() |
| 394 if len(tokens) < 4 or tokens[0] not in BENCHMARKS: | 405 if len(tokens) < 4 or tokens[0] not in GetBenchmarks(): |
| 395 #Done tabulating data. | 406 #Done tabulating data. |
| 396 break | 407 break |
| 397 v8_value = float(tokens[1]) | 408 v8_value = float(tokens[1]) |
| 398 frog_value = float(tokens[3]) | 409 frog_value = float(tokens[3]) |
| 399 if v8_value == 0 or frog_value == 0: | 410 if v8_value == 0 or frog_value == 0: |
| 400 #Then there was an error when this performance test was run. Do not | 411 #Then there was an error when this performance test was run. Do not |
| 401 #count it in our numbers. | 412 #count it in our numbers. |
| 402 return | 413 return |
| 403 benchmark = tokens[0] | 414 benchmark = tokens[0] |
| 404 self.revision_dict[COMMAND_LINE][V8][benchmark] += [revision_num] | 415 self.revision_dict[COMMAND_LINE][V8][benchmark] += [revision_num] |
| (...skipping 21 matching lines...) Expand all Loading... |
| 426 def __init__(self, result_folder_name): | 437 def __init__(self, result_folder_name): |
| 427 super(BrowserPerformanceTestRunner, self).__init__( | 438 super(BrowserPerformanceTestRunner, self).__init__( |
| 428 result_folder_name, GetBrowsers(), 'browser') | 439 result_folder_name, GetBrowsers(), 'browser') |
| 429 | 440 |
| 430 def RunTests(self): | 441 def RunTests(self): |
| 431 """Run a performance test in the browser.""" | 442 """Run a performance test in the browser.""" |
| 432 # For the smoke test, just run a simple test, not the actual benchmarks to | 443 # For the smoke test, just run a simple test, not the actual benchmarks to |
| 433 # ensure we haven't broken the Firefox DOM. | 444 # ensure we haven't broken the Firefox DOM. |
| 434 | 445 |
| 435 os.chdir('frog') | 446 os.chdir('frog') |
| 436 RunCmd(['python', os.path.join('benchmarks', 'make_web_benchmarks.py')]) | 447 if PERFBOT_MODE: |
| 448 RunCmd(['python', os.path.join('benchmarks', 'make_web_benchmarks.py')]) |
| 449 else: |
| 450 RunCmd(['./minfrog', '--out=../tools/testing/perf_testing/smoketest/' + \ |
| 451 'smoketest_frog.js', '--libdir=%s/lib' % os.getcwd(), |
| 452 '--compile-only', '../tools/testing/perf_testing/smoketest/' + \ |
| 453 'dartWebBase.dart']) |
| 437 os.chdir('..') | 454 os.chdir('..') |
| 438 | 455 |
| 439 for browser in GetBrowsers(): | 456 for browser in GetBrowsers(): |
| 440 for version in GetVersions(): | 457 for version in GetVersions(): |
| 441 self.trace_file = os.path.join('tools', 'testing', 'perf_testing', | 458 self.trace_file = os.path.join('tools', 'testing', 'perf_testing', |
| 442 self.result_folder_name, | 459 self.result_folder_name, |
| 443 'perf-%s-%s-%s' % (self.cur_time, browser, version)) | 460 'perf-%s-%s-%s' % (self.cur_time, browser, version)) |
| 444 self.AddSvnRevisionToTrace(self.trace_file) | 461 self.AddSvnRevisionToTrace(self.trace_file) |
| 445 bench_page = 'benchmark_page' | 462 file_path = os.path.join(os.getcwd(), 'internal', 'browserBenchmarks', |
| 463 'benchmark_page_%s.html' % version) |
| 446 if not PERFBOT_MODE: | 464 if not PERFBOT_MODE: |
| 447 bench_page = 'smoketest' | 465 file_path = os.path.join(os.getcwd(), 'tools', 'testing', |
| 448 pass | 466 'perf_testing', 'smoketest', 'smoketest_%s.html' % version) |
| 449 RunCmd(['python', os.path.join('tools', 'testing', 'run_selenium.py'), | 467 RunCmd(['python', os.path.join('tools', 'testing', 'run_selenium.py'), |
| 450 '--out', os.path.join(os.getcwd(), 'internal', 'browserBenchmarks', | 468 '--out', file_path, '--browser', browser, |
| 451 '%s_%s.html' % (bench_page, version)), '--browser', browser, | |
| 452 '--timeout', '600', '--perf'], self.trace_file, append=True) | 469 '--timeout', '600', '--perf'], self.trace_file, append=True) |
| 453 | 470 |
| 454 def ProcessFile(self, afile): | 471 def ProcessFile(self, afile): |
| 455 """Comb through the html to find the performance results.""" | 472 """Comb through the html to find the performance results.""" |
| 456 parts = afile.split('-') | 473 parts = afile.split('-') |
| 457 browser = parts[2] | 474 browser = parts[2] |
| 458 version = parts[3] | 475 version = parts[3] |
| 459 f = open(os.path.join(self.result_folder_name, afile)) | 476 f = open(os.path.join(self.result_folder_name, afile)) |
| 460 lines = f.readlines() | 477 lines = f.readlines() |
| 461 line = '' | 478 line = '' |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 734 if HasNewCode(): | 751 if HasNewCode(): |
| 735 RunTestSequence(cl, size, language, perf) | 752 RunTestSequence(cl, size, language, perf) |
| 736 else: | 753 else: |
| 737 time.sleep(SLEEP_TIME) | 754 time.sleep(SLEEP_TIME) |
| 738 else: | 755 else: |
| 739 RunTestSequence(cl, size, language, perf) | 756 RunTestSequence(cl, size, language, perf) |
| 740 | 757 |
| 741 if __name__ == '__main__': | 758 if __name__ == '__main__': |
| 742 main() | 759 main() |
| 743 | 760 |
| OLD | NEW |