Skip to content

Commit eafdee6

Browse files
committed
Add --concurrent option and support concurrent requests
1 parent 799afff commit eafdee6

File tree

6 files changed

+44
-14
lines changed

6 files changed

+44
-14
lines changed

defs/bytes_counter.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"io"
88
"log"
9+
"sync"
910
"time"
1011
)
1112

@@ -16,20 +17,32 @@ type BytesCounter struct {
1617
payload []byte
1718
reader io.ReadSeeker
1819
mebi bool
20+
21+
lock *sync.Mutex
22+
}
23+
24+
func NewCounter() *BytesCounter {
25+
return &BytesCounter{
26+
lock: &sync.Mutex{},
27+
}
1928
}
2029

2130
// Write implements io.Writer
2231
func (c *BytesCounter) Write(p []byte) (int, error) {
2332
n := len(p)
33+
c.lock.Lock()
2434
c.total += n
35+
c.lock.Unlock()
2536

2637
return n, nil
2738
}
2839

2940
// Read implements io.Reader
3041
func (c *BytesCounter) Read(p []byte) (int, error) {
3142
n, err := c.reader.Read(p)
43+
c.lock.Lock()
3244
c.total += n
45+
c.lock.Unlock()
3346

3447
return n, err
3548
}
@@ -39,8 +52,8 @@ func (c *BytesCounter) SetMebi(mebi bool) {
3952
c.mebi = mebi
4053
}
4154

