diff --git a/decor/counters.go b/decor/counters.go index db4bf53..be62b49 100644 --- a/decor/counters.go +++ b/decor/counters.go @@ -136,29 +136,24 @@ io.WriteString(st, res) } -// CountersNoUnit returns raw counters decorator -// -// `pairFormat` printf compatible verbs for current and total, like "%f" or "%d" -// -// `wcc` optional WC config +// CountersNoUnit is a wrapper around Counters with no unit param. func CountersNoUnit(pairFormat string, wcc ...WC) Decorator { - return counters(0, pairFormat, wcc...) + return Counters(0, pairFormat, wcc...) } -// CountersKibiByte returns human friendly byte counters decorator, where counters unit is multiple by 1024. -// -// `pairFormat` printf compatible verbs for current and total, like "%f" or "%d" -// -// `wcc` optional WC config -// -// pairFormat example: -// -// "%.1f / %.1f" = "1.0MiB / 12.0MiB" or "% .1f / % .1f" = "1.0 MiB / 12.0 MiB" +// CountersKibiByte is a wrapper around Counters with predefined unit UnitKiB (bytes/1024). func CountersKibiByte(pairFormat string, wcc ...WC) Decorator { - return counters(UnitKiB, pairFormat, wcc...) + return Counters(UnitKiB, pairFormat, wcc...) } -// CountersKiloByte returns human friendly byte counters decorator, where counters unit is multiple by 1000. +// CountersKiloByte is a wrapper around Counters with predefined unit UnitKB (bytes/1000). +func CountersKiloByte(pairFormat string, wcc ...WC) Decorator { + return Counters(UnitKB, pairFormat, wcc...) +} + +// Counters decorator with dynamic unit measure adjustement +// +// `unit` one of [0|UnitKiB|UnitKB] zero for no unit // // `pairFormat` printf compatible verbs for current and total, like "%f" or "%d" // @@ -167,11 +162,7 @@ // pairFormat example: // // "%.1f / %.1f" = "1.0MB / 12.0MB" or "% .1f / % .1f" = "1.0 MB / 12.0 MB" -func CountersKiloByte(pairFormat string, wcc ...WC) Decorator { - return counters(UnitKB, pairFormat, wcc...) -} - -func counters(unit int, pairFormat string, wcc ...WC) Decorator { +func Counters(unit int, pairFormat string, wcc ...WC) Decorator { var wc WC for _, widthConf := range wcc { wc = widthConf diff --git a/decor/eta.go b/decor/eta.go index a6f3a33..a4a2c71 100644 --- a/decor/eta.go +++ b/decor/eta.go @@ -9,28 +9,34 @@ "github.com/vbauerster/mpb/internal" ) -// ETA returns exponential-weighted-moving-average ETA decorator. +// EwmaETA exponential-weighted-moving-average based ETA decorator. // // `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS] // // `age` is the previous N samples to average over. -// If zero value provided, it defaults to 30. // -// `sb` is a start block receive channel. User suppose to send time.Now() -// to this channel on each iteration of a start block, right before actual job. -// The channel will be auto closed on bar shutdown event, so there is no need -// to close from user side. +// `sb` is a start block receive channel. It's required by MovingAverage algorithm, +// therefore result of time.Now() must be sent to this channel on each iteration +// of a start block, right before the actual job. There is no need to close the channel, +// as it will be closed automatically on bar completion event. // // `wcc` optional WC config -func ETA(style int, age float64, sb chan time.Time, wcc ...WC) Decorator { +func EwmaETA(style int, age float64, sb chan time.Time, wcc ...WC) Decorator { return MovingAverageETA(style, ewma.NewMovingAverage(age), sb, wcc...) } -// MovingAverageETA returns ETA decorator, which relies on MovingAverage implementation to calculate average. -// Default ETA decorator relies on ewma implementation. However you're free to provide your own implementation -// or use alternative one, which is provided by decor package: +// MovingAverageETA decorator relies on MovingAverage implementation to calculate its average. // -// decor.MovingAverageETA(decor.ET_STYLE_GO, decor.NewMedian(), sb) +// `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS] +// +// `average` MovingAverage implementation +// +// `sb` is a start block receive channel. It's required by MovingAverage algorithm, +// therefore result of time.Now() must be sent to this channel on each iteration +// of a start block, right before the actual job. There is no need to close the channel, +// as it will be closed automatically on bar completion event. +// +// `wcc` optional WC config func MovingAverageETA(style int, average MovingAverage, sb chan time.Time, wcc ...WC) Decorator { if sb == nil { panic("start block channel must not be nil") @@ -120,3 +126,42 @@ s.sbStreamer <- now } } + +// TotalAverageETA decorator. +// +// `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS] +// +// `wcc` optional WC config +func TotalAverageETA(style int, wcc ...WC) Decorator { + var wc WC + for _, widthConf := range wcc { + wc = widthConf + } + wc.BuildFormat() + startTime := time.Now() + return DecoratorFunc(func(st *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string { + var str string + timeElapsed := time.Since(startTime) + + v := internal.Round(float64(timeElapsed) / float64(st.Current)) + if math.IsInf(v, 0) || math.IsNaN(v) { + v = .0 + } + remaining := time.Duration((st.Total - st.Current) * int64(v)) + hours := int64((remaining / time.Hour) % 60) + minutes := int64((remaining / time.Minute) % 60) + seconds := int64((remaining / time.Second) % 60) + + switch style { + case ET_STYLE_GO: + str = fmt.Sprint(time.Duration(remaining.Seconds()) * time.Second) + case ET_STYLE_HHMMSS: + str = fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds) + case ET_STYLE_HHMM: + str = fmt.Sprintf("%02d:%02d", hours, minutes) + case ET_STYLE_MMSS: + str = fmt.Sprintf("%02d:%02d", minutes, seconds) + } + return wc.FormatMsg(str, widthAccumulator, widthDistributor) + }) +} diff --git a/decor/speed.go b/decor/speed.go index be2c91c..b6f0a23 100644 --- a/decor/speed.go +++ b/decor/speed.go @@ -118,74 +118,39 @@ io.WriteString(st, res) } -// SpeedNoUnit returns raw I/O operation speed decorator. +// EwmaSpeed exponential-weighted-moving-average based speed decorator, +// with dynamic unit measure adjustement. +// +// `unit` one of [0|UnitKiB|UnitKB] zero for no unit // // `unitFormat` printf compatible verb for value, like "%f" or "%d" // -// `age` is the previous N samples to average over. -// If zero value provided, it defaults to 30. -// -// `sb` is a start block receive channel. User suppose to send time.Now() -// to this channel on each iteration of a start block, right before actual job. -// The channel will be auto closed on bar shutdown event, so there is no need -// to close from user side. +// `average` MovingAverage implementation +// +// `sb` is a start block receive channel. It's required by MovingAverage algorithm, +// therefore result of time.Now() must be sent to this channel on each iteration +// of a start block, right before the actual job. There is no need to close the channel, +// as it will be closed automatically on bar completion event. // // `wcc` optional WC config -// -// unitFormat example: -// -// "%.1f" = "1.0" or "% .1f" = "1.0" -func SpeedNoUnit(unitFormat string, age float64, sb chan time.Time, wcc ...WC) Decorator { - return MovingAverageSpeed(0, unitFormat, ewma.NewMovingAverage(age), sb, wcc...) -} - -// SpeedKibiByte returns human friendly I/O operation speed decorator, +func EwmaSpeed(unit int, unitFormat string, age float64, sb chan time.Time, wcc ...WC) Decorator { + return MovingAverageSpeed(unit, unitFormat, ewma.NewMovingAverage(age), sb, wcc...) +} + +// MovingAverageSpeed decorator relies on MovingAverage implementation to calculate its average. +// +// `unit` one of [0|UnitKiB|UnitKB] zero for no unit // // `unitFormat` printf compatible verb for value, like "%f" or "%d" // -// `age` is the previous N samples to average over. -// If zero value provided, it defaults to 30. -// -// `sb` is a start block receive channel. User suppose to send time.Now() -// to this channel on each iteration of a start block, right before actual job. -// The channel will be auto closed on bar shutdown event, so there is no need -// to close from user side. +// `average` MovingAverage implementation +// +// `sb` is a start block receive channel. It's required by MovingAverage algorithm, +// therefore result of time.Now() must be sent to this channel on each iteration +// of a start block, right before the actual job. There is no need to close the channel, +// as it will be closed automatically on bar completion event. // // `wcc` optional WC config -// -// unitFormat example: -// -// "%.1f" = "1.0MiB/s" or "% .1f" = "1.0 MiB/s" -func SpeedKibiByte(unitFormat string, age float64, sb chan time.Time, wcc ...WC) Decorator { - return MovingAverageSpeed(UnitKiB, unitFormat, ewma.NewMovingAverage(age), sb, wcc...) -} - -// SpeedKiloByte returns human friendly I/O operation speed decorator, -// -// `unitFormat` printf compatible verb for value, like "%f" or "%d" -// -// `age` is the previous N samples to average over. -// If zero value provided, it defaults to 30. -// -// `sb` is a start block receive channel. User suppose to send time.Now() -// to this channel on each iteration of a start block, right before actual job. -// The channel will be auto closed on bar shutdown event, so there is no need -// to close from user side. -// -// `wcc` optional WC config -// -// unitFormat example: -// -// "%.1f" = "1.0MB/s" or "% .1f" = "1.0 MB/s" -func SpeedKiloByte(unitFormat string, age float64, sb chan time.Time, wcc ...WC) Decorator { - return MovingAverageSpeed(UnitKB, unitFormat, ewma.NewMovingAverage(age), sb, wcc...) -} - -// MovingAverageSpeed returns Speed decorator, which relies on MovingAverage implementation to calculate average. -// Default Speed decorator relies on ewma implementation. However you're free to provide your own implementation -// or use alternative one, which is provided by decor package: -// -// decor.MovingAverageSpeed(decor.UnitKiB, "% .2f", decor.NewMedian(), sb) func MovingAverageSpeed(unit int, unitFormat string, average MovingAverage, sb chan time.Time, wcc ...WC) Decorator { if sb == nil { panic("start block channel must not be nil") @@ -264,3 +229,34 @@ s.sbStreamer <- now } } + +// TotalAverageSpeed decorator with dynamic unit measure adjustement. +// +// `unit` one of [0|UnitKiB|UnitKB] zero for no unit +// +// `unitFormat` printf compatible verb for value, like "%f" or "%d" +// +// `wcc` optional WC config +func TotalAverageSpeed(unit int, unitFormat string, wcc ...WC) Decorator { + var wc WC + for _, widthConf := range wcc { + wc = widthConf + } + wc.BuildFormat() + startTime := time.Now() + return DecoratorFunc(func(st *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string { + var str string + timeElapsed := time.Since(startTime) + speed := float64(st.Current) / timeElapsed.Seconds() + + switch unit { + case UnitKiB: + str = fmt.Sprintf(unitFormat, SpeedKiB(speed)) + case UnitKB: + str = fmt.Sprintf(unitFormat, SpeedKB(speed)) + default: + str = fmt.Sprintf(unitFormat, speed) + } + return wc.FormatMsg(str, widthAccumulator, widthDistributor) + }) +}