OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Performance Test Bisect Tool | 6 """Performance Test Bisect Tool |
7 | 7 |
8 This script bisects a series of changelists using binary search. It starts at | 8 This script bisects a series of changelists using binary search. It starts at |
9 a bad revision where a performance metric has regressed, and asks for a last | 9 a bad revision where a performance metric has regressed, and asks for a last |
10 known-good revision. It will then binary search across this revision range by | 10 known-good revision. It will then binary search across this revision range by |
(...skipping 1501 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1512 updated_deps_content = self.UpdateDepsContents( | 1512 updated_deps_content = self.UpdateDepsContents( |
1513 deps_contents, depot, revision, deps_var) | 1513 deps_contents, depot, revision, deps_var) |
1514 # Write changes to DEPS file | 1514 # Write changes to DEPS file |
1515 if updated_deps_content: | 1515 if updated_deps_content: |
1516 WriteStringToFile(updated_deps_content, deps_file) | 1516 WriteStringToFile(updated_deps_content, deps_file) |
1517 return True | 1517 return True |
1518 except IOError, e: | 1518 except IOError, e: |
1519 print 'Something went wrong while updating DEPS file. [%s]' % e | 1519 print 'Something went wrong while updating DEPS file. [%s]' % e |
1520 return False | 1520 return False |
1521 | 1521 |
1522 | |
1523 def CreateDEPSPatch(self, depot, revision): | 1522 def CreateDEPSPatch(self, depot, revision): |
1524 """Modifies DEPS and returns diff as text. | 1523 """Modifies DEPS and returns diff as text. |
1525 | 1524 |
1526 Args: | 1525 Args: |
1527 depot: Current depot being bisected. | 1526 depot: Current depot being bisected. |
1528 revision: A git hash revision of the dependency repository. | 1527 revision: A git hash revision of the dependency repository. |
1529 | 1528 |
1530 Returns: | 1529 Returns: |
1531 A tuple with git hash of chromium revision and DEPS patch text. | 1530 A tuple with git hash of chromium revision and DEPS patch text. |
1532 """ | 1531 """ |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1658 """ | 1657 """ |
1659 success_code, failure_code = 0, -1 | 1658 success_code, failure_code = 0, -1 |
1660 | 1659 |
1661 if self.opts.debug_ignore_perf_test: | 1660 if self.opts.debug_ignore_perf_test: |
1662 fake_results = { | 1661 fake_results = { |
1663 'mean': 0.0, | 1662 'mean': 0.0, |
1664 'std_err': 0.0, | 1663 'std_err': 0.0, |
1665 'std_dev': 0.0, | 1664 'std_dev': 0.0, |
1666 'values': [0.0] | 1665 'values': [0.0] |
1667 } | 1666 } |
1667 | |
1668 # When debug_fake_test_mean is passed, its value is returned as the mean | |
1669 # and such flag is cleared so that further calls behave as if it wasn't | |
1670 # passed. | |
qyearsley
2014/10/12 03:37:11
In this comment, it might be clearer to say "set"
RobertoCN
2014/10/15 18:44:44
Done.
| |
1671 if self.opts.debug_fake_first_test_mean: | |
1672 fake_results['mean'] = float(self.opts.debug_fake_first_test_mean) | |
1673 self.opts.debug_fake_first_test_mean = 0 | |
1674 | |
1668 return (fake_results, success_code) | 1675 return (fake_results, success_code) |
1669 | 1676 |
1670 # For Windows platform set posix=False, to parse windows paths correctly. | 1677 # For Windows platform set posix=False, to parse windows paths correctly. |
1671 # On Windows, path separators '\' or '\\' are replace by '' when posix=True, | 1678 # On Windows, path separators '\' or '\\' are replace by '' when posix=True, |
1672 # refer to http://bugs.python.org/issue1724822. By default posix=True. | 1679 # refer to http://bugs.python.org/issue1724822. By default posix=True. |
1673 args = shlex.split(command_to_run, posix=not bisect_utils.IsWindowsHost()) | 1680 args = shlex.split(command_to_run, posix=not bisect_utils.IsWindowsHost()) |
1674 | 1681 |
1675 if not _GenerateProfileIfNecessary(args): | 1682 if not _GenerateProfileIfNecessary(args): |
1676 err_text = 'Failed to generate profile for performance test.' | 1683 err_text = 'Failed to generate profile for performance test.' |
1677 return (err_text, failure_code) | 1684 return (err_text, failure_code) |
(...skipping 754 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2432 bad_results[0]) | 2439 bad_results[0]) |
2433 return results | 2440 return results |
2434 | 2441 |
2435 if good_results[1]: | 2442 if good_results[1]: |
2436 results.error = ('An error occurred while building and running ' | 2443 results.error = ('An error occurred while building and running ' |
2437 'the \'good\' reference value. The bisect cannot continue without ' | 2444 'the \'good\' reference value. The bisect cannot continue without ' |
2438 'a working \'good\' revision to start from.\n\nError: %s' % | 2445 'a working \'good\' revision to start from.\n\nError: %s' % |
2439 good_results[0]) | 2446 good_results[0]) |
2440 return results | 2447 return results |
2441 | 2448 |
2442 | |
2443 # We need these reference values to determine if later runs should be | 2449 # We need these reference values to determine if later runs should be |
2444 # classified as pass or fail. | 2450 # classified as pass or fail. |
2445 known_bad_value = bad_results[0] | 2451 known_bad_value = bad_results[0] |
2446 known_good_value = good_results[0] | 2452 known_good_value = good_results[0] |
2447 | 2453 |
2454 # Check the direction of improvement only if the direction_of_improvement | |
2455 # flag is non-false. | |
qyearsley
2014/10/12 03:37:11
What can it be if its non-false? It can be -1 or 1
RobertoCN
2014/10/15 18:44:44
Done.
| |
2456 improvement_dir = self.opts.direction_of_improvement | |
2457 if improvement_dir: | |
2458 higher_is_better = improvement_dir > 0 | |
2459 metric_increased = known_bad_value['mean'] > known_good_value['mean'] | |
2460 if ((higher_is_better and metric_increased) or | |
2461 (not higher_is_better and not metric_increased)): | |
2462 results.error = ('The given "good" - "bad" range does not represent ' | |
2463 'a regression but an improvement.') | |
2464 return results | |
2465 | |
2448 # Can just mark the good and bad revisions explicitly here since we | 2466 # Can just mark the good and bad revisions explicitly here since we |
2449 # already know the results. | 2467 # already know the results. |
2450 bad_revision_data = revision_data[revision_list[0]] | 2468 bad_revision_data = revision_data[revision_list[0]] |
2451 bad_revision_data['external'] = bad_results[2] | 2469 bad_revision_data['external'] = bad_results[2] |
2452 bad_revision_data['perf_time'] = bad_results[3] | 2470 bad_revision_data['perf_time'] = bad_results[3] |
2453 bad_revision_data['build_time'] = bad_results[4] | 2471 bad_revision_data['build_time'] = bad_results[4] |
2454 bad_revision_data['passed'] = False | 2472 bad_revision_data['passed'] = False |
2455 bad_revision_data['value'] = known_bad_value | 2473 bad_revision_data['value'] = known_bad_value |
2456 | 2474 |
2457 good_revision_data = revision_data[revision_list[max_revision]] | 2475 good_revision_data = revision_data[revision_list[max_revision]] |
(...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2939 self.max_time_minutes = 20 | 2957 self.max_time_minutes = 20 |
2940 self.metric = None | 2958 self.metric = None |
2941 self.command = None | 2959 self.command = None |
2942 self.output_buildbot_annotations = None | 2960 self.output_buildbot_annotations = None |
2943 self.no_custom_deps = False | 2961 self.no_custom_deps = False |
2944 self.working_directory = None | 2962 self.working_directory = None |
2945 self.extra_src = None | 2963 self.extra_src = None |
2946 self.debug_ignore_build = None | 2964 self.debug_ignore_build = None |
2947 self.debug_ignore_sync = None | 2965 self.debug_ignore_sync = None |
2948 self.debug_ignore_perf_test = None | 2966 self.debug_ignore_perf_test = None |
2967 self.debug_fake_first_test_mean = 0 | |
2949 self.gs_bucket = None | 2968 self.gs_bucket = None |
2950 self.target_arch = 'ia32' | 2969 self.target_arch = 'ia32' |
2951 self.target_build_type = 'Release' | 2970 self.target_build_type = 'Release' |
2952 self.builder_host = None | 2971 self.builder_host = None |
2953 self.builder_port = None | 2972 self.builder_port = None |
2954 self.bisect_mode = BISECT_MODE_MEAN | 2973 self.bisect_mode = BISECT_MODE_MEAN |
2974 self.direction_of_improvement = 0 | |
2955 | 2975 |
2956 @staticmethod | 2976 @staticmethod |
2957 def _CreateCommandLineParser(): | 2977 def _CreateCommandLineParser(): |
2958 """Creates a parser with bisect options. | 2978 """Creates a parser with bisect options. |
2959 | 2979 |
2960 Returns: | 2980 Returns: |
2961 An instance of optparse.OptionParser. | 2981 An instance of optparse.OptionParser. |
2962 """ | 2982 """ |
2963 usage = ('%prog [options] [-- chromium-options]\n' | 2983 usage = ('%prog [options] [-- chromium-options]\n' |
2964 'Perform binary search on revision history to find a minimal ' | 2984 'Perform binary search on revision history to find a minimal ' |
(...skipping 13 matching lines...) Expand all Loading... | |
2978 ' or svn revision.') | 2998 ' or svn revision.') |
2979 group.add_option('-g', '--good_revision', | 2999 group.add_option('-g', '--good_revision', |
2980 type='str', | 3000 type='str', |
2981 help='A revision to start bisection where performance' + | 3001 help='A revision to start bisection where performance' + |
2982 ' test is known to pass. Must be earlier than the ' + | 3002 ' test is known to pass. Must be earlier than the ' + |
2983 'bad revision. May be either a git or svn revision.') | 3003 'bad revision. May be either a git or svn revision.') |
2984 group.add_option('-m', '--metric', | 3004 group.add_option('-m', '--metric', |
2985 type='str', | 3005 type='str', |
2986 help='The desired metric to bisect on. For example ' + | 3006 help='The desired metric to bisect on. For example ' + |
2987 '"vm_rss_final_b/vm_rss_f_b"') | 3007 '"vm_rss_final_b/vm_rss_f_b"') |
3008 group.add_option('-d', '--direction_of_improvement', | |
3009 type='int', | |
3010 default=0, | |
3011 help='An integer number representing the direction of ' + | |
3012 'improvement. 1 for higher is better, -1 for lower is ' + | |
3013 'better, 0 for ignore (default).') | |
2988 group.add_option('-r', '--repeat_test_count', | 3014 group.add_option('-r', '--repeat_test_count', |
2989 type='int', | 3015 type='int', |
2990 default=20, | 3016 default=20, |
2991 help='The number of times to repeat the performance ' | 3017 help='The number of times to repeat the performance ' |
2992 'test. Values will be clamped to range [1, 100]. ' | 3018 'test. Values will be clamped to range [1, 100]. ' |
2993 'Default value is 20.') | 3019 'Default value is 20.') |
2994 group.add_option('--max_time_minutes', | 3020 group.add_option('--max_time_minutes', |
2995 type='int', | 3021 type='int', |
2996 default=20, | 3022 default=20, |
2997 help='The maximum time (in minutes) to take running the ' | 3023 help='The maximum time (in minutes) to take running the ' |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3098 group = optparse.OptionGroup(parser, 'Debug options') | 3124 group = optparse.OptionGroup(parser, 'Debug options') |
3099 group.add_option('--debug_ignore_build', | 3125 group.add_option('--debug_ignore_build', |
3100 action='store_true', | 3126 action='store_true', |
3101 help='DEBUG: Don\'t perform builds.') | 3127 help='DEBUG: Don\'t perform builds.') |
3102 group.add_option('--debug_ignore_sync', | 3128 group.add_option('--debug_ignore_sync', |
3103 action='store_true', | 3129 action='store_true', |
3104 help='DEBUG: Don\'t perform syncs.') | 3130 help='DEBUG: Don\'t perform syncs.') |
3105 group.add_option('--debug_ignore_perf_test', | 3131 group.add_option('--debug_ignore_perf_test', |
3106 action='store_true', | 3132 action='store_true', |
3107 help='DEBUG: Don\'t perform performance tests.') | 3133 help='DEBUG: Don\'t perform performance tests.') |
3134 group.add_option('--debug_fake_first_test_mean', | |
3135 type='int', | |
3136 default='0', | |
3137 help=('DEBUG: When faking performance tests, return this ' | |
3138 'value as the mean of the first performance test, ' | |
3139 'and return a mean of 0.0 for further tests.')) | |
3108 parser.add_option_group(group) | 3140 parser.add_option_group(group) |
3109 return parser | 3141 return parser |
3110 | 3142 |
3111 def ParseCommandLine(self): | 3143 def ParseCommandLine(self): |
3112 """Parses the command line for bisect options.""" | 3144 """Parses the command line for bisect options.""" |
3113 parser = self._CreateCommandLineParser() | 3145 parser = self._CreateCommandLineParser() |
3114 opts, _ = parser.parse_args() | 3146 opts, _ = parser.parse_args() |
3115 | 3147 |
3116 try: | 3148 try: |
3117 if not opts.command: | 3149 if not opts.command: |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3257 # bugs. If you change this, please update the perf dashboard as well. | 3289 # bugs. If you change this, please update the perf dashboard as well. |
3258 bisect_utils.OutputAnnotationStepStart('Results') | 3290 bisect_utils.OutputAnnotationStepStart('Results') |
3259 print 'Error: %s' % e.message | 3291 print 'Error: %s' % e.message |
3260 if opts.output_buildbot_annotations: | 3292 if opts.output_buildbot_annotations: |
3261 bisect_utils.OutputAnnotationStepClosed() | 3293 bisect_utils.OutputAnnotationStepClosed() |
3262 return 1 | 3294 return 1 |
3263 | 3295 |
3264 | 3296 |
3265 if __name__ == '__main__': | 3297 if __name__ == '__main__': |
3266 sys.exit(main()) | 3298 sys.exit(main()) |
OLD | NEW |