Fix bitrate measurement stability

- improve accuracy of bitrate calculation
- reduce test input timing error
This commit is contained in:
Atsushi Watanabe
2020-05-23 00:12:44 +09:00
committed by Lukas Herman
parent 6471064956
commit 305b7086e3
2 changed files with 38 additions and 22 deletions

View File

@@ -11,12 +11,15 @@ import (
func MeasureBitRate(r io.Reader, dur time.Duration) (float64, error) {
var n, totalBytes int
var err error
buf := make([]byte, 1024)
start := time.Now()
now := start
end := now.Add(dur)
for now.Before(end) {
for {
n, err = r.Read(buf)
now = time.Now()
if err != nil {
if e, ok := err.(*mio.InsufficientBufferError); ok {
buf = make([]byte, 2*e.RequiredSize)
@@ -24,6 +27,7 @@ func MeasureBitRate(r io.Reader, dur time.Duration) (float64, error) {
}
if err == io.EOF {
dur = now.Sub(start)
totalBytes += n
break
}
@@ -31,11 +35,12 @@ func MeasureBitRate(r io.Reader, dur time.Duration) (float64, error) {
return 0, err
}
totalBytes += n
now = time.Now()
if now.After(end) {
break
}
totalBytes += n // count bytes if the data arrived within the period
}
elapsed := time.Now().Sub(start).Seconds()
avg := float64(totalBytes*8) / elapsed
avg := float64(totalBytes*8) / dur.Seconds()
return avg, nil
}

View File

@@ -9,18 +9,25 @@ import (
func TestMeasureBitRateStatic(t *testing.T) {
r, w := io.Pipe()
dur := time.Second * 5
dataSize := 1000
var precision float64 = 8 // 1 byte
const (
dataSize = 1000
dur = 5 * time.Second
packetInterval = time.Second
precision = 8.0 // 1 byte
)
var wg sync.WaitGroup
wg.Add(1)
done := make(chan struct{})
go func() {
data := make([]byte, dataSize)
ticker := time.NewTicker(packetInterval)
// Wait half interval
time.Sleep(packetInterval / 2)
// Make sure that this goroutine is synchronized with main goroutine
wg.Done()
ticker := time.NewTicker(time.Second)
for {
select {
@@ -48,30 +55,34 @@ func TestMeasureBitRateStatic(t *testing.T) {
func TestMeasureBitRateDynamic(t *testing.T) {
r, w := io.Pipe()
dur := time.Second * 5
dataSize := 1000
var precision float64 = 8 // 1 byte
const (
dataSize = 1000
dur = 5 * time.Second
packetInterval = time.Millisecond * 250
precision = 8.0 // 1 byte
)
var wg sync.WaitGroup
wg.Add(1)
done := make(chan struct{})
go func() {
data := make([]byte, dataSize)
wg.Done()
ticker := time.NewTicker(time.Millisecond * 500)
var count int
ticker := time.NewTicker(packetInterval)
// Wait half interval
time.Sleep(packetInterval / 2)
wg.Done()
var count int
for {
select {
case <-ticker.C:
w.Write(data)
count++
// Wait until 4 slow ticks, which is also equal to 2 seconds
if count == 4 {
ticker.Stop()
// Speed up the tick by 2 times for the rest
ticker = time.NewTicker(time.Millisecond * 250)
// 4 x 500ms ticks and 250ms ticks
if count%2 == 1 || count >= 8 {
w.Write(data)
}
count++
case <-done:
w.Close()
return