mpb icon indicating copy to clipboard operation
mpb copied to clipboard

Invalid rate calculation

Open jtolio opened this issue 1 year ago • 2 comments

Here is a modified version of this example, to use a ProxyWriter. It does not show the right rate:

package main

import (
	"io"
	"time"

	"github.com/vbauerster/mpb/v8"
	"github.com/vbauerster/mpb/v8/decor"
)

func main() {
	var total int64 = 1024 * 1024 * 500

	p := mpb.New(
		mpb.WithWidth(60),
		mpb.WithRefreshRate(180*time.Millisecond),
	)

	bar := p.New(total,
		mpb.BarStyle().Rbound("|"),
		mpb.PrependDecorators(
			decor.Counters(decor.SizeB1000(0), "% .2f / % .2f"),
		),
		mpb.AppendDecorators(
			decor.EwmaETA(decor.ET_STYLE_GO, 30),
			decor.Name(" ] "),
			decor.EwmaSpeed(decor.SizeB1024(0), "% .2f", 30),
		),
	)

	bar.SetTotal(total, false)
	bar.EnableTriggerComplete()

	var data [64 * 1024]byte

	pw := bar.ProxyWriter(io.Discard)

	for i := 0; i < 1024; i++ {
		pw.Write(data[:])
		time.Sleep(time.Second / 10)
	}
	pw.Close()

	p.Wait()
}

As you can see, this is doing 64KiB of writes every tenth of a second, so that means the speed here is 640KiB/s. Right?

Running this command consistently shows me a rate output of somewhere between 60 and 90 GiB/s. What?

jtolio avatar Nov 30 '23 16:11 jtolio

Implementation of Ewma prefixed decorators is delegated to ewma lib. So if you decided to use it I kindly recommend to read its documentation thoroughly. If you need a quick fix I recommend to use decor.AverageSpeed instead. In your example you use ProxyWriter(io.Discard) so you could end up measuring write speed of io.Discard. By using ProxyReader instead I've got adequate results with decor.EwmaSpeed. Try io example with following patch:

diff --git a/_examples/io/main.go b/_examples/io/main.go
index 252a967..eeae8d9 100644
--- a/_examples/io/main.go
+++ b/_examples/io/main.go
@@ -11,8 +11,20 @@ import (
 )
 
 func main() {
-	var total int64 = 1024 * 1024 * 500
-	reader := io.LimitReader(rand.Reader, total)
+	var total int64 = 64 * 1024 * 1024
+
+	r, w := io.Pipe()
+
+	go func() {
+		for i := 0; i < 1024; i++ {
+			_, err := io.Copy(w, io.LimitReader(rand.Reader, 64*1024))
+			if err != nil {
+				panic(err)
+			}
+			time.Sleep(time.Second / 10)
+		}
+		w.Close()
+	}()
 
 	p := mpb.New(
 		mpb.WithWidth(60),
@@ -27,12 +39,12 @@ func main() {
 		mpb.AppendDecorators(
 			decor.EwmaETA(decor.ET_STYLE_GO, 30),
 			decor.Name(" ] "),
-			decor.EwmaSpeed(decor.SizeB1024(0), "% .2f", 30),
+			decor.EwmaSpeed(decor.SizeB1024(0), "% .2f", 60),
 		),
 	)
 
 	// create proxy reader
-	proxyReader := bar.ProxyReader(reader)
+	proxyReader := bar.ProxyReader(r)
 	defer proxyReader.Close()
 
 	// copy from proxyReader, ignoring errors

vbauerster avatar Dec 05 '23 08:12 vbauerster

Hmm, I'm surprised that whether you use ProxyReader or ProxyWriter makes a difference - does this mean that the Proxy measurements are starting and also stopping clocks that only run during the Read or Write call? How might I reliably obtain the overall io.Copy speed, considering that either the Reader or Writer might be slow?

jtolio avatar Dec 23 '23 02:12 jtolio