Skip to content

Commit

Permalink
metrics: Add Throughput to Metrics (#420)
Browse files Browse the repository at this point in the history
* echosrv: Add sleep flag

* metrics: Add Throughput to Metrics

This commit adds a `Throughput` field to the `Metrics` struct which
represents the rate of successful requests per second. It is calculated
by dividing the number of successful requests by the time span in
seconds starting from the beginning of the earliest request in the
result set and ending in the time the very last response arrived.
  • Loading branch information
tsenart authored Jul 19, 2019
1 parent 97cae82 commit f807d60
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 18 deletions.
15 changes: 5 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ Examples:
#### `report -type=text`

```console
Requests [total, rate] 1200, 120.00
Requests [total, rate, throughput] 1200, 120.00, 65.87
Duration [total, attack, wait] 10.094965987s, 9.949883921s, 145.082066ms
Latencies [mean, 50, 95, 99, max] 113.172398ms, 108.272568ms, 140.18235ms, 247.771566ms, 264.815246ms
Bytes In [total, mean] 3714690, 3095.57
Expand All @@ -399,7 +399,8 @@ Get http://localhost:6060: http: can't write HTTP request on broken connection
The `Requests` row shows:

- The `total` number of issued requests.
- The real request `rate` sustained during the attack.
- The real request `rate` sustained during the `attack` period.
- The `throughput` of successful requests over the `total` period.

The `Duration` row shows:

Expand Down Expand Up @@ -452,6 +453,7 @@ The `Error Set` shows a unique set of errors returned by all issued requests. Th
"wait": 3507222,
"requests": 100,
"rate": 101.01010672380401,
"throughput": 101.00012489812,
"success": 1,
"status_codes": {
"200": 100
Expand Down Expand Up @@ -693,14 +695,7 @@ The `report` command accepts multiple result files.
It'll read and sort them by timestamp before generating reports.

```console
$ vegeta report 10.0.1.1.bin 10.0.2.1.bin 10.0.3.1.bin
Requests [total, rate] 3600000, 60000.00
Latencies [mean, 95, 99, max] 223.340085ms, 326.913687ms, 416.537743ms, 7.788103259s
Bytes In [total, mean] 3714690, 3095.57
Bytes Out [total, mean] 0, 0.00
Success [ratio] 100.0%
Status Codes [code:count] 200:3600000
Error Set:
vegeta report *.bin
```

## Usage: Real-time Analysis
Expand Down
12 changes: 9 additions & 3 deletions internal/cmd/echosrv/main.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package main

import (
"flag"
"log"
"net/http"
"net/http/httputil"
"os"
"sync/atomic"
"time"
)

func main() {
sleep := flag.Duration("sleep", 0, "Time to sleep per request")

flag.Parse()

count := uint64(0)
go func(last time.Time) {
ticks := time.Tick(time.Second)
Expand All @@ -20,8 +24,10 @@ func main() {
}
}(time.Now())

http.ListenAndServe(os.Args[1], http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
atomic.AddUint64(&count, 1)
http.ListenAndServe(flag.Arg(0), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer atomic.AddUint64(&count, 1)
time.Sleep(*sleep)

bs, _ := httputil.DumpRequest(r, true)
w.Write(bs)
}))
Expand Down
12 changes: 9 additions & 3 deletions lib/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type Metrics struct {
BytesIn ByteMetrics `json:"bytes_in"`
// BytesOut holds computed outgoing byte metrics.
BytesOut ByteMetrics `json:"bytes_out"`
// First is the earliest timestamp in a Result set.
// Earliest is the earliest timestamp in a Result set.
Earliest time.Time `json:"earliest"`
// Latest is the latest timestamp in a Result set.
Latest time.Time `json:"latest"`
Expand All @@ -30,8 +30,10 @@ type Metrics struct {
Wait time.Duration `json:"wait"`
// Requests is the total number of requests executed.
Requests uint64 `json:"requests"`
// Rate is the rate of requests per second.
// Rate is the rate of sent requests per second.
Rate float64 `json:"rate"`
// Throughput is the rate of successful requests per second.
Throughput float64 `json:"throughput"`
// Success is the percentage of non-error responses.
Success float64 `json:"success"`
// StatusCodes is a histogram of the responses' status codes.
Expand Down Expand Up @@ -88,11 +90,15 @@ func (m *Metrics) Add(r *Result) {
func (m *Metrics) Close() {
m.init()
m.Rate = float64(m.Requests)
m.Throughput = float64(m.success)
m.Duration = m.Latest.Sub(m.Earliest)
m.Wait = m.End.Sub(m.Latest)
if secs := m.Duration.Seconds(); secs > 0 {
m.Rate /= secs
// No need to check for zero because we know m.Duration > 0
m.Throughput /= (m.Duration + m.Wait).Seconds()
}
m.Wait = m.End.Sub(m.Latest)

m.BytesIn.Mean = float64(m.BytesIn.Total) / float64(m.Requests)
m.BytesOut.Mean = float64(m.BytesOut.Total) / float64(m.Requests)
m.Success = float64(m.success) / float64(m.Requests)
Expand Down
1 change: 1 addition & 0 deletions lib/metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func TestMetrics_Add(t *testing.T) {
Wait: duration("10ms"),
Requests: 10000,
Rate: 1.000100010001,
Throughput: 0.6667660098349737,
Success: 0.6667,
StatusCodes: map[string]int{"500": 3333, "200": 3334, "302": 3333},
Errors: []string{"Internal server error"},
Expand Down
4 changes: 2 additions & 2 deletions lib/reporters.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func NewHistogramReporter(h *Histogram) Reporter {
// NewTextReporter returns a Reporter that writes out Metrics as aligned,
// formatted text.
func NewTextReporter(m *Metrics) Reporter {
const fmtstr = "Requests\t[total, rate]\t%d, %.2f\n" +
const fmtstr = "Requests\t[total, rate, throughput]\t%d, %.2f, %.2f\n" +
"Duration\t[total, attack, wait]\t%s, %s, %s\n" +
"Latencies\t[mean, 50, 95, 99, max]\t%s, %s, %s, %s, %s\n" +
"Bytes In\t[total, mean]\t%d, %.2f\n" +
Expand All @@ -66,7 +66,7 @@ func NewTextReporter(m *Metrics) Reporter {
return func(w io.Writer) (err error) {
tw := tabwriter.NewWriter(w, 0, 8, 2, ' ', tabwriter.StripEscape)
if _, err = fmt.Fprintf(tw, fmtstr,
m.Requests, m.Rate,
m.Requests, m.Rate, m.Throughput,
m.Duration+m.Wait, m.Duration, m.Wait,
m.Latencies.Mean, m.Latencies.P50, m.Latencies.P95, m.Latencies.P99, m.Latencies.Max,
m.BytesIn.Total, m.BytesIn.Mean,
Expand Down

0 comments on commit f807d60

Please sign in to comment.