| // Copyright 2017 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Significance tests. |
| |
| package benchstat |
| |
| import ( |
| "errors" |
| |
| "golang.org/x/perf/internal/stats" |
| ) |
| |
| // A DeltaTest compares the old and new metrics and returns the |
| // expected probability that they are drawn from the same distribution. |
| // |
| // If a probability cannot be computed, the DeltaTest returns an |
| // error explaining why. Common errors include ErrSamplesEqual |
| // (all samples are equal), ErrSampleSize (there aren't enough samples), |
| // and ErrZeroVariance (the sample has zero variance). |
| // |
| // As a special case, the missing test NoDeltaTest returns -1, nil. |
| type DeltaTest func(old, new *Metrics) (float64, error) |
| |
| // Errors returned by DeltaTest. |
| var ( |
| ErrSamplesEqual = errors.New("all equal") |
| ErrSampleSize = errors.New("too few samples") |
| ErrZeroVariance = errors.New("zero variance") |
| ) |
| |
| // NoDeltaTest applies no delta test; it returns -1, nil. |
| func NoDeltaTest(old, new *Metrics) (pval float64, err error) { |
| return -1, nil |
| } |
| |
| // TTest is a DeltaTest using the two-sample Welch t-test. |
| func TTest(old, new *Metrics) (pval float64, err error) { |
| t, err := stats.TwoSampleWelchTTest(stats.Sample{Xs: old.RValues}, stats.Sample{Xs: new.RValues}, stats.LocationDiffers) |
| if err != nil { |
| return -1, convertErr(err) |
| } |
| return t.P, nil |
| } |
| |
| // UTest is a DeltaTest using the Mann-Whitney U test. |
| func UTest(old, new *Metrics) (pval float64, err error) { |
| u, err := stats.MannWhitneyUTest(old.RValues, new.RValues, stats.LocationDiffers) |
| if err != nil { |
| return -1, convertErr(err) |
| } |
| return u.P, nil |
| } |
| |
| // convertErr converts from the stats package's internal errors |
| // to errors exported by this package and expected from |
| // a DeltaTest. |
| // Using different errors makes it possible for clients to use |
| // package benchstat without access to the internal stats package, |
| // and it also gives us a chance to use shorter error messages. |
| func convertErr(err error) error { |
| switch err { |
| case stats.ErrZeroVariance: |
| return ErrZeroVariance |
| case stats.ErrSampleSize: |
| return ErrSampleSize |
| case stats.ErrSamplesEqual: |
| return ErrSamplesEqual |
| } |
| return err |
| } |