accounting: fix time to completion estimates

Previous to this change package used for this
github.com/VividCortex/ewma took a 0 average to mean reset the
statistics.  This happens quite often when transferring files though a
buffer.

Replace that implementation with a simple home grown one (with about
the same constant), without that feature.
This commit is contained in:
Nick Craig-Wood 2018-06-11 11:28:12 +01:00
parent 842ed7d2a9
commit ca44fb1fba

View File

@ -7,7 +7,6 @@ import (
"sync" "sync"
"time" "time"
"github.com/VividCortex/ewma"
"github.com/ncw/rclone/fs" "github.com/ncw/rclone/fs"
"github.com/ncw/rclone/fs/asyncreader" "github.com/ncw/rclone/fs/asyncreader"
"github.com/ncw/rclone/fs/fserrors" "github.com/ncw/rclone/fs/fserrors"
@ -37,12 +36,14 @@ type Account struct {
start time.Time // Start time of first read start time.Time // Start time of first read
lpTime time.Time // Time of last average measurement lpTime time.Time // Time of last average measurement
lpBytes int // Number of bytes read since last measurement lpBytes int // Number of bytes read since last measurement
avg ewma.MovingAverage // Moving average of last few measurements avg float64 // Moving average of last few measurements in bytes/s
closed bool // set if the file is closed closed bool // set if the file is closed
exit chan struct{} // channel that will be closed when transfer is finished exit chan struct{} // channel that will be closed when transfer is finished
withBuf bool // is using a buffered in withBuf bool // is using a buffered in
} }
const averagePeriod = 16 // period to do exponentially weighted averages over
// NewAccountSizeName makes a Account reader for an io.ReadCloser of // NewAccountSizeName makes a Account reader for an io.ReadCloser of
// the given size and name // the given size and name
func NewAccountSizeName(in io.ReadCloser, size int64, name string) *Account { func NewAccountSizeName(in io.ReadCloser, size int64, name string) *Account {
@ -53,7 +54,7 @@ func NewAccountSizeName(in io.ReadCloser, size int64, name string) *Account {
size: size, size: size,
name: name, name: name,
exit: make(chan struct{}), exit: make(chan struct{}),
avg: ewma.NewMovingAverage(), avg: 0,
lpTime: time.Now(), lpTime: time.Now(),
max: int64(fs.Config.MaxTransfer), max: int64(fs.Config.MaxTransfer),
} }
@ -136,7 +137,7 @@ func (acc *Account) averageLoop() {
// Add average of last second. // Add average of last second.
elapsed := now.Sub(acc.lpTime).Seconds() elapsed := now.Sub(acc.lpTime).Seconds()
avg := float64(acc.lpBytes) / elapsed avg := float64(acc.lpBytes) / elapsed
acc.avg.Add(avg) acc.avg = (avg + (averagePeriod-1)*acc.avg) / averagePeriod
acc.lpBytes = 0 acc.lpBytes = 0
acc.lpTime = now acc.lpTime = now
// Unlock stats // Unlock stats
@ -221,7 +222,7 @@ func (acc *Account) speed() (bps, current float64) {
// Calculate speed from first read. // Calculate speed from first read.
total := float64(time.Now().Sub(acc.start)) / float64(time.Second) total := float64(time.Now().Sub(acc.start)) / float64(time.Second)
bps = float64(acc.bytes) / total bps = float64(acc.bytes) / total
current = acc.avg.Value() current = acc.avg
return return
} }
@ -241,13 +242,13 @@ func (acc *Account) eta() (eta time.Duration, ok bool) {
if left <= 0 { if left <= 0 {
return 0, true return 0, true
} }
avg := acc.avg.Value() avg := acc.avg
if avg <= 0 { if avg <= 0 {
return 0, false return 0, false
} }
seconds := float64(left) / acc.avg.Value() seconds := float64(left) / avg
return time.Duration(time.Second * time.Duration(int(seconds))), true return time.Second * time.Duration(seconds), true
} }
// String produces stats for this file // String produces stats for this file