in pkg/degradation-detector/degradationDetector.go [39:124]
func detectDegradations(values []int, builds []string, timestamps []int64, analysisSettings analysisSettings) []Degradation {
degradations := make([]Degradation, 0)
if analysisSettings.GetAnalysisKind() == ThresholdAnalysis {
return detectThresholdExceed(values, builds, timestamps, analysisSettings)
}
minimumSegmentLength := analysisSettings.GetMinimumSegmentLength()
if minimumSegmentLength == 0 {
minimumSegmentLength = 5
}
medianDifference := analysisSettings.GetMedianDifferenceThreshold()
if medianDifference == 0 {
medianDifference = 10
}
effectSizeThreshold := analysisSettings.GetEffectSizeThreshold()
if effectSizeThreshold == 0 {
effectSizeThreshold = 2
}
changePoints := statistic.GetChangePointIndexes(values, min(5, len(values)/2))
segments := GetSegmentsBetweenChangePoints(changePoints, values)
if len(segments) < 2 {
slog.Debug("no significant change points were detected")
return degradations
}
lastSegment := segments[len(segments)-1]
if len(lastSegment) < minimumSegmentLength {
slog.Info("last segment is too short")
return degradations
}
skippedSegments := 0
for i := len(segments) - 2; i >= 0 && skippedSegments < 4; i-- {
if len(segments[i]) < minimumSegmentLength {
skippedSegments++
continue
}
currentCenter, err := pragmastat.Center(lastSegment)
if err != nil {
skippedSegments++
continue
}
previousCenter, err := pragmastat.Center(segments[i])
if err != nil {
skippedSegments++
continue
}
ratio := currentCenter / previousCenter
percentageChange := math.Abs((ratio - 1) * 100)
absoluteChange := math.Abs(currentCenter - previousCenter)
if absoluteChange < 10 || percentageChange < medianDifference {
break
}
es := statistic.EffectSize(lastSegment, segments[i])
if es < effectSizeThreshold {
break
}
isDegradation := currentCenter > previousCenter
reportType := analysisSettings.GetReportType()
if !isDegradation && reportType == DegradationEvent {
break
}
if isDegradation && reportType == ImprovementEvent {
break
}
index := changePoints[len(segments)-2]
degradations = append(degradations, Degradation{
Build: builds[index],
timestamp: timestamps[index],
medianValues: CenterValues{previousValue: previousCenter, newValue: currentCenter},
IsDegradation: isDegradation,
})
break
}
return degradations
}