| 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 getpass | 8 import getpass |
| 9 import math | 9 import math |
| 10 try: | 10 try: |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 self.values_dict[platform] = dict() | 336 self.values_dict[platform] = dict() |
| 337 for f in variants: | 337 for f in variants: |
| 338 self.revision_dict[platform][f] = dict() | 338 self.revision_dict[platform][f] = dict() |
| 339 self.values_dict[platform][f] = dict() | 339 self.values_dict[platform][f] = dict() |
| 340 for val in values_list: | 340 for val in values_list: |
| 341 self.revision_dict[platform][f][val] = [] | 341 self.revision_dict[platform][f][val] = [] |
| 342 self.values_dict[platform][f][val] = [] | 342 self.values_dict[platform][f][val] = [] |
| 343 for extra_metric in extra_metrics: | 343 for extra_metric in extra_metrics: |
| 344 self.revision_dict[platform][f][extra_metric] = [] | 344 self.revision_dict[platform][f][extra_metric] = [] |
| 345 self.values_dict[platform][f][extra_metric] = [] | 345 self.values_dict[platform][f][extra_metric] = [] |
| 346 | 346 |
| 347 def is_valid_combination(self, platform, variant): |
| 348 """Check whether data should be captured for this platform/variant |
| 349 combination. |
| 350 """ |
| 351 return True |
| 352 |
| 347 def run(self, graph_only): | 353 def run(self, graph_only): |
| 348 """Run the benchmarks/tests from the command line and plot the | 354 """Run the benchmarks/tests from the command line and plot the |
| 349 results. | 355 results. |
| 350 | 356 |
| 351 Args: | 357 Args: |
| 352 graph_only: True if we should just graph the results instead of also | 358 graph_only: True if we should just graph the results instead of also |
| 353 running tests.""" | 359 running tests.""" |
| 354 for visitor in [self.tester, self.file_processor, self.grapher]: | 360 for visitor in [self.tester, self.file_processor, self.grapher]: |
| 355 visitor.prepare() | 361 visitor.prepare() |
| 356 | 362 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 379 methods that many Tester objects use. Any class that would like to be a | 385 methods that many Tester objects use. Any class that would like to be a |
| 380 TesterVisitor must implement the run_tests() method.""" | 386 TesterVisitor must implement the run_tests() method.""" |
| 381 | 387 |
| 382 def __init__(self, test): | 388 def __init__(self, test): |
| 383 self.test = test | 389 self.test = test |
| 384 | 390 |
| 385 def prepare(self): | 391 def prepare(self): |
| 386 """Perform any initial setup required before the test is run.""" | 392 """Perform any initial setup required before the test is run.""" |
| 387 pass | 393 pass |
| 388 | 394 |
| 389 def add_svn_revision_to_trace(self, outfile): | 395 def add_svn_revision_to_trace(self, outfile, browser = None): |
| 390 """Add the svn version number to the provided tracefile.""" | 396 """Add the svn version number to the provided tracefile.""" |
| 391 def search_for_revision(svn_info_command): | 397 def search_for_revision(svn_info_command): |
| 392 p = subprocess.Popen(svn_info_command, stdout = subprocess.PIPE, | 398 p = subprocess.Popen(svn_info_command, stdout = subprocess.PIPE, |
| 393 stderr = subprocess.STDOUT, shell = | 399 stderr = subprocess.STDOUT, shell = |
| 394 self.test.test_runner.has_shell) | 400 self.test.test_runner.has_shell) |
| 395 output, _ = p.communicate() | 401 output, _ = p.communicate() |
| 396 for line in output.split('\n'): | 402 for line in output.split('\n'): |
| 397 if 'Revision' in line: | 403 if 'Revision' in line: |
| 398 self.test.test_runner.run_cmd(['echo', line.strip()], outfile) | 404 self.test.test_runner.run_cmd(['echo', line.strip()], outfile) |
| 399 return True | 405 return True |
| 400 return False | 406 return False |
| 401 | 407 |
| 402 if not search_for_revision(['svn', 'info']): | 408 def get_dartium_revision(): |
| 409 version_file_name = os.path.join(DART_INSTALL_LOCATION, 'client', 'tests', |
| 410 'dartium', 'LAST_VERSION') |
| 411 version_file = open(version_file_name, 'r') |
| 412 version = version_file.read().split('.')[-2] |
| 413 version_file.close() |
| 414 return version |
| 415 |
| 416 if browser and browser == 'dartium': |
| 417 revision = get_dartium_revision() |
| 418 self.test.test_runner.run_cmd(['echo', 'Revision: ' + revision], outfile) |
| 419 elif not search_for_revision(['svn', 'info']): |
| 403 if not search_for_revision(['git', 'svn', 'info']): | 420 if not search_for_revision(['git', 'svn', 'info']): |
| 404 self.test.test_runner.run_cmd(['echo', 'Revision: unknown'], outfile) | 421 self.test.test_runner.run_cmd(['echo', 'Revision: unknown'], outfile) |
| 405 | 422 |
| 406 | 423 |
| 407 class Processor(object): | 424 class Processor(object): |
| 408 """The base level vistor class that processes tests. It contains convenience | 425 """The base level vistor class that processes tests. It contains convenience |
| 409 methods that many File Processor objects use. Any class that would like to be | 426 methods that many File Processor objects use. Any class that would like to be |
| 410 a ProcessorVisitor must implement the process_file() method.""" | 427 a ProcessorVisitor must implement the process_file() method.""" |
| 411 | 428 |
| 412 def __init__(self, test): | 429 def __init__(self, test): |
| 413 self.test = test | 430 self.test = test |
| 414 | 431 |
| 415 def prepare(self): | 432 def prepare(self): |
| 416 """Perform any initial setup required before the test is run.""" | 433 """Perform any initial setup required before the test is run.""" |
| 417 pass | 434 pass |
| 418 | 435 |
| 419 def calculate_geometric_mean(self, platform, variant, svn_revision): | 436 def calculate_geometric_mean(self, platform, variant, svn_revision): |
| 420 """Calculate the aggregate geometric mean for JS and frog benchmark sets, | 437 """Calculate the aggregate geometric mean for JS and frog benchmark sets, |
| 421 given two benchmark dictionaries.""" | 438 given two benchmark dictionaries.""" |
| 422 geo_mean = 0 | 439 geo_mean = 0 |
| 423 for benchmark in self.test.values_list: | 440 # TODO(vsm): Suppress graphing this combination altogether. For |
| 424 geo_mean += math.log(self.test.values_dict[platform][variant][benchmark][ | 441 # now, we feed a geomean of 0. |
| 425 len(self.test.values_dict[platform][variant][benchmark]) - 1]) | 442 if self.test.is_valid_combination(platform, variant): |
| 443 for benchmark in self.test.values_list: |
| 444 geo_mean += math.log( |
| 445 self.test.values_dict[platform][variant][benchmark][ |
| 446 len(self.test.values_dict[platform][variant][benchmark]) - 1]) |
| 426 | 447 |
| 427 self.test.values_dict[platform][variant]['Geo-Mean'] += \ | 448 self.test.values_dict[platform][variant]['Geo-Mean'] += \ |
| 428 [math.pow(math.e, geo_mean / len(self.test.values_list))] | 449 [math.pow(math.e, geo_mean / len(self.test.values_list))] |
| 429 self.test.revision_dict[platform][variant]['Geo-Mean'] += [svn_revision] | 450 self.test.revision_dict[platform][variant]['Geo-Mean'] += [svn_revision] |
| 430 | 451 |
| 431 | 452 |
| 432 class Grapher(object): | 453 class Grapher(object): |
| 433 """The base level visitor class that generates graphs for data. It contains | 454 """The base level visitor class that generates graphs for data. It contains |
| 434 convenience methods that many Grapher objects use. Any class that would like | 455 convenience methods that many Grapher objects use. Any class that would like |
| 435 to be a GrapherVisitor must implement the plot_results() method.""" | 456 to be a GrapherVisitor must implement the plot_results() method.""" |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 559 def plot_avg_perf(self, png_filename): | 580 def plot_avg_perf(self, png_filename): |
| 560 """Generate a plot that shows the performance changes of the geomentric | 581 """Generate a plot that shows the performance changes of the geomentric |
| 561 mean of JS and frog benchmark performance over svn history.""" | 582 mean of JS and frog benchmark performance over svn history.""" |
| 562 (title, y_axis, size_x, size_y, loc, filename) = \ | 583 (title, y_axis, size_x, size_y, loc, filename) = \ |
| 563 ('Geometric Mean of benchmark %s performance on %s ' % | 584 ('Geometric Mean of benchmark %s performance on %s ' % |
| 564 (self.test.platform_type, utils.GuessOS()), 'Speed (bigger = better)', | 585 (self.test.platform_type, utils.GuessOS()), 'Speed (bigger = better)', |
| 565 16, 5, 'lower left', 'avg'+png_filename) | 586 16, 5, 'lower left', 'avg'+png_filename) |
| 566 clear_axis = True | 587 clear_axis = True |
| 567 for platform in self.test.platform_list: | 588 for platform in self.test.platform_list: |
| 568 for version in self.test.versions: | 589 for version in self.test.versions: |
| 569 for metric in self.test.extra_metrics: | 590 if self.test.is_valid_combination(platform, version): |
| 570 self.style_and_save_perf_plot(title, y_axis, size_x, size_y, loc, | 591 for metric in self.test.extra_metrics: |
| 571 filename, [platform], [version], | 592 self.style_and_save_perf_plot(title, y_axis, size_x, size_y, loc, |
| 572 [metric], clear_axis) | 593 filename, [platform], [version], |
| 573 clear_axis = False | 594 [metric], clear_axis) |
| 595 clear_axis = False |
| 574 | 596 |
| 575 def plot_results(self, png_filename): | 597 def plot_results(self, png_filename): |
| 576 self.plot_all_perf(png_filename) | 598 self.plot_all_perf(png_filename) |
| 577 self.plot_avg_perf('2' + png_filename) | 599 self.plot_avg_perf('2' + png_filename) |
| 578 | 600 |
| 579 | 601 |
| 580 class CommonCommandLineTest(RuntimePerformanceTest): | 602 class CommonCommandLineTest(RuntimePerformanceTest): |
| 581 """Run the basic performance tests (Benchpress, some V8 benchmarks) from the | 603 """Run the basic performance tests (Benchpress, some V8 benchmarks) from the |
| 582 command line.""" | 604 command line.""" |
| 583 | 605 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 649 [revision_num] | 671 [revision_num] |
| 650 self.test.values_dict['commandline']['frog'][benchmark] += \ | 672 self.test.values_dict['commandline']['frog'][benchmark] += \ |
| 651 [frog_value] | 673 [frog_value] |
| 652 f.close() | 674 f.close() |
| 653 | 675 |
| 654 self.calculate_geometric_mean('commandline', 'frog', revision_num) | 676 self.calculate_geometric_mean('commandline', 'frog', revision_num) |
| 655 self.calculate_geometric_mean('commandline', 'js', revision_num) | 677 self.calculate_geometric_mean('commandline', 'js', revision_num) |
| 656 | 678 |
| 657 | 679 |
| 658 class BrowserTester(Tester): | 680 class BrowserTester(Tester): |
| 659 # TODO(vsm): Add Dartium. | |
| 660 @staticmethod | 681 @staticmethod |
| 661 def get_browsers(): | 682 def get_browsers(): |
| 662 browsers = ['ff', 'chrome'] | 683 browsers = ['dartium', 'ff', 'chrome'] |
| 684 has_shell = False |
| 663 if platform.system() == 'Darwin': | 685 if platform.system() == 'Darwin': |
| 664 browsers += ['safari'] | 686 browsers += ['safari'] |
| 665 if platform.system() == 'Windows': | 687 if platform.system() == 'Windows': |
| 666 browsers += ['ie'] | 688 browsers += ['ie'] |
| 689 has_shell = True |
| 690 if 'dartium' in browsers: |
| 691 # Fetch it if necessary. |
| 692 get_dartium = ['python', |
| 693 os.path.join(DART_INSTALL_LOCATION, 'tools', 'get_drt.py'), |
| 694 '--dartium'] |
| 695 # TODO(vsm): It's inconvenient that run_cmd isn't in scope here. |
| 696 # Perhaps there is a better place to put that or this. |
| 697 subprocess.Popen(get_dartium, shell=has_shell) |
| 667 return browsers | 698 return browsers |
| 668 | 699 |
| 669 | 700 |
| 670 class CommonBrowserTest(RuntimePerformanceTest): | 701 class CommonBrowserTest(RuntimePerformanceTest): |
| 671 """Runs this basic performance tests (Benchpress, some V8 benchmarks) in the | 702 """Runs this basic performance tests (Benchpress, some V8 benchmarks) in the |
| 672 browser.""" | 703 browser.""" |
| 673 | 704 |
| 674 def __init__(self, test_runner): | 705 def __init__(self, test_runner): |
| 675 """Args: | 706 """Args: |
| 676 test_runner: Reference to the object that notifies us when to run.""" | 707 test_runner: Reference to the object that notifies us when to run.""" |
| (...skipping 18 matching lines...) Expand all Loading... |
| 695 class CommonBrowserTester(BrowserTester): | 726 class CommonBrowserTester(BrowserTester): |
| 696 def run_tests(self): | 727 def run_tests(self): |
| 697 """Run a performance test in the browser.""" | 728 """Run a performance test in the browser.""" |
| 698 os.chdir('frog') | 729 os.chdir('frog') |
| 699 self.test.test_runner.run_cmd(['python', os.path.join('benchmarks', | 730 self.test.test_runner.run_cmd(['python', os.path.join('benchmarks', |
| 700 'make_web_benchmarks.py')]) | 731 'make_web_benchmarks.py')]) |
| 701 os.chdir('..') | 732 os.chdir('..') |
| 702 | 733 |
| 703 for browser in BrowserTester.get_browsers(): | 734 for browser in BrowserTester.get_browsers(): |
| 704 for version in self.test.versions: | 735 for version in self.test.versions: |
| 736 if not self.test.is_valid_combination(browser, version): |
| 737 continue |
| 705 self.test.trace_file = os.path.join( | 738 self.test.trace_file = os.path.join( |
| 706 'tools', 'testing', 'perf_testing', self.test.result_folder_name, | 739 'tools', 'testing', 'perf_testing', self.test.result_folder_name, |
| 707 'perf-%s-%s-%s' % (self.test.cur_time, browser, version)) | 740 'perf-%s-%s-%s' % (self.test.cur_time, browser, version)) |
| 708 self.add_svn_revision_to_trace(self.test.trace_file) | 741 self.add_svn_revision_to_trace(self.test.trace_file, browser) |
| 709 file_path = os.path.join( | 742 file_path = os.path.join( |
| 710 os.getcwd(), 'internal', 'browserBenchmarks', | 743 os.getcwd(), 'internal', 'browserBenchmarks', |
| 711 'benchmark_page_%s.html' % version) | 744 'benchmark_page_%s.html' % version) |
| 712 self.test.test_runner.run_cmd( | 745 self.test.test_runner.run_cmd( |
| 713 ['python', os.path.join('tools', 'testing', 'run_selenium.py'), | 746 ['python', os.path.join('tools', 'testing', 'run_selenium.py'), |
| 714 '--out', file_path, '--browser', browser, | 747 '--out', file_path, '--browser', browser, |
| 715 '--timeout', '600', '--mode', 'perf'], self.test.trace_file, | 748 '--timeout', '600', '--mode', 'perf'], self.test.trace_file, |
| 716 append=True) | 749 append=True) |
| 717 | 750 |
| 718 class CommonBrowserFileProcessor(Processor): | 751 class CommonBrowserFileProcessor(Processor): |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 839 self.name(), BrowserTester.get_browsers(), 'browser', | 872 self.name(), BrowserTester.get_browsers(), 'browser', |
| 840 DromaeoTester.get_dromaeo_versions(), | 873 DromaeoTester.get_dromaeo_versions(), |
| 841 DromaeoTester.get_dromaeo_benchmarks(), test_runner, | 874 DromaeoTester.get_dromaeo_benchmarks(), test_runner, |
| 842 self.DromaeoPerfTester(self), | 875 self.DromaeoPerfTester(self), |
| 843 self.DromaeoFileProcessor(self)) | 876 self.DromaeoFileProcessor(self)) |
| 844 | 877 |
| 845 @staticmethod | 878 @staticmethod |
| 846 def name(): | 879 def name(): |
| 847 return 'dromaeo' | 880 return 'dromaeo' |
| 848 | 881 |
| 882 def is_valid_combination(self, browser, version): |
| 883 # TODO(vsm): This avoids a bug in 32-bit Chrome (dartium) |
| 884 # running JS dromaeo. |
| 885 if browser == 'dartium' and version == 'js': |
| 886 return False |
| 887 return True |
| 888 |
| 849 class DromaeoPerfTester(DromaeoTester): | 889 class DromaeoPerfTester(DromaeoTester): |
| 850 def run_tests(self): | 890 def run_tests(self): |
| 851 """Run dromaeo in the browser.""" | 891 """Run dromaeo in the browser.""" |
| 852 | 892 |
| 853 # Build tests. | 893 # Build tests. |
| 854 dromaeo_path = os.path.join('samples', 'third_party', 'dromaeo') | 894 dromaeo_path = os.path.join('samples', 'third_party', 'dromaeo') |
| 855 current_path = os.getcwd() | 895 current_path = os.getcwd() |
| 856 os.chdir(dromaeo_path) | 896 os.chdir(dromaeo_path) |
| 857 self.test.test_runner.run_cmd(['python', 'generate_frog_tests.py']) | 897 self.test.test_runner.run_cmd(['python', 'generate_frog_tests.py']) |
| 858 os.chdir(current_path) | 898 os.chdir(current_path) |
| 859 | 899 |
| 860 versions = DromaeoTester.get_dromaeo_versions() | 900 versions = DromaeoTester.get_dromaeo_versions() |
| 861 | 901 |
| 862 for browser in BrowserTester.get_browsers(): | 902 for browser in BrowserTester.get_browsers(): |
| 863 for version_name in versions: | 903 for version_name in versions: |
| 904 if not self.test.is_valid_combination(browser, version): |
| 905 continue |
| 864 version = DromaeoTest.DromaeoPerfTester.get_dromaeo_url_query( | 906 version = DromaeoTest.DromaeoPerfTester.get_dromaeo_url_query( |
| 865 version_name) | 907 browser, version_name) |
| 866 self.test.trace_file = os.path.join( | 908 self.test.trace_file = os.path.join( |
| 867 'tools', 'testing', 'perf_testing', self.test.result_folder_name, | 909 'tools', 'testing', 'perf_testing', self.test.result_folder_name, |
| 868 'dromaeo-%s-%s-%s' % (self.test.cur_time, browser, version_name)) | 910 'dromaeo-%s-%s-%s' % (self.test.cur_time, browser, version_name)) |
| 869 self.add_svn_revision_to_trace(self.test.trace_file) | 911 self.add_svn_revision_to_trace(self.test.trace_file, browser) |
| 870 file_path = '"%s"' % os.path.join(os.getcwd(), dromaeo_path, | 912 file_path = '"%s"' % os.path.join(os.getcwd(), dromaeo_path, |
| 871 'index-js.html?%s' % version) | 913 'index-js.html?%s' % version) |
| 872 self.test.test_runner.run_cmd( | 914 self.test.test_runner.run_cmd( |
| 873 ['python', os.path.join('tools', 'testing', 'run_selenium.py'), | 915 ['python', os.path.join('tools', 'testing', 'run_selenium.py'), |
| 874 '--out', file_path, '--browser', browser, | 916 '--out', file_path, '--browser', browser, |
| 875 '--timeout', '600', '--mode', 'dromaeo'], self.test.trace_file, | 917 '--timeout', '600', '--mode', 'dromaeo'], self.test.trace_file, |
| 876 append=True) | 918 append=True) |
| 877 | 919 |
| 878 @staticmethod | 920 @staticmethod |
| 879 def get_dromaeo_url_query(version): | 921 def get_dromaeo_url_query(browser, version): |
| 922 if browser == 'dartium': |
| 923 version = version.replace('frog', 'dart') |
| 880 version = version.replace('_','&') | 924 version = version.replace('_','&') |
| 881 tags = DromaeoTester.get_valid_dromaeo_tags() | 925 tags = DromaeoTester.get_valid_dromaeo_tags() |
| 882 return '|'.join([ '%s&%s' % (version, tag) for tag in tags]) | 926 return '|'.join([ '%s&%s' % (version, tag) for tag in tags]) |
| 883 | 927 |
| 884 | 928 |
| 885 class DromaeoFileProcessor(Processor): | 929 class DromaeoFileProcessor(Processor): |
| 886 def process_file(self, afile): | 930 def process_file(self, afile): |
| 887 """Comb through the html to find the performance results.""" | 931 """Comb through the html to find the performance results.""" |
| 888 parts = afile.split('-') | 932 parts = afile.split('-') |
| 889 browser = parts[2] | 933 browser = parts[2] |
| (...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1221 while True: | 1265 while True: |
| 1222 if runner.has_new_code(): | 1266 if runner.has_new_code(): |
| 1223 runner.run_test_sequence() | 1267 runner.run_test_sequence() |
| 1224 else: | 1268 else: |
| 1225 time.sleep(200) | 1269 time.sleep(200) |
| 1226 else: | 1270 else: |
| 1227 runner.run_test_sequence() | 1271 runner.run_test_sequence() |
| 1228 | 1272 |
| 1229 if __name__ == '__main__': | 1273 if __name__ == '__main__': |
| 1230 main() | 1274 main() |
| OLD | NEW |