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