-
-
Notifications
You must be signed in to change notification settings - Fork 282
/
stats.go
153 lines (126 loc) · 5.46 KB
/
stats.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package gmeasure
import (
"fmt"
"time"
"github.com/onsi/gomega/gmeasure/table"
)
/*
Stat is an enum representing the statistics you can request of a Stats struct
*/
type Stat uint
const (
StatInvalid Stat = iota
StatMin
StatMax
StatMean
StatMedian
StatStdDev
)
var statEnumSupport = newEnumSupport(map[uint]string{uint(StatInvalid): "INVALID STAT", uint(StatMin): "Min", uint(StatMax): "Max", uint(StatMean): "Mean", uint(StatMedian): "Median", uint(StatStdDev): "StdDev"})
func (s Stat) String() string { return statEnumSupport.String(uint(s)) }
func (s *Stat) UnmarshalJSON(b []byte) error {
out, err := statEnumSupport.UnmarshJSON(b)
*s = Stat(out)
return err
}
func (s Stat) MarshalJSON() ([]byte, error) { return statEnumSupport.MarshJSON(uint(s)) }
type StatsType uint
const (
StatsTypeInvalid StatsType = iota
StatsTypeValue
StatsTypeDuration
)
var statsTypeEnumSupport = newEnumSupport(map[uint]string{uint(StatsTypeInvalid): "INVALID STATS TYPE", uint(StatsTypeValue): "StatsTypeValue", uint(StatsTypeDuration): "StatsTypeDuration"})
func (s StatsType) String() string { return statsTypeEnumSupport.String(uint(s)) }
func (s *StatsType) UnmarshalJSON(b []byte) error {
out, err := statsTypeEnumSupport.UnmarshJSON(b)
*s = StatsType(out)
return err
}
func (s StatsType) MarshalJSON() ([]byte, error) { return statsTypeEnumSupport.MarshJSON(uint(s)) }
/*
Stats records the key statistics for a given measurement. You generally don't make Stats directly - but you can fetch them from Experiments using GetStats() and from Measurements using Stats().
When using Ginkgo, you can register Measurements as Report Entries via AddReportEntry. This will emit all the captured data points when Ginkgo generates the report.
*/
type Stats struct {
// Type is the StatType - one of StatTypeDuration or StatTypeValue
Type StatsType
// ExperimentName is the name of the Experiment that recorded the Measurement from which this Stat is derived
ExperimentName string
// MeasurementName is the name of the Measurement from which this Stat is derived
MeasurementName string
// Units captures the Units of the Measurement from which this Stat is derived
Units string
// Style captures the Style of the Measurement from which this Stat is derived
Style string
// PrecisionBundle captures the precision to use when rendering data for this Measurement.
// If Type is StatTypeDuration then PrecisionBundle.Duration is used to round any durations before presentation.
// If Type is StatTypeValue then PrecisionBundle.ValueFormat is used to format any values before presentation
PrecisionBundle PrecisionBundle
// N represents the total number of data points in the Meassurement from which this Stat is derived
N int
// If Type is StatTypeValue, ValueBundle will be populated with float64s representing this Stat's statistics
ValueBundle map[Stat]float64
// If Type is StatTypeDuration, DurationBundle will be populated with float64s representing this Stat's statistics
DurationBundle map[Stat]time.Duration
// AnnotationBundle is populated with Annotations corresponding to the data points that can be associated with a Stat.
// For example AnnotationBundle[StatMin] will return the Annotation for the data point that has the minimum value/duration.
AnnotationBundle map[Stat]string
}
// String returns a minimal summary of the stats of the form "MIN < [MEDIAN] | <MEAN> ±STDDEV < MAX"
func (s Stats) String() string {
return fmt.Sprintf("%s < [%s] | <%s> ±%s < %s", s.StringFor(StatMin), s.StringFor(StatMedian), s.StringFor(StatMean), s.StringFor(StatStdDev), s.StringFor(StatMax))
}
// ValueFor returns the float64 value for a particular Stat. You should only use this if the Stats has Type StatsTypeValue
// For example:
//
// median := experiment.GetStats("length").ValueFor(gmeasure.StatMedian)
//
// will return the median data point for the "length" Measurement.
func (s Stats) ValueFor(stat Stat) float64 {
return s.ValueBundle[stat]
}
// DurationFor returns the time.Duration for a particular Stat. You should only use this if the Stats has Type StatsTypeDuration
// For example:
//
// mean := experiment.GetStats("runtime").ValueFor(gmeasure.StatMean)
//
// will return the mean duration for the "runtime" Measurement.
func (s Stats) DurationFor(stat Stat) time.Duration {
return s.DurationBundle[stat]
}
// FloatFor returns a float64 representation of the passed-in Stat.
// When Type is StatsTypeValue this is equivalent to s.ValueFor(stat).
// When Type is StatsTypeDuration this is equivalent to float64(s.DurationFor(stat))
func (s Stats) FloatFor(stat Stat) float64 {
switch s.Type {
case StatsTypeValue:
return s.ValueFor(stat)
case StatsTypeDuration:
return float64(s.DurationFor(stat))
}
return 0
}
// StringFor returns a formatted string representation of the passed-in Stat.
// The formatting honors the precision directives provided in stats.PrecisionBundle
func (s Stats) StringFor(stat Stat) string {
switch s.Type {
case StatsTypeValue:
return fmt.Sprintf(s.PrecisionBundle.ValueFormat, s.ValueFor(stat))
case StatsTypeDuration:
return s.DurationFor(stat).Round(s.PrecisionBundle.Duration).String()
}
return ""
}
func (s Stats) cells() []table.Cell {
out := []table.Cell{}
out = append(out, table.C(fmt.Sprintf("%d", s.N)))
for _, stat := range []Stat{StatMin, StatMedian, StatMean, StatStdDev, StatMax} {
content := s.StringFor(stat)
if s.AnnotationBundle[stat] != "" {
content += "\n" + s.AnnotationBundle[stat]
}
out = append(out, table.C(content))
}
return out
}