Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(51)

Side by Side Diff: tools/testing/perf_testing/run_perf_tests.py

Issue 10829408: Smarter "new interesting code" detection. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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()
OLDNEW
« no previous file with comments | « no previous file | tools/testing/webdriver_test_setup.py » ('j') | tools/testing/webdriver_test_setup.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698