Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 | 2 |
| 3 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 3 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 4 # for details. All rights reserved. Use of this source code is governed by a | 4 # for details. All rights reserved. Use of this source code is governed by a |
| 5 # BSD-style license that can be found in the LICENSE file. | 5 # BSD-style license that can be found in the LICENSE file. |
| 6 | 6 |
| 7 import datetime | 7 import datetime |
| 8 import math | 8 import math |
| 9 import optparse | 9 import optparse |
| 10 import os | 10 import os |
| 11 from os.path import dirname, abspath | 11 from os.path import dirname, abspath |
| 12 import pickle | 12 import pickle |
| 13 import platform | 13 import platform |
| 14 import random | |
| 14 import re | 15 import re |
| 15 import shutil | 16 import shutil |
| 16 import stat | 17 import stat |
| 17 import subprocess | 18 import subprocess |
| 18 import sys | 19 import sys |
| 19 import time | 20 import time |
| 20 | 21 |
| 21 TOOLS_PATH = os.path.join(dirname(dirname(dirname(abspath(__file__))))) | 22 TOOLS_PATH = os.path.join(dirname(dirname(dirname(abspath(__file__))))) |
| 22 TOP_LEVEL_DIR = abspath(os.path.join(dirname(abspath(__file__)), '..', '..', | 23 TOP_LEVEL_DIR = abspath(os.path.join(dirname(abspath(__file__)), '..', '..', |
| 23 '..')) | 24 '..')) |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 51 stdout to | 52 stdout to |
| 52 append: True if we want to append to the file instead of overwriting it | 53 append: True if we want to append to the file instead of overwriting it |
| 53 std_in: a string that should be written to the process executing to | 54 std_in: a string that should be written to the process executing to |
| 54 interact with it (if needed)""" | 55 interact with it (if needed)""" |
| 55 if self.verbose: | 56 if self.verbose: |
| 56 print ' '.join(cmd_list) | 57 print ' '.join(cmd_list) |
| 57 out = subprocess.PIPE | 58 out = subprocess.PIPE |
| 58 if outfile: | 59 if outfile: |
| 59 mode = 'w' | 60 mode = 'w' |
| 60 if append: | 61 if append: |
| 61 mode = 'a' | 62 mode = 'a+' |
| 62 out = open(outfile, mode) | 63 out = open(outfile, mode) |
| 63 if append: | 64 if append: |
| 64 # Annoying Windows "feature" -- append doesn't actually append unless | 65 # Annoying Windows "feature" -- append doesn't actually append unless |
| 65 # you explicitly go to the end of the file. | 66 # you explicitly go to the end of the file. |
| 66 # http://mail.python.org/pipermail/python-list/2009-October/1221859.html | 67 # http://mail.python.org/pipermail/python-list/2009-October/1221859.html |
| 67 out.seek(0, os.SEEK_END) | 68 out.seek(0, os.SEEK_END) |
| 68 p = subprocess.Popen(cmd_list, stdout = out, stderr=subprocess.PIPE, | 69 p = subprocess.Popen(cmd_list, stdout = out, stderr=subprocess.PIPE, |
| 69 stdin=subprocess.PIPE, shell=self.has_shell) | 70 stdin=subprocess.PIPE, shell=self.has_shell) |
| 70 output, stderr = p.communicate(std_in) | 71 output, stderr = p.communicate(std_in) |
| 71 if output: | 72 if output: |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 87 os.chdir(DART_REPO_LOC) | 88 os.chdir(DART_REPO_LOC) |
| 88 results, _ = self.run_cmd(['svn', 'st']) | 89 results, _ = self.run_cmd(['svn', 'st']) |
| 89 for line in results.split('\n'): | 90 for line in results.split('\n'): |
| 90 if line.startswith('?'): | 91 if line.startswith('?'): |
| 91 to_remove = line.split()[1] | 92 to_remove = line.split()[1] |
| 92 if os.path.isdir(to_remove): | 93 if os.path.isdir(to_remove): |
| 93 shutil.rmtree(to_remove)#, ignore_errors=True) | 94 shutil.rmtree(to_remove)#, ignore_errors=True) |
| 94 else: | 95 else: |
| 95 os.remove(to_remove) | 96 os.remove(to_remove) |
| 96 | 97 |
| 97 def get_archive(archive_name): | 98 def get_archive(self, archive_name): |
| 98 """Wrapper around the pulling down a specific archive from Google Storage. | 99 """Wrapper around the pulling down a specific archive from Google Storage. |
| 99 Adds a specific revision argument as needed. | 100 Adds a specific revision argument as needed. |
| 100 Returns: The stderr from running this command.""" | 101 Returns: The stderr from running this command.""" |
| 101 cmd = ['python', os.path.join(DART_REPO_LOC, 'tools', 'get_archive.py'), | 102 cmd = ['python', os.path.join(DART_REPO_LOC, 'tools', 'get_archive.py'), |
| 102 archive_name] | 103 archive_name] |
| 103 if self.current_revision_num != -1: | 104 if self.current_revision_num != -1: |
| 104 cmd += ['-r', revision_num] | 105 cmd += ['-r', self.current_revision_num] |
| 105 _, stderr = self.test.test_runner.run_cmd(cmd) | 106 _, stderr = self.run_cmd(cmd) |
| 106 return stderr | 107 return stderr |
| 107 | 108 |
| 108 def sync_and_build(self, suites, revision_num=''): | 109 def sync_and_build(self, suites, revision_num=''): |
| 109 """Make sure we have the latest version of of the repo, and build it. We | 110 """Make sure we have the latest version of of the repo, and build it. We |
| 110 begin and end standing in DART_REPO_LOC. | 111 begin and end standing in DART_REPO_LOC. |
| 111 | 112 |
| 112 Args: | 113 Args: |
| 113 suites: The set of suites that we wish to build. | 114 suites: The set of suites that we wish to build. |
| 114 | 115 |
| 115 Returns: | 116 Returns: |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 128 shutil.copy( | 129 shutil.copy( |
| 129 os.path.join(TOP_LEVEL_DIR, 'tools', 'testing', 'run_selenium.py'), | 130 os.path.join(TOP_LEVEL_DIR, 'tools', 'testing', 'run_selenium.py'), |
| 130 os.path.join(DART_REPO_LOC, 'tools', 'testing', 'run_selenium.py')) | 131 os.path.join(DART_REPO_LOC, 'tools', 'testing', 'run_selenium.py')) |
| 131 | 132 |
| 132 if revision_num == '': | 133 if revision_num == '': |
| 133 revision_num = search_for_revision(['svn', 'info']) | 134 revision_num = search_for_revision(['svn', 'info']) |
| 134 if revision_num == -1: | 135 if revision_num == -1: |
| 135 revision_num = search_for_revision(['git', 'svn', 'info']) | 136 revision_num = search_for_revision(['git', 'svn', 'info']) |
| 136 | 137 |
| 137 self.current_revision_num = revision_num | 138 self.current_revision_num = revision_num |
| 138 stderr = get_archive('sdk') | 139 stderr = self.get_archive('sdk') |
| 139 if not os.path.exists(get_archive_path) or 'InvalidUriError' in stderr: | 140 if not os.path.exists(os.path.join( |
| 141 DART_REPO_LOC, 'tools', 'get_archive.py')) \ | |
| 142 or 'InvalidUriError' in stderr: | |
| 140 # Couldn't find the SDK on Google Storage. Build it locally. | 143 # Couldn't find the SDK on Google Storage. Build it locally. |
| 141 | 144 |
| 142 # On Windows, the output directory is marked as "Read Only," which causes | 145 # On Windows, the output directory is marked as "Read Only," which causes |
| 143 # an error to be thrown when we use shutil.rmtree. This helper function | 146 # an error to be thrown when we use shutil.rmtree. This helper function |
| 144 # changes the permissions so we can still delete the directory. | 147 # changes the permissions so we can still delete the directory. |
| 145 def on_rm_error(func, path, exc_info): | 148 def on_rm_error(func, path, exc_info): |
| 146 if os.path.exists(path): | 149 if os.path.exists(path): |
| 147 os.chmod(path, stat.S_IWRITE) | 150 os.chmod(path, stat.S_IWRITE) |
| 148 os.unlink(path) | 151 os.unlink(path) |
| 149 # TODO(efortuna): Currently always building ia32 architecture because we | 152 # TODO(efortuna): Currently always building ia32 architecture because we |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 240 | 243 |
| 241 def run_test_sequence(self, revision_num='', num_reruns=1): | 244 def run_test_sequence(self, revision_num='', num_reruns=1): |
| 242 """Run the set of commands to (possibly) build, run, and post the results | 245 """Run the set of commands to (possibly) build, run, and post the results |
| 243 of our tests. Returns 0 on a successful run, 1 if we fail to post results or | 246 of our tests. Returns 0 on a successful run, 1 if we fail to post results or |
| 244 the run failed, -1 if the build is broken. | 247 the run failed, -1 if the build is broken. |
| 245 """ | 248 """ |
| 246 suites = [] | 249 suites = [] |
| 247 success = True | 250 success = True |
| 248 if not self.no_build and self.sync_and_build(suites, revision_num) == 1: | 251 if not self.no_build and self.sync_and_build(suites, revision_num) == 1: |
| 249 return -1 # The build is broken. | 252 return -1 # The build is broken. |
| 250 | 253 |
| 251 for name in self.suite_names: | 254 for name in self.suite_names: |
| 252 for run in range(num_reruns): | 255 for run in range(num_reruns): |
| 253 suites += [TestBuilder.make_test(name, self)] | 256 suites += [TestBuilder.make_test(name, self)] |
| 254 | 257 |
| 255 for test in suites: | 258 for test in suites: |
| 256 success = success and test.run() | 259 success = success and test.run() |
| 257 if success: | 260 if success: |
| 258 return 0 | 261 return 0 |
| 259 else: | 262 else: |
| 260 return 1 | 263 return 1 |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 417 variant: Specifies whether the data was about generated Frog, js, a | 420 variant: Specifies whether the data was about generated Frog, js, a |
| 418 combination of both, or Dart depending on the test. | 421 combination of both, or Dart depending on the test. |
| 419 revision_number: The revision of the code (and sometimes the revision of | 422 revision_number: The revision of the code (and sometimes the revision of |
| 420 dartium). | 423 dartium). |
| 421 | 424 |
| 422 Returns: True if the post was successful file.""" | 425 Returns: True if the post was successful file.""" |
| 423 return post_results.report_results(benchmark_name, score, platform, variant, | 426 return post_results.report_results(benchmark_name, score, platform, variant, |
| 424 revision_number, metric) | 427 revision_number, metric) |
| 425 | 428 |
| 426 def calculate_geometric_mean(self, platform, variant, svn_revision): | 429 def calculate_geometric_mean(self, platform, variant, svn_revision): |
| 427 """Calculate the aggregate geometric mean for JS and frog benchmark sets, | 430 """Calculate the aggregate geometric mean for JS and dart2js benchmark sets, |
| 428 given two benchmark dictionaries.""" | 431 given two benchmark dictionaries.""" |
| 429 geo_mean = 0 | 432 geo_mean = 0 |
| 430 if self.test.is_valid_combination(platform, variant): | 433 if self.test.is_valid_combination(platform, variant): |
| 431 for benchmark in self.test.values_list: | 434 for benchmark in self.test.values_list: |
| 432 geo_mean += math.log( | 435 geo_mean += math.log( |
| 433 self.test.values_dict[platform][variant][benchmark][ | 436 self.test.values_dict[platform][variant][benchmark][ |
| 434 len(self.test.values_dict[platform][variant][benchmark]) - 1]) | 437 len(self.test.values_dict[platform][variant][benchmark]) - 1]) |
| 435 | 438 |
| 436 self.test.values_dict[platform][variant]['Geo-Mean'] += \ | 439 self.test.values_dict[platform][variant]['Geo-Mean'] += \ |
| 437 [math.pow(math.e, geo_mean / len(self.test.values_list))] | 440 [math.pow(math.e, geo_mean / len(self.test.values_list))] |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 491 | 494 |
| 492 class CommonBrowserTest(RuntimePerformanceTest): | 495 class CommonBrowserTest(RuntimePerformanceTest): |
| 493 """Runs this basic performance tests (Benchpress, some V8 benchmarks) in the | 496 """Runs this basic performance tests (Benchpress, some V8 benchmarks) in the |
| 494 browser.""" | 497 browser.""" |
| 495 | 498 |
| 496 def __init__(self, test_runner): | 499 def __init__(self, test_runner): |
| 497 """Args: | 500 """Args: |
| 498 test_runner: Reference to the object that notifies us when to run.""" | 501 test_runner: Reference to the object that notifies us when to run.""" |
| 499 super(CommonBrowserTest, self).__init__( | 502 super(CommonBrowserTest, self).__init__( |
| 500 self.name(), BrowserTester.get_browsers(False), | 503 self.name(), BrowserTester.get_browsers(False), |
| 501 'browser', ['js', 'frog', 'dart2js'], | 504 'browser', ['js', 'dart2js'], |
| 502 self.get_standalone_benchmarks(), test_runner, | 505 self.get_standalone_benchmarks(), test_runner, |
| 503 self.CommonBrowserTester(self), | 506 self.CommonBrowserTester(self), |
| 504 self.CommonBrowserFileProcessor(self)) | 507 self.CommonBrowserFileProcessor(self)) |
| 505 | 508 |
| 506 @staticmethod | 509 @staticmethod |
| 507 def name(): | 510 def name(): |
| 508 return 'browser-perf' | 511 return 'browser-perf' |
| 509 | 512 |
| 510 @staticmethod | 513 @staticmethod |
| 511 def get_standalone_benchmarks(): | 514 def get_standalone_benchmarks(): |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 658 def get_dromaeo_benchmarks(): | 661 def get_dromaeo_benchmarks(): |
| 659 valid = DromaeoTester.get_valid_dromaeo_tags() | 662 valid = DromaeoTester.get_valid_dromaeo_tags() |
| 660 benchmarks = reduce(lambda l1,l2: l1+l2, | 663 benchmarks = reduce(lambda l1,l2: l1+l2, |
| 661 [tests for (tag, tests) in | 664 [tests for (tag, tests) in |
| 662 DromaeoTester.DROMAEO_BENCHMARKS.values() | 665 DromaeoTester.DROMAEO_BENCHMARKS.values() |
| 663 if tag in valid]) | 666 if tag in valid]) |
| 664 return map(DromaeoTester.legalize_filename, benchmarks) | 667 return map(DromaeoTester.legalize_filename, benchmarks) |
| 665 | 668 |
| 666 @staticmethod | 669 @staticmethod |
| 667 def get_dromaeo_versions(): | 670 def get_dromaeo_versions(): |
| 668 return ['js', 'dart2js_dom', 'dart2js_html'] | 671 return ['js', 'dart2js_html'] |
| 669 | 672 |
| 670 | 673 |
| 671 class DromaeoTest(RuntimePerformanceTest): | 674 class DromaeoTest(RuntimePerformanceTest): |
| 672 """Runs Dromaeo tests, in the browser.""" | 675 """Runs Dromaeo tests, in the browser.""" |
| 673 def __init__(self, test_runner): | 676 def __init__(self, test_runner): |
| 674 super(DromaeoTest, self).__init__( | 677 super(DromaeoTest, self).__init__( |
| 675 self.name(), | 678 self.name(), |
| 676 BrowserTester.get_browsers(True), | 679 BrowserTester.get_browsers(True), |
| 677 'browser', | 680 'browser', |
| 678 DromaeoTester.get_dromaeo_versions(), | 681 DromaeoTester.get_dromaeo_versions(), |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 700 """Move the appropriate version of ChromeDriver onto the path. | 703 """Move the appropriate version of ChromeDriver onto the path. |
| 701 TODO(efortuna): This is a total hack because the latest version of Chrome | 704 TODO(efortuna): This is a total hack because the latest version of Chrome |
| 702 (Dartium builds) requires a different version of ChromeDriver, that is | 705 (Dartium builds) requires a different version of ChromeDriver, that is |
| 703 incompatible with the release or beta Chrome and vice versa. Remove these | 706 incompatible with the release or beta Chrome and vice versa. Remove these |
| 704 shenanigans once we're back to both versions of Chrome using the same | 707 shenanigans once we're back to both versions of Chrome using the same |
| 705 version of ChromeDriver. IMPORTANT NOTE: This assumes your chromedriver is | 708 version of ChromeDriver. IMPORTANT NOTE: This assumes your chromedriver is |
| 706 in the default location (inside depot_tools). | 709 in the default location (inside depot_tools). |
| 707 """ | 710 """ |
| 708 current_dir = os.getcwd() | 711 current_dir = os.getcwd() |
| 709 self.test.test_runner.get_archive('chromedriver') | 712 self.test.test_runner.get_archive('chromedriver') |
| 710 self.test.test_runner.run_cmd(['python', os.path.join( | |
| 711 path = os.environ['PATH'].split(os.pathsep) | 713 path = os.environ['PATH'].split(os.pathsep) |
| 712 orig_chromedriver_path = os.path.join(DART_REPO_LOC, 'tools', 'testing', | 714 orig_chromedriver_path = os.path.join(DART_REPO_LOC, 'tools', 'testing', |
| 713 'orig-chromedriver') | 715 'orig-chromedriver') |
| 714 dartium_chromedriver_path = os.path.join(DART_REPO_LOC, 'tools', | 716 dartium_chromedriver_path = os.path.join(DART_REPO_LOC, 'tools', |
| 715 'testing', | 717 'testing', |
| 716 'dartium-chromedriver') | 718 'dartium-chromedriver') |
| 717 extension = '' | 719 extension = '' |
| 718 if platform.system() == 'Windows': | 720 if platform.system() == 'Windows': |
| 719 extension = '.exe' | 721 extension = '.exe' |
| 720 | 722 |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 841 upload_success = upload_success and self.report_results( | 843 upload_success = upload_success and self.report_results( |
| 842 name, score, browser, version, revision_num, | 844 name, score, browser, version, revision_num, |
| 843 self.get_score_type(name)) | 845 self.get_score_type(name)) |
| 844 else: | 846 else: |
| 845 upload_success = False | 847 upload_success = False |
| 846 | 848 |
| 847 f.close() | 849 f.close() |
| 848 self.calculate_geometric_mean(browser, version, revision_num) | 850 self.calculate_geometric_mean(browser, version, revision_num) |
| 849 return upload_success | 851 return upload_success |
| 850 | 852 |
| 851 | |
| 852 class DromaeoSizeTest(Test): | |
| 853 """Run tests to determine the compiled file output size of Dromaeo.""" | |
| 854 def __init__(self, test_runner): | |
| 855 super(DromaeoSizeTest, self).__init__( | |
| 856 self.name(), | |
| 857 ['commandline'], ['dart', 'frog_dom', 'frog_html', | |
| 858 'frog_htmlidiomatic'], | |
| 859 DromaeoTester.DROMAEO_BENCHMARKS.keys(), test_runner, | |
| 860 self.DromaeoSizeTester(self), | |
| 861 self.DromaeoSizeProcessor(self), extra_metrics=['sum']) | |
| 862 | |
| 863 @staticmethod | |
| 864 def name(): | |
| 865 return 'dromaeo-size' | |
| 866 | |
| 867 | |
| 868 class DromaeoSizeTester(DromaeoTester): | |
| 869 def run_tests(self): | |
| 870 # Build tests. | |
| 871 dromaeo_path = os.path.join('samples', 'third_party', 'dromaeo') | |
| 872 current_path = os.getcwd() | |
| 873 os.chdir(dromaeo_path) | |
| 874 self.test.test_runner.run_cmd( | |
| 875 ['python', os.path.join('generate_dart2js_tests.py')]) | |
| 876 self.test.test_runner.get_archive('dartium') | |
| 877 os.chdir(current_path) | |
| 878 | |
| 879 self.test.trace_file = os.path.join(TOP_LEVEL_DIR, | |
| 880 'tools', 'testing', 'perf_testing', self.test.result_folder_name, | |
| 881 self.test.result_folder_name + self.test.cur_time) | |
| 882 self.add_svn_revision_to_trace(self.test.trace_file) | |
| 883 | |
| 884 variants = [ | |
| 885 ('frog_dom', ''), | |
| 886 ('frog_html', '-html'), | |
| 887 ('frog_htmlidiomatic', '-htmlidiomatic')] | |
| 888 | |
| 889 test_path = os.path.join(dromaeo_path, 'tests') | |
| 890 frog_path = os.path.join(test_path, 'frog') | |
| 891 total_size = {} | |
| 892 for (variant, _) in variants: | |
| 893 total_size[variant] = 0 | |
| 894 total_dart_size = 0 | |
| 895 for suite in DromaeoTester.DROMAEO_BENCHMARKS.keys(): | |
| 896 dart_size = 0 | |
| 897 try: | |
| 898 dart_size = os.path.getsize(os.path.join(test_path, | |
| 899 'dom-%s.dart' % suite)) | |
| 900 except OSError: | |
| 901 pass #If compilation failed, continue on running other tests. | |
| 902 | |
| 903 total_dart_size += dart_size | |
| 904 self.test.test_runner.run_cmd( | |
| 905 ['echo', 'Size (dart, %s): %s' % (suite, str(dart_size))], | |
| 906 self.test.trace_file, append=True) | |
| 907 | |
| 908 for (variant, suffix) in variants: | |
| 909 name = 'dom-%s%s.dart.js' % (suite, suffix) | |
| 910 js_size = 0 | |
| 911 try: | |
| 912 # TODO(vsm): Strip comments at least. Consider compression. | |
| 913 js_size = os.path.getsize(os.path.join(frog_path, name)) | |
| 914 except OSError: | |
| 915 pass #If compilation failed, continue on running other tests. | |
| 916 | |
| 917 total_size[variant] += js_size | |
| 918 self.test.test_runner.run_cmd( | |
| 919 ['echo', 'Size (%s, %s): %s' % (variant, suite, str(js_size))], | |
| 920 self.test.trace_file, append=True) | |
| 921 | |
| 922 self.test.test_runner.run_cmd( | |
| 923 ['echo', 'Size (dart, %s): %s' % (total_dart_size, | |
| 924 self.test.extra_metrics[0])], | |
| 925 self.test.trace_file, append=True) | |
| 926 for (variant, _) in variants: | |
| 927 self.test.test_runner.run_cmd( | |
| 928 ['echo', 'Size (%s, %s): %s' % (variant, self.test.extra_metrics[0], | |
| 929 total_size[variant])], | |
| 930 self.test.trace_file, append=True) | |
| 931 | |
| 932 | |
| 933 class DromaeoSizeProcessor(Processor): | |
| 934 def process_file(self, afile, should_post_file): | |
| 935 """Pull all the relevant information out of a given tracefile. | |
| 936 | |
| 937 Args: | |
| 938 afile: is the filename string we will be processing. | |
| 939 Returns: True if we successfully posted our data to storage.""" | |
| 940 os.chdir(os.path.join(TOP_LEVEL_DIR, 'tools', | |
| 941 'testing', 'perf_testing')) | |
| 942 f = self.open_trace_file(afile, should_post_file) | |
| 943 tabulate_data = False | |
| 944 revision_num = 0 | |
| 945 revision_pattern = r'Revision: (\d+)' | |
| 946 result_pattern = r'Size \((\w+), ([a-zA-Z0-9-]+)\): (\d+)' | |
| 947 | |
| 948 upload_success = True | |
| 949 for line in f.readlines(): | |
| 950 rev = re.match(revision_pattern, line.strip()) | |
| 951 if rev: | |
| 952 revision_num = int(rev.group(1)) | |
| 953 continue | |
| 954 | |
| 955 result = re.match(result_pattern, line.strip()) | |
| 956 if result: | |
| 957 variant = result.group(1) | |
| 958 metric = result.group(2) | |
| 959 num = result.group(3) | |
| 960 if num.find('.') == -1: | |
| 961 num = int(num) | |
| 962 else: | |
| 963 num = float(num) | |
| 964 self.test.values_dict['commandline'][variant][metric] += [num] | |
| 965 self.test.revision_dict['commandline'][variant][metric] += \ | |
| 966 [revision_num] | |
| 967 if not self.test.test_runner.no_upload and should_post_file: | |
| 968 upload_success = upload_success and self.report_results( | |
| 969 metric, num, 'commandline', variant, revision_num, | |
| 970 self.get_score_type(metric)) | |
| 971 else: | |
| 972 upload_success = False | |
| 973 | |
| 974 f.close() | |
| 975 return upload_success | |
| 976 | |
| 977 def get_score_type(self, metric): | |
| 978 return self.CODE_SIZE | |
| 979 | |
| 980 | |
| 981 class CompileTimeAndSizeTest(Test): | |
| 982 """Run tests to determine how long frogc takes to compile, and the compiled | |
| 983 file output size of some benchmarking files. | |
| 984 Note: This test is now 'deprecated' since frog is no longer in the sdk. We | |
| 985 just return the last numbers found for frog.""" | |
| 986 def __init__(self, test_runner): | |
| 987 """Reference to the test_runner object that notifies us when to begin | |
| 988 testing.""" | |
| 989 super(CompileTimeAndSizeTest, self).__init__( | |
| 990 self.name(), ['commandline'], ['dart2js'], ['swarm'], | |
| 991 test_runner, self.CompileTester(self), | |
| 992 self.CompileProcessor(self)) | |
| 993 self.dart_compiler = os.path.join( | |
| 994 DART_REPO_LOC, utils.GetBuildRoot(utils.GuessOS(), | |
| 995 'release', 'ia32'), 'dart-sdk', 'bin', 'dart2js') | |
| 996 _suffix = '' | |
| 997 if platform.system() == 'Windows': | |
| 998 _suffix = '.exe' | |
| 999 self.failure_threshold = {'swarm' : 100} | |
| 1000 | |
| 1001 @staticmethod | |
| 1002 def name(): | |
| 1003 return 'time-size' | |
| 1004 | |
| 1005 class CompileTester(Tester): | |
| 1006 def run_tests(self): | |
| 1007 self.test.trace_file = os.path.join(TOP_LEVEL_DIR, | |
| 1008 'tools', 'testing', 'perf_testing', | |
| 1009 self.test.result_folder_name, | |
| 1010 self.test.result_folder_name + self.test.cur_time) | |
| 1011 | |
| 1012 self.add_svn_revision_to_trace(self.test.trace_file) | |
| 1013 | |
| 1014 self.test.test_runner.run_cmd( | |
| 1015 ['./xcodebuild/ReleaseIA32/dart-sdk/dart2js', '-c', '-o', | |
| 1016 'swarm-result', os.path.join('samples', 'swarm', 'swarm.dart')]) | |
| 1017 swarm_size = 0 | |
| 1018 try: | |
| 1019 swarm_size = os.path.getsize('swarm-result') | |
| 1020 except OSError: | |
| 1021 pass #If compilation failed, continue on running other tests. | |
| 1022 | |
| 1023 self.test.test_runner.run_cmd( | |
| 1024 ['echo', '%d Generated checked swarm size' % swarm_size], | |
| 1025 self.test.trace_file, append=True) | |
| 1026 | |
| 1027 class CompileProcessor(Processor): | |
| 1028 def process_file(self, afile, should_post_file): | |
| 1029 """Pull all the relevant information out of a given tracefile. | |
| 1030 | |
| 1031 Args: | |
| 1032 afile: is the filename string we will be processing. | |
| 1033 Returns: True if we successfully posted our data to storage.""" | |
| 1034 os.chdir(os.path.join(TOP_LEVEL_DIR, 'tools', | |
| 1035 'testing', 'perf_testing')) | |
| 1036 f = self.open_trace_file(afile, should_post_file) | |
| 1037 tabulate_data = False | |
| 1038 revision_num = 0 | |
| 1039 upload_success = True | |
| 1040 for line in f.readlines(): | |
| 1041 tokens = line.split() | |
| 1042 if 'Revision' in line: | |
| 1043 revision_num = int(line.split()[1]) | |
| 1044 else: | |
| 1045 for metric in self.test.values_list: | |
| 1046 if metric in line: | |
| 1047 num = tokens[0] | |
| 1048 if num.find('.') == -1: | |
| 1049 num = int(num) | |
| 1050 else: | |
| 1051 num = float(num) | |
| 1052 self.test.values_dict['commandline']['dart2js'][metric] += [num] | |
| 1053 self.test.revision_dict['commandline']['dart2js'][metric] += \ | |
| 1054 [revision_num] | |
| 1055 score_type = self.get_score_type(metric) | |
| 1056 if not self.test.test_runner.no_upload and should_post_file: | |
| 1057 if num < self.test.failure_threshold[metric]: | |
| 1058 num = 0 | |
| 1059 upload_success = upload_success and self.report_results( | |
| 1060 metric, num, 'commandline', 'dart2js', revision_num, | |
| 1061 score_type) | |
| 1062 else: | |
| 1063 upload_success = False | |
| 1064 if revision_num != 0: | |
| 1065 for metric in self.test.values_list: | |
| 1066 try: | |
| 1067 self.test.revision_dict['commandline']['dart2js'][metric].pop() | |
| 1068 self.test.revision_dict['commandline']['dart2js'][metric] += \ | |
| 1069 [revision_num] | |
| 1070 # Fill in 0 if compilation failed. | |
| 1071 if self.test.values_dict['commandline']['dart2js'][metric][-1] < \ | |
| 1072 self.test.failure_threshold[metric]: | |
| 1073 self.test.values_dict['commandline']['dart2js'][metric] += [0] | |
| 1074 self.test.revision_dict['commandline']['dart2js'][metric] += \ | |
| 1075 [revision_num] | |
| 1076 except IndexError: | |
| 1077 # We tried to pop from an empty list. This happens if the first | |
| 1078 # trace file we encounter is incomplete. | |
| 1079 pass | |
| 1080 | |
| 1081 f.close() | |
| 1082 return upload_success | |
| 1083 | |
| 1084 def get_score_type(self, metric): | |
| 1085 if 'Compiling' in metric or 'Bootstrapping' in metric: | |
| 1086 return self.COMPILE_TIME | |
| 1087 return self.CODE_SIZE | |
| 1088 | |
| 1089 class TestBuilder(object): | 853 class TestBuilder(object): |
| 1090 """Construct the desired test object.""" | 854 """Construct the desired test object.""" |
| 1091 available_suites = dict((suite.name(), suite) for suite in [ | 855 available_suites = dict((suite.name(), suite) for suite in [ |
| 1092 CompileTimeAndSizeTest, CommonBrowserTest, DromaeoTest, DromaeoSizeTest]) | 856 CommonBrowserTest, DromaeoTest]) |
| 1093 | 857 |
| 1094 @staticmethod | 858 @staticmethod |
| 1095 def make_test(test_name, test_runner): | 859 def make_test(test_name, test_runner): |
| 1096 return TestBuilder.available_suites[test_name](test_runner) | 860 return TestBuilder.available_suites[test_name](test_runner) |
| 1097 | 861 |
| 1098 @staticmethod | 862 @staticmethod |
| 1099 def available_suite_names(): | 863 def available_suite_names(): |
| 1100 return TestBuilder.available_suites.keys() | 864 return TestBuilder.available_suites.keys() |
| 1101 | 865 |
| 1102 def search_for_revision(svn_info_command): | 866 def search_for_revision(svn_info_command): |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 1122 f.close() | 886 f.close() |
| 1123 f = open(filename, 'r+') | 887 f = open(filename, 'r+') |
| 1124 result_set = pickle.load(f) | 888 result_set = pickle.load(f) |
| 1125 if revision_num: | 889 if revision_num: |
| 1126 f.seek(0) | 890 f.seek(0) |
| 1127 result_set.add(revision_num) | 891 result_set.add(revision_num) |
| 1128 pickle.dump(result_set, f) | 892 pickle.dump(result_set, f) |
| 1129 f.close() | 893 f.close() |
| 1130 return result_set | 894 return result_set |
| 1131 | 895 |
| 896 def fill_in_back_history(results_set, runner): | |
| 897 """ Fill in back history performance data. This is done one of two ways, with | |
| 898 equal probability of trying each way (falling back on the sequential version | |
| 899 as our data becomes more densely populated).""" | |
| 900 has_run_extra = False | |
| 901 os.chdir(DART_REPO_LOC) | |
| 902 revision_num = int(search_for_revision(['svn', 'info'])) | |
| 903 if revision_num == -1: | |
| 904 revision_num = int(search_for_revision(['git', 'svn', 'info'])) | |
|
vsm
2012/08/15 15:27:32
Nit: I'd fold the previous 4 lines into search_for
Emily Fortuna
2012/08/15 22:10:10
Done.
| |
| 905 os.chdir(TOP_LEVEL_DIR) | |
| 906 | |
| 907 def try_to_run_additional(revision_number): | |
| 908 """Determine the number of results we have stored for a particular revision | |
| 909 number, and if it is less than 10, run some extra tests. | |
| 910 Args: | |
| 911 - revision_number: the revision whose performance we want to potentially | |
| 912 test.""" | |
| 913 print 'running %s~~~~~~~~~' % revision_number | |
| 914 a_test = TestBuilder.make_test(runner.suite_names[0], runner) | |
| 915 benchmark_name = a_test.values_list[0] | |
| 916 platform_name = a_test.platform_list[0] | |
| 917 variant = a_test.values_dict[platform_name].keys()[0] | |
| 918 num_results = post_results.get_num_results(benchmark_name, | |
| 919 platform_name, variant, revision_number, | |
| 920 a_test.file_processor.get_score_type(benchmark_name)) | |
| 921 if 10 - num_results < 2 and num_results >= 0: | |
|
vsm
2012/08/15 15:27:32
This looks fishy. "10 - num_results < 2" is equiv
Emily Fortuna
2012/08/15 22:10:10
num_results returns -1 if it has an error connecti
| |
| 922 reruns = 10 - num_results | |
| 923 else: | |
| 924 reruns = 2 | |
| 925 run = runner.run_test_sequence(revision_num=str(revision_number), | |
| 926 num_reruns=reruns) | |
| 927 if run == 0 and num_results + reruns >= 10: | |
| 928 results_set = update_set_of_done_cls(revision_number) | |
| 929 else: | |
| 930 return False | |
| 931 return True | |
| 932 | |
| 933 if random.choice([True, False]): | |
| 934 # Select a random CL number, with greater likelihood of selecting a CL in | |
| 935 # the more recent history than the distant past (using a simplified weighted | |
| 936 # bucket algorithm). If that CL has less than 10 runs, run additional. If it | |
| 937 # already has 10 runs, look for another CL number that is not yet have all | |
| 938 # of its additional runs (do this up to 15 times). | |
| 939 tries = 0 | |
| 940 thousands_list = range(1, int(revision_num)/1000 + 1) | |
| 941 weighted_total = sum(thousands_list) | |
| 942 generated_random_number = random.randint(0, weighted_total - 1) | |
| 943 for i in list(reversed(thousands_list)): | |
| 944 thousands = thousands_list[i - 1] | |
| 945 weighted_total -= thousands_list[i - 1] | |
| 946 if weighted_total <= generated_random_number: | |
| 947 break | |
| 948 while tries < 15 and not has_run_extra: | |
| 949 rev = thousands * 1000 + random.randrange(0, | |
| 950 int(revision_num) - | |
| 951 int(math.pow(10, int(math.floor(math.log10(int(revision_num))))) + 1)) | |
| 952 has_run_extra = try_to_run_additional(rev) | |
| 953 tries += 1 | |
| 954 | |
| 955 if not has_run_extra: | |
| 956 # Try to get up to 10 runs of each CL, starting with the most recent | |
| 957 # CL that does not yet have 10 runs. But only perform a set of extra | |
| 958 # runs at most 2 at a time before | |
| 959 # checking to see if new code has been checked in. | |
| 960 while revision_num > 0 and not has_run_extra: | |
| 961 if revision_num not in results_set: | |
| 962 has_run_extra = try_to_run_additional(revision_num) | |
| 963 revision_num -= 1 | |
| 964 if not has_run_extra: | |
| 965 # No more extra back-runs to do (for now). Wait for new code. | |
| 966 time.sleep(200) | |
| 967 return results_set | |
| 968 | |
| 1132 def main(): | 969 def main(): |
| 1133 runner = TestRunner() | 970 runner = TestRunner() |
| 1134 continuous = runner.parse_args() | 971 continuous = runner.parse_args() |
| 1135 | 972 |
| 1136 if not os.path.exists(DART_REPO_LOC): | 973 if not os.path.exists(DART_REPO_LOC): |
| 1137 os.mkdir(dirname(DART_REPO_LOC)) | 974 os.mkdir(dirname(DART_REPO_LOC)) |
| 1138 os.chdir(dirname(DART_REPO_LOC)) | 975 os.chdir(dirname(DART_REPO_LOC)) |
| 1139 p = subprocess.Popen('gclient config https://dart.googlecode.com/svn/' + | 976 p = subprocess.Popen('gclient config https://dart.googlecode.com/svn/' + |
| 1140 'branches/bleeding_edge/deps/all.deps', | 977 'branches/bleeding_edge/deps/all.deps', |
| 1141 stdout=subprocess.PIPE, stderr=subprocess.PIPE, | 978 stdout=subprocess.PIPE, stderr=subprocess.PIPE, |
| 1142 shell=True) | 979 shell=True) |
| 1143 p.communicate() | 980 p.communicate() |
| 1144 if continuous: | 981 if continuous: |
| 1145 while True: | 982 while True: |
| 1146 results_set = update_set_of_done_cls() | 983 results_set = update_set_of_done_cls() |
| 1147 if runner.has_new_code(): | 984 if runner.has_new_code(): |
| 1148 runner.run_test_sequence() | 985 runner.run_test_sequence() |
| 1149 else: | 986 else: |
| 1150 # Try to get up to 10 runs of each CL, starting with the most recent CL | 987 results_set = fill_in_back_history(results_set, runner) |
| 1151 # that does not yet have 10 runs. But only perform a set of extra runs | |
| 1152 # at most 10 at a time (get all the extra runs for one CL) before | |
| 1153 # checking to see if new code has been checked in. | |
| 1154 has_run_extra = False | |
| 1155 revision_num = int(search_for_revision(['svn', 'info'])) | |
| 1156 if revision_num == -1: | |
| 1157 revision_num = int(search_for_revision(['git', 'svn', 'info'])) | |
| 1158 | |
| 1159 # No need to track the performance before revision 3000. That's way in | |
| 1160 # the past. | |
| 1161 while revision_num > 3000 and not has_run_extra: | |
| 1162 if revision_num not in results_set: | |
| 1163 a_test = TestBuilder.make_test(runner.suite_names[0], runner) | |
| 1164 benchmark_name = a_test.values_list[0] | |
| 1165 platform_name = a_test.platform_list[0] | |
| 1166 variant = a_test.values_dict[platform_name].keys()[0] | |
| 1167 number_of_results = post_results.get_num_results(benchmark_name, | |
| 1168 platform_name, variant, revision_num, | |
| 1169 a_test.file_processor.get_score_type(benchmark_name)) | |
| 1170 if number_of_results < 10 and number_of_results >= 0: | |
| 1171 run = runner.run_test_sequence(revision_num=str(revision_num), | |
| 1172 num_reruns=(10-number_of_results)) | |
| 1173 if run == 0: | |
| 1174 has_run_extra = True | |
| 1175 results_set = update_set_of_done_cls(revision_num) | |
| 1176 revision_num -= 1 | |
| 1177 # No more extra back-runs to do (for now). Wait for new code. | |
| 1178 time.sleep(200) | |
| 1179 else: | 988 else: |
| 1180 runner.run_test_sequence() | 989 runner.run_test_sequence() |
| 1181 | 990 |
| 1182 if __name__ == '__main__': | 991 if __name__ == '__main__': |
| 1183 main() | 992 main() |
| OLD | NEW |