Merge pull request #7147 from gyuho/pkg/report

pkg/report: add 'Stats' to expose report raw data
This commit is contained in:
Gyu-Ho Lee 2017-01-13 11:17:57 -08:00 committed by GitHub
commit bb797c1ee9
2 changed files with 72 additions and 15 deletions

View File

@ -55,12 +55,30 @@ type report struct {
sps *secondPoints
}
// Stats exposes results raw data.
type Stats struct {
AvgTotal float64
Fastest float64
Slowest float64
Average float64
Stddev float64
RPS float64
Total time.Duration
ErrorDist map[string]int
Lats []float64
TimeSeries TimeSeries
}
// Report processes a result stream until it is closed, then produces a
// string with information about the consumed result data.
type Report interface {
Results() chan<- Result
// Run returns results in print-friendly format.
Run() <-chan string
String() string
// Stats returns results in raw data.
Stats() <-chan Stats
}
func NewReport(precision string) Report {
@ -89,6 +107,41 @@ func (r *report) Run() <-chan string {
return donec
}
func (r *report) Stats() <-chan Stats {
donec := make(chan Stats, 1)
go func() {
defer close(donec)
r.processResults()
donec <- Stats{
AvgTotal: r.avgTotal,
Fastest: r.fastest,
Slowest: r.slowest,
Average: r.average,
Stddev: r.stddev,
RPS: r.rps,
Total: r.total,
ErrorDist: copyMap(r.errorDist),
Lats: copyFloats(r.lats),
TimeSeries: r.sps.getTimeSeries(),
}
}()
return donec
}
func copyMap(m map[string]int) (c map[string]int) {
c = make(map[string]int, len(m))
for k, v := range m {
c[k] = v
}
return
}
func copyFloats(s []float64) (c []float64) {
c = make([]float64, len(s))
copy(c, s)
return
}
func (r *report) String() (s string) {
if len(r.lats) > 0 {
s += fmt.Sprintf("\nSummary:\n")
@ -158,7 +211,11 @@ func (r *report) processResults() {
var pctls = []float64{10, 25, 50, 75, 90, 95, 99, 99.9}
// percentiles returns percentile distribution of float64 slice.
// Percentiles returns percentile distribution of float64 slice.
func Percentiles(nums []float64) (pcs []float64, data []float64) {
return pctls, percentiles(nums)
}
func percentiles(nums []float64) (data []float64) {
data = make([]float64, len(pctls))
j := 0

View File

@ -25,17 +25,17 @@ import (
"time"
)
type timeSeries struct {
timestamp int64
avgLatency time.Duration
throughPut int64
type DataPoint struct {
Timestamp int64
AvgLatency time.Duration
ThroughPut int64
}
type TimeSeries []timeSeries
type TimeSeries []DataPoint
func (t TimeSeries) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
func (t TimeSeries) Len() int { return len(t) }
func (t TimeSeries) Less(i, j int) bool { return t[i].timestamp < t[j].timestamp }
func (t TimeSeries) Less(i, j int) bool { return t[i].Timestamp < t[j].Timestamp }
type secondPoint struct {
totalLatency time.Duration
@ -96,10 +96,10 @@ func (sp *secondPoints) getTimeSeries() TimeSeries {
if v.count > 0 {
lat = time.Duration(v.totalLatency) / time.Duration(v.count)
}
tslice[i] = timeSeries{
timestamp: k,
avgLatency: lat,
throughPut: v.count,
tslice[i] = DataPoint{
Timestamp: k,
AvgLatency: lat,
ThroughPut: v.count,
}
i++
}
@ -117,9 +117,9 @@ func (ts TimeSeries) String() string {
rows := [][]string{}
for i := range ts {
row := []string{
fmt.Sprintf("%d", ts[i].timestamp),
fmt.Sprintf("%s", ts[i].avgLatency),
fmt.Sprintf("%d", ts[i].throughPut),
fmt.Sprintf("%d", ts[i].Timestamp),
fmt.Sprintf("%s", ts[i].AvgLatency),
fmt.Sprintf("%d", ts[i].ThroughPut),
}
rows = append(rows, row)
}