42-
// Average returns the average bytes/second
43-
func (c *BytesCounter) Average() float64 {
55+
// AvgBytes returns the average bytes/second
56+
func (c *BytesCounter) AvgBytes() float64 {
4457
return float64(c.total) / time.Now().Sub(c.start).Seconds()
4558
}
4659

@@ -49,11 +62,11 @@ func (c *BytesCounter) AvgMbps() float64 {
4962
if c.mebi {
5063
base = 131072
5164
}
52-
return c.Average() / base
65+
return c.AvgBytes() / base
5366
}
5467

5568
func (c *BytesCounter) AvgHumanize() string {
56-
val := c.Average()
69+
val := c.AvgBytes()
5770

5871
var base float64 = 1000
5972
if c.mebi {

defs/options.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const (
88
OptionIPv6Alt = "6"
99
OptionNoDownload = "no-download"
1010
OptionNoUpload = "no-upload"
11+
OptionConcurrent = "concurrent"
1112
OptionBytes = "bytes"
1213
OptionMebiBytes = "mebibytes"
1314
OptionDistance = "distance"

defs/server.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,13 +177,13 @@ func (s *Server) PingAndJitter(count int) (float64, float64, error) {
177177
}
178178

179179
// Download performs the actual download test
180-
func (s *Server) Download(silent bool, useBytes, useMebi bool) (float64, int, error) {
180+
func (s *Server) Download(silent bool, useBytes, useMebi bool, requests int) (float64, int, error) {
181181
t := time.Now()
182182
defer func() {
183183
s.TLog.Logf("Download took %s", time.Now().Sub(t).String())
184184
}()
185185

186-
counter := &BytesCounter{}
186+
counter := NewCounter()
187187
counter.SetMebi(useMebi)
188188

189189
ctx, cancel := context.WithCancel(context.Background())
@@ -207,7 +207,7 @@ func (s *Server) Download(silent bool, useBytes, useMebi bool) (float64, int, er
207207
req.Header.Set("User-Agent", UserAgent)
208208
req.Header.Set("Accept-Encoding", "identity")
209209

210-
downloadDone := make(chan struct{})
210+
downloadDone := make(chan struct{}, requests)
211211

212212
doDownload := func() {
213213
resp, err := http.DefaultClient.Do(req)
@@ -249,7 +249,10 @@ func (s *Server) Download(silent bool, useBytes, useMebi bool) (float64, int, er
249249
}()
250250
}
251251

252-
go doDownload()
252+
for i := 0; i < requests; i++ {
253+
go doDownload()
254+
time.Sleep(200 * time.Millisecond)
255+
}
253256
timeout := time.After(15 * time.Second)
254257
Loop:
255258
for {
@@ -266,13 +269,13 @@ Loop:
266269
}
267270

268271
// Upload performs the actual upload test
269-
func (s *Server) Upload(noPrealloc, silent, useBytes, useMebi bool) (float64, int, error) {
272+
func (s *Server) Upload(noPrealloc, silent, useBytes, useMebi bool, requests int) (float64, int, error) {
270273
t := time.Now()
271274
defer func() {
272275
s.TLog.Logf("Upload took %s", time.Now().Sub(t).String())
273276
}()
274277

275-
counter := &BytesCounter{}
278+
counter := NewCounter()
276279
counter.SetMebi(useMebi)
277280

278281
if noPrealloc {
@@ -299,7 +302,7 @@ func (s *Server) Upload(noPrealloc, silent, useBytes, useMebi bool) (float64, in
299302
req.Header.Set("User-Agent", UserAgent)
300303
req.Header.Set("Accept-Encoding", "identity")
301304

302-
uploadDone := make(chan struct{})
305+
uploadDone := make(chan struct{}, requests)
303306

304307
doUpload := func() {
305308
resp, err := http.DefaultClient.Do(req)
@@ -339,7 +342,10 @@ func (s *Server) Upload(noPrealloc, silent, useBytes, useMebi bool) (float64, in
339342
}()
340343
}
341344

342-
go doUpload()
345+
for i := 0; i < requests; i++ {
346+
go doUpload()
347+
time.Sleep(200 * time.Millisecond)
348+
}
343349
timeout := time.After(15 * time.Second)
344350
Loop:
345351
for {

main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ func main() {
5555
Name: defs.OptionNoUpload,
5656
Usage: "Do not perform upload test",
5757
},
58+
&cli.IntFlag{
59+
Name: defs.OptionConcurrent,
60+
Usage: "Concurrent HTTP requests being made",
61+
Value: 3,
62+
},
5863
&cli.BoolFlag{
5964
Name: defs.OptionBytes,
6065
Usage: "Display values in bytes instead of bits. Does not affect\n" +

speedtest/helper.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func doSpeedTest(c *cli.Context, servers []defs.Server, telemetryServer defs.Tel
7878
if c.Bool(defs.OptionNoDownload) {
7979
log.Info("Download test is disabled")
8080
} else {
81-
download, br, err := currentServer.Download(silent, c.Bool(defs.OptionBytes), c.Bool(defs.OptionMebiBytes))
81+
download, br, err := currentServer.Download(silent, c.Bool(defs.OptionBytes), c.Bool(defs.OptionMebiBytes), c.Int(defs.OptionConcurrent))
8282
if err != nil {
8383
log.Errorf("Failed to get download speed: %s", err)
8484
return err
@@ -93,7 +93,7 @@ func doSpeedTest(c *cli.Context, servers []defs.Server, telemetryServer defs.Tel
9393
if c.Bool(defs.OptionNoUpload) {
9494
log.Info("Upload test is disabled")
9595
} else {
96-
upload, bw, err := currentServer.Upload(c.Bool(defs.OptionNoPreAllocate), silent, c.Bool(defs.OptionBytes), c.Bool(defs.OptionMebiBytes))
96+
upload, bw, err := currentServer.Upload(c.Bool(defs.OptionNoPreAllocate), silent, c.Bool(defs.OptionBytes), c.Bool(defs.OptionMebiBytes), c.Int(defs.OptionConcurrent))
9797
if err != nil {
9898
log.Errorf("Failed to get upload speed: %s", err)
9999
return err

speedtest/speedtest.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ func SpeedTest(c *cli.Context) error {
123123
}
124124
}
125125

126+
if req := c.Int(defs.OptionConcurrent); req <= 0 {
127+
log.Errorf("Concurrent requests cannot be lower than 1: %d is given", req)
128+
return errors.New("invalid concurrent requests setting")
129+
}
130+
126131
// HTTP requests timeout
127132
http.DefaultClient.Timeout = time.Duration(c.Int(defs.OptionTimeout)) * time.Second
128133

0 commit comments

Comments
 (0)