net/speedtest: retune to meet iperf on localhost in a VM

- removed some in-flow time calls
- increase buffer size to 2MB to overcome syscall cost
- move relative time computation from record to report time

Signed-off-by: James Tucker <james@tailscale.com>
pull/5736/head
James Tucker 2 years ago committed by James Tucker
parent 146f51ce76
commit f7cb535693

@ -110,11 +110,12 @@ func runSpeedtest(ctx context.Context, args []string) error {
w := tabwriter.NewWriter(os.Stdout, 12, 0, 0, ' ', tabwriter.TabIndent)
fmt.Println("Results:")
fmt.Fprintln(w, "Interval\t\tTransfer\t\tBandwidth\t\t")
startTime := results[0].IntervalStart
for _, r := range results {
if r.Total {
fmt.Fprintln(w, "-------------------------------------------------------------------------")
}
fmt.Fprintf(w, "%.2f-%.2f\tsec\t%.4f\tMBits\t%.4f\tMbits/sec\t\n", r.IntervalStart.Seconds(), r.IntervalEnd.Seconds(), r.MegaBits(), r.MBitsPerSecond())
fmt.Fprintf(w, "%.2f-%.2f\tsec\t%.4f\tMBits\t%.4f\tMbits/sec\t\n", r.IntervalStart.Sub(startTime).Seconds(), r.IntervalEnd.Sub(startTime).Seconds(), r.MegaBits(), r.MBitsPerSecond())
}
w.Flush()
return nil

@ -11,11 +11,11 @@ import (
)
const (
blockSize = 32000 // size of the block of data to send
blockSize = 2 * 1024 * 1024 // size of the block of data to send
MinDuration = 5 * time.Second // minimum duration for a test
DefaultDuration = MinDuration // default duration for a test
MaxDuration = 30 * time.Second // maximum duration for a test
version = 1 // value used when comparing client and server versions
version = 2 // value used when comparing client and server versions
increment = time.Second // increment to display results for, in seconds
minInterval = 10 * time.Millisecond // minimum interval length for a result to be included
DefaultPort = 20333
@ -37,14 +37,14 @@ type configResponse struct {
// This represents the Result of a speedtest within a specific interval
type Result struct {
Bytes int // number of bytes sent/received during the interval
IntervalStart time.Duration // duration between the start of the interval and the start of the test
IntervalEnd time.Duration // duration between the end of the interval and the start of the test
Total bool // if true, this result struct represents the entire test, rather than a segment of the test
Bytes int // number of bytes sent/received during the interval
IntervalStart time.Time // start of the interval
IntervalEnd time.Time // end of the interval
Total bool // if true, this result struct represents the entire test, rather than a segment of the test
}
func (r Result) MBitsPerSecond() float64 {
return r.MegaBits() / (r.IntervalEnd - r.IntervalStart).Seconds()
return r.MegaBits() / r.IntervalEnd.Sub(r.IntervalStart).Seconds()
}
func (r Result) MegaBytes() float64 {
@ -56,7 +56,7 @@ func (r Result) MegaBits() float64 {
}
func (r Result) Interval() time.Duration {
return r.IntervalEnd - r.IntervalStart
return r.IntervalEnd.Sub(r.IntervalStart)
}
type Direction int

@ -81,9 +81,6 @@ func doTest(conn net.Conn, conf config) ([]Result, error) {
var currentTime time.Time
var results []Result
startTime := time.Now()
lastCalculated := startTime
if conf.Direction == Download {
conn.SetReadDeadline(time.Now().Add(conf.TestDuration).Add(5 * time.Second))
} else {
@ -94,6 +91,9 @@ func doTest(conn net.Conn, conf config) ([]Result, error) {
}
startTime := time.Now()
lastCalculated := startTime
SpeedTestLoop:
for {
var n int
@ -110,48 +110,37 @@ SpeedTestLoop:
return nil, fmt.Errorf("unexpected error has occurred: %w", err)
}
} else {
// Need to change the data a little bit, to avoid any compression.
for i := range bufferData {
bufferData[i]++
}
n, err = conn.Write(bufferData)
if err != nil {
// If the write failed, there is most likely something wrong with the connection.
return nil, fmt.Errorf("upload failed: %w", err)
}
}
currentTime = time.Now()
intervalBytes += n
currentTime = time.Now()
// checks if the current time is more or equal to the lastCalculated time plus the increment
if currentTime.After(lastCalculated.Add(increment)) {
intervalStart := lastCalculated.Sub(startTime)
intervalEnd := currentTime.Sub(startTime)
if (intervalEnd - intervalStart) > minInterval {
results = append(results, Result{Bytes: intervalBytes, IntervalStart: intervalStart, IntervalEnd: intervalEnd, Total: false})
}
if currentTime.Sub(lastCalculated) >= increment {
results = append(results, Result{Bytes: intervalBytes, IntervalStart: lastCalculated, IntervalEnd: currentTime, Total: false})
lastCalculated = currentTime
totalBytes += intervalBytes
intervalBytes = 0
}
if conf.Direction == Upload && time.Since(startTime) > conf.TestDuration {
if conf.Direction == Upload && currentTime.Sub(startTime) > conf.TestDuration {
break SpeedTestLoop
}
}
// get last segment
intervalStart := lastCalculated.Sub(startTime)
intervalEnd := currentTime.Sub(startTime)
if (intervalEnd - intervalStart) > minInterval {
results = append(results, Result{Bytes: intervalBytes, IntervalStart: intervalStart, IntervalEnd: intervalEnd, Total: false})
if currentTime.Sub(lastCalculated) > minInterval {
results = append(results, Result{Bytes: intervalBytes, IntervalStart: lastCalculated, IntervalEnd: currentTime, Total: false})
}
// get total
totalBytes += intervalBytes
intervalEnd = currentTime.Sub(startTime)
if intervalEnd > minInterval {
results = append(results, Result{Bytes: totalBytes, IntervalStart: 0, IntervalEnd: intervalEnd, Total: true})
if currentTime.Sub(startTime) > minInterval {
results = append(results, Result{Bytes: totalBytes, IntervalStart: startTime, IntervalEnd: currentTime, Total: true})
}
return results, nil

@ -7,6 +7,7 @@ package speedtest
import (
"net"
"testing"
"time"
)
func TestDownload(t *testing.T) {
@ -23,9 +24,9 @@ func TestDownload(t *testing.T) {
type state struct {
err error
}
displayResult := func(t *testing.T, r Result) {
displayResult := func(t *testing.T, r Result, start time.Time) {
t.Helper()
t.Logf("{ Megabytes: %.2f, Start: %.1f, End: %.1f, Total: %t }", r.MegaBytes(), r.IntervalStart.Seconds(), r.IntervalEnd.Seconds(), r.Total)
t.Logf("{ Megabytes: %.2f, Start: %.1f, End: %.1f, Total: %t }", r.MegaBytes(), r.IntervalStart.Sub(start).Seconds(), r.IntervalEnd.Sub(start).Seconds(), r.Total)
}
stateChan := make(chan state, 1)
@ -49,8 +50,9 @@ func TestDownload(t *testing.T) {
t.Fatalf("download results: expected length: %d, actual length: %d", expectedLen, len(results))
}
start := results[0].IntervalStart
for _, result := range results {
displayResult(t, result)
displayResult(t, result, start)
}
})
@ -66,8 +68,9 @@ func TestDownload(t *testing.T) {
t.Fatalf("upload results: expected length: %d, actual length: %d", expectedLen, len(results))
}
start := results[0].IntervalStart
for _, result := range results {
displayResult(t, result)
displayResult(t, result, start)
}
})

Loading…
Cancel
Save