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 |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
102 """Wrapper around the pulling down a specific archive from Google Storage. | 102 """Wrapper around the pulling down a specific archive from Google Storage. |
103 Adds a specific revision argument as needed. | 103 Adds a specific revision argument as needed. |
104 Returns: The stderr from running this command.""" | 104 Returns: The stderr from running this command.""" |
105 cmd = ['python', os.path.join(DART_REPO_LOC, 'tools', 'get_archive.py'), | 105 cmd = ['python', os.path.join(DART_REPO_LOC, 'tools', 'get_archive.py'), |
106 archive_name] | 106 archive_name] |
107 if self.current_revision_num != -1: | 107 if self.current_revision_num != -1: |
108 cmd += ['-r', self.current_revision_num] | 108 cmd += ['-r', self.current_revision_num] |
109 _, stderr = self.run_cmd(cmd) | 109 _, stderr = self.run_cmd(cmd) |
110 return stderr | 110 return stderr |
111 | 111 |
112 def sync_and_build(self, suites, revision_num=''): | 112 def _sync(self, revision_num=''): |
sra1
2012/08/18 23:08:55
nit: we would usually use None for the default val
Emily Fortuna
2012/08/20 19:59:05
Done.
| |
113 """Make sure we have the latest version of of the repo, and build it. We | 113 """Update the repository to the latest or specified revision.""" |
114 begin and end standing in DART_REPO_LOC. | |
115 | |
116 Args: | |
117 suites: The set of suites that we wish to build. | |
118 | |
119 Returns: | |
120 err_code = 1 if there was a problem building.""" | |
121 os.chdir(dirname(DART_REPO_LOC)) | 114 os.chdir(dirname(DART_REPO_LOC)) |
122 self.clear_out_unversioned_files() | 115 self.clear_out_unversioned_files() |
123 if revision_num == '': | 116 if revision_num == '': |
124 self.run_cmd(['gclient', 'sync']) | 117 self.run_cmd(['gclient', 'sync']) |
125 else: | 118 else: |
126 self.run_cmd(['gclient', 'sync', '-r', revision_num, '-t']) | 119 self.run_cmd(['gclient', 'sync', '-r', revision_num, '-t']) |
127 | 120 |
128 shutil.copytree(os.path.join(TOP_LEVEL_DIR, 'internal'), | 121 shutil.copytree(os.path.join(TOP_LEVEL_DIR, 'internal'), |
129 os.path.join(DART_REPO_LOC, 'internal')) | 122 os.path.join(DART_REPO_LOC, 'internal')) |
130 shutil.copy(os.path.join(TOP_LEVEL_DIR, 'tools', 'get_archive.py'), | 123 shutil.copy(os.path.join(TOP_LEVEL_DIR, 'tools', 'get_archive.py'), |
131 os.path.join(DART_REPO_LOC, 'tools', 'get_archive.py')) | 124 os.path.join(DART_REPO_LOC, 'tools', 'get_archive.py')) |
132 shutil.copy( | 125 shutil.copy( |
133 os.path.join(TOP_LEVEL_DIR, 'tools', 'testing', 'run_selenium.py'), | 126 os.path.join(TOP_LEVEL_DIR, 'tools', 'testing', 'run_selenium.py'), |
134 os.path.join(DART_REPO_LOC, 'tools', 'testing', 'run_selenium.py')) | 127 os.path.join(DART_REPO_LOC, 'tools', 'testing', 'run_selenium.py')) |
135 | 128 |
129 def sync_and_build(self, suites, revision_num=''): | |
sra1
2012/08/18 23:08:55
Google style is to use MixedCase for functions and
Emily Fortuna
2012/08/20 19:59:05
Not for methods:
http://google-styleguide.googlec
sra1
2012/08/21 22:59:36
The second link says "Python code should follow PE
Emily Fortuna
2012/08/22 21:08:20
Yea, I was reading the wrong section of the style
| |
130 """Make sure we have the latest version of of the repo, and build it. We | |
131 begin and end standing in DART_REPO_LOC. | |
132 | |
133 Args: | |
134 suites: The set of suites that we wish to build. | |
135 | |
136 Returns: | |
137 err_code = 1 if there was a problem building.""" | |
138 self._sync(revision_num) | |
136 if revision_num == '': | 139 if revision_num == '': |
137 revision_num = search_for_revision() | 140 revision_num = search_for_revision() |
138 | 141 |
139 self.current_revision_num = revision_num | 142 self.current_revision_num = revision_num |
140 stderr = self.get_archive('sdk') | 143 stderr = self.get_archive('sdk') |
141 if not os.path.exists(os.path.join( | 144 if not os.path.exists(os.path.join( |
142 DART_REPO_LOC, 'tools', 'get_archive.py')) \ | 145 DART_REPO_LOC, 'tools', 'get_archive.py')) \ |
sra1
2012/08/18 23:08:55
Better style is to put the whole condition in pare
Emily Fortuna
2012/08/20 19:59:05
Done.
| |
143 or 'InvalidUriError' in stderr: | 146 or 'InvalidUriError' in stderr: |
144 # Couldn't find the SDK on Google Storage. Build it locally. | 147 # Couldn't find the SDK on Google Storage. Build it locally. |
145 | 148 |
146 # On Windows, the output directory is marked as "Read Only," which causes | 149 # On Windows, the output directory is marked as "Read Only," which causes |
147 # an error to be thrown when we use shutil.rmtree. This helper function | 150 # an error to be thrown when we use shutil.rmtree. This helper function |
148 # changes the permissions so we can still delete the directory. | 151 # changes the permissions so we can still delete the directory. |
149 def on_rm_error(func, path, exc_info): | 152 def on_rm_error(func, path, exc_info): |
150 if os.path.exists(path): | 153 if os.path.exists(path): |
151 os.chmod(path, stat.S_IWRITE) | 154 os.chmod(path, stat.S_IWRITE) |
152 os.unlink(path) | 155 os.unlink(path) |
(...skipping 21 matching lines...) Expand all Loading... | |
174 Args: | 177 Args: |
175 dir_name: the directory we will create if it does not exist.""" | 178 dir_name: the directory we will create if it does not exist.""" |
176 dir_path = os.path.join(TOP_LEVEL_DIR, 'tools', | 179 dir_path = os.path.join(TOP_LEVEL_DIR, 'tools', |
177 'testing', 'perf_testing', dir_name) | 180 'testing', 'perf_testing', dir_name) |
178 if not os.path.exists(dir_path): | 181 if not os.path.exists(dir_path): |
179 os.makedirs(dir_path) | 182 os.makedirs(dir_path) |
180 print 'Creating output directory ', dir_path | 183 print 'Creating output directory ', dir_path |
181 | 184 |
182 def has_interesting_code(self, past_revision_num=None): | 185 def has_interesting_code(self, past_revision_num=None): |
183 """Tests if there are any versions of files that might change performance | 186 """Tests if there are any versions of files that might change performance |
184 results on the server.""" | 187 results on the server. |
188 Returns a tuple of a boolean and potentially a revision number that has | |
189 interesting code. (If the boolean is false, there is no interesting code, | |
190 therefore the second element in the tuple will be None.)""" | |
185 if not os.path.exists(DART_REPO_LOC): | 191 if not os.path.exists(DART_REPO_LOC): |
186 return True | 192 self._sync() |
187 os.chdir(DART_REPO_LOC) | 193 os.chdir(DART_REPO_LOC) |
188 no_effect = ['client', 'compiler', 'editor', 'pkg', 'samples', 'tests', | 194 no_effect = ['client', 'compiler', 'editor', 'pkg', 'samples', 'tests', |
189 'third_party', 'tools', 'utils'] | 195 'third_party', 'utils'] |
190 # Pass 'p' in if we have a new certificate for the svn server, we want to | 196 def get_svn_log_data(revision): |
sra1
2012/08/18 23:08:55
The function is not really getting log data. it i
Emily Fortuna
2012/08/20 19:59:05
Made into a global function. No unit tests for thi
| |
191 # (p)ermanently accept it. | 197 """Determine the set of files that were changed for a particular |
192 if past_revision_num: | 198 revision.""" |
193 # TODO(efortuna): This assumes you're using svn. Have a git fallback as | 199 # TODO(efortuna): This assumes you're using svn. Have a git fallback as |
194 # well. | 200 # well. |
201 # Pass 'p' in if we have a new certificate for the svn server, we want to | |
202 # (p)ermanently accept it. | |
195 results, _ = self.run_cmd(['svn', 'log', '-v', '-r', | 203 results, _ = self.run_cmd(['svn', 'log', '-v', '-r', |
196 str(past_revision_num)], std_in='p\r\n') | 204 str(revision)], std_in='p\r\n') |
197 results = results.split('\n') | 205 results = results.split('\n') |
198 if len(results) <= 3: | 206 if len(results) <= 3: |
199 results = [] | 207 return [] |
200 else: | 208 else: |
201 # Trim off the details about revision number and commit message. We're | 209 # Trim off the details about revision number and commit message. We're |
202 # only interested in the files that are changed. | 210 # only interested in the files that are changed. |
203 results = results[3:] | 211 results = results[3:] |
204 changed_files = [] | 212 changed_files = [] |
205 for result in results: | 213 for result in results: |
206 if result == '': | 214 if len(result) <= 1: |
207 break | 215 break |
208 changed_files += [result.replace('/branches/bleeding_edge/dart/', '')] | 216 changed_files += [result.replace('/branches/bleeding_edge/dart/', '')] |
sra1
2012/08/18 23:08:55
Don't strip of 'dart', you don't want to miss /bra
Emily Fortuna
2012/08/20 19:59:05
Sort-of-done (with a TODO)... This requires me to
| |
209 results = changed_files | 217 return changed_files |
218 | |
219 def has_perf_affecting_results(results): | |
sra1
2012/08/18 23:08:55
'results' is kind of generic.
Is this a list of li
Emily Fortuna
2012/08/20 19:59:05
Done.
| |
220 """Determine if this set of changed files might effect performance | |
221 tests.""" | |
222 for line in results: | |
223 tokens = line.split() | |
224 if len(tokens) >= 1: | |
225 # Loop through the changed files to see if it contains any files that | |
226 # are NOT listed in the no_effect list (directories not listed in | |
227 # the "no_effect" list are assumed to potentially affect performance. | |
228 if not reduce(lambda x, y: x or y, | |
229 [tokens[-1].startswith(item) for item in no_effect], False): | |
sra1
2012/08/18 23:08:55
If the filenames are cleanly extracted, and the no
Emily Fortuna
2012/08/20 19:59:05
Done.
| |
230 return True | |
231 return False | |
232 | |
233 if past_revision_num: | |
234 return (has_perf_affecting_results(get_svn_log_data(past_revision_num)), | |
235 past_revision_num) | |
210 else: | 236 else: |
211 results, _ = self.run_cmd(['svn', 'st', '-u'], std_in='p\r\n') | 237 results, _ = self.run_cmd(['svn', 'st', '-u'], std_in='p\r\n') |
212 results = results.split('\n') | 238 latest_interesting_server_rev = int(results.split('\n')[-2].split()[-1]) |
213 for line in results: | 239 done_cls = list(update_set_of_done_cls()) |
214 tokens = line.split() | 240 done_cls.sort() |
215 if past_revision_num or len(tokens) >= 3 and '*' in tokens[-3]: | 241 if len(done_cls) == 0: |
sra1
2012/08/18 23:08:55
idoimatic python tests for non-empty list like thi
Emily Fortuna
2012/08/20 19:59:05
Done.
| |
216 # Loop through the changed files to see if it contains any files that | 242 last_done_cl = EARLIEST_REVISION |
217 # are NOT listed in the no_effect list (directories not listed in | 243 else: |
218 # the "no_effect" list are assumed to potentially affect performance. | 244 last_done_cl = int(done_cls[-1]) |
219 if not reduce(lambda x, y: x or y, | 245 |
220 [tokens[-1].startswith(item) for item in no_effect], False): | 246 while latest_interesting_server_rev >= last_done_cl: |
221 return True | 247 results = get_svn_log_data(latest_interesting_server_rev) |
222 return False | 248 if has_perf_affecting_results(results): |
249 return (True, latest_interesting_server_rev) | |
250 else: | |
251 update_set_of_done_cls(latest_interesting_server_rev) | |
252 latest_interesting_server_rev -= 1 | |
253 return (False, None) | |
223 | 254 |
224 def get_os_directory(self): | 255 def get_os_directory(self): |
225 """Specifies the name of the directory for the testing build of dart, which | 256 """Specifies the name of the directory for the testing build of dart, which |
226 has yet a different naming convention from utils.getBuildRoot(...).""" | 257 has yet a different naming convention from utils.getBuildRoot(...).""" |
227 if platform.system() == 'Windows': | 258 if platform.system() == 'Windows': |
228 return 'windows' | 259 return 'windows' |
229 elif platform.system() == 'Darwin': | 260 elif platform.system() == 'Darwin': |
230 return 'macos' | 261 return 'macos' |
231 else: | 262 else: |
232 return 'linux' | 263 return 'linux' |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
464 Returns: True if the post was successful file.""" | 495 Returns: True if the post was successful file.""" |
465 return post_results.report_results(benchmark_name, score, platform, variant, | 496 return post_results.report_results(benchmark_name, score, platform, variant, |
466 revision_number, metric) | 497 revision_number, metric) |
467 | 498 |
468 def calculate_geometric_mean(self, platform, variant, svn_revision): | 499 def calculate_geometric_mean(self, platform, variant, svn_revision): |
469 """Calculate the aggregate geometric mean for JS and dart2js benchmark sets, | 500 """Calculate the aggregate geometric mean for JS and dart2js benchmark sets, |
470 given two benchmark dictionaries.""" | 501 given two benchmark dictionaries.""" |
471 geo_mean = 0 | 502 geo_mean = 0 |
472 if self.test.is_valid_combination(platform, variant): | 503 if self.test.is_valid_combination(platform, variant): |
473 for benchmark in self.test.values_list: | 504 for benchmark in self.test.values_list: |
505 if len(self.test.values_dict[platform][variant][benchmark]) == 0: | |
sra1
2012/08/18 23:08:55
len(x) == 0 --> not x
if not self.test.values_dict
Emily Fortuna
2012/08/20 19:59:05
Done.
| |
506 print 'Error determining mean for %s %s %s' % (platform, variant, | |
507 benchmark) | |
508 continue | |
474 geo_mean += math.log( | 509 geo_mean += math.log( |
475 self.test.values_dict[platform][variant][benchmark][ | 510 self.test.values_dict[platform][variant][benchmark][ |
476 len(self.test.values_dict[platform][variant][benchmark]) - 1]) | 511 len(self.test.values_dict[platform][variant][benchmark]) - 1]) |
sra1
2012/08/18 23:08:55
Python has negative indexes from the end, so index
Emily Fortuna
2012/08/20 19:59:05
Done.
| |
477 | 512 |
478 self.test.values_dict[platform][variant]['Geo-Mean'] += \ | 513 self.test.values_dict[platform][variant]['Geo-Mean'] += \ |
479 [math.pow(math.e, geo_mean / len(self.test.values_list))] | 514 [math.pow(math.e, geo_mean / len(self.test.values_list))] |
480 self.test.revision_dict[platform][variant]['Geo-Mean'] += [svn_revision] | 515 self.test.revision_dict[platform][variant]['Geo-Mean'] += [svn_revision] |
481 | 516 |
482 def get_score_type(self, benchmark_name): | 517 def get_score_type(self, benchmark_name): |
483 """Determine the type of score for posting -- default is 'Score' (aka | 518 """Determine the type of score for posting -- default is 'Score' (aka |
484 Runtime), other options are CompileTime and CodeSize.""" | 519 Runtime), other options are CompileTime and CodeSize.""" |
485 return self.SCORE | 520 return self.SCORE |
486 | 521 |
(...skipping 25 matching lines...) Expand all Loading... | |
512 file_processor) | 547 file_processor) |
513 self.platform_list = platform_list | 548 self.platform_list = platform_list |
514 self.platform_type = platform_type | 549 self.platform_type = platform_type |
515 self.versions = versions | 550 self.versions = versions |
516 self.benchmarks = benchmarks | 551 self.benchmarks = benchmarks |
517 | 552 |
518 | 553 |
519 class BrowserTester(Tester): | 554 class BrowserTester(Tester): |
520 @staticmethod | 555 @staticmethod |
521 def get_browsers(add_dartium=True): | 556 def get_browsers(add_dartium=True): |
522 browsers = []#['ff', 'chrome'] | 557 browsers = ['ff', 'chrome'] |
523 if add_dartium: | 558 if add_dartium: |
524 browsers += ['dartium'] | 559 browsers += ['dartium'] |
525 has_shell = False | 560 has_shell = False |
526 if platform.system() == 'Darwin': | 561 if platform.system() == 'Darwin': |
527 browsers += ['safari'] | 562 browsers += ['safari'] |
528 if platform.system() == 'Windows': | 563 if platform.system() == 'Windows': |
529 browsers += ['ie'] | 564 browsers += ['ie'] |
530 has_shell = True | 565 has_shell = True |
531 return browsers | 566 return browsers |
532 | 567 |
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
948 has_run_extra = False | 983 has_run_extra = False |
949 revision_num = int(search_for_revision(DART_REPO_LOC)) | 984 revision_num = int(search_for_revision(DART_REPO_LOC)) |
950 | 985 |
951 def try_to_run_additional(revision_number): | 986 def try_to_run_additional(revision_number): |
952 """Determine the number of results we have stored for a particular revision | 987 """Determine the number of results we have stored for a particular revision |
953 number, and if it is less than 10, run some extra tests. | 988 number, and if it is less than 10, run some extra tests. |
954 Args: | 989 Args: |
955 - revision_number: the revision whose performance we want to potentially | 990 - revision_number: the revision whose performance we want to potentially |
956 test. | 991 test. |
957 Returns: True if we successfully ran some additional tests.""" | 992 Returns: True if we successfully ran some additional tests.""" |
958 if not runner.has_interesting_code(revision_number): | 993 if not runner.has_interesting_code(revision_number)[0]: |
959 results_set = update_set_of_done_cls(revision_number) | 994 results_set = update_set_of_done_cls(revision_number) |
960 return False | 995 return False |
961 a_test = TestBuilder.make_test(runner.suite_names[0], runner) | 996 a_test = TestBuilder.make_test(runner.suite_names[0], runner) |
962 benchmark_name = a_test.values_list[0] | 997 benchmark_name = a_test.values_list[0] |
963 platform_name = a_test.platform_list[0] | 998 platform_name = a_test.platform_list[0] |
964 variant = a_test.values_dict[platform_name].keys()[0] | 999 variant = a_test.values_dict[platform_name].keys()[0] |
965 num_results = post_results.get_num_results(benchmark_name, | 1000 num_results = post_results.get_num_results(benchmark_name, |
966 platform_name, variant, revision_number, | 1001 platform_name, variant, revision_number, |
967 a_test.file_processor.get_score_type(benchmark_name)) | 1002 a_test.file_processor.get_score_type(benchmark_name)) |
968 if num_results < 10: | 1003 if num_results < 10: |
(...skipping 17 matching lines...) Expand all Loading... | |
986 # already has 10 runs, look for another CL number that is not yet have all | 1021 # already has 10 runs, look for another CL number that is not yet have all |
987 # of its additional runs (do this up to 15 times). | 1022 # of its additional runs (do this up to 15 times). |
988 tries = 0 | 1023 tries = 0 |
989 # Select which "thousands bucket" we're going to run additional tests for. | 1024 # Select which "thousands bucket" we're going to run additional tests for. |
990 bucket_size = 1000 | 1025 bucket_size = 1000 |
991 thousands_list = range(EARLIEST_REVISION/bucket_size, | 1026 thousands_list = range(EARLIEST_REVISION/bucket_size, |
992 int(revision_num)/bucket_size + 1) | 1027 int(revision_num)/bucket_size + 1) |
993 weighted_total = sum(thousands_list) | 1028 weighted_total = sum(thousands_list) |
994 generated_random_number = random.randint(0, weighted_total - 1) | 1029 generated_random_number = random.randint(0, weighted_total - 1) |
995 for i in list(reversed(thousands_list)): | 1030 for i in list(reversed(thousands_list)): |
996 thousands = thousands_list[i - 1] | 1031 thousands = i |
997 weighted_total -= thousands_list[i - 1] | 1032 weighted_total -= i |
998 if weighted_total <= generated_random_number: | 1033 if weighted_total <= generated_random_number: |
999 break | 1034 break |
1000 while tries < 15 and not has_run_extra: | 1035 while tries < 15 and not has_run_extra: |
1001 # Now select a particular revision in that bucket. | 1036 # Now select a particular revision in that bucket. |
1002 if thousands == int(revision_num)/bucket_size: | 1037 if thousands == int(revision_num)/bucket_size: |
1003 max_range = 1 + revision_num % bucket_size | 1038 max_range = 1 + revision_num % bucket_size |
1004 else: | 1039 else: |
1005 max_range = bucket_size | 1040 max_range = bucket_size |
1006 rev = thousands * bucket_size + random.randrange(0, max_range) | 1041 rev = thousands * bucket_size + random.randrange(0, max_range) |
1007 if rev not in results_set: | 1042 if rev not in results_set: |
(...skipping 22 matching lines...) Expand all Loading... | |
1030 os.mkdir(dirname(DART_REPO_LOC)) | 1065 os.mkdir(dirname(DART_REPO_LOC)) |
1031 os.chdir(dirname(DART_REPO_LOC)) | 1066 os.chdir(dirname(DART_REPO_LOC)) |
1032 p = subprocess.Popen('gclient config https://dart.googlecode.com/svn/' + | 1067 p = subprocess.Popen('gclient config https://dart.googlecode.com/svn/' + |
1033 'branches/bleeding_edge/deps/all.deps', | 1068 'branches/bleeding_edge/deps/all.deps', |
1034 stdout=subprocess.PIPE, stderr=subprocess.PIPE, | 1069 stdout=subprocess.PIPE, stderr=subprocess.PIPE, |
1035 shell=True) | 1070 shell=True) |
1036 p.communicate() | 1071 p.communicate() |
1037 if continuous: | 1072 if continuous: |
1038 while True: | 1073 while True: |
1039 results_set = update_set_of_done_cls() | 1074 results_set = update_set_of_done_cls() |
1040 if runner.has_interesting_code(): | 1075 interesting_code_results = runner.has_interesting_code() |
1041 runner.run_test_sequence() | 1076 if interesting_code_results[0]: |
1077 runner.run_test_sequence(interesting_code_results[1]) | |
1042 else: | 1078 else: |
1043 results_set = fill_in_back_history(results_set, runner) | 1079 results_set = fill_in_back_history(results_set, runner) |
1044 else: | 1080 else: |
1045 runner.run_test_sequence() | 1081 runner.run_test_sequence() |
1046 | 1082 |
1047 if __name__ == '__main__': | 1083 if __name__ == '__main__': |
1048 main() | 1084 main() |
OLD | NEW |