-
Notifications
You must be signed in to change notification settings - Fork 108
/
stats.go
151 lines (135 loc) · 4.34 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
package main
import (
"encoding/json"
"fmt"
"log"
"sort"
"strings"
)
type Stats struct {
Url string
Connections int
Threads int
AvgDuration float64
Duration float64
Sum float64
Times []int
Transferred int64
Resp200 int64
Resp300 int64
Resp400 int64
Resp500 int64
Errors int64
Contains int64
}
func CalcStats(responseChannel chan *Response, duration int64) []byte {
stats := &Stats{
Url: target,
Connections: *numConnections,
Threads: *numThreads,
Times: make([]int, len(responseChannel)),
Duration: float64(duration),
AvgDuration: float64(duration),
}
if *respContains != "" {
log.Printf("search in response for: %v", *respContains)
}
i := 0
for res := range responseChannel {
switch {
case res.StatusCode < 200:
// error
case res.StatusCode < 300:
stats.Resp200++
case res.StatusCode < 400:
stats.Resp300++
case res.StatusCode < 500:
stats.Resp400++
case res.StatusCode < 600:
stats.Resp500++
}
if *respContains != "" && strings.Contains(res.Body, *respContains) {
stats.Contains++
}
stats.Sum += float64(res.Duration)
stats.Times[i] = int(res.Duration)
i++
stats.Transferred += res.Size
if res.Error {
stats.Errors++
}
if len(responseChannel) == 0 {
break
}
}
sort.Ints(stats.Times)
PrintStats(stats)
b, err := json.Marshal(&stats)
if err != nil {
fmt.Println(err)
}
return b
}
func CalcDistStats(distChan chan string) {
if len(distChan) == 0 {
return
}
allStats := &Stats{
Url: target,
Connections: *numConnections,
Threads: *numThreads,
}
statCount := len(distChan)
for res := range distChan {
var stats Stats
err := json.Unmarshal([]byte(res), &stats)
if err != nil {
fmt.Println(err)
}
allStats.Duration += stats.Duration
allStats.Sum += stats.Sum
allStats.Times = append(allStats.Times, stats.Times...)
allStats.Resp200 += stats.Resp200
allStats.Resp300 += stats.Resp300
allStats.Resp400 += stats.Resp400
allStats.Resp500 += stats.Resp500
allStats.Errors += stats.Errors
allStats.Contains += stats.Contains
if len(distChan) == 0 {
break
}
}
allStats.AvgDuration = allStats.Duration / float64(statCount)
PrintStats(allStats)
}
func PrintStats(allStats *Stats) {
sort.Ints(allStats.Times)
total := float64(len(allStats.Times))
totalInt := int64(total)
fmt.Println("==========================BENCHMARK==========================")
fmt.Printf("URL:\t\t\t\t%s\n\n", allStats.Url)
fmt.Printf("Used Connections:\t\t%d\n", allStats.Connections)
fmt.Printf("Used Threads:\t\t\t%d\n", allStats.Threads)
fmt.Printf("Total number of calls:\t\t%d\n\n", totalInt)
fmt.Println("===========================TIMINGS===========================")
fmt.Printf("Total time passed:\t\t%.2fs\n", allStats.AvgDuration/1E6)
fmt.Printf("Avg time per request:\t\t%.2fms\n", allStats.Sum/total/1000)
fmt.Printf("Requests per second:\t\t%.2f\n", total/(allStats.AvgDuration/1E6))
fmt.Printf("Median time per request:\t%.2fms\n", float64(allStats.Times[(totalInt-1)/2])/1000)
fmt.Printf("99th percentile time:\t\t%.2fms\n", float64(allStats.Times[(totalInt/100*99)])/1000)
fmt.Printf("Slowest time for request:\t%.2fms\n\n", float64(allStats.Times[totalInt-1]/1000))
fmt.Println("=============================DATA=============================")
fmt.Printf("Total response body sizes:\t\t%d\n", allStats.Transferred)
fmt.Printf("Avg response body per request:\t\t%.2f Byte\n", float64(allStats.Transferred)/total)
tr := float64(allStats.Transferred) / (allStats.AvgDuration / 1E6)
fmt.Printf("Transfer rate per second:\t\t%.2f Byte/s (%.2f MByte/s)\n", tr, tr/1E6)
fmt.Println("==========================RESPONSES==========================")
fmt.Printf("20X Responses:\t\t%d\t(%.2f%%)\n", allStats.Resp200, float64(allStats.Resp200)/total*1e2)
fmt.Printf("30X Responses:\t\t%d\t(%.2f%%)\n", allStats.Resp300, float64(allStats.Resp300)/total*1e2)
fmt.Printf("40X Responses:\t\t%d\t(%.2f%%)\n", allStats.Resp400, float64(allStats.Resp400)/total*1e2)
fmt.Printf("50X Responses:\t\t%d\t(%.2f%%)\n", allStats.Resp500, float64(allStats.Resp500)/total*1e2)
if *respContains != "" {
fmt.Printf("matchResponses:\t\t%d\t(%.2f%%)\n", allStats.Contains, float64(allStats.Contains)/total*1e2)
}
fmt.Printf("Errors:\t\t\t%d\t(%.2f%%)\n", allStats.Errors, float64(allStats.Errors)/total*1e2)
}