blob: 309b15afce9e3578c31a7c2300fe463fa4064099 [file] [log] [blame]
package stepfit
import (
"math"
"go.skia.org/infra/go/vec32"
)
const (
// The possible values for StepFit.Status are:
LOW = "Low"
HIGH = "High"
UNINTERESTING = "Uninteresting"
// MIN_SSE is the minimum sum squares error we'll accept.
MIN_SSE = 10e-6
)
// StepFit stores information on the best Step Function fit on a trace.
//
// Used in ClusterSummary.
type StepFit struct {
// LeastSquares is the Least Squares error for a step function curve fit to the trace.
LeastSquares float32 `json:"least_squares"`
// TurningPoint is the index where the Step Function changes value.
TurningPoint int `json:"turning_point"`
// StepSize is the size of the step in the step function. Negative values
// indicate a step up, i.e. they look like a performance regression in the
// trace, as opposed to positive values which look like performance
// improvements.
StepSize float32 `json:"step_size"`
// The "Regression" value is calculated as Step Size / Least Squares Error.
//
// The better the fit the larger the number returned, because LSE
// gets smaller with a better fit. The higher the Step Size the
// larger the number returned.
Regression float32 `json:"regression"`
// Status of the cluster.
//
// Values can be "High", "Low", and "Uninteresting"
Status string `json:"status"`
}
// GetStepFitAtMid takes one []float32 trace and calculates and returns a StepFit.
//
// See StepFit for a description of the values being calculated.
func GetStepFitAtMid(trace []float32, interesting float32) *StepFit {
lse := float32(math.MaxFloat32)
stepSize := float32(-1.0)
turn := 0
i := len(trace) / 2
y0 := vec32.Mean(trace[:i])
y1 := vec32.Mean(trace[i:])
if y0 != y1 {
d := vec32.SSE(trace[:i], y0) + vec32.SSE(trace[i:], y1)
if d < lse {
lse = d
stepSize = (y0 - y1)
turn = i
}
}
lse = float32(math.Sqrt(float64(lse))) / float32(len(trace))
var regression float32
if lse < MIN_SSE {
regression = stepSize / MIN_SSE
} else {
regression = stepSize / lse
}
status := UNINTERESTING
if regression > interesting {
status = LOW
} else if regression < -interesting {
status = HIGH
}
return &StepFit{
LeastSquares: lse,
StepSize: stepSize,
TurningPoint: turn,
Regression: regression,
Status: status,
}
}