@@ -23,42 +23,46 @@ import (
23
23
"io/ioutil"
24
24
"net/http"
25
25
"os"
26
+ "os/signal"
26
27
"strings"
27
28
"sync"
29
+ "syscall"
28
30
"time"
29
31
30
32
"github.com/cortexlabs/cortex/pkg/lib/debug"
31
33
"github.com/cortexlabs/cortex/pkg/lib/files"
34
+ "go.uber.org/atomic"
32
35
)
33
36
34
37
// usage: go run load.go <url> <sample.json OR sample json string>
35
38
36
- // either set _numConcurrent > 0 or _requestInterval > 0 (and configure the corresponding sections)
37
-
38
- // constant in-flight requests
39
+ // configuration options (either set _numConcurrent > 0 or _requestInterval > 0, and configure the corresponding section)
39
40
const (
41
+ // constant in-flight requests
40
42
_numConcurrent = 3
41
- _numRequestsPerThread = - 1 // -1 means loop infinitely
42
- _requestDelay = 0 * time .Second
43
- _numMainLoops = 10 // only relevant if _numRequestsPerThread != -1
44
- )
43
+ _requestDelay = 0 * time .Millisecond
44
+ _numRequestsPerThread = 0 // 0 means loop infinitely
45
+ _numMainLoops = 1 // only relevant if _numRequestsPerThread > 0
45
46
46
- // constant requests per second
47
- const (
48
- _requestInterval = - 1 * time .Millisecond
49
- _maxInFlight = 5
50
- )
47
+ // constant requests per second
48
+ _requestInterval = 0 * time .Millisecond
49
+ _numRequests uint64 = 0 // 0 means loop infinitely
50
+ _maxInFlight = 5
51
51
52
- // other options
53
- const (
52
+ // other options
54
53
_printSuccessDots = true
54
+ _printFailures = true
55
55
)
56
56
57
57
type Counter struct {
58
58
sync.Mutex
59
- count int
59
+ count int64
60
60
}
61
61
62
+ var _requestCount = atomic.Uint64 {}
63
+ var _successCount = atomic.Uint64 {}
64
+ var _failureCount = atomic.Uint64 {}
65
+
62
66
var _client = & http.Client {
63
67
Timeout : 0 , // no timeout
64
68
Transport : & http.Transport {
@@ -68,12 +72,12 @@ var _client = &http.Client{
68
72
69
73
func main () {
70
74
if _numConcurrent > 0 && _requestInterval > 0 {
71
- fmt .Println ("error: you must set either _numConcurrent or _requestInterval, but not both" )
75
+ fmt .Println ("error: you must set either _numConcurrent or _requestInterval > 0 , but not both" )
72
76
os .Exit (1 )
73
77
}
74
78
75
79
if _numConcurrent == 0 && _requestInterval == 0 {
76
- fmt .Println ("error: you must set either _numConcurrent or _requestInterval" )
80
+ fmt .Println ("error: you must set either _numConcurrent or _requestInterval > 0 " )
77
81
os .Exit (1 )
78
82
}
79
83
@@ -99,17 +103,31 @@ func runConstantRequestsPerSecond(url string, jsonBytes []byte) {
99
103
ticker := time .NewTicker (_requestInterval )
100
104
done := make (chan bool )
101
105
106
+ c := make (chan os.Signal )
107
+ signal .Notify (c , os .Interrupt , syscall .SIGTERM )
108
+ go func () {
109
+ <- c
110
+ done <- true
111
+ }()
112
+
113
+ start := time .Now ()
114
+
115
+ FOR_LOOP:
102
116
for {
103
117
select {
104
118
case <- done :
105
- return
119
+ break FOR_LOOP
106
120
case <- ticker .C :
107
- go runConstantRequestsPerSecondIteration (url , jsonBytes , & inFlightCount )
121
+ go runConstantRequestsPerSecondIteration (url , jsonBytes , & inFlightCount , done )
108
122
}
109
123
}
124
+
125
+ elapsed := time .Since (start )
126
+ requestRate := float64 (_requestCount .Load ()) / elapsed .Seconds ()
127
+ fmt .Printf ("\n elapsed time: %s | %d requests @ %f req/s | %d succeeded | %d failed\n " , elapsed , _requestCount .Load (), requestRate , _successCount .Load (), _failureCount .Load ())
110
128
}
111
129
112
- func runConstantRequestsPerSecondIteration (url string , jsonBytes []byte , inFlightCount * Counter ) {
130
+ func runConstantRequestsPerSecondIteration (url string , jsonBytes []byte , inFlightCount * Counter , done chan bool ) {
113
131
if _maxInFlight > 0 {
114
132
inFlightCount .Lock ()
115
133
if inFlightCount .count >= _maxInFlight {
@@ -123,6 +141,10 @@ func runConstantRequestsPerSecondIteration(url string, jsonBytes []byte, inFligh
123
141
124
142
makeRequest (url , jsonBytes )
125
143
144
+ if _numRequests > 0 && _requestCount .Load () >= _numRequests {
145
+ done <- true
146
+ }
147
+
126
148
if _maxInFlight > 0 {
127
149
inFlightCount .Lock ()
128
150
inFlightCount .count --
@@ -131,26 +153,52 @@ func runConstantRequestsPerSecondIteration(url string, jsonBytes []byte, inFligh
131
153
}
132
154
133
155
func runConstantInFlight (url string , jsonBytes []byte ) {
156
+ if _numRequestsPerThread > 0 {
157
+ fmt .Printf ("spawning %d threads, %d requests each, %s delay on each\n " , _numConcurrent , _numRequestsPerThread , _requestDelay .String ())
158
+ } else {
159
+ fmt .Printf ("spawning %d infinite threads, %s delay on each\n " , _numConcurrent , _requestDelay .String ())
160
+ }
161
+
162
+ var summedRequestCount uint64
163
+ var summedSuccessCount uint64
164
+ var summedFailureCount uint64
165
+
134
166
start := time .Now ()
135
167
loopNum := 1
136
168
for {
137
- runConstantInFlightIteration (url , jsonBytes )
138
- if loopNum >= _numMainLoops {
169
+ wasKilled := runConstantInFlightIteration (url , jsonBytes , loopNum )
170
+
171
+ summedRequestCount += _requestCount .Load ()
172
+ summedSuccessCount += _successCount .Load ()
173
+ summedFailureCount += _failureCount .Load ()
174
+ _requestCount .Store (0 )
175
+ _successCount .Store (0 )
176
+ _failureCount .Store (0 )
177
+
178
+ if loopNum >= _numMainLoops || wasKilled {
139
179
break
140
180
}
141
181
loopNum ++
142
182
}
143
- fmt .Println ("total elapsed time:" , time .Since (start ))
183
+
184
+ if _numMainLoops > 1 {
185
+ elapsed := time .Since (start )
186
+ requestRate := float64 (summedRequestCount ) / elapsed .Seconds ()
187
+ fmt .Printf ("\n total elapsed time: %s | %d requests @ %f req/s | %d succeeded | %d failed\n " , elapsed , summedRequestCount , requestRate , summedSuccessCount , summedFailureCount )
188
+ }
144
189
}
145
190
146
- func runConstantInFlightIteration (url string , jsonBytes []byte ) {
191
+ func runConstantInFlightIteration (url string , jsonBytes []byte , loopNum int ) bool {
147
192
start := time .Now ()
148
193
149
- if _numRequestsPerThread > 0 {
150
- fmt .Printf ("spawning %d threads, %d requests each, %s delay on each\n " , _numConcurrent , _numRequestsPerThread , _requestDelay .String ())
151
- } else {
152
- fmt .Printf ("spawning %d infinite threads, %s delay on each\n " , _numConcurrent , _requestDelay .String ())
153
- }
194
+ wasKilled := false
195
+ killed := make (chan bool )
196
+ c := make (chan os.Signal )
197
+ signal .Notify (c , os .Interrupt , syscall .SIGTERM )
198
+ go func () {
199
+ <- c
200
+ killed <- true
201
+ }()
154
202
155
203
doneChans := make ([]chan struct {}, _numConcurrent )
156
204
for i := range doneChans {
@@ -166,12 +214,22 @@ func runConstantInFlightIteration(url string, jsonBytes []byte) {
166
214
}()
167
215
}
168
216
217
+ LOOP:
169
218
for _ , doneChan := range doneChans {
170
- <- doneChan
219
+ select {
220
+ case <- killed :
221
+ wasKilled = true
222
+ break LOOP
223
+ case <- doneChan :
224
+ continue
225
+ }
171
226
}
172
227
173
- fmt .Println ()
174
- fmt .Println ("elapsed time:" , time .Now ().Sub (start ))
228
+ elapsed := time .Now ().Sub (start )
229
+ requestRate := float64 (_requestCount .Load ()) / elapsed .Seconds ()
230
+ fmt .Printf ("\n elapsed time: %s | %d requests @ %f req/s | %d succeeded | %d failed\n " , elapsed , _requestCount .Load (), requestRate , _successCount .Load (), _failureCount .Load ())
231
+
232
+ return wasKilled
175
233
}
176
234
177
235
func makeRequestLoop (url string , jsonBytes []byte ) {
@@ -211,13 +269,20 @@ func makeRequest(url string, jsonBytes []byte) {
211
269
body , bodyReadErr := ioutil .ReadAll (response .Body )
212
270
response .Body .Close ()
213
271
214
- if response .StatusCode != 200 {
215
- if bodyReadErr == nil {
216
- fmt .Printf ("\n status code: %d; body: %s\n " , response .StatusCode , string (body ))
217
- } else {
218
- fmt .Printf ("\n status code: %d; error reading body: %s\n " , response .StatusCode , bodyReadErr .Error ())
272
+ _requestCount .Inc ()
273
+
274
+ if response .StatusCode == 200 {
275
+ _successCount .Inc ()
276
+ } else {
277
+ _failureCount .Inc ()
278
+ if _printFailures {
279
+ if bodyReadErr == nil {
280
+ fmt .Printf ("\n status code: %d; body: %s\n " , response .StatusCode , string (body ))
281
+ } else {
282
+ fmt .Printf ("\n status code: %d; error reading body: %s\n " , response .StatusCode , bodyReadErr .Error ())
283
+ }
284
+ return
219
285
}
220
- return
221
286
}
222
287
223
288
if _printSuccessDots {
0 commit comments