mirror of
https://github.com/rocky-linux/peridot.git
synced 2024-10-19 07:55:07 +00:00
172 lines
4.2 KiB
Go
172 lines
4.2 KiB
Go
|
package decor
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"math"
|
||
|
"time"
|
||
|
|
||
|
"github.com/VividCortex/ewma"
|
||
|
)
|
||
|
|
||
|
// FmtAsSpeed adds "/s" to the end of the input formatter. To be
|
||
|
// used with SizeB1000 or SizeB1024 types, for example:
|
||
|
//
|
||
|
// fmt.Printf("%.1f", FmtAsSpeed(SizeB1024(2048)))
|
||
|
//
|
||
|
func FmtAsSpeed(input fmt.Formatter) fmt.Formatter {
|
||
|
return &speedFormatter{input}
|
||
|
}
|
||
|
|
||
|
type speedFormatter struct {
|
||
|
fmt.Formatter
|
||
|
}
|
||
|
|
||
|
func (self *speedFormatter) Format(st fmt.State, verb rune) {
|
||
|
self.Formatter.Format(st, verb)
|
||
|
io.WriteString(st, "/s")
|
||
|
}
|
||
|
|
||
|
// EwmaSpeed exponential-weighted-moving-average based speed decorator.
|
||
|
// For this decorator to work correctly you have to measure each
|
||
|
// iteration's duration and pass it to the
|
||
|
// *Bar.DecoratorEwmaUpdate(time.Duration) method after each increment.
|
||
|
func EwmaSpeed(unit int, format string, age float64, wcc ...WC) Decorator {
|
||
|
var average ewma.MovingAverage
|
||
|
if age == 0 {
|
||
|
average = ewma.NewMovingAverage()
|
||
|
} else {
|
||
|
average = ewma.NewMovingAverage(age)
|
||
|
}
|
||
|
return MovingAverageSpeed(unit, format, NewThreadSafeMovingAverage(average), wcc...)
|
||
|
}
|
||
|
|
||
|
// MovingAverageSpeed decorator relies on MovingAverage implementation
|
||
|
// to calculate its average.
|
||
|
//
|
||
|
// `unit` one of [0|UnitKiB|UnitKB] zero for no unit
|
||
|
//
|
||
|
// `format` printf compatible verb for value, like "%f" or "%d"
|
||
|
//
|
||
|
// `average` MovingAverage implementation
|
||
|
//
|
||
|
// `wcc` optional WC config
|
||
|
//
|
||
|
// format examples:
|
||
|
//
|
||
|
// unit=UnitKiB, format="%.1f" output: "1.0MiB/s"
|
||
|
// unit=UnitKiB, format="% .1f" output: "1.0 MiB/s"
|
||
|
// unit=UnitKB, format="%.1f" output: "1.0MB/s"
|
||
|
// unit=UnitKB, format="% .1f" output: "1.0 MB/s"
|
||
|
//
|
||
|
func MovingAverageSpeed(unit int, format string, average ewma.MovingAverage, wcc ...WC) Decorator {
|
||
|
if format == "" {
|
||
|
format = "%.0f"
|
||
|
}
|
||
|
d := &movingAverageSpeed{
|
||
|
WC: initWC(wcc...),
|
||
|
average: average,
|
||
|
producer: chooseSpeedProducer(unit, format),
|
||
|
}
|
||
|
return d
|
||
|
}
|
||
|
|
||
|
type movingAverageSpeed struct {
|
||
|
WC
|
||
|
producer func(float64) string
|
||
|
average ewma.MovingAverage
|
||
|
msg string
|
||
|
}
|
||
|
|
||
|
func (d *movingAverageSpeed) Decor(s Statistics) string {
|
||
|
if !s.Completed {
|
||
|
var speed float64
|
||
|
if v := d.average.Value(); v > 0 {
|
||
|
speed = 1 / v
|
||
|
}
|
||
|
d.msg = d.producer(speed * 1e9)
|
||
|
}
|
||
|
return d.FormatMsg(d.msg)
|
||
|
}
|
||
|
|
||
|
func (d *movingAverageSpeed) EwmaUpdate(n int64, dur time.Duration) {
|
||
|
durPerByte := float64(dur) / float64(n)
|
||
|
if math.IsInf(durPerByte, 0) || math.IsNaN(durPerByte) {
|
||
|
return
|
||
|
}
|
||
|
d.average.Add(durPerByte)
|
||
|
}
|
||
|
|
||
|
// AverageSpeed decorator with dynamic unit measure adjustment. It's
|
||
|
// a wrapper of NewAverageSpeed.
|
||
|
func AverageSpeed(unit int, format string, wcc ...WC) Decorator {
|
||
|
return NewAverageSpeed(unit, format, time.Now(), wcc...)
|
||
|
}
|
||
|
|
||
|
// NewAverageSpeed decorator with dynamic unit measure adjustment and
|
||
|
// user provided start time.
|
||
|
//
|
||
|
// `unit` one of [0|UnitKiB|UnitKB] zero for no unit
|
||
|
//
|
||
|
// `format` printf compatible verb for value, like "%f" or "%d"
|
||
|
//
|
||
|
// `startTime` start time
|
||
|
//
|
||
|
// `wcc` optional WC config
|
||
|
//
|
||
|
// format examples:
|
||
|
//
|
||
|
// unit=UnitKiB, format="%.1f" output: "1.0MiB/s"
|
||
|
// unit=UnitKiB, format="% .1f" output: "1.0 MiB/s"
|
||
|
// unit=UnitKB, format="%.1f" output: "1.0MB/s"
|
||
|
// unit=UnitKB, format="% .1f" output: "1.0 MB/s"
|
||
|
//
|
||
|
func NewAverageSpeed(unit int, format string, startTime time.Time, wcc ...WC) Decorator {
|
||
|
if format == "" {
|
||
|
format = "%.0f"
|
||
|
}
|
||
|
d := &averageSpeed{
|
||
|
WC: initWC(wcc...),
|
||
|
startTime: startTime,
|
||
|
producer: chooseSpeedProducer(unit, format),
|
||
|
}
|
||
|
return d
|
||
|
}
|
||
|
|
||
|
type averageSpeed struct {
|
||
|
WC
|
||
|
startTime time.Time
|
||
|
producer func(float64) string
|
||
|
msg string
|
||
|
}
|
||
|
|
||
|
func (d *averageSpeed) Decor(s Statistics) string {
|
||
|
if !s.Completed {
|
||
|
speed := float64(s.Current) / float64(time.Since(d.startTime))
|
||
|
d.msg = d.producer(speed * 1e9)
|
||
|
}
|
||
|
|
||
|
return d.FormatMsg(d.msg)
|
||
|
}
|
||
|
|
||
|
func (d *averageSpeed) AverageAdjust(startTime time.Time) {
|
||
|
d.startTime = startTime
|
||
|
}
|
||
|
|
||
|
func chooseSpeedProducer(unit int, format string) func(float64) string {
|
||
|
switch unit {
|
||
|
case UnitKiB:
|
||
|
return func(speed float64) string {
|
||
|
return fmt.Sprintf(format, FmtAsSpeed(SizeB1024(math.Round(speed))))
|
||
|
}
|
||
|
case UnitKB:
|
||
|
return func(speed float64) string {
|
||
|
return fmt.Sprintf(format, FmtAsSpeed(SizeB1000(math.Round(speed))))
|
||
|
}
|
||
|
default:
|
||
|
return func(speed float64) string {
|
||
|
return fmt.Sprintf(format, speed)
|
||
|
}
|
||
|
}
|
||
|
}
|