Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 | 2 |
| 3 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 3 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 4 # for details. All rights reserved. Use of this source code is governed by a | 4 # for details. All rights reserved. Use of this source code is governed by a |
| 5 # BSD-style license that can be found in the LICENSE file. | 5 # BSD-style license that can be found in the LICENSE file. |
| 6 | 6 |
| 7 import datetime | 7 import datetime |
| 8 import math | 8 import math |
| 9 try: | 9 try: |
| 10 from matplotlib.font_manager import FontProperties | 10 from matplotlib.font_manager import FontProperties |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 137 print 'Broken Build' | 137 print 'Broken Build' |
| 138 return 1 | 138 return 1 |
| 139 return 0 | 139 return 0 |
| 140 | 140 |
| 141 def ensure_output_directory(self, dir_name): | 141 def ensure_output_directory(self, dir_name): |
| 142 """Test that the listed directory name exists, and if not, create one for | 142 """Test that the listed directory name exists, and if not, create one for |
| 143 our output to be placed. | 143 our output to be placed. |
| 144 | 144 |
| 145 Args: | 145 Args: |
| 146 dir_name: the directory we will create if it does not exist.""" | 146 dir_name: the directory we will create if it does not exist.""" |
| 147 dir_path = os.path.join(DART_INSTALL_LOCATION, 'tools', | 147 for directory in [dir_name, 'old', os.path.join('old', dir_name)]: |
| 148 'testing', 'perf_testing', dir_name) | 148 dir_path = os.path.join(DART_INSTALL_LOCATION, 'tools', |
| 149 if not os.path.exists(dir_path): | 149 'testing', 'perf_testing', directory) |
| 150 os.mkdir(dir_path) | 150 if not os.path.exists(dir_path): |
| 151 print 'Creating output directory ', dir_path | 151 os.mkdir(dir_path) |
|
vsm
2012/05/07 20:25:54
You can eliminate 'old' from your list and just ca
Emily Fortuna
2012/05/08 01:24:51
Done.
| |
| 152 print 'Creating output directory ', dir_path | |
| 152 | 153 |
| 153 def has_new_code(self): | 154 def has_new_code(self): |
| 154 """Tests if there are any newer versions of files on the server.""" | 155 """Tests if there are any newer versions of files on the server.""" |
| 155 os.chdir(DART_INSTALL_LOCATION) | 156 os.chdir(DART_INSTALL_LOCATION) |
| 156 # Pass 'p' in if we have a new certificate for the svn server, we want to | 157 # Pass 'p' in if we have a new certificate for the svn server, we want to |
| 157 # (p)ermanently accept it. | 158 # (p)ermanently accept it. |
| 158 results = self.run_cmd(['svn', 'st', '-u'], std_in='p') | 159 results = self.run_cmd(['svn', 'st', '-u'], std_in='p\r\n') |
| 159 for line in results: | 160 for line in results: |
| 160 if '*' in line: | 161 if '*' in line: |
| 161 return True | 162 return True |
| 162 return False | 163 return False |
| 163 | 164 |
| 164 def get_os_directory(self): | 165 def get_os_directory(self): |
| 165 """Specifies the name of the directory for the testing build of dart, which | 166 """Specifies the name of the directory for the testing build of dart, which |
| 166 has yet a different naming convention from utils.getBuildRoot(...).""" | 167 has yet a different naming convention from utils.getBuildRoot(...).""" |
| 167 if platform.system() == 'Windows': | 168 if platform.system() == 'Windows': |
| 168 return 'windows' | 169 return 'windows' |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 344 for visitor in [self.tester, self.file_processor, self.grapher]: | 345 for visitor in [self.tester, self.file_processor, self.grapher]: |
| 345 visitor.prepare() | 346 visitor.prepare() |
| 346 | 347 |
| 347 os.chdir(DART_INSTALL_LOCATION) | 348 os.chdir(DART_INSTALL_LOCATION) |
| 348 self.test_runner.ensure_output_directory(self.result_folder_name) | 349 self.test_runner.ensure_output_directory(self.result_folder_name) |
| 349 if not self.test_runner.no_test: | 350 if not self.test_runner.no_test: |
| 350 self.tester.run_tests() | 351 self.tester.run_tests() |
| 351 | 352 |
| 352 os.chdir(os.path.join('tools', 'testing', 'perf_testing')) | 353 os.chdir(os.path.join('tools', 'testing', 'perf_testing')) |
| 353 | 354 |
| 354 files = os.listdir(self.result_folder_name) | 355 for directory in [os.path.join('old', self.result_folder_name), |
| 355 for afile in files: | 356 self.result_folder_name]: |
|
vsm
2012/05/07 20:25:54
I would unroll this loop for clarity also - especi
Emily Fortuna
2012/05/08 01:24:51
Done.
| |
| 356 if not afile.startswith('.'): | 357 old_dir = '/old/' in directory or '\\old\\' in directory |
| 357 self.file_processor.process_file(afile) | 358 files = os.listdir(directory) |
| 358 | 359 for afile in files: |
| 359 if 'plt' in globals(): | 360 if not afile.startswith('.'): |
| 360 # Only run Matplotlib if it is installed. | 361 if self.file_processor.process_file(afile, not old_dir) and \ |
|
vsm
2012/05/07 20:25:54
I'd take process_file out of the conditional. It'
Emily Fortuna
2012/05/08 01:24:51
Done.
| |
| 361 self.grapher.plot_results('%s.png' % self.result_folder_name) | 362 not old_dir: |
| 363 shutil.move(os.path.join(self.result_folder_name, afile), | |
| 364 os.path.join('old', self.result_folder_name, afile)) | |
| 365 if 'plt' in globals() and old_dir: | |
| 366 # Only run Matplotlib if it is installed. | |
| 367 self.grapher.plot_results('%s.png' % self.result_folder_name) | |
| 362 | 368 |
| 363 | 369 |
| 364 class Tester(object): | 370 class Tester(object): |
| 365 """The base level visitor class that runs tests. It contains convenience | 371 """The base level visitor class that runs tests. It contains convenience |
| 366 methods that many Tester objects use. Any class that would like to be a | 372 methods that many Tester objects use. Any class that would like to be a |
| 367 TesterVisitor must implement the run_tests() method.""" | 373 TesterVisitor must implement the run_tests() method.""" |
| 368 | 374 |
| 369 def __init__(self, test): | 375 def __init__(self, test): |
| 370 self.test = test | 376 self.test = test |
| 371 | 377 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 411 COMPILE_TIME = 'CompileTime' | 417 COMPILE_TIME = 'CompileTime' |
| 412 CODE_SIZE = 'CodeSize' | 418 CODE_SIZE = 'CodeSize' |
| 413 | 419 |
| 414 def __init__(self, test): | 420 def __init__(self, test): |
| 415 self.test = test | 421 self.test = test |
| 416 | 422 |
| 417 def prepare(self): | 423 def prepare(self): |
| 418 """Perform any initial setup required before the test is run.""" | 424 """Perform any initial setup required before the test is run.""" |
| 419 pass | 425 pass |
| 420 | 426 |
| 421 def should_report_results(self, afile): | |
| 422 """We store all trace files locally, but we don't want to post all of the | |
| 423 results every time, so we only attempt to post results for recent runs.""" | |
| 424 cur_time = time.time() | |
| 425 file_mod_time = os.path.getmtime(os.path.join( | |
| 426 self.test.result_folder_name, afile)) | |
| 427 return cur_time - file_mod_time < 1000 # Files modified in the last ~15 min. | |
| 428 | |
| 429 def report_results(self, benchmark_name, score, platform, variant, | 427 def report_results(self, benchmark_name, score, platform, variant, |
| 430 revision_number, metric): | 428 revision_number, metric): |
| 431 """Store the results of the benchmark run. | 429 """Store the results of the benchmark run. |
| 432 Args: | 430 Args: |
| 433 benchmark_name: The name of the individual benchmark. | 431 benchmark_name: The name of the individual benchmark. |
| 434 score: The numerical value of this benchmark. | 432 score: The numerical value of this benchmark. |
| 435 platform: The platform the test was run on (firefox, command line, etc). | 433 platform: The platform the test was run on (firefox, command line, etc). |
| 436 variant: Specifies whether the data was about generated Frog, js, a | 434 variant: Specifies whether the data was about generated Frog, js, a |
| 437 combination of both, or Dart depending on the test. | 435 combination of both, or Dart depending on the test. |
| 438 revision_number: The revision of the code (and sometimes the revision of | 436 revision_number: The revision of the code (and sometimes the revision of |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 674 file_path = os.path.join( | 672 file_path = os.path.join( |
| 675 os.getcwd(), 'internal', 'browserBenchmarks', | 673 os.getcwd(), 'internal', 'browserBenchmarks', |
| 676 'benchmark_page_%s.html' % version) | 674 'benchmark_page_%s.html' % version) |
| 677 self.test.test_runner.run_cmd( | 675 self.test.test_runner.run_cmd( |
| 678 ['python', os.path.join('tools', 'testing', 'run_selenium.py'), | 676 ['python', os.path.join('tools', 'testing', 'run_selenium.py'), |
| 679 '--out', file_path, '--browser', browser, | 677 '--out', file_path, '--browser', browser, |
| 680 '--timeout', '600', '--mode', 'perf'], self.test.trace_file, | 678 '--timeout', '600', '--mode', 'perf'], self.test.trace_file, |
| 681 append=True) | 679 append=True) |
| 682 | 680 |
| 683 class CommonBrowserFileProcessor(Processor): | 681 class CommonBrowserFileProcessor(Processor): |
| 684 def process_file(self, afile): | 682 def process_file(self, afile, should_post_file): |
| 685 """Comb through the html to find the performance results. | 683 """Comb through the html to find the performance results. |
| 686 Returns: True if we successfully posted our data to storage and/or we can | 684 Returns: True if we successfully posted our data to storage and/or we can |
| 687 delete the trace file.""" | 685 delete the trace file.""" |
| 688 os.chdir(os.path.join(DART_INSTALL_LOCATION, 'tools', | 686 os.chdir(os.path.join(DART_INSTALL_LOCATION, 'tools', |
| 689 'testing', 'perf_testing')) | 687 'testing', 'perf_testing')) |
| 690 parts = afile.split('-') | 688 parts = afile.split('-') |
| 691 browser = parts[2] | 689 browser = parts[2] |
| 692 version = parts[3] | 690 version = parts[3] |
| 693 f = open(os.path.join(self.test.result_folder_name, afile)) | 691 f = open(os.path.join(self.test.result_folder_name, afile)) |
| 694 lines = f.readlines() | 692 lines = f.readlines() |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 719 name_and_score = result.split(':') | 717 name_and_score = result.split(':') |
| 720 if len(name_and_score) < 2: | 718 if len(name_and_score) < 2: |
| 721 break | 719 break |
| 722 name = name_and_score[0].strip() | 720 name = name_and_score[0].strip() |
| 723 score = name_and_score[1].strip() | 721 score = name_and_score[1].strip() |
| 724 if version == 'js' or version == 'v8': | 722 if version == 'js' or version == 'v8': |
| 725 version = 'js' | 723 version = 'js' |
| 726 bench_dict = self.test.values_dict[browser][version] | 724 bench_dict = self.test.values_dict[browser][version] |
| 727 bench_dict[name] += [float(score)] | 725 bench_dict[name] += [float(score)] |
| 728 self.test.revision_dict[browser][version][name] += [revision_num] | 726 self.test.revision_dict[browser][version][name] += [revision_num] |
| 729 if self.should_report_results(afile) and \ | 727 if not self.test.test_runner.no_upload and should_post_file: |
| 730 not self.test.test_runner.no_upload: | |
| 731 upload_success = upload_success and self.report_results( | 728 upload_success = upload_success and self.report_results( |
| 732 name, score, browser, version, revision_num, self.SCORE) | 729 name, score, browser, version, revision_num, self.SCORE) |
| 733 else: | 730 else: |
| 734 upload_success = False | 731 upload_success = False |
| 735 | 732 |
| 736 f.close() | 733 f.close() |
| 737 self.calculate_geometric_mean(browser, version, revision_num) | 734 self.calculate_geometric_mean(browser, version, revision_num) |
| 738 return upload_success | 735 return upload_success |
| 739 | 736 |
| 740 | 737 |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 863 @staticmethod | 860 @staticmethod |
| 864 def get_dromaeo_url_query(browser, version): | 861 def get_dromaeo_url_query(browser, version): |
| 865 if browser == 'dartium': | 862 if browser == 'dartium': |
| 866 version = version.replace('frog', 'dart') | 863 version = version.replace('frog', 'dart') |
| 867 version = version.replace('_','&') | 864 version = version.replace('_','&') |
| 868 tags = DromaeoTester.get_valid_dromaeo_tags() | 865 tags = DromaeoTester.get_valid_dromaeo_tags() |
| 869 return '|'.join([ '%s&%s' % (version, tag) for tag in tags]) | 866 return '|'.join([ '%s&%s' % (version, tag) for tag in tags]) |
| 870 | 867 |
| 871 | 868 |
| 872 class DromaeoFileProcessor(Processor): | 869 class DromaeoFileProcessor(Processor): |
| 873 def process_file(self, afile): | 870 def process_file(self, afile, should_post_file): |
| 874 """Comb through the html to find the performance results. | 871 """Comb through the html to find the performance results. |
| 875 Returns: True if we successfully posted our data to storage.""" | 872 Returns: True if we successfully posted our data to storage.""" |
| 876 parts = afile.split('-') | 873 parts = afile.split('-') |
| 877 browser = parts[2] | 874 browser = parts[2] |
| 878 version = parts[3] | 875 version = parts[3] |
| 879 | 876 |
| 880 bench_dict = self.test.values_dict[browser][version] | 877 bench_dict = self.test.values_dict[browser][version] |
| 881 | 878 |
| 882 f = open(os.path.join(self.test.result_folder_name, afile)) | 879 f = open(os.path.join(self.test.result_folder_name, afile)) |
| 883 lines = f.readlines() | 880 lines = f.readlines() |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 899 for suite_result in suite_results: | 896 for suite_result in suite_results: |
| 900 results = re.findall(r'<li>(.*?)</li>', suite_result) | 897 results = re.findall(r'<li>(.*?)</li>', suite_result) |
| 901 if results: | 898 if results: |
| 902 for result in results: | 899 for result in results: |
| 903 r = re.match(result_pattern, result) | 900 r = re.match(result_pattern, result) |
| 904 name = DromaeoTester.legalize_filename(r.group(1).strip(':')) | 901 name = DromaeoTester.legalize_filename(r.group(1).strip(':')) |
| 905 score = float(r.group(2)) | 902 score = float(r.group(2)) |
| 906 bench_dict[name] += [float(score)] | 903 bench_dict[name] += [float(score)] |
| 907 self.test.revision_dict[browser][version][name] += \ | 904 self.test.revision_dict[browser][version][name] += \ |
| 908 [revision_num] | 905 [revision_num] |
| 909 if self.should_report_results(afile) and \ | 906 if not self.test.test_runner.no_upload and should_post_file: |
| 910 not self.test.test_runner.no_upload: | |
| 911 upload_success = upload_success and self.report_results( | 907 upload_success = upload_success and self.report_results( |
| 912 name, score, browser, version, revision_num, self.SCORE) | 908 name, score, browser, version, revision_num, self.SCORE) |
| 913 else: | 909 else: |
| 914 upload_success = False | 910 upload_success = False |
| 915 | 911 |
| 916 f.close() | 912 f.close() |
| 917 self.calculate_geometric_mean(browser, version, revision_num) | 913 self.calculate_geometric_mean(browser, version, revision_num) |
| 918 return upload_success | 914 return upload_success |
| 919 | 915 |
| 920 | 916 |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 993 self.test.extra_metrics[0])], | 989 self.test.extra_metrics[0])], |
| 994 self.test.trace_file, append=True) | 990 self.test.trace_file, append=True) |
| 995 for (variant, _) in variants: | 991 for (variant, _) in variants: |
| 996 self.test.test_runner.run_cmd( | 992 self.test.test_runner.run_cmd( |
| 997 ['echo', 'Size (%s, %s): %s' % (variant, self.test.extra_metrics[0], | 993 ['echo', 'Size (%s, %s): %s' % (variant, self.test.extra_metrics[0], |
| 998 total_size[variant])], | 994 total_size[variant])], |
| 999 self.test.trace_file, append=True) | 995 self.test.trace_file, append=True) |
| 1000 | 996 |
| 1001 | 997 |
| 1002 class DromaeoSizeProcessor(Processor): | 998 class DromaeoSizeProcessor(Processor): |
| 1003 def process_file(self, afile): | 999 def process_file(self, afile, should_post_file): |
| 1004 """Pull all the relevant information out of a given tracefile. | 1000 """Pull all the relevant information out of a given tracefile. |
| 1005 | 1001 |
| 1006 Args: | 1002 Args: |
| 1007 afile: is the filename string we will be processing. | 1003 afile: is the filename string we will be processing. |
| 1008 Returns: True if we successfully posted our data to storage.""" | 1004 Returns: True if we successfully posted our data to storage.""" |
| 1009 os.chdir(os.path.join(DART_INSTALL_LOCATION, 'tools', | 1005 os.chdir(os.path.join(DART_INSTALL_LOCATION, 'tools', |
| 1010 'testing', 'perf_testing')) | 1006 'testing', 'perf_testing')) |
| 1011 f = open(os.path.join(self.test.result_folder_name, afile)) | 1007 f = open(os.path.join(self.test.result_folder_name, afile)) |
| 1012 tabulate_data = False | 1008 tabulate_data = False |
| 1013 revision_num = 0 | 1009 revision_num = 0 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1026 variant = result.group(1) | 1022 variant = result.group(1) |
| 1027 metric = result.group(2) | 1023 metric = result.group(2) |
| 1028 num = result.group(3) | 1024 num = result.group(3) |
| 1029 if num.find('.') == -1: | 1025 if num.find('.') == -1: |
| 1030 num = int(num) | 1026 num = int(num) |
| 1031 else: | 1027 else: |
| 1032 num = float(num) | 1028 num = float(num) |
| 1033 self.test.values_dict['commandline'][variant][metric] += [num] | 1029 self.test.values_dict['commandline'][variant][metric] += [num] |
| 1034 self.test.revision_dict['commandline'][variant][metric] += \ | 1030 self.test.revision_dict['commandline'][variant][metric] += \ |
| 1035 [revision_num] | 1031 [revision_num] |
| 1036 if self.should_report_results(afile) and \ | 1032 if not self.test.test_runner.no_upload and should_post_file: |
| 1037 not self.test.test_runner.no_upload: | |
| 1038 upload_success = upload_success and self.report_results( | 1033 upload_success = upload_success and self.report_results( |
| 1039 metric, num, 'commandline', variant, revision_num, | 1034 metric, num, 'commandline', variant, revision_num, |
| 1040 self.CODE_SIZE) | 1035 self.CODE_SIZE) |
| 1041 else: | 1036 else: |
| 1042 upload_success = False | 1037 upload_success = False |
| 1043 | 1038 |
| 1044 f.close() | 1039 f.close() |
| 1045 return upload_success | 1040 return upload_success |
| 1046 | 1041 |
| 1047 class DromaeoSizeGrapher(Grapher): | 1042 class DromaeoSizeGrapher(Grapher): |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1123 | 1118 |
| 1124 self.test.test_runner.run_cmd( | 1119 self.test.test_runner.run_cmd( |
| 1125 ['echo', '%d Generated checked total size' % total_size], | 1120 ['echo', '%d Generated checked total size' % total_size], |
| 1126 self.test.trace_file, append=True) | 1121 self.test.trace_file, append=True) |
| 1127 | 1122 |
| 1128 os.chdir('..') | 1123 os.chdir('..') |
| 1129 | 1124 |
| 1130 | 1125 |
| 1131 class CompileProcessor(Processor): | 1126 class CompileProcessor(Processor): |
| 1132 | 1127 |
| 1133 def process_file(self, afile): | 1128 def process_file(self, afile, should_post_file): |
| 1134 """Pull all the relevant information out of a given tracefile. | 1129 """Pull all the relevant information out of a given tracefile. |
| 1135 | 1130 |
| 1136 Args: | 1131 Args: |
| 1137 afile: is the filename string we will be processing. | 1132 afile: is the filename string we will be processing. |
| 1138 Returns: True if we successfully posted our data to storage.""" | 1133 Returns: True if we successfully posted our data to storage.""" |
| 1139 os.chdir(os.path.join(DART_INSTALL_LOCATION, 'tools', | 1134 os.chdir(os.path.join(DART_INSTALL_LOCATION, 'tools', |
| 1140 'testing', 'perf_testing')) | 1135 'testing', 'perf_testing')) |
| 1141 f = open(os.path.join(self.test.result_folder_name, afile)) | 1136 f = open(os.path.join(self.test.result_folder_name, afile)) |
| 1142 tabulate_data = False | 1137 tabulate_data = False |
| 1143 revision_num = 0 | 1138 revision_num = 0 |
| 1144 upload_success = True | 1139 upload_success = True |
| 1145 for line in f.readlines(): | 1140 for line in f.readlines(): |
| 1146 tokens = line.split() | 1141 tokens = line.split() |
| 1147 if 'Revision' in line: | 1142 if 'Revision' in line: |
| 1148 revision_num = int(line.split()[1]) | 1143 revision_num = int(line.split()[1]) |
| 1149 else: | 1144 else: |
| 1150 for metric in self.test.values_list: | 1145 for metric in self.test.values_list: |
| 1151 if metric in line: | 1146 if metric in line: |
| 1152 num = tokens[0] | 1147 num = tokens[0] |
| 1153 if num.find('.') == -1: | 1148 if num.find('.') == -1: |
| 1154 num = int(num) | 1149 num = int(num) |
| 1155 else: | 1150 else: |
| 1156 num = float(num) | 1151 num = float(num) |
| 1157 self.test.values_dict['commandline']['frog'][metric] += [num] | 1152 self.test.values_dict['commandline']['frog'][metric] += [num] |
| 1158 self.test.revision_dict['commandline']['frog'][metric] += \ | 1153 self.test.revision_dict['commandline']['frog'][metric] += \ |
| 1159 [revision_num] | 1154 [revision_num] |
| 1160 score_type = self.CODE_SIZE | 1155 score_type = self.CODE_SIZE |
| 1161 if 'Compiling' in metric or 'Bootstrapping' in metric: | 1156 if 'Compiling' in metric or 'Bootstrapping' in metric: |
| 1162 score_type = self.COMPILE_TIME | 1157 score_type = self.COMPILE_TIME |
| 1163 if self.should_report_results(afile) and \ | 1158 if not self.test.test_runner.no_upload and should_post_file: |
| 1164 not self.test.test_runner.no_upload: | |
| 1165 if num < self.test.failure_threshold[metric]: | 1159 if num < self.test.failure_threshold[metric]: |
| 1166 num = 0 | 1160 num = 0 |
| 1167 upload_success = upload_success and self.report_results( | 1161 upload_success = upload_success and self.report_results( |
| 1168 metric, num, 'commandline', 'frog', revision_num, | 1162 metric, num, 'commandline', 'frog', revision_num, |
| 1169 score_type) | 1163 score_type) |
| 1170 else: | 1164 else: |
| 1171 upload_success = False | 1165 upload_success = False |
| 1172 if revision_num != 0: | 1166 if revision_num != 0: |
| 1173 for metric in self.test.values_list: | 1167 for metric in self.test.values_list: |
| 1174 self.test.revision_dict['commandline']['frog'][metric].pop() | 1168 self.test.revision_dict['commandline']['frog'][metric].pop() |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1213 while True: | 1207 while True: |
| 1214 if runner.has_new_code(): | 1208 if runner.has_new_code(): |
| 1215 runner.run_test_sequence() | 1209 runner.run_test_sequence() |
| 1216 else: | 1210 else: |
| 1217 time.sleep(200) | 1211 time.sleep(200) |
| 1218 else: | 1212 else: |
| 1219 runner.run_test_sequence() | 1213 runner.run_test_sequence() |
| 1220 | 1214 |
| 1221 if __name__ == '__main__': | 1215 if __name__ == '__main__': |
| 1222 main() | 1216 main() |
| OLD | NEW |