| 31 | } |
| 32 | |
| 33 | func (a *Auditor) auditMatrix(x, y model.Matrix) (diff Diff, err error) { |
| 34 | // different # of returned series |
| 35 | if len(x) != len(y) { |
| 36 | return diff, errors.Errorf("different # of series: control=%d, other=%d", len(x), len(y)) |
| 37 | } |
| 38 | |
| 39 | for i := range x { |
| 40 | xSeries, ySeries := x[i], y[i] |
| 41 | if !xSeries.Metric.Equal(ySeries.Metric) { |
| 42 | return diff, errors.Errorf("mismatched metrics: %v vs %v", xSeries.Metric, ySeries.Metric) |
| 43 | } |
| 44 | |
| 45 | xVals, yVals := xSeries.Values, ySeries.Values |
| 46 | if len(xVals) != len(yVals) { |
| 47 | return diff, errors.Errorf( |
| 48 | "mismatched number of samples for series %v. control=%d, other=%d", |
| 49 | xSeries.Metric, |
| 50 | len(xVals), |
| 51 | len(yVals), |
| 52 | ) |
| 53 | } |
| 54 | |
| 55 | for j := range xVals { |
| 56 | xSample, ySample := xVals[j], yVals[j] |
| 57 | |
| 58 | if xSample.Timestamp != ySample.Timestamp { |
| 59 | return diff, errors.Errorf( |
| 60 | "mismatched timestamp for %d sample of series %v. control=%d, other=%d", |
| 61 | j, |
| 62 | xSeries.Metric, |
| 63 | xSample.Timestamp, |
| 64 | ySample.Timestamp, |
| 65 | ) |
| 66 | } |
| 67 | |
| 68 | absDiff := math.Abs(float64(ySample.Value-xSample.Value)) / math.Abs(float64(xSample.Value)) |
| 69 | |
| 70 | // 0/0 -> no diff |
| 71 | if math.IsNaN(absDiff) { |
| 72 | absDiff = 0 |
| 73 | } |
| 74 | |
| 75 | diff.sampleDiffs = append(diff.sampleDiffs, absDiff) |
| 76 | |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | diff.Series = len(x) |
| 81 | var avgDiffProportion float64 |
| 82 | for _, d := range diff.sampleDiffs { |
| 83 | avgDiffProportion += d |
| 84 | } |
| 85 | diff.Diff = avgDiffProportion / float64(len(diff.sampleDiffs)) |
| 86 | |
| 87 | return diff, nil |
| 88 | } |
| 89 | |
| 90 | func (a *Auditor) auditVector(x, y model.Vector) (Diff, error) { |