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 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
284 | 284 |
285 mean = CalculateMean(values) | 285 mean = CalculateMean(values) |
286 differences_from_mean = [float(x) - mean for x in values] | 286 differences_from_mean = [float(x) - mean for x in values] |
287 squared_differences = [float(x * x) for x in differences_from_mean] | 287 squared_differences = [float(x * x) for x in differences_from_mean] |
288 variance = sum(squared_differences) / (len(values) - 1) | 288 variance = sum(squared_differences) / (len(values) - 1) |
289 std_dev = math.sqrt(variance) | 289 std_dev = math.sqrt(variance) |
290 | 290 |
291 return std_dev | 291 return std_dev |
292 | 292 |
293 | 293 |
| 294 def CalculateRelativeChange(before, after): |
| 295 """Returns the relative change of before and after, relative to before. |
| 296 |
| 297 There are several different ways to define relative difference between |
| 298 two numbers; sometimes it is defined as relative to the smaller number, |
| 299 or to the mean of the two numbers. This version returns the difference |
| 300 relative to the first of the two numbers. |
| 301 |
| 302 Args: |
| 303 before: A number representing an earlier value. |
| 304 after: Another number, representing a later value. |
| 305 |
| 306 Returns: |
| 307 A non-negative floating point number; 0.1 represents a 10% change. |
| 308 """ |
| 309 if before == after: |
| 310 return 0.0 |
| 311 if before == 0: |
| 312 return float('nan') |
| 313 difference = after - before |
| 314 return math.fabs(difference / before) |
| 315 |
| 316 |
294 def CalculatePooledStandardError(work_sets): | 317 def CalculatePooledStandardError(work_sets): |
295 numerator = 0.0 | 318 numerator = 0.0 |
296 denominator1 = 0.0 | 319 denominator1 = 0.0 |
297 denominator2 = 0.0 | 320 denominator2 = 0.0 |
298 | 321 |
299 for current_set in work_sets: | 322 for current_set in work_sets: |
300 std_dev = CalculateStandardDeviation(current_set) | 323 std_dev = CalculateStandardDeviation(current_set) |
301 numerator += (len(current_set) - 1) * std_dev ** 2 | 324 numerator += (len(current_set) - 1) * std_dev ** 2 |
302 denominator1 += len(current_set) - 1 | 325 denominator1 += len(current_set) - 1 |
303 denominator2 += 1.0 / len(current_set) | 326 denominator2 += 1.0 / len(current_set) |
(...skipping 2854 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3158 working_means.append(revision_data_sorted[i][1]['value']['values']) | 3181 working_means.append(revision_data_sorted[i][1]['value']['values']) |
3159 | 3182 |
3160 # Flatten the lists to calculate mean of all values. | 3183 # Flatten the lists to calculate mean of all values. |
3161 working_mean = sum(working_means, []) | 3184 working_mean = sum(working_means, []) |
3162 broken_mean = sum(broken_means, []) | 3185 broken_mean = sum(broken_means, []) |
3163 | 3186 |
3164 # Calculate the approximate size of the regression | 3187 # Calculate the approximate size of the regression |
3165 mean_of_bad_runs = CalculateMean(broken_mean) | 3188 mean_of_bad_runs = CalculateMean(broken_mean) |
3166 mean_of_good_runs = CalculateMean(working_mean) | 3189 mean_of_good_runs = CalculateMean(working_mean) |
3167 | 3190 |
3168 regression_size = math.fabs(max(mean_of_good_runs, mean_of_bad_runs) / | 3191 regression_size = 100 * CalculateRelativeChange(mean_of_good_runs, |
3169 max(0.0001, min(mean_of_good_runs, mean_of_bad_runs))) * 100.0 - 100.0 | 3192 mean_of_bad_runs) |
| 3193 if math.isnan(regression_size): |
| 3194 regression_size = 'zero-to-nonzero' |
3170 | 3195 |
3171 regression_std_err = math.fabs(CalculatePooledStandardError( | 3196 regression_std_err = math.fabs(CalculatePooledStandardError( |
3172 [working_mean, broken_mean]) / | 3197 [working_mean, broken_mean]) / |
3173 max(0.0001, min(mean_of_good_runs, mean_of_bad_runs))) * 100.0 | 3198 max(0.0001, min(mean_of_good_runs, mean_of_bad_runs))) * 100.0 |
3174 | 3199 |
3175 # Give a "confidence" in the bisect. At the moment we use how distinct the | 3200 # Give a "confidence" in the bisect. At the moment we use how distinct the |
3176 # values are before and after the last broken revision, and how noisy the | 3201 # values are before and after the last broken revision, and how noisy the |
3177 # overall graph is. | 3202 # overall graph is. |
3178 confidence = CalculateConfidence(working_means, broken_means) | 3203 confidence = CalculateConfidence(working_means, broken_means) |
3179 | 3204 |
(...skipping 514 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3694 # The perf dashboard scrapes the "results" step in order to comment on | 3719 # The perf dashboard scrapes the "results" step in order to comment on |
3695 # bugs. If you change this, please update the perf dashboard as well. | 3720 # bugs. If you change this, please update the perf dashboard as well. |
3696 bisect_utils.OutputAnnotationStepStart('Results') | 3721 bisect_utils.OutputAnnotationStepStart('Results') |
3697 print 'Error: %s' % e.message | 3722 print 'Error: %s' % e.message |
3698 if opts.output_buildbot_annotations: | 3723 if opts.output_buildbot_annotations: |
3699 bisect_utils.OutputAnnotationStepClosed() | 3724 bisect_utils.OutputAnnotationStepClosed() |
3700 return 1 | 3725 return 1 |
3701 | 3726 |
3702 if __name__ == '__main__': | 3727 if __name__ == '__main__': |
3703 sys.exit(main()) | 3728 sys.exit(main()) |
OLD | NEW |